[Intel-gfx] [RFC 59/60] drm/i915: defer pd lmem block put to worker
Matthew Auld
matthew.auld at intel.com
Fri Jul 10 11:57:56 UTC 2020
From: Daniele Ceraolo Spurio <daniele.ceraolospurio at 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.auld at intel.com>
Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
Signed-off-by: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota at 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
More information about the Intel-gfx
mailing list