From: Daniele Ceraolo Spurio <daniele.ceraolospurio@xxxxxxxxx> We take mem->mm_lock inside __i915_vma_unbind to release the memory used for the page table itself, but __i915_vma_unbind is called while holding vm->mutex; vm->mutex is tainted by the shrinker and therefore locks related to allocations can't be taken while holding it (kmem_cache_alloc is called under mem->mm_lock in i915_buddy_alloc, so mem->mm_lock is a lock managing allocations). As a temporary WA, move the memory release to a dedicated work called outside the vm->mutex lock. A lockless list has been used to avoid any locking dependency. Cc: Matthew Auld <matthew.auld@xxxxxxxxx> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@xxxxxxxxx> Signed-off-by: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_buddy.h | 10 +++++++ drivers/gpu/drm/i915/intel_memory_region.c | 28 ++++++++++++++++--- drivers/gpu/drm/i915/intel_memory_region.h | 5 ++++ .../gpu/drm/i915/selftests/mock_gem_device.c | 3 +- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_buddy.h b/drivers/gpu/drm/i915/i915_buddy.h index ed41f3507cdc..fb08eb99d654 100644 --- a/drivers/gpu/drm/i915/i915_buddy.h +++ b/drivers/gpu/drm/i915/i915_buddy.h @@ -8,6 +8,7 @@ #include <linux/bitops.h> #include <linux/list.h> +#include <linux/llist.h> struct i915_buddy_block { #define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) @@ -32,6 +33,15 @@ struct i915_buddy_block { */ struct list_head link; struct list_head tmp_link; + + /* + * XXX: consider moving this somewhere specific to the pd stuff. In an + * ideal world we would like to keep i915_buddy as non-i915 specific as + * possible and in this case the delayed freeing is only required for + * our pd handling, which is only one part of our overall i915_buddy + * use. + */ + struct llist_node freed; }; #define I915_BUDDY_MAX_ORDER I915_BUDDY_HEADER_ORDER diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index 6e9d0861cf8c..80d827c4973d 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -84,14 +84,29 @@ __intel_memory_region_put_pages_buddy(struct intel_memory_region *mem, mutex_unlock(&mem->mm_lock); } -void -__intel_memory_region_put_block_buddy(struct i915_buddy_block *block) +static void __intel_memory_region_put_block_work(struct work_struct *work) { + struct intel_memory_region *mem = + container_of(work, struct intel_memory_region, pd_put.work); + struct llist_node *freed = llist_del_all(&mem->pd_put.blocks); + struct i915_buddy_block *block; struct list_head blocks; INIT_LIST_HEAD(&blocks); - list_add(&block->link, &blocks); - __intel_memory_region_put_pages_buddy(block->private, &blocks); + + llist_for_each_entry(block, freed, freed) + list_add(&block->link, &blocks); + + __intel_memory_region_put_pages_buddy(mem, &blocks); +} + +void +__intel_memory_region_put_block_buddy(struct i915_buddy_block *block) +{ + struct intel_memory_region *mem = block->private; + + if (llist_add(&block->freed, &mem->pd_put.blocks)) + queue_work(mem->i915->wq, &mem->pd_put.work); } int @@ -224,6 +239,8 @@ intel_memory_region_create(struct drm_i915_private *i915, mem->total = size; mem->avail = mem->total; + INIT_WORK(&mem->pd_put.work, __intel_memory_region_put_block_work); + mutex_init(&mem->objects.lock); INIT_LIST_HEAD(&mem->objects.list); INIT_LIST_HEAD(&mem->objects.purgeable); @@ -260,6 +277,9 @@ static void __intel_memory_region_destroy(struct kref *kref) struct intel_memory_region *mem = container_of(kref, typeof(*mem), kref); + /* Flush any pending work items to free blocks region */ + flush_workqueue(mem->i915->wq); + if (mem->ops->release) mem->ops->release(mem); diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index e082b895afdb..e11ee974301f 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -83,6 +83,11 @@ struct intel_memory_region { struct i915_buddy_mm mm; struct mutex mm_lock; + struct { + struct work_struct work; + struct llist_head blocks; + } pd_put; + struct kref kref; resource_size_t io_start; diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 9a46be05425a..07838a587413 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -69,11 +69,12 @@ static void mock_device_release(struct drm_device *dev) i915_gem_drain_freed_objects(i915); mock_fini_ggtt(&i915->ggtt); - destroy_workqueue(i915->wq); intel_gt_driver_late_release(&i915->gt); intel_memory_regions_driver_release(i915); + destroy_workqueue(i915->wq); + drm_mode_config_cleanup(&i915->drm); out: -- 2.26.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx