Skip to content

Commit

Permalink
drm/i915: Introduce drm_i915_gem_object_ops
Browse files Browse the repository at this point in the history
In order to specialise functions depending upon the type of object, we
can attach vfuncs to each object via a new ->ops pointer.

For instance, this will be used in future patches to only bind pages from
a dma-buf for the duration that the object is used by the GPU - and so
prevent them from pinning those pages for the entire of the object.

v2: Bonus comments.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Chris Wilson authored and Daniel Vetter committed Sep 20, 2012
1 parent 8c0bd3c commit 37e680a
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 27 deletions.
25 changes: 23 additions & 2 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -899,9 +899,29 @@ enum i915_cache_level {
I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */
};

struct drm_i915_gem_object_ops {
/* Interface between the GEM object and its backing storage.
* get_pages() is called once prior to the use of the associated set
* of pages before to binding them into the GTT, and put_pages() is
* called after we no longer need them. As we expect there to be
* associated cost with migrating pages between the backing storage
* and making them available for the GPU (e.g. clflush), we may hold
* onto the pages after they are no longer referenced by the GPU
* in case they may be used again shortly (for example migrating the
* pages to a different memory domain within the GTT). put_pages()
* will therefore most likely be called when the object itself is
* being released or under memory pressure (where we attempt to
* reap pages for the shrinker).
*/
int (*get_pages)(struct drm_i915_gem_object *);
void (*put_pages)(struct drm_i915_gem_object *);
};

struct drm_i915_gem_object {
struct drm_gem_object base;

const struct drm_i915_gem_object_ops *ops;

/** Current space allocated to this object in the GTT, if any. */
struct drm_mm_node *gtt_space;
struct list_head gtt_list;
Expand Down Expand Up @@ -1306,7 +1326,8 @@ int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void i915_gem_load(struct drm_device *dev);
int i915_gem_init_object(struct drm_gem_object *obj);
void i915_gem_object_init(struct drm_i915_gem_object *obj);
void i915_gem_object_init(struct drm_i915_gem_object *obj,
const struct drm_i915_gem_object_ops *ops);
struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
size_t size);
void i915_gem_free_object(struct drm_gem_object *obj);
Expand All @@ -1319,7 +1340,7 @@ int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj);
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
void i915_gem_lastclose(struct drm_device *dev);

int __must_check i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj);
int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
int i915_gem_object_sync(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *to);
Expand Down
78 changes: 55 additions & 23 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1650,18 +1650,12 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
return obj->madv == I915_MADV_DONTNEED;
}

static int
static void
i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
{
int page_count = obj->base.size / PAGE_SIZE;
int ret, i;

BUG_ON(obj->gtt_space);

if (obj->pages == NULL)
return 0;

BUG_ON(obj->gtt_space);
BUG_ON(obj->madv == __I915_MADV_PURGED);

ret = i915_gem_object_set_to_cpu_domain(obj, true);
Expand Down Expand Up @@ -1693,9 +1687,21 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)

drm_free_large(obj->pages);
obj->pages = NULL;
}

list_del(&obj->gtt_list);
static int
i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
{
const struct drm_i915_gem_object_ops *ops = obj->ops;

if (obj->sg_table || obj->pages == NULL)
return 0;

BUG_ON(obj->gtt_space);

ops->put_pages(obj);

list_del(&obj->gtt_list);
if (i915_gem_object_is_purgeable(obj))
i915_gem_object_truncate(obj);

Expand All @@ -1712,7 +1718,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
&dev_priv->mm.unbound_list,
gtt_list) {
if (i915_gem_object_is_purgeable(obj) &&
i915_gem_object_put_pages_gtt(obj) == 0) {
i915_gem_object_put_pages(obj) == 0) {
count += obj->base.size >> PAGE_SHIFT;
if (count >= target)
return count;
Expand All @@ -1724,7 +1730,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
mm_list) {
if (i915_gem_object_is_purgeable(obj) &&
i915_gem_object_unbind(obj) == 0 &&
i915_gem_object_put_pages_gtt(obj) == 0) {
i915_gem_object_put_pages(obj) == 0) {
count += obj->base.size >> PAGE_SHIFT;
if (count >= target)
return count;
Expand All @@ -1742,10 +1748,10 @@ i915_gem_shrink_all(struct drm_i915_private *dev_priv)
i915_gem_evict_everything(dev_priv->dev);

list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list)
i915_gem_object_put_pages_gtt(obj);
i915_gem_object_put_pages(obj);
}

int
static int
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
Expand All @@ -1754,9 +1760,6 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
struct page *page;
gfp_t gfp;

if (obj->pages || obj->sg_table)
return 0;

/* Assert that the object is not currently in any GPU domain. As it
* wasn't in the GTT, there shouldn't be any way it could have been in
* a GPU cache
Expand Down Expand Up @@ -1806,7 +1809,6 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
if (i915_gem_object_needs_bit17_swizzle(obj))
i915_gem_object_do_bit_17_swizzle(obj);

list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
return 0;

err_pages:
Expand All @@ -1818,6 +1820,31 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
return PTR_ERR(page);
}

/* Ensure that the associated pages are gathered from the backing storage
* and pinned into our object. i915_gem_object_get_pages() may be called
* multiple times before they are released by a single call to
* i915_gem_object_put_pages() - once the pages are no longer referenced
* either as a result of memory pressure (reaping pages under the shrinker)
* or as the object is itself released.
*/
int
i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
const struct drm_i915_gem_object_ops *ops = obj->ops;
int ret;

if (obj->sg_table || obj->pages)
return 0;

ret = ops->get_pages(obj);
if (ret)
return ret;

list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
return 0;
}

void
i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *ring,
Expand Down Expand Up @@ -2071,7 +2098,6 @@ void i915_gem_reset(struct drm_device *dev)
obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
}


/* The fence registers are invalidated so clear them out */
i915_gem_reset_fences(dev);
}
Expand Down Expand Up @@ -2871,7 +2897,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
return -E2BIG;
}

ret = i915_gem_object_get_pages_gtt(obj);
ret = i915_gem_object_get_pages(obj);
if (ret)
return ret;

Expand Down Expand Up @@ -3610,15 +3636,16 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
return ret;
}

void i915_gem_object_init(struct drm_i915_gem_object *obj)
void i915_gem_object_init(struct drm_i915_gem_object *obj,
const struct drm_i915_gem_object_ops *ops)
{
obj->base.driver_private = NULL;

INIT_LIST_HEAD(&obj->mm_list);
INIT_LIST_HEAD(&obj->gtt_list);
INIT_LIST_HEAD(&obj->ring_list);
INIT_LIST_HEAD(&obj->exec_list);

obj->ops = ops;

obj->fence_reg = I915_FENCE_REG_NONE;
obj->madv = I915_MADV_WILLNEED;
/* Avoid an unnecessary call to unbind on the first bind. */
Expand All @@ -3627,6 +3654,11 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj)
i915_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size);
}

static const struct drm_i915_gem_object_ops i915_gem_object_ops = {
.get_pages = i915_gem_object_get_pages_gtt,
.put_pages = i915_gem_object_put_pages_gtt,
};

struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
size_t size)
{
Expand All @@ -3653,7 +3685,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
mapping_set_gfp_mask(mapping, mask);

i915_gem_object_init(obj);
i915_gem_object_init(obj, &i915_gem_object_ops);

obj->base.write_domain = I915_GEM_DOMAIN_CPU;
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
Expand Down Expand Up @@ -3711,7 +3743,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
dev_priv->mm.interruptible = was_interruptible;
}

i915_gem_object_put_pages_gtt(obj);
i915_gem_object_put_pages(obj);
i915_gem_object_free_mmap_offset(obj);

drm_gem_object_release(&obj->base);
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/i915_gem_dmabuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme
if (ret)
return ERR_PTR(ret);

ret = i915_gem_object_get_pages_gtt(obj);
ret = i915_gem_object_get_pages(obj);
if (ret) {
sg = ERR_PTR(ret);
goto out;
Expand Down Expand Up @@ -89,7 +89,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
goto out_unlock;
}

ret = i915_gem_object_get_pages_gtt(obj);
ret = i915_gem_object_get_pages(obj);
if (ret) {
mutex_unlock(&dev->struct_mutex);
return ERR_PTR(ret);
Expand Down

0 comments on commit 37e680a

Please sign in to comment.