[22/23] drm/i915: Add an implementation for i915_gem_ww_ctx locking, v2.
diff mbox series

Message ID 20200702083225.20044-22-chris@chris-wilson.co.uk
State New
Headers show
Series
  • [01/23] drm/i915: Drop vm.ref for duplicate vma on construction
Related show

Commit Message

Chris Wilson July 2, 2020, 8:32 a.m. UTC
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

i915_gem_ww_ctx is used to lock all gem bo's for pinning and memory
eviction. We don't use it yet, but lets start adding the definition
first.

To use it, we have to pass a non-NULL ww to gem_object_lock, and don't
unlock directly. It is done in i915_gem_ww_ctx_fini.

Changes since v1:
- Change ww_ctx and obj order in locking functions (Jonas Lahtinen)

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   4 +
 drivers/gpu/drm/i915/gem/i915_gem_object.h    |   8 +-
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |   9 ++
 drivers/gpu/drm/i915/mm/i915_acquire_ctx.c    | 110 ++++++++++++++++++
 drivers/gpu/drm/i915/mm/i915_acquire_ctx.h    |  34 ++++++
 5 files changed, 161 insertions(+), 4 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/mm/i915_acquire_ctx.c
 create mode 100644 drivers/gpu/drm/i915/mm/i915_acquire_ctx.h

Patch
diff mbox series

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 41a27fd5dbc7..33c85b4ff3ed 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -124,6 +124,10 @@  gt-y += \
 	gt/gen9_renderstate.o
 i915-y += $(gt-y)
 
+# Memory + DMA management
+i915-y += \
+	mm/i915_acquire_ctx.o
+
 # GEM (Graphics Execution Management) code
 gem-y += \
 	gem/i915_gem_busy.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index 2faa481cc18f..8b4a341ebc56 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -110,14 +110,14 @@  i915_gem_object_put(struct drm_i915_gem_object *obj)
 
 #define assert_object_held(obj) dma_resv_assert_held((obj)->base.resv)
 
-static inline void i915_gem_object_lock(struct drm_i915_gem_object *obj)
+static inline bool i915_gem_object_trylock(struct drm_i915_gem_object *obj)
 {
-	dma_resv_lock(obj->base.resv, NULL);
+	return dma_resv_trylock(obj->base.resv);
 }
 
