From: Daniele Ceraolo Spurio <daniele.ceraolospu...@intel.com>

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.a...@intel.com>
Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospu...@intel.com>
Signed-off-by: Venkata Sandeep Dhanalakota <venkata.s.dhanalak...@intel.com>
---
 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@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to