Skip to content

Commit

Permalink
BACKPORT: drm/i915: Create a dummy object for gen6 ppgtt
Browse files Browse the repository at this point in the history
We currently have to special case vma->obj being NULL because
of gen6 ppgtt and mock_engine. Fix gen6 ppgtt, so we may soon
be able to remove a few checks. As the object only exists as
a fake object pointing to ggtt, we have no backing storage,
so no real object is created. It just has to look real enough.

Also kill pin_mutex, it's not compatible with ww locking,
and we can use the vm lock instead.

v2:
  - Drop IS_SHRINKABLE and shorten overly long line
v3:
  - Checkpatch fix for alignment

Signed-off-by: Maarten Lankhorst <[email protected]>
Reviewed-by: Matthew Auld <[email protected]>
Signed-off-by: Matthew Auld <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
mlankhorst authored and moetayuko committed Nov 26, 2023
1 parent 8da725e commit 2ac4e7b
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 72 deletions.
45 changes: 26 additions & 19 deletions drivers/gpu/drm/i915/gem/i915_gem_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,24 +165,10 @@ static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = {
.put_pages = i915_gem_object_put_pages_internal,
};

/**
* i915_gem_object_create_internal: create an object with volatile pages
* @i915: the i915 device
* @size: the size in bytes of backing storage to allocate for the object
*
* Creates a new object that wraps some internal memory for private use.
* This object is not backed by swappable storage, and as such its contents
* are volatile and only valid whilst pinned. If the object is reaped by the
* shrinker, its pages and data will be discarded. Equally, it is not a full
* GEM object and so not valid for access from userspace. This makes it useful
* for hardware interfaces like ringbuffers (which are pinned from the time
* the request is written to the time the hardware stops accessing it), but
* not for contexts (which need to be preserved when not active for later
* reuse). Note that it is not cleared upon allocation.
*/
struct drm_i915_gem_object *
i915_gem_object_create_internal(struct drm_i915_private *i915,
phys_addr_t size)
__i915_gem_object_create_internal(struct drm_i915_private *i915,
const struct drm_i915_gem_object_ops *ops,
phys_addr_t size)
{
static struct lock_class_key lock_class;
struct drm_i915_gem_object *obj;
Expand All @@ -199,8 +185,7 @@ i915_gem_object_create_internal(struct drm_i915_private *i915,
return ERR_PTR(-ENOMEM);

drm_gem_private_object_init(&i915->drm, &obj->base, size);
i915_gem_object_init(obj, &i915_gem_object_internal_ops, &lock_class,
I915_BO_STRUCT_PAGE);
i915_gem_object_init(obj, ops, &lock_class, I915_BO_STRUCT_PAGE);

/*
* Mark the object as volatile, such that the pages are marked as
Expand All @@ -219,3 +204,25 @@ i915_gem_object_create_internal(struct drm_i915_private *i915,

return obj;
}

/**
* i915_gem_object_create_internal: create an object with volatile pages
* @i915: the i915 device
* @size: the size in bytes of backing storage to allocate for the object
*
* Creates a new object that wraps some internal memory for private use.
* This object is not backed by swappable storage, and as such its contents
* are volatile and only valid whilst pinned. If the object is reaped by the
* shrinker, its pages and data will be discarded. Equally, it is not a full
* GEM object and so not valid for access from userspace. This makes it useful
* for hardware interfaces like ringbuffers (which are pinned from the time
* the request is written to the time the hardware stops accessing it), but
* not for contexts (which need to be preserved when not active for later
* reuse). Note that it is not cleared upon allocation.
*/
struct drm_i915_gem_object *
i915_gem_object_create_internal(struct drm_i915_private *i915,
phys_addr_t size)
{
return __i915_gem_object_create_internal(i915, &i915_gem_object_internal_ops, size);
}
121 changes: 69 additions & 52 deletions drivers/gpu/drm/i915/gt/gen6_ppgtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,17 +260,13 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
{
struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm));

if (ppgtt->vma)
__i915_vma_put(ppgtt->vma);

gen6_ppgtt_free_pd(ppgtt);
i915_vm_free_scratch(vm);

if (ppgtt->base.pd)
free_pd(&ppgtt->base.vm, ppgtt->base.pd);

mutex_destroy(&ppgtt->flush);
mutex_destroy(&ppgtt->pin_mutex);
}

static int pd_vma_set_pages(struct i915_vma *vma)
Expand Down Expand Up @@ -331,37 +327,6 @@ static const struct i915_vma_ops pd_vma_ops = {
.unbind_vma = pd_vma_unbind,
};

static struct i915_vma *pd_vma_create(struct gen6_ppgtt *ppgtt, int size)
{
struct i915_ggtt *ggtt = ppgtt->base.vm.gt->ggtt;
struct i915_vma *vma;

GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
GEM_BUG_ON(size > ggtt->vm.total);

vma = i915_vma_alloc();
if (!vma)
return ERR_PTR(-ENOMEM);

i915_active_init(&vma->active, NULL, NULL, 0);

kref_init(&vma->ref);
mutex_init(&vma->pages_mutex);
vma->vm = i915_vm_get(&ggtt->vm);
vma->ops = &pd_vma_ops;
vma->private = ppgtt;

vma->size = size;
vma->fence_size = size;
atomic_set(&vma->flags, I915_VMA_GGTT);
vma->ggtt_view.type = I915_GGTT_VIEW_ROTATED; /* prevent fencing */

INIT_LIST_HEAD(&vma->obj_link);
INIT_LIST_HEAD(&vma->closed_link);

return vma;
}

int gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
{
struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
Expand All @@ -378,24 +343,85 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
if (atomic_add_unless(&ppgtt->pin_count, 1, 0))
return 0;

if (mutex_lock_interruptible(&ppgtt->pin_mutex))
return -EINTR;
/* grab the ppgtt resv to pin the object */
err = i915_vm_lock_objects(&ppgtt->base.vm, ww);
if (err)
return err;

/*
* PPGTT PDEs reside in the GGTT and consists of 512 entries. The
* allocator works in address space sizes, so it's multiplied by page
* size. We allocate at the top of the GTT to avoid fragmentation.
*/
err = 0;
if (!atomic_read(&ppgtt->pin_count))
if (!atomic_read(&ppgtt->pin_count)) {
err = i915_ggtt_pin(ppgtt->vma, ww, GEN6_PD_ALIGN, PIN_HIGH);

GEM_BUG_ON(ppgtt->vma->fence);
clear_bit(I915_VMA_CAN_FENCE_BIT, __i915_vma_flags(ppgtt->vma));
}
if (!err)
atomic_inc(&ppgtt->pin_count);
mutex_unlock(&ppgtt->pin_mutex);

return err;
}

static int pd_dummy_obj_get_pages(struct drm_i915_gem_object *obj)
{
obj->mm.pages = ZERO_SIZE_PTR;
return 0;
}

static int pd_dummy_obj_put_pages(struct drm_i915_gem_object *obj,
struct sg_table *pages)
{
return 0;
}

static const struct drm_i915_gem_object_ops pd_dummy_obj_ops = {
.name = "pd_dummy_obj",
.get_pages = pd_dummy_obj_get_pages,
.put_pages = pd_dummy_obj_put_pages,
};

static struct i915_page_directory *
gen6_alloc_top_pd(struct gen6_ppgtt *ppgtt)
{
struct i915_ggtt * const ggtt = ppgtt->base.vm.gt->ggtt;
struct i915_page_directory *pd;
int err;

pd = __alloc_pd(I915_PDES);
if (unlikely(!pd))
return ERR_PTR(-ENOMEM);

pd->pt.base = __i915_gem_object_create_internal(ppgtt->base.vm.gt->i915,
&pd_dummy_obj_ops,
I915_PDES * SZ_4K);
if (IS_ERR(pd->pt.base)) {
err = PTR_ERR(pd->pt.base);
pd->pt.base = NULL;
goto err_pd;
}

i915_gem_object_share_resv(ppgtt->base.vm.root_obj, pd->pt.base);

ppgtt->vma = i915_vma_instance(pd->pt.base, &ggtt->vm, NULL);
if (IS_ERR(ppgtt->vma)) {
err = PTR_ERR(ppgtt->vma);
ppgtt->vma = NULL;
goto err_pd;
}

/* The dummy object we create is special, override ops.. */
ppgtt->vma->ops = &pd_vma_ops;
ppgtt->vma->private = ppgtt;
return pd;

err_pd:
free_pd(&ppgtt->base.vm, pd);
return ERR_PTR(err);
}

void gen6_ppgtt_unpin(struct i915_ppgtt *base)
{
struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
Expand All @@ -420,15 +446,13 @@ struct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt)
{
struct i915_ggtt * const ggtt = gt->ggtt;
struct gen6_ppgtt *ppgtt;
struct i915_vma *vma;
int err;

ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
if (!ppgtt)
return ERR_PTR(-ENOMEM);

mutex_init(&ppgtt->flush);
mutex_init(&ppgtt->pin_mutex);

err = ppgtt_init(&ppgtt->base, gt);
if (err) {
Expand All @@ -449,22 +473,15 @@ struct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt)
ppgtt->base.vm.alloc_scratch_dma = alloc_pt_dma;
ppgtt->base.vm.pte_encode = ggtt->vm.pte_encode;

ppgtt->base.pd = __alloc_pd(I915_PDES);
if (!ppgtt->base.pd) {
err = -ENOMEM;
goto err_put;
}

err = gen6_ppgtt_init_scratch(ppgtt);
if (err)
goto err_put;

vma = pd_vma_create(ppgtt, GEN6_PD_SIZE);
if (IS_ERR(vma)) {
err = PTR_ERR(vma);
ppgtt->base.pd = gen6_alloc_top_pd(ppgtt);
if (IS_ERR(ppgtt->base.pd)) {
err = PTR_ERR(ppgtt->base.pd);
goto err_put;
}
ppgtt->vma = vma;

return &ppgtt->base;

Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/i915/gt/gen6_ppgtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ struct gen6_ppgtt {
u32 pp_dir;

atomic_t pin_count;
struct mutex pin_mutex;

bool scan_for_unused_pt;
};
Expand Down

0 comments on commit 2ac4e7b

Please sign in to comment.