-static inline bool i915_gem_object_trylock(struct drm_i915_gem_object *obj)
+static inline void i915_gem_object_lock(struct drm_i915_gem_object *obj)
 {
-	return dma_resv_trylock(obj->base.resv);
+	dma_resv_lock(obj->base.resv, NULL);
 }
 
 static inline int
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
index d0847d7896f9..80b2cdd3875f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -206,6 +206,15 @@  struct drm_i915_gem_object {
 		 */
 		struct list_head region_link;
 
+		/**
+		 * @acquire_link: Link into @i915_acquire_ctx.list
+		 *
+		 * When we lock this object through i915_gem_object_lock() with a
+		 * context, we add it to the list to ensure we can unlock everything
+		 * when i915_gem_ww_ctx_backoff() or i915_gem_ww_ctx_fini() are called.
+		 */
+		struct list_head acquire_link;
+
 		struct sg_table *pages;
 		void *mapping;
 
diff --git a/drivers/gpu/drm/i915/mm/i915_acquire_ctx.c b/drivers/gpu/drm/i915/mm/i915_acquire_ctx.c
new file mode 100644
index 000000000000..7e8771d8a711
--- /dev/null
+++ b/drivers/gpu/drm/i915/mm/i915_acquire_ctx.c
@@ -0,0 +1,110 @@ 
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+
+#include <linux/dma-resv.h>
+
+#include "gem/i915_gem_object.h"
+
+#include "i915_acquire_ctx.h"
+
+void i915_acquire_ctx_init(struct i915_acquire_ctx *acquire)
+{
+	ww_acquire_init(&acquire->ctx, &reservation_ww_class);
+	INIT_LIST_HEAD(&acquire->list);
+	acquire->contended = NULL;
+}
+
+int i915_acquire_ctx_lock(struct i915_acquire_ctx *acquire,
+			  struct drm_i915_gem_object *obj)
+{
+	int ret;
+
+	ret = dma_resv_lock_interruptible(obj->base.resv, &acquire->ctx);
+	if (!ret)
+		list_add_tail(&obj->mm.acquire_link, &acquire->list);
+	if (ret == -EALREADY)
+		ret = 0;
+	if (ret == -EDEADLK)
+		acquire->contended = obj;
+
+	return ret;
+}
+
+static void i915_acquire_ctx_unlock_all(struct i915_acquire_ctx *acquire)
+{
+	struct drm_i915_gem_object *obj, *on;
+
+	list_for_each_entry_safe(obj, on, &acquire->list, mm.acquire_link)
+		i915_gem_object_unlock(obj);
+	INIT_LIST_HEAD(&acquire->list);
+}
+
+int __must_check i915_acquire_ctx_backoff(struct i915_acquire_ctx *acquire)
+{
+	struct drm_i915_gem_object *obj;
+	int ret = 0;
+
+	GEM_BUG_ON(!acquire->contended);
+
+	i915_acquire_ctx_unlock_all(acquire);
+
+	obj = fetch_and_zero(&acquire->contended);
+	ret = dma_resv_lock_slow_interruptible(obj->base.resv, &acquire->ctx);
+	if (!ret)
+		list_add_tail(&obj->mm.acquire_link, &acquire->list);
+
+	return ret;
+}
+
+void i915_acquire_ctx_fini(struct i915_acquire_ctx *acquire)
+{
+	GEM_BUG_ON(acquire->contended);
+
+	i915_acquire_ctx_unlock_all(acquire);
+	ww_acquire_fini(&acquire->ctx);
+}
+
+#if 0
+static int igt_acquire_ctx(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj, *obj2;
+	struct i915_acquire_ctx acquire;
+	int err = 0;
+
+	obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	obj2 = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(obj)) {
+		err = PTR_ERR(obj);
+		goto put1;
+	}
+
+	i915_acquire_ctx_init(&acquire, true);
+retry:
+	/* Lock the objects, twice for good measure (-EALREADY handling) */
+	err = i915_gem_object_lock(obj, &acquire);
+	if (!err)
+		err = i915_gem_object_lock_interruptible(obj, &acquire);
+	if (!err)
+		err = i915_gem_object_lock_interruptible(obj2, &acquire);
+	if (!err)
+		err = i915_gem_object_lock(obj2, &acquire);
+
+	if (err == -EDEADLK) {
+		err = i915_acquire_ctx_backoff(&acquire);
+		if (!err)
+			goto retry;
+	}
+	i915_acquire_ctx_fini(&acquire);
+	i915_gem_object_put(obj2);
+put1:
+	i915_gem_object_put(obj);
+	return err;
+}
+
+#endif
diff --git a/drivers/gpu/drm/i915/mm/i915_acquire_ctx.h b/drivers/gpu/drm/i915/mm/i915_acquire_ctx.h
new file mode 100644
index 000000000000..71cd9373c4fe
--- /dev/null
+++ b/drivers/gpu/drm/i915/mm/i915_acquire_ctx.h
@@ -0,0 +1,34 @@ 
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+
+#ifndef __I915_ACQIURE_CTX_H__
+#define __I915_ACQUIRE_CTX_H__
+
+#include <linux/list.h>
+#include <linux/ww_mutex.h>
+
+struct drm_i915_gem_object;
+
+struct i915_acquire_ctx {
+	struct ww_acquire_ctx ctx;
+	struct list_head list;
+	struct drm_i915_gem_object *contended;
+};
+
+void i915_acquire_ctx_init(struct i915_acquire_ctx *acquire);
+
+static inline void i915_acquire_ctx_done(struct i915_acquire_ctx *acquire)
+{
+	ww_acquire_done(&acquire->ctx);
+}
+
+void i915_acquire_ctx_fini(struct i915_acquire_ctx *acquire);
+
+int i915_acquire_ctx_lock(struct i915_acquire_ctx *acquire,
+			  struct drm_i915_gem_object *obj);
+
+int __must_check i915_acquire_ctx_backoff(struct i915_acquire_ctx *acquire);
+
+#endif /* __I915_ACQUIRE_CTX_H__ */