All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] drm/i915: Move LMEM (VRAM) management over to TTM
@ 2021-05-11 13:25 ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

This is an initial patch series to move discrete memory management over to
TTM. It will be followed up shortly with adding more functionality.

The buddy allocator is temporarily removed along with its selftests and
It is replaced with the TTM range manager and some selftests are adjusted
to account for introduced fragmentation. Work is ongoing to reintroduce the
buddy allocator as a TTM resource manager.

A new memcpy ttm move is introduced that uses kmap_local() functionality
rather than vmap(). Among other things stated in the patch commit message
it helps us deal with page-pased LMEM memory. It is generic enough to replace
the ttm memcpy move with some additional work if so desired. On x86 it also
enables prefetching reads from write-combined memory.

Finally the old i915 gem object LMEM backend is replaced with a
i915 gem object TTM backend and some additional i915 gem object ops are
introduced to support the added functionality.
Currently it is used only to support management and eviction of the LMEM
region, but work is underway to extend the support to system memory. In this
way we use TTM the way it was originally intended, having the GPU binding
taken care of by driver code.

Intention is to follow up with
- System memory support
- TTM CPU pagefaulting
- Pipelined accelerated moves / migration


Thomas Hellström (7):
  drm/i915: Untangle the vma pages_mutex
  drm/i915: Don't free shared locks while shared
  drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
  drm/i915/ttm: Embed a ttm buffer object in the i915 gem object
  drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based
    iomem
  drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  drm/i915/lmem: Verify checks for lmem residency

 drivers/gpu/drm/i915/Kconfig                  |   1 +
 drivers/gpu/drm/i915/Makefile                 |   4 +-
 drivers/gpu/drm/i915/display/intel_display.c  |   2 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  71 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
 drivers/gpu/drm/i915/gem/i915_gem_object.c    | 161 +++-
 drivers/gpu/drm/i915/gem/i915_gem_object.h    |  13 +
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |  37 +-
 drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
 drivers/gpu/drm/i915/gem/i915_gem_region.c    | 126 +--
 drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
 drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++
 drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++
 drivers/gpu/drm/i915/gt/intel_ggtt.c          |  13 +-
 drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
 drivers/gpu/drm/i915/gt/intel_gtt.c           |  45 +-
 drivers/gpu/drm/i915/gt/intel_gtt.h           |  29 +-
 drivers/gpu/drm/i915/gt/intel_ppgtt.c         |   2 +-
 drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  30 +-
 drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
 drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
 drivers/gpu/drm/i915/i915_drv.c               |   8 +
 drivers/gpu/drm/i915/i915_drv.h               |   7 +-
 drivers/gpu/drm/i915/i915_gem.c               |   6 +-
 drivers/gpu/drm/i915/i915_globals.c           |   1 -
 drivers/gpu/drm/i915/i915_globals.h           |   1 -
 drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
 drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
 drivers/gpu/drm/i915/i915_vma.c               |  33 +-
 drivers/gpu/drm/i915/intel_memory_region.c    | 181 ++--
 drivers/gpu/drm/i915/intel_memory_region.h    |  45 +-
 drivers/gpu/drm/i915/intel_region_ttm.c       | 247 ++++++
 drivers/gpu/drm/i915/intel_region_ttm.h       |  32 +
 drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------------
 .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
 .../drm/i915/selftests/intel_memory_region.c  | 133 +--
 drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
 drivers/gpu/drm/ttm/ttm_bo.c                  |  13 +
 drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
 include/drm/ttm/ttm_bo_driver.h               |  23 +
 include/drm/ttm/ttm_device.h                  |   9 +
 46 files changed, 1876 insertions(+), 1879 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
 delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c

-- 
2.30.2


^ permalink raw reply	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 0/7] drm/i915: Move LMEM (VRAM) management over to TTM
@ 2021-05-11 13:25 ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

This is an initial patch series to move discrete memory management over to
TTM. It will be followed up shortly with adding more functionality.

The buddy allocator is temporarily removed along with its selftests and
It is replaced with the TTM range manager and some selftests are adjusted
to account for introduced fragmentation. Work is ongoing to reintroduce the
buddy allocator as a TTM resource manager.

A new memcpy ttm move is introduced that uses kmap_local() functionality
rather than vmap(). Among other things stated in the patch commit message
it helps us deal with page-pased LMEM memory. It is generic enough to replace
the ttm memcpy move with some additional work if so desired. On x86 it also
enables prefetching reads from write-combined memory.

Finally the old i915 gem object LMEM backend is replaced with a
i915 gem object TTM backend and some additional i915 gem object ops are
introduced to support the added functionality.
Currently it is used only to support management and eviction of the LMEM
region, but work is underway to extend the support to system memory. In this
way we use TTM the way it was originally intended, having the GPU binding
taken care of by driver code.

Intention is to follow up with
- System memory support
- TTM CPU pagefaulting
- Pipelined accelerated moves / migration


Thomas Hellström (7):
  drm/i915: Untangle the vma pages_mutex
  drm/i915: Don't free shared locks while shared
  drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
  drm/i915/ttm: Embed a ttm buffer object in the i915 gem object
  drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based
    iomem
  drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  drm/i915/lmem: Verify checks for lmem residency

 drivers/gpu/drm/i915/Kconfig                  |   1 +
 drivers/gpu/drm/i915/Makefile                 |   4 +-
 drivers/gpu/drm/i915/display/intel_display.c  |   2 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  71 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
 drivers/gpu/drm/i915/gem/i915_gem_object.c    | 161 +++-
 drivers/gpu/drm/i915/gem/i915_gem_object.h    |  13 +
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |  37 +-
 drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
 drivers/gpu/drm/i915/gem/i915_gem_region.c    | 126 +--
 drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
 drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++
 drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++
 drivers/gpu/drm/i915/gt/intel_ggtt.c          |  13 +-
 drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
 drivers/gpu/drm/i915/gt/intel_gtt.c           |  45 +-
 drivers/gpu/drm/i915/gt/intel_gtt.h           |  29 +-
 drivers/gpu/drm/i915/gt/intel_ppgtt.c         |   2 +-
 drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  30 +-
 drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
 drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
 drivers/gpu/drm/i915/i915_drv.c               |   8 +
 drivers/gpu/drm/i915/i915_drv.h               |   7 +-
 drivers/gpu/drm/i915/i915_gem.c               |   6 +-
 drivers/gpu/drm/i915/i915_globals.c           |   1 -
 drivers/gpu/drm/i915/i915_globals.h           |   1 -
 drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
 drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
 drivers/gpu/drm/i915/i915_vma.c               |  33 +-
 drivers/gpu/drm/i915/intel_memory_region.c    | 181 ++--
 drivers/gpu/drm/i915/intel_memory_region.h    |  45 +-
 drivers/gpu/drm/i915/intel_region_ttm.c       | 247 ++++++
 drivers/gpu/drm/i915/intel_region_ttm.h       |  32 +
 drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------------
 .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
 .../drm/i915/selftests/intel_memory_region.c  | 133 +--
 drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
 drivers/gpu/drm/ttm/ttm_bo.c                  |  13 +
 drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
 include/drm/ttm/ttm_bo_driver.h               |  23 +
 include/drm/ttm/ttm_device.h                  |   9 +
 46 files changed, 1876 insertions(+), 1879 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
 delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c

-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH 1/7] drm/i915: Untangle the vma pages_mutex
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:25   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

From: Thomas Hellström <thomas.hellstrom@intel.com>

Any sleeping dma_resv lock taken while the vma pages_mutex is held
will cause a lockdep splat.
Move the i915_gem_object_pin_pages() call out of the pages_mutex
critical section.

Signed-off-by: Thomas Hellström <thomas.hellstrom@intel.com>
---
 drivers/gpu/drm/i915/i915_vma.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index a6cd0fa62847..7b1c0f4e60d7 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -800,32 +800,37 @@ static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
 static int vma_get_pages(struct i915_vma *vma)
 {
 	int err = 0;
+	bool pinned_pages = false;
 
 	if (atomic_add_unless(&vma->pages_count, 1, 0))
 		return 0;
 
+	if (vma->obj) {
+		err = i915_gem_object_pin_pages(vma->obj);
+		if (err)
+			return err;
+		pinned_pages = true;
+	}
+
 	/* Allocations ahoy! */
-	if (mutex_lock_interruptible(&vma->pages_mutex))
-		return -EINTR;
+	if (mutex_lock_interruptible(&vma->pages_mutex)) {
+		err = -EINTR;
+		goto unpin;
+	}
 
 	if (!atomic_read(&vma->pages_count)) {
-		if (vma->obj) {
-			err = i915_gem_object_pin_pages(vma->obj);
-			if (err)
-				goto unlock;
-		}
-
 		err = vma->ops->set_pages(vma);
-		if (err) {
-			if (vma->obj)
-				i915_gem_object_unpin_pages(vma->obj);
+		if (err)
 			goto unlock;
-		}
+		pinned_pages = false;
 	}
 	atomic_inc(&vma->pages_count);
 
 unlock:
 	mutex_unlock(&vma->pages_mutex);
+unpin:
+	if (pinned_pages)
+		__i915_gem_object_unpin_pages(vma->obj);
 
 	return err;
 }
@@ -838,10 +843,10 @@ static void __vma_put_pages(struct i915_vma *vma, unsigned int count)
 	if (atomic_sub_return(count, &vma->pages_count) == 0) {
 		vma->ops->clear_pages(vma);
 		GEM_BUG_ON(vma->pages);
-		if (vma->obj)
-			i915_gem_object_unpin_pages(vma->obj);
 	}
 	mutex_unlock(&vma->pages_mutex);
+	if (vma->obj)
+		i915_gem_object_unpin_pages(vma->obj);
 }
 
 static void vma_put_pages(struct i915_vma *vma)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 1/7] drm/i915: Untangle the vma pages_mutex
@ 2021-05-11 13:25   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

From: Thomas Hellström <thomas.hellstrom@intel.com>

Any sleeping dma_resv lock taken while the vma pages_mutex is held
will cause a lockdep splat.
Move the i915_gem_object_pin_pages() call out of the pages_mutex
critical section.

Signed-off-by: Thomas Hellström <thomas.hellstrom@intel.com>
---
 drivers/gpu/drm/i915/i915_vma.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index a6cd0fa62847..7b1c0f4e60d7 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -800,32 +800,37 @@ static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
 static int vma_get_pages(struct i915_vma *vma)
 {
 	int err = 0;
+	bool pinned_pages = false;
 
 	if (atomic_add_unless(&vma->pages_count, 1, 0))
 		return 0;
 
+	if (vma->obj) {
+		err = i915_gem_object_pin_pages(vma->obj);
+		if (err)
+			return err;
+		pinned_pages = true;
+	}
+
 	/* Allocations ahoy! */
-	if (mutex_lock_interruptible(&vma->pages_mutex))
-		return -EINTR;
+	if (mutex_lock_interruptible(&vma->pages_mutex)) {
+		err = -EINTR;
+		goto unpin;
+	}
 
 	if (!atomic_read(&vma->pages_count)) {
-		if (vma->obj) {
-			err = i915_gem_object_pin_pages(vma->obj);
-			if (err)
-				goto unlock;
-		}
-
 		err = vma->ops->set_pages(vma);
-		if (err) {
-			if (vma->obj)
-				i915_gem_object_unpin_pages(vma->obj);
+		if (err)
 			goto unlock;
-		}
+		pinned_pages = false;
 	}
 	atomic_inc(&vma->pages_count);
 
 unlock:
 	mutex_unlock(&vma->pages_mutex);
+unpin:
+	if (pinned_pages)
+		__i915_gem_object_unpin_pages(vma->obj);
 
 	return err;
 }
@@ -838,10 +843,10 @@ static void __vma_put_pages(struct i915_vma *vma, unsigned int count)
 	if (atomic_sub_return(count, &vma->pages_count) == 0) {
 		vma->ops->clear_pages(vma);
 		GEM_BUG_ON(vma->pages);
-		if (vma->obj)
-			i915_gem_object_unpin_pages(vma->obj);
 	}
 	mutex_unlock(&vma->pages_mutex);
+	if (vma->obj)
+		i915_gem_object_unpin_pages(vma->obj);
 }
 
 static void vma_put_pages(struct i915_vma *vma)
-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH 2/7] drm/i915: Don't free shared locks while shared
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:25   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

We are currently sharing the VM reservation locks across a number of
gem objects with page-table memory. Since TTM will individiualize the
reservation locks when freeing objects, including accessing the shared
locks, make sure that the shared locks are not freed until that is done.
For PPGTT we add an additional refcount, for GGTT we flush the object
freeing workqueue before freeing the shared lock.

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_object.c    |  3 ++
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |  1 +
 drivers/gpu/drm/i915/gt/intel_ggtt.c          | 13 ++++--
 drivers/gpu/drm/i915/gt/intel_gtt.c           | 45 +++++++++++++++----
 drivers/gpu/drm/i915/gt/intel_gtt.h           | 29 +++++++++++-
 drivers/gpu/drm/i915/gt/intel_ppgtt.c         |  2 +-
 6 files changed, 80 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index 28144410df86..abadf0994ad0 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -252,6 +252,9 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
 		if (obj->mm.n_placements > 1)
 			kfree(obj->mm.placements);
 
+		if (obj->resv_shared_from)
+			i915_vm_resv_put(obj->resv_shared_from);
+
 		/* But keep the pointer alive for RCU-protected lookups */
 		call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
 		cond_resched();
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 0727d0c76aa0..450340a73186 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -149,6 +149,7 @@ struct drm_i915_gem_object {
 	 * when i915_gem_ww_ctx_backoff() or i915_gem_ww_ctx_fini() are called.
 	 */
 	struct list_head obj_link;
+	struct dma_resv *resv_shared_from;
 
 	union {
 		struct rcu_head rcu;
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
index 35069ca5d7de..128d781e429f 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
@@ -746,7 +746,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
 
 	mutex_unlock(&ggtt->vm.mutex);
 	i915_address_space_fini(&ggtt->vm);
-	dma_resv_fini(&ggtt->vm.resv);
+	/*
+	 * Make sure our pagetable gem objects have been freed,
+	 * so that nobody shares our reservation object anymore.
+	 */
+	i915_gem_flush_free_objects(ggtt->vm.i915);
+	GEM_WARN_ON(kref_read(&ggtt->vm.resv_ref) != 1);
+	dma_resv_fini(&ggtt->vm._resv);
 
 	arch_phys_wc_del(ggtt->mtrr);
 
@@ -829,6 +835,7 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
 		return -ENOMEM;
 	}
 
+	kref_init(&ggtt->vm.resv_ref);
 	ret = setup_scratch_page(&ggtt->vm);
 	if (ret) {
 		drm_err(&i915->drm, "Scratch setup failed\n");
@@ -1135,7 +1142,7 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt)
 	ggtt->vm.gt = gt;
 	ggtt->vm.i915 = i915;
 	ggtt->vm.dma = i915->drm.dev;
-	dma_resv_init(&ggtt->vm.resv);
+	dma_resv_init(&ggtt->vm._resv);
 
 	if (INTEL_GEN(i915) <= 5)
 		ret = i915_gmch_probe(ggtt);
@@ -1144,7 +1151,7 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt)
 	else
 		ret = gen8_gmch_probe(ggtt);
 	if (ret) {
-		dma_resv_fini(&ggtt->vm.resv);
+		dma_resv_fini(&ggtt->vm._resv);
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index 9b98f9d9faa3..695b22b17644 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -22,8 +22,11 @@ struct drm_i915_gem_object *alloc_pt_lmem(struct i915_address_space *vm, int sz)
 	 * object underneath, with the idea that one object_lock() will lock
 	 * them all at once.
 	 */
-	if (!IS_ERR(obj))
-		obj->base.resv = &vm->resv;
+	if (!IS_ERR(obj)) {
+		obj->base.resv = i915_vm_resv_get(vm);
+		obj->resv_shared_from = obj->base.resv;
+	}
+
 	return obj;
 }
 
@@ -40,8 +43,11 @@ struct drm_i915_gem_object *alloc_pt_dma(struct i915_address_space *vm, int sz)
 	 * object underneath, with the idea that one object_lock() will lock
 	 * them all at once.
 	 */
-	if (!IS_ERR(obj))
-		obj->base.resv = &vm->resv;
+	if (!IS_ERR(obj)) {
+		obj->base.resv = i915_vm_resv_get(vm);
+		obj->resv_shared_from = obj->base.resv;
+	}
+
 	return obj;
 }
 
@@ -102,7 +108,7 @@ void __i915_vm_close(struct i915_address_space *vm)
 int i915_vm_lock_objects(struct i915_address_space *vm,
 			 struct i915_gem_ww_ctx *ww)
 {
-	if (vm->scratch[0]->base.resv == &vm->resv) {
+	if (vm->scratch[0]->base.resv == &vm->_resv) {
 		return i915_gem_object_lock(vm->scratch[0], ww);
 	} else {
 		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
@@ -118,6 +124,22 @@ void i915_address_space_fini(struct i915_address_space *vm)
 	mutex_destroy(&vm->mutex);
 }
 
+/**
+ * i915_vm_resv_release - Final struct i915_address_space destructor
+ * @kref: Pointer to the &i915_address_space.resv_ref member.
+ *
+ * This function is called when the last lock sharer no longer shares the
+ * &i915_address_space._resv lock.
+ */
+void i915_vm_resv_release(struct kref *kref)
+{
+	struct i915_address_space *vm =
+		container_of(kref, typeof(*vm), resv_ref);
+
+	dma_resv_fini(&vm->_resv);
+	kfree(vm);
+}
+
 static void __i915_vm_release(struct work_struct *work)
 {
 	struct i915_address_space *vm =
@@ -125,9 +147,8 @@ static void __i915_vm_release(struct work_struct *work)
 
 	vm->cleanup(vm);
 	i915_address_space_fini(vm);
-	dma_resv_fini(&vm->resv);
 
-	kfree(vm);
+	i915_vm_resv_put(&vm->_resv);
 }
 
 void i915_vm_release(struct kref *kref)
@@ -144,6 +165,14 @@ void i915_vm_release(struct kref *kref)
 void i915_address_space_init(struct i915_address_space *vm, int subclass)
 {
 	kref_init(&vm->ref);
+
+	/*
+	 * Special case for GGTT that has already done an early
+	 * kref_init here.
+	 */
+	if (!kref_read(&vm->resv_ref))
+		kref_init(&vm->resv_ref);
+
 	INIT_RCU_WORK(&vm->rcu, __i915_vm_release);
 	atomic_set(&vm->open, 1);
 
@@ -170,7 +199,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
 		might_alloc(GFP_KERNEL);
 		mutex_release(&vm->mutex.dep_map, _THIS_IP_);
 	}
-	dma_resv_init(&vm->resv);
+	dma_resv_init(&vm->_resv);
 
 	GEM_BUG_ON(!vm->total);
 	drm_mm_init(&vm->mm, 0, vm->total);
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index ca00b45827b7..e760d4fadb43 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -245,7 +245,9 @@ struct i915_address_space {
 	atomic_t open;
 
 	struct mutex mutex; /* protects vma and our lists */
-	struct dma_resv resv; /* reservation lock for all pd objects, and buffer pool */
+
+	struct kref resv_ref; /* kref to keep the reservation lock alive. */
+	struct dma_resv _resv; /* reservation lock for all pd objects, and buffer pool */
 #define VM_CLASS_GGTT 0
 #define VM_CLASS_PPGTT 1
 #define VM_CLASS_DPT 2
@@ -404,13 +406,38 @@ i915_vm_get(struct i915_address_space *vm)
 	return vm;
 }
 
+/**
+ * i915_vm_resv_get - Obtain a reference on the vm's reservation lock
+ * @vm: The vm whose reservation lock we want to share.
+ *
+ * Return: A pointer to the vm's reservation lock.
+ */
+static inline struct dma_resv *i915_vm_resv_get(struct i915_address_space *vm)
+{
+	kref_get(&vm->resv_ref);
+	return &vm->_resv;
+}
+
 void i915_vm_release(struct kref *kref);
 
+void i915_vm_resv_release(struct kref *kref);
+
 static inline void i915_vm_put(struct i915_address_space *vm)
 {
 	kref_put(&vm->ref, i915_vm_release);
 }
 
+/**
+ * i915_vm_resv_put - Release a reference on the vm's reservation lock
+ * @resv: Pointer to a reservation lock obtained from i915_vm_resv_get()
+ */
+static inline void i915_vm_resv_put(struct dma_resv *resv)
+{
+	struct i915_address_space *vm = container_of(resv, typeof(*vm), _resv);
+
+	kref_put(&vm->resv_ref, i915_vm_resv_release);
+}
+
 static inline struct i915_address_space *
 i915_vm_open(struct i915_address_space *vm)
 {
diff --git a/drivers/gpu/drm/i915/gt/intel_ppgtt.c b/drivers/gpu/drm/i915/gt/intel_ppgtt.c
index 4e3d80c2295c..aee3a8929245 100644
--- a/drivers/gpu/drm/i915/gt/intel_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ppgtt.c
@@ -307,7 +307,7 @@ void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt)
 	ppgtt->vm.dma = i915->drm.dev;
 	ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size);
 
-	dma_resv_init(&ppgtt->vm.resv);
+	dma_resv_init(&ppgtt->vm._resv);
 	i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
 
 	ppgtt->vm.vma_ops.bind_vma    = ppgtt_bind_vma;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 2/7] drm/i915: Don't free shared locks while shared
@ 2021-05-11 13:25   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

We are currently sharing the VM reservation locks across a number of
gem objects with page-table memory. Since TTM will individiualize the
reservation locks when freeing objects, including accessing the shared
locks, make sure that the shared locks are not freed until that is done.
For PPGTT we add an additional refcount, for GGTT we flush the object
freeing workqueue before freeing the shared lock.

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_object.c    |  3 ++
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |  1 +
 drivers/gpu/drm/i915/gt/intel_ggtt.c          | 13 ++++--
 drivers/gpu/drm/i915/gt/intel_gtt.c           | 45 +++++++++++++++----
 drivers/gpu/drm/i915/gt/intel_gtt.h           | 29 +++++++++++-
 drivers/gpu/drm/i915/gt/intel_ppgtt.c         |  2 +-
 6 files changed, 80 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index 28144410df86..abadf0994ad0 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -252,6 +252,9 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
 		if (obj->mm.n_placements > 1)
 			kfree(obj->mm.placements);
 
+		if (obj->resv_shared_from)
+			i915_vm_resv_put(obj->resv_shared_from);
+
 		/* But keep the pointer alive for RCU-protected lookups */
 		call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
 		cond_resched();
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 0727d0c76aa0..450340a73186 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -149,6 +149,7 @@ struct drm_i915_gem_object {
 	 * when i915_gem_ww_ctx_backoff() or i915_gem_ww_ctx_fini() are called.
 	 */
 	struct list_head obj_link;
+	struct dma_resv *resv_shared_from;
 
 	union {
 		struct rcu_head rcu;
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
index 35069ca5d7de..128d781e429f 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
@@ -746,7 +746,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
 
 	mutex_unlock(&ggtt->vm.mutex);
 	i915_address_space_fini(&ggtt->vm);
-	dma_resv_fini(&ggtt->vm.resv);
+	/*
+	 * Make sure our pagetable gem objects have been freed,
+	 * so that nobody shares our reservation object anymore.
+	 */
+	i915_gem_flush_free_objects(ggtt->vm.i915);
+	GEM_WARN_ON(kref_read(&ggtt->vm.resv_ref) != 1);
+	dma_resv_fini(&ggtt->vm._resv);
 
 	arch_phys_wc_del(ggtt->mtrr);
 
@@ -829,6 +835,7 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
 		return -ENOMEM;
 	}
 
+	kref_init(&ggtt->vm.resv_ref);
 	ret = setup_scratch_page(&ggtt->vm);
 	if (ret) {
 		drm_err(&i915->drm, "Scratch setup failed\n");
@@ -1135,7 +1142,7 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt)
 	ggtt->vm.gt = gt;
 	ggtt->vm.i915 = i915;
 	ggtt->vm.dma = i915->drm.dev;
-	dma_resv_init(&ggtt->vm.resv);
+	dma_resv_init(&ggtt->vm._resv);
 
 	if (INTEL_GEN(i915) <= 5)
 		ret = i915_gmch_probe(ggtt);
@@ -1144,7 +1151,7 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt)
 	else
 		ret = gen8_gmch_probe(ggtt);
 	if (ret) {
-		dma_resv_fini(&ggtt->vm.resv);
+		dma_resv_fini(&ggtt->vm._resv);
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index 9b98f9d9faa3..695b22b17644 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -22,8 +22,11 @@ struct drm_i915_gem_object *alloc_pt_lmem(struct i915_address_space *vm, int sz)
 	 * object underneath, with the idea that one object_lock() will lock
 	 * them all at once.
 	 */
-	if (!IS_ERR(obj))
-		obj->base.resv = &vm->resv;
+	if (!IS_ERR(obj)) {
+		obj->base.resv = i915_vm_resv_get(vm);
+		obj->resv_shared_from = obj->base.resv;
+	}
+
 	return obj;
 }
 
@@ -40,8 +43,11 @@ struct drm_i915_gem_object *alloc_pt_dma(struct i915_address_space *vm, int sz)
 	 * object underneath, with the idea that one object_lock() will lock
 	 * them all at once.
 	 */
-	if (!IS_ERR(obj))
-		obj->base.resv = &vm->resv;
+	if (!IS_ERR(obj)) {
+		obj->base.resv = i915_vm_resv_get(vm);
+		obj->resv_shared_from = obj->base.resv;
+	}
+
 	return obj;
 }
 
@@ -102,7 +108,7 @@ void __i915_vm_close(struct i915_address_space *vm)
 int i915_vm_lock_objects(struct i915_address_space *vm,
 			 struct i915_gem_ww_ctx *ww)
 {
-	if (vm->scratch[0]->base.resv == &vm->resv) {
+	if (vm->scratch[0]->base.resv == &vm->_resv) {
 		return i915_gem_object_lock(vm->scratch[0], ww);
 	} else {
 		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
@@ -118,6 +124,22 @@ void i915_address_space_fini(struct i915_address_space *vm)
 	mutex_destroy(&vm->mutex);
 }
 
+/**
+ * i915_vm_resv_release - Final struct i915_address_space destructor
+ * @kref: Pointer to the &i915_address_space.resv_ref member.
+ *
+ * This function is called when the last lock sharer no longer shares the
+ * &i915_address_space._resv lock.
+ */
+void i915_vm_resv_release(struct kref *kref)
+{
+	struct i915_address_space *vm =
+		container_of(kref, typeof(*vm), resv_ref);
+
+	dma_resv_fini(&vm->_resv);
+	kfree(vm);
+}
+
 static void __i915_vm_release(struct work_struct *work)
 {
 	struct i915_address_space *vm =
@@ -125,9 +147,8 @@ static void __i915_vm_release(struct work_struct *work)
 
 	vm->cleanup(vm);
 	i915_address_space_fini(vm);
-	dma_resv_fini(&vm->resv);
 
-	kfree(vm);
+	i915_vm_resv_put(&vm->_resv);
 }
 
 void i915_vm_release(struct kref *kref)
@@ -144,6 +165,14 @@ void i915_vm_release(struct kref *kref)
 void i915_address_space_init(struct i915_address_space *vm, int subclass)
 {
 	kref_init(&vm->ref);
+
+	/*
+	 * Special case for GGTT that has already done an early
+	 * kref_init here.
+	 */
+	if (!kref_read(&vm->resv_ref))
+		kref_init(&vm->resv_ref);
+
 	INIT_RCU_WORK(&vm->rcu, __i915_vm_release);
 	atomic_set(&vm->open, 1);
 
@@ -170,7 +199,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
 		might_alloc(GFP_KERNEL);
 		mutex_release(&vm->mutex.dep_map, _THIS_IP_);
 	}
-	dma_resv_init(&vm->resv);
+	dma_resv_init(&vm->_resv);
 
 	GEM_BUG_ON(!vm->total);
 	drm_mm_init(&vm->mm, 0, vm->total);
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index ca00b45827b7..e760d4fadb43 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -245,7 +245,9 @@ struct i915_address_space {
 	atomic_t open;
 
 	struct mutex mutex; /* protects vma and our lists */
-	struct dma_resv resv; /* reservation lock for all pd objects, and buffer pool */
+
+	struct kref resv_ref; /* kref to keep the reservation lock alive. */
+	struct dma_resv _resv; /* reservation lock for all pd objects, and buffer pool */
 #define VM_CLASS_GGTT 0
 #define VM_CLASS_PPGTT 1
 #define VM_CLASS_DPT 2
@@ -404,13 +406,38 @@ i915_vm_get(struct i915_address_space *vm)
 	return vm;
 }
 
+/**
+ * i915_vm_resv_get - Obtain a reference on the vm's reservation lock
+ * @vm: The vm whose reservation lock we want to share.
+ *
+ * Return: A pointer to the vm's reservation lock.
+ */
+static inline struct dma_resv *i915_vm_resv_get(struct i915_address_space *vm)
+{
+	kref_get(&vm->resv_ref);
+	return &vm->_resv;
+}
+
 void i915_vm_release(struct kref *kref);
 
+void i915_vm_resv_release(struct kref *kref);
+
 static inline void i915_vm_put(struct i915_address_space *vm)
 {
 	kref_put(&vm->ref, i915_vm_release);
 }
 
+/**
+ * i915_vm_resv_put - Release a reference on the vm's reservation lock
+ * @resv: Pointer to a reservation lock obtained from i915_vm_resv_get()
+ */
+static inline void i915_vm_resv_put(struct dma_resv *resv)
+{
+	struct i915_address_space *vm = container_of(resv, typeof(*vm), _resv);
+
+	kref_put(&vm->resv_ref, i915_vm_resv_release);
+}
+
 static inline struct i915_address_space *
 i915_vm_open(struct i915_address_space *vm)
 {
diff --git a/drivers/gpu/drm/i915/gt/intel_ppgtt.c b/drivers/gpu/drm/i915/gt/intel_ppgtt.c
index 4e3d80c2295c..aee3a8929245 100644
--- a/drivers/gpu/drm/i915/gt/intel_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ppgtt.c
@@ -307,7 +307,7 @@ void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt)
 	ppgtt->vm.dma = i915->drm.dev;
 	ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size);
 
-	dma_resv_init(&ppgtt->vm.resv);
+	dma_resv_init(&ppgtt->vm._resv);
 	i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
 
 	ppgtt->vm.vma_ops.bind_vma    = ppgtt_bind_vma;
-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:25   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström, Christian König

Temporarily remove the buddy allocator and related selftests
and hook up the TTM range manager for i915 regions.

In order to support some of the mock region-related selftests, we need to
be able to initialize the TTM range-manager standalone without a struct
ttm_device. Add two functions to allow that to the TTM api.

Finally modify the mock region selftests somewhat to account for a
fragmenting manager.

Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/Kconfig                  |   1 +
 drivers/gpu/drm/i915/Makefile                 |   2 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
 drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
 drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
 drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
 drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
 drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
 drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
 drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
 drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
 drivers/gpu/drm/i915/i915_drv.c               |   8 +
 drivers/gpu/drm/i915/i915_drv.h               |   7 +-
 drivers/gpu/drm/i915/i915_gem.c               |   1 +
 drivers/gpu/drm/i915/i915_globals.c           |   1 -
 drivers/gpu/drm/i915/i915_globals.h           |   1 -
 drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
 drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
 drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
 drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
 drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
 drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
 drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------------
 .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
 .../drm/i915/selftests/intel_memory_region.c  | 133 +--
 drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
 drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
 include/drm/ttm/ttm_bo_driver.h               |  23 +
 31 files changed, 715 insertions(+), 1771 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
 delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c

diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 1e1cb245fca7..b63d374dff23 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -26,6 +26,7 @@ config DRM_I915
 	select SND_HDA_I915 if SND_HDA_CORE
 	select CEC_CORE if CEC_NOTIFIER
 	select VMAP_PFN
+	select DRM_TTM
 	help
 	  Choose this option if you have a system that has "Intel Graphics
 	  Media Accelerator" or "HD Graphics" integrated graphics,
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index d0d936d9137b..cb8823570996 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -50,6 +50,7 @@ i915-y += i915_drv.o \
 	  intel_memory_region.o \
 	  intel_pch.o \
 	  intel_pm.o \
+	  intel_region_ttm.o \
 	  intel_runtime_pm.o \
 	  intel_sideband.o \
 	  intel_step.o \
@@ -160,7 +161,6 @@ gem-y += \
 i915-y += \
 	  $(gem-y) \
 	  i915_active.o \
-	  i915_buddy.o \
 	  i915_cmd_parser.o \
 	  i915_gem_evict.o \
 	  i915_gem_gtt.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
index f44bdd08f7cb..f42803ea48f2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
@@ -4,16 +4,70 @@
  */
 
 #include "intel_memory_region.h"
+#include "intel_region_ttm.h"
 #include "gem/i915_gem_region.h"
 #include "gem/i915_gem_lmem.h"
 #include "i915_drv.h"
 
+static void lmem_put_pages(struct drm_i915_gem_object *obj,
+				  struct sg_table *pages)
+{
+	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
+	obj->mm.dirty = false;
+	sg_free_table(pages);
+	kfree(pages);
+}
+
+static int lmem_get_pages(struct drm_i915_gem_object *obj)
+{
+	unsigned int flags;
+	struct sg_table *pages;
+
+	flags = I915_ALLOC_MIN_PAGE_SIZE;
+	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
+		flags |= I915_ALLOC_CONTIGUOUS;
+
+	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
+							 obj->base.size,
+							 flags);
+	if (IS_ERR(obj->mm.st_mm_node))
+		return PTR_ERR(obj->mm.st_mm_node);
+
+	/* Range manager is always contigous */
+	if (obj->mm.region->is_range_manager)
+		obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
+	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
+	if (IS_ERR(pages))
+		return PTR_ERR(pages);
+
+	__i915_gem_object_set_pages(obj, pages,
+				    i915_sg_dma_page_sizes(pages->sgl));
+
+	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
+		void __iomem *vaddr =
+			i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
+
+		if (!vaddr) {
+			struct sg_table *pages =
+				__i915_gem_object_unset_pages(obj);
+
+			if (!IS_ERR_OR_NULL(pages))
+				lmem_put_pages(obj, pages);
+		}
+
+		memset_io(vaddr, 0, obj->base.size);
+		io_mapping_unmap(vaddr);
+	}
+
+	return 0;
+}
+
 const struct drm_i915_gem_object_ops i915_gem_lmem_obj_ops = {
 	.name = "i915_gem_object_lmem",
 	.flags = I915_GEM_OBJECT_HAS_IOMEM,
 
-	.get_pages = i915_gem_object_get_pages_buddy,
-	.put_pages = i915_gem_object_put_pages_buddy,
+	.get_pages = lmem_get_pages,
+	.put_pages = lmem_put_pages,
 	.release = i915_gem_object_release_memory_region,
 };
 
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 450340a73186..dbd7fffe956e 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -232,10 +232,12 @@ struct drm_i915_gem_object {
 		 * Memory region for this object.
 		 */
 		struct intel_memory_region *region;
+
 		/**
-		 * List of memory region blocks allocated for this object.
+		 * Memory manager node allocated for this object.
 		 */
-		struct list_head blocks;
+		void *st_mm_node;
+
 		/**
 		 * Element within memory_region->objects or region->purgeable
 		 * if the object is marked as DONTNEED. Access is protected by
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
index aed8a37ccdc9..62ee2185a41b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
@@ -473,7 +473,8 @@ __i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
 
 	might_sleep();
 	GEM_BUG_ON(n >= obj->base.size >> PAGE_SHIFT);
-	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
+	if (!i915_gem_object_has_pinned_pages(obj))
+		assert_object_held(obj);
 
 	/* As we iterate forward through the sg, we record each entry in a
 	 * radixtree for quick repeated (backwards) lookups. If we have seen
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
index ce8fcfc54079..f25e6646c5b7 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
@@ -8,129 +8,9 @@
 #include "i915_drv.h"
 #include "i915_trace.h"
 
-void
-i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
-				struct sg_table *pages)
-{
-	__intel_memory_region_put_pages_buddy(obj->mm.region, &obj->mm.blocks);
-
-	obj->mm.dirty = false;
-	sg_free_table(pages);
-	kfree(pages);
-}
-
-int
-i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
-{
-	const u64 max_segment = i915_sg_segment_size();
-	struct intel_memory_region *mem = obj->mm.region;
-	struct list_head *blocks = &obj->mm.blocks;
-	resource_size_t size = obj->base.size;
-	resource_size_t prev_end;
-	struct i915_buddy_block *block;
-	unsigned int flags;
-	struct sg_table *st;
-	struct scatterlist *sg;
-	unsigned int sg_page_sizes;
-	int ret;
-
-	st = kmalloc(sizeof(*st), GFP_KERNEL);
-	if (!st)
-		return -ENOMEM;
-
-	if (sg_alloc_table(st, size >> PAGE_SHIFT, GFP_KERNEL)) {
-		kfree(st);
-		return -ENOMEM;
-	}
-
-	flags = I915_ALLOC_MIN_PAGE_SIZE;
-	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
-		flags |= I915_ALLOC_CONTIGUOUS;
-
-	ret = __intel_memory_region_get_pages_buddy(mem, size, flags, blocks);
-	if (ret)
-		goto err_free_sg;
-
-	GEM_BUG_ON(list_empty(blocks));
-
-	sg = st->sgl;
-	st->nents = 0;
-	sg_page_sizes = 0;
-	prev_end = (resource_size_t)-1;
-
-	list_for_each_entry(block, blocks, link) {
-		u64 block_size, offset;
-
-		block_size = min_t(u64, size,
-				   i915_buddy_block_size(&mem->mm, block));
-		offset = i915_buddy_block_offset(block);
-
-		while (block_size) {
-			u64 len;
-
-			if (offset != prev_end || sg->length >= max_segment) {
-				if (st->nents) {
-					sg_page_sizes |= sg->length;
-					sg = __sg_next(sg);
-				}
-
-				sg_dma_address(sg) = mem->region.start + offset;
-				sg_dma_len(sg) = 0;
-				sg->length = 0;
-				st->nents++;
-			}
-
-			len = min(block_size, max_segment - sg->length);
-			sg->length += len;
-			sg_dma_len(sg) += len;
-
-			offset += len;
-			block_size -= len;
-
-			prev_end = offset;
-		}
-	}
-
-	sg_page_sizes |= sg->length;
-	sg_mark_end(sg);
-	i915_sg_trim(st);
-
-	/* Intended for kernel internal use only */
-	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
-		struct scatterlist *sg;
-		unsigned long i;
-
-		for_each_sg(st->sgl, sg, st->nents, i) {
-			unsigned int length;
-			void __iomem *vaddr;
-			dma_addr_t daddr;
-
-			daddr = sg_dma_address(sg);
-			daddr -= mem->region.start;
-			length = sg_dma_len(sg);
-
-			vaddr = io_mapping_map_wc(&mem->iomap, daddr, length);
-			memset64((void __force *)vaddr, 0, length / sizeof(u64));
-			io_mapping_unmap(vaddr);
-		}
-
-		wmb();
-	}
-
-	__i915_gem_object_set_pages(obj, st, sg_page_sizes);
-
-	return 0;
-
-err_free_sg:
-	sg_free_table(st);
-	kfree(st);
-	return ret;
-}
-
 void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
 					struct intel_memory_region *mem)
 {
-	INIT_LIST_HEAD(&obj->mm.blocks);
 	obj->mm.region = intel_memory_region_get(mem);
 
 	if (obj->base.size <= mem->min_page_size)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.h b/drivers/gpu/drm/i915/gem/i915_gem_region.h
index ebddc86d78f7..84fcb3297400 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_region.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_region.h
@@ -12,10 +12,6 @@ struct intel_memory_region;
 struct drm_i915_gem_object;
 struct sg_table;
 
-int i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj);
-void i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
-				     struct sg_table *pages);
-
 void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
 					struct intel_memory_region *mem);
 void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index a9bfa66c8da1..5d16c4462fda 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -628,11 +628,13 @@ static const struct intel_memory_region_ops shmem_region_ops = {
 	.init_object = shmem_object_init,
 };
 
-struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915)
+struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915,
+						 u16 type, u16 instance)
 {
 	return intel_memory_region_create(i915, 0,
 					  totalram_pages() << PAGE_SHIFT,
 					  PAGE_SIZE, 0,
+					  type, instance,
 					  &shmem_region_ops);
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
index 293f640faa0a..c42abee206da 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
@@ -770,7 +770,8 @@ static const struct intel_memory_region_ops i915_region_stolen_lmem_ops = {
 };
 
 struct intel_memory_region *
-i915_gem_stolen_lmem_setup(struct drm_i915_private *i915)
+i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance)
 {
 	struct intel_uncore *uncore = &i915->uncore;
 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
@@ -788,6 +789,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915)
 
 	mem = intel_memory_region_create(i915, lmem_base, lmem_size,
 					 I915_GTT_PAGE_SIZE_4K, io_start,
+					 type, instance,
 					 &i915_region_stolen_lmem_ops);
 	if (IS_ERR(mem))
 		return mem;
@@ -809,14 +811,15 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915)
 }
 
 struct intel_memory_region*
-i915_gem_stolen_smem_setup(struct drm_i915_private *i915)
+i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance)
 {
 	struct intel_memory_region *mem;
 
 	mem = intel_memory_region_create(i915,
 					 intel_graphics_stolen_res.start,
 					 resource_size(&intel_graphics_stolen_res),
-					 PAGE_SIZE, 0,
+					 PAGE_SIZE, 0, type, instance,
 					 &i915_region_stolen_smem_ops);
 	if (IS_ERR(mem))
 		return mem;
@@ -824,7 +827,6 @@ i915_gem_stolen_smem_setup(struct drm_i915_private *i915)
 	intel_memory_region_set_name(mem, "stolen-system");
 
 	mem->private = true;
-
 	return mem;
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
index 2bec6c367b9c..ccdf7befc571 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
@@ -21,8 +21,13 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv,
 					 u64 end);
 void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
 				 struct drm_mm_node *node);
-struct intel_memory_region *i915_gem_stolen_smem_setup(struct drm_i915_private *i915);
-struct intel_memory_region *i915_gem_stolen_lmem_setup(struct drm_i915_private *i915);
+struct intel_memory_region *
+i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance);
+struct intel_memory_region *
+i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance);
+
 struct drm_i915_gem_object *
 i915_gem_object_create_stolen(struct drm_i915_private *dev_priv,
 			      resource_size_t size);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
index 8d77dcbad059..3f88ecdee031 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -68,8 +68,6 @@ int intel_gt_probe_lmem(struct intel_gt *gt)
 	id = INTEL_REGION_LMEM;
 
 	mem->id = id;
-	mem->type = INTEL_MEMORY_LOCAL;
-	mem->instance = 0;
 
 	intel_memory_region_set_name(mem, "local%u", mem->instance);
 
diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
index 73fceb0c25fc..f7366b054f8e 100644
--- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c
+++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
@@ -5,6 +5,8 @@
 
 #include "i915_drv.h"
 #include "intel_memory_region.h"
+#include "intel_region_lmem.h"
+#include "intel_region_ttm.h"
 #include "gem/i915_gem_lmem.h"
 #include "gem/i915_gem_region.h"
 #include "intel_region_lmem.h"
@@ -66,9 +68,9 @@ static void release_fake_lmem_bar(struct intel_memory_region *mem)
 static void
 region_lmem_release(struct intel_memory_region *mem)
 {
-	release_fake_lmem_bar(mem);
+	intel_region_ttm_fini(mem);
 	io_mapping_fini(&mem->iomap);
-	intel_memory_region_release_buddy(mem);
+	release_fake_lmem_bar(mem);
 }
 
 static int
@@ -83,12 +85,21 @@ region_lmem_init(struct intel_memory_region *mem)
 
 	if (!io_mapping_init_wc(&mem->iomap,
 				mem->io_start,
-				resource_size(&mem->region)))
-		return -EIO;
+				resource_size(&mem->region))) {
+		ret = -EIO;
+		goto out_no_io;
+	}
 
-	ret = intel_memory_region_init_buddy(mem);
+	ret = intel_region_ttm_init(mem);
 	if (ret)
-		io_mapping_fini(&mem->iomap);
+		goto out_no_buddy;
+
+	return 0;
+
+out_no_buddy:
+	io_mapping_fini(&mem->iomap);
+out_no_io:
+	release_fake_lmem_bar(mem);
 
 	return ret;
 }
@@ -127,6 +138,8 @@ intel_gt_setup_fake_lmem(struct intel_gt *gt)
 					 mappable_end,
 					 PAGE_SIZE,
 					 io_start,
+					 INTEL_MEMORY_LOCAL,
+					 0,
 					 &intel_region_lmem_ops);
 	if (!IS_ERR(mem)) {
 		drm_info(&i915->drm, "Intel graphics fake LMEM: %pR\n",
@@ -198,6 +211,8 @@ static struct intel_memory_region *setup_lmem(struct intel_gt *gt)
 					 lmem_size,
 					 I915_GTT_PAGE_SIZE_4K,
 					 io_start,
+					 INTEL_MEMORY_LOCAL,
+					 0,
 					 &intel_region_lmem_ops);
 	if (IS_ERR(mem))
 		return mem;
diff --git a/drivers/gpu/drm/i915/i915_buddy.c b/drivers/gpu/drm/i915/i915_buddy.c
deleted file mode 100644
index 3a2f6eecb2fc..000000000000
--- a/drivers/gpu/drm/i915/i915_buddy.c
+++ /dev/null
@@ -1,435 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include <linux/kmemleak.h>
-#include <linux/slab.h>
-
-#include "i915_buddy.h"
-
-#include "i915_gem.h"
-#include "i915_globals.h"
-#include "i915_utils.h"
-
-static struct i915_global_block {
-	struct i915_global base;
-	struct kmem_cache *slab_blocks;
-} global;
-
-static void i915_global_buddy_shrink(void)
-{
-	kmem_cache_shrink(global.slab_blocks);
-}
-
-static void i915_global_buddy_exit(void)
-{
-	kmem_cache_destroy(global.slab_blocks);
-}
-
-static struct i915_global_block global = { {
-	.shrink = i915_global_buddy_shrink,
-	.exit = i915_global_buddy_exit,
-} };
-
-int __init i915_global_buddy_init(void)
-{
-	global.slab_blocks = KMEM_CACHE(i915_buddy_block, SLAB_HWCACHE_ALIGN);
-	if (!global.slab_blocks)
-		return -ENOMEM;
-
-	i915_global_register(&global.base);
-	return 0;
-}
-
-static struct i915_buddy_block *i915_block_alloc(struct i915_buddy_block *parent,
-						 unsigned int order,
-						 u64 offset)
-{
-	struct i915_buddy_block *block;
-
-	GEM_BUG_ON(order > I915_BUDDY_MAX_ORDER);
-
-	block = kmem_cache_zalloc(global.slab_blocks, GFP_KERNEL);
-	if (!block)
-		return NULL;
-
-	block->header = offset;
-	block->header |= order;
-	block->parent = parent;
-
-	GEM_BUG_ON(block->header & I915_BUDDY_HEADER_UNUSED);
-	return block;
-}
-
-static void i915_block_free(struct i915_buddy_block *block)
-{
-	kmem_cache_free(global.slab_blocks, block);
-}
-
-static void mark_allocated(struct i915_buddy_block *block)
-{
-	block->header &= ~I915_BUDDY_HEADER_STATE;
-	block->header |= I915_BUDDY_ALLOCATED;
-
-	list_del(&block->link);
-}
-
-static void mark_free(struct i915_buddy_mm *mm,
-		      struct i915_buddy_block *block)
-{
-	block->header &= ~I915_BUDDY_HEADER_STATE;
-	block->header |= I915_BUDDY_FREE;
-
-	list_add(&block->link,
-		 &mm->free_list[i915_buddy_block_order(block)]);
-}
-
-static void mark_split(struct i915_buddy_block *block)
-{
-	block->header &= ~I915_BUDDY_HEADER_STATE;
-	block->header |= I915_BUDDY_SPLIT;
-
-	list_del(&block->link);
-}
-
-int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size)
-{
-	unsigned int i;
-	u64 offset;
-
-	if (size < chunk_size)
-		return -EINVAL;
-
-	if (chunk_size < PAGE_SIZE)
-		return -EINVAL;
-
-	if (!is_power_of_2(chunk_size))
-		return -EINVAL;
-
-	size = round_down(size, chunk_size);
-
-	mm->size = size;
-	mm->chunk_size = chunk_size;
-	mm->max_order = ilog2(size) - ilog2(chunk_size);
-
-	GEM_BUG_ON(mm->max_order > I915_BUDDY_MAX_ORDER);
-
-	mm->free_list = kmalloc_array(mm->max_order + 1,
-				      sizeof(struct list_head),
-				      GFP_KERNEL);
-	if (!mm->free_list)
-		return -ENOMEM;
-
-	for (i = 0; i <= mm->max_order; ++i)
-		INIT_LIST_HEAD(&mm->free_list[i]);
-
-	mm->n_roots = hweight64(size);
-
-	mm->roots = kmalloc_array(mm->n_roots,
-				  sizeof(struct i915_buddy_block *),
-				  GFP_KERNEL);
-	if (!mm->roots)
-		goto out_free_list;
-
-	offset = 0;
-	i = 0;
-
-	/*
-	 * Split into power-of-two blocks, in case we are given a size that is
-	 * not itself a power-of-two.
-	 */
-	do {
-		struct i915_buddy_block *root;
-		unsigned int order;
-		u64 root_size;
-
-		root_size = rounddown_pow_of_two(size);
-		order = ilog2(root_size) - ilog2(chunk_size);
-
-		root = i915_block_alloc(NULL, order, offset);
-		if (!root)
-			goto out_free_roots;
-
-		mark_free(mm, root);
-
-		GEM_BUG_ON(i > mm->max_order);
-		GEM_BUG_ON(i915_buddy_block_size(mm, root) < chunk_size);
-
-		mm->roots[i] = root;
-
-		offset += root_size;
-		size -= root_size;
-		i++;
-	} while (size);
-
-	return 0;
-
-out_free_roots:
-	while (i--)
-		i915_block_free(mm->roots[i]);
-	kfree(mm->roots);
-out_free_list:
-	kfree(mm->free_list);
-	return -ENOMEM;
-}
-
-void i915_buddy_fini(struct i915_buddy_mm *mm)
-{
-	int i;
-
-	for (i = 0; i < mm->n_roots; ++i) {
-		GEM_WARN_ON(!i915_buddy_block_is_free(mm->roots[i]));
-		i915_block_free(mm->roots[i]);
-	}
-
-	kfree(mm->roots);
-	kfree(mm->free_list);
-}
-
-static int split_block(struct i915_buddy_mm *mm,
-		       struct i915_buddy_block *block)
-{
-	unsigned int block_order = i915_buddy_block_order(block) - 1;
-	u64 offset = i915_buddy_block_offset(block);
-
-	GEM_BUG_ON(!i915_buddy_block_is_free(block));
-	GEM_BUG_ON(!i915_buddy_block_order(block));
-
-	block->left = i915_block_alloc(block, block_order, offset);
-	if (!block->left)
-		return -ENOMEM;
-
-	block->right = i915_block_alloc(block, block_order,
-					offset + (mm->chunk_size << block_order));
-	if (!block->right) {
-		i915_block_free(block->left);
-		return -ENOMEM;
-	}
-
-	mark_free(mm, block->left);
-	mark_free(mm, block->right);
-
-	mark_split(block);
-
-	return 0;
-}
-
-static struct i915_buddy_block *
-get_buddy(struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *parent;
-
-	parent = block->parent;
-	if (!parent)
-		return NULL;
-
-	if (parent->left == block)
-		return parent->right;
-
-	return parent->left;
-}
-
-static void __i915_buddy_free(struct i915_buddy_mm *mm,
-			      struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *parent;
-
-	while ((parent = block->parent)) {
-		struct i915_buddy_block *buddy;
-
-		buddy = get_buddy(block);
-
-		if (!i915_buddy_block_is_free(buddy))
-			break;
-
-		list_del(&buddy->link);
-
-		i915_block_free(block);
-		i915_block_free(buddy);
-
-		block = parent;
-	}
-
-	mark_free(mm, block);
-}
-
-void i915_buddy_free(struct i915_buddy_mm *mm,
-		     struct i915_buddy_block *block)
-{
-	GEM_BUG_ON(!i915_buddy_block_is_allocated(block));
-	__i915_buddy_free(mm, block);
-}
-
-void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects)
-{
-	struct i915_buddy_block *block, *on;
-
-	list_for_each_entry_safe(block, on, objects, link) {
-		i915_buddy_free(mm, block);
-		cond_resched();
-	}
-	INIT_LIST_HEAD(objects);
-}
-
-/*
- * Allocate power-of-two block. The order value here translates to:
- *
- *   0 = 2^0 * mm->chunk_size
- *   1 = 2^1 * mm->chunk_size
- *   2 = 2^2 * mm->chunk_size
- *   ...
- */
-struct i915_buddy_block *
-i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order)
-{
-	struct i915_buddy_block *block = NULL;
-	unsigned int i;
-	int err;
-
-	for (i = order; i <= mm->max_order; ++i) {
-		block = list_first_entry_or_null(&mm->free_list[i],
-						 struct i915_buddy_block,
-						 link);
-		if (block)
-			break;
-	}
-
-	if (!block)
-		return ERR_PTR(-ENOSPC);
-
-	GEM_BUG_ON(!i915_buddy_block_is_free(block));
-
-	while (i != order) {
-		err = split_block(mm, block);
-		if (unlikely(err))
-			goto out_free;
-
-		/* Go low */
-		block = block->left;
-		i--;
-	}
-
-	mark_allocated(block);
-	kmemleak_update_trace(block);
-	return block;
-
-out_free:
-	if (i != order)
-		__i915_buddy_free(mm, block);
-	return ERR_PTR(err);
-}
-
-static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
-{
-	return s1 <= e2 && e1 >= s2;
-}
-
-static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
-{
-	return s1 <= s2 && e1 >= e2;
-}
-
-/*
- * Allocate range. Note that it's safe to chain together multiple alloc_ranges
- * with the same blocks list.
- *
- * Intended for pre-allocating portions of the address space, for example to
- * reserve a block for the initial framebuffer or similar, hence the expectation
- * here is that i915_buddy_alloc() is still the main vehicle for
- * allocations, so if that's not the case then the drm_mm range allocator is
- * probably a much better fit, and so you should probably go use that instead.
- */
-int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
-			   struct list_head *blocks,
-			   u64 start, u64 size)
-{
-	struct i915_buddy_block *block;
-	struct i915_buddy_block *buddy;
-	LIST_HEAD(allocated);
-	LIST_HEAD(dfs);
-	u64 end;
-	int err;
-	int i;
-
-	if (size < mm->chunk_size)
-		return -EINVAL;
-
-	if (!IS_ALIGNED(size | start, mm->chunk_size))
-		return -EINVAL;
-
-	if (range_overflows(start, size, mm->size))
-		return -EINVAL;
-
-	for (i = 0; i < mm->n_roots; ++i)
-		list_add_tail(&mm->roots[i]->tmp_link, &dfs);
-
-	end = start + size - 1;
-
-	do {
-		u64 block_start;
-		u64 block_end;
-
-		block = list_first_entry_or_null(&dfs,
-						 struct i915_buddy_block,
-						 tmp_link);
-		if (!block)
-			break;
-
-		list_del(&block->tmp_link);
-
-		block_start = i915_buddy_block_offset(block);
-		block_end = block_start + i915_buddy_block_size(mm, block) - 1;
-
-		if (!overlaps(start, end, block_start, block_end))
-			continue;
-
-		if (i915_buddy_block_is_allocated(block)) {
-			err = -ENOSPC;
-			goto err_free;
-		}
-
-		if (contains(start, end, block_start, block_end)) {
-			if (!i915_buddy_block_is_free(block)) {
-				err = -ENOSPC;
-				goto err_free;
-			}
-
-			mark_allocated(block);
-			list_add_tail(&block->link, &allocated);
-			continue;
-		}
-
-		if (!i915_buddy_block_is_split(block)) {
-			err = split_block(mm, block);
-			if (unlikely(err))
-				goto err_undo;
-		}
-
-		list_add(&block->right->tmp_link, &dfs);
-		list_add(&block->left->tmp_link, &dfs);
-	} while (1);
-
-	list_splice_tail(&allocated, blocks);
-	return 0;
-
-err_undo:
-	/*
-	 * We really don't want to leave around a bunch of split blocks, since
-	 * bigger is better, so make sure we merge everything back before we
-	 * free the allocated blocks.
-	 */
-	buddy = get_buddy(block);
-	if (buddy &&
-	    (i915_buddy_block_is_free(block) &&
-	     i915_buddy_block_is_free(buddy)))
-		__i915_buddy_free(mm, block);
-
-err_free:
-	i915_buddy_free_list(mm, &allocated);
-	return err;
-}
-
-#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
-#include "selftests/i915_buddy.c"
-#endif
diff --git a/drivers/gpu/drm/i915/i915_buddy.h b/drivers/gpu/drm/i915/i915_buddy.h
deleted file mode 100644
index 9ce5200f4001..000000000000
--- a/drivers/gpu/drm/i915/i915_buddy.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __I915_BUDDY_H__
-#define __I915_BUDDY_H__
-
-#include <linux/bitops.h>
-#include <linux/list.h>
-
-struct i915_buddy_block {
-#define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
-#define I915_BUDDY_HEADER_STATE  GENMASK_ULL(11, 10)
-#define   I915_BUDDY_ALLOCATED	   (1 << 10)
-#define   I915_BUDDY_FREE	   (2 << 10)
-#define   I915_BUDDY_SPLIT	   (3 << 10)
-/* Free to be used, if needed in the future */
-#define I915_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6)
-#define I915_BUDDY_HEADER_ORDER  GENMASK_ULL(5, 0)
-	u64 header;
-
-	struct i915_buddy_block *left;
-	struct i915_buddy_block *right;
-	struct i915_buddy_block *parent;
-
-	void *private; /* owned by creator */
-
-	/*
-	 * While the block is allocated by the user through i915_buddy_alloc*,
-	 * the user has ownership of the link, for example to maintain within
-	 * a list, if so desired. As soon as the block is freed with
-	 * i915_buddy_free* ownership is given back to the mm.
-	 */
-	struct list_head link;
-	struct list_head tmp_link;
-};
-
-/* Order-zero must be at least PAGE_SIZE */
-#define I915_BUDDY_MAX_ORDER (63 - PAGE_SHIFT)
-
-/*
- * Binary Buddy System.
- *
- * Locking should be handled by the user, a simple mutex around
- * i915_buddy_alloc* and i915_buddy_free* should suffice.
- */
-struct i915_buddy_mm {
-	/* Maintain a free list for each order. */
-	struct list_head *free_list;
-
-	/*
-	 * Maintain explicit binary tree(s) to track the allocation of the
-	 * address space. This gives us a simple way of finding a buddy block
-	 * and performing the potentially recursive merge step when freeing a
-	 * block.  Nodes are either allocated or free, in which case they will
-	 * also exist on the respective free list.
-	 */
-	struct i915_buddy_block **roots;
-
-	/*
-	 * Anything from here is public, and remains static for the lifetime of
-	 * the mm. Everything above is considered do-not-touch.
-	 */
-	unsigned int n_roots;
-	unsigned int max_order;
-
-	/* Must be at least PAGE_SIZE */
-	u64 chunk_size;
-	u64 size;
-};
-
-static inline u64
-i915_buddy_block_offset(struct i915_buddy_block *block)
-{
-	return block->header & I915_BUDDY_HEADER_OFFSET;
-}
-
-static inline unsigned int
-i915_buddy_block_order(struct i915_buddy_block *block)
-{
-	return block->header & I915_BUDDY_HEADER_ORDER;
-}
-
-static inline unsigned int
-i915_buddy_block_state(struct i915_buddy_block *block)
-{
-	return block->header & I915_BUDDY_HEADER_STATE;
-}
-
-static inline bool
-i915_buddy_block_is_allocated(struct i915_buddy_block *block)
-{
-	return i915_buddy_block_state(block) == I915_BUDDY_ALLOCATED;
-}
-
-static inline bool
-i915_buddy_block_is_free(struct i915_buddy_block *block)
-{
-	return i915_buddy_block_state(block) == I915_BUDDY_FREE;
-}
-
-static inline bool
-i915_buddy_block_is_split(struct i915_buddy_block *block)
-{
-	return i915_buddy_block_state(block) == I915_BUDDY_SPLIT;
-}
-
-static inline u64
-i915_buddy_block_size(struct i915_buddy_mm *mm,
-		      struct i915_buddy_block *block)
-{
-	return mm->chunk_size << i915_buddy_block_order(block);
-}
-
-int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size);
-
-void i915_buddy_fini(struct i915_buddy_mm *mm);
-
-struct i915_buddy_block *
-i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order);
-
-int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
-			   struct list_head *blocks,
-			   u64 start, u64 size);
-
-void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block *block);
-
-void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects);
-
-#endif
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 5118dc8386b2..c89ed09b8d63 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -84,6 +84,7 @@
 #include "intel_gvt.h"
 #include "intel_memory_region.h"
 #include "intel_pm.h"
+#include "intel_region_ttm.h"
 #include "intel_sideband.h"
 #include "vlv_suspend.h"
 
@@ -335,6 +336,10 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
 	if (ret < 0)
 		goto err_workqueues;
 
+	ret = intel_region_ttm_device_init(dev_priv);
+	if (ret)
+		goto err_ttm;
+
 	intel_wopcm_init_early(&dev_priv->wopcm);
 
 	intel_gt_init_early(&dev_priv->gt, dev_priv);
@@ -359,6 +364,8 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
 err_gem:
 	i915_gem_cleanup_early(dev_priv);
 	intel_gt_driver_late_release(&dev_priv->gt);
+	intel_region_ttm_device_fini(dev_priv);
+err_ttm:
 	vlv_suspend_cleanup(dev_priv);
 err_workqueues:
 	i915_workqueues_cleanup(dev_priv);
@@ -376,6 +383,7 @@ static void i915_driver_late_release(struct drm_i915_private *dev_priv)
 	intel_power_domains_cleanup(dev_priv);
 	i915_gem_cleanup_early(dev_priv);
 	intel_gt_driver_late_release(&dev_priv->gt);
+	intel_region_ttm_device_fini(dev_priv);
 	vlv_suspend_cleanup(dev_priv);
 	i915_workqueues_cleanup(dev_priv);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 128198e8b4d0..1276a2f60740 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -60,6 +60,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_connector.h>
 #include <drm/i915_mei_hdcp_interface.h>
+#include <drm/ttm/ttm_device.h>
 
 #include "i915_params.h"
 #include "i915_reg.h"
@@ -1166,6 +1167,9 @@ struct drm_i915_private {
 	/* Mutex to protect the above hdcp component related values. */
 	struct mutex hdcp_comp_mutex;
 
+	/* The TTM device structure. */
+	struct ttm_device bdev;
+
 	I915_SELFTEST_DECLARE(struct i915_selftest_stash selftest;)
 
 	/*
@@ -1751,7 +1755,8 @@ void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv);
 void i915_gem_init_early(struct drm_i915_private *dev_priv);
 void i915_gem_cleanup_early(struct drm_i915_private *dev_priv);
 
-struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915);
+struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915,
+						 u16 type, u16 instance);
 
 static inline void i915_gem_drain_freed_objects(struct drm_i915_private *i915)
 {
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d0018c5f88bd..180f6e9107d4 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1109,6 +1109,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
 	}
 
 	i915_gem_drain_freed_objects(dev_priv);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_globals.c b/drivers/gpu/drm/i915/i915_globals.c
index 3aa213684293..77f1911c463b 100644
--- a/drivers/gpu/drm/i915/i915_globals.c
+++ b/drivers/gpu/drm/i915/i915_globals.c
@@ -87,7 +87,6 @@ static void __i915_globals_cleanup(void)
 
 static __initconst int (* const initfn[])(void) = {
 	i915_global_active_init,
-	i915_global_buddy_init,
 	i915_global_context_init,
 	i915_global_gem_context_init,
 	i915_global_objects_init,
diff --git a/drivers/gpu/drm/i915/i915_globals.h b/drivers/gpu/drm/i915/i915_globals.h
index b2f5cd9b9b1a..2d199f411a4a 100644
--- a/drivers/gpu/drm/i915/i915_globals.h
+++ b/drivers/gpu/drm/i915/i915_globals.h
@@ -27,7 +27,6 @@ void i915_globals_exit(void);
 
 /* constructors */
 int i915_global_active_init(void);
-int i915_global_buddy_init(void);
 int i915_global_context_init(void);
 int i915_global_gem_context_init(void);
 int i915_global_objects_init(void);
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
index cc6b3846a8c7..69e9e6c3135e 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -6,6 +6,10 @@
 
 #include "i915_scatterlist.h"
 
+#include <drm/drm_mm.h>
+
+#include <linux/slab.h>
+
 bool i915_sg_trim(struct sg_table *orig_st)
 {
 	struct sg_table new_st;
@@ -34,6 +38,72 @@ bool i915_sg_trim(struct sg_table *orig_st)
 	return true;
 }
 
+/**
+ * i915_sg_from_mm_node - Create an sg_table from a struct drm_mm_node
+ * @node: The drm_mm_node.
+ * @region_start: An offset to add to the dma addresses of the sg list.
+ *
+ * Create a struct sg_table, initializing it from a struct drm_mm_node,
+ * taking a maximum segment length into account, splitting into segments
+ * if necessary.
+ *
+ * Return: A pointer to a kmalloced struct sg_table on success, negative
+ * error code cast to an error pointer on failure.
+ */
+struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
+				      u64 region_start)
+{
+	const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
+	u64 segment_pages = max_segment >> PAGE_SHIFT;
+	u64 block_size, offset, prev_end;
+	struct sg_table *st;
+	struct scatterlist *sg;
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	if (sg_alloc_table(st, DIV_ROUND_UP(node->size, segment_pages),
+			   GFP_KERNEL)) {
+		kfree(st);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sg = st->sgl;
+	st->nents = 0;
+	prev_end = (resource_size_t)-1;
+	block_size = node->size << PAGE_SHIFT;
+	offset = node->start << PAGE_SHIFT;
+
+	while (block_size) {
+		u64 len;
+
+		if (offset != prev_end || sg->length >= max_segment) {
+			if (st->nents)
+				sg = __sg_next(sg);
+
+			sg_dma_address(sg) = region_start + offset;
+			sg_dma_len(sg) = 0;
+			sg->length = 0;
+			st->nents++;
+		}
+
+		len = min(block_size, max_segment - sg->length);
+		sg->length += len;
+		sg_dma_len(sg) += len;
+
+		offset += len;
+		block_size -= len;
+
+		prev_end = offset;
+	}
+
+	sg_mark_end(sg);
+	i915_sg_trim(st);
+
+	return st;
+}
+
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftests/scatterlist.c"
 #endif
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h
index 9cb26a224034..75c320020780 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.h
+++ b/drivers/gpu/drm/i915/i915_scatterlist.h
@@ -13,6 +13,8 @@
 
 #include "i915_gem.h"
 
+struct drm_mm_node;
+
 /*
  * Optimised SGL iterator for GEM objects
  */
@@ -133,4 +135,37 @@ static inline unsigned int i915_sg_segment_size(void)
 
 bool i915_sg_trim(struct sg_table *orig_st);
 
+/**
+ * i915_sg_dma_page_sizes - Calculate page sizes from a scatterlist
+ * @sg: The scatterlist from which to calculate page sizes
+ *
+ * Return: a value with bits sets for relevant page sizes.
+ */
+static inline unsigned int i915_sg_dma_page_sizes(struct scatterlist *sg)
+{
+	unsigned int page_sizes;
+
+	page_sizes = 0;
+	while (sg) {
+		GEM_BUG_ON(sg->offset);
+		GEM_BUG_ON(!IS_ALIGNED(sg->dma_length, PAGE_SIZE));
+		page_sizes |= sg->dma_length;
+		sg = __sg_next(sg);
+	}
+
+	/*
+	 * Is this necessary to support building large GPU pages from
+	 * even larger segments?
+	 */
+
+	if (page_sizes > SZ_64K)
+		page_sizes |= SZ_64K;
+	if (page_sizes > SZ_2M)
+		page_sizes |= SZ_2M;
+
+	return page_sizes;
+}
+
+struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
+				      u64 region_start);
 #endif
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index d98e8b81d322..4092cc987679 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -28,6 +28,11 @@ static const struct {
 	},
 };
 
+struct intel_region_reserve {
+	struct list_head link;
+	void *node;
+};
+
 struct intel_memory_region *
 intel_memory_region_lookup(struct drm_i915_private *i915,
 			   u16 class, u16 instance)
@@ -58,146 +63,61 @@ intel_memory_region_by_type(struct drm_i915_private *i915,
 	return NULL;
 }
 
-static u64
-intel_memory_region_free_pages(struct intel_memory_region *mem,
-			       struct list_head *blocks)
+/**
+ * intel_memory_region_unreserve - Unreserve all previously reserved
+ * ranges
+ * @mem: The region containing the reserved ranges.
+ */
+void intel_memory_region_unreserve(struct intel_memory_region *mem)
 {
-	struct i915_buddy_block *block, *on;
-	u64 size = 0;
+	struct intel_region_reserve *reserve, *next;
 
-	list_for_each_entry_safe(block, on, blocks, link) {
-		size += i915_buddy_block_size(&mem->mm, block);
-		i915_buddy_free(&mem->mm, block);
-	}
-	INIT_LIST_HEAD(blocks);
+	if (!mem->priv_ops || !mem->priv_ops->free)
+		return;
 
-	return size;
-}
-
-void
-__intel_memory_region_put_pages_buddy(struct intel_memory_region *mem,
-				      struct list_head *blocks)
-{
 	mutex_lock(&mem->mm_lock);
-	mem->avail += intel_memory_region_free_pages(mem, blocks);
-	mutex_unlock(&mem->mm_lock);
-}
-
-void
-__intel_memory_region_put_block_buddy(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);
-}
-
-int
-__intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
-				      resource_size_t size,
-				      unsigned int flags,
-				      struct list_head *blocks)
-{
-	unsigned int min_order = 0;
-	unsigned long n_pages;
-
-	GEM_BUG_ON(!IS_ALIGNED(size, mem->mm.chunk_size));
-	GEM_BUG_ON(!list_empty(blocks));
-
-	if (flags & I915_ALLOC_MIN_PAGE_SIZE) {
-		min_order = ilog2(mem->min_page_size) -
-			    ilog2(mem->mm.chunk_size);
-	}
-
-	if (flags & I915_ALLOC_CONTIGUOUS) {
-		size = roundup_pow_of_two(size);
-		min_order = ilog2(size) - ilog2(mem->mm.chunk_size);
+	list_for_each_entry_safe(reserve, next, &mem->reserved, link) {
+		list_del(&reserve->link);
+		mem->priv_ops->free(mem, reserve->node);
+		kfree(reserve);
 	}
-
-	if (size > mem->mm.size)
-		return -E2BIG;
-
-	n_pages = size >> ilog2(mem->mm.chunk_size);
-
-	mutex_lock(&mem->mm_lock);
-
-	do {
-		struct i915_buddy_block *block;
-		unsigned int order;
-
-		order = fls(n_pages) - 1;
-		GEM_BUG_ON(order > mem->mm.max_order);
-		GEM_BUG_ON(order < min_order);
-
-		do {
-			block = i915_buddy_alloc(&mem->mm, order);
-			if (!IS_ERR(block))
-				break;
-
-			if (order-- == min_order)
-				goto err_free_blocks;
-		} while (1);
-
-		n_pages -= BIT(order);
-
-		block->private = mem;
-		list_add_tail(&block->link, blocks);
-
-		if (!n_pages)
-			break;
-	} while (1);
-
-	mem->avail -= size;
 	mutex_unlock(&mem->mm_lock);
-	return 0;
-
-err_free_blocks:
-	intel_memory_region_free_pages(mem, blocks);
-	mutex_unlock(&mem->mm_lock);
-	return -ENXIO;
 }
 
-struct i915_buddy_block *
-__intel_memory_region_get_block_buddy(struct intel_memory_region *mem,
-				      resource_size_t size,
-				      unsigned int flags)
+/**
+ * intel_memory_region_reserve - Reserve a memory range
+ * @mem: The region for which we want to reserve a range.
+ * @offset: Start of the range to reserve.
+ * @size: The size of the range to reserve.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int intel_memory_region_reserve(struct intel_memory_region *mem,
+				resource_size_t offset,
+				resource_size_t size)
 {
-	struct i915_buddy_block *block;
-	LIST_HEAD(blocks);
 	int ret;
+	struct intel_region_reserve *reserve;
 
-	ret = __intel_memory_region_get_pages_buddy(mem, size, flags, &blocks);
-	if (ret)
-		return ERR_PTR(ret);
+	if (!mem->priv_ops || !mem->priv_ops->reserve)
+		return -EINVAL;
 
-	block = list_first_entry(&blocks, typeof(*block), link);
-	list_del_init(&block->link);
-	return block;
-}
+	reserve = kzalloc(sizeof(*reserve), GFP_KERNEL);
+	if (!reserve)
+		return -ENOMEM;
 
-int intel_memory_region_init_buddy(struct intel_memory_region *mem)
-{
-	return i915_buddy_init(&mem->mm, resource_size(&mem->region),
-			       PAGE_SIZE);
-}
-
-void intel_memory_region_release_buddy(struct intel_memory_region *mem)
-{
-	i915_buddy_free_list(&mem->mm, &mem->reserved);
-	i915_buddy_fini(&mem->mm);
-}
-
-int intel_memory_region_reserve(struct intel_memory_region *mem,
-				u64 offset, u64 size)
-{
-	int ret;
+	reserve->node = mem->priv_ops->reserve(mem, offset, size);
+	if (IS_ERR(reserve->node)) {
+		ret = PTR_ERR(reserve->node);
+		kfree(reserve);
+		return ret;
+	}
 
 	mutex_lock(&mem->mm_lock);
-	ret = i915_buddy_alloc_range(&mem->mm, &mem->reserved, offset, size);
+	list_add_tail(&reserve->link, &mem->reserved);
 	mutex_unlock(&mem->mm_lock);
 
-	return ret;
+	return 0;
 }
 
 struct intel_memory_region *
@@ -206,6 +126,8 @@ intel_memory_region_create(struct drm_i915_private *i915,
 			   resource_size_t size,
 			   resource_size_t min_page_size,
 			   resource_size_t io_start,
+			   u16 type,
+			   u16 instance,
 			   const struct intel_memory_region_ops *ops)
 {
 	struct intel_memory_region *mem;
@@ -222,6 +144,8 @@ intel_memory_region_create(struct drm_i915_private *i915,
 	mem->ops = ops;
 	mem->total = size;
 	mem->avail = mem->total;
+	mem->type = type;
+	mem->instance = instance;
 
 	mutex_init(&mem->objects.lock);
 	INIT_LIST_HEAD(&mem->objects.list);
@@ -259,6 +183,7 @@ static void __intel_memory_region_destroy(struct kref *kref)
 	struct intel_memory_region *mem =
 		container_of(kref, typeof(*mem), kref);
 
+	intel_memory_region_unreserve(mem);
 	if (mem->ops->release)
 		mem->ops->release(mem);
 
@@ -296,15 +221,15 @@ int intel_memory_regions_hw_probe(struct drm_i915_private *i915)
 		instance = intel_region_map[i].instance;
 		switch (type) {
 		case INTEL_MEMORY_SYSTEM:
-			mem = i915_gem_shmem_setup(i915);
+			mem = i915_gem_shmem_setup(i915, type, instance);
 			break;
 		case INTEL_MEMORY_STOLEN_LOCAL:
-			mem = i915_gem_stolen_lmem_setup(i915);
+			mem = i915_gem_stolen_lmem_setup(i915, type, instance);
 			if (!IS_ERR(mem))
 				i915->mm.stolen_region = mem;
 			break;
 		case INTEL_MEMORY_STOLEN_SYSTEM:
-			mem = i915_gem_stolen_smem_setup(i915);
+			mem = i915_gem_stolen_smem_setup(i915, type, instance);
 			if (!IS_ERR(mem))
 				i915->mm.stolen_region = mem;
 			break;
@@ -321,9 +246,6 @@ int intel_memory_regions_hw_probe(struct drm_i915_private *i915)
 		}
 
 		mem->id = i;
-		mem->type = type;
-		mem->instance = instance;
-
 		i915->mm.regions[i] = mem;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
index d24ce5a0b30b..e69cde13daf2 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.h
+++ b/drivers/gpu/drm/i915/intel_memory_region.h
@@ -13,8 +13,6 @@
 #include <drm/drm_mm.h>
 #include <drm/i915_drm.h>
 
-#include "i915_buddy.h"
-
 struct drm_i915_private;
 struct drm_i915_gem_object;
 struct intel_memory_region;
@@ -25,6 +23,7 @@ enum intel_memory_type {
 	INTEL_MEMORY_LOCAL = I915_MEMORY_CLASS_DEVICE,
 	INTEL_MEMORY_STOLEN_SYSTEM,
 	INTEL_MEMORY_STOLEN_LOCAL,
+	INTEL_MEMORY_MOCK,
 };
 
 enum intel_region_id {
@@ -59,10 +58,19 @@ struct intel_memory_region_ops {
 			   unsigned int flags);
 };
 
+struct intel_memory_region_private_ops {
+	void *(*reserve)(struct intel_memory_region *mem,
+			 resource_size_t offset,
+			 resource_size_t size);
+	void (*free)(struct intel_memory_region *mem,
+		     void *node);
+};
+
 struct intel_memory_region {
 	struct drm_i915_private *i915;
 
 	const struct intel_memory_region_ops *ops;
+	const struct intel_memory_region_private_ops *priv_ops;
 
 	struct io_mapping iomap;
 	struct resource region;
@@ -70,7 +78,6 @@ struct intel_memory_region {
 	/* For fake LMEM */
 	struct drm_mm_node fake_mappable;
 
-	struct i915_buddy_mm mm;
 	struct mutex mm_lock;
 
 	struct kref kref;
@@ -95,36 +102,26 @@ struct intel_memory_region {
 		struct list_head list;
 		struct list_head purgeable;
 	} objects;
+
+	size_t chunk_size;
+	unsigned int max_order;
+	bool is_range_manager;
+
+	void *region_private;
 };
 
 struct intel_memory_region *
 intel_memory_region_lookup(struct drm_i915_private *i915,
 			   u16 class, u16 instance);
 
-int intel_memory_region_init_buddy(struct intel_memory_region *mem);
-void intel_memory_region_release_buddy(struct intel_memory_region *mem);
-
-int __intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
-					  resource_size_t size,
-					  unsigned int flags,
-					  struct list_head *blocks);
-struct i915_buddy_block *
-__intel_memory_region_get_block_buddy(struct intel_memory_region *mem,
-				      resource_size_t size,
-				      unsigned int flags);
-void __intel_memory_region_put_pages_buddy(struct intel_memory_region *mem,
-					   struct list_head *blocks);
-void __intel_memory_region_put_block_buddy(struct i915_buddy_block *block);
-
-int intel_memory_region_reserve(struct intel_memory_region *mem,
-				u64 offset, u64 size);
-
 struct intel_memory_region *
 intel_memory_region_create(struct drm_i915_private *i915,
 			   resource_size_t start,
 			   resource_size_t size,
 			   resource_size_t min_page_size,
 			   resource_size_t io_start,
+			   u16 type,
+			   u16 instance,
 			   const struct intel_memory_region_ops *ops);
 
 struct intel_memory_region *
@@ -141,4 +138,9 @@ __printf(2, 3) void
 intel_memory_region_set_name(struct intel_memory_region *mem,
 			     const char *fmt, ...);
 
+void intel_memory_region_unreserve(struct intel_memory_region *mem);
+
+int intel_memory_region_reserve(struct intel_memory_region *mem,
+				resource_size_t offset,
+				resource_size_t size);
 #endif
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
new file mode 100644
index 000000000000..3bd9caa60298
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_device.h>
+
+#include "i915_drv.h"
+#include "i915_scatterlist.h"
+
+#include "intel_region_ttm.h"
+
+/* A Zero-initialized driver for now. We don't have a TTM backend yet. */
+static struct ttm_device_funcs i915_ttm_bo_driver;
+
+/**
+ * DOC: TTM support structure
+ *
+ * The code in this file deals with setting up memory managers for TTM
+ * LMEM and MOCK regions and converting the output from
+ * the managers to struct sg_table, Basically providing the mapping from
+ * i915 GEM regions to TTM memory types and resource managers.
+ */
+
+/**
+ * intel_region_ttm_device_init - Initialize a TTM device
+ * @dev_priv: Pointer to an i915 device private structure.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int intel_region_ttm_device_init(struct drm_i915_private *dev_priv)
+{
+	struct drm_device *drm = &dev_priv->drm;
+
+	return ttm_device_init(&dev_priv->bdev, &i915_ttm_bo_driver,
+			       drm->dev, drm->anon_inode->i_mapping,
+			       drm->vma_offset_manager, false, false);
+}
+
+/**
+ * intel_region_ttm_device_fini - Finalize a TTM device
+ * @dev_priv: Pointer to an i915 device private structure.
+ */
+void intel_region_ttm_device_fini(struct drm_i915_private *dev_priv)
+{
+	ttm_device_fini(&dev_priv->bdev);
+}
+
+/*
+ * Map the i915 memory regions to TTM memory types. We use the
+ * driver-private types for now, reserving TTM_PL_VRAM for stolen
+ * memory and TTM_PL_TT for GGTT use if decided to implement this.
+ */
+static int intel_region_to_ttm_type(struct intel_memory_region *mem)
+{
+	int type;
+
+	GEM_BUG_ON(mem->type != INTEL_MEMORY_LOCAL);
+
+	type = mem->instance + TTM_PL_PRIV;
+	GEM_BUG_ON(type >= TTM_NUM_MEM_TYPES);
+
+	return type;
+}
+
+static void *intel_region_ttm_node_reserve(struct intel_memory_region *mem,
+					   resource_size_t offset,
+					   resource_size_t size)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+	struct ttm_place place = {};
+	struct ttm_resource res = {};
+	struct ttm_buffer_object mock_bo = {};
+	int ret;
+
+	/*
+	 * Having to use a mock_bo is unfortunate but stems from some
+	 * drivers having private managers that insist to know what the
+	 * allocate memory is intended for, using it to send private
+	 * data to the manager. Also recently the bo has been used to send
+	 * alignment info to the manager. Assume that apart from the latter,
+	 * none of the managers we use will ever access the buffer object
+	 * members, hoping we can pass the alignment info in the
+	 * struct ttm_place in the future.
+	 */
+
+	place.fpfn = offset >> PAGE_SHIFT;
+	place.lpfn = place.fpfn + (size >> PAGE_SHIFT);
+	res.num_pages = size >> PAGE_SHIFT;
+	ret = man->func->alloc(man, &mock_bo, &place, &res);
+	if (ret == -ENOSPC)
+		ret = -ENXIO;
+
+	return ret ? ERR_PTR(ret) : res.mm_node;
+}
+
+/**
+ * intel_region_ttm_node_free - Free a node allocated from a resource manager
+ * @mem: The region the node was allocated from.
+ * @node: The opaque node representing an allocation.
+ */
+void intel_region_ttm_node_free(struct intel_memory_region *mem,
+				void *node)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+	struct ttm_resource res = {};
+
+	res.mm_node = node;
+	man->func->free(man, &res);
+}
+
+static const struct intel_memory_region_private_ops priv_ops = {
+	.reserve = intel_region_ttm_node_reserve,
+	.free = intel_region_ttm_node_free,
+};
+
+/**
+ * intel_region_ttm_init - Initialize a memory region for TTM.
+ * @mem: The region to initialize.
+ *
+ * This function initializes a suitable TTM resource manager for the
+ * region, and if it's a LMEM region type, attaches it to the TTM
+ * device. MOCK regions are NOT attached to the TTM device, since we don't
+ * have one for the mock selftests.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int intel_region_ttm_init(struct intel_memory_region *mem)
+{
+	struct ttm_resource_manager *man;
+
+	man = ttm_range_man_init_standalone(resource_size(&mem->region) >>
+					    PAGE_SHIFT, false);
+	if (IS_ERR(man))
+		return PTR_ERR(man);
+
+	ttm_resource_manager_set_used(man, true);
+	mem->chunk_size = PAGE_SIZE;
+	mem->max_order =
+		get_order(rounddown_pow_of_two(resource_size(&mem->region)));
+	mem->is_range_manager = true;
+	mem->priv_ops = &priv_ops;
+	mem->region_private = man;
+
+
+	/*
+	 * Register only LOCAL memory with the device so that we can
+	 * run the mock selftests using the manager.
+	 */
+	if (mem->type == INTEL_MEMORY_LOCAL) {
+		ttm_set_driver_manager(&mem->i915->bdev,
+				       intel_region_to_ttm_type(mem),
+				       man);
+	}
+
+	return 0;
+}
+
+/**
+ * intel_region_ttm_fini - Finalize a TTM region.
+ * @mem: The memory region
+ *
+ * This functions takes down the TTM resource manager associated with the
+ * memory region, and if it was registered with the TTM device,
+ * removes that registration.
+ */
+void intel_region_ttm_fini(struct intel_memory_region *mem)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+
+	if (mem->type == INTEL_MEMORY_LOCAL) {
+		int ret;
+
+		ret = ttm_range_man_fini(&mem->i915->bdev,
+					 intel_region_to_ttm_type(mem));
+		GEM_WARN_ON(ret);
+	} else {
+		ttm_resource_manager_set_used(man, false);
+		ttm_range_man_fini_standalone(man);
+	}
+}
+
+/**
+ * intel_region_ttm_node_to_st - Convert an opaque TTM resource manager node
+ * to an sg_table.
+ * @mem: The memory region.
+ * @node: The resource manager node obtained from the TTM resource manager.
+ *
+ * The gem backends typically use sg-tables for operations on the underlying
+ * io_memory. So provide a way for the backends to translate the
+ * nodes they are handed from TTM to sg-tables.
+ *
+ * Return: A malloced sg_table on success, an error pointer on failure.
+ */
+struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
+					     void *node)
+{
+	return i915_sg_from_mm_node(node, mem->region.start);
+}
+
+/**
+ * intel_region_ttm_node_alloc - Allocate memory resources from a region
+ * @mem: The memory region,
+ * @size: The requested size in bytes
+ * @flags: Allocation flags
+ *
+ * This functionality is provided only for callers that need to allocate
+ * memory from standalone TTM range managers, without the TTM eviction
+ * functionality. Don't use if you are not completely sure that's the
+ * case. The returned opaque node can be converted to an sg_table using
+ * intel_region_ttm_node_to_st(), and can be freed using
+ * intel_region_ttm_node_free().
+ *
+ * Return: A valid pointer on success, an error pointer on failure.
+ */
+void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
+				  resource_size_t size,
+				  unsigned int flags)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+	struct ttm_place place = {};
+	struct ttm_resource res = {};
+	struct ttm_buffer_object mock_bo = {};
+	int ret;
+
+	/*
+	 * We ignore the flags for now since we're using the range
+	 * manager and contigous and min page size would be fulfilled
+	 * by default if size is min page size aligned.
+	 */
+	res.num_pages = size >> PAGE_SHIFT;
+
+	if (mem->is_range_manager) {
+		if (size >= SZ_1G)
+			mock_bo.page_alignment = SZ_1G >> PAGE_SHIFT;
+		else if (size >= SZ_2M)
+			mock_bo.page_alignment = SZ_2M >> PAGE_SHIFT;
+		else if (size >= SZ_64K)
+			mock_bo.page_alignment = SZ_64K >> PAGE_SHIFT;
+	}
+
+	ret = man->func->alloc(man, &mock_bo, &place, &res);
+	if (ret == -ENOSPC)
+		ret = -ENXIO;
+	return ret ? ERR_PTR(ret) : res.mm_node;
+}
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
new file mode 100644
index 000000000000..40129f7e0317
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_region_ttm.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+#ifndef _INTEL_REGION_TTM_H_
+#define _INTEL_REGION_TTM_H_
+
+#include <linux/types.h>
+
+struct drm_i915_private;
+struct intel_memory_region;
+
+int intel_region_ttm_device_init(struct drm_i915_private *dev_priv);
+
+void intel_region_ttm_device_fini(struct drm_i915_private *dev_priv);
+
+int intel_region_ttm_init(struct intel_memory_region *mem);
+
+void intel_region_ttm_fini(struct intel_memory_region *mem);
+
+struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
+					     void *node);
+
+void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
+				  resource_size_t size,
+				  unsigned int flags);
+void intel_region_ttm_node_free(struct intel_memory_region *mem,
+				void *node);
+#endif /* _INTEL_REGION_TTM_H_ */
diff --git a/drivers/gpu/drm/i915/selftests/i915_buddy.c b/drivers/gpu/drm/i915/selftests/i915_buddy.c
deleted file mode 100644
index f0f5c4df8dbc..000000000000
--- a/drivers/gpu/drm/i915/selftests/i915_buddy.c
+++ /dev/null
@@ -1,789 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include <linux/prime_numbers.h>
-
-#include "../i915_selftest.h"
-#include "i915_random.h"
-
-static void __igt_dump_block(struct i915_buddy_mm *mm,
-			     struct i915_buddy_block *block,
-			     bool buddy)
-{
-	pr_err("block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%s buddy=%s\n",
-	       block->header,
-	       i915_buddy_block_state(block),
-	       i915_buddy_block_order(block),
-	       i915_buddy_block_offset(block),
-	       i915_buddy_block_size(mm, block),
-	       yesno(!block->parent),
-	       yesno(buddy));
-}
-
-static void igt_dump_block(struct i915_buddy_mm *mm,
-			   struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *buddy;
-
-	__igt_dump_block(mm, block, false);
-
-	buddy = get_buddy(block);
-	if (buddy)
-		__igt_dump_block(mm, buddy, true);
-}
-
-static int igt_check_block(struct i915_buddy_mm *mm,
-			   struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *buddy;
-	unsigned int block_state;
-	u64 block_size;
-	u64 offset;
-	int err = 0;
-
-	block_state = i915_buddy_block_state(block);
-
-	if (block_state != I915_BUDDY_ALLOCATED &&
-	    block_state != I915_BUDDY_FREE &&
-	    block_state != I915_BUDDY_SPLIT) {
-		pr_err("block state mismatch\n");
-		err = -EINVAL;
-	}
-
-	block_size = i915_buddy_block_size(mm, block);
-	offset = i915_buddy_block_offset(block);
-
-	if (block_size < mm->chunk_size) {
-		pr_err("block size smaller than min size\n");
-		err = -EINVAL;
-	}
-
-	if (!is_power_of_2(block_size)) {
-		pr_err("block size not power of two\n");
-		err = -EINVAL;
-	}
-
-	if (!IS_ALIGNED(block_size, mm->chunk_size)) {
-		pr_err("block size not aligned to min size\n");
-		err = -EINVAL;
-	}
-
-	if (!IS_ALIGNED(offset, mm->chunk_size)) {
-		pr_err("block offset not aligned to min size\n");
-		err = -EINVAL;
-	}
-
-	if (!IS_ALIGNED(offset, block_size)) {
-		pr_err("block offset not aligned to block size\n");
-		err = -EINVAL;
-	}
-
-	buddy = get_buddy(block);
-
-	if (!buddy && block->parent) {
-		pr_err("buddy has gone fishing\n");
-		err = -EINVAL;
-	}
-
-	if (buddy) {
-		if (i915_buddy_block_offset(buddy) != (offset ^ block_size)) {
-			pr_err("buddy has wrong offset\n");
-			err = -EINVAL;
-		}
-
-		if (i915_buddy_block_size(mm, buddy) != block_size) {
-			pr_err("buddy size mismatch\n");
-			err = -EINVAL;
-		}
-
-		if (i915_buddy_block_state(buddy) == block_state &&
-		    block_state == I915_BUDDY_FREE) {
-			pr_err("block and its buddy are free\n");
-			err = -EINVAL;
-		}
-	}
-
-	return err;
-}
-
-static int igt_check_blocks(struct i915_buddy_mm *mm,
-			    struct list_head *blocks,
-			    u64 expected_size,
-			    bool is_contiguous)
-{
-	struct i915_buddy_block *block;
-	struct i915_buddy_block *prev;
-	u64 total;
-	int err = 0;
-
-	block = NULL;
-	prev = NULL;
-	total = 0;
-
-	list_for_each_entry(block, blocks, link) {
-		err = igt_check_block(mm, block);
-
-		if (!i915_buddy_block_is_allocated(block)) {
-			pr_err("block not allocated\n"),
-			err = -EINVAL;
-		}
-
-		if (is_contiguous && prev) {
-			u64 prev_block_size;
-			u64 prev_offset;
-			u64 offset;
-
-			prev_offset = i915_buddy_block_offset(prev);
-			prev_block_size = i915_buddy_block_size(mm, prev);
-			offset = i915_buddy_block_offset(block);
-
-			if (offset != (prev_offset + prev_block_size)) {
-				pr_err("block offset mismatch\n");
-				err = -EINVAL;
-			}
-		}
-
-		if (err)
-			break;
-
-		total += i915_buddy_block_size(mm, block);
-		prev = block;
-	}
-
-	if (!err) {
-		if (total != expected_size) {
-			pr_err("size mismatch, expected=%llx, found=%llx\n",
-			       expected_size, total);
-			err = -EINVAL;
-		}
-		return err;
-	}
-
-	if (prev) {
-		pr_err("prev block, dump:\n");
-		igt_dump_block(mm, prev);
-	}
-
-	if (block) {
-		pr_err("bad block, dump:\n");
-		igt_dump_block(mm, block);
-	}
-
-	return err;
-}
-
-static int igt_check_mm(struct i915_buddy_mm *mm)
-{
-	struct i915_buddy_block *root;
-	struct i915_buddy_block *prev;
-	unsigned int i;
-	u64 total;
-	int err = 0;
-
-	if (!mm->n_roots) {
-		pr_err("n_roots is zero\n");
-		return -EINVAL;
-	}
-
-	if (mm->n_roots != hweight64(mm->size)) {
-		pr_err("n_roots mismatch, n_roots=%u, expected=%lu\n",
-		       mm->n_roots, hweight64(mm->size));
-		return -EINVAL;
-	}
-
-	root = NULL;
-	prev = NULL;
-	total = 0;
-
-	for (i = 0; i < mm->n_roots; ++i) {
-		struct i915_buddy_block *block;
-		unsigned int order;
-
-		root = mm->roots[i];
-		if (!root) {
-			pr_err("root(%u) is NULL\n", i);
-			err = -EINVAL;
-			break;
-		}
-
-		err = igt_check_block(mm, root);
-
-		if (!i915_buddy_block_is_free(root)) {
-			pr_err("root not free\n");
-			err = -EINVAL;
-		}
-
-		order = i915_buddy_block_order(root);
-
-		if (!i) {
-			if (order != mm->max_order) {
-				pr_err("max order root missing\n");
-				err = -EINVAL;
-			}
-		}
-
-		if (prev) {
-			u64 prev_block_size;
-			u64 prev_offset;
-			u64 offset;
-
-			prev_offset = i915_buddy_block_offset(prev);
-			prev_block_size = i915_buddy_block_size(mm, prev);
-			offset = i915_buddy_block_offset(root);
-
-			if (offset != (prev_offset + prev_block_size)) {
-				pr_err("root offset mismatch\n");
-				err = -EINVAL;
-			}
-		}
-
-		block = list_first_entry_or_null(&mm->free_list[order],
-						 struct i915_buddy_block,
-						 link);
-		if (block != root) {
-			pr_err("root mismatch at order=%u\n", order);
-			err = -EINVAL;
-		}
-
-		if (err)
-			break;
-
-		prev = root;
-		total += i915_buddy_block_size(mm, root);
-	}
-
-	if (!err) {
-		if (total != mm->size) {
-			pr_err("expected mm size=%llx, found=%llx\n", mm->size,
-			       total);
-			err = -EINVAL;
-		}
-		return err;
-	}
-
-	if (prev) {
-		pr_err("prev root(%u), dump:\n", i - 1);
-		igt_dump_block(mm, prev);
-	}
-
-	if (root) {
-		pr_err("bad root(%u), dump:\n", i);
-		igt_dump_block(mm, root);
-	}
-
-	return err;
-}
-
-static void igt_mm_config(u64 *size, u64 *chunk_size)
-{
-	I915_RND_STATE(prng);
-	u32 s, ms;
-
-	/* Nothing fancy, just try to get an interesting bit pattern */
-
-	prandom_seed_state(&prng, i915_selftest.random_seed);
-
-	/* Let size be a random number of pages up to 8 GB (2M pages) */
-	s = 1 + i915_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng);
-	/* Let the chunk size be a random power of 2 less than size */
-	ms = BIT(i915_prandom_u32_max_state(ilog2(s), &prng));
-	/* Round size down to the chunk size */
-	s &= -ms;
-
-	/* Convert from pages to bytes */
-	*chunk_size = (u64)ms << 12;
-	*size = (u64)s << 12;
-}
-
-static int igt_buddy_alloc_smoke(void *arg)
-{
-	struct i915_buddy_mm mm;
-	IGT_TIMEOUT(end_time);
-	I915_RND_STATE(prng);
-	u64 chunk_size;
-	u64 mm_size;
-	int *order;
-	int err, i;
-
-	igt_mm_config(&mm_size, &chunk_size);
-
-	pr_info("buddy_init with size=%llx, chunk_size=%llx\n", mm_size, chunk_size);
-
-	err = i915_buddy_init(&mm, mm_size, chunk_size);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-
-	order = i915_random_order(mm.max_order + 1, &prng);
-	if (!order)
-		goto out_fini;
-
-	for (i = 0; i <= mm.max_order; ++i) {
-		struct i915_buddy_block *block;
-		int max_order = order[i];
-		bool timeout = false;
-		LIST_HEAD(blocks);
-		int order;
-		u64 total;
-
-		err = igt_check_mm(&mm);
-		if (err) {
-			pr_err("pre-mm check failed, abort\n");
-			break;
-		}
-
-		pr_info("filling from max_order=%u\n", max_order);
-
-		order = max_order;
-		total = 0;
-
-		do {
-retry:
-			block = i915_buddy_alloc(&mm, order);
-			if (IS_ERR(block)) {
-				err = PTR_ERR(block);
-				if (err == -ENOMEM) {
-					pr_info("buddy_alloc hit -ENOMEM with order=%d\n",
-						order);
-				} else {
-					if (order--) {
-						err = 0;
-						goto retry;
-					}
-
-					pr_err("buddy_alloc with order=%d failed(%d)\n",
-					       order, err);
-				}
-
-				break;
-			}
-
-			list_add_tail(&block->link, &blocks);
-
-			if (i915_buddy_block_order(block) != order) {
-				pr_err("buddy_alloc order mismatch\n");
-				err = -EINVAL;
-				break;
-			}
-
-			total += i915_buddy_block_size(&mm, block);
-
-			if (__igt_timeout(end_time, NULL)) {
-				timeout = true;
-				break;
-			}
-		} while (total < mm.size);
-
-		if (!err)
-			err = igt_check_blocks(&mm, &blocks, total, false);
-
-		i915_buddy_free_list(&mm, &blocks);
-
-		if (!err) {
-			err = igt_check_mm(&mm);
-			if (err)
-				pr_err("post-mm check failed\n");
-		}
-
-		if (err || timeout)
-			break;
-
-		cond_resched();
-	}
-
-	if (err == -ENOMEM)
-		err = 0;
-
-	kfree(order);
-out_fini:
-	i915_buddy_fini(&mm);
-
-	return err;
-}
-
-static int igt_buddy_alloc_pessimistic(void *arg)
-{
-	const unsigned int max_order = 16;
-	struct i915_buddy_block *block, *bn;
-	struct i915_buddy_mm mm;
-	unsigned int order;
-	LIST_HEAD(blocks);
-	int err;
-
-	/*
-	 * Create a pot-sized mm, then allocate one of each possible
-	 * order within. This should leave the mm with exactly one
-	 * page left.
-	 */
-
-	err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-	GEM_BUG_ON(mm.max_order != max_order);
-
-	for (order = 0; order < max_order; order++) {
-		block = i915_buddy_alloc(&mm, order);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc hit -ENOMEM with order=%d\n",
-				order);
-			err = PTR_ERR(block);
-			goto err;
-		}
-
-		list_add_tail(&block->link, &blocks);
-	}
-
-	/* And now the last remaining block available */
-	block = i915_buddy_alloc(&mm, 0);
-	if (IS_ERR(block)) {
-		pr_info("buddy_alloc hit -ENOMEM on final alloc\n");
-		err = PTR_ERR(block);
-		goto err;
-	}
-	list_add_tail(&block->link, &blocks);
-
-	/* Should be completely full! */
-	for (order = max_order; order--; ) {
-		block = i915_buddy_alloc(&mm, order);
-		if (!IS_ERR(block)) {
-			pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!",
-				order);
-			list_add_tail(&block->link, &blocks);
-			err = -EINVAL;
-			goto err;
-		}
-	}
-
-	block = list_last_entry(&blocks, typeof(*block), link);
-	list_del(&block->link);
-	i915_buddy_free(&mm, block);
-
-	/* As we free in increasing size, we make available larger blocks */
-	order = 1;
-	list_for_each_entry_safe(block, bn, &blocks, link) {
-		list_del(&block->link);
-		i915_buddy_free(&mm, block);
-
-		block = i915_buddy_alloc(&mm, order);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n",
-				order);
-			err = PTR_ERR(block);
-			goto err;
-		}
-		i915_buddy_free(&mm, block);
-		order++;
-	}
-
-	/* To confirm, now the whole mm should be available */
-	block = i915_buddy_alloc(&mm, max_order);
-	if (IS_ERR(block)) {
-		pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n",
-			max_order);
-		err = PTR_ERR(block);
-		goto err;
-	}
-	i915_buddy_free(&mm, block);
-
-err:
-	i915_buddy_free_list(&mm, &blocks);
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-static int igt_buddy_alloc_optimistic(void *arg)
-{
-	const int max_order = 16;
-	struct i915_buddy_block *block;
-	struct i915_buddy_mm mm;
-	LIST_HEAD(blocks);
-	int order;
-	int err;
-
-	/*
-	 * Create a mm with one block of each order available, and
-	 * try to allocate them all.
-	 */
-
-	err = i915_buddy_init(&mm,
-			      PAGE_SIZE * ((1 << (max_order + 1)) - 1),
-			      PAGE_SIZE);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-	GEM_BUG_ON(mm.max_order != max_order);
-
-	for (order = 0; order <= max_order; order++) {
-		block = i915_buddy_alloc(&mm, order);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc hit -ENOMEM with order=%d\n",
-				order);
-			err = PTR_ERR(block);
-			goto err;
-		}
-
-		list_add_tail(&block->link, &blocks);
-	}
-
-	/* Should be completely full! */
-	block = i915_buddy_alloc(&mm, 0);
-	if (!IS_ERR(block)) {
-		pr_info("buddy_alloc unexpectedly succeeded, it should be full!");
-		list_add_tail(&block->link, &blocks);
-		err = -EINVAL;
-		goto err;
-	}
-
-err:
-	i915_buddy_free_list(&mm, &blocks);
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-static int igt_buddy_alloc_pathological(void *arg)
-{
-	const int max_order = 16;
-	struct i915_buddy_block *block;
-	struct i915_buddy_mm mm;
-	LIST_HEAD(blocks);
-	LIST_HEAD(holes);
-	int order, top;
-	int err;
-
-	/*
-	 * Create a pot-sized mm, then allocate one of each possible
-	 * order within. This should leave the mm with exactly one
-	 * page left. Free the largest block, then whittle down again.
-	 * Eventually we will have a fully 50% fragmented mm.
-	 */
-
-	err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-	GEM_BUG_ON(mm.max_order != max_order);
-
-	for (top = max_order; top; top--) {
-		/* Make room by freeing the largest allocated block */
-		block = list_first_entry_or_null(&blocks, typeof(*block), link);
-		if (block) {
-			list_del(&block->link);
-			i915_buddy_free(&mm, block);
-		}
-
-		for (order = top; order--; ) {
-			block = i915_buddy_alloc(&mm, order);
-			if (IS_ERR(block)) {
-				pr_info("buddy_alloc hit -ENOMEM with order=%d, top=%d\n",
-					order, top);
-				err = PTR_ERR(block);
-				goto err;
-			}
-			list_add_tail(&block->link, &blocks);
-		}
-
-		/* There should be one final page for this sub-allocation */
-		block = i915_buddy_alloc(&mm, 0);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc hit -ENOMEM for hole\n");
-			err = PTR_ERR(block);
-			goto err;
-		}
-		list_add_tail(&block->link, &holes);
-
-		block = i915_buddy_alloc(&mm, top);
-		if (!IS_ERR(block)) {
-			pr_info("buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!",
-				top, max_order);
-			list_add_tail(&block->link, &blocks);
-			err = -EINVAL;
-			goto err;
-		}
-	}
-
-	i915_buddy_free_list(&mm, &holes);
-
-	/* Nothing larger than blocks of chunk_size now available */
-	for (order = 1; order <= max_order; order++) {
-		block = i915_buddy_alloc(&mm, order);
-		if (!IS_ERR(block)) {
-			pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!",
-				order);
-			list_add_tail(&block->link, &blocks);
-			err = -EINVAL;
-			goto err;
-		}
-	}
-
-err:
-	list_splice_tail(&holes, &blocks);
-	i915_buddy_free_list(&mm, &blocks);
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-static int igt_buddy_alloc_range(void *arg)
-{
-	struct i915_buddy_mm mm;
-	unsigned long page_num;
-	LIST_HEAD(blocks);
-	u64 chunk_size;
-	u64 offset;
-	u64 size;
-	u64 rem;
-	int err;
-
-	igt_mm_config(&size, &chunk_size);
-
-	pr_info("buddy_init with size=%llx, chunk_size=%llx\n", size, chunk_size);
-
-	err = i915_buddy_init(&mm, size, chunk_size);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-
-	err = igt_check_mm(&mm);
-	if (err) {
-		pr_err("pre-mm check failed, abort, abort, abort!\n");
-		goto err_fini;
-	}
-
-	rem = mm.size;
-	offset = 0;
-
-	for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) {
-		struct i915_buddy_block *block;
-		LIST_HEAD(tmp);
-
-		size = min(page_num * mm.chunk_size, rem);
-
-		err = i915_buddy_alloc_range(&mm, &tmp, offset, size);
-		if (err) {
-			if (err == -ENOMEM) {
-				pr_info("alloc_range hit -ENOMEM with size=%llx\n",
-					size);
-			} else {
-				pr_err("alloc_range with offset=%llx, size=%llx failed(%d)\n",
-				       offset, size, err);
-			}
-
-			break;
-		}
-
-		block = list_first_entry_or_null(&tmp,
-						 struct i915_buddy_block,
-						 link);
-		if (!block) {
-			pr_err("alloc_range has no blocks\n");
-			err = -EINVAL;
-			break;
-		}
-
-		if (i915_buddy_block_offset(block) != offset) {
-			pr_err("alloc_range start offset mismatch, found=%llx, expected=%llx\n",
-			       i915_buddy_block_offset(block), offset);
-			err = -EINVAL;
-		}
-
-		if (!err)
-			err = igt_check_blocks(&mm, &tmp, size, true);
-
-		list_splice_tail(&tmp, &blocks);
-
-		if (err)
-			break;
-
-		offset += size;
-
-		rem -= size;
-		if (!rem)
-			break;
-
-		cond_resched();
-	}
-
-	if (err == -ENOMEM)
-		err = 0;
-
-	i915_buddy_free_list(&mm, &blocks);
-
-	if (!err) {
-		err = igt_check_mm(&mm);
-		if (err)
-			pr_err("post-mm check failed\n");
-	}
-
-err_fini:
-	i915_buddy_fini(&mm);
-
-	return err;
-}
-
-static int igt_buddy_alloc_limit(void *arg)
-{
-	struct i915_buddy_block *block;
-	struct i915_buddy_mm mm;
-	const u64 size = U64_MAX;
-	int err;
-
-	err = i915_buddy_init(&mm, size, PAGE_SIZE);
-	if (err)
-		return err;
-
-	if (mm.max_order != I915_BUDDY_MAX_ORDER) {
-		pr_err("mm.max_order(%d) != %d\n",
-		       mm.max_order, I915_BUDDY_MAX_ORDER);
-		err = -EINVAL;
-		goto out_fini;
-	}
-
-	block = i915_buddy_alloc(&mm, mm.max_order);
-	if (IS_ERR(block)) {
-		err = PTR_ERR(block);
-		goto out_fini;
-	}
-
-	if (i915_buddy_block_order(block) != mm.max_order) {
-		pr_err("block order(%d) != %d\n",
-		       i915_buddy_block_order(block), mm.max_order);
-		err = -EINVAL;
-		goto out_free;
-	}
-
-	if (i915_buddy_block_size(&mm, block) !=
-	    BIT_ULL(mm.max_order) * PAGE_SIZE) {
-		pr_err("block size(%llu) != %llu\n",
-		       i915_buddy_block_size(&mm, block),
-		       BIT_ULL(mm.max_order) * PAGE_SIZE);
-		err = -EINVAL;
-		goto out_free;
-	}
-
-out_free:
-	i915_buddy_free(&mm, block);
-out_fini:
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-int i915_buddy_mock_selftests(void)
-{
-	static const struct i915_subtest tests[] = {
-		SUBTEST(igt_buddy_alloc_pessimistic),
-		SUBTEST(igt_buddy_alloc_optimistic),
-		SUBTEST(igt_buddy_alloc_pathological),
-		SUBTEST(igt_buddy_alloc_smoke),
-		SUBTEST(igt_buddy_alloc_range),
-		SUBTEST(igt_buddy_alloc_limit),
-	};
-
-	return i915_subtests(tests, NULL);
-}
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 3db34d3eea58..34e5caf38093 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -33,5 +33,4 @@ selftest(evict, i915_gem_evict_mock_selftests)
 selftest(gtt, i915_gem_gtt_mock_selftests)
 selftest(hugepages, i915_gem_huge_page_mock_selftests)
 selftest(contexts, i915_gem_context_mock_selftests)
-selftest(buddy, i915_buddy_mock_selftests)
 selftest(memory_region, intel_memory_region_mock_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
index f85fd8cbfbf5..c85d516b85cd 100644
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -57,9 +57,10 @@ static int igt_mock_fill(void *arg)
 	LIST_HEAD(objects);
 	int err = 0;
 
-	page_size = mem->mm.chunk_size;
-	max_pages = div64_u64(total, page_size);
+	page_size = mem->chunk_size;
 	rem = total;
+retry:
+	max_pages = div64_u64(rem, page_size);
 
 	for_each_prime_number_from(page_num, 1, max_pages) {
 		resource_size_t size = page_num * page_size;
@@ -85,6 +86,11 @@ static int igt_mock_fill(void *arg)
 		err = 0;
 	if (err == -ENXIO) {
 		if (page_num * page_size <= rem) {
+			if (mem->is_range_manager && max_pages > 1) {
+				max_pages >>= 1;
+				goto retry;
+			}
+
 			pr_err("%s failed, space still left in region\n",
 			       __func__);
 			err = -EINVAL;
@@ -199,12 +205,18 @@ static int igt_mock_reserve(void *arg)
 	do {
 		u32 size = i915_prandom_u32_max_state(cur_avail, &prng);
 
+retry:
 		size = max_t(u32, round_up(size, PAGE_SIZE), PAGE_SIZE);
 		obj = igt_object_create(mem, &objects, size, 0);
 		if (IS_ERR(obj)) {
-			if (PTR_ERR(obj) == -ENXIO)
+			if (PTR_ERR(obj) == -ENXIO) {
+				if (mem->is_range_manager &&
+				    size > mem->chunk_size) {
+					size >>= 1;
+					goto retry;
+				}
 				break;
-
+			}
 			err = PTR_ERR(obj);
 			goto out_close;
 		}
@@ -220,7 +232,7 @@ static int igt_mock_reserve(void *arg)
 out_close:
 	kfree(order);
 	close_objects(mem, &objects);
-	i915_buddy_free_list(&mem->mm, &mem->reserved);
+	intel_memory_region_unreserve(mem);
 	return err;
 }
 
@@ -240,7 +252,7 @@ static int igt_mock_contiguous(void *arg)
 	total = resource_size(&mem->region);
 
 	/* Min size */
-	obj = igt_object_create(mem, &objects, mem->mm.chunk_size,
+	obj = igt_object_create(mem, &objects, mem->chunk_size,
 				I915_BO_ALLOC_CONTIGUOUS);
 	if (IS_ERR(obj))
 		return PTR_ERR(obj);
@@ -321,14 +333,16 @@ static int igt_mock_contiguous(void *arg)
 	min = target;
 	target = total >> 1;
 
-	/* Make sure we can still allocate all the fragmented space */
-	obj = igt_object_create(mem, &objects, target, 0);
-	if (IS_ERR(obj)) {
-		err = PTR_ERR(obj);
-		goto err_close_objects;
-	}
+	if (!mem->is_range_manager) {
+		/* Make sure we can still allocate all the fragmented space */
+		obj = igt_object_create(mem, &objects, target, 0);
+		if (IS_ERR(obj)) {
+			err = PTR_ERR(obj);
+			goto err_close_objects;
+		}
 
-	igt_object_release(obj);
+		igt_object_release(obj);
+	}
 
 	/*
 	 * Even though we have enough free space, we don't have a big enough
@@ -348,7 +362,7 @@ static int igt_mock_contiguous(void *arg)
 		}
 
 		target >>= 1;
-	} while (target >= mem->mm.chunk_size);
+	} while (target >= mem->chunk_size);
 
 err_close_objects:
 	list_splice_tail(&holes, &objects);
@@ -368,7 +382,7 @@ static int igt_mock_splintered_region(void *arg)
 
 	/*
 	 * Sanity check we can still allocate everything even if the
-	 * mm.max_order != mm.size. i.e our starting address space size is not a
+	 * max_order != mm.size. i.e our starting address space size is not a
 	 * power-of-two.
 	 */
 
@@ -377,17 +391,10 @@ static int igt_mock_splintered_region(void *arg)
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
-	if (mem->mm.size != size) {
-		pr_err("%s size mismatch(%llu != %llu)\n",
-		       __func__, mem->mm.size, size);
-		err = -EINVAL;
-		goto out_put;
-	}
-
 	expected_order = get_order(rounddown_pow_of_two(size));
-	if (mem->mm.max_order != expected_order) {
+	if (mem->max_order != expected_order) {
 		pr_err("%s order mismatch(%u != %u)\n",
-		       __func__, mem->mm.max_order, expected_order);
+		       __func__, mem->max_order, expected_order);
 		err = -EINVAL;
 		goto out_put;
 	}
@@ -408,12 +415,15 @@ static int igt_mock_splintered_region(void *arg)
 	 * sure that does indeed hold true.
 	 */
 
-	obj = igt_object_create(mem, &objects, size, I915_BO_ALLOC_CONTIGUOUS);
-	if (!IS_ERR(obj)) {
-		pr_err("%s too large contiguous allocation was not rejected\n",
-		       __func__);
-		err = -EINVAL;
-		goto out_close;
+	if (!mem->is_range_manager) {
+		obj = igt_object_create(mem, &objects, size,
+					I915_BO_ALLOC_CONTIGUOUS);
+		if (!IS_ERR(obj)) {
+			pr_err("%s too large contiguous allocation was not rejected\n",
+			       __func__);
+			err = -EINVAL;
+			goto out_close;
+		}
 	}
 
 	obj = igt_object_create(mem, &objects, rounddown_pow_of_two(size),
@@ -432,68 +442,6 @@ static int igt_mock_splintered_region(void *arg)
 	return err;
 }
 
-#ifndef SZ_8G
-#define SZ_8G BIT_ULL(33)
-#endif
-
-static int igt_mock_max_segment(void *arg)
-{
-	const unsigned int max_segment = i915_sg_segment_size();
-	struct intel_memory_region *mem = arg;
-	struct drm_i915_private *i915 = mem->i915;
-	struct drm_i915_gem_object *obj;
-	struct i915_buddy_block *block;
-	struct scatterlist *sg;
-	LIST_HEAD(objects);
-	u64 size;
-	int err = 0;
-
-	/*
-	 * While we may create very large contiguous blocks, we may need
-	 * to break those down for consumption elsewhere. In particular,
-	 * dma-mapping with scatterlist elements have an implicit limit of
-	 * UINT_MAX on each element.
-	 */
-
-	size = SZ_8G;
-	mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0);
-	if (IS_ERR(mem))
-		return PTR_ERR(mem);
-
-	obj = igt_object_create(mem, &objects, size, 0);
-	if (IS_ERR(obj)) {
-		err = PTR_ERR(obj);
-		goto out_put;
-	}
-
-	size = 0;
-	list_for_each_entry(block, &obj->mm.blocks, link) {
-		if (i915_buddy_block_size(&mem->mm, block) > size)
-			size = i915_buddy_block_size(&mem->mm, block);
-	}
-	if (size < max_segment) {
-		pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n",
-		       __func__, max_segment, size);
-		err = -EINVAL;
-		goto out_close;
-	}
-
-	for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
-		if (sg->length > max_segment) {
-			pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
-			       __func__, sg->length, max_segment);
-			err = -EINVAL;
-			goto out_close;
-		}
-	}
-
-out_close:
-	close_objects(mem, &objects);
-out_put:
-	intel_memory_region_put(mem);
-	return err;
-}
-
 static int igt_gpu_write_dw(struct intel_context *ce,
 			    struct i915_vma *vma,
 			    u32 dword,
@@ -1098,7 +1046,6 @@ int intel_memory_region_mock_selftests(void)
 		SUBTEST(igt_mock_fill),
 		SUBTEST(igt_mock_contiguous),
 		SUBTEST(igt_mock_splintered_region),
-		SUBTEST(igt_mock_max_segment),
 	};
 	struct intel_memory_region *mem;
 	struct drm_i915_private *i915;
diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c
index 5d2d010a1e22..9067601aa717 100644
--- a/drivers/gpu/drm/i915/selftests/mock_region.c
+++ b/drivers/gpu/drm/i915/selftests/mock_region.c
@@ -1,17 +1,53 @@
 // SPDX-License-Identifier: MIT
 /*
- * Copyright © 2019 Intel Corporation
+ * Copyright © 2019-2021 Intel Corporation
  */
 
+#include <linux/scatterlist.h>
+
 #include "gem/i915_gem_region.h"
 #include "intel_memory_region.h"
+#include "intel_region_ttm.h"
 
 #include "mock_region.h"
 
+static void mock_region_put_pages(struct drm_i915_gem_object *obj,
+				  struct sg_table *pages)
+{
+	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
+	sg_free_table(pages);
+	kfree(pages);
+}
+
+static int mock_region_get_pages(struct drm_i915_gem_object *obj)
+{
+	unsigned int flags;
+	struct sg_table *pages;
+
+	flags = I915_ALLOC_MIN_PAGE_SIZE;
+	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
+		flags |= I915_ALLOC_CONTIGUOUS;
+
+	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
+							 obj->base.size,
+							 flags);
+	if (IS_ERR(obj->mm.st_mm_node))
+		return PTR_ERR(obj->mm.st_mm_node);
+
+	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
+	if (IS_ERR(pages))
+		return PTR_ERR(pages);
+
+	__i915_gem_object_set_pages(obj, pages,
+				    i915_sg_dma_page_sizes(pages->sgl));
+
+	return 0;
+}
+
 static const struct drm_i915_gem_object_ops mock_region_obj_ops = {
 	.name = "mock-region",
-	.get_pages = i915_gem_object_get_pages_buddy,
-	.put_pages = i915_gem_object_put_pages_buddy,
+	.get_pages = mock_region_get_pages,
+	.put_pages = mock_region_put_pages,
 	.release = i915_gem_object_release_memory_region,
 };
 
@@ -23,7 +59,7 @@ static int mock_object_init(struct intel_memory_region *mem,
 	static struct lock_class_key lock_class;
 	struct drm_i915_private *i915 = mem->i915;
 
-	if (size > mem->mm.size)
+	if (size > resource_size(&mem->region))
 		return -E2BIG;
 
 	drm_gem_private_object_init(&i915->drm, &obj->base, size);
@@ -39,8 +75,8 @@ static int mock_object_init(struct intel_memory_region *mem,
 }
 
 static const struct intel_memory_region_ops mock_region_ops = {
-	.init = intel_memory_region_init_buddy,
-	.release = intel_memory_region_release_buddy,
+	.init = intel_region_ttm_init,
+	.release = intel_region_ttm_fini,
 	.init_object = mock_object_init,
 };
 
@@ -52,5 +88,6 @@ mock_region_create(struct drm_i915_private *i915,
 		   resource_size_t io_start)
 {
 	return intel_memory_region_create(i915, start, size, min_page_size,
-					  io_start, &mock_region_ops);
+					  io_start, INTEL_MEMORY_MOCK, 0,
+					  &mock_region_ops);
 }
diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c
index b9d5da6e6a81..6957dfb0cf5a 100644
--- a/drivers/gpu/drm/ttm/ttm_range_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -125,55 +125,76 @@ static const struct ttm_resource_manager_func ttm_range_manager_func = {
 	.debug = ttm_range_man_debug
 };
 
-int ttm_range_man_init(struct ttm_device *bdev,
-		       unsigned type, bool use_tt,
-		       unsigned long p_size)
+struct ttm_resource_manager *
+ttm_range_man_init_standalone(unsigned long size, bool use_tt)
 {
 	struct ttm_resource_manager *man;
 	struct ttm_range_manager *rman;
 
 	rman = kzalloc(sizeof(*rman), GFP_KERNEL);
 	if (!rman)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	man = &rman->manager;
 	man->use_tt = use_tt;
 
 	man->func = &ttm_range_manager_func;
 
-	ttm_resource_manager_init(man, p_size);
+	ttm_resource_manager_init(man, size);
 
-	drm_mm_init(&rman->mm, 0, p_size);
+	drm_mm_init(&rman->mm, 0, size);
 	spin_lock_init(&rman->lock);
 
-	ttm_set_driver_manager(bdev, type, &rman->manager);
+	return man;
+}
+EXPORT_SYMBOL(ttm_range_man_init_standalone);
+
+int ttm_range_man_init(struct ttm_device *bdev,
+		       unsigned int type, bool use_tt,
+		       unsigned long p_size)
+{
+	struct ttm_resource_manager *man;
+
+	man = ttm_range_man_init_standalone(p_size, use_tt);
+	if (IS_ERR(man))
+		return PTR_ERR(man);
+
 	ttm_resource_manager_set_used(man, true);
+	ttm_set_driver_manager(bdev, type, man);
+
 	return 0;
 }
 EXPORT_SYMBOL(ttm_range_man_init);
 
+void ttm_range_man_fini_standalone(struct ttm_resource_manager *man)
+{
+	struct ttm_range_manager *rman = to_range_manager(man);
+	struct drm_mm *mm = &rman->mm;
+
+	spin_lock(&rman->lock);
+	drm_mm_clean(mm);
+	drm_mm_takedown(mm);
+	spin_unlock(&rman->lock);
+
+	ttm_resource_manager_cleanup(man);
+	kfree(rman);
+}
+EXPORT_SYMBOL(ttm_range_man_fini_standalone);
+
 int ttm_range_man_fini(struct ttm_device *bdev,
 		       unsigned type)
 {
 	struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
-	struct ttm_range_manager *rman = to_range_manager(man);
-	struct drm_mm *mm = &rman->mm;
 	int ret;
 
 	ttm_resource_manager_set_used(man, false);
-
 	ret = ttm_resource_manager_evict_all(bdev, man);
 	if (ret)
 		return ret;
 
-	spin_lock(&rman->lock);
-	drm_mm_clean(mm);
-	drm_mm_takedown(mm);
-	spin_unlock(&rman->lock);
-
-	ttm_resource_manager_cleanup(man);
 	ttm_set_driver_manager(bdev, type, NULL);
-	kfree(rman);
+	ttm_range_man_fini_standalone(man);
+
 	return 0;
 }
 EXPORT_SYMBOL(ttm_range_man_fini);
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index dbccac957f8f..734b1712ea72 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -321,6 +321,20 @@ int ttm_range_man_init(struct ttm_device *bdev,
 		       unsigned type, bool use_tt,
 		       unsigned long p_size);
 
+/**
+ * ttm_range_man_init_standalone - Initialize a ttm range manager without
+ * device interaction.
+ * @size: Size of the area to be managed in pages.
+ * @use_tt: The memory type requires tt backing.
+ *
+ * This function is intended for selftests. It initializes a range manager
+ * without any device interaction.
+ *
+ * Return: pointer to a range manager on success. Error pointer on failure.
+ */
+struct ttm_resource_manager *
+ttm_range_man_init_standalone(unsigned long size, bool use_tt);
+
 /**
  * ttm_range_man_fini
  *
@@ -332,4 +346,13 @@ int ttm_range_man_init(struct ttm_device *bdev,
 int ttm_range_man_fini(struct ttm_device *bdev,
 		       unsigned type);
 
+/**
+ * ttm_range_man_fini_standalone
+ * @man: The range manager
+ *
+ * Tear down a range manager initialized with
+ * ttm_range_manager_init_standalone().
+ */
+void ttm_range_man_fini_standalone(struct ttm_resource_manager *man);
+
 #endif
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
@ 2021-05-11 13:25   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström, Christian König

Temporarily remove the buddy allocator and related selftests
and hook up the TTM range manager for i915 regions.

In order to support some of the mock region-related selftests, we need to
be able to initialize the TTM range-manager standalone without a struct
ttm_device. Add two functions to allow that to the TTM api.

Finally modify the mock region selftests somewhat to account for a
fragmenting manager.

Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/Kconfig                  |   1 +
 drivers/gpu/drm/i915/Makefile                 |   2 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
 drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
 drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
 drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
 drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
 drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
 drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
 drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
 drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
 drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
 drivers/gpu/drm/i915/i915_drv.c               |   8 +
 drivers/gpu/drm/i915/i915_drv.h               |   7 +-
 drivers/gpu/drm/i915/i915_gem.c               |   1 +
 drivers/gpu/drm/i915/i915_globals.c           |   1 -
 drivers/gpu/drm/i915/i915_globals.h           |   1 -
 drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
 drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
 drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
 drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
 drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
 drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
 drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------------
 .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
 .../drm/i915/selftests/intel_memory_region.c  | 133 +--
 drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
 drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
 include/drm/ttm/ttm_bo_driver.h               |  23 +
 31 files changed, 715 insertions(+), 1771 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
 delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
 create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
 delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c

diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 1e1cb245fca7..b63d374dff23 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -26,6 +26,7 @@ config DRM_I915
 	select SND_HDA_I915 if SND_HDA_CORE
 	select CEC_CORE if CEC_NOTIFIER
 	select VMAP_PFN
+	select DRM_TTM
 	help
 	  Choose this option if you have a system that has "Intel Graphics
 	  Media Accelerator" or "HD Graphics" integrated graphics,
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index d0d936d9137b..cb8823570996 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -50,6 +50,7 @@ i915-y += i915_drv.o \
 	  intel_memory_region.o \
 	  intel_pch.o \
 	  intel_pm.o \
+	  intel_region_ttm.o \
 	  intel_runtime_pm.o \
 	  intel_sideband.o \
 	  intel_step.o \
@@ -160,7 +161,6 @@ gem-y += \
 i915-y += \
 	  $(gem-y) \
 	  i915_active.o \
-	  i915_buddy.o \
 	  i915_cmd_parser.o \
 	  i915_gem_evict.o \
 	  i915_gem_gtt.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
index f44bdd08f7cb..f42803ea48f2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
@@ -4,16 +4,70 @@
  */
 
 #include "intel_memory_region.h"
+#include "intel_region_ttm.h"
 #include "gem/i915_gem_region.h"
 #include "gem/i915_gem_lmem.h"
 #include "i915_drv.h"
 
+static void lmem_put_pages(struct drm_i915_gem_object *obj,
+				  struct sg_table *pages)
+{
+	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
+	obj->mm.dirty = false;
+	sg_free_table(pages);
+	kfree(pages);
+}
+
+static int lmem_get_pages(struct drm_i915_gem_object *obj)
+{
+	unsigned int flags;
+	struct sg_table *pages;
+
+	flags = I915_ALLOC_MIN_PAGE_SIZE;
+	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
+		flags |= I915_ALLOC_CONTIGUOUS;
+
+	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
+							 obj->base.size,
+							 flags);
+	if (IS_ERR(obj->mm.st_mm_node))
+		return PTR_ERR(obj->mm.st_mm_node);
+
+	/* Range manager is always contigous */
+	if (obj->mm.region->is_range_manager)
+		obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
+	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
+	if (IS_ERR(pages))
+		return PTR_ERR(pages);
+
+	__i915_gem_object_set_pages(obj, pages,
+				    i915_sg_dma_page_sizes(pages->sgl));
+
+	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
+		void __iomem *vaddr =
+			i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
+
+		if (!vaddr) {
+			struct sg_table *pages =
+				__i915_gem_object_unset_pages(obj);
+
+			if (!IS_ERR_OR_NULL(pages))
+				lmem_put_pages(obj, pages);
+		}
+
+		memset_io(vaddr, 0, obj->base.size);
+		io_mapping_unmap(vaddr);
+	}
+
+	return 0;
+}
+
 const struct drm_i915_gem_object_ops i915_gem_lmem_obj_ops = {
 	.name = "i915_gem_object_lmem",
 	.flags = I915_GEM_OBJECT_HAS_IOMEM,
 
-	.get_pages = i915_gem_object_get_pages_buddy,
-	.put_pages = i915_gem_object_put_pages_buddy,
+	.get_pages = lmem_get_pages,
+	.put_pages = lmem_put_pages,
 	.release = i915_gem_object_release_memory_region,
 };
 
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 450340a73186..dbd7fffe956e 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -232,10 +232,12 @@ struct drm_i915_gem_object {
 		 * Memory region for this object.
 		 */
 		struct intel_memory_region *region;
+
 		/**
-		 * List of memory region blocks allocated for this object.
+		 * Memory manager node allocated for this object.
 		 */
-		struct list_head blocks;
+		void *st_mm_node;
+
 		/**
 		 * Element within memory_region->objects or region->purgeable
 		 * if the object is marked as DONTNEED. Access is protected by
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
index aed8a37ccdc9..62ee2185a41b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
@@ -473,7 +473,8 @@ __i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
 
 	might_sleep();
 	GEM_BUG_ON(n >= obj->base.size >> PAGE_SHIFT);
-	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
+	if (!i915_gem_object_has_pinned_pages(obj))
+		assert_object_held(obj);
 
 	/* As we iterate forward through the sg, we record each entry in a
 	 * radixtree for quick repeated (backwards) lookups. If we have seen
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
index ce8fcfc54079..f25e6646c5b7 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
@@ -8,129 +8,9 @@
 #include "i915_drv.h"
 #include "i915_trace.h"
 
-void
-i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
-				struct sg_table *pages)
-{
-	__intel_memory_region_put_pages_buddy(obj->mm.region, &obj->mm.blocks);
-
-	obj->mm.dirty = false;
-	sg_free_table(pages);
-	kfree(pages);
-}
-
-int
-i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
-{
-	const u64 max_segment = i915_sg_segment_size();
-	struct intel_memory_region *mem = obj->mm.region;
-	struct list_head *blocks = &obj->mm.blocks;
-	resource_size_t size = obj->base.size;
-	resource_size_t prev_end;
-	struct i915_buddy_block *block;
-	unsigned int flags;
-	struct sg_table *st;
-	struct scatterlist *sg;
-	unsigned int sg_page_sizes;
-	int ret;
-
-	st = kmalloc(sizeof(*st), GFP_KERNEL);
-	if (!st)
-		return -ENOMEM;
-
-	if (sg_alloc_table(st, size >> PAGE_SHIFT, GFP_KERNEL)) {
-		kfree(st);
-		return -ENOMEM;
-	}
-
-	flags = I915_ALLOC_MIN_PAGE_SIZE;
-	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
-		flags |= I915_ALLOC_CONTIGUOUS;
-
-	ret = __intel_memory_region_get_pages_buddy(mem, size, flags, blocks);
-	if (ret)
-		goto err_free_sg;
-
-	GEM_BUG_ON(list_empty(blocks));
-
-	sg = st->sgl;
-	st->nents = 0;
-	sg_page_sizes = 0;
-	prev_end = (resource_size_t)-1;
-
-	list_for_each_entry(block, blocks, link) {
-		u64 block_size, offset;
-
-		block_size = min_t(u64, size,
-				   i915_buddy_block_size(&mem->mm, block));
-		offset = i915_buddy_block_offset(block);
-
-		while (block_size) {
-			u64 len;
-
-			if (offset != prev_end || sg->length >= max_segment) {
-				if (st->nents) {
-					sg_page_sizes |= sg->length;
-					sg = __sg_next(sg);
-				}
-
-				sg_dma_address(sg) = mem->region.start + offset;
-				sg_dma_len(sg) = 0;
-				sg->length = 0;
-				st->nents++;
-			}
-
-			len = min(block_size, max_segment - sg->length);
-			sg->length += len;
-			sg_dma_len(sg) += len;
-
-			offset += len;
-			block_size -= len;
-
-			prev_end = offset;
-		}
-	}
-
-	sg_page_sizes |= sg->length;
-	sg_mark_end(sg);
-	i915_sg_trim(st);
-
-	/* Intended for kernel internal use only */
-	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
-		struct scatterlist *sg;
-		unsigned long i;
-
-		for_each_sg(st->sgl, sg, st->nents, i) {
-			unsigned int length;
-			void __iomem *vaddr;
-			dma_addr_t daddr;
-
-			daddr = sg_dma_address(sg);
-			daddr -= mem->region.start;
-			length = sg_dma_len(sg);
-
-			vaddr = io_mapping_map_wc(&mem->iomap, daddr, length);
-			memset64((void __force *)vaddr, 0, length / sizeof(u64));
-			io_mapping_unmap(vaddr);
-		}
-
-		wmb();
-	}
-
-	__i915_gem_object_set_pages(obj, st, sg_page_sizes);
-
-	return 0;
-
-err_free_sg:
-	sg_free_table(st);
-	kfree(st);
-	return ret;
-}
-
 void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
 					struct intel_memory_region *mem)
 {
-	INIT_LIST_HEAD(&obj->mm.blocks);
 	obj->mm.region = intel_memory_region_get(mem);
 
 	if (obj->base.size <= mem->min_page_size)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.h b/drivers/gpu/drm/i915/gem/i915_gem_region.h
index ebddc86d78f7..84fcb3297400 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_region.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_region.h
@@ -12,10 +12,6 @@ struct intel_memory_region;
 struct drm_i915_gem_object;
 struct sg_table;
 
-int i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj);
-void i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
-				     struct sg_table *pages);
-
 void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
 					struct intel_memory_region *mem);
 void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index a9bfa66c8da1..5d16c4462fda 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -628,11 +628,13 @@ static const struct intel_memory_region_ops shmem_region_ops = {
 	.init_object = shmem_object_init,
 };
 
-struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915)
+struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915,
+						 u16 type, u16 instance)
 {
 	return intel_memory_region_create(i915, 0,
 					  totalram_pages() << PAGE_SHIFT,
 					  PAGE_SIZE, 0,
+					  type, instance,
 					  &shmem_region_ops);
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
index 293f640faa0a..c42abee206da 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
@@ -770,7 +770,8 @@ static const struct intel_memory_region_ops i915_region_stolen_lmem_ops = {
 };
 
 struct intel_memory_region *
-i915_gem_stolen_lmem_setup(struct drm_i915_private *i915)
+i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance)
 {
 	struct intel_uncore *uncore = &i915->uncore;
 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
@@ -788,6 +789,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915)
 
 	mem = intel_memory_region_create(i915, lmem_base, lmem_size,
 					 I915_GTT_PAGE_SIZE_4K, io_start,
+					 type, instance,
 					 &i915_region_stolen_lmem_ops);
 	if (IS_ERR(mem))
 		return mem;
@@ -809,14 +811,15 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915)
 }
 
 struct intel_memory_region*
-i915_gem_stolen_smem_setup(struct drm_i915_private *i915)
+i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance)
 {
 	struct intel_memory_region *mem;
 
 	mem = intel_memory_region_create(i915,
 					 intel_graphics_stolen_res.start,
 					 resource_size(&intel_graphics_stolen_res),
-					 PAGE_SIZE, 0,
+					 PAGE_SIZE, 0, type, instance,
 					 &i915_region_stolen_smem_ops);
 	if (IS_ERR(mem))
 		return mem;
@@ -824,7 +827,6 @@ i915_gem_stolen_smem_setup(struct drm_i915_private *i915)
 	intel_memory_region_set_name(mem, "stolen-system");
 
 	mem->private = true;
-
 	return mem;
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
index 2bec6c367b9c..ccdf7befc571 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
@@ -21,8 +21,13 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv,
 					 u64 end);
 void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
 				 struct drm_mm_node *node);
-struct intel_memory_region *i915_gem_stolen_smem_setup(struct drm_i915_private *i915);
-struct intel_memory_region *i915_gem_stolen_lmem_setup(struct drm_i915_private *i915);
+struct intel_memory_region *
+i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance);
+struct intel_memory_region *
+i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
+			   u16 instance);
+
 struct drm_i915_gem_object *
 i915_gem_object_create_stolen(struct drm_i915_private *dev_priv,
 			      resource_size_t size);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
index 8d77dcbad059..3f88ecdee031 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -68,8 +68,6 @@ int intel_gt_probe_lmem(struct intel_gt *gt)
 	id = INTEL_REGION_LMEM;
 
 	mem->id = id;
-	mem->type = INTEL_MEMORY_LOCAL;
-	mem->instance = 0;
 
 	intel_memory_region_set_name(mem, "local%u", mem->instance);
 
diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
index 73fceb0c25fc..f7366b054f8e 100644
--- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c
+++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
@@ -5,6 +5,8 @@
 
 #include "i915_drv.h"
 #include "intel_memory_region.h"
+#include "intel_region_lmem.h"
+#include "intel_region_ttm.h"
 #include "gem/i915_gem_lmem.h"
 #include "gem/i915_gem_region.h"
 #include "intel_region_lmem.h"
@@ -66,9 +68,9 @@ static void release_fake_lmem_bar(struct intel_memory_region *mem)
 static void
 region_lmem_release(struct intel_memory_region *mem)
 {
-	release_fake_lmem_bar(mem);
+	intel_region_ttm_fini(mem);
 	io_mapping_fini(&mem->iomap);
-	intel_memory_region_release_buddy(mem);
+	release_fake_lmem_bar(mem);
 }
 
 static int
@@ -83,12 +85,21 @@ region_lmem_init(struct intel_memory_region *mem)
 
 	if (!io_mapping_init_wc(&mem->iomap,
 				mem->io_start,
-				resource_size(&mem->region)))
-		return -EIO;
+				resource_size(&mem->region))) {
+		ret = -EIO;
+		goto out_no_io;
+	}
 
-	ret = intel_memory_region_init_buddy(mem);
+	ret = intel_region_ttm_init(mem);
 	if (ret)
-		io_mapping_fini(&mem->iomap);
+		goto out_no_buddy;
+
+	return 0;
+
+out_no_buddy:
+	io_mapping_fini(&mem->iomap);
+out_no_io:
+	release_fake_lmem_bar(mem);
 
 	return ret;
 }
@@ -127,6 +138,8 @@ intel_gt_setup_fake_lmem(struct intel_gt *gt)
 					 mappable_end,
 					 PAGE_SIZE,
 					 io_start,
+					 INTEL_MEMORY_LOCAL,
+					 0,
 					 &intel_region_lmem_ops);
 	if (!IS_ERR(mem)) {
 		drm_info(&i915->drm, "Intel graphics fake LMEM: %pR\n",
@@ -198,6 +211,8 @@ static struct intel_memory_region *setup_lmem(struct intel_gt *gt)
 					 lmem_size,
 					 I915_GTT_PAGE_SIZE_4K,
 					 io_start,
+					 INTEL_MEMORY_LOCAL,
+					 0,
 					 &intel_region_lmem_ops);
 	if (IS_ERR(mem))
 		return mem;
diff --git a/drivers/gpu/drm/i915/i915_buddy.c b/drivers/gpu/drm/i915/i915_buddy.c
deleted file mode 100644
index 3a2f6eecb2fc..000000000000
--- a/drivers/gpu/drm/i915/i915_buddy.c
+++ /dev/null
@@ -1,435 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include <linux/kmemleak.h>
-#include <linux/slab.h>
-
-#include "i915_buddy.h"
-
-#include "i915_gem.h"
-#include "i915_globals.h"
-#include "i915_utils.h"
-
-static struct i915_global_block {
-	struct i915_global base;
-	struct kmem_cache *slab_blocks;
-} global;
-
-static void i915_global_buddy_shrink(void)
-{
-	kmem_cache_shrink(global.slab_blocks);
-}
-
-static void i915_global_buddy_exit(void)
-{
-	kmem_cache_destroy(global.slab_blocks);
-}
-
-static struct i915_global_block global = { {
-	.shrink = i915_global_buddy_shrink,
-	.exit = i915_global_buddy_exit,
-} };
-
-int __init i915_global_buddy_init(void)
-{
-	global.slab_blocks = KMEM_CACHE(i915_buddy_block, SLAB_HWCACHE_ALIGN);
-	if (!global.slab_blocks)
-		return -ENOMEM;
-
-	i915_global_register(&global.base);
-	return 0;
-}
-
-static struct i915_buddy_block *i915_block_alloc(struct i915_buddy_block *parent,
-						 unsigned int order,
-						 u64 offset)
-{
-	struct i915_buddy_block *block;
-
-	GEM_BUG_ON(order > I915_BUDDY_MAX_ORDER);
-
-	block = kmem_cache_zalloc(global.slab_blocks, GFP_KERNEL);
-	if (!block)
-		return NULL;
-
-	block->header = offset;
-	block->header |= order;
-	block->parent = parent;
-
-	GEM_BUG_ON(block->header & I915_BUDDY_HEADER_UNUSED);
-	return block;
-}
-
-static void i915_block_free(struct i915_buddy_block *block)
-{
-	kmem_cache_free(global.slab_blocks, block);
-}
-
-static void mark_allocated(struct i915_buddy_block *block)
-{
-	block->header &= ~I915_BUDDY_HEADER_STATE;
-	block->header |= I915_BUDDY_ALLOCATED;
-
-	list_del(&block->link);
-}
-
-static void mark_free(struct i915_buddy_mm *mm,
-		      struct i915_buddy_block *block)
-{
-	block->header &= ~I915_BUDDY_HEADER_STATE;
-	block->header |= I915_BUDDY_FREE;
-
-	list_add(&block->link,
-		 &mm->free_list[i915_buddy_block_order(block)]);
-}
-
-static void mark_split(struct i915_buddy_block *block)
-{
-	block->header &= ~I915_BUDDY_HEADER_STATE;
-	block->header |= I915_BUDDY_SPLIT;
-
-	list_del(&block->link);
-}
-
-int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size)
-{
-	unsigned int i;
-	u64 offset;
-
-	if (size < chunk_size)
-		return -EINVAL;
-
-	if (chunk_size < PAGE_SIZE)
-		return -EINVAL;
-
-	if (!is_power_of_2(chunk_size))
-		return -EINVAL;
-
-	size = round_down(size, chunk_size);
-
-	mm->size = size;
-	mm->chunk_size = chunk_size;
-	mm->max_order = ilog2(size) - ilog2(chunk_size);
-
-	GEM_BUG_ON(mm->max_order > I915_BUDDY_MAX_ORDER);
-
-	mm->free_list = kmalloc_array(mm->max_order + 1,
-				      sizeof(struct list_head),
-				      GFP_KERNEL);
-	if (!mm->free_list)
-		return -ENOMEM;
-
-	for (i = 0; i <= mm->max_order; ++i)
-		INIT_LIST_HEAD(&mm->free_list[i]);
-
-	mm->n_roots = hweight64(size);
-
-	mm->roots = kmalloc_array(mm->n_roots,
-				  sizeof(struct i915_buddy_block *),
-				  GFP_KERNEL);
-	if (!mm->roots)
-		goto out_free_list;
-
-	offset = 0;
-	i = 0;
-
-	/*
-	 * Split into power-of-two blocks, in case we are given a size that is
-	 * not itself a power-of-two.
-	 */
-	do {
-		struct i915_buddy_block *root;
-		unsigned int order;
-		u64 root_size;
-
-		root_size = rounddown_pow_of_two(size);
-		order = ilog2(root_size) - ilog2(chunk_size);
-
-		root = i915_block_alloc(NULL, order, offset);
-		if (!root)
-			goto out_free_roots;
-
-		mark_free(mm, root);
-
-		GEM_BUG_ON(i > mm->max_order);
-		GEM_BUG_ON(i915_buddy_block_size(mm, root) < chunk_size);
-
-		mm->roots[i] = root;
-
-		offset += root_size;
-		size -= root_size;
-		i++;
-	} while (size);
-
-	return 0;
-
-out_free_roots:
-	while (i--)
-		i915_block_free(mm->roots[i]);
-	kfree(mm->roots);
-out_free_list:
-	kfree(mm->free_list);
-	return -ENOMEM;
-}
-
-void i915_buddy_fini(struct i915_buddy_mm *mm)
-{
-	int i;
-
-	for (i = 0; i < mm->n_roots; ++i) {
-		GEM_WARN_ON(!i915_buddy_block_is_free(mm->roots[i]));
-		i915_block_free(mm->roots[i]);
-	}
-
-	kfree(mm->roots);
-	kfree(mm->free_list);
-}
-
-static int split_block(struct i915_buddy_mm *mm,
-		       struct i915_buddy_block *block)
-{
-	unsigned int block_order = i915_buddy_block_order(block) - 1;
-	u64 offset = i915_buddy_block_offset(block);
-
-	GEM_BUG_ON(!i915_buddy_block_is_free(block));
-	GEM_BUG_ON(!i915_buddy_block_order(block));
-
-	block->left = i915_block_alloc(block, block_order, offset);
-	if (!block->left)
-		return -ENOMEM;
-
-	block->right = i915_block_alloc(block, block_order,
-					offset + (mm->chunk_size << block_order));
-	if (!block->right) {
-		i915_block_free(block->left);
-		return -ENOMEM;
-	}
-
-	mark_free(mm, block->left);
-	mark_free(mm, block->right);
-
-	mark_split(block);
-
-	return 0;
-}
-
-static struct i915_buddy_block *
-get_buddy(struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *parent;
-
-	parent = block->parent;
-	if (!parent)
-		return NULL;
-
-	if (parent->left == block)
-		return parent->right;
-
-	return parent->left;
-}
-
-static void __i915_buddy_free(struct i915_buddy_mm *mm,
-			      struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *parent;
-
-	while ((parent = block->parent)) {
-		struct i915_buddy_block *buddy;
-
-		buddy = get_buddy(block);
-
-		if (!i915_buddy_block_is_free(buddy))
-			break;
-
-		list_del(&buddy->link);
-
-		i915_block_free(block);
-		i915_block_free(buddy);
-
-		block = parent;
-	}
-
-	mark_free(mm, block);
-}
-
-void i915_buddy_free(struct i915_buddy_mm *mm,
-		     struct i915_buddy_block *block)
-{
-	GEM_BUG_ON(!i915_buddy_block_is_allocated(block));
-	__i915_buddy_free(mm, block);
-}
-
-void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects)
-{
-	struct i915_buddy_block *block, *on;
-
-	list_for_each_entry_safe(block, on, objects, link) {
-		i915_buddy_free(mm, block);
-		cond_resched();
-	}
-	INIT_LIST_HEAD(objects);
-}
-
-/*
- * Allocate power-of-two block. The order value here translates to:
- *
- *   0 = 2^0 * mm->chunk_size
- *   1 = 2^1 * mm->chunk_size
- *   2 = 2^2 * mm->chunk_size
- *   ...
- */
-struct i915_buddy_block *
-i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order)
-{
-	struct i915_buddy_block *block = NULL;
-	unsigned int i;
-	int err;
-
-	for (i = order; i <= mm->max_order; ++i) {
-		block = list_first_entry_or_null(&mm->free_list[i],
-						 struct i915_buddy_block,
-						 link);
-		if (block)
-			break;
-	}
-
-	if (!block)
-		return ERR_PTR(-ENOSPC);
-
-	GEM_BUG_ON(!i915_buddy_block_is_free(block));
-
-	while (i != order) {
-		err = split_block(mm, block);
-		if (unlikely(err))
-			goto out_free;
-
-		/* Go low */
-		block = block->left;
-		i--;
-	}
-
-	mark_allocated(block);
-	kmemleak_update_trace(block);
-	return block;
-
-out_free:
-	if (i != order)
-		__i915_buddy_free(mm, block);
-	return ERR_PTR(err);
-}
-
-static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
-{
-	return s1 <= e2 && e1 >= s2;
-}
-
-static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
-{
-	return s1 <= s2 && e1 >= e2;
-}
-
-/*
- * Allocate range. Note that it's safe to chain together multiple alloc_ranges
- * with the same blocks list.
- *
- * Intended for pre-allocating portions of the address space, for example to
- * reserve a block for the initial framebuffer or similar, hence the expectation
- * here is that i915_buddy_alloc() is still the main vehicle for
- * allocations, so if that's not the case then the drm_mm range allocator is
- * probably a much better fit, and so you should probably go use that instead.
- */
-int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
-			   struct list_head *blocks,
-			   u64 start, u64 size)
-{
-	struct i915_buddy_block *block;
-	struct i915_buddy_block *buddy;
-	LIST_HEAD(allocated);
-	LIST_HEAD(dfs);
-	u64 end;
-	int err;
-	int i;
-
-	if (size < mm->chunk_size)
-		return -EINVAL;
-
-	if (!IS_ALIGNED(size | start, mm->chunk_size))
-		return -EINVAL;
-
-	if (range_overflows(start, size, mm->size))
-		return -EINVAL;
-
-	for (i = 0; i < mm->n_roots; ++i)
-		list_add_tail(&mm->roots[i]->tmp_link, &dfs);
-
-	end = start + size - 1;
-
-	do {
-		u64 block_start;
-		u64 block_end;
-
-		block = list_first_entry_or_null(&dfs,
-						 struct i915_buddy_block,
-						 tmp_link);
-		if (!block)
-			break;
-
-		list_del(&block->tmp_link);
-
-		block_start = i915_buddy_block_offset(block);
-		block_end = block_start + i915_buddy_block_size(mm, block) - 1;
-
-		if (!overlaps(start, end, block_start, block_end))
-			continue;
-
-		if (i915_buddy_block_is_allocated(block)) {
-			err = -ENOSPC;
-			goto err_free;
-		}
-
-		if (contains(start, end, block_start, block_end)) {
-			if (!i915_buddy_block_is_free(block)) {
-				err = -ENOSPC;
-				goto err_free;
-			}
-
-			mark_allocated(block);
-			list_add_tail(&block->link, &allocated);
-			continue;
-		}
-
-		if (!i915_buddy_block_is_split(block)) {
-			err = split_block(mm, block);
-			if (unlikely(err))
-				goto err_undo;
-		}
-
-		list_add(&block->right->tmp_link, &dfs);
-		list_add(&block->left->tmp_link, &dfs);
-	} while (1);
-
-	list_splice_tail(&allocated, blocks);
-	return 0;
-
-err_undo:
-	/*
-	 * We really don't want to leave around a bunch of split blocks, since
-	 * bigger is better, so make sure we merge everything back before we
-	 * free the allocated blocks.
-	 */
-	buddy = get_buddy(block);
-	if (buddy &&
-	    (i915_buddy_block_is_free(block) &&
-	     i915_buddy_block_is_free(buddy)))
-		__i915_buddy_free(mm, block);
-
-err_free:
-	i915_buddy_free_list(mm, &allocated);
-	return err;
-}
-
-#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
-#include "selftests/i915_buddy.c"
-#endif
diff --git a/drivers/gpu/drm/i915/i915_buddy.h b/drivers/gpu/drm/i915/i915_buddy.h
deleted file mode 100644
index 9ce5200f4001..000000000000
--- a/drivers/gpu/drm/i915/i915_buddy.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __I915_BUDDY_H__
-#define __I915_BUDDY_H__
-
-#include <linux/bitops.h>
-#include <linux/list.h>
-
-struct i915_buddy_block {
-#define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
-#define I915_BUDDY_HEADER_STATE  GENMASK_ULL(11, 10)
-#define   I915_BUDDY_ALLOCATED	   (1 << 10)
-#define   I915_BUDDY_FREE	   (2 << 10)
-#define   I915_BUDDY_SPLIT	   (3 << 10)
-/* Free to be used, if needed in the future */
-#define I915_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6)
-#define I915_BUDDY_HEADER_ORDER  GENMASK_ULL(5, 0)
-	u64 header;
-
-	struct i915_buddy_block *left;
-	struct i915_buddy_block *right;
-	struct i915_buddy_block *parent;
-
-	void *private; /* owned by creator */
-
-	/*
-	 * While the block is allocated by the user through i915_buddy_alloc*,
-	 * the user has ownership of the link, for example to maintain within
-	 * a list, if so desired. As soon as the block is freed with
-	 * i915_buddy_free* ownership is given back to the mm.
-	 */
-	struct list_head link;
-	struct list_head tmp_link;
-};
-
-/* Order-zero must be at least PAGE_SIZE */
-#define I915_BUDDY_MAX_ORDER (63 - PAGE_SHIFT)
-
-/*
- * Binary Buddy System.
- *
- * Locking should be handled by the user, a simple mutex around
- * i915_buddy_alloc* and i915_buddy_free* should suffice.
- */
-struct i915_buddy_mm {
-	/* Maintain a free list for each order. */
-	struct list_head *free_list;
-
-	/*
-	 * Maintain explicit binary tree(s) to track the allocation of the
-	 * address space. This gives us a simple way of finding a buddy block
-	 * and performing the potentially recursive merge step when freeing a
-	 * block.  Nodes are either allocated or free, in which case they will
-	 * also exist on the respective free list.
-	 */
-	struct i915_buddy_block **roots;
-
-	/*
-	 * Anything from here is public, and remains static for the lifetime of
-	 * the mm. Everything above is considered do-not-touch.
-	 */
-	unsigned int n_roots;
-	unsigned int max_order;
-
-	/* Must be at least PAGE_SIZE */
-	u64 chunk_size;
-	u64 size;
-};
-
-static inline u64
-i915_buddy_block_offset(struct i915_buddy_block *block)
-{
-	return block->header & I915_BUDDY_HEADER_OFFSET;
-}
-
-static inline unsigned int
-i915_buddy_block_order(struct i915_buddy_block *block)
-{
-	return block->header & I915_BUDDY_HEADER_ORDER;
-}
-
-static inline unsigned int
-i915_buddy_block_state(struct i915_buddy_block *block)
-{
-	return block->header & I915_BUDDY_HEADER_STATE;
-}
-
-static inline bool
-i915_buddy_block_is_allocated(struct i915_buddy_block *block)
-{
-	return i915_buddy_block_state(block) == I915_BUDDY_ALLOCATED;
-}
-
-static inline bool
-i915_buddy_block_is_free(struct i915_buddy_block *block)
-{
-	return i915_buddy_block_state(block) == I915_BUDDY_FREE;
-}
-
-static inline bool
-i915_buddy_block_is_split(struct i915_buddy_block *block)
-{
-	return i915_buddy_block_state(block) == I915_BUDDY_SPLIT;
-}
-
-static inline u64
-i915_buddy_block_size(struct i915_buddy_mm *mm,
-		      struct i915_buddy_block *block)
-{
-	return mm->chunk_size << i915_buddy_block_order(block);
-}
-
-int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size);
-
-void i915_buddy_fini(struct i915_buddy_mm *mm);
-
-struct i915_buddy_block *
-i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order);
-
-int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
-			   struct list_head *blocks,
-			   u64 start, u64 size);
-
-void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block *block);
-
-void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects);
-
-#endif
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 5118dc8386b2..c89ed09b8d63 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -84,6 +84,7 @@
 #include "intel_gvt.h"
 #include "intel_memory_region.h"
 #include "intel_pm.h"
+#include "intel_region_ttm.h"
 #include "intel_sideband.h"
 #include "vlv_suspend.h"
 
@@ -335,6 +336,10 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
 	if (ret < 0)
 		goto err_workqueues;
 
+	ret = intel_region_ttm_device_init(dev_priv);
+	if (ret)
+		goto err_ttm;
+
 	intel_wopcm_init_early(&dev_priv->wopcm);
 
 	intel_gt_init_early(&dev_priv->gt, dev_priv);
@@ -359,6 +364,8 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
 err_gem:
 	i915_gem_cleanup_early(dev_priv);
 	intel_gt_driver_late_release(&dev_priv->gt);
+	intel_region_ttm_device_fini(dev_priv);
+err_ttm:
 	vlv_suspend_cleanup(dev_priv);
 err_workqueues:
 	i915_workqueues_cleanup(dev_priv);
@@ -376,6 +383,7 @@ static void i915_driver_late_release(struct drm_i915_private *dev_priv)
 	intel_power_domains_cleanup(dev_priv);
 	i915_gem_cleanup_early(dev_priv);
 	intel_gt_driver_late_release(&dev_priv->gt);
+	intel_region_ttm_device_fini(dev_priv);
 	vlv_suspend_cleanup(dev_priv);
 	i915_workqueues_cleanup(dev_priv);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 128198e8b4d0..1276a2f60740 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -60,6 +60,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_connector.h>
 #include <drm/i915_mei_hdcp_interface.h>
+#include <drm/ttm/ttm_device.h>
 
 #include "i915_params.h"
 #include "i915_reg.h"
@@ -1166,6 +1167,9 @@ struct drm_i915_private {
 	/* Mutex to protect the above hdcp component related values. */
 	struct mutex hdcp_comp_mutex;
 
+	/* The TTM device structure. */
+	struct ttm_device bdev;
+
 	I915_SELFTEST_DECLARE(struct i915_selftest_stash selftest;)
 
 	/*
@@ -1751,7 +1755,8 @@ void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv);
 void i915_gem_init_early(struct drm_i915_private *dev_priv);
 void i915_gem_cleanup_early(struct drm_i915_private *dev_priv);
 
-struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915);
+struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915,
+						 u16 type, u16 instance);
 
 static inline void i915_gem_drain_freed_objects(struct drm_i915_private *i915)
 {
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d0018c5f88bd..180f6e9107d4 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1109,6 +1109,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
 	}
 
 	i915_gem_drain_freed_objects(dev_priv);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_globals.c b/drivers/gpu/drm/i915/i915_globals.c
index 3aa213684293..77f1911c463b 100644
--- a/drivers/gpu/drm/i915/i915_globals.c
+++ b/drivers/gpu/drm/i915/i915_globals.c
@@ -87,7 +87,6 @@ static void __i915_globals_cleanup(void)
 
 static __initconst int (* const initfn[])(void) = {
 	i915_global_active_init,
-	i915_global_buddy_init,
 	i915_global_context_init,
 	i915_global_gem_context_init,
 	i915_global_objects_init,
diff --git a/drivers/gpu/drm/i915/i915_globals.h b/drivers/gpu/drm/i915/i915_globals.h
index b2f5cd9b9b1a..2d199f411a4a 100644
--- a/drivers/gpu/drm/i915/i915_globals.h
+++ b/drivers/gpu/drm/i915/i915_globals.h
@@ -27,7 +27,6 @@ void i915_globals_exit(void);
 
 /* constructors */
 int i915_global_active_init(void);
-int i915_global_buddy_init(void);
 int i915_global_context_init(void);
 int i915_global_gem_context_init(void);
 int i915_global_objects_init(void);
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
index cc6b3846a8c7..69e9e6c3135e 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -6,6 +6,10 @@
 
 #include "i915_scatterlist.h"
 
+#include <drm/drm_mm.h>
+
+#include <linux/slab.h>
+
 bool i915_sg_trim(struct sg_table *orig_st)
 {
 	struct sg_table new_st;
@@ -34,6 +38,72 @@ bool i915_sg_trim(struct sg_table *orig_st)
 	return true;
 }
 
+/**
+ * i915_sg_from_mm_node - Create an sg_table from a struct drm_mm_node
+ * @node: The drm_mm_node.
+ * @region_start: An offset to add to the dma addresses of the sg list.
+ *
+ * Create a struct sg_table, initializing it from a struct drm_mm_node,
+ * taking a maximum segment length into account, splitting into segments
+ * if necessary.
+ *
+ * Return: A pointer to a kmalloced struct sg_table on success, negative
+ * error code cast to an error pointer on failure.
+ */
+struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
+				      u64 region_start)
+{
+	const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
+	u64 segment_pages = max_segment >> PAGE_SHIFT;
+	u64 block_size, offset, prev_end;
+	struct sg_table *st;
+	struct scatterlist *sg;
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	if (sg_alloc_table(st, DIV_ROUND_UP(node->size, segment_pages),
+			   GFP_KERNEL)) {
+		kfree(st);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sg = st->sgl;
+	st->nents = 0;
+	prev_end = (resource_size_t)-1;
+	block_size = node->size << PAGE_SHIFT;
+	offset = node->start << PAGE_SHIFT;
+
+	while (block_size) {
+		u64 len;
+
+		if (offset != prev_end || sg->length >= max_segment) {
+			if (st->nents)
+				sg = __sg_next(sg);
+
+			sg_dma_address(sg) = region_start + offset;
+			sg_dma_len(sg) = 0;
+			sg->length = 0;
+			st->nents++;
+		}
+
+		len = min(block_size, max_segment - sg->length);
+		sg->length += len;
+		sg_dma_len(sg) += len;
+
+		offset += len;
+		block_size -= len;
+
+		prev_end = offset;
+	}
+
+	sg_mark_end(sg);
+	i915_sg_trim(st);
+
+	return st;
+}
+
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftests/scatterlist.c"
 #endif
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h
index 9cb26a224034..75c320020780 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.h
+++ b/drivers/gpu/drm/i915/i915_scatterlist.h
@@ -13,6 +13,8 @@
 
 #include "i915_gem.h"
 
+struct drm_mm_node;
+
 /*
  * Optimised SGL iterator for GEM objects
  */
@@ -133,4 +135,37 @@ static inline unsigned int i915_sg_segment_size(void)
 
 bool i915_sg_trim(struct sg_table *orig_st);
 
+/**
+ * i915_sg_dma_page_sizes - Calculate page sizes from a scatterlist
+ * @sg: The scatterlist from which to calculate page sizes
+ *
+ * Return: a value with bits sets for relevant page sizes.
+ */
+static inline unsigned int i915_sg_dma_page_sizes(struct scatterlist *sg)
+{
+	unsigned int page_sizes;
+
+	page_sizes = 0;
+	while (sg) {
+		GEM_BUG_ON(sg->offset);
+		GEM_BUG_ON(!IS_ALIGNED(sg->dma_length, PAGE_SIZE));
+		page_sizes |= sg->dma_length;
+		sg = __sg_next(sg);
+	}
+
+	/*
+	 * Is this necessary to support building large GPU pages from
+	 * even larger segments?
+	 */
+
+	if (page_sizes > SZ_64K)
+		page_sizes |= SZ_64K;
+	if (page_sizes > SZ_2M)
+		page_sizes |= SZ_2M;
+
+	return page_sizes;
+}
+
+struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
+				      u64 region_start);
 #endif
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index d98e8b81d322..4092cc987679 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -28,6 +28,11 @@ static const struct {
 	},
 };
 
+struct intel_region_reserve {
+	struct list_head link;
+	void *node;
+};
+
 struct intel_memory_region *
 intel_memory_region_lookup(struct drm_i915_private *i915,
 			   u16 class, u16 instance)
@@ -58,146 +63,61 @@ intel_memory_region_by_type(struct drm_i915_private *i915,
 	return NULL;
 }
 
-static u64
-intel_memory_region_free_pages(struct intel_memory_region *mem,
-			       struct list_head *blocks)
+/**
+ * intel_memory_region_unreserve - Unreserve all previously reserved
+ * ranges
+ * @mem: The region containing the reserved ranges.
+ */
+void intel_memory_region_unreserve(struct intel_memory_region *mem)
 {
-	struct i915_buddy_block *block, *on;
-	u64 size = 0;
+	struct intel_region_reserve *reserve, *next;
 
-	list_for_each_entry_safe(block, on, blocks, link) {
-		size += i915_buddy_block_size(&mem->mm, block);
-		i915_buddy_free(&mem->mm, block);
-	}
-	INIT_LIST_HEAD(blocks);
+	if (!mem->priv_ops || !mem->priv_ops->free)
+		return;
 
-	return size;
-}
-
-void
-__intel_memory_region_put_pages_buddy(struct intel_memory_region *mem,
-				      struct list_head *blocks)
-{
 	mutex_lock(&mem->mm_lock);
-	mem->avail += intel_memory_region_free_pages(mem, blocks);
-	mutex_unlock(&mem->mm_lock);
-}
-
-void
-__intel_memory_region_put_block_buddy(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);
-}
-
-int
-__intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
-				      resource_size_t size,
-				      unsigned int flags,
-				      struct list_head *blocks)
-{
-	unsigned int min_order = 0;
-	unsigned long n_pages;
-
-	GEM_BUG_ON(!IS_ALIGNED(size, mem->mm.chunk_size));
-	GEM_BUG_ON(!list_empty(blocks));
-
-	if (flags & I915_ALLOC_MIN_PAGE_SIZE) {
-		min_order = ilog2(mem->min_page_size) -
-			    ilog2(mem->mm.chunk_size);
-	}
-
-	if (flags & I915_ALLOC_CONTIGUOUS) {
-		size = roundup_pow_of_two(size);
-		min_order = ilog2(size) - ilog2(mem->mm.chunk_size);
+	list_for_each_entry_safe(reserve, next, &mem->reserved, link) {
+		list_del(&reserve->link);
+		mem->priv_ops->free(mem, reserve->node);
+		kfree(reserve);
 	}
-
-	if (size > mem->mm.size)
-		return -E2BIG;
-
-	n_pages = size >> ilog2(mem->mm.chunk_size);
-
-	mutex_lock(&mem->mm_lock);
-
-	do {
-		struct i915_buddy_block *block;
-		unsigned int order;
-
-		order = fls(n_pages) - 1;
-		GEM_BUG_ON(order > mem->mm.max_order);
-		GEM_BUG_ON(order < min_order);
-
-		do {
-			block = i915_buddy_alloc(&mem->mm, order);
-			if (!IS_ERR(block))
-				break;
-
-			if (order-- == min_order)
-				goto err_free_blocks;
-		} while (1);
-
-		n_pages -= BIT(order);
-
-		block->private = mem;
-		list_add_tail(&block->link, blocks);
-
-		if (!n_pages)
-			break;
-	} while (1);
-
-	mem->avail -= size;
 	mutex_unlock(&mem->mm_lock);
-	return 0;
-
-err_free_blocks:
-	intel_memory_region_free_pages(mem, blocks);
-	mutex_unlock(&mem->mm_lock);
-	return -ENXIO;
 }
 
-struct i915_buddy_block *
-__intel_memory_region_get_block_buddy(struct intel_memory_region *mem,
-				      resource_size_t size,
-				      unsigned int flags)
+/**
+ * intel_memory_region_reserve - Reserve a memory range
+ * @mem: The region for which we want to reserve a range.
+ * @offset: Start of the range to reserve.
+ * @size: The size of the range to reserve.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int intel_memory_region_reserve(struct intel_memory_region *mem,
+				resource_size_t offset,
+				resource_size_t size)
 {
-	struct i915_buddy_block *block;
-	LIST_HEAD(blocks);
 	int ret;
+	struct intel_region_reserve *reserve;
 
-	ret = __intel_memory_region_get_pages_buddy(mem, size, flags, &blocks);
-	if (ret)
-		return ERR_PTR(ret);
+	if (!mem->priv_ops || !mem->priv_ops->reserve)
+		return -EINVAL;
 
-	block = list_first_entry(&blocks, typeof(*block), link);
-	list_del_init(&block->link);
-	return block;
-}
+	reserve = kzalloc(sizeof(*reserve), GFP_KERNEL);
+	if (!reserve)
+		return -ENOMEM;
 
-int intel_memory_region_init_buddy(struct intel_memory_region *mem)
-{
-	return i915_buddy_init(&mem->mm, resource_size(&mem->region),
-			       PAGE_SIZE);
-}
-
-void intel_memory_region_release_buddy(struct intel_memory_region *mem)
-{
-	i915_buddy_free_list(&mem->mm, &mem->reserved);
-	i915_buddy_fini(&mem->mm);
-}
-
-int intel_memory_region_reserve(struct intel_memory_region *mem,
-				u64 offset, u64 size)
-{
-	int ret;
+	reserve->node = mem->priv_ops->reserve(mem, offset, size);
+	if (IS_ERR(reserve->node)) {
+		ret = PTR_ERR(reserve->node);
+		kfree(reserve);
+		return ret;
+	}
 
 	mutex_lock(&mem->mm_lock);
-	ret = i915_buddy_alloc_range(&mem->mm, &mem->reserved, offset, size);
+	list_add_tail(&reserve->link, &mem->reserved);
 	mutex_unlock(&mem->mm_lock);
 
-	return ret;
+	return 0;
 }
 
 struct intel_memory_region *
@@ -206,6 +126,8 @@ intel_memory_region_create(struct drm_i915_private *i915,
 			   resource_size_t size,
 			   resource_size_t min_page_size,
 			   resource_size_t io_start,
+			   u16 type,
+			   u16 instance,
 			   const struct intel_memory_region_ops *ops)
 {
 	struct intel_memory_region *mem;
@@ -222,6 +144,8 @@ intel_memory_region_create(struct drm_i915_private *i915,
 	mem->ops = ops;
 	mem->total = size;
 	mem->avail = mem->total;
+	mem->type = type;
+	mem->instance = instance;
 
 	mutex_init(&mem->objects.lock);
 	INIT_LIST_HEAD(&mem->objects.list);
@@ -259,6 +183,7 @@ static void __intel_memory_region_destroy(struct kref *kref)
 	struct intel_memory_region *mem =
 		container_of(kref, typeof(*mem), kref);
 
+	intel_memory_region_unreserve(mem);
 	if (mem->ops->release)
 		mem->ops->release(mem);
 
@@ -296,15 +221,15 @@ int intel_memory_regions_hw_probe(struct drm_i915_private *i915)
 		instance = intel_region_map[i].instance;
 		switch (type) {
 		case INTEL_MEMORY_SYSTEM:
-			mem = i915_gem_shmem_setup(i915);
+			mem = i915_gem_shmem_setup(i915, type, instance);
 			break;
 		case INTEL_MEMORY_STOLEN_LOCAL:
-			mem = i915_gem_stolen_lmem_setup(i915);
+			mem = i915_gem_stolen_lmem_setup(i915, type, instance);
 			if (!IS_ERR(mem))
 				i915->mm.stolen_region = mem;
 			break;
 		case INTEL_MEMORY_STOLEN_SYSTEM:
-			mem = i915_gem_stolen_smem_setup(i915);
+			mem = i915_gem_stolen_smem_setup(i915, type, instance);
 			if (!IS_ERR(mem))
 				i915->mm.stolen_region = mem;
 			break;
@@ -321,9 +246,6 @@ int intel_memory_regions_hw_probe(struct drm_i915_private *i915)
 		}
 
 		mem->id = i;
-		mem->type = type;
-		mem->instance = instance;
-
 		i915->mm.regions[i] = mem;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
index d24ce5a0b30b..e69cde13daf2 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.h
+++ b/drivers/gpu/drm/i915/intel_memory_region.h
@@ -13,8 +13,6 @@
 #include <drm/drm_mm.h>
 #include <drm/i915_drm.h>
 
-#include "i915_buddy.h"
-
 struct drm_i915_private;
 struct drm_i915_gem_object;
 struct intel_memory_region;
@@ -25,6 +23,7 @@ enum intel_memory_type {
 	INTEL_MEMORY_LOCAL = I915_MEMORY_CLASS_DEVICE,
 	INTEL_MEMORY_STOLEN_SYSTEM,
 	INTEL_MEMORY_STOLEN_LOCAL,
+	INTEL_MEMORY_MOCK,
 };
 
 enum intel_region_id {
@@ -59,10 +58,19 @@ struct intel_memory_region_ops {
 			   unsigned int flags);
 };
 
+struct intel_memory_region_private_ops {
+	void *(*reserve)(struct intel_memory_region *mem,
+			 resource_size_t offset,
+			 resource_size_t size);
+	void (*free)(struct intel_memory_region *mem,
+		     void *node);
+};
+
 struct intel_memory_region {
 	struct drm_i915_private *i915;
 
 	const struct intel_memory_region_ops *ops;
+	const struct intel_memory_region_private_ops *priv_ops;
 
 	struct io_mapping iomap;
 	struct resource region;
@@ -70,7 +78,6 @@ struct intel_memory_region {
 	/* For fake LMEM */
 	struct drm_mm_node fake_mappable;
 
-	struct i915_buddy_mm mm;
 	struct mutex mm_lock;
 
 	struct kref kref;
@@ -95,36 +102,26 @@ struct intel_memory_region {
 		struct list_head list;
 		struct list_head purgeable;
 	} objects;
+
+	size_t chunk_size;
+	unsigned int max_order;
+	bool is_range_manager;
+
+	void *region_private;
 };
 
 struct intel_memory_region *
 intel_memory_region_lookup(struct drm_i915_private *i915,
 			   u16 class, u16 instance);
 
-int intel_memory_region_init_buddy(struct intel_memory_region *mem);
-void intel_memory_region_release_buddy(struct intel_memory_region *mem);
-
-int __intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
-					  resource_size_t size,
-					  unsigned int flags,
-					  struct list_head *blocks);
-struct i915_buddy_block *
-__intel_memory_region_get_block_buddy(struct intel_memory_region *mem,
-				      resource_size_t size,
-				      unsigned int flags);
-void __intel_memory_region_put_pages_buddy(struct intel_memory_region *mem,
-					   struct list_head *blocks);
-void __intel_memory_region_put_block_buddy(struct i915_buddy_block *block);
-
-int intel_memory_region_reserve(struct intel_memory_region *mem,
-				u64 offset, u64 size);
-
 struct intel_memory_region *
 intel_memory_region_create(struct drm_i915_private *i915,
 			   resource_size_t start,
 			   resource_size_t size,
 			   resource_size_t min_page_size,
 			   resource_size_t io_start,
+			   u16 type,
+			   u16 instance,
 			   const struct intel_memory_region_ops *ops);
 
 struct intel_memory_region *
@@ -141,4 +138,9 @@ __printf(2, 3) void
 intel_memory_region_set_name(struct intel_memory_region *mem,
 			     const char *fmt, ...);
 
+void intel_memory_region_unreserve(struct intel_memory_region *mem);
+
+int intel_memory_region_reserve(struct intel_memory_region *mem,
+				resource_size_t offset,
+				resource_size_t size);
 #endif
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
new file mode 100644
index 000000000000..3bd9caa60298
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_device.h>
+
+#include "i915_drv.h"
+#include "i915_scatterlist.h"
+
+#include "intel_region_ttm.h"
+
+/* A Zero-initialized driver for now. We don't have a TTM backend yet. */
+static struct ttm_device_funcs i915_ttm_bo_driver;
+
+/**
+ * DOC: TTM support structure
+ *
+ * The code in this file deals with setting up memory managers for TTM
+ * LMEM and MOCK regions and converting the output from
+ * the managers to struct sg_table, Basically providing the mapping from
+ * i915 GEM regions to TTM memory types and resource managers.
+ */
+
+/**
+ * intel_region_ttm_device_init - Initialize a TTM device
+ * @dev_priv: Pointer to an i915 device private structure.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int intel_region_ttm_device_init(struct drm_i915_private *dev_priv)
+{
+	struct drm_device *drm = &dev_priv->drm;
+
+	return ttm_device_init(&dev_priv->bdev, &i915_ttm_bo_driver,
+			       drm->dev, drm->anon_inode->i_mapping,
+			       drm->vma_offset_manager, false, false);
+}
+
+/**
+ * intel_region_ttm_device_fini - Finalize a TTM device
+ * @dev_priv: Pointer to an i915 device private structure.
+ */
+void intel_region_ttm_device_fini(struct drm_i915_private *dev_priv)
+{
+	ttm_device_fini(&dev_priv->bdev);
+}
+
+/*
+ * Map the i915 memory regions to TTM memory types. We use the
+ * driver-private types for now, reserving TTM_PL_VRAM for stolen
+ * memory and TTM_PL_TT for GGTT use if decided to implement this.
+ */
+static int intel_region_to_ttm_type(struct intel_memory_region *mem)
+{
+	int type;
+
+	GEM_BUG_ON(mem->type != INTEL_MEMORY_LOCAL);
+
+	type = mem->instance + TTM_PL_PRIV;
+	GEM_BUG_ON(type >= TTM_NUM_MEM_TYPES);
+
+	return type;
+}
+
+static void *intel_region_ttm_node_reserve(struct intel_memory_region *mem,
+					   resource_size_t offset,
+					   resource_size_t size)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+	struct ttm_place place = {};
+	struct ttm_resource res = {};
+	struct ttm_buffer_object mock_bo = {};
+	int ret;
+
+	/*
+	 * Having to use a mock_bo is unfortunate but stems from some
+	 * drivers having private managers that insist to know what the
+	 * allocate memory is intended for, using it to send private
+	 * data to the manager. Also recently the bo has been used to send
+	 * alignment info to the manager. Assume that apart from the latter,
+	 * none of the managers we use will ever access the buffer object
+	 * members, hoping we can pass the alignment info in the
+	 * struct ttm_place in the future.
+	 */
+
+	place.fpfn = offset >> PAGE_SHIFT;
+	place.lpfn = place.fpfn + (size >> PAGE_SHIFT);
+	res.num_pages = size >> PAGE_SHIFT;
+	ret = man->func->alloc(man, &mock_bo, &place, &res);
+	if (ret == -ENOSPC)
+		ret = -ENXIO;
+
+	return ret ? ERR_PTR(ret) : res.mm_node;
+}
+
+/**
+ * intel_region_ttm_node_free - Free a node allocated from a resource manager
+ * @mem: The region the node was allocated from.
+ * @node: The opaque node representing an allocation.
+ */
+void intel_region_ttm_node_free(struct intel_memory_region *mem,
+				void *node)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+	struct ttm_resource res = {};
+
+	res.mm_node = node;
+	man->func->free(man, &res);
+}
+
+static const struct intel_memory_region_private_ops priv_ops = {
+	.reserve = intel_region_ttm_node_reserve,
+	.free = intel_region_ttm_node_free,
+};
+
+/**
+ * intel_region_ttm_init - Initialize a memory region for TTM.
+ * @mem: The region to initialize.
+ *
+ * This function initializes a suitable TTM resource manager for the
+ * region, and if it's a LMEM region type, attaches it to the TTM
+ * device. MOCK regions are NOT attached to the TTM device, since we don't
+ * have one for the mock selftests.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int intel_region_ttm_init(struct intel_memory_region *mem)
+{
+	struct ttm_resource_manager *man;
+
+	man = ttm_range_man_init_standalone(resource_size(&mem->region) >>
+					    PAGE_SHIFT, false);
+	if (IS_ERR(man))
+		return PTR_ERR(man);
+
+	ttm_resource_manager_set_used(man, true);
+	mem->chunk_size = PAGE_SIZE;
+	mem->max_order =
+		get_order(rounddown_pow_of_two(resource_size(&mem->region)));
+	mem->is_range_manager = true;
+	mem->priv_ops = &priv_ops;
+	mem->region_private = man;
+
+
+	/*
+	 * Register only LOCAL memory with the device so that we can
+	 * run the mock selftests using the manager.
+	 */
+	if (mem->type == INTEL_MEMORY_LOCAL) {
+		ttm_set_driver_manager(&mem->i915->bdev,
+				       intel_region_to_ttm_type(mem),
+				       man);
+	}
+
+	return 0;
+}
+
+/**
+ * intel_region_ttm_fini - Finalize a TTM region.
+ * @mem: The memory region
+ *
+ * This functions takes down the TTM resource manager associated with the
+ * memory region, and if it was registered with the TTM device,
+ * removes that registration.
+ */
+void intel_region_ttm_fini(struct intel_memory_region *mem)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+
+	if (mem->type == INTEL_MEMORY_LOCAL) {
+		int ret;
+
+		ret = ttm_range_man_fini(&mem->i915->bdev,
+					 intel_region_to_ttm_type(mem));
+		GEM_WARN_ON(ret);
+	} else {
+		ttm_resource_manager_set_used(man, false);
+		ttm_range_man_fini_standalone(man);
+	}
+}
+
+/**
+ * intel_region_ttm_node_to_st - Convert an opaque TTM resource manager node
+ * to an sg_table.
+ * @mem: The memory region.
+ * @node: The resource manager node obtained from the TTM resource manager.
+ *
+ * The gem backends typically use sg-tables for operations on the underlying
+ * io_memory. So provide a way for the backends to translate the
+ * nodes they are handed from TTM to sg-tables.
+ *
+ * Return: A malloced sg_table on success, an error pointer on failure.
+ */
+struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
+					     void *node)
+{
+	return i915_sg_from_mm_node(node, mem->region.start);
+}
+
+/**
+ * intel_region_ttm_node_alloc - Allocate memory resources from a region
+ * @mem: The memory region,
+ * @size: The requested size in bytes
+ * @flags: Allocation flags
+ *
+ * This functionality is provided only for callers that need to allocate
+ * memory from standalone TTM range managers, without the TTM eviction
+ * functionality. Don't use if you are not completely sure that's the
+ * case. The returned opaque node can be converted to an sg_table using
+ * intel_region_ttm_node_to_st(), and can be freed using
+ * intel_region_ttm_node_free().
+ *
+ * Return: A valid pointer on success, an error pointer on failure.
+ */
+void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
+				  resource_size_t size,
+				  unsigned int flags)
+{
+	struct ttm_resource_manager *man = mem->region_private;
+	struct ttm_place place = {};
+	struct ttm_resource res = {};
+	struct ttm_buffer_object mock_bo = {};
+	int ret;
+
+	/*
+	 * We ignore the flags for now since we're using the range
+	 * manager and contigous and min page size would be fulfilled
+	 * by default if size is min page size aligned.
+	 */
+	res.num_pages = size >> PAGE_SHIFT;
+
+	if (mem->is_range_manager) {
+		if (size >= SZ_1G)
+			mock_bo.page_alignment = SZ_1G >> PAGE_SHIFT;
+		else if (size >= SZ_2M)
+			mock_bo.page_alignment = SZ_2M >> PAGE_SHIFT;
+		else if (size >= SZ_64K)
+			mock_bo.page_alignment = SZ_64K >> PAGE_SHIFT;
+	}
+
+	ret = man->func->alloc(man, &mock_bo, &place, &res);
+	if (ret == -ENOSPC)
+		ret = -ENXIO;
+	return ret ? ERR_PTR(ret) : res.mm_node;
+}
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
new file mode 100644
index 000000000000..40129f7e0317
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_region_ttm.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+#ifndef _INTEL_REGION_TTM_H_
+#define _INTEL_REGION_TTM_H_
+
+#include <linux/types.h>
+
+struct drm_i915_private;
+struct intel_memory_region;
+
+int intel_region_ttm_device_init(struct drm_i915_private *dev_priv);
+
+void intel_region_ttm_device_fini(struct drm_i915_private *dev_priv);
+
+int intel_region_ttm_init(struct intel_memory_region *mem);
+
+void intel_region_ttm_fini(struct intel_memory_region *mem);
+
+struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
+					     void *node);
+
+void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
+				  resource_size_t size,
+				  unsigned int flags);
+void intel_region_ttm_node_free(struct intel_memory_region *mem,
+				void *node);
+#endif /* _INTEL_REGION_TTM_H_ */
diff --git a/drivers/gpu/drm/i915/selftests/i915_buddy.c b/drivers/gpu/drm/i915/selftests/i915_buddy.c
deleted file mode 100644
index f0f5c4df8dbc..000000000000
--- a/drivers/gpu/drm/i915/selftests/i915_buddy.c
+++ /dev/null
@@ -1,789 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include <linux/prime_numbers.h>
-
-#include "../i915_selftest.h"
-#include "i915_random.h"
-
-static void __igt_dump_block(struct i915_buddy_mm *mm,
-			     struct i915_buddy_block *block,
-			     bool buddy)
-{
-	pr_err("block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%s buddy=%s\n",
-	       block->header,
-	       i915_buddy_block_state(block),
-	       i915_buddy_block_order(block),
-	       i915_buddy_block_offset(block),
-	       i915_buddy_block_size(mm, block),
-	       yesno(!block->parent),
-	       yesno(buddy));
-}
-
-static void igt_dump_block(struct i915_buddy_mm *mm,
-			   struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *buddy;
-
-	__igt_dump_block(mm, block, false);
-
-	buddy = get_buddy(block);
-	if (buddy)
-		__igt_dump_block(mm, buddy, true);
-}
-
-static int igt_check_block(struct i915_buddy_mm *mm,
-			   struct i915_buddy_block *block)
-{
-	struct i915_buddy_block *buddy;
-	unsigned int block_state;
-	u64 block_size;
-	u64 offset;
-	int err = 0;
-
-	block_state = i915_buddy_block_state(block);
-
-	if (block_state != I915_BUDDY_ALLOCATED &&
-	    block_state != I915_BUDDY_FREE &&
-	    block_state != I915_BUDDY_SPLIT) {
-		pr_err("block state mismatch\n");
-		err = -EINVAL;
-	}
-
-	block_size = i915_buddy_block_size(mm, block);
-	offset = i915_buddy_block_offset(block);
-
-	if (block_size < mm->chunk_size) {
-		pr_err("block size smaller than min size\n");
-		err = -EINVAL;
-	}
-
-	if (!is_power_of_2(block_size)) {
-		pr_err("block size not power of two\n");
-		err = -EINVAL;
-	}
-
-	if (!IS_ALIGNED(block_size, mm->chunk_size)) {
-		pr_err("block size not aligned to min size\n");
-		err = -EINVAL;
-	}
-
-	if (!IS_ALIGNED(offset, mm->chunk_size)) {
-		pr_err("block offset not aligned to min size\n");
-		err = -EINVAL;
-	}
-
-	if (!IS_ALIGNED(offset, block_size)) {
-		pr_err("block offset not aligned to block size\n");
-		err = -EINVAL;
-	}
-
-	buddy = get_buddy(block);
-
-	if (!buddy && block->parent) {
-		pr_err("buddy has gone fishing\n");
-		err = -EINVAL;
-	}
-
-	if (buddy) {
-		if (i915_buddy_block_offset(buddy) != (offset ^ block_size)) {
-			pr_err("buddy has wrong offset\n");
-			err = -EINVAL;
-		}
-
-		if (i915_buddy_block_size(mm, buddy) != block_size) {
-			pr_err("buddy size mismatch\n");
-			err = -EINVAL;
-		}
-
-		if (i915_buddy_block_state(buddy) == block_state &&
-		    block_state == I915_BUDDY_FREE) {
-			pr_err("block and its buddy are free\n");
-			err = -EINVAL;
-		}
-	}
-
-	return err;
-}
-
-static int igt_check_blocks(struct i915_buddy_mm *mm,
-			    struct list_head *blocks,
-			    u64 expected_size,
-			    bool is_contiguous)
-{
-	struct i915_buddy_block *block;
-	struct i915_buddy_block *prev;
-	u64 total;
-	int err = 0;
-
-	block = NULL;
-	prev = NULL;
-	total = 0;
-
-	list_for_each_entry(block, blocks, link) {
-		err = igt_check_block(mm, block);
-
-		if (!i915_buddy_block_is_allocated(block)) {
-			pr_err("block not allocated\n"),
-			err = -EINVAL;
-		}
-
-		if (is_contiguous && prev) {
-			u64 prev_block_size;
-			u64 prev_offset;
-			u64 offset;
-
-			prev_offset = i915_buddy_block_offset(prev);
-			prev_block_size = i915_buddy_block_size(mm, prev);
-			offset = i915_buddy_block_offset(block);
-
-			if (offset != (prev_offset + prev_block_size)) {
-				pr_err("block offset mismatch\n");
-				err = -EINVAL;
-			}
-		}
-
-		if (err)
-			break;
-
-		total += i915_buddy_block_size(mm, block);
-		prev = block;
-	}
-
-	if (!err) {
-		if (total != expected_size) {
-			pr_err("size mismatch, expected=%llx, found=%llx\n",
-			       expected_size, total);
-			err = -EINVAL;
-		}
-		return err;
-	}
-
-	if (prev) {
-		pr_err("prev block, dump:\n");
-		igt_dump_block(mm, prev);
-	}
-
-	if (block) {
-		pr_err("bad block, dump:\n");
-		igt_dump_block(mm, block);
-	}
-
-	return err;
-}
-
-static int igt_check_mm(struct i915_buddy_mm *mm)
-{
-	struct i915_buddy_block *root;
-	struct i915_buddy_block *prev;
-	unsigned int i;
-	u64 total;
-	int err = 0;
-
-	if (!mm->n_roots) {
-		pr_err("n_roots is zero\n");
-		return -EINVAL;
-	}
-
-	if (mm->n_roots != hweight64(mm->size)) {
-		pr_err("n_roots mismatch, n_roots=%u, expected=%lu\n",
-		       mm->n_roots, hweight64(mm->size));
-		return -EINVAL;
-	}
-
-	root = NULL;
-	prev = NULL;
-	total = 0;
-
-	for (i = 0; i < mm->n_roots; ++i) {
-		struct i915_buddy_block *block;
-		unsigned int order;
-
-		root = mm->roots[i];
-		if (!root) {
-			pr_err("root(%u) is NULL\n", i);
-			err = -EINVAL;
-			break;
-		}
-
-		err = igt_check_block(mm, root);
-
-		if (!i915_buddy_block_is_free(root)) {
-			pr_err("root not free\n");
-			err = -EINVAL;
-		}
-
-		order = i915_buddy_block_order(root);
-
-		if (!i) {
-			if (order != mm->max_order) {
-				pr_err("max order root missing\n");
-				err = -EINVAL;
-			}
-		}
-
-		if (prev) {
-			u64 prev_block_size;
-			u64 prev_offset;
-			u64 offset;
-
-			prev_offset = i915_buddy_block_offset(prev);
-			prev_block_size = i915_buddy_block_size(mm, prev);
-			offset = i915_buddy_block_offset(root);
-
-			if (offset != (prev_offset + prev_block_size)) {
-				pr_err("root offset mismatch\n");
-				err = -EINVAL;
-			}
-		}
-
-		block = list_first_entry_or_null(&mm->free_list[order],
-						 struct i915_buddy_block,
-						 link);
-		if (block != root) {
-			pr_err("root mismatch at order=%u\n", order);
-			err = -EINVAL;
-		}
-
-		if (err)
-			break;
-
-		prev = root;
-		total += i915_buddy_block_size(mm, root);
-	}
-
-	if (!err) {
-		if (total != mm->size) {
-			pr_err("expected mm size=%llx, found=%llx\n", mm->size,
-			       total);
-			err = -EINVAL;
-		}
-		return err;
-	}
-
-	if (prev) {
-		pr_err("prev root(%u), dump:\n", i - 1);
-		igt_dump_block(mm, prev);
-	}
-
-	if (root) {
-		pr_err("bad root(%u), dump:\n", i);
-		igt_dump_block(mm, root);
-	}
-
-	return err;
-}
-
-static void igt_mm_config(u64 *size, u64 *chunk_size)
-{
-	I915_RND_STATE(prng);
-	u32 s, ms;
-
-	/* Nothing fancy, just try to get an interesting bit pattern */
-
-	prandom_seed_state(&prng, i915_selftest.random_seed);
-
-	/* Let size be a random number of pages up to 8 GB (2M pages) */
-	s = 1 + i915_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng);
-	/* Let the chunk size be a random power of 2 less than size */
-	ms = BIT(i915_prandom_u32_max_state(ilog2(s), &prng));
-	/* Round size down to the chunk size */
-	s &= -ms;
-
-	/* Convert from pages to bytes */
-	*chunk_size = (u64)ms << 12;
-	*size = (u64)s << 12;
-}
-
-static int igt_buddy_alloc_smoke(void *arg)
-{
-	struct i915_buddy_mm mm;
-	IGT_TIMEOUT(end_time);
-	I915_RND_STATE(prng);
-	u64 chunk_size;
-	u64 mm_size;
-	int *order;
-	int err, i;
-
-	igt_mm_config(&mm_size, &chunk_size);
-
-	pr_info("buddy_init with size=%llx, chunk_size=%llx\n", mm_size, chunk_size);
-
-	err = i915_buddy_init(&mm, mm_size, chunk_size);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-
-	order = i915_random_order(mm.max_order + 1, &prng);
-	if (!order)
-		goto out_fini;
-
-	for (i = 0; i <= mm.max_order; ++i) {
-		struct i915_buddy_block *block;
-		int max_order = order[i];
-		bool timeout = false;
-		LIST_HEAD(blocks);
-		int order;
-		u64 total;
-
-		err = igt_check_mm(&mm);
-		if (err) {
-			pr_err("pre-mm check failed, abort\n");
-			break;
-		}
-
-		pr_info("filling from max_order=%u\n", max_order);
-
-		order = max_order;
-		total = 0;
-
-		do {
-retry:
-			block = i915_buddy_alloc(&mm, order);
-			if (IS_ERR(block)) {
-				err = PTR_ERR(block);
-				if (err == -ENOMEM) {
-					pr_info("buddy_alloc hit -ENOMEM with order=%d\n",
-						order);
-				} else {
-					if (order--) {
-						err = 0;
-						goto retry;
-					}
-
-					pr_err("buddy_alloc with order=%d failed(%d)\n",
-					       order, err);
-				}
-
-				break;
-			}
-
-			list_add_tail(&block->link, &blocks);
-
-			if (i915_buddy_block_order(block) != order) {
-				pr_err("buddy_alloc order mismatch\n");
-				err = -EINVAL;
-				break;
-			}
-
-			total += i915_buddy_block_size(&mm, block);
-
-			if (__igt_timeout(end_time, NULL)) {
-				timeout = true;
-				break;
-			}
-		} while (total < mm.size);
-
-		if (!err)
-			err = igt_check_blocks(&mm, &blocks, total, false);
-
-		i915_buddy_free_list(&mm, &blocks);
-
-		if (!err) {
-			err = igt_check_mm(&mm);
-			if (err)
-				pr_err("post-mm check failed\n");
-		}
-
-		if (err || timeout)
-			break;
-
-		cond_resched();
-	}
-
-	if (err == -ENOMEM)
-		err = 0;
-
-	kfree(order);
-out_fini:
-	i915_buddy_fini(&mm);
-
-	return err;
-}
-
-static int igt_buddy_alloc_pessimistic(void *arg)
-{
-	const unsigned int max_order = 16;
-	struct i915_buddy_block *block, *bn;
-	struct i915_buddy_mm mm;
-	unsigned int order;
-	LIST_HEAD(blocks);
-	int err;
-
-	/*
-	 * Create a pot-sized mm, then allocate one of each possible
-	 * order within. This should leave the mm with exactly one
-	 * page left.
-	 */
-
-	err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-	GEM_BUG_ON(mm.max_order != max_order);
-
-	for (order = 0; order < max_order; order++) {
-		block = i915_buddy_alloc(&mm, order);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc hit -ENOMEM with order=%d\n",
-				order);
-			err = PTR_ERR(block);
-			goto err;
-		}
-
-		list_add_tail(&block->link, &blocks);
-	}
-
-	/* And now the last remaining block available */
-	block = i915_buddy_alloc(&mm, 0);
-	if (IS_ERR(block)) {
-		pr_info("buddy_alloc hit -ENOMEM on final alloc\n");
-		err = PTR_ERR(block);
-		goto err;
-	}
-	list_add_tail(&block->link, &blocks);
-
-	/* Should be completely full! */
-	for (order = max_order; order--; ) {
-		block = i915_buddy_alloc(&mm, order);
-		if (!IS_ERR(block)) {
-			pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!",
-				order);
-			list_add_tail(&block->link, &blocks);
-			err = -EINVAL;
-			goto err;
-		}
-	}
-
-	block = list_last_entry(&blocks, typeof(*block), link);
-	list_del(&block->link);
-	i915_buddy_free(&mm, block);
-
-	/* As we free in increasing size, we make available larger blocks */
-	order = 1;
-	list_for_each_entry_safe(block, bn, &blocks, link) {
-		list_del(&block->link);
-		i915_buddy_free(&mm, block);
-
-		block = i915_buddy_alloc(&mm, order);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n",
-				order);
-			err = PTR_ERR(block);
-			goto err;
-		}
-		i915_buddy_free(&mm, block);
-		order++;
-	}
-
-	/* To confirm, now the whole mm should be available */
-	block = i915_buddy_alloc(&mm, max_order);
-	if (IS_ERR(block)) {
-		pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n",
-			max_order);
-		err = PTR_ERR(block);
-		goto err;
-	}
-	i915_buddy_free(&mm, block);
-
-err:
-	i915_buddy_free_list(&mm, &blocks);
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-static int igt_buddy_alloc_optimistic(void *arg)
-{
-	const int max_order = 16;
-	struct i915_buddy_block *block;
-	struct i915_buddy_mm mm;
-	LIST_HEAD(blocks);
-	int order;
-	int err;
-
-	/*
-	 * Create a mm with one block of each order available, and
-	 * try to allocate them all.
-	 */
-
-	err = i915_buddy_init(&mm,
-			      PAGE_SIZE * ((1 << (max_order + 1)) - 1),
-			      PAGE_SIZE);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-	GEM_BUG_ON(mm.max_order != max_order);
-
-	for (order = 0; order <= max_order; order++) {
-		block = i915_buddy_alloc(&mm, order);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc hit -ENOMEM with order=%d\n",
-				order);
-			err = PTR_ERR(block);
-			goto err;
-		}
-
-		list_add_tail(&block->link, &blocks);
-	}
-
-	/* Should be completely full! */
-	block = i915_buddy_alloc(&mm, 0);
-	if (!IS_ERR(block)) {
-		pr_info("buddy_alloc unexpectedly succeeded, it should be full!");
-		list_add_tail(&block->link, &blocks);
-		err = -EINVAL;
-		goto err;
-	}
-
-err:
-	i915_buddy_free_list(&mm, &blocks);
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-static int igt_buddy_alloc_pathological(void *arg)
-{
-	const int max_order = 16;
-	struct i915_buddy_block *block;
-	struct i915_buddy_mm mm;
-	LIST_HEAD(blocks);
-	LIST_HEAD(holes);
-	int order, top;
-	int err;
-
-	/*
-	 * Create a pot-sized mm, then allocate one of each possible
-	 * order within. This should leave the mm with exactly one
-	 * page left. Free the largest block, then whittle down again.
-	 * Eventually we will have a fully 50% fragmented mm.
-	 */
-
-	err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-	GEM_BUG_ON(mm.max_order != max_order);
-
-	for (top = max_order; top; top--) {
-		/* Make room by freeing the largest allocated block */
-		block = list_first_entry_or_null(&blocks, typeof(*block), link);
-		if (block) {
-			list_del(&block->link);
-			i915_buddy_free(&mm, block);
-		}
-
-		for (order = top; order--; ) {
-			block = i915_buddy_alloc(&mm, order);
-			if (IS_ERR(block)) {
-				pr_info("buddy_alloc hit -ENOMEM with order=%d, top=%d\n",
-					order, top);
-				err = PTR_ERR(block);
-				goto err;
-			}
-			list_add_tail(&block->link, &blocks);
-		}
-
-		/* There should be one final page for this sub-allocation */
-		block = i915_buddy_alloc(&mm, 0);
-		if (IS_ERR(block)) {
-			pr_info("buddy_alloc hit -ENOMEM for hole\n");
-			err = PTR_ERR(block);
-			goto err;
-		}
-		list_add_tail(&block->link, &holes);
-
-		block = i915_buddy_alloc(&mm, top);
-		if (!IS_ERR(block)) {
-			pr_info("buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!",
-				top, max_order);
-			list_add_tail(&block->link, &blocks);
-			err = -EINVAL;
-			goto err;
-		}
-	}
-
-	i915_buddy_free_list(&mm, &holes);
-
-	/* Nothing larger than blocks of chunk_size now available */
-	for (order = 1; order <= max_order; order++) {
-		block = i915_buddy_alloc(&mm, order);
-		if (!IS_ERR(block)) {
-			pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!",
-				order);
-			list_add_tail(&block->link, &blocks);
-			err = -EINVAL;
-			goto err;
-		}
-	}
-
-err:
-	list_splice_tail(&holes, &blocks);
-	i915_buddy_free_list(&mm, &blocks);
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-static int igt_buddy_alloc_range(void *arg)
-{
-	struct i915_buddy_mm mm;
-	unsigned long page_num;
-	LIST_HEAD(blocks);
-	u64 chunk_size;
-	u64 offset;
-	u64 size;
-	u64 rem;
-	int err;
-
-	igt_mm_config(&size, &chunk_size);
-
-	pr_info("buddy_init with size=%llx, chunk_size=%llx\n", size, chunk_size);
-
-	err = i915_buddy_init(&mm, size, chunk_size);
-	if (err) {
-		pr_err("buddy_init failed(%d)\n", err);
-		return err;
-	}
-
-	err = igt_check_mm(&mm);
-	if (err) {
-		pr_err("pre-mm check failed, abort, abort, abort!\n");
-		goto err_fini;
-	}
-
-	rem = mm.size;
-	offset = 0;
-
-	for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) {
-		struct i915_buddy_block *block;
-		LIST_HEAD(tmp);
-
-		size = min(page_num * mm.chunk_size, rem);
-
-		err = i915_buddy_alloc_range(&mm, &tmp, offset, size);
-		if (err) {
-			if (err == -ENOMEM) {
-				pr_info("alloc_range hit -ENOMEM with size=%llx\n",
-					size);
-			} else {
-				pr_err("alloc_range with offset=%llx, size=%llx failed(%d)\n",
-				       offset, size, err);
-			}
-
-			break;
-		}
-
-		block = list_first_entry_or_null(&tmp,
-						 struct i915_buddy_block,
-						 link);
-		if (!block) {
-			pr_err("alloc_range has no blocks\n");
-			err = -EINVAL;
-			break;
-		}
-
-		if (i915_buddy_block_offset(block) != offset) {
-			pr_err("alloc_range start offset mismatch, found=%llx, expected=%llx\n",
-			       i915_buddy_block_offset(block), offset);
-			err = -EINVAL;
-		}
-
-		if (!err)
-			err = igt_check_blocks(&mm, &tmp, size, true);
-
-		list_splice_tail(&tmp, &blocks);
-
-		if (err)
-			break;
-
-		offset += size;
-
-		rem -= size;
-		if (!rem)
-			break;
-
-		cond_resched();
-	}
-
-	if (err == -ENOMEM)
-		err = 0;
-
-	i915_buddy_free_list(&mm, &blocks);
-
-	if (!err) {
-		err = igt_check_mm(&mm);
-		if (err)
-			pr_err("post-mm check failed\n");
-	}
-
-err_fini:
-	i915_buddy_fini(&mm);
-
-	return err;
-}
-
-static int igt_buddy_alloc_limit(void *arg)
-{
-	struct i915_buddy_block *block;
-	struct i915_buddy_mm mm;
-	const u64 size = U64_MAX;
-	int err;
-
-	err = i915_buddy_init(&mm, size, PAGE_SIZE);
-	if (err)
-		return err;
-
-	if (mm.max_order != I915_BUDDY_MAX_ORDER) {
-		pr_err("mm.max_order(%d) != %d\n",
-		       mm.max_order, I915_BUDDY_MAX_ORDER);
-		err = -EINVAL;
-		goto out_fini;
-	}
-
-	block = i915_buddy_alloc(&mm, mm.max_order);
-	if (IS_ERR(block)) {
-		err = PTR_ERR(block);
-		goto out_fini;
-	}
-
-	if (i915_buddy_block_order(block) != mm.max_order) {
-		pr_err("block order(%d) != %d\n",
-		       i915_buddy_block_order(block), mm.max_order);
-		err = -EINVAL;
-		goto out_free;
-	}
-
-	if (i915_buddy_block_size(&mm, block) !=
-	    BIT_ULL(mm.max_order) * PAGE_SIZE) {
-		pr_err("block size(%llu) != %llu\n",
-		       i915_buddy_block_size(&mm, block),
-		       BIT_ULL(mm.max_order) * PAGE_SIZE);
-		err = -EINVAL;
-		goto out_free;
-	}
-
-out_free:
-	i915_buddy_free(&mm, block);
-out_fini:
-	i915_buddy_fini(&mm);
-	return err;
-}
-
-int i915_buddy_mock_selftests(void)
-{
-	static const struct i915_subtest tests[] = {
-		SUBTEST(igt_buddy_alloc_pessimistic),
-		SUBTEST(igt_buddy_alloc_optimistic),
-		SUBTEST(igt_buddy_alloc_pathological),
-		SUBTEST(igt_buddy_alloc_smoke),
-		SUBTEST(igt_buddy_alloc_range),
-		SUBTEST(igt_buddy_alloc_limit),
-	};
-
-	return i915_subtests(tests, NULL);
-}
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 3db34d3eea58..34e5caf38093 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -33,5 +33,4 @@ selftest(evict, i915_gem_evict_mock_selftests)
 selftest(gtt, i915_gem_gtt_mock_selftests)
 selftest(hugepages, i915_gem_huge_page_mock_selftests)
 selftest(contexts, i915_gem_context_mock_selftests)
-selftest(buddy, i915_buddy_mock_selftests)
 selftest(memory_region, intel_memory_region_mock_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
index f85fd8cbfbf5..c85d516b85cd 100644
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -57,9 +57,10 @@ static int igt_mock_fill(void *arg)
 	LIST_HEAD(objects);
 	int err = 0;
 
-	page_size = mem->mm.chunk_size;
-	max_pages = div64_u64(total, page_size);
+	page_size = mem->chunk_size;
 	rem = total;
+retry:
+	max_pages = div64_u64(rem, page_size);
 
 	for_each_prime_number_from(page_num, 1, max_pages) {
 		resource_size_t size = page_num * page_size;
@@ -85,6 +86,11 @@ static int igt_mock_fill(void *arg)
 		err = 0;
 	if (err == -ENXIO) {
 		if (page_num * page_size <= rem) {
+			if (mem->is_range_manager && max_pages > 1) {
+				max_pages >>= 1;
+				goto retry;
+			}
+
 			pr_err("%s failed, space still left in region\n",
 			       __func__);
 			err = -EINVAL;
@@ -199,12 +205,18 @@ static int igt_mock_reserve(void *arg)
 	do {
 		u32 size = i915_prandom_u32_max_state(cur_avail, &prng);
 
+retry:
 		size = max_t(u32, round_up(size, PAGE_SIZE), PAGE_SIZE);
 		obj = igt_object_create(mem, &objects, size, 0);
 		if (IS_ERR(obj)) {
-			if (PTR_ERR(obj) == -ENXIO)
+			if (PTR_ERR(obj) == -ENXIO) {
+				if (mem->is_range_manager &&
+				    size > mem->chunk_size) {
+					size >>= 1;
+					goto retry;
+				}
 				break;
-
+			}
 			err = PTR_ERR(obj);
 			goto out_close;
 		}
@@ -220,7 +232,7 @@ static int igt_mock_reserve(void *arg)
 out_close:
 	kfree(order);
 	close_objects(mem, &objects);
-	i915_buddy_free_list(&mem->mm, &mem->reserved);
+	intel_memory_region_unreserve(mem);
 	return err;
 }
 
@@ -240,7 +252,7 @@ static int igt_mock_contiguous(void *arg)
 	total = resource_size(&mem->region);
 
 	/* Min size */
-	obj = igt_object_create(mem, &objects, mem->mm.chunk_size,
+	obj = igt_object_create(mem, &objects, mem->chunk_size,
 				I915_BO_ALLOC_CONTIGUOUS);
 	if (IS_ERR(obj))
 		return PTR_ERR(obj);
@@ -321,14 +333,16 @@ static int igt_mock_contiguous(void *arg)
 	min = target;
 	target = total >> 1;
 
-	/* Make sure we can still allocate all the fragmented space */
-	obj = igt_object_create(mem, &objects, target, 0);
-	if (IS_ERR(obj)) {
-		err = PTR_ERR(obj);
-		goto err_close_objects;
-	}
+	if (!mem->is_range_manager) {
+		/* Make sure we can still allocate all the fragmented space */
+		obj = igt_object_create(mem, &objects, target, 0);
+		if (IS_ERR(obj)) {
+			err = PTR_ERR(obj);
+			goto err_close_objects;
+		}
 
-	igt_object_release(obj);
+		igt_object_release(obj);
+	}
 
 	/*
 	 * Even though we have enough free space, we don't have a big enough
@@ -348,7 +362,7 @@ static int igt_mock_contiguous(void *arg)
 		}
 
 		target >>= 1;
-	} while (target >= mem->mm.chunk_size);
+	} while (target >= mem->chunk_size);
 
 err_close_objects:
 	list_splice_tail(&holes, &objects);
@@ -368,7 +382,7 @@ static int igt_mock_splintered_region(void *arg)
 
 	/*
 	 * Sanity check we can still allocate everything even if the
-	 * mm.max_order != mm.size. i.e our starting address space size is not a
+	 * max_order != mm.size. i.e our starting address space size is not a
 	 * power-of-two.
 	 */
 
@@ -377,17 +391,10 @@ static int igt_mock_splintered_region(void *arg)
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
-	if (mem->mm.size != size) {
-		pr_err("%s size mismatch(%llu != %llu)\n",
-		       __func__, mem->mm.size, size);
-		err = -EINVAL;
-		goto out_put;
-	}
-
 	expected_order = get_order(rounddown_pow_of_two(size));
-	if (mem->mm.max_order != expected_order) {
+	if (mem->max_order != expected_order) {
 		pr_err("%s order mismatch(%u != %u)\n",
-		       __func__, mem->mm.max_order, expected_order);
+		       __func__, mem->max_order, expected_order);
 		err = -EINVAL;
 		goto out_put;
 	}
@@ -408,12 +415,15 @@ static int igt_mock_splintered_region(void *arg)
 	 * sure that does indeed hold true.
 	 */
 
-	obj = igt_object_create(mem, &objects, size, I915_BO_ALLOC_CONTIGUOUS);
-	if (!IS_ERR(obj)) {
-		pr_err("%s too large contiguous allocation was not rejected\n",
-		       __func__);
-		err = -EINVAL;
-		goto out_close;
+	if (!mem->is_range_manager) {
+		obj = igt_object_create(mem, &objects, size,
+					I915_BO_ALLOC_CONTIGUOUS);
+		if (!IS_ERR(obj)) {
+			pr_err("%s too large contiguous allocation was not rejected\n",
+			       __func__);
+			err = -EINVAL;
+			goto out_close;
+		}
 	}
 
 	obj = igt_object_create(mem, &objects, rounddown_pow_of_two(size),
@@ -432,68 +442,6 @@ static int igt_mock_splintered_region(void *arg)
 	return err;
 }
 
-#ifndef SZ_8G
-#define SZ_8G BIT_ULL(33)
-#endif
-
-static int igt_mock_max_segment(void *arg)
-{
-	const unsigned int max_segment = i915_sg_segment_size();
-	struct intel_memory_region *mem = arg;
-	struct drm_i915_private *i915 = mem->i915;
-	struct drm_i915_gem_object *obj;
-	struct i915_buddy_block *block;
-	struct scatterlist *sg;
-	LIST_HEAD(objects);
-	u64 size;
-	int err = 0;
-
-	/*
-	 * While we may create very large contiguous blocks, we may need
-	 * to break those down for consumption elsewhere. In particular,
-	 * dma-mapping with scatterlist elements have an implicit limit of
-	 * UINT_MAX on each element.
-	 */
-
-	size = SZ_8G;
-	mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0);
-	if (IS_ERR(mem))
-		return PTR_ERR(mem);
-
-	obj = igt_object_create(mem, &objects, size, 0);
-	if (IS_ERR(obj)) {
-		err = PTR_ERR(obj);
-		goto out_put;
-	}
-
-	size = 0;
-	list_for_each_entry(block, &obj->mm.blocks, link) {
-		if (i915_buddy_block_size(&mem->mm, block) > size)
-			size = i915_buddy_block_size(&mem->mm, block);
-	}
-	if (size < max_segment) {
-		pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n",
-		       __func__, max_segment, size);
-		err = -EINVAL;
-		goto out_close;
-	}
-
-	for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
-		if (sg->length > max_segment) {
-			pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
-			       __func__, sg->length, max_segment);
-			err = -EINVAL;
-			goto out_close;
-		}
-	}
-
-out_close:
-	close_objects(mem, &objects);
-out_put:
-	intel_memory_region_put(mem);
-	return err;
-}
-
 static int igt_gpu_write_dw(struct intel_context *ce,
 			    struct i915_vma *vma,
 			    u32 dword,
@@ -1098,7 +1046,6 @@ int intel_memory_region_mock_selftests(void)
 		SUBTEST(igt_mock_fill),
 		SUBTEST(igt_mock_contiguous),
 		SUBTEST(igt_mock_splintered_region),
-		SUBTEST(igt_mock_max_segment),
 	};
 	struct intel_memory_region *mem;
 	struct drm_i915_private *i915;
diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c
index 5d2d010a1e22..9067601aa717 100644
--- a/drivers/gpu/drm/i915/selftests/mock_region.c
+++ b/drivers/gpu/drm/i915/selftests/mock_region.c
@@ -1,17 +1,53 @@
 // SPDX-License-Identifier: MIT
 /*
- * Copyright © 2019 Intel Corporation
+ * Copyright © 2019-2021 Intel Corporation
  */
 
+#include <linux/scatterlist.h>
+
 #include "gem/i915_gem_region.h"
 #include "intel_memory_region.h"
+#include "intel_region_ttm.h"
 
 #include "mock_region.h"
 
+static void mock_region_put_pages(struct drm_i915_gem_object *obj,
+				  struct sg_table *pages)
+{
+	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
+	sg_free_table(pages);
+	kfree(pages);
+}
+
+static int mock_region_get_pages(struct drm_i915_gem_object *obj)
+{
+	unsigned int flags;
+	struct sg_table *pages;
+
+	flags = I915_ALLOC_MIN_PAGE_SIZE;
+	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
+		flags |= I915_ALLOC_CONTIGUOUS;
+
+	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
+							 obj->base.size,
+							 flags);
+	if (IS_ERR(obj->mm.st_mm_node))
+		return PTR_ERR(obj->mm.st_mm_node);
+
+	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
+	if (IS_ERR(pages))
+		return PTR_ERR(pages);
+
+	__i915_gem_object_set_pages(obj, pages,
+				    i915_sg_dma_page_sizes(pages->sgl));
+
+	return 0;
+}
+
 static const struct drm_i915_gem_object_ops mock_region_obj_ops = {
 	.name = "mock-region",
-	.get_pages = i915_gem_object_get_pages_buddy,
-	.put_pages = i915_gem_object_put_pages_buddy,
+	.get_pages = mock_region_get_pages,
+	.put_pages = mock_region_put_pages,
 	.release = i915_gem_object_release_memory_region,
 };
 
@@ -23,7 +59,7 @@ static int mock_object_init(struct intel_memory_region *mem,
 	static struct lock_class_key lock_class;
 	struct drm_i915_private *i915 = mem->i915;
 
-	if (size > mem->mm.size)
+	if (size > resource_size(&mem->region))
 		return -E2BIG;
 
 	drm_gem_private_object_init(&i915->drm, &obj->base, size);
@@ -39,8 +75,8 @@ static int mock_object_init(struct intel_memory_region *mem,
 }
 
 static const struct intel_memory_region_ops mock_region_ops = {
-	.init = intel_memory_region_init_buddy,
-	.release = intel_memory_region_release_buddy,
+	.init = intel_region_ttm_init,
+	.release = intel_region_ttm_fini,
 	.init_object = mock_object_init,
 };
 
@@ -52,5 +88,6 @@ mock_region_create(struct drm_i915_private *i915,
 		   resource_size_t io_start)
 {
 	return intel_memory_region_create(i915, start, size, min_page_size,
-					  io_start, &mock_region_ops);
+					  io_start, INTEL_MEMORY_MOCK, 0,
+					  &mock_region_ops);
 }
diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c
index b9d5da6e6a81..6957dfb0cf5a 100644
--- a/drivers/gpu/drm/ttm/ttm_range_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -125,55 +125,76 @@ static const struct ttm_resource_manager_func ttm_range_manager_func = {
 	.debug = ttm_range_man_debug
 };
 
-int ttm_range_man_init(struct ttm_device *bdev,
-		       unsigned type, bool use_tt,
-		       unsigned long p_size)
+struct ttm_resource_manager *
+ttm_range_man_init_standalone(unsigned long size, bool use_tt)
 {
 	struct ttm_resource_manager *man;
 	struct ttm_range_manager *rman;
 
 	rman = kzalloc(sizeof(*rman), GFP_KERNEL);
 	if (!rman)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	man = &rman->manager;
 	man->use_tt = use_tt;
 
 	man->func = &ttm_range_manager_func;
 
-	ttm_resource_manager_init(man, p_size);
+	ttm_resource_manager_init(man, size);
 
-	drm_mm_init(&rman->mm, 0, p_size);
+	drm_mm_init(&rman->mm, 0, size);
 	spin_lock_init(&rman->lock);
 
-	ttm_set_driver_manager(bdev, type, &rman->manager);
+	return man;
+}
+EXPORT_SYMBOL(ttm_range_man_init_standalone);
+
+int ttm_range_man_init(struct ttm_device *bdev,
+		       unsigned int type, bool use_tt,
+		       unsigned long p_size)
+{
+	struct ttm_resource_manager *man;
+
+	man = ttm_range_man_init_standalone(p_size, use_tt);
+	if (IS_ERR(man))
+		return PTR_ERR(man);
+
 	ttm_resource_manager_set_used(man, true);
+	ttm_set_driver_manager(bdev, type, man);
+
 	return 0;
 }
 EXPORT_SYMBOL(ttm_range_man_init);
 
+void ttm_range_man_fini_standalone(struct ttm_resource_manager *man)
+{
+	struct ttm_range_manager *rman = to_range_manager(man);
+	struct drm_mm *mm = &rman->mm;
+
+	spin_lock(&rman->lock);
+	drm_mm_clean(mm);
+	drm_mm_takedown(mm);
+	spin_unlock(&rman->lock);
+
+	ttm_resource_manager_cleanup(man);
+	kfree(rman);
+}
+EXPORT_SYMBOL(ttm_range_man_fini_standalone);
+
 int ttm_range_man_fini(struct ttm_device *bdev,
 		       unsigned type)
 {
 	struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
-	struct ttm_range_manager *rman = to_range_manager(man);
-	struct drm_mm *mm = &rman->mm;
 	int ret;
 
 	ttm_resource_manager_set_used(man, false);
-
 	ret = ttm_resource_manager_evict_all(bdev, man);
 	if (ret)
 		return ret;
 
-	spin_lock(&rman->lock);
-	drm_mm_clean(mm);
-	drm_mm_takedown(mm);
-	spin_unlock(&rman->lock);
-
-	ttm_resource_manager_cleanup(man);
 	ttm_set_driver_manager(bdev, type, NULL);
-	kfree(rman);
+	ttm_range_man_fini_standalone(man);
+
 	return 0;
 }
 EXPORT_SYMBOL(ttm_range_man_fini);
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index dbccac957f8f..734b1712ea72 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -321,6 +321,20 @@ int ttm_range_man_init(struct ttm_device *bdev,
 		       unsigned type, bool use_tt,
 		       unsigned long p_size);
 
+/**
+ * ttm_range_man_init_standalone - Initialize a ttm range manager without
+ * device interaction.
+ * @size: Size of the area to be managed in pages.
+ * @use_tt: The memory type requires tt backing.
+ *
+ * This function is intended for selftests. It initializes a range manager
+ * without any device interaction.
+ *
+ * Return: pointer to a range manager on success. Error pointer on failure.
+ */
+struct ttm_resource_manager *
+ttm_range_man_init_standalone(unsigned long size, bool use_tt);
+
 /**
  * ttm_range_man_fini
  *
@@ -332,4 +346,13 @@ int ttm_range_man_init(struct ttm_device *bdev,
 int ttm_range_man_fini(struct ttm_device *bdev,
 		       unsigned type);
 
+/**
+ * ttm_range_man_fini_standalone
+ * @man: The range manager
+ *
+ * Tear down a range manager initialized with
+ * ttm_range_manager_init_standalone().
+ */
+void ttm_range_man_fini_standalone(struct ttm_resource_manager *man);
+
 #endif
-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH 4/7] drm/i915/ttm: Embed a ttm buffer object in the i915 gem object
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:25   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

Embed a struct ttm_buffer_object into the i915 gem object, making sure
we alias the gem object part. It's a bit unfortunate that the
struct ttm_buffer_ojbect embeds a gem object since we otherwise could
make the TTM part private to the TTM backend, and use the usual
i915 gem object for the other backends.
To make this a bit more storage efficient for the other backends,
we'd have to use a pointer for the gem object which would require
a lot of changes in the driver. We postpone that for later.

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_object.c       |  7 +++++++
 drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 12 +++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index abadf0994ad0..c8953e3f5c70 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -62,6 +62,13 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 			  const struct drm_i915_gem_object_ops *ops,
 			  struct lock_class_key *key, unsigned flags)
 {
+	/*
+	 * A gem object is embedded both in a struct ttm_buffer_object :/ and
+	 * in a drm_i915_gem_object. Make sure they are aliased.
+	 */
+	BUILD_BUG_ON(offsetof(typeof(*obj), base) !=
+		     offsetof(typeof(*obj), __do_not_access.base));
+
 	spin_lock_init(&obj->vma.lock);
 	INIT_LIST_HEAD(&obj->vma.list);
 
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 dbd7fffe956e..98f69d8fd37d 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -10,6 +10,7 @@
 #include <linux/mmu_notifier.h>
 
 #include <drm/drm_gem.h>
+#include <drm/ttm/ttm_bo_api.h>
 #include <uapi/drm/i915_drm.h>
 
 #include "i915_active.h"
@@ -99,7 +100,16 @@ struct i915_gem_object_page_iter {
 };
 
 struct drm_i915_gem_object {
-	struct drm_gem_object base;
+	/*
+	 * We might have reason to revisit the below since it wastes
+	 * a lot of space for non-ttm gem objects.
+	 * In any case, always use the accessors for the ttm_buffer_object
+	 * when accessing it.
+	 */
+	union {
+		struct drm_gem_object base;
+		struct ttm_buffer_object __do_not_access;
+	};
 
 	const struct drm_i915_gem_object_ops *ops;
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 4/7] drm/i915/ttm: Embed a ttm buffer object in the i915 gem object
@ 2021-05-11 13:25   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

Embed a struct ttm_buffer_object into the i915 gem object, making sure
we alias the gem object part. It's a bit unfortunate that the
struct ttm_buffer_ojbect embeds a gem object since we otherwise could
make the TTM part private to the TTM backend, and use the usual
i915 gem object for the other backends.
To make this a bit more storage efficient for the other backends,
we'd have to use a pointer for the gem object which would require
a lot of changes in the driver. We postpone that for later.

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_object.c       |  7 +++++++
 drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 12 +++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index abadf0994ad0..c8953e3f5c70 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -62,6 +62,13 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 			  const struct drm_i915_gem_object_ops *ops,
 			  struct lock_class_key *key, unsigned flags)
 {
+	/*
+	 * A gem object is embedded both in a struct ttm_buffer_object :/ and
+	 * in a drm_i915_gem_object. Make sure they are aliased.
+	 */
+	BUILD_BUG_ON(offsetof(typeof(*obj), base) !=
+		     offsetof(typeof(*obj), __do_not_access.base));
+
 	spin_lock_init(&obj->vma.lock);
 	INIT_LIST_HEAD(&obj->vma.list);
 
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 dbd7fffe956e..98f69d8fd37d 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -10,6 +10,7 @@
 #include <linux/mmu_notifier.h>
 
 #include <drm/drm_gem.h>
+#include <drm/ttm/ttm_bo_api.h>
 #include <uapi/drm/i915_drm.h>
 
 #include "i915_active.h"
@@ -99,7 +100,16 @@ struct i915_gem_object_page_iter {
 };
 
 struct drm_i915_gem_object {
-	struct drm_gem_object base;
+	/*
+	 * We might have reason to revisit the below since it wastes
+	 * a lot of space for non-ttm gem objects.
+	 * In any case, always use the accessors for the ttm_buffer_object
+	 * when accessing it.
+	 */
+	union {
+		struct drm_gem_object base;
+		struct ttm_buffer_object __do_not_access;
+	};
 
 	const struct drm_i915_gem_object_ops *ops;
 
-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH 5/7] drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:25   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström, Christian König

The internal ttm_bo_util memcpy uses vmap functionality, and while it
probably might be possible to use it for copying in- and out of
sglist represented io memory, using io_mem_reserve() / io_mem_free()
callbacks, that would cause problems with fault().
Instead, implement a method mapping page-by-page using kmap_local()
semantics. As an additional benefit we then avoid the occasional global
TLB flushes of vmap() and consuming vmap space, elimination of a critical
point of failure and with a slight change of semantics we could also push
the memcpy out async for testing and async driver develpment purposes.
Pushing out async can be done since there is no memory allocation going on
that could violate the dma_fence lockdep rules.

Note that drivers that don't want to use struct io_mapping but relies on
memremap functionality, and that don't want to use scatterlists for
VRAM may well define specialized (hopefully reusable) iterators for their
particular environment.

Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++++++++++++++++
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++++++++++++++
 drivers/gpu/drm/ttm/ttm_bo.c                  |   1 +
 4 files changed, 298 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index cb8823570996..958ccc1edfed 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -155,6 +155,7 @@ gem-y += \
 	gem/i915_gem_stolen.o \
 	gem/i915_gem_throttle.o \
 	gem/i915_gem_tiling.o \
+	gem/i915_gem_ttm_bo_util.o \
 	gem/i915_gem_userptr.o \
 	gem/i915_gem_wait.o \
 	gem/i915_gemfs.o
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
new file mode 100644
index 000000000000..1116d7df1461
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+/**
+ * DOC: Usage and intentions.
+ *
+ * This file contains functionality that we might want to move into
+ * ttm_bo_util.c if there is a common interest.
+ * Currently a kmap_local only memcpy with support for page-based iomem regions,
+ * and fast memcpy from write-combined memory.
+ */
+
+#include <linux/dma-buf-map.h>
+#include <linux/highmem.h>
+#include <linux/io-mapping.h>
+#include <linux/scatterlist.h>
+
+#include "i915_memcpy.h"
+
+#include "gem/i915_gem_ttm_bo_util.h"
+
+static void i915_ttm_kmap_iter_tt_kmap_local(struct i915_ttm_kmap_iter *iter,
+					     struct dma_buf_map *dmap,
+					     pgoff_t i)
+{
+	struct i915_ttm_kmap_iter_tt *iter_tt =
+		container_of(iter, typeof(*iter_tt), base);
+
+	dma_buf_map_set_vaddr(dmap, kmap_local_page(iter_tt->tt->pages[i]));
+}
+
+static void i915_ttm_kmap_iter_iomap_kmap_local(struct i915_ttm_kmap_iter *iter,
+						struct dma_buf_map *dmap,
+						pgoff_t i)
+{
+	struct i915_ttm_kmap_iter_iomap *iter_io =
+		container_of(iter, typeof(*iter_io), base);
+	void __iomem *addr;
+
+retry:
+	while (i >= iter_io->cache.end) {
+		iter_io->cache.sg = iter_io->cache.sg ?
+			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
+		iter_io->cache.i = iter_io->cache.end;
+		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
+			PAGE_SHIFT;
+		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
+			iter_io->start;
+	}
+
+	if (i < iter_io->cache.i) {
+		iter_io->cache.end = 0;
+		iter_io->cache.sg = NULL;
+		goto retry;
+	}
+
+	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
+				       (((resource_size_t)i - iter_io->cache.i)
+					<< PAGE_SHIFT));
+	dma_buf_map_set_vaddr_iomem(dmap, addr);
+}
+
+struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops = {
+	.kmap_local = i915_ttm_kmap_iter_tt_kmap_local
+};
+
+struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops = {
+	.kmap_local =  i915_ttm_kmap_iter_iomap_kmap_local
+};
+
+static void kunmap_local_dma_buf_map(struct dma_buf_map *map)
+{
+	if (map->is_iomem)
+		io_mapping_unmap_local(map->vaddr_iomem);
+	else
+		kunmap_local(map->vaddr);
+}
+
+/**
+ * i915_ttm_move_memcpy - Helper to perform a memcpy ttm move operation.
+ * @bo: The struct ttm_buffer_object.
+ * @new_mem: The struct ttm_resource we're moving to (copy destination).
+ * @new_kmap: A struct i915_ttm_kmap_iter representing the destination resource.
+ * @old_kmap: A struct i915_ttm_kmap_iter representing the source resource.
+ */
+void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
+			  struct ttm_resource *new_mem,
+			  struct i915_ttm_kmap_iter *new_kmap,
+			  struct i915_ttm_kmap_iter *old_kmap)
+{
+	struct ttm_device *bdev = bo->bdev;
+	struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
+	struct ttm_tt *ttm = bo->ttm;
+	struct ttm_resource *old_mem = &bo->mem;
+	struct ttm_resource old_copy = *old_mem;
+	struct ttm_resource_manager *old_man = ttm_manager_type(bdev, old_mem->mem_type);
+	struct dma_buf_map old_map, new_map;
+	pgoff_t i;
+
+	/* For the page-based allocator we need sgtable iterators as well.*/
+
+	/* Single TTM move. NOP */
+	if (old_man->use_tt && man->use_tt)
+		goto done;
+
+	/* Don't move nonexistent data. Clear destination instead. */
+	if (old_man->use_tt && !man->use_tt &&
+	    (ttm == NULL || !ttm_tt_is_populated(ttm))) {
+		if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC))
+			goto done;
+
+		for (i = 0; i < new_mem->num_pages; ++i) {
+			new_kmap->ops->kmap_local(new_kmap, &new_map, i);
+			memset_io(new_map.vaddr_iomem, 0, PAGE_SIZE);
+			kunmap_local_dma_buf_map(&new_map);
+		}
+		goto done;
+	}
+
+	for (i = 0; i < new_mem->num_pages; ++i) {
+		new_kmap->ops->kmap_local(new_kmap, &new_map, i);
+		old_kmap->ops->kmap_local(old_kmap, &old_map, i);
+		if (!old_map.is_iomem ||
+		    !i915_memcpy_from_wc(new_map.vaddr, old_map.vaddr, PAGE_SIZE)) {
+			if (!old_map.is_iomem) {
+				dma_buf_map_memcpy_to(&new_map, old_map.vaddr,
+						      PAGE_SIZE);
+			} else if (!new_map.is_iomem) {
+				memcpy_fromio(new_map.vaddr, old_map.vaddr_iomem,
+					      PAGE_SIZE);
+			} else {
+				pgoff_t j;
+				u32 __iomem *src = old_map.vaddr_iomem;
+				u32 __iomem *dst = new_map.vaddr_iomem;
+
+				for (j = 0; j < (PAGE_SIZE >> 2); ++j)
+					iowrite32(ioread32(src++), dst++);
+			}
+		}
+		kunmap_local_dma_buf_map(&old_map);
+		kunmap_local_dma_buf_map(&new_map);
+	}
+
+done:
+	old_copy = *old_mem;
+
+	ttm_bo_assign_mem(bo, new_mem);
+
+	if (!man->use_tt)
+		ttm_bo_tt_destroy(bo);
+
+	ttm_resource_free(bo, &old_copy);
+}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
new file mode 100644
index 000000000000..82c92176718d
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+/*
+ * This files contains functionality that we might want to move into
+ * ttm_bo_util.c if there is a common interest.
+ */
+#ifndef _I915_GEM_TTM_BO_UTIL_H_
+#define _I915_GEM_TTM_BO_UTIL_H_
+
+#include <drm/ttm/ttm_bo_driver.h>
+struct dma_buf_map;
+struct io_mapping;
+struct sg_table;
+struct scatterlist;
+
+struct ttm_tt;
+struct i915_ttm_kmap_iter;
+
+/**
+ * struct i915_ttm_kmap_iter_ops - Ops structure for a struct
+ * i915_ttm_kmap_iter.
+ */
+struct i915_ttm_kmap_iter_ops {
+	/**
+	 * kmap_local - Map a PAGE_SIZE part of the resource using
+	 * kmap_local semantics.
+	 * @res_kmap: Pointer to the struct i915_ttm_kmap_iter representing
+	 * the resource.
+	 * @dmap: The struct dma_buf_map holding the virtual address after
+	 * the operation.
+	 * @i: The location within the resource to map. PAGE_SIZE granularity.
+	 */
+	void (*kmap_local)(struct i915_ttm_kmap_iter *res_kmap,
+			   struct dma_buf_map *dmap, pgoff_t i);
+};
+
+/**
+ * struct i915_ttm_kmap_iter - Iterator for kmap_local type operations on a
+ * resource.
+ * @ops: Pointer to the operations struct.
+ *
+ * This struct is intended to be embedded in a resource-specific specialization
+ * implementing operations for the resource.
+ *
+ * Nothing stops us from extending the operations to vmap, vmap_pfn etc,
+ * replacing some or parts of the ttm_bo_util. cpu-map functionality.
+ */
+struct i915_ttm_kmap_iter {
+	const struct i915_ttm_kmap_iter_ops *ops;
+};
+
+/**
+ * struct i915_ttm_kmap_iter_tt - Specialization for a tt (page) backed struct
+ * ttm_resource.
+ * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface
+ * @tt: Cached struct ttm_tt.
+ */
+struct i915_ttm_kmap_iter_tt {
+	struct i915_ttm_kmap_iter base;
+	struct ttm_tt *tt;
+};
+
+/**
+ * struct i915_ttm_kmap_iter_iomap - Specialization for a struct io_mapping +
+ * struct sg_table backed struct ttm_resource.
+ * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface.
+ * @iomap: struct io_mapping representing the underlying linear io_memory.
+ * @st: sg_table into @iomap, representing the memory of the struct ttm_resource.
+ * @start: Offset that needs to be subtracted from @st to make
+ * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
+ * @cache: Scatterlist traversal cache for fast lookups.
+ * @cache.sg: Pointer to the currently cached scatterlist segment.
+ * @cache.i: First index of @sg. PAGE_SIZE granularity.
+ * @cache.end: Last index + 1 of @sg. PAGE_SIZE granularity.
+ * @cache.offs: First offset into @iomap of @sg. PAGE_SIZE granularity.
+ */
+struct i915_ttm_kmap_iter_iomap {
+	struct i915_ttm_kmap_iter base;
+	struct io_mapping *iomap;
+	struct sg_table *st;
+	resource_size_t start;
+	struct {
+		struct scatterlist *sg;
+		pgoff_t i;
+		pgoff_t end;
+		pgoff_t offs;
+	} cache;
+};
+
+extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops;
+extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops;
+
+/**
+ * i915_ttm_kmap_iter_iomap_init - Initialize a struct i915_ttm_kmap_iter_iomap
+ * @iter_io: The struct i915_ttm_kmap_iter_iomap to initialize.
+ * @iomap: The struct io_mapping representing the underlying linear io_memory.
+ * @st: sg_table into @iomap, representing the memory of the struct
+ * ttm_resource.
+ * @start: Offset that needs to be subtracted from @st to make
+ * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
+ *
+ * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
+ */
+static inline struct i915_ttm_kmap_iter *
+i915_ttm_kmap_iter_iomap_init(struct i915_ttm_kmap_iter_iomap *iter_io,
+			      struct io_mapping *iomap,
+			      struct sg_table *st,
+			      resource_size_t start)
+{
+	iter_io->base.ops = &i915_ttm_kmap_iter_io_ops;
+	iter_io->iomap = iomap;
+	iter_io->st = st;
+	iter_io->start = start;
+	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
+	return &iter_io->base;
+}
+
+/**
+ * ttm_kmap_iter_tt_init - Initialize a struct i915_ttm_kmap_iter_tt
+ * @iter_tt: The struct i915_ttm_kmap_iter_tt to initialize.
+ * @tt: Struct ttm_tt holding page pointers of the struct ttm_resource.
+ *
+ * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
+ */
+static inline struct i915_ttm_kmap_iter *
+i915_ttm_kmap_iter_tt_init(struct i915_ttm_kmap_iter_tt *iter_tt,
+			   struct ttm_tt *tt)
+{
+	iter_tt->base.ops = &i915_ttm_kmap_iter_tt_ops;
+	iter_tt->tt = tt;
+	return &iter_tt->base;
+}
+
+void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
+			  struct ttm_resource *new_mem,
+			  struct i915_ttm_kmap_iter *new_iter,
+			  struct i915_ttm_kmap_iter *old_iter);
+#endif
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index ca1b098b6a56..4479c55aaa1d 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1221,3 +1221,4 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo)
 	ttm_tt_destroy(bo->bdev, bo->ttm);
 	bo->ttm = NULL;
 }
+EXPORT_SYMBOL(ttm_bo_tt_destroy);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 5/7] drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
@ 2021-05-11 13:25   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström, Christian König

The internal ttm_bo_util memcpy uses vmap functionality, and while it
probably might be possible to use it for copying in- and out of
sglist represented io memory, using io_mem_reserve() / io_mem_free()
callbacks, that would cause problems with fault().
Instead, implement a method mapping page-by-page using kmap_local()
semantics. As an additional benefit we then avoid the occasional global
TLB flushes of vmap() and consuming vmap space, elimination of a critical
point of failure and with a slight change of semantics we could also push
the memcpy out async for testing and async driver develpment purposes.
Pushing out async can be done since there is no memory allocation going on
that could violate the dma_fence lockdep rules.

Note that drivers that don't want to use struct io_mapping but relies on
memremap functionality, and that don't want to use scatterlists for
VRAM may well define specialized (hopefully reusable) iterators for their
particular environment.

Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++++++++++++++++
 .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++++++++++++++
 drivers/gpu/drm/ttm/ttm_bo.c                  |   1 +
 4 files changed, 298 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index cb8823570996..958ccc1edfed 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -155,6 +155,7 @@ gem-y += \
 	gem/i915_gem_stolen.o \
 	gem/i915_gem_throttle.o \
 	gem/i915_gem_tiling.o \
+	gem/i915_gem_ttm_bo_util.o \
 	gem/i915_gem_userptr.o \
 	gem/i915_gem_wait.o \
 	gem/i915_gemfs.o
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
new file mode 100644
index 000000000000..1116d7df1461
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+/**
+ * DOC: Usage and intentions.
+ *
+ * This file contains functionality that we might want to move into
+ * ttm_bo_util.c if there is a common interest.
+ * Currently a kmap_local only memcpy with support for page-based iomem regions,
+ * and fast memcpy from write-combined memory.
+ */
+
+#include <linux/dma-buf-map.h>
+#include <linux/highmem.h>
+#include <linux/io-mapping.h>
+#include <linux/scatterlist.h>
+
+#include "i915_memcpy.h"
+
+#include "gem/i915_gem_ttm_bo_util.h"
+
+static void i915_ttm_kmap_iter_tt_kmap_local(struct i915_ttm_kmap_iter *iter,
+					     struct dma_buf_map *dmap,
+					     pgoff_t i)
+{
+	struct i915_ttm_kmap_iter_tt *iter_tt =
+		container_of(iter, typeof(*iter_tt), base);
+
+	dma_buf_map_set_vaddr(dmap, kmap_local_page(iter_tt->tt->pages[i]));
+}
+
+static void i915_ttm_kmap_iter_iomap_kmap_local(struct i915_ttm_kmap_iter *iter,
+						struct dma_buf_map *dmap,
+						pgoff_t i)
+{
+	struct i915_ttm_kmap_iter_iomap *iter_io =
+		container_of(iter, typeof(*iter_io), base);
+	void __iomem *addr;
+
+retry:
+	while (i >= iter_io->cache.end) {
+		iter_io->cache.sg = iter_io->cache.sg ?
+			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
+		iter_io->cache.i = iter_io->cache.end;
+		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
+			PAGE_SHIFT;
+		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
+			iter_io->start;
+	}
+
+	if (i < iter_io->cache.i) {
+		iter_io->cache.end = 0;
+		iter_io->cache.sg = NULL;
+		goto retry;
+	}
+
+	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
+				       (((resource_size_t)i - iter_io->cache.i)
+					<< PAGE_SHIFT));
+	dma_buf_map_set_vaddr_iomem(dmap, addr);
+}
+
+struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops = {
+	.kmap_local = i915_ttm_kmap_iter_tt_kmap_local
+};
+
+struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops = {
+	.kmap_local =  i915_ttm_kmap_iter_iomap_kmap_local
+};
+
+static void kunmap_local_dma_buf_map(struct dma_buf_map *map)
+{
+	if (map->is_iomem)
+		io_mapping_unmap_local(map->vaddr_iomem);
+	else
+		kunmap_local(map->vaddr);
+}
+
+/**
+ * i915_ttm_move_memcpy - Helper to perform a memcpy ttm move operation.
+ * @bo: The struct ttm_buffer_object.
+ * @new_mem: The struct ttm_resource we're moving to (copy destination).
+ * @new_kmap: A struct i915_ttm_kmap_iter representing the destination resource.
+ * @old_kmap: A struct i915_ttm_kmap_iter representing the source resource.
+ */
+void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
+			  struct ttm_resource *new_mem,
+			  struct i915_ttm_kmap_iter *new_kmap,
+			  struct i915_ttm_kmap_iter *old_kmap)
+{
+	struct ttm_device *bdev = bo->bdev;
+	struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
+	struct ttm_tt *ttm = bo->ttm;
+	struct ttm_resource *old_mem = &bo->mem;
+	struct ttm_resource old_copy = *old_mem;
+	struct ttm_resource_manager *old_man = ttm_manager_type(bdev, old_mem->mem_type);
+	struct dma_buf_map old_map, new_map;
+	pgoff_t i;
+
+	/* For the page-based allocator we need sgtable iterators as well.*/
+
+	/* Single TTM move. NOP */
+	if (old_man->use_tt && man->use_tt)
+		goto done;
+
+	/* Don't move nonexistent data. Clear destination instead. */
+	if (old_man->use_tt && !man->use_tt &&
+	    (ttm == NULL || !ttm_tt_is_populated(ttm))) {
+		if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC))
+			goto done;
+
+		for (i = 0; i < new_mem->num_pages; ++i) {
+			new_kmap->ops->kmap_local(new_kmap, &new_map, i);
+			memset_io(new_map.vaddr_iomem, 0, PAGE_SIZE);
+			kunmap_local_dma_buf_map(&new_map);
+		}
+		goto done;
+	}
+
+	for (i = 0; i < new_mem->num_pages; ++i) {
+		new_kmap->ops->kmap_local(new_kmap, &new_map, i);
+		old_kmap->ops->kmap_local(old_kmap, &old_map, i);
+		if (!old_map.is_iomem ||
+		    !i915_memcpy_from_wc(new_map.vaddr, old_map.vaddr, PAGE_SIZE)) {
+			if (!old_map.is_iomem) {
+				dma_buf_map_memcpy_to(&new_map, old_map.vaddr,
+						      PAGE_SIZE);
+			} else if (!new_map.is_iomem) {
+				memcpy_fromio(new_map.vaddr, old_map.vaddr_iomem,
+					      PAGE_SIZE);
+			} else {
+				pgoff_t j;
+				u32 __iomem *src = old_map.vaddr_iomem;
+				u32 __iomem *dst = new_map.vaddr_iomem;
+
+				for (j = 0; j < (PAGE_SIZE >> 2); ++j)
+					iowrite32(ioread32(src++), dst++);
+			}
+		}
+		kunmap_local_dma_buf_map(&old_map);
+		kunmap_local_dma_buf_map(&new_map);
+	}
+
+done:
+	old_copy = *old_mem;
+
+	ttm_bo_assign_mem(bo, new_mem);
+
+	if (!man->use_tt)
+		ttm_bo_tt_destroy(bo);
+
+	ttm_resource_free(bo, &old_copy);
+}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
new file mode 100644
index 000000000000..82c92176718d
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+/*
+ * This files contains functionality that we might want to move into
+ * ttm_bo_util.c if there is a common interest.
+ */
+#ifndef _I915_GEM_TTM_BO_UTIL_H_
+#define _I915_GEM_TTM_BO_UTIL_H_
+
+#include <drm/ttm/ttm_bo_driver.h>
+struct dma_buf_map;
+struct io_mapping;
+struct sg_table;
+struct scatterlist;
+
+struct ttm_tt;
+struct i915_ttm_kmap_iter;
+
+/**
+ * struct i915_ttm_kmap_iter_ops - Ops structure for a struct
+ * i915_ttm_kmap_iter.
+ */
+struct i915_ttm_kmap_iter_ops {
+	/**
+	 * kmap_local - Map a PAGE_SIZE part of the resource using
+	 * kmap_local semantics.
+	 * @res_kmap: Pointer to the struct i915_ttm_kmap_iter representing
+	 * the resource.
+	 * @dmap: The struct dma_buf_map holding the virtual address after
+	 * the operation.
+	 * @i: The location within the resource to map. PAGE_SIZE granularity.
+	 */
+	void (*kmap_local)(struct i915_ttm_kmap_iter *res_kmap,
+			   struct dma_buf_map *dmap, pgoff_t i);
+};
+
+/**
+ * struct i915_ttm_kmap_iter - Iterator for kmap_local type operations on a
+ * resource.
+ * @ops: Pointer to the operations struct.
+ *
+ * This struct is intended to be embedded in a resource-specific specialization
+ * implementing operations for the resource.
+ *
+ * Nothing stops us from extending the operations to vmap, vmap_pfn etc,
+ * replacing some or parts of the ttm_bo_util. cpu-map functionality.
+ */
+struct i915_ttm_kmap_iter {
+	const struct i915_ttm_kmap_iter_ops *ops;
+};
+
+/**
+ * struct i915_ttm_kmap_iter_tt - Specialization for a tt (page) backed struct
+ * ttm_resource.
+ * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface
+ * @tt: Cached struct ttm_tt.
+ */
+struct i915_ttm_kmap_iter_tt {
+	struct i915_ttm_kmap_iter base;
+	struct ttm_tt *tt;
+};
+
+/**
+ * struct i915_ttm_kmap_iter_iomap - Specialization for a struct io_mapping +
+ * struct sg_table backed struct ttm_resource.
+ * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface.
+ * @iomap: struct io_mapping representing the underlying linear io_memory.
+ * @st: sg_table into @iomap, representing the memory of the struct ttm_resource.
+ * @start: Offset that needs to be subtracted from @st to make
+ * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
+ * @cache: Scatterlist traversal cache for fast lookups.
+ * @cache.sg: Pointer to the currently cached scatterlist segment.
+ * @cache.i: First index of @sg. PAGE_SIZE granularity.
+ * @cache.end: Last index + 1 of @sg. PAGE_SIZE granularity.
+ * @cache.offs: First offset into @iomap of @sg. PAGE_SIZE granularity.
+ */
+struct i915_ttm_kmap_iter_iomap {
+	struct i915_ttm_kmap_iter base;
+	struct io_mapping *iomap;
+	struct sg_table *st;
+	resource_size_t start;
+	struct {
+		struct scatterlist *sg;
+		pgoff_t i;
+		pgoff_t end;
+		pgoff_t offs;
+	} cache;
+};
+
+extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops;
+extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops;
+
+/**
+ * i915_ttm_kmap_iter_iomap_init - Initialize a struct i915_ttm_kmap_iter_iomap
+ * @iter_io: The struct i915_ttm_kmap_iter_iomap to initialize.
+ * @iomap: The struct io_mapping representing the underlying linear io_memory.
+ * @st: sg_table into @iomap, representing the memory of the struct
+ * ttm_resource.
+ * @start: Offset that needs to be subtracted from @st to make
+ * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
+ *
+ * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
+ */
+static inline struct i915_ttm_kmap_iter *
+i915_ttm_kmap_iter_iomap_init(struct i915_ttm_kmap_iter_iomap *iter_io,
+			      struct io_mapping *iomap,
+			      struct sg_table *st,
+			      resource_size_t start)
+{
+	iter_io->base.ops = &i915_ttm_kmap_iter_io_ops;
+	iter_io->iomap = iomap;
+	iter_io->st = st;
+	iter_io->start = start;
+	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
+	return &iter_io->base;
+}
+
+/**
+ * ttm_kmap_iter_tt_init - Initialize a struct i915_ttm_kmap_iter_tt
+ * @iter_tt: The struct i915_ttm_kmap_iter_tt to initialize.
+ * @tt: Struct ttm_tt holding page pointers of the struct ttm_resource.
+ *
+ * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
+ */
+static inline struct i915_ttm_kmap_iter *
+i915_ttm_kmap_iter_tt_init(struct i915_ttm_kmap_iter_tt *iter_tt,
+			   struct ttm_tt *tt)
+{
+	iter_tt->base.ops = &i915_ttm_kmap_iter_tt_ops;
+	iter_tt->tt = tt;
+	return &iter_tt->base;
+}
+
+void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
+			  struct ttm_resource *new_mem,
+			  struct i915_ttm_kmap_iter *new_iter,
+			  struct i915_ttm_kmap_iter *old_iter);
+#endif
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index ca1b098b6a56..4479c55aaa1d 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1221,3 +1221,4 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo)
 	ttm_tt_destroy(bo->bdev, bo->ttm);
 	bo->ttm = NULL;
 }
+EXPORT_SYMBOL(ttm_bo_tt_destroy);
-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:25   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström, Christian König

Most logical place to introduce TTM buffer objects is as an i915
gem object backend. We need to add some ops to account for added
functionality like delayed delete and LRU list manipulation.

Initially we support only LMEM and SYSTEM memory, but SYSTEM
(which in this case means evicted LMEM objects) is not
visible to i915 GEM yet. The plan is to move the i915 gem system region
over to the TTM system memory type in upcoming patches.

We set up GPU bindings directly both from LMEM and from the system region,
as there is no need to use the legacy TTM_TT memory type. We reserve
that for future porting of GGTT bindings to TTM.

There are some changes to TTM to allow for purging system memory buffer
objects and to refuse swapping of some objects: Unfortunately i915 gem
still relies heavily on short-term object pinning, and we've chosen to
keep short-term-pinned buffer objects on the TTM LRU lists for now,
meaning that we need some sort of mechanism to tell TTM they are not
swappable. A longer term goal is to get rid of the short-term pinning.

Remove the old lmem backend.

Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
 drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
 drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
 drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
 drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
 drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
 drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
 drivers/gpu/drm/i915/i915_gem.c               |   5 +-
 drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
 drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
 drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
 drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
 drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
 include/drm/ttm/ttm_device.h                  |   9 +
 17 files changed, 733 insertions(+), 140 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 958ccc1edfed..ef0d884a9e2d 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -155,6 +155,7 @@ gem-y += \
 	gem/i915_gem_stolen.o \
 	gem/i915_gem_throttle.o \
 	gem/i915_gem_tiling.o \
+	gem/i915_gem_ttm.o \
 	gem/i915_gem_ttm_bo_util.o \
 	gem/i915_gem_userptr.o \
 	gem/i915_gem_wait.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
index f42803ea48f2..2b8cd15de1d9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
@@ -4,73 +4,10 @@
  */
 
 #include "intel_memory_region.h"
-#include "intel_region_ttm.h"
 #include "gem/i915_gem_region.h"
 #include "gem/i915_gem_lmem.h"
 #include "i915_drv.h"
 
-static void lmem_put_pages(struct drm_i915_gem_object *obj,
-				  struct sg_table *pages)
-{
-	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
-	obj->mm.dirty = false;
-	sg_free_table(pages);
-	kfree(pages);
-}
-
-static int lmem_get_pages(struct drm_i915_gem_object *obj)
-{
-	unsigned int flags;
-	struct sg_table *pages;
-
-	flags = I915_ALLOC_MIN_PAGE_SIZE;
-	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
-		flags |= I915_ALLOC_CONTIGUOUS;
-
-	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
-							 obj->base.size,
-							 flags);
-	if (IS_ERR(obj->mm.st_mm_node))
-		return PTR_ERR(obj->mm.st_mm_node);
-
-	/* Range manager is always contigous */
-	if (obj->mm.region->is_range_manager)
-		obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
-	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
-	if (IS_ERR(pages))
-		return PTR_ERR(pages);
-
-	__i915_gem_object_set_pages(obj, pages,
-				    i915_sg_dma_page_sizes(pages->sgl));
-
-	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
-		void __iomem *vaddr =
-			i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
-
-		if (!vaddr) {
-			struct sg_table *pages =
-				__i915_gem_object_unset_pages(obj);
-
-			if (!IS_ERR_OR_NULL(pages))
-				lmem_put_pages(obj, pages);
-		}
-
-		memset_io(vaddr, 0, obj->base.size);
-		io_mapping_unmap(vaddr);
-	}
-
-	return 0;
-}
-
-const struct drm_i915_gem_object_ops i915_gem_lmem_obj_ops = {
-	.name = "i915_gem_object_lmem",
-	.flags = I915_GEM_OBJECT_HAS_IOMEM,
-
-	.get_pages = lmem_get_pages,
-	.put_pages = lmem_put_pages,
-	.release = i915_gem_object_release_memory_region,
-};
-
 void __iomem *
 i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
 			    unsigned long n,
@@ -102,23 +39,3 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
 	return i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_LMEM],
 					     size, flags);
 }
-
-int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
-				struct drm_i915_gem_object *obj,
-				resource_size_t size,
-				unsigned int flags)
-{
-	static struct lock_class_key lock_class;
-	struct drm_i915_private *i915 = mem->i915;
-
-	drm_gem_private_object_init(&i915->drm, &obj->base, size);
-	i915_gem_object_init(obj, &i915_gem_lmem_obj_ops, &lock_class, flags);
-
-	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
-
-	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
-
-	i915_gem_object_init_memory_region(obj, mem);
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
index fac6bc5a5ebb..ea76fd11ccb0 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
@@ -26,9 +26,4 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
 			    resource_size_t size,
 			    unsigned int flags);
 
-int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
-				struct drm_i915_gem_object *obj,
-				resource_size_t size,
-				unsigned int flags);
-
 #endif /* !__I915_GEM_LMEM_H */
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index c8953e3f5c70..c53488f391dd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -172,7 +172,7 @@ static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *f
 	}
 }
 
-static void __i915_gem_free_object_rcu(struct rcu_head *head)
+void __i915_gem_free_object_rcu(struct rcu_head *head)
 {
 	struct drm_i915_gem_object *obj =
 		container_of(head, typeof(*obj), rcu);
@@ -208,59 +208,70 @@ static void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj)
 	}
 }
 
-static void __i915_gem_free_objects(struct drm_i915_private *i915,
-				    struct llist_node *freed)
+void __i915_gem_free_object(struct drm_i915_gem_object *obj)
 {
-	struct drm_i915_gem_object *obj, *on;
+	trace_i915_gem_object_destroy(obj);
 
-	llist_for_each_entry_safe(obj, on, freed, freed) {
-		trace_i915_gem_object_destroy(obj);
+	if (!list_empty(&obj->vma.list)) {
+		struct i915_vma *vma;
+
+		/*
+		 * Note that the vma keeps an object reference while
+		 * it is active, so it *should* not sleep while we
+		 * destroy it. Our debug code errs insits it *might*.
+		 * For the moment, play along.
+		 */
+		spin_lock(&obj->vma.lock);
+		while ((vma = list_first_entry_or_null(&obj->vma.list,
+						       struct i915_vma,
+						       obj_link))) {
+			GEM_BUG_ON(vma->obj != obj);
+			spin_unlock(&obj->vma.lock);
 
-		if (!list_empty(&obj->vma.list)) {
-			struct i915_vma *vma;
+			__i915_vma_put(vma);
 
-			/*
-			 * Note that the vma keeps an object reference while
-			 * it is active, so it *should* not sleep while we
-			 * destroy it. Our debug code errs insits it *might*.
-			 * For the moment, play along.
-			 */
 			spin_lock(&obj->vma.lock);
-			while ((vma = list_first_entry_or_null(&obj->vma.list,
-							       struct i915_vma,
-							       obj_link))) {
-				GEM_BUG_ON(vma->obj != obj);
-				spin_unlock(&obj->vma.lock);
+		}
+		spin_unlock(&obj->vma.lock);
+	}
 
-				__i915_vma_put(vma);
+	__i915_gem_object_free_mmaps(obj);
 
-				spin_lock(&obj->vma.lock);
-			}
-			spin_unlock(&obj->vma.lock);
-		}
+	GEM_BUG_ON(!list_empty(&obj->lut_list));
 
-		__i915_gem_object_free_mmaps(obj);
+	atomic_set(&obj->mm.pages_pin_count, 0);
+	__i915_gem_object_put_pages(obj);
+	GEM_BUG_ON(i915_gem_object_has_pages(obj));
+	bitmap_free(obj->bit_17);
 
-		GEM_BUG_ON(!list_empty(&obj->lut_list));
+	if (obj->base.import_attach)
+		drm_prime_gem_destroy(&obj->base, NULL);
 
-		atomic_set(&obj->mm.pages_pin_count, 0);
-		__i915_gem_object_put_pages(obj);
-		GEM_BUG_ON(i915_gem_object_has_pages(obj));
-		bitmap_free(obj->bit_17);
+	drm_gem_free_mmap_offset(&obj->base);
 
-		if (obj->base.import_attach)
-			drm_prime_gem_destroy(&obj->base, NULL);
+	if (obj->ops->release)
+		obj->ops->release(obj);
 
-		drm_gem_free_mmap_offset(&obj->base);
+	if (obj->mm.n_placements > 1)
+		kfree(obj->mm.placements);
 
-		if (obj->ops->release)
-			obj->ops->release(obj);
+	if (obj->resv_shared_from)
+		i915_vm_resv_put(obj->resv_shared_from);
 
-		if (obj->mm.n_placements > 1)
-			kfree(obj->mm.placements);
+}
+
+static void __i915_gem_free_objects(struct drm_i915_private *i915,
+				    struct llist_node *freed)
+{
+	struct drm_i915_gem_object *obj, *on;
 
-		if (obj->resv_shared_from)
-			i915_vm_resv_put(obj->resv_shared_from);
+	llist_for_each_entry_safe(obj, on, freed, freed) {
+		might_sleep();
+		if (obj->ops->delayed_free) {
+			obj->ops->delayed_free(obj);
+			continue;
+		}
+		__i915_gem_free_object(obj);
 
 		/* But keep the pointer alive for RCU-protected lookups */
 		call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
@@ -318,6 +329,7 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj)
 	 * worker and performing frees directly from subsequent allocations for
 	 * crude but effective memory throttling.
 	 */
+
 	if (llist_add(&obj->freed, &i915->mm.free_list))
 		queue_work(i915->wq, &i915->mm.free_work);
 }
@@ -410,6 +422,42 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
 	return 0;
 }
 
+/**
+ * i915_gem_object_evictable - Whether object is likely evictable after unbind.
+ * @obj: The object to check
+ *
+ * This function checks whether the object is likely unvictable after unbind.
+ * If the object is not locked when checking, the result is only advisory.
+ * If the object is locked when checking, and the function returns true,
+ * then an eviction should indeed be possible. But since unlocked vma
+ * unpinning and unbinding is currently possible, the object can actually
+ * become evictable even if this function returns false.
+ *
+ * Return: true if the object may be evictable. False otherwise.
+ */
+bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
+{
+	struct i915_vma *vma;
+	int pin_count = atomic_read(&obj->mm.pages_pin_count);
+
+	if (!pin_count)
+		return true;
+
+	spin_lock(&obj->vma.lock);
+	list_for_each_entry(vma, &obj->vma.list, obj_link) {
+		if (i915_vma_is_pinned(vma)) {
+			spin_unlock(&obj->vma.lock);
+			return false;
+		}
+		if (atomic_read(&vma->pages_count))
+			pin_count--;
+	}
+	spin_unlock(&obj->vma.lock);
+	GEM_WARN_ON(pin_count < 0);
+
+	return pin_count == 0;
+}
+
 void i915_gem_init__objects(struct drm_i915_private *i915)
 {
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index 2ebd79537aea..ae5930e307d5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -200,6 +200,9 @@ static inline bool i915_gem_object_trylock(struct drm_i915_gem_object *obj)
 
 static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj)
 {
+	if (obj->ops->adjust_lru)
+		obj->ops->adjust_lru(obj);
+
 	dma_resv_unlock(obj->base.resv);
 }
 
@@ -587,6 +590,12 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
 
 bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj);
 
+void __i915_gem_free_object_rcu(struct rcu_head *head);
+
+void __i915_gem_free_object(struct drm_i915_gem_object *obj);
+
+bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
+
 #ifdef CONFIG_MMU_NOTIFIER
 static inline bool
 i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
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 98f69d8fd37d..b350765e1935 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -63,6 +63,20 @@ struct drm_i915_gem_object_ops {
 		      const struct drm_i915_gem_pwrite *arg);
 
 	int (*dmabuf_export)(struct drm_i915_gem_object *obj);
+
+	/**
+	 * adjust_lru - notify that the madvise value was updated
+	 * @obj: The gem object
+	 *
+	 * The madvise value may have been updated, or object was recently
+	 * referenced so act accordingly (Perhaps changing an LRU list etc).
+	 */
+	void (*adjust_lru)(struct drm_i915_gem_object *obj);
+
+	/**
+	 * delayed_free - Override the default delayed free implementation
+	 */
+	void (*delayed_free)(struct drm_i915_gem_object *obj);
 	void (*release)(struct drm_i915_gem_object *obj);
 
 	const char *name; /* friendly name for debug, e.g. lockdep classes */
@@ -307,6 +321,10 @@ struct drm_i915_gem_object {
 		bool dirty:1;
 	} mm;
 
+	struct {
+		struct sg_table *cached_io_st;
+	} ttm;
+
 	/** Record of address bit 17 of each page at last unbind. */
 	unsigned long *bit_17;
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
index f25e6646c5b7..d1f1840540dd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
@@ -18,11 +18,7 @@ void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
 
 	mutex_lock(&mem->objects.lock);
 
-	if (obj->flags & I915_BO_ALLOC_VOLATILE)
-		list_add(&obj->mm.region_link, &mem->objects.purgeable);
-	else
-		list_add(&obj->mm.region_link, &mem->objects.list);
-
+	list_add(&obj->mm.region_link, &mem->objects.list);
 	mutex_unlock(&mem->objects.lock);
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
new file mode 100644
index 000000000000..e3718c3cb299
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_placement.h>
+
+#include "i915_drv.h"
+#include "intel_memory_region.h"
+#include "intel_region_ttm.h"
+
+#include "gem/i915_gem_object.h"
+#include "gem/i915_gem_region.h"
+#include "gem/i915_gem_ttm.h"
+#include "gem/i915_gem_ttm_bo_util.h"
+
+#define I915_PL_LMEM0 TTM_PL_PRIV
+#define I915_PL_SYSTEM TTM_PL_SYSTEM
+#define I915_PL_STOLEN TTM_PL_VRAM
+#define I915_PL_GGTT TTM_PL_TT
+
+#define I915_TTM_PRIO_PURGE     0
+#define I915_TTM_PRIO_NO_PAGES  1
+#define I915_TTM_PRIO_HAS_PAGES 2
+
+/**
+ * struct i915_ttm_tt - TTM page vector with additional private information
+ * @ttm: The base TTM page vector.
+ * @dev: The struct device used for dma mapping and unmapping.
+ * @cached_st: The cached scatter-gather table.
+ *
+ * Note that DMA may be going on right up to the point where the page-
+ * vector is unpopulated in delayed destroy. Hence keep the
+ * scatter-gather table mapped and cached up to that point. This is
+ * different from the cached gem object io scatter-gather table which
+ * doesn't have an associated dma mapping.
+ */
+struct i915_ttm_tt {
+	struct ttm_tt ttm;
+	struct device *dev;
+	struct sg_table *cached_st;
+};
+
+static const struct ttm_place lmem0_sys_placement_flags[] = {
+	{
+		.fpfn = 0,
+		.lpfn = 0,
+		.mem_type = I915_PL_LMEM0,
+		.flags = 0,
+	}, {
+		.fpfn = 0,
+		.lpfn = 0,
+		.mem_type = I915_PL_SYSTEM,
+		.flags = 0,
+	}
+};
+
+struct ttm_placement i915_lmem0_placement = {
+	.num_placement = 1,
+	.placement = &lmem0_sys_placement_flags[0],
+	.num_busy_placement = 1,
+	.busy_placement = &lmem0_sys_placement_flags[0],
+};
+
+struct ttm_placement i915_lmem0_sys_placement = {
+	.num_placement = 1,
+	.placement = &lmem0_sys_placement_flags[0],
+	.num_busy_placement = 2,
+	.busy_placement = &lmem0_sys_placement_flags[0],
+};
+
+struct ttm_placement i915_sys_placement = {
+	.num_placement = 1,
+	.placement = &lmem0_sys_placement_flags[1],
+	.num_busy_placement = 1,
+	.busy_placement = &lmem0_sys_placement_flags[1],
+};
+
+static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj);
+
+static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
+					 uint32_t page_flags)
+{
+	struct ttm_resource_manager *man =
+		ttm_manager_type(bo->bdev, bo->mem.mem_type);
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	struct i915_ttm_tt *i915_tt;
+	int ret;
+
+	i915_tt = kzalloc(sizeof(*i915_tt), GFP_KERNEL);
+	if (!i915_tt)
+		return NULL;
+
+	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR &&
+	    man->use_tt)
+		page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC;
+
+	ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, ttm_cached);
+	if (ret) {
+		kfree(i915_tt);
+		return NULL;
+	}
+
+	i915_tt->dev = obj->base.dev->dev;
+
+	return &i915_tt->ttm;
+}
+
+static void i915_ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
+{
+	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
+
+	if (i915_tt->cached_st) {
+		dma_unmap_sgtable(i915_tt->dev, i915_tt->cached_st,
+				  DMA_BIDIRECTIONAL, 0);
+		sg_free_table(i915_tt->cached_st);
+		kfree(i915_tt->cached_st);
+		i915_tt->cached_st = NULL;
+	}
+	ttm_pool_free(&bdev->pool, ttm);
+}
+
+static void i915_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
+{
+	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
+
+	ttm_tt_destroy_common(bdev, ttm);
+	kfree(i915_tt);
+}
+
+static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo,
+				       const struct ttm_place *place)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+
+	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
+	if (!i915_gem_object_evictable(obj))
+		return false;
+
+	/* This isn't valid with a buddy allocator */
+	return ttm_bo_eviction_valuable(bo, place);
+}
+
+static void i915_ttm_evict_flags(struct ttm_buffer_object *bo,
+				 struct ttm_placement *placement)
+{
+	*placement = i915_sys_placement;
+}
+
+static int i915_ttm_move_notify(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	int ret;
+
+	ret = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE);
+	if (ret)
+		return ret;
+
+	ret = __i915_gem_object_put_pages(obj);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void i915_ttm_free_cached_io_st(struct drm_i915_gem_object *obj)
+{
+	if (obj->ttm.cached_io_st) {
+		sg_free_table(obj->ttm.cached_io_st);
+		kfree(obj->ttm.cached_io_st);
+		obj->ttm.cached_io_st = NULL;
+	}
+}
+
+static void i915_ttm_purge(struct drm_i915_gem_object *obj)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+
+	if (obj->mm.madv == __I915_MADV_PURGED)
+		return;
+
+	i915_ttm_free_cached_io_st(obj);
+
+	ttm_resource_free(bo, &bo->mem);
+	if (bo->ttm)
+		ttm_bo_tt_destroy(bo);
+
+	obj->mm.madv = __I915_MADV_PURGED;
+}
+
+static bool i915_ttm_swap_possible(struct ttm_buffer_object *bo)
+{
+	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
+	return i915_gem_object_evictable(i915_ttm_to_gem(bo));
+}
+
+static void i915_ttm_swap_notify(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	int ret = i915_ttm_move_notify(bo);
+
+	GEM_WARN_ON(ret);
+	GEM_WARN_ON(obj->ttm.cached_io_st);
+	if (!ret && obj->mm.madv != I915_MADV_WILLNEED)
+		i915_ttm_purge(obj);
+}
+
+static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+
+	if (likely(obj)) {
+		/* This releases all gem object bindings to the backend. */
+		__i915_gem_free_object(obj);
+	}
+}
+
+static struct intel_memory_region *
+i915_ttm_region(struct ttm_device *bdev, int ttm_mem_type)
+{
+	struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
+
+	/* There's some room for optimization here... */
+	GEM_BUG_ON(ttm_mem_type != I915_PL_SYSTEM &&
+		   ttm_mem_type < I915_PL_LMEM0);
+	if (ttm_mem_type == I915_PL_SYSTEM)
+		return intel_memory_region_lookup(i915, INTEL_MEMORY_SYSTEM,
+						  0);
+
+	return intel_memory_region_lookup(i915, INTEL_MEMORY_LOCAL,
+					  ttm_mem_type - I915_PL_LMEM0);
+}
+
+static struct sg_table *i915_ttm_tt_get_st(struct ttm_tt *ttm)
+{
+	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
+	struct scatterlist *sg;
+	struct sg_table *st;
+	int ret;
+
+	if (i915_tt->cached_st)
+		return i915_tt->cached_st;
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	sg = __sg_alloc_table_from_pages
+		(st, ttm->pages, ttm->num_pages, 0,
+		 (unsigned long) ttm->num_pages << PAGE_SHIFT,
+		 i915_sg_segment_size(), NULL, 0, GFP_KERNEL);
+	if (IS_ERR(sg)) {
+		kfree(st);
+		return ERR_CAST(sg);
+	}
+
+	ret = dma_map_sgtable(i915_tt->dev, st, DMA_BIDIRECTIONAL, 0);
+	if (ret) {
+		sg_free_table(st);
+		kfree(st);
+		return ERR_PTR(ret);
+	}
+
+	i915_tt->cached_st = st;
+	return st;
+}
+
+static struct sg_table *
+i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
+			 struct ttm_resource *res)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+	struct ttm_resource_manager *man =
+		ttm_manager_type(bo->bdev, res->mem_type);
+	struct sg_table *st;
+
+	if (man->use_tt)
+		return i915_ttm_tt_get_st(bo->ttm);
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	st = intel_region_ttm_node_to_st(obj->mm.region, res->mm_node);
+	if (IS_ERR(st))
+		return ERR_CAST(st);
+
+	return st;
+}
+
+static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
+			 struct ttm_operation_ctx *ctx,
+			 struct ttm_resource *new_mem,
+			 struct ttm_place *hop)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	struct ttm_resource_manager *new_man =
+		ttm_manager_type(bo->bdev, new_mem->mem_type);
+	struct ttm_resource_manager *old_man =
+		ttm_manager_type(bo->bdev, bo->mem.mem_type);
+	struct intel_memory_region *new_reg, *old_reg;
+	union {
+		struct i915_ttm_kmap_iter_tt tt;
+		struct i915_ttm_kmap_iter_iomap io;
+	} _new_iter, _old_iter;
+	struct i915_ttm_kmap_iter *new_iter, *old_iter;
+	struct sg_table *new_st;
+	int ret;
+
+	new_reg = i915_ttm_region(bo->bdev, new_mem->mem_type);
+	old_reg = i915_ttm_region(bo->bdev, bo->mem.mem_type);
+	GEM_BUG_ON(!new_reg || !old_reg);
+
+	/* Sync for now. We could do the actual copy async. */
+	ret = ttm_bo_wait_ctx(bo, ctx);
+	if (ret)
+		return ret;
+
+	ret = i915_ttm_move_notify(bo);
+	if (ret)
+		return ret;
+
+	if (obj->mm.madv != I915_MADV_WILLNEED) {
+		i915_ttm_purge(obj);
+		ttm_resource_free(bo, new_mem);
+		return 0;
+	}
+
+	/* Populate ttm with pages if needed. Typically system memory. */
+	if (new_man->use_tt && bo->ttm) {
+		ret = ttm_tt_populate(bo->bdev, bo->ttm, ctx);
+		if (ret)
+			return ret;
+	}
+
+	new_st = i915_ttm_resource_get_st(obj, new_mem);
+	if (IS_ERR(new_st))
+		return PTR_ERR(new_st);
+
+	new_iter = new_man->use_tt ?
+		i915_ttm_kmap_iter_tt_init(&_new_iter.tt, bo->ttm) :
+		i915_ttm_kmap_iter_iomap_init(&_new_iter.io, &new_reg->iomap,
+					      new_st, new_reg->region.start);
+
+	old_iter = old_man->use_tt ?
+		i915_ttm_kmap_iter_tt_init(&_old_iter.tt, bo->ttm) :
+		i915_ttm_kmap_iter_iomap_init(&_old_iter.io, &old_reg->iomap,
+					      obj->ttm.cached_io_st,
+					      old_reg->region.start);
+
+	i915_ttm_move_memcpy(bo, new_mem, new_iter, old_iter);
+	i915_ttm_free_cached_io_st(obj);
+
+	if (!new_man->use_tt)
+		obj->ttm.cached_io_st = new_st;
+
+	return 0;
+}
+
+struct ttm_device_funcs i915_ttm_bo_driver = {
+	.ttm_tt_create = i915_ttm_tt_create,
+	.ttm_tt_unpopulate = i915_ttm_tt_unpopulate,
+	.ttm_tt_destroy = i915_ttm_tt_destroy,
+	.eviction_valuable = i915_ttm_eviction_valuable,
+	.evict_flags = i915_ttm_evict_flags,
+	.move = i915_ttm_move,
+	.verify_access = NULL,
+	.swap_possible = i915_ttm_swap_possible,
+	.swap_notify = i915_ttm_swap_notify,
+	.delete_mem_notify = i915_ttm_delete_mem_notify,
+};
+
+static int i915_ttm_get_pages(struct drm_i915_gem_object *obj)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+	struct ttm_operation_ctx ctx = {
+		.interruptible = true,
+		.no_wait_gpu = false,
+	};
+	struct sg_table *st;
+	int ret;
+
+	/* Swap in. */
+	if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
+		ret = ttm_tt_populate(bo->bdev, bo->ttm, &ctx);
+		if (ret)
+			return ret;
+	}
+
+	/* Move to the requested placement. */
+	ret = ttm_bo_validate(bo, &i915_lmem0_placement, &ctx);
+	if (ret)
+		return ret;
+
+	/* Object either has a page vector or is an iomem object */
+	st = bo->ttm ? i915_ttm_tt_get_st(bo->ttm) : obj->ttm.cached_io_st;
+	if (IS_ERR(st))
+		return PTR_ERR(st);
+
+	__i915_gem_object_set_pages(obj, st, i915_sg_dma_page_sizes(st->sgl));
+
+	i915_ttm_adjust_lru(obj);
+
+	return ret;
+}
+
+static void i915_ttm_put_pages(struct drm_i915_gem_object *obj,
+			       struct sg_table *st)
+{
+	/*
+	 * We're currently not called from a shrinker, so put_pages()
+	 * typically means the object is about to destroyed, or called
+	 * from move_notify(). So just avoid doing much for now.
+	 * If the object is not destroyed next, The TTM eviction logic
+	 * and shrinkers will move it out if needed.
+	 */
+
+	i915_ttm_adjust_lru(obj);
+}
+
+static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+
+	/*
+	 * Don't manipulate the TTM LRUs while in TTM bo destruction.
+	 * We're called through i915_ttm_delete_mem_notify().
+	 */
+	if (!kref_read(&bo->kref))
+		return;
+
+	/*
+	 * Put on the correct LRU list depending on the MADV status
+	 */
+	spin_lock(&bo->bdev->lru_lock);
+	if (obj->mm.madv != I915_MADV_WILLNEED) {
+		bo->priority = I915_TTM_PRIO_PURGE;
+	} else if (!i915_gem_object_has_pages(obj)) {
+		if (bo->priority < I915_TTM_PRIO_HAS_PAGES)
+			bo->priority = I915_TTM_PRIO_HAS_PAGES;
+	} else {
+		if (bo->priority > I915_TTM_PRIO_NO_PAGES)
+			bo->priority = I915_TTM_PRIO_NO_PAGES;
+	}
+
+	ttm_bo_move_to_lru_tail(bo, &bo->mem, NULL);
+	spin_unlock(&bo->bdev->lru_lock);
+}
+
+/*
+ * TTM-backed gem object destruction requires some clarification.
+ * Basically we have two possibilities here. We can either rely on the
+ * i915 delayed destruction and put the TTM object when the object
+ * is idle. This would be detected by TTM which would bypass the
+ * TTM delayed destroy handling. The other approach is to put the TTM
+ * object early and rely on the TTM destroyed handling, and then free
+ * the leftover parts of the GEM object once TTM's destroyed list handling is
+ * complete. For now, we rely on the latter for two reasons:
+ * a) TTM can evict an object even when it's on the delayed destroy list,
+ * which in theory allows for complete eviction.
+ * b) There is work going on in TTM to allow freeing an object even when
+ * it's not idle, and using the TTM destroyed list handling could help us
+ * benefit from that.
+ */
+static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj)
+{
+	ttm_bo_put(i915_gem_to_ttm(obj));
+}
+
+static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = {
+	.name = "i915_gem_object_ttm",
+	.flags = I915_GEM_OBJECT_HAS_IOMEM,
+
+	.get_pages = i915_ttm_get_pages,
+	.put_pages = i915_ttm_put_pages,
+	.truncate = i915_ttm_purge,
+	.adjust_lru = i915_ttm_adjust_lru,
+	.delayed_free = i915_ttm_delayed_free,
+};
+
+void i915_ttm_bo_destroy(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+
+	i915_gem_object_release_memory_region(obj);
+	call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
+}
+
+/**
+ * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
+ * @mem: The initial memory region for the object.
+ * @obj: The gem object.
+ * @size: Object size in bytes.
+ * @flags: gem object flags.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
+			       struct drm_i915_gem_object *obj,
+			       resource_size_t size,
+			       unsigned int flags)
+{
+	static struct lock_class_key lock_class;
+	struct drm_i915_private *i915 = mem->i915;
+	size_t alignment = 0;
+	int ret;
+
+	/* Adjust alignment to GPU- and CPU huge page sizes. */
+
+	if (mem->is_range_manager) {
+		if (size >= SZ_1G)
+			alignment = SZ_1G >> PAGE_SHIFT;
+		else if (size >= SZ_2M)
+			alignment = SZ_2M >> PAGE_SHIFT;
+		else if (size >= SZ_64K)
+			alignment = SZ_64K >> PAGE_SHIFT;
+	}
+
+	drm_gem_private_object_init(&i915->drm, &obj->base, size);
+	i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
+	i915_gem_object_init_memory_region(obj, mem);
+	i915_gem_object_make_unshrinkable(obj);
+
+	ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
+			  ttm_bo_type_kernel, &i915_sys_placement, alignment,
+			  true, NULL, NULL, i915_ttm_bo_destroy);
+
+	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
+
+	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
new file mode 100644
index 000000000000..b8d3dcbb50df
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+#ifndef _I915_GEM_TTM_H_
+#define _I915_GEM_TTM_H_
+
+#include "gem/i915_gem_object_types.h"
+
+/**
+ * i915_gem_to_ttm - Convert a struct drm_i915_gem_object to a
+ * struct ttm_buffer_object.
+ * @obj: Pointer to the gem object.
+ *
+ * Return: Pointer to the embedded struct ttm_buffer_object.
+ */
+static inline struct ttm_buffer_object *
+i915_gem_to_ttm(struct drm_i915_gem_object *obj)
+{
+	return &obj->__do_not_access;
+}
+
+/*
+ * i915 ttm gem object destructor. Internal use only.
+ */
+void i915_ttm_bo_destroy(struct ttm_buffer_object *bo);
+
+/**
+ * i915_ttm_to_gem - Convert a struct ttm_buffer_object to an embedding
+ * struct drm_i915_gem_object.
+ *
+ * Return: Pointer to the embedding struct ttm_buffer_object, or NULL
+ * if the object was not an i915 ttm object.
+ */
+static inline struct drm_i915_gem_object *
+i915_ttm_to_gem(struct ttm_buffer_object *bo)
+{
+	if (GEM_WARN_ON(bo->destroy != i915_ttm_bo_destroy))
+		return NULL;
+
+	return container_of(bo, struct drm_i915_gem_object, __do_not_access);
+}
+
+int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
+			       struct drm_i915_gem_object *obj,
+			       resource_size_t size,
+			       unsigned int flags);
+#endif
diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
index f7366b054f8e..4ae1f717a94c 100644
--- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c
+++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
@@ -9,6 +9,7 @@
 #include "intel_region_ttm.h"
 #include "gem/i915_gem_lmem.h"
 #include "gem/i915_gem_region.h"
+#include "gem/i915_gem_ttm.h"
 #include "intel_region_lmem.h"
 
 static int init_fake_lmem_bar(struct intel_memory_region *mem)
@@ -107,7 +108,7 @@ region_lmem_init(struct intel_memory_region *mem)
 static const struct intel_memory_region_ops intel_region_lmem_ops = {
 	.init = region_lmem_init,
 	.release = region_lmem_release,
-	.init_object = __i915_gem_lmem_object_init,
+	.init_object = __i915_gem_ttm_object_init,
 };
 
 struct intel_memory_region *
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 180f6e9107d4..350283ab9a83 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1005,8 +1005,11 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
 		}
 	}
 
-	if (obj->mm.madv != __I915_MADV_PURGED)
+	if (obj->mm.madv != __I915_MADV_PURGED) {
 		obj->mm.madv = args->madv;
+		if (obj->ops->adjust_lru)
+			obj->ops->adjust_lru(obj);
+	}
 
 	if (i915_gem_object_has_pages(obj)) {
 		struct list_head *list;
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index 4092cc987679..bd27e897d4d0 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -149,7 +149,6 @@ intel_memory_region_create(struct drm_i915_private *i915,
 
 	mutex_init(&mem->objects.lock);
 	INIT_LIST_HEAD(&mem->objects.list);
-	INIT_LIST_HEAD(&mem->objects.purgeable);
 	INIT_LIST_HEAD(&mem->reserved);
 
 	mutex_init(&mem->mm_lock);
diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
index e69cde13daf2..7b5fa97c0b59 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.h
+++ b/drivers/gpu/drm/i915/intel_memory_region.h
@@ -100,7 +100,6 @@ struct intel_memory_region {
 	struct {
 		struct mutex lock; /* Protects access to objects */
 		struct list_head list;
-		struct list_head purgeable;
 	} objects;
 
 	size_t chunk_size;
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
index 3bd9caa60298..a74cae4602b5 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.c
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -10,8 +10,7 @@
 
 #include "intel_region_ttm.h"
 
-/* A Zero-initialized driver for now. We don't have a TTM backend yet. */
-static struct ttm_device_funcs i915_ttm_bo_driver;
+extern struct ttm_device_funcs i915_ttm_bo_driver;
 
 /**
  * DOC: TTM support structure
@@ -198,6 +197,7 @@ struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
 	return i915_sg_from_mm_node(node, mem->region.start);
 }
 
+#ifdef CONFIG_DRM_I915_SELFTEST
 /**
  * intel_region_ttm_node_alloc - Allocate memory resources from a region
  * @mem: The memory region,
@@ -244,3 +244,4 @@ void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
 		ret = -ENXIO;
 	return ret ? ERR_PTR(ret) : res.mm_node;
 }
+#endif
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
index 40129f7e0317..9a5b0437d73f 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.h
+++ b/drivers/gpu/drm/i915/intel_region_ttm.h
@@ -21,9 +21,12 @@ void intel_region_ttm_fini(struct intel_memory_region *mem);
 struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
 					     void *node);
 
+void intel_region_ttm_node_free(struct intel_memory_region *mem,
+				void *node);
+
+#ifdef CONFIG_DRM_I915_SELFTEST
 void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
 				  resource_size_t size,
 				  unsigned int flags);
-void intel_region_ttm_node_free(struct intel_memory_region *mem,
-				void *node);
+#endif
 #endif /* _INTEL_REGION_TTM_H_ */
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 4479c55aaa1d..74004d5cbfa2 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1150,6 +1150,14 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
 		return -EBUSY;
 	}
 
+	if (bo->bdev->funcs->swap_possible) {
+		if (!bo->bdev->funcs->swap_possible(bo)) {
+			if (locked)
+				dma_resv_unlock(bo->base.resv);
+			return -EBUSY;
+		}
+	}
+
 	if (bo->deleted) {
 		ttm_bo_cleanup_refs(bo, false, false, locked);
 		ttm_bo_put(bo);
@@ -1200,6 +1208,10 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
 	if (bo->bdev->funcs->swap_notify)
 		bo->bdev->funcs->swap_notify(bo);
 
+	/* The call to swap_notify may have purged the bo */
+	if (!bo->ttm)
+		goto out;
+
 	ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags);
 out:
 
diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h
index 7c8f87bd52d3..7c59d35e90f9 100644
--- a/include/drm/ttm/ttm_device.h
+++ b/include/drm/ttm/ttm_device.h
@@ -181,6 +181,15 @@ struct ttm_device_funcs {
 	 */
 	void (*delete_mem_notify)(struct ttm_buffer_object *bo);
 
+	/**
+	 * struct ttm_bo_driver member swap_possible
+	 *
+	 * @bo: the buffer object to be evicted
+	 *
+	 * Check with the driver if it is possible to swap out a BO.
+	 */
+	bool (*swap_possible)(struct ttm_buffer_object *bo);
+
 	/**
 	 * notify the driver that we're about to swap out this bo
 	 */
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-11 13:25   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström, Christian König

Most logical place to introduce TTM buffer objects is as an i915
gem object backend. We need to add some ops to account for added
functionality like delayed delete and LRU list manipulation.

Initially we support only LMEM and SYSTEM memory, but SYSTEM
(which in this case means evicted LMEM objects) is not
visible to i915 GEM yet. The plan is to move the i915 gem system region
over to the TTM system memory type in upcoming patches.

We set up GPU bindings directly both from LMEM and from the system region,
as there is no need to use the legacy TTM_TT memory type. We reserve
that for future porting of GGTT bindings to TTM.

There are some changes to TTM to allow for purging system memory buffer
objects and to refuse swapping of some objects: Unfortunately i915 gem
still relies heavily on short-term object pinning, and we've chosen to
keep short-term-pinned buffer objects on the TTM LRU lists for now,
meaning that we need some sort of mechanism to tell TTM they are not
swappable. A longer term goal is to get rid of the short-term pinning.

Remove the old lmem backend.

Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
 drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
 drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
 drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
 .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
 drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
 drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
 drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
 drivers/gpu/drm/i915/i915_gem.c               |   5 +-
 drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
 drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
 drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
 drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
 drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
 include/drm/ttm/ttm_device.h                  |   9 +
 17 files changed, 733 insertions(+), 140 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
 create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 958ccc1edfed..ef0d884a9e2d 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -155,6 +155,7 @@ gem-y += \
 	gem/i915_gem_stolen.o \
 	gem/i915_gem_throttle.o \
 	gem/i915_gem_tiling.o \
+	gem/i915_gem_ttm.o \
 	gem/i915_gem_ttm_bo_util.o \
 	gem/i915_gem_userptr.o \
 	gem/i915_gem_wait.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
index f42803ea48f2..2b8cd15de1d9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
@@ -4,73 +4,10 @@
  */
 
 #include "intel_memory_region.h"
-#include "intel_region_ttm.h"
 #include "gem/i915_gem_region.h"
 #include "gem/i915_gem_lmem.h"
 #include "i915_drv.h"
 
-static void lmem_put_pages(struct drm_i915_gem_object *obj,
-				  struct sg_table *pages)
-{
-	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
-	obj->mm.dirty = false;
-	sg_free_table(pages);
-	kfree(pages);
-}
-
-static int lmem_get_pages(struct drm_i915_gem_object *obj)
-{
-	unsigned int flags;
-	struct sg_table *pages;
-
-	flags = I915_ALLOC_MIN_PAGE_SIZE;
-	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
-		flags |= I915_ALLOC_CONTIGUOUS;
-
-	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
-							 obj->base.size,
-							 flags);
-	if (IS_ERR(obj->mm.st_mm_node))
-		return PTR_ERR(obj->mm.st_mm_node);
-
-	/* Range manager is always contigous */
-	if (obj->mm.region->is_range_manager)
-		obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
-	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
-	if (IS_ERR(pages))
-		return PTR_ERR(pages);
-
-	__i915_gem_object_set_pages(obj, pages,
-				    i915_sg_dma_page_sizes(pages->sgl));
-
-	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
-		void __iomem *vaddr =
-			i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
-
-		if (!vaddr) {
-			struct sg_table *pages =
-				__i915_gem_object_unset_pages(obj);
-
-			if (!IS_ERR_OR_NULL(pages))
-				lmem_put_pages(obj, pages);
-		}
-
-		memset_io(vaddr, 0, obj->base.size);
-		io_mapping_unmap(vaddr);
-	}
-
-	return 0;
-}
-
-const struct drm_i915_gem_object_ops i915_gem_lmem_obj_ops = {
-	.name = "i915_gem_object_lmem",
-	.flags = I915_GEM_OBJECT_HAS_IOMEM,
-
-	.get_pages = lmem_get_pages,
-	.put_pages = lmem_put_pages,
-	.release = i915_gem_object_release_memory_region,
-};
-
 void __iomem *
 i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
 			    unsigned long n,
@@ -102,23 +39,3 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
 	return i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_LMEM],
 					     size, flags);
 }
-
-int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
-				struct drm_i915_gem_object *obj,
-				resource_size_t size,
-				unsigned int flags)
-{
-	static struct lock_class_key lock_class;
-	struct drm_i915_private *i915 = mem->i915;
-
-	drm_gem_private_object_init(&i915->drm, &obj->base, size);
-	i915_gem_object_init(obj, &i915_gem_lmem_obj_ops, &lock_class, flags);
-
-	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
-
-	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
-
-	i915_gem_object_init_memory_region(obj, mem);
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
index fac6bc5a5ebb..ea76fd11ccb0 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
@@ -26,9 +26,4 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
 			    resource_size_t size,
 			    unsigned int flags);
 
-int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
-				struct drm_i915_gem_object *obj,
-				resource_size_t size,
-				unsigned int flags);
-
 #endif /* !__I915_GEM_LMEM_H */
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index c8953e3f5c70..c53488f391dd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -172,7 +172,7 @@ static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *f
 	}
 }
 
-static void __i915_gem_free_object_rcu(struct rcu_head *head)
+void __i915_gem_free_object_rcu(struct rcu_head *head)
 {
 	struct drm_i915_gem_object *obj =
 		container_of(head, typeof(*obj), rcu);
@@ -208,59 +208,70 @@ static void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj)
 	}
 }
 
-static void __i915_gem_free_objects(struct drm_i915_private *i915,
-				    struct llist_node *freed)
+void __i915_gem_free_object(struct drm_i915_gem_object *obj)
 {
-	struct drm_i915_gem_object *obj, *on;
+	trace_i915_gem_object_destroy(obj);
 
-	llist_for_each_entry_safe(obj, on, freed, freed) {
-		trace_i915_gem_object_destroy(obj);
+	if (!list_empty(&obj->vma.list)) {
+		struct i915_vma *vma;
+
+		/*
+		 * Note that the vma keeps an object reference while
+		 * it is active, so it *should* not sleep while we
+		 * destroy it. Our debug code errs insits it *might*.
+		 * For the moment, play along.
+		 */
+		spin_lock(&obj->vma.lock);
+		while ((vma = list_first_entry_or_null(&obj->vma.list,
+						       struct i915_vma,
+						       obj_link))) {
+			GEM_BUG_ON(vma->obj != obj);
+			spin_unlock(&obj->vma.lock);
 
-		if (!list_empty(&obj->vma.list)) {
-			struct i915_vma *vma;
+			__i915_vma_put(vma);
 
-			/*
-			 * Note that the vma keeps an object reference while
-			 * it is active, so it *should* not sleep while we
-			 * destroy it. Our debug code errs insits it *might*.
-			 * For the moment, play along.
-			 */
 			spin_lock(&obj->vma.lock);
-			while ((vma = list_first_entry_or_null(&obj->vma.list,
-							       struct i915_vma,
-							       obj_link))) {
-				GEM_BUG_ON(vma->obj != obj);
-				spin_unlock(&obj->vma.lock);
+		}
+		spin_unlock(&obj->vma.lock);
+	}
 
-				__i915_vma_put(vma);
+	__i915_gem_object_free_mmaps(obj);
 
-				spin_lock(&obj->vma.lock);
-			}
-			spin_unlock(&obj->vma.lock);
-		}
+	GEM_BUG_ON(!list_empty(&obj->lut_list));
 
-		__i915_gem_object_free_mmaps(obj);
+	atomic_set(&obj->mm.pages_pin_count, 0);
+	__i915_gem_object_put_pages(obj);
+	GEM_BUG_ON(i915_gem_object_has_pages(obj));
+	bitmap_free(obj->bit_17);
 
-		GEM_BUG_ON(!list_empty(&obj->lut_list));
+	if (obj->base.import_attach)
+		drm_prime_gem_destroy(&obj->base, NULL);
 
-		atomic_set(&obj->mm.pages_pin_count, 0);
-		__i915_gem_object_put_pages(obj);
-		GEM_BUG_ON(i915_gem_object_has_pages(obj));
-		bitmap_free(obj->bit_17);
+	drm_gem_free_mmap_offset(&obj->base);
 
-		if (obj->base.import_attach)
-			drm_prime_gem_destroy(&obj->base, NULL);
+	if (obj->ops->release)
+		obj->ops->release(obj);
 
-		drm_gem_free_mmap_offset(&obj->base);
+	if (obj->mm.n_placements > 1)
+		kfree(obj->mm.placements);
 
-		if (obj->ops->release)
-			obj->ops->release(obj);
+	if (obj->resv_shared_from)
+		i915_vm_resv_put(obj->resv_shared_from);
 
-		if (obj->mm.n_placements > 1)
-			kfree(obj->mm.placements);
+}
+
+static void __i915_gem_free_objects(struct drm_i915_private *i915,
+				    struct llist_node *freed)
+{
+	struct drm_i915_gem_object *obj, *on;
 
-		if (obj->resv_shared_from)
-			i915_vm_resv_put(obj->resv_shared_from);
+	llist_for_each_entry_safe(obj, on, freed, freed) {
+		might_sleep();
+		if (obj->ops->delayed_free) {
+			obj->ops->delayed_free(obj);
+			continue;
+		}
+		__i915_gem_free_object(obj);
 
 		/* But keep the pointer alive for RCU-protected lookups */
 		call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
@@ -318,6 +329,7 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj)
 	 * worker and performing frees directly from subsequent allocations for
 	 * crude but effective memory throttling.
 	 */
+
 	if (llist_add(&obj->freed, &i915->mm.free_list))
 		queue_work(i915->wq, &i915->mm.free_work);
 }
@@ -410,6 +422,42 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
 	return 0;
 }
 
+/**
+ * i915_gem_object_evictable - Whether object is likely evictable after unbind.
+ * @obj: The object to check
+ *
+ * This function checks whether the object is likely unvictable after unbind.
+ * If the object is not locked when checking, the result is only advisory.
+ * If the object is locked when checking, and the function returns true,
+ * then an eviction should indeed be possible. But since unlocked vma
+ * unpinning and unbinding is currently possible, the object can actually
+ * become evictable even if this function returns false.
+ *
+ * Return: true if the object may be evictable. False otherwise.
+ */
+bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
+{
+	struct i915_vma *vma;
+	int pin_count = atomic_read(&obj->mm.pages_pin_count);
+
+	if (!pin_count)
+		return true;
+
+	spin_lock(&obj->vma.lock);
+	list_for_each_entry(vma, &obj->vma.list, obj_link) {
+		if (i915_vma_is_pinned(vma)) {
+			spin_unlock(&obj->vma.lock);
+			return false;
+		}
+		if (atomic_read(&vma->pages_count))
+			pin_count--;
+	}
+	spin_unlock(&obj->vma.lock);
+	GEM_WARN_ON(pin_count < 0);
+
+	return pin_count == 0;
+}
+
 void i915_gem_init__objects(struct drm_i915_private *i915)
 {
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index 2ebd79537aea..ae5930e307d5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -200,6 +200,9 @@ static inline bool i915_gem_object_trylock(struct drm_i915_gem_object *obj)
 
 static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj)
 {
+	if (obj->ops->adjust_lru)
+		obj->ops->adjust_lru(obj);
+
 	dma_resv_unlock(obj->base.resv);
 }
 
@@ -587,6 +590,12 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
 
 bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj);
 
+void __i915_gem_free_object_rcu(struct rcu_head *head);
+
+void __i915_gem_free_object(struct drm_i915_gem_object *obj);
+
+bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
+
 #ifdef CONFIG_MMU_NOTIFIER
 static inline bool
 i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
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 98f69d8fd37d..b350765e1935 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -63,6 +63,20 @@ struct drm_i915_gem_object_ops {
 		      const struct drm_i915_gem_pwrite *arg);
 
 	int (*dmabuf_export)(struct drm_i915_gem_object *obj);
+
+	/**
+	 * adjust_lru - notify that the madvise value was updated
+	 * @obj: The gem object
+	 *
+	 * The madvise value may have been updated, or object was recently
+	 * referenced so act accordingly (Perhaps changing an LRU list etc).
+	 */
+	void (*adjust_lru)(struct drm_i915_gem_object *obj);
+
+	/**
+	 * delayed_free - Override the default delayed free implementation
+	 */
+	void (*delayed_free)(struct drm_i915_gem_object *obj);
 	void (*release)(struct drm_i915_gem_object *obj);
 
 	const char *name; /* friendly name for debug, e.g. lockdep classes */
@@ -307,6 +321,10 @@ struct drm_i915_gem_object {
 		bool dirty:1;
 	} mm;
 
+	struct {
+		struct sg_table *cached_io_st;
+	} ttm;
+
 	/** Record of address bit 17 of each page at last unbind. */
 	unsigned long *bit_17;
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
index f25e6646c5b7..d1f1840540dd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
@@ -18,11 +18,7 @@ void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
 
 	mutex_lock(&mem->objects.lock);
 
-	if (obj->flags & I915_BO_ALLOC_VOLATILE)
-		list_add(&obj->mm.region_link, &mem->objects.purgeable);
-	else
-		list_add(&obj->mm.region_link, &mem->objects.list);
-
+	list_add(&obj->mm.region_link, &mem->objects.list);
 	mutex_unlock(&mem->objects.lock);
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
new file mode 100644
index 000000000000..e3718c3cb299
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_placement.h>
+
+#include "i915_drv.h"
+#include "intel_memory_region.h"
+#include "intel_region_ttm.h"
+
+#include "gem/i915_gem_object.h"
+#include "gem/i915_gem_region.h"
+#include "gem/i915_gem_ttm.h"
+#include "gem/i915_gem_ttm_bo_util.h"
+
+#define I915_PL_LMEM0 TTM_PL_PRIV
+#define I915_PL_SYSTEM TTM_PL_SYSTEM
+#define I915_PL_STOLEN TTM_PL_VRAM
+#define I915_PL_GGTT TTM_PL_TT
+
+#define I915_TTM_PRIO_PURGE     0
+#define I915_TTM_PRIO_NO_PAGES  1
+#define I915_TTM_PRIO_HAS_PAGES 2
+
+/**
+ * struct i915_ttm_tt - TTM page vector with additional private information
+ * @ttm: The base TTM page vector.
+ * @dev: The struct device used for dma mapping and unmapping.
+ * @cached_st: The cached scatter-gather table.
+ *
+ * Note that DMA may be going on right up to the point where the page-
+ * vector is unpopulated in delayed destroy. Hence keep the
+ * scatter-gather table mapped and cached up to that point. This is
+ * different from the cached gem object io scatter-gather table which
+ * doesn't have an associated dma mapping.
+ */
+struct i915_ttm_tt {
+	struct ttm_tt ttm;
+	struct device *dev;
+	struct sg_table *cached_st;
+};
+
+static const struct ttm_place lmem0_sys_placement_flags[] = {
+	{
+		.fpfn = 0,
+		.lpfn = 0,
+		.mem_type = I915_PL_LMEM0,
+		.flags = 0,
+	}, {
+		.fpfn = 0,
+		.lpfn = 0,
+		.mem_type = I915_PL_SYSTEM,
+		.flags = 0,
+	}
+};
+
+struct ttm_placement i915_lmem0_placement = {
+	.num_placement = 1,
+	.placement = &lmem0_sys_placement_flags[0],
+	.num_busy_placement = 1,
+	.busy_placement = &lmem0_sys_placement_flags[0],
+};
+
+struct ttm_placement i915_lmem0_sys_placement = {
+	.num_placement = 1,
+	.placement = &lmem0_sys_placement_flags[0],
+	.num_busy_placement = 2,
+	.busy_placement = &lmem0_sys_placement_flags[0],
+};
+
+struct ttm_placement i915_sys_placement = {
+	.num_placement = 1,
+	.placement = &lmem0_sys_placement_flags[1],
+	.num_busy_placement = 1,
+	.busy_placement = &lmem0_sys_placement_flags[1],
+};
+
+static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj);
+
+static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
+					 uint32_t page_flags)
+{
+	struct ttm_resource_manager *man =
+		ttm_manager_type(bo->bdev, bo->mem.mem_type);
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	struct i915_ttm_tt *i915_tt;
+	int ret;
+
+	i915_tt = kzalloc(sizeof(*i915_tt), GFP_KERNEL);
+	if (!i915_tt)
+		return NULL;
+
+	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR &&
+	    man->use_tt)
+		page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC;
+
+	ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, ttm_cached);
+	if (ret) {
+		kfree(i915_tt);
+		return NULL;
+	}
+
+	i915_tt->dev = obj->base.dev->dev;
+
+	return &i915_tt->ttm;
+}
+
+static void i915_ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
+{
+	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
+
+	if (i915_tt->cached_st) {
+		dma_unmap_sgtable(i915_tt->dev, i915_tt->cached_st,
+				  DMA_BIDIRECTIONAL, 0);
+		sg_free_table(i915_tt->cached_st);
+		kfree(i915_tt->cached_st);
+		i915_tt->cached_st = NULL;
+	}
+	ttm_pool_free(&bdev->pool, ttm);
+}
+
+static void i915_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
+{
+	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
+
+	ttm_tt_destroy_common(bdev, ttm);
+	kfree(i915_tt);
+}
+
+static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo,
+				       const struct ttm_place *place)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+
+	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
+	if (!i915_gem_object_evictable(obj))
+		return false;
+
+	/* This isn't valid with a buddy allocator */
+	return ttm_bo_eviction_valuable(bo, place);
+}
+
+static void i915_ttm_evict_flags(struct ttm_buffer_object *bo,
+				 struct ttm_placement *placement)
+{
+	*placement = i915_sys_placement;
+}
+
+static int i915_ttm_move_notify(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	int ret;
+
+	ret = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE);
+	if (ret)
+		return ret;
+
+	ret = __i915_gem_object_put_pages(obj);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void i915_ttm_free_cached_io_st(struct drm_i915_gem_object *obj)
+{
+	if (obj->ttm.cached_io_st) {
+		sg_free_table(obj->ttm.cached_io_st);
+		kfree(obj->ttm.cached_io_st);
+		obj->ttm.cached_io_st = NULL;
+	}
+}
+
+static void i915_ttm_purge(struct drm_i915_gem_object *obj)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+
+	if (obj->mm.madv == __I915_MADV_PURGED)
+		return;
+
+	i915_ttm_free_cached_io_st(obj);
+
+	ttm_resource_free(bo, &bo->mem);
+	if (bo->ttm)
+		ttm_bo_tt_destroy(bo);
+
+	obj->mm.madv = __I915_MADV_PURGED;
+}
+
+static bool i915_ttm_swap_possible(struct ttm_buffer_object *bo)
+{
+	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
+	return i915_gem_object_evictable(i915_ttm_to_gem(bo));
+}
+
+static void i915_ttm_swap_notify(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	int ret = i915_ttm_move_notify(bo);
+
+	GEM_WARN_ON(ret);
+	GEM_WARN_ON(obj->ttm.cached_io_st);
+	if (!ret && obj->mm.madv != I915_MADV_WILLNEED)
+		i915_ttm_purge(obj);
+}
+
+static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+
+	if (likely(obj)) {
+		/* This releases all gem object bindings to the backend. */
+		__i915_gem_free_object(obj);
+	}
+}
+
+static struct intel_memory_region *
+i915_ttm_region(struct ttm_device *bdev, int ttm_mem_type)
+{
+	struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
+
+	/* There's some room for optimization here... */
+	GEM_BUG_ON(ttm_mem_type != I915_PL_SYSTEM &&
+		   ttm_mem_type < I915_PL_LMEM0);
+	if (ttm_mem_type == I915_PL_SYSTEM)
+		return intel_memory_region_lookup(i915, INTEL_MEMORY_SYSTEM,
+						  0);
+
+	return intel_memory_region_lookup(i915, INTEL_MEMORY_LOCAL,
+					  ttm_mem_type - I915_PL_LMEM0);
+}
+
+static struct sg_table *i915_ttm_tt_get_st(struct ttm_tt *ttm)
+{
+	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
+	struct scatterlist *sg;
+	struct sg_table *st;
+	int ret;
+
+	if (i915_tt->cached_st)
+		return i915_tt->cached_st;
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	sg = __sg_alloc_table_from_pages
+		(st, ttm->pages, ttm->num_pages, 0,
+		 (unsigned long) ttm->num_pages << PAGE_SHIFT,
+		 i915_sg_segment_size(), NULL, 0, GFP_KERNEL);
+	if (IS_ERR(sg)) {
+		kfree(st);
+		return ERR_CAST(sg);
+	}
+
+	ret = dma_map_sgtable(i915_tt->dev, st, DMA_BIDIRECTIONAL, 0);
+	if (ret) {
+		sg_free_table(st);
+		kfree(st);
+		return ERR_PTR(ret);
+	}
+
+	i915_tt->cached_st = st;
+	return st;
+}
+
+static struct sg_table *
+i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
+			 struct ttm_resource *res)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+	struct ttm_resource_manager *man =
+		ttm_manager_type(bo->bdev, res->mem_type);
+	struct sg_table *st;
+
+	if (man->use_tt)
+		return i915_ttm_tt_get_st(bo->ttm);
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	st = intel_region_ttm_node_to_st(obj->mm.region, res->mm_node);
+	if (IS_ERR(st))
+		return ERR_CAST(st);
+
+	return st;
+}
+
+static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
+			 struct ttm_operation_ctx *ctx,
+			 struct ttm_resource *new_mem,
+			 struct ttm_place *hop)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+	struct ttm_resource_manager *new_man =
+		ttm_manager_type(bo->bdev, new_mem->mem_type);
+	struct ttm_resource_manager *old_man =
+		ttm_manager_type(bo->bdev, bo->mem.mem_type);
+	struct intel_memory_region *new_reg, *old_reg;
+	union {
+		struct i915_ttm_kmap_iter_tt tt;
+		struct i915_ttm_kmap_iter_iomap io;
+	} _new_iter, _old_iter;
+	struct i915_ttm_kmap_iter *new_iter, *old_iter;
+	struct sg_table *new_st;
+	int ret;
+
+	new_reg = i915_ttm_region(bo->bdev, new_mem->mem_type);
+	old_reg = i915_ttm_region(bo->bdev, bo->mem.mem_type);
+	GEM_BUG_ON(!new_reg || !old_reg);
+
+	/* Sync for now. We could do the actual copy async. */
+	ret = ttm_bo_wait_ctx(bo, ctx);
+	if (ret)
+		return ret;
+
+	ret = i915_ttm_move_notify(bo);
+	if (ret)
+		return ret;
+
+	if (obj->mm.madv != I915_MADV_WILLNEED) {
+		i915_ttm_purge(obj);
+		ttm_resource_free(bo, new_mem);
+		return 0;
+	}
+
+	/* Populate ttm with pages if needed. Typically system memory. */
+	if (new_man->use_tt && bo->ttm) {
+		ret = ttm_tt_populate(bo->bdev, bo->ttm, ctx);
+		if (ret)
+			return ret;
+	}
+
+	new_st = i915_ttm_resource_get_st(obj, new_mem);
+	if (IS_ERR(new_st))
+		return PTR_ERR(new_st);
+
+	new_iter = new_man->use_tt ?
+		i915_ttm_kmap_iter_tt_init(&_new_iter.tt, bo->ttm) :
+		i915_ttm_kmap_iter_iomap_init(&_new_iter.io, &new_reg->iomap,
+					      new_st, new_reg->region.start);
+
+	old_iter = old_man->use_tt ?
+		i915_ttm_kmap_iter_tt_init(&_old_iter.tt, bo->ttm) :
+		i915_ttm_kmap_iter_iomap_init(&_old_iter.io, &old_reg->iomap,
+					      obj->ttm.cached_io_st,
+					      old_reg->region.start);
+
+	i915_ttm_move_memcpy(bo, new_mem, new_iter, old_iter);
+	i915_ttm_free_cached_io_st(obj);
+
+	if (!new_man->use_tt)
+		obj->ttm.cached_io_st = new_st;
+
+	return 0;
+}
+
+struct ttm_device_funcs i915_ttm_bo_driver = {
+	.ttm_tt_create = i915_ttm_tt_create,
+	.ttm_tt_unpopulate = i915_ttm_tt_unpopulate,
+	.ttm_tt_destroy = i915_ttm_tt_destroy,
+	.eviction_valuable = i915_ttm_eviction_valuable,
+	.evict_flags = i915_ttm_evict_flags,
+	.move = i915_ttm_move,
+	.verify_access = NULL,
+	.swap_possible = i915_ttm_swap_possible,
+	.swap_notify = i915_ttm_swap_notify,
+	.delete_mem_notify = i915_ttm_delete_mem_notify,
+};
+
+static int i915_ttm_get_pages(struct drm_i915_gem_object *obj)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+	struct ttm_operation_ctx ctx = {
+		.interruptible = true,
+		.no_wait_gpu = false,
+	};
+	struct sg_table *st;
+	int ret;
+
+	/* Swap in. */
+	if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
+		ret = ttm_tt_populate(bo->bdev, bo->ttm, &ctx);
+		if (ret)
+			return ret;
+	}
+
+	/* Move to the requested placement. */
+	ret = ttm_bo_validate(bo, &i915_lmem0_placement, &ctx);
+	if (ret)
+		return ret;
+
+	/* Object either has a page vector or is an iomem object */
+	st = bo->ttm ? i915_ttm_tt_get_st(bo->ttm) : obj->ttm.cached_io_st;
+	if (IS_ERR(st))
+		return PTR_ERR(st);
+
+	__i915_gem_object_set_pages(obj, st, i915_sg_dma_page_sizes(st->sgl));
+
+	i915_ttm_adjust_lru(obj);
+
+	return ret;
+}
+
+static void i915_ttm_put_pages(struct drm_i915_gem_object *obj,
+			       struct sg_table *st)
+{
+	/*
+	 * We're currently not called from a shrinker, so put_pages()
+	 * typically means the object is about to destroyed, or called
+	 * from move_notify(). So just avoid doing much for now.
+	 * If the object is not destroyed next, The TTM eviction logic
+	 * and shrinkers will move it out if needed.
+	 */
+
+	i915_ttm_adjust_lru(obj);
+}
+
+static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj)
+{
+	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+
+	/*
+	 * Don't manipulate the TTM LRUs while in TTM bo destruction.
+	 * We're called through i915_ttm_delete_mem_notify().
+	 */
+	if (!kref_read(&bo->kref))
+		return;
+
+	/*
+	 * Put on the correct LRU list depending on the MADV status
+	 */
+	spin_lock(&bo->bdev->lru_lock);
+	if (obj->mm.madv != I915_MADV_WILLNEED) {
+		bo->priority = I915_TTM_PRIO_PURGE;
+	} else if (!i915_gem_object_has_pages(obj)) {
+		if (bo->priority < I915_TTM_PRIO_HAS_PAGES)
+			bo->priority = I915_TTM_PRIO_HAS_PAGES;
+	} else {
+		if (bo->priority > I915_TTM_PRIO_NO_PAGES)
+			bo->priority = I915_TTM_PRIO_NO_PAGES;
+	}
+
+	ttm_bo_move_to_lru_tail(bo, &bo->mem, NULL);
+	spin_unlock(&bo->bdev->lru_lock);
+}
+
+/*
+ * TTM-backed gem object destruction requires some clarification.
+ * Basically we have two possibilities here. We can either rely on the
+ * i915 delayed destruction and put the TTM object when the object
+ * is idle. This would be detected by TTM which would bypass the
+ * TTM delayed destroy handling. The other approach is to put the TTM
+ * object early and rely on the TTM destroyed handling, and then free
+ * the leftover parts of the GEM object once TTM's destroyed list handling is
+ * complete. For now, we rely on the latter for two reasons:
+ * a) TTM can evict an object even when it's on the delayed destroy list,
+ * which in theory allows for complete eviction.
+ * b) There is work going on in TTM to allow freeing an object even when
+ * it's not idle, and using the TTM destroyed list handling could help us
+ * benefit from that.
+ */
+static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj)
+{
+	ttm_bo_put(i915_gem_to_ttm(obj));
+}
+
+static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = {
+	.name = "i915_gem_object_ttm",
+	.flags = I915_GEM_OBJECT_HAS_IOMEM,
+
+	.get_pages = i915_ttm_get_pages,
+	.put_pages = i915_ttm_put_pages,
+	.truncate = i915_ttm_purge,
+	.adjust_lru = i915_ttm_adjust_lru,
+	.delayed_free = i915_ttm_delayed_free,
+};
+
+void i915_ttm_bo_destroy(struct ttm_buffer_object *bo)
+{
+	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+
+	i915_gem_object_release_memory_region(obj);
+	call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
+}
+
+/**
+ * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
+ * @mem: The initial memory region for the object.
+ * @obj: The gem object.
+ * @size: Object size in bytes.
+ * @flags: gem object flags.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
+			       struct drm_i915_gem_object *obj,
+			       resource_size_t size,
+			       unsigned int flags)
+{
+	static struct lock_class_key lock_class;
+	struct drm_i915_private *i915 = mem->i915;
+	size_t alignment = 0;
+	int ret;
+
+	/* Adjust alignment to GPU- and CPU huge page sizes. */
+
+	if (mem->is_range_manager) {
+		if (size >= SZ_1G)
+			alignment = SZ_1G >> PAGE_SHIFT;
+		else if (size >= SZ_2M)
+			alignment = SZ_2M >> PAGE_SHIFT;
+		else if (size >= SZ_64K)
+			alignment = SZ_64K >> PAGE_SHIFT;
+	}
+
+	drm_gem_private_object_init(&i915->drm, &obj->base, size);
+	i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
+	i915_gem_object_init_memory_region(obj, mem);
+	i915_gem_object_make_unshrinkable(obj);
+
+	ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
+			  ttm_bo_type_kernel, &i915_sys_placement, alignment,
+			  true, NULL, NULL, i915_ttm_bo_destroy);
+
+	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
+
+	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
new file mode 100644
index 000000000000..b8d3dcbb50df
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+#ifndef _I915_GEM_TTM_H_
+#define _I915_GEM_TTM_H_
+
+#include "gem/i915_gem_object_types.h"
+
+/**
+ * i915_gem_to_ttm - Convert a struct drm_i915_gem_object to a
+ * struct ttm_buffer_object.
+ * @obj: Pointer to the gem object.
+ *
+ * Return: Pointer to the embedded struct ttm_buffer_object.
+ */
+static inline struct ttm_buffer_object *
+i915_gem_to_ttm(struct drm_i915_gem_object *obj)
+{
+	return &obj->__do_not_access;
+}
+
+/*
+ * i915 ttm gem object destructor. Internal use only.
+ */
+void i915_ttm_bo_destroy(struct ttm_buffer_object *bo);
+
+/**
+ * i915_ttm_to_gem - Convert a struct ttm_buffer_object to an embedding
+ * struct drm_i915_gem_object.
+ *
+ * Return: Pointer to the embedding struct ttm_buffer_object, or NULL
+ * if the object was not an i915 ttm object.
+ */
+static inline struct drm_i915_gem_object *
+i915_ttm_to_gem(struct ttm_buffer_object *bo)
+{
+	if (GEM_WARN_ON(bo->destroy != i915_ttm_bo_destroy))
+		return NULL;
+
+	return container_of(bo, struct drm_i915_gem_object, __do_not_access);
+}
+
+int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
+			       struct drm_i915_gem_object *obj,
+			       resource_size_t size,
+			       unsigned int flags);
+#endif
diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
index f7366b054f8e..4ae1f717a94c 100644
--- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c
+++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
@@ -9,6 +9,7 @@
 #include "intel_region_ttm.h"
 #include "gem/i915_gem_lmem.h"
 #include "gem/i915_gem_region.h"
+#include "gem/i915_gem_ttm.h"
 #include "intel_region_lmem.h"
 
 static int init_fake_lmem_bar(struct intel_memory_region *mem)
@@ -107,7 +108,7 @@ region_lmem_init(struct intel_memory_region *mem)
 static const struct intel_memory_region_ops intel_region_lmem_ops = {
 	.init = region_lmem_init,
 	.release = region_lmem_release,
-	.init_object = __i915_gem_lmem_object_init,
+	.init_object = __i915_gem_ttm_object_init,
 };
 
 struct intel_memory_region *
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 180f6e9107d4..350283ab9a83 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1005,8 +1005,11 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
 		}
 	}
 
-	if (obj->mm.madv != __I915_MADV_PURGED)
+	if (obj->mm.madv != __I915_MADV_PURGED) {
 		obj->mm.madv = args->madv;
+		if (obj->ops->adjust_lru)
+			obj->ops->adjust_lru(obj);
+	}
 
 	if (i915_gem_object_has_pages(obj)) {
 		struct list_head *list;
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index 4092cc987679..bd27e897d4d0 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -149,7 +149,6 @@ intel_memory_region_create(struct drm_i915_private *i915,
 
 	mutex_init(&mem->objects.lock);
 	INIT_LIST_HEAD(&mem->objects.list);
-	INIT_LIST_HEAD(&mem->objects.purgeable);
 	INIT_LIST_HEAD(&mem->reserved);
 
 	mutex_init(&mem->mm_lock);
diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
index e69cde13daf2..7b5fa97c0b59 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.h
+++ b/drivers/gpu/drm/i915/intel_memory_region.h
@@ -100,7 +100,6 @@ struct intel_memory_region {
 	struct {
 		struct mutex lock; /* Protects access to objects */
 		struct list_head list;
-		struct list_head purgeable;
 	} objects;
 
 	size_t chunk_size;
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
index 3bd9caa60298..a74cae4602b5 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.c
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -10,8 +10,7 @@
 
 #include "intel_region_ttm.h"
 
-/* A Zero-initialized driver for now. We don't have a TTM backend yet. */
-static struct ttm_device_funcs i915_ttm_bo_driver;
+extern struct ttm_device_funcs i915_ttm_bo_driver;
 
 /**
  * DOC: TTM support structure
@@ -198,6 +197,7 @@ struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
 	return i915_sg_from_mm_node(node, mem->region.start);
 }
 
+#ifdef CONFIG_DRM_I915_SELFTEST
 /**
  * intel_region_ttm_node_alloc - Allocate memory resources from a region
  * @mem: The memory region,
@@ -244,3 +244,4 @@ void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
 		ret = -ENXIO;
 	return ret ? ERR_PTR(ret) : res.mm_node;
 }
+#endif
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
index 40129f7e0317..9a5b0437d73f 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.h
+++ b/drivers/gpu/drm/i915/intel_region_ttm.h
@@ -21,9 +21,12 @@ void intel_region_ttm_fini(struct intel_memory_region *mem);
 struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
 					     void *node);
 
+void intel_region_ttm_node_free(struct intel_memory_region *mem,
+				void *node);
+
+#ifdef CONFIG_DRM_I915_SELFTEST
 void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
 				  resource_size_t size,
 				  unsigned int flags);
-void intel_region_ttm_node_free(struct intel_memory_region *mem,
-				void *node);
+#endif
 #endif /* _INTEL_REGION_TTM_H_ */
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 4479c55aaa1d..74004d5cbfa2 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1150,6 +1150,14 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
 		return -EBUSY;
 	}
 
+	if (bo->bdev->funcs->swap_possible) {
+		if (!bo->bdev->funcs->swap_possible(bo)) {
+			if (locked)
+				dma_resv_unlock(bo->base.resv);
+			return -EBUSY;
+		}
+	}
+
 	if (bo->deleted) {
 		ttm_bo_cleanup_refs(bo, false, false, locked);
 		ttm_bo_put(bo);
@@ -1200,6 +1208,10 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
 	if (bo->bdev->funcs->swap_notify)
 		bo->bdev->funcs->swap_notify(bo);
 
+	/* The call to swap_notify may have purged the bo */
+	if (!bo->ttm)
+		goto out;
+
 	ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags);
 out:
 
diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h
index 7c8f87bd52d3..7c59d35e90f9 100644
--- a/include/drm/ttm/ttm_device.h
+++ b/include/drm/ttm/ttm_device.h
@@ -181,6 +181,15 @@ struct ttm_device_funcs {
 	 */
 	void (*delete_mem_notify)(struct ttm_buffer_object *bo);
 
+	/**
+	 * struct ttm_bo_driver member swap_possible
+	 *
+	 * @bo: the buffer object to be evicted
+	 *
+	 * Check with the driver if it is possible to swap out a BO.
+	 */
+	bool (*swap_possible)(struct ttm_buffer_object *bo);
+
 	/**
 	 * notify the driver that we're about to swap out this bo
 	 */
-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH 7/7] drm/i915/lmem: Verify checks for lmem residency
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:25   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

Since objects can be migrated or evicted when not pinned or locked,
update the checks for lmem residency or future residency so that
the value returned is not immediately stale.

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c |  2 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c     | 42 +++++++++++++++++++-
 drivers/gpu/drm/i915/gem/i915_gem_object.c   | 29 ++++++++++++++
 drivers/gpu/drm/i915/gem/i915_gem_object.h   |  4 ++
 4 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index de1f13d203b5..b95def2d5af3 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -11615,7 +11615,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
 
 	/* object is backed with LMEM for discrete */
 	i915 = to_i915(obj->base.dev);
-	if (HAS_LMEM(i915) && !i915_gem_object_is_lmem(obj)) {
+	if (HAS_LMEM(i915) && !i915_gem_object_validates_to_lmem(obj)) {
 		/* object is "remote", not in local memory */
 		i915_gem_object_put(obj);
 		return ERR_PTR(-EREMOTE);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
index 2b8cd15de1d9..d539dffa1554 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
@@ -23,10 +23,50 @@ i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
 	return io_mapping_map_wc(&obj->mm.region->iomap, offset, size);
 }
 
+/**
+ * i915_gem_object_validates_to_lmem - Whether the object is resident in
+ * lmem when pages are present.
+ * @obj: The object to check.
+ *
+ * Migratable objects residency may change from under us if the object is
+ * not pinned or locked. This function is intended to be used to check whether
+ * the object can only reside in lmem when pages are present.
+ *
+ * Return: Whether the object is always resident in lmem when pages are
+ * present.
+ */
+bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj)
+{
+	struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
+
+	return !i915_gem_object_migratable(obj) &&
+		mr && (mr->type == INTEL_MEMORY_LOCAL ||
+		       mr->type == INTEL_MEMORY_STOLEN_LOCAL);
+}
+
+/**
+ * i915_gem_object_is_lmem - Whether the object is resident in
+ * lmem
+ * @obj: The object to check.
+ *
+ * Even if an object is allowed to migrate and change memory region,
+ * this function checks whether it will always be present in lmem when
+ * valid *or* if that's not the case, whether it's currently resident in lmem.
+ * For migratable and evictable objects, the latter only makes sense when
+ * the object is locked.
+ *
+ * Return: Whether the object migratable but resident in lmem, or not
+ * migratable and will be present in lmem when valid.
+ */
 bool i915_gem_object_is_lmem(struct drm_i915_gem_object *obj)
 {
-	struct intel_memory_region *mr = obj->mm.region;
+	struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
 
+#ifdef CONFIG_LOCKDEP
+	if (i915_gem_object_migratable(obj) &&
+	    i915_gem_object_evictable(obj))
+		assert_object_held(obj);
+#endif
 	return mr && (mr->type == INTEL_MEMORY_LOCAL ||
 		      mr->type == INTEL_MEMORY_STOLEN_LOCAL);
 }
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index c53488f391dd..0475b1c94454 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -458,6 +458,35 @@ bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
 	return pin_count == 0;
 }
 
+/**
+ * i915_gem_object_migratable - Whether the object is migratable out of the
+ * current region.
+ * @obj: Pointer to the object.
+ *
+ * Return: Whether the object is allowed to be resident in other
+ * regions than the current while pages are present.
+ */
+bool i915_gem_object_migratable(struct drm_i915_gem_object *obj)
+{
+	struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
+	struct intel_memory_region *placement;
+	int i;
+
+	if (!mr)
+		return false;
+
+	if (!obj->mm.n_placements)
+		return false;
+
+	for (i = 0; i < obj->mm.n_placements; ++i) {
+		placement = obj->mm.placements[i];
+		if (placement != mr)
+			return true;
+	}
+
+	return false;
+}
+
 void i915_gem_init__objects(struct drm_i915_private *i915)
 {
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index ae5930e307d5..a3ad8cf4eefd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -596,6 +596,10 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj);
 
 bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
 
+bool i915_gem_object_migratable(struct drm_i915_gem_object *obj);
+
+bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj);
+
 #ifdef CONFIG_MMU_NOTIFIER
 static inline bool
 i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Intel-gfx] [PATCH 7/7] drm/i915/lmem: Verify checks for lmem residency
@ 2021-05-11 13:25   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 13:25 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Thomas Hellström

Since objects can be migrated or evicted when not pinned or locked,
update the checks for lmem residency or future residency so that
the value returned is not immediately stale.

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c |  2 +-
 drivers/gpu/drm/i915/gem/i915_gem_lmem.c     | 42 +++++++++++++++++++-
 drivers/gpu/drm/i915/gem/i915_gem_object.c   | 29 ++++++++++++++
 drivers/gpu/drm/i915/gem/i915_gem_object.h   |  4 ++
 4 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index de1f13d203b5..b95def2d5af3 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -11615,7 +11615,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
 
 	/* object is backed with LMEM for discrete */
 	i915 = to_i915(obj->base.dev);
-	if (HAS_LMEM(i915) && !i915_gem_object_is_lmem(obj)) {
+	if (HAS_LMEM(i915) && !i915_gem_object_validates_to_lmem(obj)) {
 		/* object is "remote", not in local memory */
 		i915_gem_object_put(obj);
 		return ERR_PTR(-EREMOTE);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
index 2b8cd15de1d9..d539dffa1554 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
@@ -23,10 +23,50 @@ i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
 	return io_mapping_map_wc(&obj->mm.region->iomap, offset, size);
 }
 
+/**
+ * i915_gem_object_validates_to_lmem - Whether the object is resident in
+ * lmem when pages are present.
+ * @obj: The object to check.
+ *
+ * Migratable objects residency may change from under us if the object is
+ * not pinned or locked. This function is intended to be used to check whether
+ * the object can only reside in lmem when pages are present.
+ *
+ * Return: Whether the object is always resident in lmem when pages are
+ * present.
+ */
+bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj)
+{
+	struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
+
+	return !i915_gem_object_migratable(obj) &&
+		mr && (mr->type == INTEL_MEMORY_LOCAL ||
+		       mr->type == INTEL_MEMORY_STOLEN_LOCAL);
+}
+
+/**
+ * i915_gem_object_is_lmem - Whether the object is resident in
+ * lmem
+ * @obj: The object to check.
+ *
+ * Even if an object is allowed to migrate and change memory region,
+ * this function checks whether it will always be present in lmem when
+ * valid *or* if that's not the case, whether it's currently resident in lmem.
+ * For migratable and evictable objects, the latter only makes sense when
+ * the object is locked.
+ *
+ * Return: Whether the object migratable but resident in lmem, or not
+ * migratable and will be present in lmem when valid.
+ */
 bool i915_gem_object_is_lmem(struct drm_i915_gem_object *obj)
 {
-	struct intel_memory_region *mr = obj->mm.region;
+	struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
 
+#ifdef CONFIG_LOCKDEP
+	if (i915_gem_object_migratable(obj) &&
+	    i915_gem_object_evictable(obj))
+		assert_object_held(obj);
+#endif
 	return mr && (mr->type == INTEL_MEMORY_LOCAL ||
 		      mr->type == INTEL_MEMORY_STOLEN_LOCAL);
 }
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index c53488f391dd..0475b1c94454 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -458,6 +458,35 @@ bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
 	return pin_count == 0;
 }
 
+/**
+ * i915_gem_object_migratable - Whether the object is migratable out of the
+ * current region.
+ * @obj: Pointer to the object.
+ *
+ * Return: Whether the object is allowed to be resident in other
+ * regions than the current while pages are present.
+ */
+bool i915_gem_object_migratable(struct drm_i915_gem_object *obj)
+{
+	struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
+	struct intel_memory_region *placement;
+	int i;
+
+	if (!mr)
+		return false;
+
+	if (!obj->mm.n_placements)
+		return false;
+
+	for (i = 0; i < obj->mm.n_placements; ++i) {
+		placement = obj->mm.placements[i];
+		if (placement != mr)
+			return true;
+	}
+
+	return false;
+}
+
 void i915_gem_init__objects(struct drm_i915_private *i915)
 {
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index ae5930e307d5..a3ad8cf4eefd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -596,6 +596,10 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj);
 
 bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
 
+bool i915_gem_object_migratable(struct drm_i915_gem_object *obj);
+
+bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj);
+
 #ifdef CONFIG_MMU_NOTIFIER
 static inline bool
 i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
-- 
2.30.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
@ 2021-05-11 13:58     ` Christian König
  -1 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-11 13:58 UTC (permalink / raw)
  To: Thomas Hellström, intel-gfx, dri-devel

Am 11.05.21 um 15:25 schrieb Thomas Hellström:
> Most logical place to introduce TTM buffer objects is as an i915
> gem object backend. We need to add some ops to account for added
> functionality like delayed delete and LRU list manipulation.
>
> Initially we support only LMEM and SYSTEM memory, but SYSTEM
> (which in this case means evicted LMEM objects) is not
> visible to i915 GEM yet. The plan is to move the i915 gem system region
> over to the TTM system memory type in upcoming patches.
>
> We set up GPU bindings directly both from LMEM and from the system region,
> as there is no need to use the legacy TTM_TT memory type. We reserve
> that for future porting of GGTT bindings to TTM.
>
> There are some changes to TTM to allow for purging system memory buffer
> objects and to refuse swapping of some objects: Unfortunately i915 gem
> still relies heavily on short-term object pinning, and we've chosen to
> keep short-term-pinned buffer objects on the TTM LRU lists for now,
> meaning that we need some sort of mechanism to tell TTM they are not
> swappable. A longer term goal is to get rid of the short-term pinning.

Well just use the eviction_valuable interface for this.

In general please make separate patches for the TTM changes and for the 
i915 changes using them for easier review.

Christian.

>
> Remove the old lmem backend.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/Makefile                 |   1 +
>   drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
>   drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
>   drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
>   drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
>   .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
>   drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
>   drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
>   drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
>   drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
>   drivers/gpu/drm/i915/i915_gem.c               |   5 +-
>   drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
>   drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
>   drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
>   drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
>   drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
>   include/drm/ttm/ttm_device.h                  |   9 +
>   17 files changed, 733 insertions(+), 140 deletions(-)
>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 958ccc1edfed..ef0d884a9e2d 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -155,6 +155,7 @@ gem-y += \
>   	gem/i915_gem_stolen.o \
>   	gem/i915_gem_throttle.o \
>   	gem/i915_gem_tiling.o \
> +	gem/i915_gem_ttm.o \
>   	gem/i915_gem_ttm_bo_util.o \
>   	gem/i915_gem_userptr.o \
>   	gem/i915_gem_wait.o \
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index f42803ea48f2..2b8cd15de1d9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -4,73 +4,10 @@
>    */
>   
>   #include "intel_memory_region.h"
> -#include "intel_region_ttm.h"
>   #include "gem/i915_gem_region.h"
>   #include "gem/i915_gem_lmem.h"
>   #include "i915_drv.h"
>   
> -static void lmem_put_pages(struct drm_i915_gem_object *obj,
> -				  struct sg_table *pages)
> -{
> -	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
> -	obj->mm.dirty = false;
> -	sg_free_table(pages);
> -	kfree(pages);
> -}
> -
> -static int lmem_get_pages(struct drm_i915_gem_object *obj)
> -{
> -	unsigned int flags;
> -	struct sg_table *pages;
> -
> -	flags = I915_ALLOC_MIN_PAGE_SIZE;
> -	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> -		flags |= I915_ALLOC_CONTIGUOUS;
> -
> -	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
> -							 obj->base.size,
> -							 flags);
> -	if (IS_ERR(obj->mm.st_mm_node))
> -		return PTR_ERR(obj->mm.st_mm_node);
> -
> -	/* Range manager is always contigous */
> -	if (obj->mm.region->is_range_manager)
> -		obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> -	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
> -	if (IS_ERR(pages))
> -		return PTR_ERR(pages);
> -
> -	__i915_gem_object_set_pages(obj, pages,
> -				    i915_sg_dma_page_sizes(pages->sgl));
> -
> -	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> -		void __iomem *vaddr =
> -			i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
> -
> -		if (!vaddr) {
> -			struct sg_table *pages =
> -				__i915_gem_object_unset_pages(obj);
> -
> -			if (!IS_ERR_OR_NULL(pages))
> -				lmem_put_pages(obj, pages);
> -		}
> -
> -		memset_io(vaddr, 0, obj->base.size);
> -		io_mapping_unmap(vaddr);
> -	}
> -
> -	return 0;
> -}
> -
> -const struct drm_i915_gem_object_ops i915_gem_lmem_obj_ops = {
> -	.name = "i915_gem_object_lmem",
> -	.flags = I915_GEM_OBJECT_HAS_IOMEM,
> -
> -	.get_pages = lmem_get_pages,
> -	.put_pages = lmem_put_pages,
> -	.release = i915_gem_object_release_memory_region,
> -};
> -
>   void __iomem *
>   i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
>   			    unsigned long n,
> @@ -102,23 +39,3 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
>   	return i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_LMEM],
>   					     size, flags);
>   }
> -
> -int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
> -				struct drm_i915_gem_object *obj,
> -				resource_size_t size,
> -				unsigned int flags)
> -{
> -	static struct lock_class_key lock_class;
> -	struct drm_i915_private *i915 = mem->i915;
> -
> -	drm_gem_private_object_init(&i915->drm, &obj->base, size);
> -	i915_gem_object_init(obj, &i915_gem_lmem_obj_ops, &lock_class, flags);
> -
> -	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
> -
> -	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
> -
> -	i915_gem_object_init_memory_region(obj, mem);
> -
> -	return 0;
> -}
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
> index fac6bc5a5ebb..ea76fd11ccb0 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
> @@ -26,9 +26,4 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
>   			    resource_size_t size,
>   			    unsigned int flags);
>   
> -int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
> -				struct drm_i915_gem_object *obj,
> -				resource_size_t size,
> -				unsigned int flags);
> -
>   #endif /* !__I915_GEM_LMEM_H */
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> index c8953e3f5c70..c53488f391dd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> @@ -172,7 +172,7 @@ static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *f
>   	}
>   }
>   
> -static void __i915_gem_free_object_rcu(struct rcu_head *head)
> +void __i915_gem_free_object_rcu(struct rcu_head *head)
>   {
>   	struct drm_i915_gem_object *obj =
>   		container_of(head, typeof(*obj), rcu);
> @@ -208,59 +208,70 @@ static void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj)
>   	}
>   }
>   
> -static void __i915_gem_free_objects(struct drm_i915_private *i915,
> -				    struct llist_node *freed)
> +void __i915_gem_free_object(struct drm_i915_gem_object *obj)
>   {
> -	struct drm_i915_gem_object *obj, *on;
> +	trace_i915_gem_object_destroy(obj);
>   
> -	llist_for_each_entry_safe(obj, on, freed, freed) {
> -		trace_i915_gem_object_destroy(obj);
> +	if (!list_empty(&obj->vma.list)) {
> +		struct i915_vma *vma;
> +
> +		/*
> +		 * Note that the vma keeps an object reference while
> +		 * it is active, so it *should* not sleep while we
> +		 * destroy it. Our debug code errs insits it *might*.
> +		 * For the moment, play along.
> +		 */
> +		spin_lock(&obj->vma.lock);
> +		while ((vma = list_first_entry_or_null(&obj->vma.list,
> +						       struct i915_vma,
> +						       obj_link))) {
> +			GEM_BUG_ON(vma->obj != obj);
> +			spin_unlock(&obj->vma.lock);
>   
> -		if (!list_empty(&obj->vma.list)) {
> -			struct i915_vma *vma;
> +			__i915_vma_put(vma);
>   
> -			/*
> -			 * Note that the vma keeps an object reference while
> -			 * it is active, so it *should* not sleep while we
> -			 * destroy it. Our debug code errs insits it *might*.
> -			 * For the moment, play along.
> -			 */
>   			spin_lock(&obj->vma.lock);
> -			while ((vma = list_first_entry_or_null(&obj->vma.list,
> -							       struct i915_vma,
> -							       obj_link))) {
> -				GEM_BUG_ON(vma->obj != obj);
> -				spin_unlock(&obj->vma.lock);
> +		}
> +		spin_unlock(&obj->vma.lock);
> +	}
>   
> -				__i915_vma_put(vma);
> +	__i915_gem_object_free_mmaps(obj);
>   
> -				spin_lock(&obj->vma.lock);
> -			}
> -			spin_unlock(&obj->vma.lock);
> -		}
> +	GEM_BUG_ON(!list_empty(&obj->lut_list));
>   
> -		__i915_gem_object_free_mmaps(obj);
> +	atomic_set(&obj->mm.pages_pin_count, 0);
> +	__i915_gem_object_put_pages(obj);
> +	GEM_BUG_ON(i915_gem_object_has_pages(obj));
> +	bitmap_free(obj->bit_17);
>   
> -		GEM_BUG_ON(!list_empty(&obj->lut_list));
> +	if (obj->base.import_attach)
> +		drm_prime_gem_destroy(&obj->base, NULL);
>   
> -		atomic_set(&obj->mm.pages_pin_count, 0);
> -		__i915_gem_object_put_pages(obj);
> -		GEM_BUG_ON(i915_gem_object_has_pages(obj));
> -		bitmap_free(obj->bit_17);
> +	drm_gem_free_mmap_offset(&obj->base);
>   
> -		if (obj->base.import_attach)
> -			drm_prime_gem_destroy(&obj->base, NULL);
> +	if (obj->ops->release)
> +		obj->ops->release(obj);
>   
> -		drm_gem_free_mmap_offset(&obj->base);
> +	if (obj->mm.n_placements > 1)
> +		kfree(obj->mm.placements);
>   
> -		if (obj->ops->release)
> -			obj->ops->release(obj);
> +	if (obj->resv_shared_from)
> +		i915_vm_resv_put(obj->resv_shared_from);
>   
> -		if (obj->mm.n_placements > 1)
> -			kfree(obj->mm.placements);
> +}
> +
> +static void __i915_gem_free_objects(struct drm_i915_private *i915,
> +				    struct llist_node *freed)
> +{
> +	struct drm_i915_gem_object *obj, *on;
>   
> -		if (obj->resv_shared_from)
> -			i915_vm_resv_put(obj->resv_shared_from);
> +	llist_for_each_entry_safe(obj, on, freed, freed) {
> +		might_sleep();
> +		if (obj->ops->delayed_free) {
> +			obj->ops->delayed_free(obj);
> +			continue;
> +		}
> +		__i915_gem_free_object(obj);
>   
>   		/* But keep the pointer alive for RCU-protected lookups */
>   		call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
> @@ -318,6 +329,7 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj)
>   	 * worker and performing frees directly from subsequent allocations for
>   	 * crude but effective memory throttling.
>   	 */
> +
>   	if (llist_add(&obj->freed, &i915->mm.free_list))
>   		queue_work(i915->wq, &i915->mm.free_work);
>   }
> @@ -410,6 +422,42 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
>   	return 0;
>   }
>   
> +/**
> + * i915_gem_object_evictable - Whether object is likely evictable after unbind.
> + * @obj: The object to check
> + *
> + * This function checks whether the object is likely unvictable after unbind.
> + * If the object is not locked when checking, the result is only advisory.
> + * If the object is locked when checking, and the function returns true,
> + * then an eviction should indeed be possible. But since unlocked vma
> + * unpinning and unbinding is currently possible, the object can actually
> + * become evictable even if this function returns false.
> + *
> + * Return: true if the object may be evictable. False otherwise.
> + */
> +bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
> +{
> +	struct i915_vma *vma;
> +	int pin_count = atomic_read(&obj->mm.pages_pin_count);
> +
> +	if (!pin_count)
> +		return true;
> +
> +	spin_lock(&obj->vma.lock);
> +	list_for_each_entry(vma, &obj->vma.list, obj_link) {
> +		if (i915_vma_is_pinned(vma)) {
> +			spin_unlock(&obj->vma.lock);
> +			return false;
> +		}
> +		if (atomic_read(&vma->pages_count))
> +			pin_count--;
> +	}
> +	spin_unlock(&obj->vma.lock);
> +	GEM_WARN_ON(pin_count < 0);
> +
> +	return pin_count == 0;
> +}
> +
>   void i915_gem_init__objects(struct drm_i915_private *i915)
>   {
>   	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> index 2ebd79537aea..ae5930e307d5 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> @@ -200,6 +200,9 @@ static inline bool i915_gem_object_trylock(struct drm_i915_gem_object *obj)
>   
>   static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj)
>   {
> +	if (obj->ops->adjust_lru)
> +		obj->ops->adjust_lru(obj);
> +
>   	dma_resv_unlock(obj->base.resv);
>   }
>   
> @@ -587,6 +590,12 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
>   
>   bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj);
>   
> +void __i915_gem_free_object_rcu(struct rcu_head *head);
> +
> +void __i915_gem_free_object(struct drm_i915_gem_object *obj);
> +
> +bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
> +
>   #ifdef CONFIG_MMU_NOTIFIER
>   static inline bool
>   i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
> 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 98f69d8fd37d..b350765e1935 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
> @@ -63,6 +63,20 @@ struct drm_i915_gem_object_ops {
>   		      const struct drm_i915_gem_pwrite *arg);
>   
>   	int (*dmabuf_export)(struct drm_i915_gem_object *obj);
> +
> +	/**
> +	 * adjust_lru - notify that the madvise value was updated
> +	 * @obj: The gem object
> +	 *
> +	 * The madvise value may have been updated, or object was recently
> +	 * referenced so act accordingly (Perhaps changing an LRU list etc).
> +	 */
> +	void (*adjust_lru)(struct drm_i915_gem_object *obj);
> +
> +	/**
> +	 * delayed_free - Override the default delayed free implementation
> +	 */
> +	void (*delayed_free)(struct drm_i915_gem_object *obj);
>   	void (*release)(struct drm_i915_gem_object *obj);
>   
>   	const char *name; /* friendly name for debug, e.g. lockdep classes */
> @@ -307,6 +321,10 @@ struct drm_i915_gem_object {
>   		bool dirty:1;
>   	} mm;
>   
> +	struct {
> +		struct sg_table *cached_io_st;
> +	} ttm;
> +
>   	/** Record of address bit 17 of each page at last unbind. */
>   	unsigned long *bit_17;
>   
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
> index f25e6646c5b7..d1f1840540dd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
> @@ -18,11 +18,7 @@ void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
>   
>   	mutex_lock(&mem->objects.lock);
>   
> -	if (obj->flags & I915_BO_ALLOC_VOLATILE)
> -		list_add(&obj->mm.region_link, &mem->objects.purgeable);
> -	else
> -		list_add(&obj->mm.region_link, &mem->objects.list);
> -
> +	list_add(&obj->mm.region_link, &mem->objects.list);
>   	mutex_unlock(&mem->objects.lock);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> new file mode 100644
> index 000000000000..e3718c3cb299
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -0,0 +1,534 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +#include <drm/ttm/ttm_bo_driver.h>
> +#include <drm/ttm/ttm_placement.h>
> +
> +#include "i915_drv.h"
> +#include "intel_memory_region.h"
> +#include "intel_region_ttm.h"
> +
> +#include "gem/i915_gem_object.h"
> +#include "gem/i915_gem_region.h"
> +#include "gem/i915_gem_ttm.h"
> +#include "gem/i915_gem_ttm_bo_util.h"
> +
> +#define I915_PL_LMEM0 TTM_PL_PRIV
> +#define I915_PL_SYSTEM TTM_PL_SYSTEM
> +#define I915_PL_STOLEN TTM_PL_VRAM
> +#define I915_PL_GGTT TTM_PL_TT
> +
> +#define I915_TTM_PRIO_PURGE     0
> +#define I915_TTM_PRIO_NO_PAGES  1
> +#define I915_TTM_PRIO_HAS_PAGES 2
> +
> +/**
> + * struct i915_ttm_tt - TTM page vector with additional private information
> + * @ttm: The base TTM page vector.
> + * @dev: The struct device used for dma mapping and unmapping.
> + * @cached_st: The cached scatter-gather table.
> + *
> + * Note that DMA may be going on right up to the point where the page-
> + * vector is unpopulated in delayed destroy. Hence keep the
> + * scatter-gather table mapped and cached up to that point. This is
> + * different from the cached gem object io scatter-gather table which
> + * doesn't have an associated dma mapping.
> + */
> +struct i915_ttm_tt {
> +	struct ttm_tt ttm;
> +	struct device *dev;
> +	struct sg_table *cached_st;
> +};
> +
> +static const struct ttm_place lmem0_sys_placement_flags[] = {
> +	{
> +		.fpfn = 0,
> +		.lpfn = 0,
> +		.mem_type = I915_PL_LMEM0,
> +		.flags = 0,
> +	}, {
> +		.fpfn = 0,
> +		.lpfn = 0,
> +		.mem_type = I915_PL_SYSTEM,
> +		.flags = 0,
> +	}
> +};
> +
> +struct ttm_placement i915_lmem0_placement = {
> +	.num_placement = 1,
> +	.placement = &lmem0_sys_placement_flags[0],
> +	.num_busy_placement = 1,
> +	.busy_placement = &lmem0_sys_placement_flags[0],
> +};
> +
> +struct ttm_placement i915_lmem0_sys_placement = {
> +	.num_placement = 1,
> +	.placement = &lmem0_sys_placement_flags[0],
> +	.num_busy_placement = 2,
> +	.busy_placement = &lmem0_sys_placement_flags[0],
> +};
> +
> +struct ttm_placement i915_sys_placement = {
> +	.num_placement = 1,
> +	.placement = &lmem0_sys_placement_flags[1],
> +	.num_busy_placement = 1,
> +	.busy_placement = &lmem0_sys_placement_flags[1],
> +};
> +
> +static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj);
> +
> +static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
> +					 uint32_t page_flags)
> +{
> +	struct ttm_resource_manager *man =
> +		ttm_manager_type(bo->bdev, bo->mem.mem_type);
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	struct i915_ttm_tt *i915_tt;
> +	int ret;
> +
> +	i915_tt = kzalloc(sizeof(*i915_tt), GFP_KERNEL);
> +	if (!i915_tt)
> +		return NULL;
> +
> +	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR &&
> +	    man->use_tt)
> +		page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC;
> +
> +	ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, ttm_cached);
> +	if (ret) {
> +		kfree(i915_tt);
> +		return NULL;
> +	}
> +
> +	i915_tt->dev = obj->base.dev->dev;
> +
> +	return &i915_tt->ttm;
> +}
> +
> +static void i915_ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
> +{
> +	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
> +
> +	if (i915_tt->cached_st) {
> +		dma_unmap_sgtable(i915_tt->dev, i915_tt->cached_st,
> +				  DMA_BIDIRECTIONAL, 0);
> +		sg_free_table(i915_tt->cached_st);
> +		kfree(i915_tt->cached_st);
> +		i915_tt->cached_st = NULL;
> +	}
> +	ttm_pool_free(&bdev->pool, ttm);
> +}
> +
> +static void i915_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
> +{
> +	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
> +
> +	ttm_tt_destroy_common(bdev, ttm);
> +	kfree(i915_tt);
> +}
> +
> +static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo,
> +				       const struct ttm_place *place)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +
> +	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
> +	if (!i915_gem_object_evictable(obj))
> +		return false;
> +
> +	/* This isn't valid with a buddy allocator */
> +	return ttm_bo_eviction_valuable(bo, place);
> +}
> +
> +static void i915_ttm_evict_flags(struct ttm_buffer_object *bo,
> +				 struct ttm_placement *placement)
> +{
> +	*placement = i915_sys_placement;
> +}
> +
> +static int i915_ttm_move_notify(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	int ret;
> +
> +	ret = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE);
> +	if (ret)
> +		return ret;
> +
> +	ret = __i915_gem_object_put_pages(obj);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void i915_ttm_free_cached_io_st(struct drm_i915_gem_object *obj)
> +{
> +	if (obj->ttm.cached_io_st) {
> +		sg_free_table(obj->ttm.cached_io_st);
> +		kfree(obj->ttm.cached_io_st);
> +		obj->ttm.cached_io_st = NULL;
> +	}
> +}
> +
> +static void i915_ttm_purge(struct drm_i915_gem_object *obj)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +
> +	if (obj->mm.madv == __I915_MADV_PURGED)
> +		return;
> +
> +	i915_ttm_free_cached_io_st(obj);
> +
> +	ttm_resource_free(bo, &bo->mem);
> +	if (bo->ttm)
> +		ttm_bo_tt_destroy(bo);
> +
> +	obj->mm.madv = __I915_MADV_PURGED;
> +}
> +
> +static bool i915_ttm_swap_possible(struct ttm_buffer_object *bo)
> +{
> +	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
> +	return i915_gem_object_evictable(i915_ttm_to_gem(bo));
> +}
> +
> +static void i915_ttm_swap_notify(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	int ret = i915_ttm_move_notify(bo);
> +
> +	GEM_WARN_ON(ret);
> +	GEM_WARN_ON(obj->ttm.cached_io_st);
> +	if (!ret && obj->mm.madv != I915_MADV_WILLNEED)
> +		i915_ttm_purge(obj);
> +}
> +
> +static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +
> +	if (likely(obj)) {
> +		/* This releases all gem object bindings to the backend. */
> +		__i915_gem_free_object(obj);
> +	}
> +}
> +
> +static struct intel_memory_region *
> +i915_ttm_region(struct ttm_device *bdev, int ttm_mem_type)
> +{
> +	struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
> +
> +	/* There's some room for optimization here... */
> +	GEM_BUG_ON(ttm_mem_type != I915_PL_SYSTEM &&
> +		   ttm_mem_type < I915_PL_LMEM0);
> +	if (ttm_mem_type == I915_PL_SYSTEM)
> +		return intel_memory_region_lookup(i915, INTEL_MEMORY_SYSTEM,
> +						  0);
> +
> +	return intel_memory_region_lookup(i915, INTEL_MEMORY_LOCAL,
> +					  ttm_mem_type - I915_PL_LMEM0);
> +}
> +
> +static struct sg_table *i915_ttm_tt_get_st(struct ttm_tt *ttm)
> +{
> +	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
> +	struct scatterlist *sg;
> +	struct sg_table *st;
> +	int ret;
> +
> +	if (i915_tt->cached_st)
> +		return i915_tt->cached_st;
> +
> +	st = kzalloc(sizeof(*st), GFP_KERNEL);
> +	if (!st)
> +		return ERR_PTR(-ENOMEM);
> +
> +	sg = __sg_alloc_table_from_pages
> +		(st, ttm->pages, ttm->num_pages, 0,
> +		 (unsigned long) ttm->num_pages << PAGE_SHIFT,
> +		 i915_sg_segment_size(), NULL, 0, GFP_KERNEL);
> +	if (IS_ERR(sg)) {
> +		kfree(st);
> +		return ERR_CAST(sg);
> +	}
> +
> +	ret = dma_map_sgtable(i915_tt->dev, st, DMA_BIDIRECTIONAL, 0);
> +	if (ret) {
> +		sg_free_table(st);
> +		kfree(st);
> +		return ERR_PTR(ret);
> +	}
> +
> +	i915_tt->cached_st = st;
> +	return st;
> +}
> +
> +static struct sg_table *
> +i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
> +			 struct ttm_resource *res)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +	struct ttm_resource_manager *man =
> +		ttm_manager_type(bo->bdev, res->mem_type);
> +	struct sg_table *st;
> +
> +	if (man->use_tt)
> +		return i915_ttm_tt_get_st(bo->ttm);
> +
> +	st = kzalloc(sizeof(*st), GFP_KERNEL);
> +	if (!st)
> +		return ERR_PTR(-ENOMEM);
> +
> +	st = intel_region_ttm_node_to_st(obj->mm.region, res->mm_node);
> +	if (IS_ERR(st))
> +		return ERR_CAST(st);
> +
> +	return st;
> +}
> +
> +static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
> +			 struct ttm_operation_ctx *ctx,
> +			 struct ttm_resource *new_mem,
> +			 struct ttm_place *hop)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	struct ttm_resource_manager *new_man =
> +		ttm_manager_type(bo->bdev, new_mem->mem_type);
> +	struct ttm_resource_manager *old_man =
> +		ttm_manager_type(bo->bdev, bo->mem.mem_type);
> +	struct intel_memory_region *new_reg, *old_reg;
> +	union {
> +		struct i915_ttm_kmap_iter_tt tt;
> +		struct i915_ttm_kmap_iter_iomap io;
> +	} _new_iter, _old_iter;
> +	struct i915_ttm_kmap_iter *new_iter, *old_iter;
> +	struct sg_table *new_st;
> +	int ret;
> +
> +	new_reg = i915_ttm_region(bo->bdev, new_mem->mem_type);
> +	old_reg = i915_ttm_region(bo->bdev, bo->mem.mem_type);
> +	GEM_BUG_ON(!new_reg || !old_reg);
> +
> +	/* Sync for now. We could do the actual copy async. */
> +	ret = ttm_bo_wait_ctx(bo, ctx);
> +	if (ret)
> +		return ret;
> +
> +	ret = i915_ttm_move_notify(bo);
> +	if (ret)
> +		return ret;
> +
> +	if (obj->mm.madv != I915_MADV_WILLNEED) {
> +		i915_ttm_purge(obj);
> +		ttm_resource_free(bo, new_mem);
> +		return 0;
> +	}
> +
> +	/* Populate ttm with pages if needed. Typically system memory. */
> +	if (new_man->use_tt && bo->ttm) {
> +		ret = ttm_tt_populate(bo->bdev, bo->ttm, ctx);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	new_st = i915_ttm_resource_get_st(obj, new_mem);
> +	if (IS_ERR(new_st))
> +		return PTR_ERR(new_st);
> +
> +	new_iter = new_man->use_tt ?
> +		i915_ttm_kmap_iter_tt_init(&_new_iter.tt, bo->ttm) :
> +		i915_ttm_kmap_iter_iomap_init(&_new_iter.io, &new_reg->iomap,
> +					      new_st, new_reg->region.start);
> +
> +	old_iter = old_man->use_tt ?
> +		i915_ttm_kmap_iter_tt_init(&_old_iter.tt, bo->ttm) :
> +		i915_ttm_kmap_iter_iomap_init(&_old_iter.io, &old_reg->iomap,
> +					      obj->ttm.cached_io_st,
> +					      old_reg->region.start);
> +
> +	i915_ttm_move_memcpy(bo, new_mem, new_iter, old_iter);
> +	i915_ttm_free_cached_io_st(obj);
> +
> +	if (!new_man->use_tt)
> +		obj->ttm.cached_io_st = new_st;
> +
> +	return 0;
> +}
> +
> +struct ttm_device_funcs i915_ttm_bo_driver = {
> +	.ttm_tt_create = i915_ttm_tt_create,
> +	.ttm_tt_unpopulate = i915_ttm_tt_unpopulate,
> +	.ttm_tt_destroy = i915_ttm_tt_destroy,
> +	.eviction_valuable = i915_ttm_eviction_valuable,
> +	.evict_flags = i915_ttm_evict_flags,
> +	.move = i915_ttm_move,
> +	.verify_access = NULL,
> +	.swap_possible = i915_ttm_swap_possible,
> +	.swap_notify = i915_ttm_swap_notify,
> +	.delete_mem_notify = i915_ttm_delete_mem_notify,
> +};
> +
> +static int i915_ttm_get_pages(struct drm_i915_gem_object *obj)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +	struct ttm_operation_ctx ctx = {
> +		.interruptible = true,
> +		.no_wait_gpu = false,
> +	};
> +	struct sg_table *st;
> +	int ret;
> +
> +	/* Swap in. */
> +	if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
> +		ret = ttm_tt_populate(bo->bdev, bo->ttm, &ctx);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	/* Move to the requested placement. */
> +	ret = ttm_bo_validate(bo, &i915_lmem0_placement, &ctx);
> +	if (ret)
> +		return ret;
> +
> +	/* Object either has a page vector or is an iomem object */
> +	st = bo->ttm ? i915_ttm_tt_get_st(bo->ttm) : obj->ttm.cached_io_st;
> +	if (IS_ERR(st))
> +		return PTR_ERR(st);
> +
> +	__i915_gem_object_set_pages(obj, st, i915_sg_dma_page_sizes(st->sgl));
> +
> +	i915_ttm_adjust_lru(obj);
> +
> +	return ret;
> +}
> +
> +static void i915_ttm_put_pages(struct drm_i915_gem_object *obj,
> +			       struct sg_table *st)
> +{
> +	/*
> +	 * We're currently not called from a shrinker, so put_pages()
> +	 * typically means the object is about to destroyed, or called
> +	 * from move_notify(). So just avoid doing much for now.
> +	 * If the object is not destroyed next, The TTM eviction logic
> +	 * and shrinkers will move it out if needed.
> +	 */
> +
> +	i915_ttm_adjust_lru(obj);
> +}
> +
> +static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +
> +	/*
> +	 * Don't manipulate the TTM LRUs while in TTM bo destruction.
> +	 * We're called through i915_ttm_delete_mem_notify().
> +	 */
> +	if (!kref_read(&bo->kref))
> +		return;
> +
> +	/*
> +	 * Put on the correct LRU list depending on the MADV status
> +	 */
> +	spin_lock(&bo->bdev->lru_lock);
> +	if (obj->mm.madv != I915_MADV_WILLNEED) {
> +		bo->priority = I915_TTM_PRIO_PURGE;
> +	} else if (!i915_gem_object_has_pages(obj)) {
> +		if (bo->priority < I915_TTM_PRIO_HAS_PAGES)
> +			bo->priority = I915_TTM_PRIO_HAS_PAGES;
> +	} else {
> +		if (bo->priority > I915_TTM_PRIO_NO_PAGES)
> +			bo->priority = I915_TTM_PRIO_NO_PAGES;
> +	}
> +
> +	ttm_bo_move_to_lru_tail(bo, &bo->mem, NULL);
> +	spin_unlock(&bo->bdev->lru_lock);
> +}
> +
> +/*
> + * TTM-backed gem object destruction requires some clarification.
> + * Basically we have two possibilities here. We can either rely on the
> + * i915 delayed destruction and put the TTM object when the object
> + * is idle. This would be detected by TTM which would bypass the
> + * TTM delayed destroy handling. The other approach is to put the TTM
> + * object early and rely on the TTM destroyed handling, and then free
> + * the leftover parts of the GEM object once TTM's destroyed list handling is
> + * complete. For now, we rely on the latter for two reasons:
> + * a) TTM can evict an object even when it's on the delayed destroy list,
> + * which in theory allows for complete eviction.
> + * b) There is work going on in TTM to allow freeing an object even when
> + * it's not idle, and using the TTM destroyed list handling could help us
> + * benefit from that.
> + */
> +static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj)
> +{
> +	ttm_bo_put(i915_gem_to_ttm(obj));
> +}
> +
> +static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = {
> +	.name = "i915_gem_object_ttm",
> +	.flags = I915_GEM_OBJECT_HAS_IOMEM,
> +
> +	.get_pages = i915_ttm_get_pages,
> +	.put_pages = i915_ttm_put_pages,
> +	.truncate = i915_ttm_purge,
> +	.adjust_lru = i915_ttm_adjust_lru,
> +	.delayed_free = i915_ttm_delayed_free,
> +};
> +
> +void i915_ttm_bo_destroy(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +
> +	i915_gem_object_release_memory_region(obj);
> +	call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
> +}
> +
> +/**
> + * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
> + * @mem: The initial memory region for the object.
> + * @obj: The gem object.
> + * @size: Object size in bytes.
> + * @flags: gem object flags.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
> +			       struct drm_i915_gem_object *obj,
> +			       resource_size_t size,
> +			       unsigned int flags)
> +{
> +	static struct lock_class_key lock_class;
> +	struct drm_i915_private *i915 = mem->i915;
> +	size_t alignment = 0;
> +	int ret;
> +
> +	/* Adjust alignment to GPU- and CPU huge page sizes. */
> +
> +	if (mem->is_range_manager) {
> +		if (size >= SZ_1G)
> +			alignment = SZ_1G >> PAGE_SHIFT;
> +		else if (size >= SZ_2M)
> +			alignment = SZ_2M >> PAGE_SHIFT;
> +		else if (size >= SZ_64K)
> +			alignment = SZ_64K >> PAGE_SHIFT;
> +	}
> +
> +	drm_gem_private_object_init(&i915->drm, &obj->base, size);
> +	i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
> +	i915_gem_object_init_memory_region(obj, mem);
> +	i915_gem_object_make_unshrinkable(obj);
> +
> +	ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
> +			  ttm_bo_type_kernel, &i915_sys_placement, alignment,
> +			  true, NULL, NULL, i915_ttm_bo_destroy);
> +
> +	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
> +
> +	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
> new file mode 100644
> index 000000000000..b8d3dcbb50df
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +#ifndef _I915_GEM_TTM_H_
> +#define _I915_GEM_TTM_H_
> +
> +#include "gem/i915_gem_object_types.h"
> +
> +/**
> + * i915_gem_to_ttm - Convert a struct drm_i915_gem_object to a
> + * struct ttm_buffer_object.
> + * @obj: Pointer to the gem object.
> + *
> + * Return: Pointer to the embedded struct ttm_buffer_object.
> + */
> +static inline struct ttm_buffer_object *
> +i915_gem_to_ttm(struct drm_i915_gem_object *obj)
> +{
> +	return &obj->__do_not_access;
> +}
> +
> +/*
> + * i915 ttm gem object destructor. Internal use only.
> + */
> +void i915_ttm_bo_destroy(struct ttm_buffer_object *bo);
> +
> +/**
> + * i915_ttm_to_gem - Convert a struct ttm_buffer_object to an embedding
> + * struct drm_i915_gem_object.
> + *
> + * Return: Pointer to the embedding struct ttm_buffer_object, or NULL
> + * if the object was not an i915 ttm object.
> + */
> +static inline struct drm_i915_gem_object *
> +i915_ttm_to_gem(struct ttm_buffer_object *bo)
> +{
> +	if (GEM_WARN_ON(bo->destroy != i915_ttm_bo_destroy))
> +		return NULL;
> +
> +	return container_of(bo, struct drm_i915_gem_object, __do_not_access);
> +}
> +
> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
> +			       struct drm_i915_gem_object *obj,
> +			       resource_size_t size,
> +			       unsigned int flags);
> +#endif
> diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
> index f7366b054f8e..4ae1f717a94c 100644
> --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c
> +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
> @@ -9,6 +9,7 @@
>   #include "intel_region_ttm.h"
>   #include "gem/i915_gem_lmem.h"
>   #include "gem/i915_gem_region.h"
> +#include "gem/i915_gem_ttm.h"
>   #include "intel_region_lmem.h"
>   
>   static int init_fake_lmem_bar(struct intel_memory_region *mem)
> @@ -107,7 +108,7 @@ region_lmem_init(struct intel_memory_region *mem)
>   static const struct intel_memory_region_ops intel_region_lmem_ops = {
>   	.init = region_lmem_init,
>   	.release = region_lmem_release,
> -	.init_object = __i915_gem_lmem_object_init,
> +	.init_object = __i915_gem_ttm_object_init,
>   };
>   
>   struct intel_memory_region *
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 180f6e9107d4..350283ab9a83 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -1005,8 +1005,11 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
>   		}
>   	}
>   
> -	if (obj->mm.madv != __I915_MADV_PURGED)
> +	if (obj->mm.madv != __I915_MADV_PURGED) {
>   		obj->mm.madv = args->madv;
> +		if (obj->ops->adjust_lru)
> +			obj->ops->adjust_lru(obj);
> +	}
>   
>   	if (i915_gem_object_has_pages(obj)) {
>   		struct list_head *list;
> diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
> index 4092cc987679..bd27e897d4d0 100644
> --- a/drivers/gpu/drm/i915/intel_memory_region.c
> +++ b/drivers/gpu/drm/i915/intel_memory_region.c
> @@ -149,7 +149,6 @@ intel_memory_region_create(struct drm_i915_private *i915,
>   
>   	mutex_init(&mem->objects.lock);
>   	INIT_LIST_HEAD(&mem->objects.list);
> -	INIT_LIST_HEAD(&mem->objects.purgeable);
>   	INIT_LIST_HEAD(&mem->reserved);
>   
>   	mutex_init(&mem->mm_lock);
> diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
> index e69cde13daf2..7b5fa97c0b59 100644
> --- a/drivers/gpu/drm/i915/intel_memory_region.h
> +++ b/drivers/gpu/drm/i915/intel_memory_region.h
> @@ -100,7 +100,6 @@ struct intel_memory_region {
>   	struct {
>   		struct mutex lock; /* Protects access to objects */
>   		struct list_head list;
> -		struct list_head purgeable;
>   	} objects;
>   
>   	size_t chunk_size;
> diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
> index 3bd9caa60298..a74cae4602b5 100644
> --- a/drivers/gpu/drm/i915/intel_region_ttm.c
> +++ b/drivers/gpu/drm/i915/intel_region_ttm.c
> @@ -10,8 +10,7 @@
>   
>   #include "intel_region_ttm.h"
>   
> -/* A Zero-initialized driver for now. We don't have a TTM backend yet. */
> -static struct ttm_device_funcs i915_ttm_bo_driver;
> +extern struct ttm_device_funcs i915_ttm_bo_driver;
>   
>   /**
>    * DOC: TTM support structure
> @@ -198,6 +197,7 @@ struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
>   	return i915_sg_from_mm_node(node, mem->region.start);
>   }
>   
> +#ifdef CONFIG_DRM_I915_SELFTEST
>   /**
>    * intel_region_ttm_node_alloc - Allocate memory resources from a region
>    * @mem: The memory region,
> @@ -244,3 +244,4 @@ void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
>   		ret = -ENXIO;
>   	return ret ? ERR_PTR(ret) : res.mm_node;
>   }
> +#endif
> diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
> index 40129f7e0317..9a5b0437d73f 100644
> --- a/drivers/gpu/drm/i915/intel_region_ttm.h
> +++ b/drivers/gpu/drm/i915/intel_region_ttm.h
> @@ -21,9 +21,12 @@ void intel_region_ttm_fini(struct intel_memory_region *mem);
>   struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
>   					     void *node);
>   
> +void intel_region_ttm_node_free(struct intel_memory_region *mem,
> +				void *node);
> +
> +#ifdef CONFIG_DRM_I915_SELFTEST
>   void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
>   				  resource_size_t size,
>   				  unsigned int flags);
> -void intel_region_ttm_node_free(struct intel_memory_region *mem,
> -				void *node);
> +#endif
>   #endif /* _INTEL_REGION_TTM_H_ */
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 4479c55aaa1d..74004d5cbfa2 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -1150,6 +1150,14 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
>   		return -EBUSY;
>   	}
>   
> +	if (bo->bdev->funcs->swap_possible) {
> +		if (!bo->bdev->funcs->swap_possible(bo)) {
> +			if (locked)
> +				dma_resv_unlock(bo->base.resv);
> +			return -EBUSY;
> +		}
> +	}
> +
>   	if (bo->deleted) {
>   		ttm_bo_cleanup_refs(bo, false, false, locked);
>   		ttm_bo_put(bo);
> @@ -1200,6 +1208,10 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
>   	if (bo->bdev->funcs->swap_notify)
>   		bo->bdev->funcs->swap_notify(bo);
>   
> +	/* The call to swap_notify may have purged the bo */
> +	if (!bo->ttm)
> +		goto out;
> +
>   	ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags);
>   out:
>   
> diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h
> index 7c8f87bd52d3..7c59d35e90f9 100644
> --- a/include/drm/ttm/ttm_device.h
> +++ b/include/drm/ttm/ttm_device.h
> @@ -181,6 +181,15 @@ struct ttm_device_funcs {
>   	 */
>   	void (*delete_mem_notify)(struct ttm_buffer_object *bo);
>   
> +	/**
> +	 * struct ttm_bo_driver member swap_possible
> +	 *
> +	 * @bo: the buffer object to be evicted
> +	 *
> +	 * Check with the driver if it is possible to swap out a BO.
> +	 */
> +	bool (*swap_possible)(struct ttm_buffer_object *bo);
> +
>   	/**
>   	 * notify the driver that we're about to swap out this bo
>   	 */


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-11 13:58     ` Christian König
  0 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-11 13:58 UTC (permalink / raw)
  To: Thomas Hellström, intel-gfx, dri-devel

Am 11.05.21 um 15:25 schrieb Thomas Hellström:
> Most logical place to introduce TTM buffer objects is as an i915
> gem object backend. We need to add some ops to account for added
> functionality like delayed delete and LRU list manipulation.
>
> Initially we support only LMEM and SYSTEM memory, but SYSTEM
> (which in this case means evicted LMEM objects) is not
> visible to i915 GEM yet. The plan is to move the i915 gem system region
> over to the TTM system memory type in upcoming patches.
>
> We set up GPU bindings directly both from LMEM and from the system region,
> as there is no need to use the legacy TTM_TT memory type. We reserve
> that for future porting of GGTT bindings to TTM.
>
> There are some changes to TTM to allow for purging system memory buffer
> objects and to refuse swapping of some objects: Unfortunately i915 gem
> still relies heavily on short-term object pinning, and we've chosen to
> keep short-term-pinned buffer objects on the TTM LRU lists for now,
> meaning that we need some sort of mechanism to tell TTM they are not
> swappable. A longer term goal is to get rid of the short-term pinning.

Well just use the eviction_valuable interface for this.

In general please make separate patches for the TTM changes and for the 
i915 changes using them for easier review.

Christian.

>
> Remove the old lmem backend.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/Makefile                 |   1 +
>   drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
>   drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
>   drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
>   drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
>   .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
>   drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
>   drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
>   drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
>   drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
>   drivers/gpu/drm/i915/i915_gem.c               |   5 +-
>   drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
>   drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
>   drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
>   drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
>   drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
>   include/drm/ttm/ttm_device.h                  |   9 +
>   17 files changed, 733 insertions(+), 140 deletions(-)
>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 958ccc1edfed..ef0d884a9e2d 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -155,6 +155,7 @@ gem-y += \
>   	gem/i915_gem_stolen.o \
>   	gem/i915_gem_throttle.o \
>   	gem/i915_gem_tiling.o \
> +	gem/i915_gem_ttm.o \
>   	gem/i915_gem_ttm_bo_util.o \
>   	gem/i915_gem_userptr.o \
>   	gem/i915_gem_wait.o \
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index f42803ea48f2..2b8cd15de1d9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -4,73 +4,10 @@
>    */
>   
>   #include "intel_memory_region.h"
> -#include "intel_region_ttm.h"
>   #include "gem/i915_gem_region.h"
>   #include "gem/i915_gem_lmem.h"
>   #include "i915_drv.h"
>   
> -static void lmem_put_pages(struct drm_i915_gem_object *obj,
> -				  struct sg_table *pages)
> -{
> -	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
> -	obj->mm.dirty = false;
> -	sg_free_table(pages);
> -	kfree(pages);
> -}
> -
> -static int lmem_get_pages(struct drm_i915_gem_object *obj)
> -{
> -	unsigned int flags;
> -	struct sg_table *pages;
> -
> -	flags = I915_ALLOC_MIN_PAGE_SIZE;
> -	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> -		flags |= I915_ALLOC_CONTIGUOUS;
> -
> -	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
> -							 obj->base.size,
> -							 flags);
> -	if (IS_ERR(obj->mm.st_mm_node))
> -		return PTR_ERR(obj->mm.st_mm_node);
> -
> -	/* Range manager is always contigous */
> -	if (obj->mm.region->is_range_manager)
> -		obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> -	pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
> -	if (IS_ERR(pages))
> -		return PTR_ERR(pages);
> -
> -	__i915_gem_object_set_pages(obj, pages,
> -				    i915_sg_dma_page_sizes(pages->sgl));
> -
> -	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> -		void __iomem *vaddr =
> -			i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
> -
> -		if (!vaddr) {
> -			struct sg_table *pages =
> -				__i915_gem_object_unset_pages(obj);
> -
> -			if (!IS_ERR_OR_NULL(pages))
> -				lmem_put_pages(obj, pages);
> -		}
> -
> -		memset_io(vaddr, 0, obj->base.size);
> -		io_mapping_unmap(vaddr);
> -	}
> -
> -	return 0;
> -}
> -
> -const struct drm_i915_gem_object_ops i915_gem_lmem_obj_ops = {
> -	.name = "i915_gem_object_lmem",
> -	.flags = I915_GEM_OBJECT_HAS_IOMEM,
> -
> -	.get_pages = lmem_get_pages,
> -	.put_pages = lmem_put_pages,
> -	.release = i915_gem_object_release_memory_region,
> -};
> -
>   void __iomem *
>   i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
>   			    unsigned long n,
> @@ -102,23 +39,3 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
>   	return i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_LMEM],
>   					     size, flags);
>   }
> -
> -int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
> -				struct drm_i915_gem_object *obj,
> -				resource_size_t size,
> -				unsigned int flags)
> -{
> -	static struct lock_class_key lock_class;
> -	struct drm_i915_private *i915 = mem->i915;
> -
> -	drm_gem_private_object_init(&i915->drm, &obj->base, size);
> -	i915_gem_object_init(obj, &i915_gem_lmem_obj_ops, &lock_class, flags);
> -
> -	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
> -
> -	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
> -
> -	i915_gem_object_init_memory_region(obj, mem);
> -
> -	return 0;
> -}
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
> index fac6bc5a5ebb..ea76fd11ccb0 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h
> @@ -26,9 +26,4 @@ i915_gem_object_create_lmem(struct drm_i915_private *i915,
>   			    resource_size_t size,
>   			    unsigned int flags);
>   
> -int __i915_gem_lmem_object_init(struct intel_memory_region *mem,
> -				struct drm_i915_gem_object *obj,
> -				resource_size_t size,
> -				unsigned int flags);
> -
>   #endif /* !__I915_GEM_LMEM_H */
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> index c8953e3f5c70..c53488f391dd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> @@ -172,7 +172,7 @@ static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *f
>   	}
>   }
>   
> -static void __i915_gem_free_object_rcu(struct rcu_head *head)
> +void __i915_gem_free_object_rcu(struct rcu_head *head)
>   {
>   	struct drm_i915_gem_object *obj =
>   		container_of(head, typeof(*obj), rcu);
> @@ -208,59 +208,70 @@ static void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj)
>   	}
>   }
>   
> -static void __i915_gem_free_objects(struct drm_i915_private *i915,
> -				    struct llist_node *freed)
> +void __i915_gem_free_object(struct drm_i915_gem_object *obj)
>   {
> -	struct drm_i915_gem_object *obj, *on;
> +	trace_i915_gem_object_destroy(obj);
>   
> -	llist_for_each_entry_safe(obj, on, freed, freed) {
> -		trace_i915_gem_object_destroy(obj);
> +	if (!list_empty(&obj->vma.list)) {
> +		struct i915_vma *vma;
> +
> +		/*
> +		 * Note that the vma keeps an object reference while
> +		 * it is active, so it *should* not sleep while we
> +		 * destroy it. Our debug code errs insits it *might*.
> +		 * For the moment, play along.
> +		 */
> +		spin_lock(&obj->vma.lock);
> +		while ((vma = list_first_entry_or_null(&obj->vma.list,
> +						       struct i915_vma,
> +						       obj_link))) {
> +			GEM_BUG_ON(vma->obj != obj);
> +			spin_unlock(&obj->vma.lock);
>   
> -		if (!list_empty(&obj->vma.list)) {
> -			struct i915_vma *vma;
> +			__i915_vma_put(vma);
>   
> -			/*
> -			 * Note that the vma keeps an object reference while
> -			 * it is active, so it *should* not sleep while we
> -			 * destroy it. Our debug code errs insits it *might*.
> -			 * For the moment, play along.
> -			 */
>   			spin_lock(&obj->vma.lock);
> -			while ((vma = list_first_entry_or_null(&obj->vma.list,
> -							       struct i915_vma,
> -							       obj_link))) {
> -				GEM_BUG_ON(vma->obj != obj);
> -				spin_unlock(&obj->vma.lock);
> +		}
> +		spin_unlock(&obj->vma.lock);
> +	}
>   
> -				__i915_vma_put(vma);
> +	__i915_gem_object_free_mmaps(obj);
>   
> -				spin_lock(&obj->vma.lock);
> -			}
> -			spin_unlock(&obj->vma.lock);
> -		}
> +	GEM_BUG_ON(!list_empty(&obj->lut_list));
>   
> -		__i915_gem_object_free_mmaps(obj);
> +	atomic_set(&obj->mm.pages_pin_count, 0);
> +	__i915_gem_object_put_pages(obj);
> +	GEM_BUG_ON(i915_gem_object_has_pages(obj));
> +	bitmap_free(obj->bit_17);
>   
> -		GEM_BUG_ON(!list_empty(&obj->lut_list));
> +	if (obj->base.import_attach)
> +		drm_prime_gem_destroy(&obj->base, NULL);
>   
> -		atomic_set(&obj->mm.pages_pin_count, 0);
> -		__i915_gem_object_put_pages(obj);
> -		GEM_BUG_ON(i915_gem_object_has_pages(obj));
> -		bitmap_free(obj->bit_17);
> +	drm_gem_free_mmap_offset(&obj->base);
>   
> -		if (obj->base.import_attach)
> -			drm_prime_gem_destroy(&obj->base, NULL);
> +	if (obj->ops->release)
> +		obj->ops->release(obj);
>   
> -		drm_gem_free_mmap_offset(&obj->base);
> +	if (obj->mm.n_placements > 1)
> +		kfree(obj->mm.placements);
>   
> -		if (obj->ops->release)
> -			obj->ops->release(obj);
> +	if (obj->resv_shared_from)
> +		i915_vm_resv_put(obj->resv_shared_from);
>   
> -		if (obj->mm.n_placements > 1)
> -			kfree(obj->mm.placements);
> +}
> +
> +static void __i915_gem_free_objects(struct drm_i915_private *i915,
> +				    struct llist_node *freed)
> +{
> +	struct drm_i915_gem_object *obj, *on;
>   
> -		if (obj->resv_shared_from)
> -			i915_vm_resv_put(obj->resv_shared_from);
> +	llist_for_each_entry_safe(obj, on, freed, freed) {
> +		might_sleep();
> +		if (obj->ops->delayed_free) {
> +			obj->ops->delayed_free(obj);
> +			continue;
> +		}
> +		__i915_gem_free_object(obj);
>   
>   		/* But keep the pointer alive for RCU-protected lookups */
>   		call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
> @@ -318,6 +329,7 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj)
>   	 * worker and performing frees directly from subsequent allocations for
>   	 * crude but effective memory throttling.
>   	 */
> +
>   	if (llist_add(&obj->freed, &i915->mm.free_list))
>   		queue_work(i915->wq, &i915->mm.free_work);
>   }
> @@ -410,6 +422,42 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
>   	return 0;
>   }
>   
> +/**
> + * i915_gem_object_evictable - Whether object is likely evictable after unbind.
> + * @obj: The object to check
> + *
> + * This function checks whether the object is likely unvictable after unbind.
> + * If the object is not locked when checking, the result is only advisory.
> + * If the object is locked when checking, and the function returns true,
> + * then an eviction should indeed be possible. But since unlocked vma
> + * unpinning and unbinding is currently possible, the object can actually
> + * become evictable even if this function returns false.
> + *
> + * Return: true if the object may be evictable. False otherwise.
> + */
> +bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
> +{
> +	struct i915_vma *vma;
> +	int pin_count = atomic_read(&obj->mm.pages_pin_count);
> +
> +	if (!pin_count)
> +		return true;
> +
> +	spin_lock(&obj->vma.lock);
> +	list_for_each_entry(vma, &obj->vma.list, obj_link) {
> +		if (i915_vma_is_pinned(vma)) {
> +			spin_unlock(&obj->vma.lock);
> +			return false;
> +		}
> +		if (atomic_read(&vma->pages_count))
> +			pin_count--;
> +	}
> +	spin_unlock(&obj->vma.lock);
> +	GEM_WARN_ON(pin_count < 0);
> +
> +	return pin_count == 0;
> +}
> +
>   void i915_gem_init__objects(struct drm_i915_private *i915)
>   {
>   	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> index 2ebd79537aea..ae5930e307d5 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> @@ -200,6 +200,9 @@ static inline bool i915_gem_object_trylock(struct drm_i915_gem_object *obj)
>   
>   static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj)
>   {
> +	if (obj->ops->adjust_lru)
> +		obj->ops->adjust_lru(obj);
> +
>   	dma_resv_unlock(obj->base.resv);
>   }
>   
> @@ -587,6 +590,12 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
>   
>   bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj);
>   
> +void __i915_gem_free_object_rcu(struct rcu_head *head);
> +
> +void __i915_gem_free_object(struct drm_i915_gem_object *obj);
> +
> +bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
> +
>   #ifdef CONFIG_MMU_NOTIFIER
>   static inline bool
>   i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
> 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 98f69d8fd37d..b350765e1935 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
> @@ -63,6 +63,20 @@ struct drm_i915_gem_object_ops {
>   		      const struct drm_i915_gem_pwrite *arg);
>   
>   	int (*dmabuf_export)(struct drm_i915_gem_object *obj);
> +
> +	/**
> +	 * adjust_lru - notify that the madvise value was updated
> +	 * @obj: The gem object
> +	 *
> +	 * The madvise value may have been updated, or object was recently
> +	 * referenced so act accordingly (Perhaps changing an LRU list etc).
> +	 */
> +	void (*adjust_lru)(struct drm_i915_gem_object *obj);
> +
> +	/**
> +	 * delayed_free - Override the default delayed free implementation
> +	 */
> +	void (*delayed_free)(struct drm_i915_gem_object *obj);
>   	void (*release)(struct drm_i915_gem_object *obj);
>   
>   	const char *name; /* friendly name for debug, e.g. lockdep classes */
> @@ -307,6 +321,10 @@ struct drm_i915_gem_object {
>   		bool dirty:1;
>   	} mm;
>   
> +	struct {
> +		struct sg_table *cached_io_st;
> +	} ttm;
> +
>   	/** Record of address bit 17 of each page at last unbind. */
>   	unsigned long *bit_17;
>   
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
> index f25e6646c5b7..d1f1840540dd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
> @@ -18,11 +18,7 @@ void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
>   
>   	mutex_lock(&mem->objects.lock);
>   
> -	if (obj->flags & I915_BO_ALLOC_VOLATILE)
> -		list_add(&obj->mm.region_link, &mem->objects.purgeable);
> -	else
> -		list_add(&obj->mm.region_link, &mem->objects.list);
> -
> +	list_add(&obj->mm.region_link, &mem->objects.list);
>   	mutex_unlock(&mem->objects.lock);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> new file mode 100644
> index 000000000000..e3718c3cb299
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -0,0 +1,534 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +#include <drm/ttm/ttm_bo_driver.h>
> +#include <drm/ttm/ttm_placement.h>
> +
> +#include "i915_drv.h"
> +#include "intel_memory_region.h"
> +#include "intel_region_ttm.h"
> +
> +#include "gem/i915_gem_object.h"
> +#include "gem/i915_gem_region.h"
> +#include "gem/i915_gem_ttm.h"
> +#include "gem/i915_gem_ttm_bo_util.h"
> +
> +#define I915_PL_LMEM0 TTM_PL_PRIV
> +#define I915_PL_SYSTEM TTM_PL_SYSTEM
> +#define I915_PL_STOLEN TTM_PL_VRAM
> +#define I915_PL_GGTT TTM_PL_TT
> +
> +#define I915_TTM_PRIO_PURGE     0
> +#define I915_TTM_PRIO_NO_PAGES  1
> +#define I915_TTM_PRIO_HAS_PAGES 2
> +
> +/**
> + * struct i915_ttm_tt - TTM page vector with additional private information
> + * @ttm: The base TTM page vector.
> + * @dev: The struct device used for dma mapping and unmapping.
> + * @cached_st: The cached scatter-gather table.
> + *
> + * Note that DMA may be going on right up to the point where the page-
> + * vector is unpopulated in delayed destroy. Hence keep the
> + * scatter-gather table mapped and cached up to that point. This is
> + * different from the cached gem object io scatter-gather table which
> + * doesn't have an associated dma mapping.
> + */
> +struct i915_ttm_tt {
> +	struct ttm_tt ttm;
> +	struct device *dev;
> +	struct sg_table *cached_st;
> +};
> +
> +static const struct ttm_place lmem0_sys_placement_flags[] = {
> +	{
> +		.fpfn = 0,
> +		.lpfn = 0,
> +		.mem_type = I915_PL_LMEM0,
> +		.flags = 0,
> +	}, {
> +		.fpfn = 0,
> +		.lpfn = 0,
> +		.mem_type = I915_PL_SYSTEM,
> +		.flags = 0,
> +	}
> +};
> +
> +struct ttm_placement i915_lmem0_placement = {
> +	.num_placement = 1,
> +	.placement = &lmem0_sys_placement_flags[0],
> +	.num_busy_placement = 1,
> +	.busy_placement = &lmem0_sys_placement_flags[0],
> +};
> +
> +struct ttm_placement i915_lmem0_sys_placement = {
> +	.num_placement = 1,
> +	.placement = &lmem0_sys_placement_flags[0],
> +	.num_busy_placement = 2,
> +	.busy_placement = &lmem0_sys_placement_flags[0],
> +};
> +
> +struct ttm_placement i915_sys_placement = {
> +	.num_placement = 1,
> +	.placement = &lmem0_sys_placement_flags[1],
> +	.num_busy_placement = 1,
> +	.busy_placement = &lmem0_sys_placement_flags[1],
> +};
> +
> +static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj);
> +
> +static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
> +					 uint32_t page_flags)
> +{
> +	struct ttm_resource_manager *man =
> +		ttm_manager_type(bo->bdev, bo->mem.mem_type);
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	struct i915_ttm_tt *i915_tt;
> +	int ret;
> +
> +	i915_tt = kzalloc(sizeof(*i915_tt), GFP_KERNEL);
> +	if (!i915_tt)
> +		return NULL;
> +
> +	if (obj->flags & I915_BO_ALLOC_CPU_CLEAR &&
> +	    man->use_tt)
> +		page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC;
> +
> +	ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, ttm_cached);
> +	if (ret) {
> +		kfree(i915_tt);
> +		return NULL;
> +	}
> +
> +	i915_tt->dev = obj->base.dev->dev;
> +
> +	return &i915_tt->ttm;
> +}
> +
> +static void i915_ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
> +{
> +	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
> +
> +	if (i915_tt->cached_st) {
> +		dma_unmap_sgtable(i915_tt->dev, i915_tt->cached_st,
> +				  DMA_BIDIRECTIONAL, 0);
> +		sg_free_table(i915_tt->cached_st);
> +		kfree(i915_tt->cached_st);
> +		i915_tt->cached_st = NULL;
> +	}
> +	ttm_pool_free(&bdev->pool, ttm);
> +}
> +
> +static void i915_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
> +{
> +	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
> +
> +	ttm_tt_destroy_common(bdev, ttm);
> +	kfree(i915_tt);
> +}
> +
> +static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo,
> +				       const struct ttm_place *place)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +
> +	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
> +	if (!i915_gem_object_evictable(obj))
> +		return false;
> +
> +	/* This isn't valid with a buddy allocator */
> +	return ttm_bo_eviction_valuable(bo, place);
> +}
> +
> +static void i915_ttm_evict_flags(struct ttm_buffer_object *bo,
> +				 struct ttm_placement *placement)
> +{
> +	*placement = i915_sys_placement;
> +}
> +
> +static int i915_ttm_move_notify(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	int ret;
> +
> +	ret = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE);
> +	if (ret)
> +		return ret;
> +
> +	ret = __i915_gem_object_put_pages(obj);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void i915_ttm_free_cached_io_st(struct drm_i915_gem_object *obj)
> +{
> +	if (obj->ttm.cached_io_st) {
> +		sg_free_table(obj->ttm.cached_io_st);
> +		kfree(obj->ttm.cached_io_st);
> +		obj->ttm.cached_io_st = NULL;
> +	}
> +}
> +
> +static void i915_ttm_purge(struct drm_i915_gem_object *obj)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +
> +	if (obj->mm.madv == __I915_MADV_PURGED)
> +		return;
> +
> +	i915_ttm_free_cached_io_st(obj);
> +
> +	ttm_resource_free(bo, &bo->mem);
> +	if (bo->ttm)
> +		ttm_bo_tt_destroy(bo);
> +
> +	obj->mm.madv = __I915_MADV_PURGED;
> +}
> +
> +static bool i915_ttm_swap_possible(struct ttm_buffer_object *bo)
> +{
> +	/* Will do for now. Our pinned objects are still on TTM's LRU lists */
> +	return i915_gem_object_evictable(i915_ttm_to_gem(bo));
> +}
> +
> +static void i915_ttm_swap_notify(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	int ret = i915_ttm_move_notify(bo);
> +
> +	GEM_WARN_ON(ret);
> +	GEM_WARN_ON(obj->ttm.cached_io_st);
> +	if (!ret && obj->mm.madv != I915_MADV_WILLNEED)
> +		i915_ttm_purge(obj);
> +}
> +
> +static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +
> +	if (likely(obj)) {
> +		/* This releases all gem object bindings to the backend. */
> +		__i915_gem_free_object(obj);
> +	}
> +}
> +
> +static struct intel_memory_region *
> +i915_ttm_region(struct ttm_device *bdev, int ttm_mem_type)
> +{
> +	struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
> +
> +	/* There's some room for optimization here... */
> +	GEM_BUG_ON(ttm_mem_type != I915_PL_SYSTEM &&
> +		   ttm_mem_type < I915_PL_LMEM0);
> +	if (ttm_mem_type == I915_PL_SYSTEM)
> +		return intel_memory_region_lookup(i915, INTEL_MEMORY_SYSTEM,
> +						  0);
> +
> +	return intel_memory_region_lookup(i915, INTEL_MEMORY_LOCAL,
> +					  ttm_mem_type - I915_PL_LMEM0);
> +}
> +
> +static struct sg_table *i915_ttm_tt_get_st(struct ttm_tt *ttm)
> +{
> +	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
> +	struct scatterlist *sg;
> +	struct sg_table *st;
> +	int ret;
> +
> +	if (i915_tt->cached_st)
> +		return i915_tt->cached_st;
> +
> +	st = kzalloc(sizeof(*st), GFP_KERNEL);
> +	if (!st)
> +		return ERR_PTR(-ENOMEM);
> +
> +	sg = __sg_alloc_table_from_pages
> +		(st, ttm->pages, ttm->num_pages, 0,
> +		 (unsigned long) ttm->num_pages << PAGE_SHIFT,
> +		 i915_sg_segment_size(), NULL, 0, GFP_KERNEL);
> +	if (IS_ERR(sg)) {
> +		kfree(st);
> +		return ERR_CAST(sg);
> +	}
> +
> +	ret = dma_map_sgtable(i915_tt->dev, st, DMA_BIDIRECTIONAL, 0);
> +	if (ret) {
> +		sg_free_table(st);
> +		kfree(st);
> +		return ERR_PTR(ret);
> +	}
> +
> +	i915_tt->cached_st = st;
> +	return st;
> +}
> +
> +static struct sg_table *
> +i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
> +			 struct ttm_resource *res)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +	struct ttm_resource_manager *man =
> +		ttm_manager_type(bo->bdev, res->mem_type);
> +	struct sg_table *st;
> +
> +	if (man->use_tt)
> +		return i915_ttm_tt_get_st(bo->ttm);
> +
> +	st = kzalloc(sizeof(*st), GFP_KERNEL);
> +	if (!st)
> +		return ERR_PTR(-ENOMEM);
> +
> +	st = intel_region_ttm_node_to_st(obj->mm.region, res->mm_node);
> +	if (IS_ERR(st))
> +		return ERR_CAST(st);
> +
> +	return st;
> +}
> +
> +static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
> +			 struct ttm_operation_ctx *ctx,
> +			 struct ttm_resource *new_mem,
> +			 struct ttm_place *hop)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +	struct ttm_resource_manager *new_man =
> +		ttm_manager_type(bo->bdev, new_mem->mem_type);
> +	struct ttm_resource_manager *old_man =
> +		ttm_manager_type(bo->bdev, bo->mem.mem_type);
> +	struct intel_memory_region *new_reg, *old_reg;
> +	union {
> +		struct i915_ttm_kmap_iter_tt tt;
> +		struct i915_ttm_kmap_iter_iomap io;
> +	} _new_iter, _old_iter;
> +	struct i915_ttm_kmap_iter *new_iter, *old_iter;
> +	struct sg_table *new_st;
> +	int ret;
> +
> +	new_reg = i915_ttm_region(bo->bdev, new_mem->mem_type);
> +	old_reg = i915_ttm_region(bo->bdev, bo->mem.mem_type);
> +	GEM_BUG_ON(!new_reg || !old_reg);
> +
> +	/* Sync for now. We could do the actual copy async. */
> +	ret = ttm_bo_wait_ctx(bo, ctx);
> +	if (ret)
> +		return ret;
> +
> +	ret = i915_ttm_move_notify(bo);
> +	if (ret)
> +		return ret;
> +
> +	if (obj->mm.madv != I915_MADV_WILLNEED) {
> +		i915_ttm_purge(obj);
> +		ttm_resource_free(bo, new_mem);
> +		return 0;
> +	}
> +
> +	/* Populate ttm with pages if needed. Typically system memory. */
> +	if (new_man->use_tt && bo->ttm) {
> +		ret = ttm_tt_populate(bo->bdev, bo->ttm, ctx);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	new_st = i915_ttm_resource_get_st(obj, new_mem);
> +	if (IS_ERR(new_st))
> +		return PTR_ERR(new_st);
> +
> +	new_iter = new_man->use_tt ?
> +		i915_ttm_kmap_iter_tt_init(&_new_iter.tt, bo->ttm) :
> +		i915_ttm_kmap_iter_iomap_init(&_new_iter.io, &new_reg->iomap,
> +					      new_st, new_reg->region.start);
> +
> +	old_iter = old_man->use_tt ?
> +		i915_ttm_kmap_iter_tt_init(&_old_iter.tt, bo->ttm) :
> +		i915_ttm_kmap_iter_iomap_init(&_old_iter.io, &old_reg->iomap,
> +					      obj->ttm.cached_io_st,
> +					      old_reg->region.start);
> +
> +	i915_ttm_move_memcpy(bo, new_mem, new_iter, old_iter);
> +	i915_ttm_free_cached_io_st(obj);
> +
> +	if (!new_man->use_tt)
> +		obj->ttm.cached_io_st = new_st;
> +
> +	return 0;
> +}
> +
> +struct ttm_device_funcs i915_ttm_bo_driver = {
> +	.ttm_tt_create = i915_ttm_tt_create,
> +	.ttm_tt_unpopulate = i915_ttm_tt_unpopulate,
> +	.ttm_tt_destroy = i915_ttm_tt_destroy,
> +	.eviction_valuable = i915_ttm_eviction_valuable,
> +	.evict_flags = i915_ttm_evict_flags,
> +	.move = i915_ttm_move,
> +	.verify_access = NULL,
> +	.swap_possible = i915_ttm_swap_possible,
> +	.swap_notify = i915_ttm_swap_notify,
> +	.delete_mem_notify = i915_ttm_delete_mem_notify,
> +};
> +
> +static int i915_ttm_get_pages(struct drm_i915_gem_object *obj)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +	struct ttm_operation_ctx ctx = {
> +		.interruptible = true,
> +		.no_wait_gpu = false,
> +	};
> +	struct sg_table *st;
> +	int ret;
> +
> +	/* Swap in. */
> +	if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
> +		ret = ttm_tt_populate(bo->bdev, bo->ttm, &ctx);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	/* Move to the requested placement. */
> +	ret = ttm_bo_validate(bo, &i915_lmem0_placement, &ctx);
> +	if (ret)
> +		return ret;
> +
> +	/* Object either has a page vector or is an iomem object */
> +	st = bo->ttm ? i915_ttm_tt_get_st(bo->ttm) : obj->ttm.cached_io_st;
> +	if (IS_ERR(st))
> +		return PTR_ERR(st);
> +
> +	__i915_gem_object_set_pages(obj, st, i915_sg_dma_page_sizes(st->sgl));
> +
> +	i915_ttm_adjust_lru(obj);
> +
> +	return ret;
> +}
> +
> +static void i915_ttm_put_pages(struct drm_i915_gem_object *obj,
> +			       struct sg_table *st)
> +{
> +	/*
> +	 * We're currently not called from a shrinker, so put_pages()
> +	 * typically means the object is about to destroyed, or called
> +	 * from move_notify(). So just avoid doing much for now.
> +	 * If the object is not destroyed next, The TTM eviction logic
> +	 * and shrinkers will move it out if needed.
> +	 */
> +
> +	i915_ttm_adjust_lru(obj);
> +}
> +
> +static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj)
> +{
> +	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +
> +	/*
> +	 * Don't manipulate the TTM LRUs while in TTM bo destruction.
> +	 * We're called through i915_ttm_delete_mem_notify().
> +	 */
> +	if (!kref_read(&bo->kref))
> +		return;
> +
> +	/*
> +	 * Put on the correct LRU list depending on the MADV status
> +	 */
> +	spin_lock(&bo->bdev->lru_lock);
> +	if (obj->mm.madv != I915_MADV_WILLNEED) {
> +		bo->priority = I915_TTM_PRIO_PURGE;
> +	} else if (!i915_gem_object_has_pages(obj)) {
> +		if (bo->priority < I915_TTM_PRIO_HAS_PAGES)
> +			bo->priority = I915_TTM_PRIO_HAS_PAGES;
> +	} else {
> +		if (bo->priority > I915_TTM_PRIO_NO_PAGES)
> +			bo->priority = I915_TTM_PRIO_NO_PAGES;
> +	}
> +
> +	ttm_bo_move_to_lru_tail(bo, &bo->mem, NULL);
> +	spin_unlock(&bo->bdev->lru_lock);
> +}
> +
> +/*
> + * TTM-backed gem object destruction requires some clarification.
> + * Basically we have two possibilities here. We can either rely on the
> + * i915 delayed destruction and put the TTM object when the object
> + * is idle. This would be detected by TTM which would bypass the
> + * TTM delayed destroy handling. The other approach is to put the TTM
> + * object early and rely on the TTM destroyed handling, and then free
> + * the leftover parts of the GEM object once TTM's destroyed list handling is
> + * complete. For now, we rely on the latter for two reasons:
> + * a) TTM can evict an object even when it's on the delayed destroy list,
> + * which in theory allows for complete eviction.
> + * b) There is work going on in TTM to allow freeing an object even when
> + * it's not idle, and using the TTM destroyed list handling could help us
> + * benefit from that.
> + */
> +static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj)
> +{
> +	ttm_bo_put(i915_gem_to_ttm(obj));
> +}
> +
> +static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = {
> +	.name = "i915_gem_object_ttm",
> +	.flags = I915_GEM_OBJECT_HAS_IOMEM,
> +
> +	.get_pages = i915_ttm_get_pages,
> +	.put_pages = i915_ttm_put_pages,
> +	.truncate = i915_ttm_purge,
> +	.adjust_lru = i915_ttm_adjust_lru,
> +	.delayed_free = i915_ttm_delayed_free,
> +};
> +
> +void i915_ttm_bo_destroy(struct ttm_buffer_object *bo)
> +{
> +	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
> +
> +	i915_gem_object_release_memory_region(obj);
> +	call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
> +}
> +
> +/**
> + * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
> + * @mem: The initial memory region for the object.
> + * @obj: The gem object.
> + * @size: Object size in bytes.
> + * @flags: gem object flags.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
> +			       struct drm_i915_gem_object *obj,
> +			       resource_size_t size,
> +			       unsigned int flags)
> +{
> +	static struct lock_class_key lock_class;
> +	struct drm_i915_private *i915 = mem->i915;
> +	size_t alignment = 0;
> +	int ret;
> +
> +	/* Adjust alignment to GPU- and CPU huge page sizes. */
> +
> +	if (mem->is_range_manager) {
> +		if (size >= SZ_1G)
> +			alignment = SZ_1G >> PAGE_SHIFT;
> +		else if (size >= SZ_2M)
> +			alignment = SZ_2M >> PAGE_SHIFT;
> +		else if (size >= SZ_64K)
> +			alignment = SZ_64K >> PAGE_SHIFT;
> +	}
> +
> +	drm_gem_private_object_init(&i915->drm, &obj->base, size);
> +	i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
> +	i915_gem_object_init_memory_region(obj, mem);
> +	i915_gem_object_make_unshrinkable(obj);
> +
> +	ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
> +			  ttm_bo_type_kernel, &i915_sys_placement, alignment,
> +			  true, NULL, NULL, i915_ttm_bo_destroy);
> +
> +	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
> +
> +	i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
> new file mode 100644
> index 000000000000..b8d3dcbb50df
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +#ifndef _I915_GEM_TTM_H_
> +#define _I915_GEM_TTM_H_
> +
> +#include "gem/i915_gem_object_types.h"
> +
> +/**
> + * i915_gem_to_ttm - Convert a struct drm_i915_gem_object to a
> + * struct ttm_buffer_object.
> + * @obj: Pointer to the gem object.
> + *
> + * Return: Pointer to the embedded struct ttm_buffer_object.
> + */
> +static inline struct ttm_buffer_object *
> +i915_gem_to_ttm(struct drm_i915_gem_object *obj)
> +{
> +	return &obj->__do_not_access;
> +}
> +
> +/*
> + * i915 ttm gem object destructor. Internal use only.
> + */
> +void i915_ttm_bo_destroy(struct ttm_buffer_object *bo);
> +
> +/**
> + * i915_ttm_to_gem - Convert a struct ttm_buffer_object to an embedding
> + * struct drm_i915_gem_object.
> + *
> + * Return: Pointer to the embedding struct ttm_buffer_object, or NULL
> + * if the object was not an i915 ttm object.
> + */
> +static inline struct drm_i915_gem_object *
> +i915_ttm_to_gem(struct ttm_buffer_object *bo)
> +{
> +	if (GEM_WARN_ON(bo->destroy != i915_ttm_bo_destroy))
> +		return NULL;
> +
> +	return container_of(bo, struct drm_i915_gem_object, __do_not_access);
> +}
> +
> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
> +			       struct drm_i915_gem_object *obj,
> +			       resource_size_t size,
> +			       unsigned int flags);
> +#endif
> diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
> index f7366b054f8e..4ae1f717a94c 100644
> --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c
> +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c
> @@ -9,6 +9,7 @@
>   #include "intel_region_ttm.h"
>   #include "gem/i915_gem_lmem.h"
>   #include "gem/i915_gem_region.h"
> +#include "gem/i915_gem_ttm.h"
>   #include "intel_region_lmem.h"
>   
>   static int init_fake_lmem_bar(struct intel_memory_region *mem)
> @@ -107,7 +108,7 @@ region_lmem_init(struct intel_memory_region *mem)
>   static const struct intel_memory_region_ops intel_region_lmem_ops = {
>   	.init = region_lmem_init,
>   	.release = region_lmem_release,
> -	.init_object = __i915_gem_lmem_object_init,
> +	.init_object = __i915_gem_ttm_object_init,
>   };
>   
>   struct intel_memory_region *
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 180f6e9107d4..350283ab9a83 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -1005,8 +1005,11 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
>   		}
>   	}
>   
> -	if (obj->mm.madv != __I915_MADV_PURGED)
> +	if (obj->mm.madv != __I915_MADV_PURGED) {
>   		obj->mm.madv = args->madv;
> +		if (obj->ops->adjust_lru)
> +			obj->ops->adjust_lru(obj);
> +	}
>   
>   	if (i915_gem_object_has_pages(obj)) {
>   		struct list_head *list;
> diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
> index 4092cc987679..bd27e897d4d0 100644
> --- a/drivers/gpu/drm/i915/intel_memory_region.c
> +++ b/drivers/gpu/drm/i915/intel_memory_region.c
> @@ -149,7 +149,6 @@ intel_memory_region_create(struct drm_i915_private *i915,
>   
>   	mutex_init(&mem->objects.lock);
>   	INIT_LIST_HEAD(&mem->objects.list);
> -	INIT_LIST_HEAD(&mem->objects.purgeable);
>   	INIT_LIST_HEAD(&mem->reserved);
>   
>   	mutex_init(&mem->mm_lock);
> diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
> index e69cde13daf2..7b5fa97c0b59 100644
> --- a/drivers/gpu/drm/i915/intel_memory_region.h
> +++ b/drivers/gpu/drm/i915/intel_memory_region.h
> @@ -100,7 +100,6 @@ struct intel_memory_region {
>   	struct {
>   		struct mutex lock; /* Protects access to objects */
>   		struct list_head list;
> -		struct list_head purgeable;
>   	} objects;
>   
>   	size_t chunk_size;
> diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
> index 3bd9caa60298..a74cae4602b5 100644
> --- a/drivers/gpu/drm/i915/intel_region_ttm.c
> +++ b/drivers/gpu/drm/i915/intel_region_ttm.c
> @@ -10,8 +10,7 @@
>   
>   #include "intel_region_ttm.h"
>   
> -/* A Zero-initialized driver for now. We don't have a TTM backend yet. */
> -static struct ttm_device_funcs i915_ttm_bo_driver;
> +extern struct ttm_device_funcs i915_ttm_bo_driver;
>   
>   /**
>    * DOC: TTM support structure
> @@ -198,6 +197,7 @@ struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
>   	return i915_sg_from_mm_node(node, mem->region.start);
>   }
>   
> +#ifdef CONFIG_DRM_I915_SELFTEST
>   /**
>    * intel_region_ttm_node_alloc - Allocate memory resources from a region
>    * @mem: The memory region,
> @@ -244,3 +244,4 @@ void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
>   		ret = -ENXIO;
>   	return ret ? ERR_PTR(ret) : res.mm_node;
>   }
> +#endif
> diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
> index 40129f7e0317..9a5b0437d73f 100644
> --- a/drivers/gpu/drm/i915/intel_region_ttm.h
> +++ b/drivers/gpu/drm/i915/intel_region_ttm.h
> @@ -21,9 +21,12 @@ void intel_region_ttm_fini(struct intel_memory_region *mem);
>   struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
>   					     void *node);
>   
> +void intel_region_ttm_node_free(struct intel_memory_region *mem,
> +				void *node);
> +
> +#ifdef CONFIG_DRM_I915_SELFTEST
>   void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
>   				  resource_size_t size,
>   				  unsigned int flags);
> -void intel_region_ttm_node_free(struct intel_memory_region *mem,
> -				void *node);
> +#endif
>   #endif /* _INTEL_REGION_TTM_H_ */
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 4479c55aaa1d..74004d5cbfa2 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -1150,6 +1150,14 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
>   		return -EBUSY;
>   	}
>   
> +	if (bo->bdev->funcs->swap_possible) {
> +		if (!bo->bdev->funcs->swap_possible(bo)) {
> +			if (locked)
> +				dma_resv_unlock(bo->base.resv);
> +			return -EBUSY;
> +		}
> +	}
> +
>   	if (bo->deleted) {
>   		ttm_bo_cleanup_refs(bo, false, false, locked);
>   		ttm_bo_put(bo);
> @@ -1200,6 +1208,10 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
>   	if (bo->bdev->funcs->swap_notify)
>   		bo->bdev->funcs->swap_notify(bo);
>   
> +	/* The call to swap_notify may have purged the bo */
> +	if (!bo->ttm)
> +		goto out;
> +
>   	ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags);
>   out:
>   
> diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h
> index 7c8f87bd52d3..7c59d35e90f9 100644
> --- a/include/drm/ttm/ttm_device.h
> +++ b/include/drm/ttm/ttm_device.h
> @@ -181,6 +181,15 @@ struct ttm_device_funcs {
>   	 */
>   	void (*delete_mem_notify)(struct ttm_buffer_object *bo);
>   
> +	/**
> +	 * struct ttm_bo_driver member swap_possible
> +	 *
> +	 * @bo: the buffer object to be evicted
> +	 *
> +	 * Check with the driver if it is possible to swap out a BO.
> +	 */
> +	bool (*swap_possible)(struct ttm_buffer_object *bo);
> +
>   	/**
>   	 * notify the driver that we're about to swap out this bo
>   	 */

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-11 13:58     ` [Intel-gfx] " Christian König
@ 2021-05-11 14:06       ` Thomas Hellström (Intel)
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström (Intel) @ 2021-05-11 14:06 UTC (permalink / raw)
  To: Christian König, Thomas Hellström, intel-gfx, dri-devel


On 5/11/21 3:58 PM, Christian König wrote:
> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>> Most logical place to introduce TTM buffer objects is as an i915
>> gem object backend. We need to add some ops to account for added
>> functionality like delayed delete and LRU list manipulation.
>>
>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>> (which in this case means evicted LMEM objects) is not
>> visible to i915 GEM yet. The plan is to move the i915 gem system region
>> over to the TTM system memory type in upcoming patches.
>>
>> We set up GPU bindings directly both from LMEM and from the system 
>> region,
>> as there is no need to use the legacy TTM_TT memory type. We reserve
>> that for future porting of GGTT bindings to TTM.
>>
>> There are some changes to TTM to allow for purging system memory buffer
>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>> still relies heavily on short-term object pinning, and we've chosen to
>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>> meaning that we need some sort of mechanism to tell TTM they are not
>> swappable. A longer term goal is to get rid of the short-term pinning.
>
> Well just use the eviction_valuable interface for this.

Yes, we do that for vram/lmem eviction, but we have nothing similar for 
system swapping. Do I understand you correctly that you want me to add a 
call to eviction_valuable() also for that instead of swap_possible()?


>
> In general please make separate patches for the TTM changes and for 
> the i915 changes using them for easier review.

I'll respin with a split. Do you want me to do the same also for the 
other two patches that minmally touch TTM?

Thanks,

Thomas



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-11 14:06       ` Thomas Hellström (Intel)
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström (Intel) @ 2021-05-11 14:06 UTC (permalink / raw)
  To: Christian König, Thomas Hellström, intel-gfx, dri-devel


On 5/11/21 3:58 PM, Christian König wrote:
> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>> Most logical place to introduce TTM buffer objects is as an i915
>> gem object backend. We need to add some ops to account for added
>> functionality like delayed delete and LRU list manipulation.
>>
>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>> (which in this case means evicted LMEM objects) is not
>> visible to i915 GEM yet. The plan is to move the i915 gem system region
>> over to the TTM system memory type in upcoming patches.
>>
>> We set up GPU bindings directly both from LMEM and from the system 
>> region,
>> as there is no need to use the legacy TTM_TT memory type. We reserve
>> that for future porting of GGTT bindings to TTM.
>>
>> There are some changes to TTM to allow for purging system memory buffer
>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>> still relies heavily on short-term object pinning, and we've chosen to
>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>> meaning that we need some sort of mechanism to tell TTM they are not
>> swappable. A longer term goal is to get rid of the short-term pinning.
>
> Well just use the eviction_valuable interface for this.

Yes, we do that for vram/lmem eviction, but we have nothing similar for 
system swapping. Do I understand you correctly that you want me to add a 
call to eviction_valuable() also for that instead of swap_possible()?


>
> In general please make separate patches for the TTM changes and for 
> the i915 changes using them for easier review.

I'll respin with a split. Do you want me to do the same also for the 
other two patches that minmally touch TTM?

Thanks,

Thomas


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-11 14:06       ` [Intel-gfx] " Thomas Hellström (Intel)
@ 2021-05-11 14:09         ` Christian König
  -1 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-11 14:09 UTC (permalink / raw)
  To: Thomas Hellström (Intel),
	Thomas Hellström, intel-gfx, dri-devel



Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>
> On 5/11/21 3:58 PM, Christian König wrote:
>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>> Most logical place to introduce TTM buffer objects is as an i915
>>> gem object backend. We need to add some ops to account for added
>>> functionality like delayed delete and LRU list manipulation.
>>>
>>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>>> (which in this case means evicted LMEM objects) is not
>>> visible to i915 GEM yet. The plan is to move the i915 gem system region
>>> over to the TTM system memory type in upcoming patches.
>>>
>>> We set up GPU bindings directly both from LMEM and from the system 
>>> region,
>>> as there is no need to use the legacy TTM_TT memory type. We reserve
>>> that for future porting of GGTT bindings to TTM.
>>>
>>> There are some changes to TTM to allow for purging system memory buffer
>>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>>> still relies heavily on short-term object pinning, and we've chosen to
>>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>>> meaning that we need some sort of mechanism to tell TTM they are not
>>> swappable. A longer term goal is to get rid of the short-term pinning.
>>
>> Well just use the eviction_valuable interface for this.
>
> Yes, we do that for vram/lmem eviction, but we have nothing similar 
> for system swapping. Do I understand you correctly that you want me to 
> add a call to eviction_valuable() also for that instead of 
> swap_possible()?

You should already have that. eviction_valuable is called in both cases.

>
>
>>
>> In general please make separate patches for the TTM changes and for 
>> the i915 changes using them for easier review.
>
> I'll respin with a split. Do you want me to do the same also for the 
> other two patches that minmally touch TTM?

Yes, that makes it much easier to review the general usefulness of 
interface changes.

Thanks,
Christian.

>
> Thanks,
>
> Thomas
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-11 14:09         ` Christian König
  0 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-11 14:09 UTC (permalink / raw)
  To: Thomas Hellström (Intel),
	Thomas Hellström, intel-gfx, dri-devel



Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>
> On 5/11/21 3:58 PM, Christian König wrote:
>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>> Most logical place to introduce TTM buffer objects is as an i915
>>> gem object backend. We need to add some ops to account for added
>>> functionality like delayed delete and LRU list manipulation.
>>>
>>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>>> (which in this case means evicted LMEM objects) is not
>>> visible to i915 GEM yet. The plan is to move the i915 gem system region
>>> over to the TTM system memory type in upcoming patches.
>>>
>>> We set up GPU bindings directly both from LMEM and from the system 
>>> region,
>>> as there is no need to use the legacy TTM_TT memory type. We reserve
>>> that for future porting of GGTT bindings to TTM.
>>>
>>> There are some changes to TTM to allow for purging system memory buffer
>>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>>> still relies heavily on short-term object pinning, and we've chosen to
>>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>>> meaning that we need some sort of mechanism to tell TTM they are not
>>> swappable. A longer term goal is to get rid of the short-term pinning.
>>
>> Well just use the eviction_valuable interface for this.
>
> Yes, we do that for vram/lmem eviction, but we have nothing similar 
> for system swapping. Do I understand you correctly that you want me to 
> add a call to eviction_valuable() also for that instead of 
> swap_possible()?

You should already have that. eviction_valuable is called in both cases.

>
>
>>
>> In general please make separate patches for the TTM changes and for 
>> the i915 changes using them for easier review.
>
> I'll respin with a split. Do you want me to do the same also for the 
> other two patches that minmally touch TTM?

Yes, that makes it much easier to review the general usefulness of 
interface changes.

Thanks,
Christian.

>
> Thanks,
>
> Thomas
>
>

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-11 14:09         ` [Intel-gfx] " Christian König
@ 2021-05-11 14:28           ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 14:28 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel


On 5/11/21 4:09 PM, Christian König wrote:
>
>
> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>
>> On 5/11/21 3:58 PM, Christian König wrote:
>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>> Most logical place to introduce TTM buffer objects is as an i915
>>>> gem object backend. We need to add some ops to account for added
>>>> functionality like delayed delete and LRU list manipulation.
>>>>
>>>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>>>> (which in this case means evicted LMEM objects) is not
>>>> visible to i915 GEM yet. The plan is to move the i915 gem system 
>>>> region
>>>> over to the TTM system memory type in upcoming patches.
>>>>
>>>> We set up GPU bindings directly both from LMEM and from the system 
>>>> region,
>>>> as there is no need to use the legacy TTM_TT memory type. We reserve
>>>> that for future porting of GGTT bindings to TTM.
>>>>
>>>> There are some changes to TTM to allow for purging system memory 
>>>> buffer
>>>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>>>> still relies heavily on short-term object pinning, and we've chosen to
>>>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>>>> meaning that we need some sort of mechanism to tell TTM they are not
>>>> swappable. A longer term goal is to get rid of the short-term pinning.
>>>
>>> Well just use the eviction_valuable interface for this.
>>
>> Yes, we do that for vram/lmem eviction, but we have nothing similar 
>> for system swapping. Do I understand you correctly that you want me 
>> to add a call to eviction_valuable() also for that instead of 
>> swap_possible()?
>
> You should already have that. eviction_valuable is called in both cases.
>
Hmm. I can only see it called from ttm_mem_evict_first() which is not in 
the swapping path? Or do I miss something?

Thanks,

Thomas




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-11 14:28           ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-11 14:28 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel


On 5/11/21 4:09 PM, Christian König wrote:
>
>
> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>
>> On 5/11/21 3:58 PM, Christian König wrote:
>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>> Most logical place to introduce TTM buffer objects is as an i915
>>>> gem object backend. We need to add some ops to account for added
>>>> functionality like delayed delete and LRU list manipulation.
>>>>
>>>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>>>> (which in this case means evicted LMEM objects) is not
>>>> visible to i915 GEM yet. The plan is to move the i915 gem system 
>>>> region
>>>> over to the TTM system memory type in upcoming patches.
>>>>
>>>> We set up GPU bindings directly both from LMEM and from the system 
>>>> region,
>>>> as there is no need to use the legacy TTM_TT memory type. We reserve
>>>> that for future porting of GGTT bindings to TTM.
>>>>
>>>> There are some changes to TTM to allow for purging system memory 
>>>> buffer
>>>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>>>> still relies heavily on short-term object pinning, and we've chosen to
>>>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>>>> meaning that we need some sort of mechanism to tell TTM they are not
>>>> swappable. A longer term goal is to get rid of the short-term pinning.
>>>
>>> Well just use the eviction_valuable interface for this.
>>
>> Yes, we do that for vram/lmem eviction, but we have nothing similar 
>> for system swapping. Do I understand you correctly that you want me 
>> to add a call to eviction_valuable() also for that instead of 
>> swap_possible()?
>
> You should already have that. eviction_valuable is called in both cases.
>
Hmm. I can only see it called from ttm_mem_evict_first() which is not in 
the swapping path? Or do I miss something?

Thanks,

Thomas



_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Move LMEM (VRAM) management over to TTM
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
                   ` (7 preceding siblings ...)
  (?)
@ 2021-05-11 16:21 ` Patchwork
  -1 siblings, 0 replies; 55+ messages in thread
From: Patchwork @ 2021-05-11 16:21 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Move LMEM (VRAM) management over to TTM
URL   : https://patchwork.freedesktop.org/series/90022/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
7c8e78644333 drm/i915: Untangle the vma pages_mutex
e148e51b2187 drm/i915: Don't free shared locks while shared
08fe6c5181ab drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
-:69: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#69: FILE: drivers/gpu/drm/i915/gem/i915_gem_lmem.c:13:
+static void lmem_put_pages(struct drm_i915_gem_object *obj,
+				  struct sg_table *pages)

-:484: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#484: 
deleted file mode 100644

-:1818: CHECK:LINE_SPACING: Please don't use multiple blank lines
#1818: FILE: drivers/gpu/drm/i915/intel_region_ttm.c:145:
+
+

total: 0 errors, 1 warnings, 2 checks, 1636 lines checked
7dc5b6bf9897 drm/i915/ttm: Embed a ttm buffer object in the i915 gem object
1cd13783b35c drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
-:43: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#43: 
new file mode 100644

-:157: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "!ttm"
#157: FILE: drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c:110:
+	    (ttm == NULL || !ttm_tt_is_populated(ttm))) {

total: 0 errors, 1 warnings, 1 checks, 307 lines checked
1bdd626f1990 drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
-:266: CHECK:BRACES: Blank lines aren't necessary before a close brace '}'
#266: FILE: drivers/gpu/drm/i915/gem/i915_gem_object.c:261:
 
+}

-:417: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#417: 
new file mode 100644

-:672: CHECK:SPACING: No space is necessary after a cast
#672: FILE: drivers/gpu/drm/i915/gem/i915_gem_ttm.c:251:
+		 (unsigned long) ttm->num_pages << PAGE_SHIFT,

total: 0 errors, 1 warnings, 2 checks, 1016 lines checked
bd0a5cd14b4e drm/i915/lmem: Verify checks for lmem residency


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for drm/i915: Move LMEM (VRAM) management over to TTM
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
                   ` (8 preceding siblings ...)
  (?)
@ 2021-05-11 16:24 ` Patchwork
  -1 siblings, 0 replies; 55+ messages in thread
From: Patchwork @ 2021-05-11 16:24 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Move LMEM (VRAM) management over to TTM
URL   : https://patchwork.freedesktop.org/series/90022/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+./drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgv_sriovmsg.h:274:49: error: static assertion failed: "amd_sriov_msg_pf2vf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1345:25: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1345:25:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1345:25:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1346:17: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1346:17:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1346:17:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1405:17: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1405:17:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1405:17:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:287:16: error: incompatible types in comparison expression (different type sizes):
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:287:16:    unsigned long *
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:287:16:    unsigned long long *
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:274:25: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:274:25:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:274:25:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:275:17: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:275:17:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:275:17:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:329:17: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:329:17:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:329:17:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h:90:56: error: marked inline, but without a definition
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_info must be 1 KB"
+drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h:270:49: error: static assertion failed: "amd_sriov_msg_vf2pf_in


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [Intel-gfx] ✗ Fi.CI.BAT: failure for drm/i915: Move LMEM (VRAM) management over to TTM
  2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
                   ` (9 preceding siblings ...)
  (?)
@ 2021-05-11 16:48 ` Patchwork
  -1 siblings, 0 replies; 55+ messages in thread
From: Patchwork @ 2021-05-11 16:48 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 20575 bytes --]

== Series Details ==

Series: drm/i915: Move LMEM (VRAM) management over to TTM
URL   : https://patchwork.freedesktop.org/series/90022/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_10068 -> Patchwork_20100
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with Patchwork_20100 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_20100, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/index.html

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in Patchwork_20100:

### IGT changes ###

#### Possible regressions ####

  * igt@core_hotunplug@unbind-rebind:
    - fi-skl-6600u:       [PASS][1] -> [DMESG-WARN][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-skl-6600u/igt@core_hotunplug@unbind-rebind.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-skl-6600u/igt@core_hotunplug@unbind-rebind.html
    - fi-cml-s:           [PASS][3] -> [DMESG-WARN][4]
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-cml-s/igt@core_hotunplug@unbind-rebind.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-cml-s/igt@core_hotunplug@unbind-rebind.html
    - fi-cml-u2:          [PASS][5] -> [DMESG-WARN][6]
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-cml-u2/igt@core_hotunplug@unbind-rebind.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-cml-u2/igt@core_hotunplug@unbind-rebind.html
    - fi-icl-u2:          [PASS][7] -> [DMESG-WARN][8]
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-icl-u2/igt@core_hotunplug@unbind-rebind.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-icl-u2/igt@core_hotunplug@unbind-rebind.html
    - fi-tgl-y:           [PASS][9] -> [DMESG-WARN][10]
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-tgl-y/igt@core_hotunplug@unbind-rebind.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-tgl-y/igt@core_hotunplug@unbind-rebind.html

  * igt@i915_selftest@live@gem:
    - fi-snb-2520m:       [PASS][11] -> [DMESG-FAIL][12]
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-snb-2520m/igt@i915_selftest@live@gem.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-snb-2520m/igt@i915_selftest@live@gem.html

  * igt@i915_selftest@live@gt_lrc:
    - fi-kbl-x1275:       [PASS][13] -> [DMESG-FAIL][14]
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-kbl-x1275/igt@i915_selftest@live@gt_lrc.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-kbl-x1275/igt@i915_selftest@live@gt_lrc.html

  * igt@i915_selftest@live@gt_timelines:
    - fi-skl-6700k2:      [PASS][15] -> [DMESG-FAIL][16]
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-skl-6700k2/igt@i915_selftest@live@gt_timelines.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-skl-6700k2/igt@i915_selftest@live@gt_timelines.html
    - fi-cfl-8700k:       [PASS][17] -> [DMESG-FAIL][18]
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-cfl-8700k/igt@i915_selftest@live@gt_timelines.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-cfl-8700k/igt@i915_selftest@live@gt_timelines.html

  * igt@i915_selftest@live@hugepages:
    - fi-bdw-5557u:       [PASS][19] -> [DMESG-FAIL][20]
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bdw-5557u/igt@i915_selftest@live@hugepages.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bdw-5557u/igt@i915_selftest@live@hugepages.html

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-a:
    - fi-bwr-2160:        [PASS][21] -> [FAIL][22]
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bwr-2160/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bwr-2160/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html

  * igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence:
    - fi-ilk-650:         [PASS][23] -> [FAIL][24] +8 similar issues
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-ilk-650/igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-ilk-650/igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence.html

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - fi-bsw-kefka:       [PASS][25] -> [FAIL][26]
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-kefka/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-kefka/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html

  * igt@runner@aborted:
    - fi-snb-2520m:       NOTRUN -> [FAIL][27]
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-snb-2520m/igt@runner@aborted.html

  
#### Warnings ####

  * igt@gem_exec_gttfill@basic:
    - fi-ilk-650:         [FAIL][28] ([i915#3457]) -> [FAIL][29]
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-ilk-650/igt@gem_exec_gttfill@basic.html
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-ilk-650/igt@gem_exec_gttfill@basic.html

  * igt@i915_selftest@live@execlists:
    - fi-cfl-8109u:       [INCOMPLETE][30] -> [DMESG-FAIL][31]
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-cfl-8109u/igt@i915_selftest@live@execlists.html
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-cfl-8109u/igt@i915_selftest@live@execlists.html
    - fi-tgl-u2:          [DMESG-FAIL][32] -> [INCOMPLETE][33]
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-tgl-u2/igt@i915_selftest@live@execlists.html
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-tgl-u2/igt@i915_selftest@live@execlists.html

  
#### Suppressed ####

  The following results come from untrusted machines, tests, or statuses.
  They do not affect the overall result.

  * igt@core_hotunplug@unbind-rebind:
    - {fi-ehl-1}:         [PASS][34] -> [DMESG-WARN][35]
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-ehl-1/igt@core_hotunplug@unbind-rebind.html
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-ehl-1/igt@core_hotunplug@unbind-rebind.html

  * igt@i915_selftest@live@sanitycheck:
    - {fi-tgl-dsi}:       [PASS][36] -> [DMESG-FAIL][37]
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-tgl-dsi/igt@i915_selftest@live@sanitycheck.html
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-tgl-dsi/igt@i915_selftest@live@sanitycheck.html

  
Known issues
------------

  Here are the changes found in Patchwork_20100 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_exec_fence@basic-await@vcs0:
    - fi-bsw-kefka:       [PASS][38] -> [FAIL][39] ([i915#3457])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-kefka/igt@gem_exec_fence@basic-await@vcs0.html
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-kefka/igt@gem_exec_fence@basic-await@vcs0.html

  * igt@gem_wait@busy@all:
    - fi-bsw-nick:        [PASS][40] -> [FAIL][41] ([i915#3177] / [i915#3457])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-nick/igt@gem_wait@busy@all.html
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-nick/igt@gem_wait@busy@all.html

  * igt@gem_wait@wait@all:
    - fi-bwr-2160:        [PASS][42] -> [FAIL][43] ([i915#3457]) +1 similar issue
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bwr-2160/igt@gem_wait@wait@all.html
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bwr-2160/igt@gem_wait@wait@all.html
    - fi-pnv-d510:        [PASS][44] -> [FAIL][45] ([i915#3457]) +1 similar issue
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-pnv-d510/igt@gem_wait@wait@all.html
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-pnv-d510/igt@gem_wait@wait@all.html
    - fi-bsw-nick:        [PASS][46] -> [FAIL][47] ([i915#3457])
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-nick/igt@gem_wait@wait@all.html
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-nick/igt@gem_wait@wait@all.html

  * igt@i915_pm_rpm@module-reload:
    - fi-icl-y:           [PASS][48] -> [INCOMPLETE][49] ([i915#2405])
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-icl-y/igt@i915_pm_rpm@module-reload.html
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-icl-y/igt@i915_pm_rpm@module-reload.html
    - fi-glk-dsi:         [PASS][50] -> [DMESG-WARN][51] ([i915#1982])
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-glk-dsi/igt@i915_pm_rpm@module-reload.html
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-glk-dsi/igt@i915_pm_rpm@module-reload.html

  * igt@i915_selftest@live@blt:
    - fi-kbl-7500u:       [PASS][52] -> [DMESG-FAIL][53] ([i915#2927])
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-kbl-7500u/igt@i915_selftest@live@blt.html
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-kbl-7500u/igt@i915_selftest@live@blt.html

  * igt@i915_selftest@live@gt_contexts:
    - fi-bsw-kefka:       [PASS][54] -> [DMESG-FAIL][55] ([i915#2927])
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-kefka/igt@i915_selftest@live@gt_contexts.html
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-kefka/igt@i915_selftest@live@gt_contexts.html
    - fi-bsw-nick:        [PASS][56] -> [DMESG-FAIL][57] ([i915#2927])
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-nick/igt@i915_selftest@live@gt_contexts.html
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-nick/igt@i915_selftest@live@gt_contexts.html

  
#### Possible fixes ####

  * igt@gem_exec_fence@nb-await@bcs0:
    - fi-bsw-nick:        [FAIL][58] ([i915#3457]) -> [PASS][59] +1 similar issue
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-nick/igt@gem_exec_fence@nb-await@bcs0.html
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-nick/igt@gem_exec_fence@nb-await@bcs0.html

  * igt@gem_exec_fence@nb-await@rcs0:
    - fi-glk-dsi:         [FAIL][60] ([i915#3457]) -> [PASS][61] +3 similar issues
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-glk-dsi/igt@gem_exec_fence@nb-await@rcs0.html
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-glk-dsi/igt@gem_exec_fence@nb-await@rcs0.html

  * igt@gem_exec_fence@nb-await@vcs0:
    - fi-bsw-kefka:       [FAIL][62] ([i915#3457]) -> [PASS][63] +1 similar issue
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-kefka/igt@gem_exec_fence@nb-await@vcs0.html
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-kefka/igt@gem_exec_fence@nb-await@vcs0.html

  * igt@gem_exec_fence@nb-await@vecs0:
    - fi-bsw-n3050:       [FAIL][64] ([i915#3457]) -> [PASS][65]
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-n3050/igt@gem_exec_fence@nb-await@vecs0.html
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-n3050/igt@gem_exec_fence@nb-await@vecs0.html

  * igt@kms_busy@basic@modeset:
    - fi-ilk-650:         [INCOMPLETE][66] ([i915#3457]) -> [PASS][67]
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-ilk-650/igt@kms_busy@basic@modeset.html
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-ilk-650/igt@kms_busy@basic@modeset.html

  * igt@kms_chamelium@common-hpd-after-suspend:
    - fi-kbl-7500u:       [DMESG-FAIL][68] ([i915#165]) -> [PASS][69]
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-kbl-7500u/igt@kms_chamelium@common-hpd-after-suspend.html
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-kbl-7500u/igt@kms_chamelium@common-hpd-after-suspend.html

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-a:
    - fi-elk-e7500:       [FAIL][70] -> [PASS][71]
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-elk-e7500/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-elk-e7500/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - fi-bwr-2160:        [FAIL][72] -> [PASS][73]
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bwr-2160/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bwr-2160/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html

  
#### Warnings ####

  * igt@gem_exec_gttfill@basic:
    - fi-pnv-d510:        [FAIL][74] -> [FAIL][75] ([i915#3457])
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-pnv-d510/igt@gem_exec_gttfill@basic.html

  * igt@i915_module_load@reload:
    - fi-kbl-soraka:      [DMESG-WARN][76] ([i915#1982]) -> [DMESG-WARN][77] ([i915#1982] / [i915#3457])
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-kbl-soraka/igt@i915_module_load@reload.html
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-kbl-soraka/igt@i915_module_load@reload.html
    - fi-tgl-u2:          [DMESG-WARN][78] ([k.org#205379]) -> [DMESG-WARN][79] ([i915#3457] / [k.org#205379])
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-tgl-u2/igt@i915_module_load@reload.html
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-tgl-u2/igt@i915_module_load@reload.html
    - fi-bsw-kefka:       [DMESG-FAIL][80] ([i915#1982]) -> [DMESG-WARN][81] ([i915#1982] / [i915#3457])
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bsw-kefka/igt@i915_module_load@reload.html
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bsw-kefka/igt@i915_module_load@reload.html

  * igt@i915_selftest@live@mman:
    - fi-bwr-2160:        [DMESG-FAIL][82] ([i915#3457]) -> [DMESG-WARN][83] ([i915#3457])
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-bwr-2160/igt@i915_selftest@live@mman.html
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-bwr-2160/igt@i915_selftest@live@mman.html
    - fi-kbl-r:           [DMESG-WARN][84] ([i915#3457]) -> [DMESG-FAIL][85] ([i915#3457])
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-kbl-r/igt@i915_selftest@live@mman.html
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-kbl-r/igt@i915_selftest@live@mman.html

  * igt@runner@aborted:
    - fi-tgl-y:           [FAIL][86] ([i915#1436] / [i915#2966]) -> [FAIL][87] ([i915#1602])
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-tgl-y/igt@runner@aborted.html
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-tgl-y/igt@runner@aborted.html
    - fi-skl-6600u:       [FAIL][88] ([i915#1436] / [i915#3363]) -> [FAIL][89] ([i915#2283] / [i915#3363])
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-skl-6600u/igt@runner@aborted.html
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-skl-6600u/igt@runner@aborted.html
    - fi-cfl-8109u:       [FAIL][90] ([i915#3363]) -> [FAIL][91] ([i915#2426] / [i915#3363])
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-cfl-8109u/igt@runner@aborted.html
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-cfl-8109u/igt@runner@aborted.html
    - fi-icl-u2:          [FAIL][92] ([i915#2426] / [i915#2782] / [i915#3363]) -> [FAIL][93] ([i915#2283] / [i915#3363])
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-icl-u2/igt@runner@aborted.html
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-icl-u2/igt@runner@aborted.html
    - fi-glk-dsi:         [FAIL][94] ([i915#2426] / [i915#3363] / [k.org#202321]) -> [FAIL][95] ([i915#1814] / [i915#3363] / [k.org#202321])
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-glk-dsi/igt@runner@aborted.html
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-glk-dsi/igt@runner@aborted.html
    - fi-kbl-soraka:      [FAIL][96] ([i915#1436] / [i915#3363]) -> [FAIL][97] ([i915#2292] / [i915#3363] / [k.org#204565])
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-kbl-soraka/igt@runner@aborted.html
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-kbl-soraka/igt@runner@aborted.html
    - fi-cml-u2:          [FAIL][98] ([i915#3363]) -> [FAIL][99] ([i915#1602] / [i915#2283] / [i915#3363])
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-cml-u2/igt@runner@aborted.html
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-cml-u2/igt@runner@aborted.html
    - fi-cml-s:           [FAIL][100] ([i915#3363]) -> [FAIL][101] ([i915#1602] / [i915#2283] / [i915#3363])
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-cml-s/igt@runner@aborted.html
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-cml-s/igt@runner@aborted.html
    - fi-icl-y:           [FAIL][102] ([i915#2782]) -> [FAIL][103] ([i915#1814])
   [102]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10068/fi-icl-y/igt@runner@aborted.html
   [103]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/fi-icl-y/igt@runner@aborted.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [i915#1222]: https://gitlab.freedesktop.org/drm/intel/issues/1222
  [i915#1436]: https://gitlab.freedesktop.org/drm/intel/issues/1436
  [i915#1602]: https://gitlab.freedesktop.org/drm/intel/issues/1602
  [i915#165]: https://gitlab.freedesktop.org/drm/intel/issues/165
  [i915#1814]: https://gitlab.freedesktop.org/drm/intel/issues/1814
  [i915#1982]: https://gitlab.freedesktop.org/drm/intel/issues/1982
  [i915#2283]: https://gitlab.freedesktop.org/drm/intel/issues/2283
  [i915#2292]: https://gitlab.freedesktop.org/drm/intel/issues/2292
  [i915#2405]: https://gitlab.freedesktop.org/drm/intel/issues/2405
  [i915#2426]: https://gitlab.freedesktop.org/drm/intel/issues/2426
  [i915#2782]: https://gitlab.freedesktop.org/drm/intel/issues/2782
  [i915#2927]: https://gitlab.freedesktop.org/drm/intel/issues/2927
  [i915#2966]: https://gitlab.freedesktop.org/drm/intel/issues/2966
  [i915#3177]: https://gitlab.freedesktop.org/drm/intel/issues/3177
  [i915#3276]: https://gitlab.freedesktop.org/drm/intel/issues/3276
  [i915#3363]: https://gitlab.freedesktop.org/drm/intel/issues/3363
  [i915#3457]: https://gitlab.freedesktop.org/drm/intel/issues/3457
  [k.org#202321]: https://bugzilla.kernel.org/show_bug.cgi?id=202321
  [k.org#204565]: https://bugzilla.kernel.org/show_bug.cgi?id=204565
  [k.org#205379]: https://bugzilla.kernel.org/show_bug.cgi?id=205379


Participating hosts (48 -> 42)
------------------------------

  Missing    (6): fi-ilk-m540 fi-hsw-4200u fi-skl-guc fi-bsw-cyan fi-ctg-p8600 fi-bdw-samus 


Build changes
-------------

  * Linux: CI_DRM_10068 -> Patchwork_20100

  CI-20190529: 20190529
  CI_DRM_10068: f71e8fae425cfb4e06a68874bced2fb728638d2a @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_6082: 355269577baef0c5d8114e8851acaeac657e4fe6 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_20100: bd0a5cd14b4e85ee4083a9c089b38813a6724366 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

bd0a5cd14b4e drm/i915/lmem: Verify checks for lmem residency
1bdd626f1990 drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
1cd13783b35c drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
7dc5b6bf9897 drm/i915/ttm: Embed a ttm buffer object in the i915 gem object
08fe6c5181ab drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
e148e51b2187 drm/i915: Don't free shared locks while shared
7c8e78644333 drm/i915: Untangle the vma pages_mutex

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20100/index.html

[-- Attachment #1.2: Type: text/html, Size: 25526 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-11 14:28           ` [Intel-gfx] " Thomas Hellström
@ 2021-05-12  6:57             ` Christian König
  -1 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-12  6:57 UTC (permalink / raw)
  To: Thomas Hellström, Thomas Hellström (Intel),
	intel-gfx, dri-devel

Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>
> On 5/11/21 4:09 PM, Christian König wrote:
>>
>>
>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>
>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>> Most logical place to introduce TTM buffer objects is as an i915
>>>>> gem object backend. We need to add some ops to account for added
>>>>> functionality like delayed delete and LRU list manipulation.
>>>>>
>>>>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>>>>> (which in this case means evicted LMEM objects) is not
>>>>> visible to i915 GEM yet. The plan is to move the i915 gem system 
>>>>> region
>>>>> over to the TTM system memory type in upcoming patches.
>>>>>
>>>>> We set up GPU bindings directly both from LMEM and from the system 
>>>>> region,
>>>>> as there is no need to use the legacy TTM_TT memory type. We reserve
>>>>> that for future porting of GGTT bindings to TTM.
>>>>>
>>>>> There are some changes to TTM to allow for purging system memory 
>>>>> buffer
>>>>> objects and to refuse swapping of some objects: Unfortunately i915 
>>>>> gem
>>>>> still relies heavily on short-term object pinning, and we've 
>>>>> chosen to
>>>>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>>>>> meaning that we need some sort of mechanism to tell TTM they are not
>>>>> swappable. A longer term goal is to get rid of the short-term 
>>>>> pinning.
>>>>
>>>> Well just use the eviction_valuable interface for this.
>>>
>>> Yes, we do that for vram/lmem eviction, but we have nothing similar 
>>> for system swapping. Do I understand you correctly that you want me 
>>> to add a call to eviction_valuable() also for that instead of 
>>> swap_possible()?
>>
>> You should already have that. eviction_valuable is called in both cases.
>>
> Hmm. I can only see it called from ttm_mem_evict_first() which is not 
> in the swapping path? Or do I miss something?

Mhm, looks like my recollection was wrong. We should probably move the 
call into the ttm_bo_evict_swapout_allowable() function.

Christian.

>
> Thanks,
>
> Thomas
>
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12  6:57             ` Christian König
  0 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-12  6:57 UTC (permalink / raw)
  To: Thomas Hellström, Thomas Hellström (Intel),
	intel-gfx, dri-devel

Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>
> On 5/11/21 4:09 PM, Christian König wrote:
>>
>>
>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>
>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>> Most logical place to introduce TTM buffer objects is as an i915
>>>>> gem object backend. We need to add some ops to account for added
>>>>> functionality like delayed delete and LRU list manipulation.
>>>>>
>>>>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>>>>> (which in this case means evicted LMEM objects) is not
>>>>> visible to i915 GEM yet. The plan is to move the i915 gem system 
>>>>> region
>>>>> over to the TTM system memory type in upcoming patches.
>>>>>
>>>>> We set up GPU bindings directly both from LMEM and from the system 
>>>>> region,
>>>>> as there is no need to use the legacy TTM_TT memory type. We reserve
>>>>> that for future porting of GGTT bindings to TTM.
>>>>>
>>>>> There are some changes to TTM to allow for purging system memory 
>>>>> buffer
>>>>> objects and to refuse swapping of some objects: Unfortunately i915 
>>>>> gem
>>>>> still relies heavily on short-term object pinning, and we've 
>>>>> chosen to
>>>>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>>>>> meaning that we need some sort of mechanism to tell TTM they are not
>>>>> swappable. A longer term goal is to get rid of the short-term 
>>>>> pinning.
>>>>
>>>> Well just use the eviction_valuable interface for this.
>>>
>>> Yes, we do that for vram/lmem eviction, but we have nothing similar 
>>> for system swapping. Do I understand you correctly that you want me 
>>> to add a call to eviction_valuable() also for that instead of 
>>> swap_possible()?
>>
>> You should already have that. eviction_valuable is called in both cases.
>>
> Hmm. I can only see it called from ttm_mem_evict_first() which is not 
> in the swapping path? Or do I miss something?

Mhm, looks like my recollection was wrong. We should probably move the 
call into the ttm_bo_evict_swapout_allowable() function.

Christian.

>
> Thanks,
>
> Thomas
>
>
>

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-12  6:57             ` [Intel-gfx] " Christian König
@ 2021-05-12  7:05               ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12  7:05 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel

On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
> > 
> > On 5/11/21 4:09 PM, Christian König wrote:
> > > 
> > > 
> > > Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
> > > > 
> > > > On 5/11/21 3:58 PM, Christian König wrote:
> > > > > Am 11.05.21 um 15:25 schrieb Thomas Hellström:
> > > > > > Most logical place to introduce TTM buffer objects is as an
> > > > > > i915
> > > > > > gem object backend. We need to add some ops to account for
> > > > > > added
> > > > > > functionality like delayed delete and LRU list
> > > > > > manipulation.
> > > > > > 
> > > > > > Initially we support only LMEM and SYSTEM memory, but
> > > > > > SYSTEM
> > > > > > (which in this case means evicted LMEM objects) is not
> > > > > > visible to i915 GEM yet. The plan is to move the i915 gem
> > > > > > system 
> > > > > > region
> > > > > > over to the TTM system memory type in upcoming patches.
> > > > > > 
> > > > > > We set up GPU bindings directly both from LMEM and from the
> > > > > > system 
> > > > > > region,
> > > > > > as there is no need to use the legacy TTM_TT memory type.
> > > > > > We reserve
> > > > > > that for future porting of GGTT bindings to TTM.
> > > > > > 
> > > > > > There are some changes to TTM to allow for purging system
> > > > > > memory 
> > > > > > buffer
> > > > > > objects and to refuse swapping of some objects:
> > > > > > Unfortunately i915 
> > > > > > gem
> > > > > > still relies heavily on short-term object pinning, and
> > > > > > we've 
> > > > > > chosen to
> > > > > > keep short-term-pinned buffer objects on the TTM LRU lists
> > > > > > for now,
> > > > > > meaning that we need some sort of mechanism to tell TTM
> > > > > > they are not
> > > > > > swappable. A longer term goal is to get rid of the short-
> > > > > > term 
> > > > > > pinning.
> > > > > 
> > > > > Well just use the eviction_valuable interface for this.
> > > > 
> > > > Yes, we do that for vram/lmem eviction, but we have nothing
> > > > similar 
> > > > for system swapping. Do I understand you correctly that you
> > > > want me 
> > > > to add a call to eviction_valuable() also for that instead of 
> > > > swap_possible()?
> > > 
> > > You should already have that. eviction_valuable is called in both
> > > cases.
> > > 
> > Hmm. I can only see it called from ttm_mem_evict_first() which is
> > not 
> > in the swapping path? Or do I miss something?
> 
> Mhm, looks like my recollection was wrong. We should probably move
> the 
> call into the ttm_bo_evict_swapout_allowable() function.

Yes, I think we also need a convention whether it's called dma_resv
locked or not, since the helper accesses bo->mem, which should really
only be done under reservation. At the same point, there is value in
calling this function while holding the LRU lock.

Also, I wonder whether implementations of this callback might encounter
unexpected data when called from the swapout path, because at least the
helper assumes it not in system memory, since it is accessing bo-
>mem.start. 

So unless we use a separate callback for swapout, there's some auditing
to be done.

Pls let me know what you think.
Thanks,
Thomas



> 
> Christian.
> 
> > 
> > Thanks,
> > 
> > Thomas
> > 
> > 
> > 
> 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12  7:05               ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12  7:05 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel

On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
> > 
> > On 5/11/21 4:09 PM, Christian König wrote:
> > > 
> > > 
> > > Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
> > > > 
> > > > On 5/11/21 3:58 PM, Christian König wrote:
> > > > > Am 11.05.21 um 15:25 schrieb Thomas Hellström:
> > > > > > Most logical place to introduce TTM buffer objects is as an
> > > > > > i915
> > > > > > gem object backend. We need to add some ops to account for
> > > > > > added
> > > > > > functionality like delayed delete and LRU list
> > > > > > manipulation.
> > > > > > 
> > > > > > Initially we support only LMEM and SYSTEM memory, but
> > > > > > SYSTEM
> > > > > > (which in this case means evicted LMEM objects) is not
> > > > > > visible to i915 GEM yet. The plan is to move the i915 gem
> > > > > > system 
> > > > > > region
> > > > > > over to the TTM system memory type in upcoming patches.
> > > > > > 
> > > > > > We set up GPU bindings directly both from LMEM and from the
> > > > > > system 
> > > > > > region,
> > > > > > as there is no need to use the legacy TTM_TT memory type.
> > > > > > We reserve
> > > > > > that for future porting of GGTT bindings to TTM.
> > > > > > 
> > > > > > There are some changes to TTM to allow for purging system
> > > > > > memory 
> > > > > > buffer
> > > > > > objects and to refuse swapping of some objects:
> > > > > > Unfortunately i915 
> > > > > > gem
> > > > > > still relies heavily on short-term object pinning, and
> > > > > > we've 
> > > > > > chosen to
> > > > > > keep short-term-pinned buffer objects on the TTM LRU lists
> > > > > > for now,
> > > > > > meaning that we need some sort of mechanism to tell TTM
> > > > > > they are not
> > > > > > swappable. A longer term goal is to get rid of the short-
> > > > > > term 
> > > > > > pinning.
> > > > > 
> > > > > Well just use the eviction_valuable interface for this.
> > > > 
> > > > Yes, we do that for vram/lmem eviction, but we have nothing
> > > > similar 
> > > > for system swapping. Do I understand you correctly that you
> > > > want me 
> > > > to add a call to eviction_valuable() also for that instead of 
> > > > swap_possible()?
> > > 
> > > You should already have that. eviction_valuable is called in both
> > > cases.
> > > 
> > Hmm. I can only see it called from ttm_mem_evict_first() which is
> > not 
> > in the swapping path? Or do I miss something?
> 
> Mhm, looks like my recollection was wrong. We should probably move
> the 
> call into the ttm_bo_evict_swapout_allowable() function.

Yes, I think we also need a convention whether it's called dma_resv
locked or not, since the helper accesses bo->mem, which should really
only be done under reservation. At the same point, there is value in
calling this function while holding the LRU lock.

Also, I wonder whether implementations of this callback might encounter
unexpected data when called from the swapout path, because at least the
helper assumes it not in system memory, since it is accessing bo-
>mem.start. 

So unless we use a separate callback for swapout, there's some auditing
to be done.

Pls let me know what you think.
Thanks,
Thomas



> 
> Christian.
> 
> > 
> > Thanks,
> > 
> > Thomas
> > 
> > 
> > 
> 


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-12  7:05               ` [Intel-gfx] " Thomas Hellström
@ 2021-05-12  7:09                 ` Christian König
  -1 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-12  7:09 UTC (permalink / raw)
  To: Thomas Hellström, Thomas Hellström (Intel),
	intel-gfx, dri-devel

Am 12.05.21 um 09:05 schrieb Thomas Hellström:
> On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
>> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>>> On 5/11/21 4:09 PM, Christian König wrote:
>>>>
>>>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>>>> Most logical place to introduce TTM buffer objects is as an
>>>>>>> i915
>>>>>>> gem object backend. We need to add some ops to account for
>>>>>>> added
>>>>>>> functionality like delayed delete and LRU list
>>>>>>> manipulation.
>>>>>>>
>>>>>>> Initially we support only LMEM and SYSTEM memory, but
>>>>>>> SYSTEM
>>>>>>> (which in this case means evicted LMEM objects) is not
>>>>>>> visible to i915 GEM yet. The plan is to move the i915 gem
>>>>>>> system
>>>>>>> region
>>>>>>> over to the TTM system memory type in upcoming patches.
>>>>>>>
>>>>>>> We set up GPU bindings directly both from LMEM and from the
>>>>>>> system
>>>>>>> region,
>>>>>>> as there is no need to use the legacy TTM_TT memory type.
>>>>>>> We reserve
>>>>>>> that for future porting of GGTT bindings to TTM.
>>>>>>>
>>>>>>> There are some changes to TTM to allow for purging system
>>>>>>> memory
>>>>>>> buffer
>>>>>>> objects and to refuse swapping of some objects:
>>>>>>> Unfortunately i915
>>>>>>> gem
>>>>>>> still relies heavily on short-term object pinning, and
>>>>>>> we've
>>>>>>> chosen to
>>>>>>> keep short-term-pinned buffer objects on the TTM LRU lists
>>>>>>> for now,
>>>>>>> meaning that we need some sort of mechanism to tell TTM
>>>>>>> they are not
>>>>>>> swappable. A longer term goal is to get rid of the short-
>>>>>>> term
>>>>>>> pinning.
>>>>>> Well just use the eviction_valuable interface for this.
>>>>> Yes, we do that for vram/lmem eviction, but we have nothing
>>>>> similar
>>>>> for system swapping. Do I understand you correctly that you
>>>>> want me
>>>>> to add a call to eviction_valuable() also for that instead of
>>>>> swap_possible()?
>>>> You should already have that. eviction_valuable is called in both
>>>> cases.
>>>>
>>> Hmm. I can only see it called from ttm_mem_evict_first() which is
>>> not
>>> in the swapping path? Or do I miss something?
>> Mhm, looks like my recollection was wrong. We should probably move
>> the
>> call into the ttm_bo_evict_swapout_allowable() function.
> Yes, I think we also need a convention whether it's called dma_resv
> locked or not, since the helper accesses bo->mem, which should really
> only be done under reservation. At the same point, there is value in
> calling this function while holding the LRU lock.

You actually need to call it while holding the lock because eviction 
otherwise ends up in an endless loop.

Trying to fix that for years, but so far no luck with that.

> Also, I wonder whether implementations of this callback might encounter
> unexpected data when called from the swapout path, because at least the
> helper assumes it not in system memory, since it is accessing bo-
>> mem.start.
> So unless we use a separate callback for swapout, there's some auditing
> to be done.

Please audit the existing callbacks and move the callback into the 
function after doing that.

Thanks,
Christian.

>
> Pls let me know what you think.
> Thanks,
> Thomas
>
>
>
>> Christian.
>>
>>> Thanks,
>>>
>>> Thomas
>>>
>>>
>>>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12  7:09                 ` Christian König
  0 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-12  7:09 UTC (permalink / raw)
  To: Thomas Hellström, Thomas Hellström (Intel),
	intel-gfx, dri-devel

Am 12.05.21 um 09:05 schrieb Thomas Hellström:
> On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
>> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>>> On 5/11/21 4:09 PM, Christian König wrote:
>>>>
>>>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>>>> Most logical place to introduce TTM buffer objects is as an
>>>>>>> i915
>>>>>>> gem object backend. We need to add some ops to account for
>>>>>>> added
>>>>>>> functionality like delayed delete and LRU list
>>>>>>> manipulation.
>>>>>>>
>>>>>>> Initially we support only LMEM and SYSTEM memory, but
>>>>>>> SYSTEM
>>>>>>> (which in this case means evicted LMEM objects) is not
>>>>>>> visible to i915 GEM yet. The plan is to move the i915 gem
>>>>>>> system
>>>>>>> region
>>>>>>> over to the TTM system memory type in upcoming patches.
>>>>>>>
>>>>>>> We set up GPU bindings directly both from LMEM and from the
>>>>>>> system
>>>>>>> region,
>>>>>>> as there is no need to use the legacy TTM_TT memory type.
>>>>>>> We reserve
>>>>>>> that for future porting of GGTT bindings to TTM.
>>>>>>>
>>>>>>> There are some changes to TTM to allow for purging system
>>>>>>> memory
>>>>>>> buffer
>>>>>>> objects and to refuse swapping of some objects:
>>>>>>> Unfortunately i915
>>>>>>> gem
>>>>>>> still relies heavily on short-term object pinning, and
>>>>>>> we've
>>>>>>> chosen to
>>>>>>> keep short-term-pinned buffer objects on the TTM LRU lists
>>>>>>> for now,
>>>>>>> meaning that we need some sort of mechanism to tell TTM
>>>>>>> they are not
>>>>>>> swappable. A longer term goal is to get rid of the short-
>>>>>>> term
>>>>>>> pinning.
>>>>>> Well just use the eviction_valuable interface for this.
>>>>> Yes, we do that for vram/lmem eviction, but we have nothing
>>>>> similar
>>>>> for system swapping. Do I understand you correctly that you
>>>>> want me
>>>>> to add a call to eviction_valuable() also for that instead of
>>>>> swap_possible()?
>>>> You should already have that. eviction_valuable is called in both
>>>> cases.
>>>>
>>> Hmm. I can only see it called from ttm_mem_evict_first() which is
>>> not
>>> in the swapping path? Or do I miss something?
>> Mhm, looks like my recollection was wrong. We should probably move
>> the
>> call into the ttm_bo_evict_swapout_allowable() function.
> Yes, I think we also need a convention whether it's called dma_resv
> locked or not, since the helper accesses bo->mem, which should really
> only be done under reservation. At the same point, there is value in
> calling this function while holding the LRU lock.

You actually need to call it while holding the lock because eviction 
otherwise ends up in an endless loop.

Trying to fix that for years, but so far no luck with that.

> Also, I wonder whether implementations of this callback might encounter
> unexpected data when called from the swapout path, because at least the
> helper assumes it not in system memory, since it is accessing bo-
>> mem.start.
> So unless we use a separate callback for swapout, there's some auditing
> to be done.

Please audit the existing callbacks and move the callback into the 
function after doing that.

Thanks,
Christian.

>
> Pls let me know what you think.
> Thanks,
> Thomas
>
>
>
>> Christian.
>>
>>> Thanks,
>>>
>>> Thomas
>>>
>>>
>>>
>

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 7/7] drm/i915/lmem: Verify checks for lmem residency
  2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
@ 2021-05-12  7:58     ` Matthew Auld
  -1 siblings, 0 replies; 55+ messages in thread
From: Matthew Auld @ 2021-05-12  7:58 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: Intel Graphics Development, ML dri-devel

On Tue, 11 May 2021 at 14:26, Thomas Hellström
<thomas.hellstrom@linux.intel.com> wrote:
>
> Since objects can be migrated or evicted when not pinned or locked,
> update the checks for lmem residency or future residency so that
> the value returned is not immediately stale.
>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_display.c |  2 +-
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.c     | 42 +++++++++++++++++++-
>  drivers/gpu/drm/i915/gem/i915_gem_object.c   | 29 ++++++++++++++
>  drivers/gpu/drm/i915/gem/i915_gem_object.h   |  4 ++
>  4 files changed, 75 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index de1f13d203b5..b95def2d5af3 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -11615,7 +11615,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
>
>         /* object is backed with LMEM for discrete */
>         i915 = to_i915(obj->base.dev);
> -       if (HAS_LMEM(i915) && !i915_gem_object_is_lmem(obj)) {
> +       if (HAS_LMEM(i915) && !i915_gem_object_validates_to_lmem(obj)) {
>                 /* object is "remote", not in local memory */
>                 i915_gem_object_put(obj);
>                 return ERR_PTR(-EREMOTE);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index 2b8cd15de1d9..d539dffa1554 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -23,10 +23,50 @@ i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
>         return io_mapping_map_wc(&obj->mm.region->iomap, offset, size);
>  }
>
> +/**
> + * i915_gem_object_validates_to_lmem - Whether the object is resident in
> + * lmem when pages are present.
> + * @obj: The object to check.
> + *
> + * Migratable objects residency may change from under us if the object is
> + * not pinned or locked. This function is intended to be used to check whether
> + * the object can only reside in lmem when pages are present.
> + *
> + * Return: Whether the object is always resident in lmem when pages are
> + * present.
> + */
> +bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj)
> +{
> +       struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
> +
> +       return !i915_gem_object_migratable(obj) &&
> +               mr && (mr->type == INTEL_MEMORY_LOCAL ||
> +                      mr->type == INTEL_MEMORY_STOLEN_LOCAL);
> +}
> +
> +/**
> + * i915_gem_object_is_lmem - Whether the object is resident in
> + * lmem
> + * @obj: The object to check.
> + *
> + * Even if an object is allowed to migrate and change memory region,
> + * this function checks whether it will always be present in lmem when
> + * valid *or* if that's not the case, whether it's currently resident in lmem.
> + * For migratable and evictable objects, the latter only makes sense when
> + * the object is locked.
> + *
> + * Return: Whether the object migratable but resident in lmem, or not
> + * migratable and will be present in lmem when valid.
> + */
>  bool i915_gem_object_is_lmem(struct drm_i915_gem_object *obj)
>  {
> -       struct intel_memory_region *mr = obj->mm.region;
> +       struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
>
> +#ifdef CONFIG_LOCKDEP
> +       if (i915_gem_object_migratable(obj) &&
> +           i915_gem_object_evictable(obj))
> +               assert_object_held(obj);
> +#endif
>         return mr && (mr->type == INTEL_MEMORY_LOCAL ||
>                       mr->type == INTEL_MEMORY_STOLEN_LOCAL);
>  }
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> index c53488f391dd..0475b1c94454 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> @@ -458,6 +458,35 @@ bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
>         return pin_count == 0;
>  }
>
> +/**
> + * i915_gem_object_migratable - Whether the object is migratable out of the
> + * current region.
> + * @obj: Pointer to the object.
> + *
> + * Return: Whether the object is allowed to be resident in other
> + * regions than the current while pages are present.
> + */
> +bool i915_gem_object_migratable(struct drm_i915_gem_object *obj)
> +{
> +       struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
> +       struct intel_memory_region *placement;
> +       int i;
> +
> +       if (!mr)
> +               return false;
> +
> +       if (!obj->mm.n_placements)
> +               return false;
> +
> +       for (i = 0; i < obj->mm.n_placements; ++i) {
> +               placement = obj->mm.placements[i];
> +               if (placement != mr)
> +                       return true;
> +       }

Maybe this can simply be:
return obj->mm.n_placements > 1;

?

The uAPI guarantees that mm.placements are each unique.

> +
> +       return false;
> +}
> +
>  void i915_gem_init__objects(struct drm_i915_private *i915)
>  {
>         INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> index ae5930e307d5..a3ad8cf4eefd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> @@ -596,6 +596,10 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj);
>
>  bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
>
> +bool i915_gem_object_migratable(struct drm_i915_gem_object *obj);
> +
> +bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj);
> +
>  #ifdef CONFIG_MMU_NOTIFIER
>  static inline bool
>  i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
> --
> 2.30.2
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 7/7] drm/i915/lmem: Verify checks for lmem residency
@ 2021-05-12  7:58     ` Matthew Auld
  0 siblings, 0 replies; 55+ messages in thread
From: Matthew Auld @ 2021-05-12  7:58 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: Intel Graphics Development, ML dri-devel

On Tue, 11 May 2021 at 14:26, Thomas Hellström
<thomas.hellstrom@linux.intel.com> wrote:
>
> Since objects can be migrated or evicted when not pinned or locked,
> update the checks for lmem residency or future residency so that
> the value returned is not immediately stale.
>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_display.c |  2 +-
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.c     | 42 +++++++++++++++++++-
>  drivers/gpu/drm/i915/gem/i915_gem_object.c   | 29 ++++++++++++++
>  drivers/gpu/drm/i915/gem/i915_gem_object.h   |  4 ++
>  4 files changed, 75 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index de1f13d203b5..b95def2d5af3 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -11615,7 +11615,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
>
>         /* object is backed with LMEM for discrete */
>         i915 = to_i915(obj->base.dev);
> -       if (HAS_LMEM(i915) && !i915_gem_object_is_lmem(obj)) {
> +       if (HAS_LMEM(i915) && !i915_gem_object_validates_to_lmem(obj)) {
>                 /* object is "remote", not in local memory */
>                 i915_gem_object_put(obj);
>                 return ERR_PTR(-EREMOTE);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index 2b8cd15de1d9..d539dffa1554 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -23,10 +23,50 @@ i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
>         return io_mapping_map_wc(&obj->mm.region->iomap, offset, size);
>  }
>
> +/**
> + * i915_gem_object_validates_to_lmem - Whether the object is resident in
> + * lmem when pages are present.
> + * @obj: The object to check.
> + *
> + * Migratable objects residency may change from under us if the object is
> + * not pinned or locked. This function is intended to be used to check whether
> + * the object can only reside in lmem when pages are present.
> + *
> + * Return: Whether the object is always resident in lmem when pages are
> + * present.
> + */
> +bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj)
> +{
> +       struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
> +
> +       return !i915_gem_object_migratable(obj) &&
> +               mr && (mr->type == INTEL_MEMORY_LOCAL ||
> +                      mr->type == INTEL_MEMORY_STOLEN_LOCAL);
> +}
> +
> +/**
> + * i915_gem_object_is_lmem - Whether the object is resident in
> + * lmem
> + * @obj: The object to check.
> + *
> + * Even if an object is allowed to migrate and change memory region,
> + * this function checks whether it will always be present in lmem when
> + * valid *or* if that's not the case, whether it's currently resident in lmem.
> + * For migratable and evictable objects, the latter only makes sense when
> + * the object is locked.
> + *
> + * Return: Whether the object migratable but resident in lmem, or not
> + * migratable and will be present in lmem when valid.
> + */
>  bool i915_gem_object_is_lmem(struct drm_i915_gem_object *obj)
>  {
> -       struct intel_memory_region *mr = obj->mm.region;
> +       struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
>
> +#ifdef CONFIG_LOCKDEP
> +       if (i915_gem_object_migratable(obj) &&
> +           i915_gem_object_evictable(obj))
> +               assert_object_held(obj);
> +#endif
>         return mr && (mr->type == INTEL_MEMORY_LOCAL ||
>                       mr->type == INTEL_MEMORY_STOLEN_LOCAL);
>  }
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> index c53488f391dd..0475b1c94454 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> @@ -458,6 +458,35 @@ bool i915_gem_object_evictable(struct drm_i915_gem_object *obj)
>         return pin_count == 0;
>  }
>
> +/**
> + * i915_gem_object_migratable - Whether the object is migratable out of the
> + * current region.
> + * @obj: Pointer to the object.
> + *
> + * Return: Whether the object is allowed to be resident in other
> + * regions than the current while pages are present.
> + */
> +bool i915_gem_object_migratable(struct drm_i915_gem_object *obj)
> +{
> +       struct intel_memory_region *mr = READ_ONCE(obj->mm.region);
> +       struct intel_memory_region *placement;
> +       int i;
> +
> +       if (!mr)
> +               return false;
> +
> +       if (!obj->mm.n_placements)
> +               return false;
> +
> +       for (i = 0; i < obj->mm.n_placements; ++i) {
> +               placement = obj->mm.placements[i];
> +               if (placement != mr)
> +                       return true;
> +       }

Maybe this can simply be:
return obj->mm.n_placements > 1;

?

The uAPI guarantees that mm.placements are each unique.

> +
> +       return false;
> +}
> +
>  void i915_gem_init__objects(struct drm_i915_private *i915)
>  {
>         INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> index ae5930e307d5..a3ad8cf4eefd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
> @@ -596,6 +596,10 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj);
>
>  bool i915_gem_object_evictable(struct drm_i915_gem_object *obj);
>
> +bool i915_gem_object_migratable(struct drm_i915_gem_object *obj);
> +
> +bool i915_gem_object_validates_to_lmem(struct drm_i915_gem_object *obj);
> +
>  #ifdef CONFIG_MMU_NOTIFIER
>  static inline bool
>  i915_gem_object_is_userptr(struct drm_i915_gem_object *obj)
> --
> 2.30.2
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
  2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
@ 2021-05-12  8:57     ` Matthew Auld
  -1 siblings, 0 replies; 55+ messages in thread
From: Matthew Auld @ 2021-05-12  8:57 UTC (permalink / raw)
  To: Thomas Hellström
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Tue, 11 May 2021 at 14:26, Thomas Hellström
<thomas.hellstrom@linux.intel.com> wrote:
>
> Temporarily remove the buddy allocator and related selftests
> and hook up the TTM range manager for i915 regions.
>
> In order to support some of the mock region-related selftests, we need to
> be able to initialize the TTM range-manager standalone without a struct
> ttm_device. Add two functions to allow that to the TTM api.
>
> Finally modify the mock region selftests somewhat to account for a
> fragmenting manager.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Kconfig                  |   1 +
>  drivers/gpu/drm/i915/Makefile                 |   2 +-
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
>  .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
>  drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
>  drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
>  drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
>  drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
>  drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
>  drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
>  drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
>  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
>  drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
>  drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
>  drivers/gpu/drm/i915/i915_drv.c               |   8 +
>  drivers/gpu/drm/i915/i915_drv.h               |   7 +-
>  drivers/gpu/drm/i915/i915_gem.c               |   1 +
>  drivers/gpu/drm/i915/i915_globals.c           |   1 -
>  drivers/gpu/drm/i915/i915_globals.h           |   1 -
>  drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
>  drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
>  drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
>  drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
>  drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
>  drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
>  drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------------
>  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
>  .../drm/i915/selftests/intel_memory_region.c  | 133 +--
>  drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
>  drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
>  include/drm/ttm/ttm_bo_driver.h               |  23 +
>  31 files changed, 715 insertions(+), 1771 deletions(-)
>  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
>  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
>  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
>  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
>  delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c
>
> diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
> index 1e1cb245fca7..b63d374dff23 100644
> --- a/drivers/gpu/drm/i915/Kconfig
> +++ b/drivers/gpu/drm/i915/Kconfig
> @@ -26,6 +26,7 @@ config DRM_I915
>         select SND_HDA_I915 if SND_HDA_CORE
>         select CEC_CORE if CEC_NOTIFIER
>         select VMAP_PFN
> +       select DRM_TTM
>         help
>           Choose this option if you have a system that has "Intel Graphics
>           Media Accelerator" or "HD Graphics" integrated graphics,
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index d0d936d9137b..cb8823570996 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -50,6 +50,7 @@ i915-y += i915_drv.o \
>           intel_memory_region.o \
>           intel_pch.o \
>           intel_pm.o \
> +         intel_region_ttm.o \
>           intel_runtime_pm.o \
>           intel_sideband.o \
>           intel_step.o \
> @@ -160,7 +161,6 @@ gem-y += \
>  i915-y += \
>           $(gem-y) \
>           i915_active.o \
> -         i915_buddy.o \
>           i915_cmd_parser.o \
>           i915_gem_evict.o \
>           i915_gem_gtt.o \
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index f44bdd08f7cb..f42803ea48f2 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -4,16 +4,70 @@
>   */
>
>  #include "intel_memory_region.h"
> +#include "intel_region_ttm.h"
>  #include "gem/i915_gem_region.h"
>  #include "gem/i915_gem_lmem.h"
>  #include "i915_drv.h"
>
> +static void lmem_put_pages(struct drm_i915_gem_object *obj,
> +                                 struct sg_table *pages)
> +{
> +       intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
> +       obj->mm.dirty = false;
> +       sg_free_table(pages);
> +       kfree(pages);
> +}
> +
> +static int lmem_get_pages(struct drm_i915_gem_object *obj)
> +{
> +       unsigned int flags;
> +       struct sg_table *pages;
> +
> +       flags = I915_ALLOC_MIN_PAGE_SIZE;
> +       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> +               flags |= I915_ALLOC_CONTIGUOUS;
> +
> +       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
> +                                                        obj->base.size,
> +                                                        flags);
> +       if (IS_ERR(obj->mm.st_mm_node))
> +               return PTR_ERR(obj->mm.st_mm_node);
> +
> +       /* Range manager is always contigous */
> +       if (obj->mm.region->is_range_manager)
> +               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> +       pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
> +       if (IS_ERR(pages))
> +               return PTR_ERR(pages);

error unwind?

> +
> +       __i915_gem_object_set_pages(obj, pages,
> +                                   i915_sg_dma_page_sizes(pages->sgl));
> +
> +       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> +               void __iomem *vaddr =
> +                       i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
> +
> +               if (!vaddr) {
> +                       struct sg_table *pages =
> +                               __i915_gem_object_unset_pages(obj);
> +
> +                       if (!IS_ERR_OR_NULL(pages))
> +                               lmem_put_pages(obj, pages);
> +               }
> +
> +               memset_io(vaddr, 0, obj->base.size);
> +               io_mapping_unmap(vaddr);
> +       }
> +
> +       return 0;
> +}

<snip>

> +/**
> + * i915_sg_dma_page_sizes - Calculate page sizes from a scatterlist
> + * @sg: The scatterlist from which to calculate page sizes
> + *
> + * Return: a value with bits sets for relevant page sizes.
> + */
> +static inline unsigned int i915_sg_dma_page_sizes(struct scatterlist *sg)
> +{
> +       unsigned int page_sizes;
> +
> +       page_sizes = 0;
> +       while (sg) {
> +               GEM_BUG_ON(sg->offset);
> +               GEM_BUG_ON(!IS_ALIGNED(sg->dma_length, PAGE_SIZE));
> +               page_sizes |= sg->dma_length;
> +               sg = __sg_next(sg);
> +       }
> +
> +       /*
> +        * Is this necessary to support building large GPU pages from
> +        * even larger segments?
> +        */

We just need to know the above sg page_sizes, which is the mask of
sg->dma_length for each sg. Later in __i915_gem_object_set_pages() we
use this to determine the potential GPU page sizes for the object,
depending on what the device supports. So the below stuff shouldn't be
needed. Also we can just use i915_sg_page_sizes() here.

Although since we do have control over building the sg, we should
ideally just pass in the sg_page_sizes to say i915_sg_from_mm_node()
for it to fill in, instead of looping over the whole thing again, but
that can be something to do in the future.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
@ 2021-05-12  8:57     ` Matthew Auld
  0 siblings, 0 replies; 55+ messages in thread
From: Matthew Auld @ 2021-05-12  8:57 UTC (permalink / raw)
  To: Thomas Hellström
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Tue, 11 May 2021 at 14:26, Thomas Hellström
<thomas.hellstrom@linux.intel.com> wrote:
>
> Temporarily remove the buddy allocator and related selftests
> and hook up the TTM range manager for i915 regions.
>
> In order to support some of the mock region-related selftests, we need to
> be able to initialize the TTM range-manager standalone without a struct
> ttm_device. Add two functions to allow that to the TTM api.
>
> Finally modify the mock region selftests somewhat to account for a
> fragmenting manager.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Kconfig                  |   1 +
>  drivers/gpu/drm/i915/Makefile                 |   2 +-
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
>  .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
>  drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
>  drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
>  drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
>  drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
>  drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
>  drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
>  drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
>  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
>  drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
>  drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
>  drivers/gpu/drm/i915/i915_drv.c               |   8 +
>  drivers/gpu/drm/i915/i915_drv.h               |   7 +-
>  drivers/gpu/drm/i915/i915_gem.c               |   1 +
>  drivers/gpu/drm/i915/i915_globals.c           |   1 -
>  drivers/gpu/drm/i915/i915_globals.h           |   1 -
>  drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
>  drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
>  drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
>  drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
>  drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
>  drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
>  drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------------
>  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
>  .../drm/i915/selftests/intel_memory_region.c  | 133 +--
>  drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
>  drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
>  include/drm/ttm/ttm_bo_driver.h               |  23 +
>  31 files changed, 715 insertions(+), 1771 deletions(-)
>  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
>  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
>  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
>  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
>  delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c
>
> diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
> index 1e1cb245fca7..b63d374dff23 100644
> --- a/drivers/gpu/drm/i915/Kconfig
> +++ b/drivers/gpu/drm/i915/Kconfig
> @@ -26,6 +26,7 @@ config DRM_I915
>         select SND_HDA_I915 if SND_HDA_CORE
>         select CEC_CORE if CEC_NOTIFIER
>         select VMAP_PFN
> +       select DRM_TTM
>         help
>           Choose this option if you have a system that has "Intel Graphics
>           Media Accelerator" or "HD Graphics" integrated graphics,
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index d0d936d9137b..cb8823570996 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -50,6 +50,7 @@ i915-y += i915_drv.o \
>           intel_memory_region.o \
>           intel_pch.o \
>           intel_pm.o \
> +         intel_region_ttm.o \
>           intel_runtime_pm.o \
>           intel_sideband.o \
>           intel_step.o \
> @@ -160,7 +161,6 @@ gem-y += \
>  i915-y += \
>           $(gem-y) \
>           i915_active.o \
> -         i915_buddy.o \
>           i915_cmd_parser.o \
>           i915_gem_evict.o \
>           i915_gem_gtt.o \
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index f44bdd08f7cb..f42803ea48f2 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -4,16 +4,70 @@
>   */
>
>  #include "intel_memory_region.h"
> +#include "intel_region_ttm.h"
>  #include "gem/i915_gem_region.h"
>  #include "gem/i915_gem_lmem.h"
>  #include "i915_drv.h"
>
> +static void lmem_put_pages(struct drm_i915_gem_object *obj,
> +                                 struct sg_table *pages)
> +{
> +       intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
> +       obj->mm.dirty = false;
> +       sg_free_table(pages);
> +       kfree(pages);
> +}
> +
> +static int lmem_get_pages(struct drm_i915_gem_object *obj)
> +{
> +       unsigned int flags;
> +       struct sg_table *pages;
> +
> +       flags = I915_ALLOC_MIN_PAGE_SIZE;
> +       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> +               flags |= I915_ALLOC_CONTIGUOUS;
> +
> +       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
> +                                                        obj->base.size,
> +                                                        flags);
> +       if (IS_ERR(obj->mm.st_mm_node))
> +               return PTR_ERR(obj->mm.st_mm_node);
> +
> +       /* Range manager is always contigous */
> +       if (obj->mm.region->is_range_manager)
> +               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> +       pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
> +       if (IS_ERR(pages))
> +               return PTR_ERR(pages);

error unwind?

> +
> +       __i915_gem_object_set_pages(obj, pages,
> +                                   i915_sg_dma_page_sizes(pages->sgl));
> +
> +       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> +               void __iomem *vaddr =
> +                       i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
> +
> +               if (!vaddr) {
> +                       struct sg_table *pages =
> +                               __i915_gem_object_unset_pages(obj);
> +
> +                       if (!IS_ERR_OR_NULL(pages))
> +                               lmem_put_pages(obj, pages);
> +               }
> +
> +               memset_io(vaddr, 0, obj->base.size);
> +               io_mapping_unmap(vaddr);
> +       }
> +
> +       return 0;
> +}

<snip>

> +/**
> + * i915_sg_dma_page_sizes - Calculate page sizes from a scatterlist
> + * @sg: The scatterlist from which to calculate page sizes
> + *
> + * Return: a value with bits sets for relevant page sizes.
> + */
> +static inline unsigned int i915_sg_dma_page_sizes(struct scatterlist *sg)
> +{
> +       unsigned int page_sizes;
> +
> +       page_sizes = 0;
> +       while (sg) {
> +               GEM_BUG_ON(sg->offset);
> +               GEM_BUG_ON(!IS_ALIGNED(sg->dma_length, PAGE_SIZE));
> +               page_sizes |= sg->dma_length;
> +               sg = __sg_next(sg);
> +       }
> +
> +       /*
> +        * Is this necessary to support building large GPU pages from
> +        * even larger segments?
> +        */

We just need to know the above sg page_sizes, which is the mask of
sg->dma_length for each sg. Later in __i915_gem_object_set_pages() we
use this to determine the potential GPU page sizes for the object,
depending on what the device supports. So the below stuff shouldn't be
needed. Also we can just use i915_sg_page_sizes() here.

Although since we do have control over building the sg, we should
ideally just pass in the sg_page_sizes to say i915_sg_from_mm_node()
for it to fill in, instead of looping over the whole thing again, but
that can be something to do in the future.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
@ 2021-05-12 11:45     ` Matthew Auld
  -1 siblings, 0 replies; 55+ messages in thread
From: Matthew Auld @ 2021-05-12 11:45 UTC (permalink / raw)
  To: Thomas Hellström
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Tue, 11 May 2021 at 14:26, Thomas Hellström
<thomas.hellstrom@linux.intel.com> wrote:
>
> Most logical place to introduce TTM buffer objects is as an i915
> gem object backend. We need to add some ops to account for added
> functionality like delayed delete and LRU list manipulation.
>
> Initially we support only LMEM and SYSTEM memory, but SYSTEM
> (which in this case means evicted LMEM objects) is not
> visible to i915 GEM yet. The plan is to move the i915 gem system region
> over to the TTM system memory type in upcoming patches.
>
> We set up GPU bindings directly both from LMEM and from the system region,
> as there is no need to use the legacy TTM_TT memory type. We reserve
> that for future porting of GGTT bindings to TTM.
>
> There are some changes to TTM to allow for purging system memory buffer
> objects and to refuse swapping of some objects: Unfortunately i915 gem
> still relies heavily on short-term object pinning, and we've chosen to
> keep short-term-pinned buffer objects on the TTM LRU lists for now,
> meaning that we need some sort of mechanism to tell TTM they are not
> swappable. A longer term goal is to get rid of the short-term pinning.
>
> Remove the old lmem backend.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
>  drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
>  drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
>  .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
>  drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
>  drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
>  drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
>  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
>  drivers/gpu/drm/i915/i915_gem.c               |   5 +-
>  drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
>  drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
>  drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
>  drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
>  drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
>  include/drm/ttm/ttm_device.h                  |   9 +
>  17 files changed, 733 insertions(+), 140 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 958ccc1edfed..ef0d884a9e2d 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -155,6 +155,7 @@ gem-y += \
>         gem/i915_gem_stolen.o \
>         gem/i915_gem_throttle.o \
>         gem/i915_gem_tiling.o \
> +       gem/i915_gem_ttm.o \
>         gem/i915_gem_ttm_bo_util.o \
>         gem/i915_gem_userptr.o \
>         gem/i915_gem_wait.o \
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index f42803ea48f2..2b8cd15de1d9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -4,73 +4,10 @@
>   */
>
>  #include "intel_memory_region.h"
> -#include "intel_region_ttm.h"
>  #include "gem/i915_gem_region.h"
>  #include "gem/i915_gem_lmem.h"
>  #include "i915_drv.h"
>
> -static void lmem_put_pages(struct drm_i915_gem_object *obj,
> -                                 struct sg_table *pages)
> -{
> -       intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
> -       obj->mm.dirty = false;
> -       sg_free_table(pages);
> -       kfree(pages);
> -}
> -
> -static int lmem_get_pages(struct drm_i915_gem_object *obj)
> -{
> -       unsigned int flags;
> -       struct sg_table *pages;
> -
> -       flags = I915_ALLOC_MIN_PAGE_SIZE;
> -       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> -               flags |= I915_ALLOC_CONTIGUOUS;
> -
> -       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
> -                                                        obj->base.size,
> -                                                        flags);
> -       if (IS_ERR(obj->mm.st_mm_node))
> -               return PTR_ERR(obj->mm.st_mm_node);
> -
> -       /* Range manager is always contigous */
> -       if (obj->mm.region->is_range_manager)
> -               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> -       pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
> -       if (IS_ERR(pages))
> -               return PTR_ERR(pages);
> -
> -       __i915_gem_object_set_pages(obj, pages,
> -                                   i915_sg_dma_page_sizes(pages->sgl));
> -
> -       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> -               void __iomem *vaddr =
> -                       i915_gem_object_lmem_io_map(obj, 0, obj->base.size);

Where did the object clearing go? I'm not seeing it in the new code.

<snip>

> +
> +static struct sg_table *
> +i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
> +                        struct ttm_resource *res)
> +{
> +       struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +       struct ttm_resource_manager *man =
> +               ttm_manager_type(bo->bdev, res->mem_type);
> +       struct sg_table *st;
> +
> +       if (man->use_tt)
> +               return i915_ttm_tt_get_st(bo->ttm);
> +
> +       st = kzalloc(sizeof(*st), GFP_KERNEL);
> +       if (!st)
> +               return ERR_PTR(-ENOMEM);

The st is already allocated below.

<snip>

> +
> +/**
> + * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
> + * @mem: The initial memory region for the object.
> + * @obj: The gem object.
> + * @size: Object size in bytes.
> + * @flags: gem object flags.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
> +                              struct drm_i915_gem_object *obj,
> +                              resource_size_t size,
> +                              unsigned int flags)
> +{
> +       static struct lock_class_key lock_class;
> +       struct drm_i915_private *i915 = mem->i915;
> +       size_t alignment = 0;
> +       int ret;
> +
> +       /* Adjust alignment to GPU- and CPU huge page sizes. */
> +
> +       if (mem->is_range_manager) {
> +               if (size >= SZ_1G)
> +                       alignment = SZ_1G >> PAGE_SHIFT;
> +               else if (size >= SZ_2M)
> +                       alignment = SZ_2M >> PAGE_SHIFT;
> +               else if (size >= SZ_64K)
> +                       alignment = SZ_64K >> PAGE_SHIFT;
> +       }
> +
> +       drm_gem_private_object_init(&i915->drm, &obj->base, size);
> +       i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
> +       i915_gem_object_init_memory_region(obj, mem);
> +       i915_gem_object_make_unshrinkable(obj);
> +
> +       ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
> +                         ttm_bo_type_kernel, &i915_sys_placement, alignment,
> +                         true, NULL, NULL, i915_ttm_bo_destroy);

Handle the error?

> +
> +       obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
> +
> +       i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
> +
> +       return 0;
> +}

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12 11:45     ` Matthew Auld
  0 siblings, 0 replies; 55+ messages in thread
From: Matthew Auld @ 2021-05-12 11:45 UTC (permalink / raw)
  To: Thomas Hellström
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Tue, 11 May 2021 at 14:26, Thomas Hellström
<thomas.hellstrom@linux.intel.com> wrote:
>
> Most logical place to introduce TTM buffer objects is as an i915
> gem object backend. We need to add some ops to account for added
> functionality like delayed delete and LRU list manipulation.
>
> Initially we support only LMEM and SYSTEM memory, but SYSTEM
> (which in this case means evicted LMEM objects) is not
> visible to i915 GEM yet. The plan is to move the i915 gem system region
> over to the TTM system memory type in upcoming patches.
>
> We set up GPU bindings directly both from LMEM and from the system region,
> as there is no need to use the legacy TTM_TT memory type. We reserve
> that for future porting of GGTT bindings to TTM.
>
> There are some changes to TTM to allow for purging system memory buffer
> objects and to refuse swapping of some objects: Unfortunately i915 gem
> still relies heavily on short-term object pinning, and we've chosen to
> keep short-term-pinned buffer objects on the TTM LRU lists for now,
> meaning that we need some sort of mechanism to tell TTM they are not
> swappable. A longer term goal is to get rid of the short-term pinning.
>
> Remove the old lmem backend.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
>  drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
>  drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
>  drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
>  .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
>  drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
>  drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
>  drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
>  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
>  drivers/gpu/drm/i915/i915_gem.c               |   5 +-
>  drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
>  drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
>  drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
>  drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
>  drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
>  include/drm/ttm/ttm_device.h                  |   9 +
>  17 files changed, 733 insertions(+), 140 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 958ccc1edfed..ef0d884a9e2d 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -155,6 +155,7 @@ gem-y += \
>         gem/i915_gem_stolen.o \
>         gem/i915_gem_throttle.o \
>         gem/i915_gem_tiling.o \
> +       gem/i915_gem_ttm.o \
>         gem/i915_gem_ttm_bo_util.o \
>         gem/i915_gem_userptr.o \
>         gem/i915_gem_wait.o \
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> index f42803ea48f2..2b8cd15de1d9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> @@ -4,73 +4,10 @@
>   */
>
>  #include "intel_memory_region.h"
> -#include "intel_region_ttm.h"
>  #include "gem/i915_gem_region.h"
>  #include "gem/i915_gem_lmem.h"
>  #include "i915_drv.h"
>
> -static void lmem_put_pages(struct drm_i915_gem_object *obj,
> -                                 struct sg_table *pages)
> -{
> -       intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
> -       obj->mm.dirty = false;
> -       sg_free_table(pages);
> -       kfree(pages);
> -}
> -
> -static int lmem_get_pages(struct drm_i915_gem_object *obj)
> -{
> -       unsigned int flags;
> -       struct sg_table *pages;
> -
> -       flags = I915_ALLOC_MIN_PAGE_SIZE;
> -       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> -               flags |= I915_ALLOC_CONTIGUOUS;
> -
> -       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
> -                                                        obj->base.size,
> -                                                        flags);
> -       if (IS_ERR(obj->mm.st_mm_node))
> -               return PTR_ERR(obj->mm.st_mm_node);
> -
> -       /* Range manager is always contigous */
> -       if (obj->mm.region->is_range_manager)
> -               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> -       pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
> -       if (IS_ERR(pages))
> -               return PTR_ERR(pages);
> -
> -       __i915_gem_object_set_pages(obj, pages,
> -                                   i915_sg_dma_page_sizes(pages->sgl));
> -
> -       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> -               void __iomem *vaddr =
> -                       i915_gem_object_lmem_io_map(obj, 0, obj->base.size);

Where did the object clearing go? I'm not seeing it in the new code.

<snip>

> +
> +static struct sg_table *
> +i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
> +                        struct ttm_resource *res)
> +{
> +       struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +       struct ttm_resource_manager *man =
> +               ttm_manager_type(bo->bdev, res->mem_type);
> +       struct sg_table *st;
> +
> +       if (man->use_tt)
> +               return i915_ttm_tt_get_st(bo->ttm);
> +
> +       st = kzalloc(sizeof(*st), GFP_KERNEL);
> +       if (!st)
> +               return ERR_PTR(-ENOMEM);

The st is already allocated below.

<snip>

> +
> +/**
> + * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
> + * @mem: The initial memory region for the object.
> + * @obj: The gem object.
> + * @size: Object size in bytes.
> + * @flags: gem object flags.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
> +                              struct drm_i915_gem_object *obj,
> +                              resource_size_t size,
> +                              unsigned int flags)
> +{
> +       static struct lock_class_key lock_class;
> +       struct drm_i915_private *i915 = mem->i915;
> +       size_t alignment = 0;
> +       int ret;
> +
> +       /* Adjust alignment to GPU- and CPU huge page sizes. */
> +
> +       if (mem->is_range_manager) {
> +               if (size >= SZ_1G)
> +                       alignment = SZ_1G >> PAGE_SHIFT;
> +               else if (size >= SZ_2M)
> +                       alignment = SZ_2M >> PAGE_SHIFT;
> +               else if (size >= SZ_64K)
> +                       alignment = SZ_64K >> PAGE_SHIFT;
> +       }
> +
> +       drm_gem_private_object_init(&i915->drm, &obj->base, size);
> +       i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
> +       i915_gem_object_init_memory_region(obj, mem);
> +       i915_gem_object_make_unshrinkable(obj);
> +
> +       ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
> +                         ttm_bo_type_kernel, &i915_sys_placement, alignment,
> +                         true, NULL, NULL, i915_ttm_bo_destroy);

Handle the error?

> +
> +       obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
> +
> +       i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
> +
> +       return 0;
> +}
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-12 11:45     ` Matthew Auld
@ 2021-05-12 11:50       ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12 11:50 UTC (permalink / raw)
  To: Matthew Auld
  Cc: Intel Graphics Development, Christian König, ML dri-devel

Hi, Matthew,

Thanks for reviewing!

On 5/12/21 1:45 PM, Matthew Auld wrote:
> On Tue, 11 May 2021 at 14:26, Thomas Hellström
> <thomas.hellstrom@linux.intel.com> wrote:
>> Most logical place to introduce TTM buffer objects is as an i915
>> gem object backend. We need to add some ops to account for added
>> functionality like delayed delete and LRU list manipulation.
>>
>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>> (which in this case means evicted LMEM objects) is not
>> visible to i915 GEM yet. The plan is to move the i915 gem system region
>> over to the TTM system memory type in upcoming patches.
>>
>> We set up GPU bindings directly both from LMEM and from the system region,
>> as there is no need to use the legacy TTM_TT memory type. We reserve
>> that for future porting of GGTT bindings to TTM.
>>
>> There are some changes to TTM to allow for purging system memory buffer
>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>> still relies heavily on short-term object pinning, and we've chosen to
>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>> meaning that we need some sort of mechanism to tell TTM they are not
>> swappable. A longer term goal is to get rid of the short-term pinning.
>>
>> Remove the old lmem backend.
>>
>> Cc: Christian König <christian.koenig@amd.com>
>> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>> ---
>>   drivers/gpu/drm/i915/Makefile                 |   1 +
>>   drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
>>   drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
>>   drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
>>   drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
>>   .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
>>   drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
>>   drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
>>   drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
>>   drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
>>   drivers/gpu/drm/i915/i915_gem.c               |   5 +-
>>   drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
>>   drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
>>   drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
>>   drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
>>   drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
>>   include/drm/ttm/ttm_device.h                  |   9 +
>>   17 files changed, 733 insertions(+), 140 deletions(-)
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index 958ccc1edfed..ef0d884a9e2d 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -155,6 +155,7 @@ gem-y += \
>>          gem/i915_gem_stolen.o \
>>          gem/i915_gem_throttle.o \
>>          gem/i915_gem_tiling.o \
>> +       gem/i915_gem_ttm.o \
>>          gem/i915_gem_ttm_bo_util.o \
>>          gem/i915_gem_userptr.o \
>>          gem/i915_gem_wait.o \
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
>> index f42803ea48f2..2b8cd15de1d9 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
>> @@ -4,73 +4,10 @@
>>    */
>>
>>   #include "intel_memory_region.h"
>> -#include "intel_region_ttm.h"
>>   #include "gem/i915_gem_region.h"
>>   #include "gem/i915_gem_lmem.h"
>>   #include "i915_drv.h"
>>
>> -static void lmem_put_pages(struct drm_i915_gem_object *obj,
>> -                                 struct sg_table *pages)
>> -{
>> -       intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
>> -       obj->mm.dirty = false;
>> -       sg_free_table(pages);
>> -       kfree(pages);
>> -}
>> -
>> -static int lmem_get_pages(struct drm_i915_gem_object *obj)
>> -{
>> -       unsigned int flags;
>> -       struct sg_table *pages;
>> -
>> -       flags = I915_ALLOC_MIN_PAGE_SIZE;
>> -       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
>> -               flags |= I915_ALLOC_CONTIGUOUS;
>> -
>> -       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
>> -                                                        obj->base.size,
>> -                                                        flags);
>> -       if (IS_ERR(obj->mm.st_mm_node))
>> -               return PTR_ERR(obj->mm.st_mm_node);
>> -
>> -       /* Range manager is always contigous */
>> -       if (obj->mm.region->is_range_manager)
>> -               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
>> -       pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
>> -       if (IS_ERR(pages))
>> -               return PTR_ERR(pages);
>> -
>> -       __i915_gem_object_set_pages(obj, pages,
>> -                                   i915_sg_dma_page_sizes(pages->sgl));
>> -
>> -       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
>> -               void __iomem *vaddr =
>> -                       i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
> Where did the object clearing go? I'm not seeing it in the new code.

It's in the move callback with TTM. If the object had not been 
previously initialized,
the copying is skipped, and a fill is done instead.

>
> <snip>
>
>> +
>> +static struct sg_table *
>> +i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
>> +                        struct ttm_resource *res)
>> +{
>> +       struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
>> +       struct ttm_resource_manager *man =
>> +               ttm_manager_type(bo->bdev, res->mem_type);
>> +       struct sg_table *st;
>> +
>> +       if (man->use_tt)
>> +               return i915_ttm_tt_get_st(bo->ttm);
>> +
>> +       st = kzalloc(sizeof(*st), GFP_KERNEL);
>> +       if (!st)
>> +               return ERR_PTR(-ENOMEM);
> The st is already allocated below.
Will fix.
>
> <snip>
>
>> +
>> +/**
>> + * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
>> + * @mem: The initial memory region for the object.
>> + * @obj: The gem object.
>> + * @size: Object size in bytes.
>> + * @flags: gem object flags.
>> + *
>> + * Return: 0 on success, negative error code on failure.
>> + */
>> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
>> +                              struct drm_i915_gem_object *obj,
>> +                              resource_size_t size,
>> +                              unsigned int flags)
>> +{
>> +       static struct lock_class_key lock_class;
>> +       struct drm_i915_private *i915 = mem->i915;
>> +       size_t alignment = 0;
>> +       int ret;
>> +
>> +       /* Adjust alignment to GPU- and CPU huge page sizes. */
>> +
>> +       if (mem->is_range_manager) {
>> +               if (size >= SZ_1G)
>> +                       alignment = SZ_1G >> PAGE_SHIFT;
>> +               else if (size >= SZ_2M)
>> +                       alignment = SZ_2M >> PAGE_SHIFT;
>> +               else if (size >= SZ_64K)
>> +                       alignment = SZ_64K >> PAGE_SHIFT;
>> +       }
>> +
>> +       drm_gem_private_object_init(&i915->drm, &obj->base, size);
>> +       i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
>> +       i915_gem_object_init_memory_region(obj, mem);
>> +       i915_gem_object_make_unshrinkable(obj);
>> +
>> +       ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
>> +                         ttm_bo_type_kernel, &i915_sys_placement, alignment,
>> +                         true, NULL, NULL, i915_ttm_bo_destroy);
> Handle the error?
Ugh. Will fix
>
>> +
>> +       obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
>> +
>> +       i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
>> +
>> +       return 0;
>> +}


Thanks!

Thomas



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12 11:50       ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12 11:50 UTC (permalink / raw)
  To: Matthew Auld
  Cc: Intel Graphics Development, Christian König, ML dri-devel

Hi, Matthew,

Thanks for reviewing!

On 5/12/21 1:45 PM, Matthew Auld wrote:
> On Tue, 11 May 2021 at 14:26, Thomas Hellström
> <thomas.hellstrom@linux.intel.com> wrote:
>> Most logical place to introduce TTM buffer objects is as an i915
>> gem object backend. We need to add some ops to account for added
>> functionality like delayed delete and LRU list manipulation.
>>
>> Initially we support only LMEM and SYSTEM memory, but SYSTEM
>> (which in this case means evicted LMEM objects) is not
>> visible to i915 GEM yet. The plan is to move the i915 gem system region
>> over to the TTM system memory type in upcoming patches.
>>
>> We set up GPU bindings directly both from LMEM and from the system region,
>> as there is no need to use the legacy TTM_TT memory type. We reserve
>> that for future porting of GGTT bindings to TTM.
>>
>> There are some changes to TTM to allow for purging system memory buffer
>> objects and to refuse swapping of some objects: Unfortunately i915 gem
>> still relies heavily on short-term object pinning, and we've chosen to
>> keep short-term-pinned buffer objects on the TTM LRU lists for now,
>> meaning that we need some sort of mechanism to tell TTM they are not
>> swappable. A longer term goal is to get rid of the short-term pinning.
>>
>> Remove the old lmem backend.
>>
>> Cc: Christian König <christian.koenig@amd.com>
>> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>> ---
>>   drivers/gpu/drm/i915/Makefile                 |   1 +
>>   drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  83 ---
>>   drivers/gpu/drm/i915/gem/i915_gem_lmem.h      |   5 -
>>   drivers/gpu/drm/i915/gem/i915_gem_object.c    | 126 +++--
>>   drivers/gpu/drm/i915/gem/i915_gem_object.h    |   9 +
>>   .../gpu/drm/i915/gem/i915_gem_object_types.h  |  18 +
>>   drivers/gpu/drm/i915/gem/i915_gem_region.c    |   6 +-
>>   drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 534 ++++++++++++++++++
>>   drivers/gpu/drm/i915/gem/i915_gem_ttm.h       |  48 ++
>>   drivers/gpu/drm/i915/gt/intel_region_lmem.c   |   3 +-
>>   drivers/gpu/drm/i915/i915_gem.c               |   5 +-
>>   drivers/gpu/drm/i915/intel_memory_region.c    |   1 -
>>   drivers/gpu/drm/i915/intel_memory_region.h    |   1 -
>>   drivers/gpu/drm/i915/intel_region_ttm.c       |   5 +-
>>   drivers/gpu/drm/i915/intel_region_ttm.h       |   7 +-
>>   drivers/gpu/drm/ttm/ttm_bo.c                  |  12 +
>>   include/drm/ttm/ttm_device.h                  |   9 +
>>   17 files changed, 733 insertions(+), 140 deletions(-)
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index 958ccc1edfed..ef0d884a9e2d 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -155,6 +155,7 @@ gem-y += \
>>          gem/i915_gem_stolen.o \
>>          gem/i915_gem_throttle.o \
>>          gem/i915_gem_tiling.o \
>> +       gem/i915_gem_ttm.o \
>>          gem/i915_gem_ttm_bo_util.o \
>>          gem/i915_gem_userptr.o \
>>          gem/i915_gem_wait.o \
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
>> index f42803ea48f2..2b8cd15de1d9 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
>> @@ -4,73 +4,10 @@
>>    */
>>
>>   #include "intel_memory_region.h"
>> -#include "intel_region_ttm.h"
>>   #include "gem/i915_gem_region.h"
>>   #include "gem/i915_gem_lmem.h"
>>   #include "i915_drv.h"
>>
>> -static void lmem_put_pages(struct drm_i915_gem_object *obj,
>> -                                 struct sg_table *pages)
>> -{
>> -       intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
>> -       obj->mm.dirty = false;
>> -       sg_free_table(pages);
>> -       kfree(pages);
>> -}
>> -
>> -static int lmem_get_pages(struct drm_i915_gem_object *obj)
>> -{
>> -       unsigned int flags;
>> -       struct sg_table *pages;
>> -
>> -       flags = I915_ALLOC_MIN_PAGE_SIZE;
>> -       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
>> -               flags |= I915_ALLOC_CONTIGUOUS;
>> -
>> -       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
>> -                                                        obj->base.size,
>> -                                                        flags);
>> -       if (IS_ERR(obj->mm.st_mm_node))
>> -               return PTR_ERR(obj->mm.st_mm_node);
>> -
>> -       /* Range manager is always contigous */
>> -       if (obj->mm.region->is_range_manager)
>> -               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
>> -       pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
>> -       if (IS_ERR(pages))
>> -               return PTR_ERR(pages);
>> -
>> -       __i915_gem_object_set_pages(obj, pages,
>> -                                   i915_sg_dma_page_sizes(pages->sgl));
>> -
>> -       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
>> -               void __iomem *vaddr =
>> -                       i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
> Where did the object clearing go? I'm not seeing it in the new code.

It's in the move callback with TTM. If the object had not been 
previously initialized,
the copying is skipped, and a fill is done instead.

>
> <snip>
>
>> +
>> +static struct sg_table *
>> +i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
>> +                        struct ttm_resource *res)
>> +{
>> +       struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
>> +       struct ttm_resource_manager *man =
>> +               ttm_manager_type(bo->bdev, res->mem_type);
>> +       struct sg_table *st;
>> +
>> +       if (man->use_tt)
>> +               return i915_ttm_tt_get_st(bo->ttm);
>> +
>> +       st = kzalloc(sizeof(*st), GFP_KERNEL);
>> +       if (!st)
>> +               return ERR_PTR(-ENOMEM);
> The st is already allocated below.
Will fix.
>
> <snip>
>
>> +
>> +/**
>> + * __i915_gem_ttm_object_init - Initialize a ttm-backed i915 gem object
>> + * @mem: The initial memory region for the object.
>> + * @obj: The gem object.
>> + * @size: Object size in bytes.
>> + * @flags: gem object flags.
>> + *
>> + * Return: 0 on success, negative error code on failure.
>> + */
>> +int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
>> +                              struct drm_i915_gem_object *obj,
>> +                              resource_size_t size,
>> +                              unsigned int flags)
>> +{
>> +       static struct lock_class_key lock_class;
>> +       struct drm_i915_private *i915 = mem->i915;
>> +       size_t alignment = 0;
>> +       int ret;
>> +
>> +       /* Adjust alignment to GPU- and CPU huge page sizes. */
>> +
>> +       if (mem->is_range_manager) {
>> +               if (size >= SZ_1G)
>> +                       alignment = SZ_1G >> PAGE_SHIFT;
>> +               else if (size >= SZ_2M)
>> +                       alignment = SZ_2M >> PAGE_SHIFT;
>> +               else if (size >= SZ_64K)
>> +                       alignment = SZ_64K >> PAGE_SHIFT;
>> +       }
>> +
>> +       drm_gem_private_object_init(&i915->drm, &obj->base, size);
>> +       i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
>> +       i915_gem_object_init_memory_region(obj, mem);
>> +       i915_gem_object_make_unshrinkable(obj);
>> +
>> +       ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
>> +                         ttm_bo_type_kernel, &i915_sys_placement, alignment,
>> +                         true, NULL, NULL, i915_ttm_bo_destroy);
> Handle the error?
Ugh. Will fix
>
>> +
>> +       obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
>> +
>> +       i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
>> +
>> +       return 0;
>> +}


Thanks!

Thomas


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-12  7:09                 ` [Intel-gfx] " Christian König
@ 2021-05-12 13:02                   ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12 13:02 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel

On Wed, 2021-05-12 at 09:09 +0200, Christian König wrote:
> Am 12.05.21 um 09:05 schrieb Thomas Hellström:
> > On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
> > > Am 11.05.21 um 16:28 schrieb Thomas Hellström:
> > > > On 5/11/21 4:09 PM, Christian König wrote:
> > > > > 
> > > > > Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
> > > > > > On 5/11/21 3:58 PM, Christian König wrote:
> > > > > > > Am 11.05.21 um 15:25 schrieb Thomas Hellström:
> > > > > > > > Most logical place to introduce TTM buffer objects is
> > > > > > > > as an
> > > > > > > > i915
> > > > > > > > gem object backend. We need to add some ops to account
> > > > > > > > for
> > > > > > > > added
> > > > > > > > functionality like delayed delete and LRU list
> > > > > > > > manipulation.
> > > > > > > > 
> > > > > > > > Initially we support only LMEM and SYSTEM memory, but
> > > > > > > > SYSTEM
> > > > > > > > (which in this case means evicted LMEM objects) is not
> > > > > > > > visible to i915 GEM yet. The plan is to move the i915
> > > > > > > > gem
> > > > > > > > system
> > > > > > > > region
> > > > > > > > over to the TTM system memory type in upcoming patches.
> > > > > > > > 
> > > > > > > > We set up GPU bindings directly both from LMEM and from
> > > > > > > > the
> > > > > > > > system
> > > > > > > > region,
> > > > > > > > as there is no need to use the legacy TTM_TT memory
> > > > > > > > type.
> > > > > > > > We reserve
> > > > > > > > that for future porting of GGTT bindings to TTM.
> > > > > > > > 
> > > > > > > > There are some changes to TTM to allow for purging
> > > > > > > > system
> > > > > > > > memory
> > > > > > > > buffer
> > > > > > > > objects and to refuse swapping of some objects:
> > > > > > > > Unfortunately i915
> > > > > > > > gem
> > > > > > > > still relies heavily on short-term object pinning, and
> > > > > > > > we've
> > > > > > > > chosen to
> > > > > > > > keep short-term-pinned buffer objects on the TTM LRU
> > > > > > > > lists
> > > > > > > > for now,
> > > > > > > > meaning that we need some sort of mechanism to tell TTM
> > > > > > > > they are not
> > > > > > > > swappable. A longer term goal is to get rid of the
> > > > > > > > short-
> > > > > > > > term
> > > > > > > > pinning.
> > > > > > > Well just use the eviction_valuable interface for this.
> > > > > > Yes, we do that for vram/lmem eviction, but we have nothing
> > > > > > similar
> > > > > > for system swapping. Do I understand you correctly that you
> > > > > > want me
> > > > > > to add a call to eviction_valuable() also for that instead
> > > > > > of
> > > > > > swap_possible()?
> > > > > You should already have that. eviction_valuable is called in
> > > > > both
> > > > > cases.
> > > > > 
> > > > Hmm. I can only see it called from ttm_mem_evict_first() which
> > > > is
> > > > not
> > > > in the swapping path? Or do I miss something?
> > > Mhm, looks like my recollection was wrong. We should probably
> > > move
> > > the
> > > call into the ttm_bo_evict_swapout_allowable() function.
> > Yes, I think we also need a convention whether it's called dma_resv
> > locked or not, since the helper accesses bo->mem, which should
> > really
> > only be done under reservation. At the same point, there is value
> > in
> > calling this function while holding the LRU lock.
> 
> You actually need to call it while holding the lock because eviction 
> otherwise ends up in an endless loop.
> 
> Trying to fix that for years, but so far no luck with that.
> 
> > Also, I wonder whether implementations of this callback might
> > encounter
> > unexpected data when called from the swapout path, because at least
> > the
> > helper assumes it not in system memory, since it is accessing bo-
> > > mem.start.
> > So unless we use a separate callback for swapout, there's some
> > auditing
> > to be done.
> 
> Please audit the existing callbacks and move the callback into the 
> function after doing that.
> 
> Thanks,
> Christian.

Would it be OK if I also move the kref_get_unless_zero() to before 
ttm_bo_evict_swapout_allowable() to make the code less sensitive to
surprises?

/Thomas


> 
> > 
> > Pls let me know what you think.
> > Thanks,
> > Thomas
> > 
> > 
> > 
> > > Christian.
> > > 
> > > > Thanks,
> > > > 
> > > > Thomas
> > > > 
> > > > 
> > > > 
> > 
> 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12 13:02                   ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12 13:02 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel

On Wed, 2021-05-12 at 09:09 +0200, Christian König wrote:
> Am 12.05.21 um 09:05 schrieb Thomas Hellström:
> > On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
> > > Am 11.05.21 um 16:28 schrieb Thomas Hellström:
> > > > On 5/11/21 4:09 PM, Christian König wrote:
> > > > > 
> > > > > Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
> > > > > > On 5/11/21 3:58 PM, Christian König wrote:
> > > > > > > Am 11.05.21 um 15:25 schrieb Thomas Hellström:
> > > > > > > > Most logical place to introduce TTM buffer objects is
> > > > > > > > as an
> > > > > > > > i915
> > > > > > > > gem object backend. We need to add some ops to account
> > > > > > > > for
> > > > > > > > added
> > > > > > > > functionality like delayed delete and LRU list
> > > > > > > > manipulation.
> > > > > > > > 
> > > > > > > > Initially we support only LMEM and SYSTEM memory, but
> > > > > > > > SYSTEM
> > > > > > > > (which in this case means evicted LMEM objects) is not
> > > > > > > > visible to i915 GEM yet. The plan is to move the i915
> > > > > > > > gem
> > > > > > > > system
> > > > > > > > region
> > > > > > > > over to the TTM system memory type in upcoming patches.
> > > > > > > > 
> > > > > > > > We set up GPU bindings directly both from LMEM and from
> > > > > > > > the
> > > > > > > > system
> > > > > > > > region,
> > > > > > > > as there is no need to use the legacy TTM_TT memory
> > > > > > > > type.
> > > > > > > > We reserve
> > > > > > > > that for future porting of GGTT bindings to TTM.
> > > > > > > > 
> > > > > > > > There are some changes to TTM to allow for purging
> > > > > > > > system
> > > > > > > > memory
> > > > > > > > buffer
> > > > > > > > objects and to refuse swapping of some objects:
> > > > > > > > Unfortunately i915
> > > > > > > > gem
> > > > > > > > still relies heavily on short-term object pinning, and
> > > > > > > > we've
> > > > > > > > chosen to
> > > > > > > > keep short-term-pinned buffer objects on the TTM LRU
> > > > > > > > lists
> > > > > > > > for now,
> > > > > > > > meaning that we need some sort of mechanism to tell TTM
> > > > > > > > they are not
> > > > > > > > swappable. A longer term goal is to get rid of the
> > > > > > > > short-
> > > > > > > > term
> > > > > > > > pinning.
> > > > > > > Well just use the eviction_valuable interface for this.
> > > > > > Yes, we do that for vram/lmem eviction, but we have nothing
> > > > > > similar
> > > > > > for system swapping. Do I understand you correctly that you
> > > > > > want me
> > > > > > to add a call to eviction_valuable() also for that instead
> > > > > > of
> > > > > > swap_possible()?
> > > > > You should already have that. eviction_valuable is called in
> > > > > both
> > > > > cases.
> > > > > 
> > > > Hmm. I can only see it called from ttm_mem_evict_first() which
> > > > is
> > > > not
> > > > in the swapping path? Or do I miss something?
> > > Mhm, looks like my recollection was wrong. We should probably
> > > move
> > > the
> > > call into the ttm_bo_evict_swapout_allowable() function.
> > Yes, I think we also need a convention whether it's called dma_resv
> > locked or not, since the helper accesses bo->mem, which should
> > really
> > only be done under reservation. At the same point, there is value
> > in
> > calling this function while holding the LRU lock.
> 
> You actually need to call it while holding the lock because eviction 
> otherwise ends up in an endless loop.
> 
> Trying to fix that for years, but so far no luck with that.
> 
> > Also, I wonder whether implementations of this callback might
> > encounter
> > unexpected data when called from the swapout path, because at least
> > the
> > helper assumes it not in system memory, since it is accessing bo-
> > > mem.start.
> > So unless we use a separate callback for swapout, there's some
> > auditing
> > to be done.
> 
> Please audit the existing callbacks and move the callback into the 
> function after doing that.
> 
> Thanks,
> Christian.

Would it be OK if I also move the kref_get_unless_zero() to before 
ttm_bo_evict_swapout_allowable() to make the code less sensitive to
surprises?

/Thomas


> 
> > 
> > Pls let me know what you think.
> > Thanks,
> > Thomas
> > 
> > 
> > 
> > > Christian.
> > > 
> > > > Thanks,
> > > > 
> > > > Thomas
> > > > 
> > > > 
> > > > 
> > 
> 


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-12 13:02                   ` [Intel-gfx] " Thomas Hellström
@ 2021-05-12 13:05                     ` Christian König
  -1 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-12 13:05 UTC (permalink / raw)
  To: Thomas Hellström, Thomas Hellström (Intel),
	intel-gfx, dri-devel

Am 12.05.21 um 15:02 schrieb Thomas Hellström:
> On Wed, 2021-05-12 at 09:09 +0200, Christian König wrote:
>> Am 12.05.21 um 09:05 schrieb Thomas Hellström:
>>> On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
>>>> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>>>>> On 5/11/21 4:09 PM, Christian König wrote:
>>>>>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>>>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>>>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>>>>>> Most logical place to introduce TTM buffer objects is
>>>>>>>>> as an
>>>>>>>>> i915
>>>>>>>>> gem object backend. We need to add some ops to account
>>>>>>>>> for
>>>>>>>>> added
>>>>>>>>> functionality like delayed delete and LRU list
>>>>>>>>> manipulation.
>>>>>>>>>
>>>>>>>>> Initially we support only LMEM and SYSTEM memory, but
>>>>>>>>> SYSTEM
>>>>>>>>> (which in this case means evicted LMEM objects) is not
>>>>>>>>> visible to i915 GEM yet. The plan is to move the i915
>>>>>>>>> gem
>>>>>>>>> system
>>>>>>>>> region
>>>>>>>>> over to the TTM system memory type in upcoming patches.
>>>>>>>>>
>>>>>>>>> We set up GPU bindings directly both from LMEM and from
>>>>>>>>> the
>>>>>>>>> system
>>>>>>>>> region,
>>>>>>>>> as there is no need to use the legacy TTM_TT memory
>>>>>>>>> type.
>>>>>>>>> We reserve
>>>>>>>>> that for future porting of GGTT bindings to TTM.
>>>>>>>>>
>>>>>>>>> There are some changes to TTM to allow for purging
>>>>>>>>> system
>>>>>>>>> memory
>>>>>>>>> buffer
>>>>>>>>> objects and to refuse swapping of some objects:
>>>>>>>>> Unfortunately i915
>>>>>>>>> gem
>>>>>>>>> still relies heavily on short-term object pinning, and
>>>>>>>>> we've
>>>>>>>>> chosen to
>>>>>>>>> keep short-term-pinned buffer objects on the TTM LRU
>>>>>>>>> lists
>>>>>>>>> for now,
>>>>>>>>> meaning that we need some sort of mechanism to tell TTM
>>>>>>>>> they are not
>>>>>>>>> swappable. A longer term goal is to get rid of the
>>>>>>>>> short-
>>>>>>>>> term
>>>>>>>>> pinning.
>>>>>>>> Well just use the eviction_valuable interface for this.
>>>>>>> Yes, we do that for vram/lmem eviction, but we have nothing
>>>>>>> similar
>>>>>>> for system swapping. Do I understand you correctly that you
>>>>>>> want me
>>>>>>> to add a call to eviction_valuable() also for that instead
>>>>>>> of
>>>>>>> swap_possible()?
>>>>>> You should already have that. eviction_valuable is called in
>>>>>> both
>>>>>> cases.
>>>>>>
>>>>> Hmm. I can only see it called from ttm_mem_evict_first() which
>>>>> is
>>>>> not
>>>>> in the swapping path? Or do I miss something?
>>>> Mhm, looks like my recollection was wrong. We should probably
>>>> move
>>>> the
>>>> call into the ttm_bo_evict_swapout_allowable() function.
>>> Yes, I think we also need a convention whether it's called dma_resv
>>> locked or not, since the helper accesses bo->mem, which should
>>> really
>>> only be done under reservation. At the same point, there is value
>>> in
>>> calling this function while holding the LRU lock.
>> You actually need to call it while holding the lock because eviction
>> otherwise ends up in an endless loop.
>>
>> Trying to fix that for years, but so far no luck with that.
>>
>>> Also, I wonder whether implementations of this callback might
>>> encounter
>>> unexpected data when called from the swapout path, because at least
>>> the
>>> helper assumes it not in system memory, since it is accessing bo-
>>>> mem.start.
>>> So unless we use a separate callback for swapout, there's some
>>> auditing
>>> to be done.
>> Please audit the existing callbacks and move the callback into the
>> function after doing that.
>>
>> Thanks,
>> Christian.
> Would it be OK if I also move the kref_get_unless_zero() to before
> ttm_bo_evict_swapout_allowable() to make the code less sensitive to
> surprises?

No, because then you need a kref_put while holding the spinlock which is 
not allowed.

Christian.

>
> /Thomas
>
>
>>> Pls let me know what you think.
>>> Thanks,
>>> Thomas
>>>
>>>
>>>
>>>> Christian.
>>>>
>>>>> Thanks,
>>>>>
>>>>> Thomas
>>>>>
>>>>>
>>>>>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12 13:05                     ` Christian König
  0 siblings, 0 replies; 55+ messages in thread
From: Christian König @ 2021-05-12 13:05 UTC (permalink / raw)
  To: Thomas Hellström, Thomas Hellström (Intel),
	intel-gfx, dri-devel

Am 12.05.21 um 15:02 schrieb Thomas Hellström:
> On Wed, 2021-05-12 at 09:09 +0200, Christian König wrote:
>> Am 12.05.21 um 09:05 schrieb Thomas Hellström:
>>> On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
>>>> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>>>>> On 5/11/21 4:09 PM, Christian König wrote:
>>>>>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>>>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>>>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>>>>>> Most logical place to introduce TTM buffer objects is
>>>>>>>>> as an
>>>>>>>>> i915
>>>>>>>>> gem object backend. We need to add some ops to account
>>>>>>>>> for
>>>>>>>>> added
>>>>>>>>> functionality like delayed delete and LRU list
>>>>>>>>> manipulation.
>>>>>>>>>
>>>>>>>>> Initially we support only LMEM and SYSTEM memory, but
>>>>>>>>> SYSTEM
>>>>>>>>> (which in this case means evicted LMEM objects) is not
>>>>>>>>> visible to i915 GEM yet. The plan is to move the i915
>>>>>>>>> gem
>>>>>>>>> system
>>>>>>>>> region
>>>>>>>>> over to the TTM system memory type in upcoming patches.
>>>>>>>>>
>>>>>>>>> We set up GPU bindings directly both from LMEM and from
>>>>>>>>> the
>>>>>>>>> system
>>>>>>>>> region,
>>>>>>>>> as there is no need to use the legacy TTM_TT memory
>>>>>>>>> type.
>>>>>>>>> We reserve
>>>>>>>>> that for future porting of GGTT bindings to TTM.
>>>>>>>>>
>>>>>>>>> There are some changes to TTM to allow for purging
>>>>>>>>> system
>>>>>>>>> memory
>>>>>>>>> buffer
>>>>>>>>> objects and to refuse swapping of some objects:
>>>>>>>>> Unfortunately i915
>>>>>>>>> gem
>>>>>>>>> still relies heavily on short-term object pinning, and
>>>>>>>>> we've
>>>>>>>>> chosen to
>>>>>>>>> keep short-term-pinned buffer objects on the TTM LRU
>>>>>>>>> lists
>>>>>>>>> for now,
>>>>>>>>> meaning that we need some sort of mechanism to tell TTM
>>>>>>>>> they are not
>>>>>>>>> swappable. A longer term goal is to get rid of the
>>>>>>>>> short-
>>>>>>>>> term
>>>>>>>>> pinning.
>>>>>>>> Well just use the eviction_valuable interface for this.
>>>>>>> Yes, we do that for vram/lmem eviction, but we have nothing
>>>>>>> similar
>>>>>>> for system swapping. Do I understand you correctly that you
>>>>>>> want me
>>>>>>> to add a call to eviction_valuable() also for that instead
>>>>>>> of
>>>>>>> swap_possible()?
>>>>>> You should already have that. eviction_valuable is called in
>>>>>> both
>>>>>> cases.
>>>>>>
>>>>> Hmm. I can only see it called from ttm_mem_evict_first() which
>>>>> is
>>>>> not
>>>>> in the swapping path? Or do I miss something?
>>>> Mhm, looks like my recollection was wrong. We should probably
>>>> move
>>>> the
>>>> call into the ttm_bo_evict_swapout_allowable() function.
>>> Yes, I think we also need a convention whether it's called dma_resv
>>> locked or not, since the helper accesses bo->mem, which should
>>> really
>>> only be done under reservation. At the same point, there is value
>>> in
>>> calling this function while holding the LRU lock.
>> You actually need to call it while holding the lock because eviction
>> otherwise ends up in an endless loop.
>>
>> Trying to fix that for years, but so far no luck with that.
>>
>>> Also, I wonder whether implementations of this callback might
>>> encounter
>>> unexpected data when called from the swapout path, because at least
>>> the
>>> helper assumes it not in system memory, since it is accessing bo-
>>>> mem.start.
>>> So unless we use a separate callback for swapout, there's some
>>> auditing
>>> to be done.
>> Please audit the existing callbacks and move the callback into the
>> function after doing that.
>>
>> Thanks,
>> Christian.
> Would it be OK if I also move the kref_get_unless_zero() to before
> ttm_bo_evict_swapout_allowable() to make the code less sensitive to
> surprises?

No, because then you need a kref_put while holding the spinlock which is 
not allowed.

Christian.

>
> /Thomas
>
>
>>> Pls let me know what you think.
>>> Thanks,
>>> Thomas
>>>
>>>
>>>
>>>> Christian.
>>>>
>>>>> Thanks,
>>>>>
>>>>> Thomas
>>>>>
>>>>>
>>>>>
>

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
  2021-05-12 13:05                     ` [Intel-gfx] " Christian König
@ 2021-05-12 13:25                       ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12 13:25 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel


On 5/12/21 3:05 PM, Christian König wrote:
> Am 12.05.21 um 15:02 schrieb Thomas Hellström:
>> On Wed, 2021-05-12 at 09:09 +0200, Christian König wrote:
>>> Am 12.05.21 um 09:05 schrieb Thomas Hellström:
>>>> On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
>>>>> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>>>>>> On 5/11/21 4:09 PM, Christian König wrote:
>>>>>>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>>>>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>>>>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>>>>>>> Most logical place to introduce TTM buffer objects is
>>>>>>>>>> as an
>>>>>>>>>> i915
>>>>>>>>>> gem object backend. We need to add some ops to account
>>>>>>>>>> for
>>>>>>>>>> added
>>>>>>>>>> functionality like delayed delete and LRU list
>>>>>>>>>> manipulation.
>>>>>>>>>>
>>>>>>>>>> Initially we support only LMEM and SYSTEM memory, but
>>>>>>>>>> SYSTEM
>>>>>>>>>> (which in this case means evicted LMEM objects) is not
>>>>>>>>>> visible to i915 GEM yet. The plan is to move the i915
>>>>>>>>>> gem
>>>>>>>>>> system
>>>>>>>>>> region
>>>>>>>>>> over to the TTM system memory type in upcoming patches.
>>>>>>>>>>
>>>>>>>>>> We set up GPU bindings directly both from LMEM and from
>>>>>>>>>> the
>>>>>>>>>> system
>>>>>>>>>> region,
>>>>>>>>>> as there is no need to use the legacy TTM_TT memory
>>>>>>>>>> type.
>>>>>>>>>> We reserve
>>>>>>>>>> that for future porting of GGTT bindings to TTM.
>>>>>>>>>>
>>>>>>>>>> There are some changes to TTM to allow for purging
>>>>>>>>>> system
>>>>>>>>>> memory
>>>>>>>>>> buffer
>>>>>>>>>> objects and to refuse swapping of some objects:
>>>>>>>>>> Unfortunately i915
>>>>>>>>>> gem
>>>>>>>>>> still relies heavily on short-term object pinning, and
>>>>>>>>>> we've
>>>>>>>>>> chosen to
>>>>>>>>>> keep short-term-pinned buffer objects on the TTM LRU
>>>>>>>>>> lists
>>>>>>>>>> for now,
>>>>>>>>>> meaning that we need some sort of mechanism to tell TTM
>>>>>>>>>> they are not
>>>>>>>>>> swappable. A longer term goal is to get rid of the
>>>>>>>>>> short-
>>>>>>>>>> term
>>>>>>>>>> pinning.
>>>>>>>>> Well just use the eviction_valuable interface for this.
>>>>>>>> Yes, we do that for vram/lmem eviction, but we have nothing
>>>>>>>> similar
>>>>>>>> for system swapping. Do I understand you correctly that you
>>>>>>>> want me
>>>>>>>> to add a call to eviction_valuable() also for that instead
>>>>>>>> of
>>>>>>>> swap_possible()?
>>>>>>> You should already have that. eviction_valuable is called in
>>>>>>> both
>>>>>>> cases.
>>>>>>>
>>>>>> Hmm. I can only see it called from ttm_mem_evict_first() which
>>>>>> is
>>>>>> not
>>>>>> in the swapping path? Or do I miss something?
>>>>> Mhm, looks like my recollection was wrong. We should probably
>>>>> move
>>>>> the
>>>>> call into the ttm_bo_evict_swapout_allowable() function.
>>>> Yes, I think we also need a convention whether it's called dma_resv
>>>> locked or not, since the helper accesses bo->mem, which should
>>>> really
>>>> only be done under reservation. At the same point, there is value
>>>> in
>>>> calling this function while holding the LRU lock.
>>> You actually need to call it while holding the lock because eviction
>>> otherwise ends up in an endless loop.
>>>
>>> Trying to fix that for years, but so far no luck with that.
>>>
>>>> Also, I wonder whether implementations of this callback might
>>>> encounter
>>>> unexpected data when called from the swapout path, because at least
>>>> the
>>>> helper assumes it not in system memory, since it is accessing bo-
>>>>> mem.start.
>>>> So unless we use a separate callback for swapout, there's some
>>>> auditing
>>>> to be done.
>>> Please audit the existing callbacks and move the callback into the
>>> function after doing that.
>>>
>>> Thanks,
>>> Christian.
>> Would it be OK if I also move the kref_get_unless_zero() to before
>> ttm_bo_evict_swapout_allowable() to make the code less sensitive to
>> surprises?
>
> No, because then you need a kref_put while holding the spinlock which 
> is not allowed.
>
> Christian.

Ugh. yes, you're right.

/Thomas



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend
@ 2021-05-12 13:25                       ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-12 13:25 UTC (permalink / raw)
  To: Christian König, Thomas Hellström (Intel),
	intel-gfx, dri-devel


On 5/12/21 3:05 PM, Christian König wrote:
> Am 12.05.21 um 15:02 schrieb Thomas Hellström:
>> On Wed, 2021-05-12 at 09:09 +0200, Christian König wrote:
>>> Am 12.05.21 um 09:05 schrieb Thomas Hellström:
>>>> On Wed, 2021-05-12 at 08:57 +0200, Christian König wrote:
>>>>> Am 11.05.21 um 16:28 schrieb Thomas Hellström:
>>>>>> On 5/11/21 4:09 PM, Christian König wrote:
>>>>>>> Am 11.05.21 um 16:06 schrieb Thomas Hellström (Intel):
>>>>>>>> On 5/11/21 3:58 PM, Christian König wrote:
>>>>>>>>> Am 11.05.21 um 15:25 schrieb Thomas Hellström:
>>>>>>>>>> Most logical place to introduce TTM buffer objects is
>>>>>>>>>> as an
>>>>>>>>>> i915
>>>>>>>>>> gem object backend. We need to add some ops to account
>>>>>>>>>> for
>>>>>>>>>> added
>>>>>>>>>> functionality like delayed delete and LRU list
>>>>>>>>>> manipulation.
>>>>>>>>>>
>>>>>>>>>> Initially we support only LMEM and SYSTEM memory, but
>>>>>>>>>> SYSTEM
>>>>>>>>>> (which in this case means evicted LMEM objects) is not
>>>>>>>>>> visible to i915 GEM yet. The plan is to move the i915
>>>>>>>>>> gem
>>>>>>>>>> system
>>>>>>>>>> region
>>>>>>>>>> over to the TTM system memory type in upcoming patches.
>>>>>>>>>>
>>>>>>>>>> We set up GPU bindings directly both from LMEM and from
>>>>>>>>>> the
>>>>>>>>>> system
>>>>>>>>>> region,
>>>>>>>>>> as there is no need to use the legacy TTM_TT memory
>>>>>>>>>> type.
>>>>>>>>>> We reserve
>>>>>>>>>> that for future porting of GGTT bindings to TTM.
>>>>>>>>>>
>>>>>>>>>> There are some changes to TTM to allow for purging
>>>>>>>>>> system
>>>>>>>>>> memory
>>>>>>>>>> buffer
>>>>>>>>>> objects and to refuse swapping of some objects:
>>>>>>>>>> Unfortunately i915
>>>>>>>>>> gem
>>>>>>>>>> still relies heavily on short-term object pinning, and
>>>>>>>>>> we've
>>>>>>>>>> chosen to
>>>>>>>>>> keep short-term-pinned buffer objects on the TTM LRU
>>>>>>>>>> lists
>>>>>>>>>> for now,
>>>>>>>>>> meaning that we need some sort of mechanism to tell TTM
>>>>>>>>>> they are not
>>>>>>>>>> swappable. A longer term goal is to get rid of the
>>>>>>>>>> short-
>>>>>>>>>> term
>>>>>>>>>> pinning.
>>>>>>>>> Well just use the eviction_valuable interface for this.
>>>>>>>> Yes, we do that for vram/lmem eviction, but we have nothing
>>>>>>>> similar
>>>>>>>> for system swapping. Do I understand you correctly that you
>>>>>>>> want me
>>>>>>>> to add a call to eviction_valuable() also for that instead
>>>>>>>> of
>>>>>>>> swap_possible()?
>>>>>>> You should already have that. eviction_valuable is called in
>>>>>>> both
>>>>>>> cases.
>>>>>>>
>>>>>> Hmm. I can only see it called from ttm_mem_evict_first() which
>>>>>> is
>>>>>> not
>>>>>> in the swapping path? Or do I miss something?
>>>>> Mhm, looks like my recollection was wrong. We should probably
>>>>> move
>>>>> the
>>>>> call into the ttm_bo_evict_swapout_allowable() function.
>>>> Yes, I think we also need a convention whether it's called dma_resv
>>>> locked or not, since the helper accesses bo->mem, which should
>>>> really
>>>> only be done under reservation. At the same point, there is value
>>>> in
>>>> calling this function while holding the LRU lock.
>>> You actually need to call it while holding the lock because eviction
>>> otherwise ends up in an endless loop.
>>>
>>> Trying to fix that for years, but so far no luck with that.
>>>
>>>> Also, I wonder whether implementations of this callback might
>>>> encounter
>>>> unexpected data when called from the swapout path, because at least
>>>> the
>>>> helper assumes it not in system memory, since it is accessing bo-
>>>>> mem.start.
>>>> So unless we use a separate callback for swapout, there's some
>>>> auditing
>>>> to be done.
>>> Please audit the existing callbacks and move the callback into the
>>> function after doing that.
>>>
>>> Thanks,
>>> Christian.
>> Would it be OK if I also move the kref_get_unless_zero() to before
>> ttm_bo_evict_swapout_allowable() to make the code less sensitive to
>> surprises?
>
> No, because then you need a kref_put while holding the spinlock which 
> is not allowed.
>
> Christian.

Ugh. yes, you're right.

/Thomas


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
  2021-05-12  8:57     ` Matthew Auld
@ 2021-05-17  7:18       ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-17  7:18 UTC (permalink / raw)
  To: Matthew Auld
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Wed, 2021-05-12 at 09:57 +0100, Matthew Auld wrote:
> On Tue, 11 May 2021 at 14:26, Thomas Hellström
> <thomas.hellstrom@linux.intel.com> wrote:
> > 
> > Temporarily remove the buddy allocator and related selftests
> > and hook up the TTM range manager for i915 regions.
> > 
> > In order to support some of the mock region-related selftests, we
> > need to
> > be able to initialize the TTM range-manager standalone without a
> > struct
> > ttm_device. Add two functions to allow that to the TTM api.
> > 
> > Finally modify the mock region selftests somewhat to account for a
> > fragmenting manager.
> > 
> > Cc: Christian König <christian.koenig@amd.com>
> > Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/Kconfig                  |   1 +
> >  drivers/gpu/drm/i915/Makefile                 |   2 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
> >  .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
> >  drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
> >  drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
> >  drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
> >  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
> >  drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
> >  drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
> >  drivers/gpu/drm/i915/i915_drv.c               |   8 +
> >  drivers/gpu/drm/i915/i915_drv.h               |   7 +-
> >  drivers/gpu/drm/i915/i915_gem.c               |   1 +
> >  drivers/gpu/drm/i915/i915_globals.c           |   1 -
> >  drivers/gpu/drm/i915/i915_globals.h           |   1 -
> >  drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
> >  drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
> >  drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
> >  drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
> >  drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
> >  drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
> >  drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 --------------
> > ----
> >  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
> >  .../drm/i915/selftests/intel_memory_region.c  | 133 +--
> >  drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
> >  drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
> >  include/drm/ttm/ttm_bo_driver.h               |  23 +
> >  31 files changed, 715 insertions(+), 1771 deletions(-)
> >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
> >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
> >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
> >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
> >  delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c
> > 
> > diff --git a/drivers/gpu/drm/i915/Kconfig
> > b/drivers/gpu/drm/i915/Kconfig
> > index 1e1cb245fca7..b63d374dff23 100644
> > --- a/drivers/gpu/drm/i915/Kconfig
> > +++ b/drivers/gpu/drm/i915/Kconfig
> > @@ -26,6 +26,7 @@ config DRM_I915
> >         select SND_HDA_I915 if SND_HDA_CORE
> >         select CEC_CORE if CEC_NOTIFIER
> >         select VMAP_PFN
> > +       select DRM_TTM
> >         help
> >           Choose this option if you have a system that has "Intel
> > Graphics
> >           Media Accelerator" or "HD Graphics" integrated graphics,
> > diff --git a/drivers/gpu/drm/i915/Makefile
> > b/drivers/gpu/drm/i915/Makefile
> > index d0d936d9137b..cb8823570996 100644
> > --- a/drivers/gpu/drm/i915/Makefile
> > +++ b/drivers/gpu/drm/i915/Makefile
> > @@ -50,6 +50,7 @@ i915-y += i915_drv.o \
> >           intel_memory_region.o \
> >           intel_pch.o \
> >           intel_pm.o \
> > +         intel_region_ttm.o \
> >           intel_runtime_pm.o \
> >           intel_sideband.o \
> >           intel_step.o \
> > @@ -160,7 +161,6 @@ gem-y += \
> >  i915-y += \
> >           $(gem-y) \
> >           i915_active.o \
> > -         i915_buddy.o \
> >           i915_cmd_parser.o \
> >           i915_gem_evict.o \
> >           i915_gem_gtt.o \
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > index f44bdd08f7cb..f42803ea48f2 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > @@ -4,16 +4,70 @@
> >   */
> > 
> >  #include "intel_memory_region.h"
> > +#include "intel_region_ttm.h"
> >  #include "gem/i915_gem_region.h"
> >  #include "gem/i915_gem_lmem.h"
> >  #include "i915_drv.h"
> > 
> > +static void lmem_put_pages(struct drm_i915_gem_object *obj,
> > +                                 struct sg_table *pages)
> > +{
> > +       intel_region_ttm_node_free(obj->mm.region, obj-
> > >mm.st_mm_node);
> > +       obj->mm.dirty = false;
> > +       sg_free_table(pages);
> > +       kfree(pages);
> > +}
> > +
> > +static int lmem_get_pages(struct drm_i915_gem_object *obj)
> > +{
> > +       unsigned int flags;
> > +       struct sg_table *pages;
> > +
> > +       flags = I915_ALLOC_MIN_PAGE_SIZE;
> > +       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> > +               flags |= I915_ALLOC_CONTIGUOUS;
> > +
> > +       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj-
> > >mm.region,
> > +                                                        obj-
> > >base.size,
> > +                                                        flags);
> > +       if (IS_ERR(obj->mm.st_mm_node))
> > +               return PTR_ERR(obj->mm.st_mm_node);
> > +
> > +       /* Range manager is always contigous */
> > +       if (obj->mm.region->is_range_manager)
> > +               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> > +       pages = intel_region_ttm_node_to_st(obj->mm.region, obj-
> > >mm.st_mm_node);
> > +       if (IS_ERR(pages))
> > +               return PTR_ERR(pages);
> 
> error unwind?
> 
> > +
> > +       __i915_gem_object_set_pages(obj, pages,
> > +                                   i915_sg_dma_page_sizes(pages-
> > >sgl));
> > +
> > +       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> > +               void __iomem *vaddr =
> > +                       i915_gem_object_lmem_io_map(obj, 0, obj-
> > >base.size);
> > +
> > +               if (!vaddr) {
> > +                       struct sg_table *pages =
> > +                               __i915_gem_object_unset_pages(obj);
> > +
> > +                       if (!IS_ERR_OR_NULL(pages))
> > +                               lmem_put_pages(obj, pages);
> > +               }
> > +
> > +               memset_io(vaddr, 0, obj->base.size);
> > +               io_mapping_unmap(vaddr);
> > +       }
> > +
> > +       return 0;
> > +}
> 
> <snip>
> 
> > +/**
> > + * i915_sg_dma_page_sizes - Calculate page sizes from a
> > scatterlist
> > + * @sg: The scatterlist from which to calculate page sizes
> > + *
> > + * Return: a value with bits sets for relevant page sizes.
> > + */
> > +static inline unsigned int i915_sg_dma_page_sizes(struct
> > scatterlist *sg)
> > +{
> > +       unsigned int page_sizes;
> > +
> > +       page_sizes = 0;
> > +       while (sg) {
> > +               GEM_BUG_ON(sg->offset);
> > +               GEM_BUG_ON(!IS_ALIGNED(sg->dma_length, PAGE_SIZE));
> > +               page_sizes |= sg->dma_length;
> > +               sg = __sg_next(sg);
> > +       }
> > +
> > +       /*
> > +        * Is this necessary to support building large GPU pages
> > from
> > +        * even larger segments?
> > +        */
> 
> We just need to know the above sg page_sizes, which is the mask of
> sg->dma_length for each sg. Later in __i915_gem_object_set_pages() we
> use this to determine the potential GPU page sizes for the object,
> depending on what the device supports. So the below stuff shouldn't
> be
> needed. Also we can just use i915_sg_page_sizes() here.

I noticed that i915_sg_page_sizes() uses sg->length() instead of sg-
>dma_length(). That doesn't look like what we're after here. Do you
know if there is a reason for that?

Thanks,
Thomas



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
@ 2021-05-17  7:18       ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-17  7:18 UTC (permalink / raw)
  To: Matthew Auld
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Wed, 2021-05-12 at 09:57 +0100, Matthew Auld wrote:
> On Tue, 11 May 2021 at 14:26, Thomas Hellström
> <thomas.hellstrom@linux.intel.com> wrote:
> > 
> > Temporarily remove the buddy allocator and related selftests
> > and hook up the TTM range manager for i915 regions.
> > 
> > In order to support some of the mock region-related selftests, we
> > need to
> > be able to initialize the TTM range-manager standalone without a
> > struct
> > ttm_device. Add two functions to allow that to the TTM api.
> > 
> > Finally modify the mock region selftests somewhat to account for a
> > fragmenting manager.
> > 
> > Cc: Christian König <christian.koenig@amd.com>
> > Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/Kconfig                  |   1 +
> >  drivers/gpu/drm/i915/Makefile                 |   2 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
> >  .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
> >  drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
> >  drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
> >  drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
> >  drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
> >  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
> >  drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
> >  drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
> >  drivers/gpu/drm/i915/i915_drv.c               |   8 +
> >  drivers/gpu/drm/i915/i915_drv.h               |   7 +-
> >  drivers/gpu/drm/i915/i915_gem.c               |   1 +
> >  drivers/gpu/drm/i915/i915_globals.c           |   1 -
> >  drivers/gpu/drm/i915/i915_globals.h           |   1 -
> >  drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
> >  drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
> >  drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
> >  drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
> >  drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
> >  drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
> >  drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 --------------
> > ----
> >  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
> >  .../drm/i915/selftests/intel_memory_region.c  | 133 +--
> >  drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
> >  drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
> >  include/drm/ttm/ttm_bo_driver.h               |  23 +
> >  31 files changed, 715 insertions(+), 1771 deletions(-)
> >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
> >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
> >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
> >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
> >  delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c
> > 
> > diff --git a/drivers/gpu/drm/i915/Kconfig
> > b/drivers/gpu/drm/i915/Kconfig
> > index 1e1cb245fca7..b63d374dff23 100644
> > --- a/drivers/gpu/drm/i915/Kconfig
> > +++ b/drivers/gpu/drm/i915/Kconfig
> > @@ -26,6 +26,7 @@ config DRM_I915
> >         select SND_HDA_I915 if SND_HDA_CORE
> >         select CEC_CORE if CEC_NOTIFIER
> >         select VMAP_PFN
> > +       select DRM_TTM
> >         help
> >           Choose this option if you have a system that has "Intel
> > Graphics
> >           Media Accelerator" or "HD Graphics" integrated graphics,
> > diff --git a/drivers/gpu/drm/i915/Makefile
> > b/drivers/gpu/drm/i915/Makefile
> > index d0d936d9137b..cb8823570996 100644
> > --- a/drivers/gpu/drm/i915/Makefile
> > +++ b/drivers/gpu/drm/i915/Makefile
> > @@ -50,6 +50,7 @@ i915-y += i915_drv.o \
> >           intel_memory_region.o \
> >           intel_pch.o \
> >           intel_pm.o \
> > +         intel_region_ttm.o \
> >           intel_runtime_pm.o \
> >           intel_sideband.o \
> >           intel_step.o \
> > @@ -160,7 +161,6 @@ gem-y += \
> >  i915-y += \
> >           $(gem-y) \
> >           i915_active.o \
> > -         i915_buddy.o \
> >           i915_cmd_parser.o \
> >           i915_gem_evict.o \
> >           i915_gem_gtt.o \
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > index f44bdd08f7cb..f42803ea48f2 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > @@ -4,16 +4,70 @@
> >   */
> > 
> >  #include "intel_memory_region.h"
> > +#include "intel_region_ttm.h"
> >  #include "gem/i915_gem_region.h"
> >  #include "gem/i915_gem_lmem.h"
> >  #include "i915_drv.h"
> > 
> > +static void lmem_put_pages(struct drm_i915_gem_object *obj,
> > +                                 struct sg_table *pages)
> > +{
> > +       intel_region_ttm_node_free(obj->mm.region, obj-
> > >mm.st_mm_node);
> > +       obj->mm.dirty = false;
> > +       sg_free_table(pages);
> > +       kfree(pages);
> > +}
> > +
> > +static int lmem_get_pages(struct drm_i915_gem_object *obj)
> > +{
> > +       unsigned int flags;
> > +       struct sg_table *pages;
> > +
> > +       flags = I915_ALLOC_MIN_PAGE_SIZE;
> > +       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> > +               flags |= I915_ALLOC_CONTIGUOUS;
> > +
> > +       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj-
> > >mm.region,
> > +                                                        obj-
> > >base.size,
> > +                                                        flags);
> > +       if (IS_ERR(obj->mm.st_mm_node))
> > +               return PTR_ERR(obj->mm.st_mm_node);
> > +
> > +       /* Range manager is always contigous */
> > +       if (obj->mm.region->is_range_manager)
> > +               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> > +       pages = intel_region_ttm_node_to_st(obj->mm.region, obj-
> > >mm.st_mm_node);
> > +       if (IS_ERR(pages))
> > +               return PTR_ERR(pages);
> 
> error unwind?
> 
> > +
> > +       __i915_gem_object_set_pages(obj, pages,
> > +                                   i915_sg_dma_page_sizes(pages-
> > >sgl));
> > +
> > +       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> > +               void __iomem *vaddr =
> > +                       i915_gem_object_lmem_io_map(obj, 0, obj-
> > >base.size);
> > +
> > +               if (!vaddr) {
> > +                       struct sg_table *pages =
> > +                               __i915_gem_object_unset_pages(obj);
> > +
> > +                       if (!IS_ERR_OR_NULL(pages))
> > +                               lmem_put_pages(obj, pages);
> > +               }
> > +
> > +               memset_io(vaddr, 0, obj->base.size);
> > +               io_mapping_unmap(vaddr);
> > +       }
> > +
> > +       return 0;
> > +}
> 
> <snip>
> 
> > +/**
> > + * i915_sg_dma_page_sizes - Calculate page sizes from a
> > scatterlist
> > + * @sg: The scatterlist from which to calculate page sizes
> > + *
> > + * Return: a value with bits sets for relevant page sizes.
> > + */
> > +static inline unsigned int i915_sg_dma_page_sizes(struct
> > scatterlist *sg)
> > +{
> > +       unsigned int page_sizes;
> > +
> > +       page_sizes = 0;
> > +       while (sg) {
> > +               GEM_BUG_ON(sg->offset);
> > +               GEM_BUG_ON(!IS_ALIGNED(sg->dma_length, PAGE_SIZE));
> > +               page_sizes |= sg->dma_length;
> > +               sg = __sg_next(sg);
> > +       }
> > +
> > +       /*
> > +        * Is this necessary to support building large GPU pages
> > from
> > +        * even larger segments?
> > +        */
> 
> We just need to know the above sg page_sizes, which is the mask of
> sg->dma_length for each sg. Later in __i915_gem_object_set_pages() we
> use this to determine the potential GPU page sizes for the object,
> depending on what the device supports. So the below stuff shouldn't
> be
> needed. Also we can just use i915_sg_page_sizes() here.

I noticed that i915_sg_page_sizes() uses sg->length() instead of sg-
>dma_length(). That doesn't look like what we're after here. Do you
know if there is a reason for that?

Thanks,
Thomas


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
  2021-05-17  7:18       ` Thomas Hellström
@ 2021-05-17  7:28         ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-17  7:28 UTC (permalink / raw)
  To: Matthew Auld
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Mon, 2021-05-17 at 09:18 +0200, Thomas Hellström wrote:
> On Wed, 2021-05-12 at 09:57 +0100, Matthew Auld wrote:
> > On Tue, 11 May 2021 at 14:26, Thomas Hellström
> > <thomas.hellstrom@linux.intel.com> wrote:
> > > 
> > > Temporarily remove the buddy allocator and related selftests
> > > and hook up the TTM range manager for i915 regions.
> > > 
> > > In order to support some of the mock region-related selftests, we
> > > need to
> > > be able to initialize the TTM range-manager standalone without a
> > > struct
> > > ttm_device. Add two functions to allow that to the TTM api.
> > > 
> > > Finally modify the mock region selftests somewhat to account for
> > > a
> > > fragmenting manager.
> > > 
> > > Cc: Christian König <christian.koenig@amd.com>
> > > Signed-off-by: Thomas Hellström
> > > <thomas.hellstrom@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/Kconfig                  |   1 +
> > >  drivers/gpu/drm/i915/Makefile                 |   2 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
> > >  .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
> > >  drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
> > >  drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
> > >  drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
> > >  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
> > >  drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
> > >  drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
> > >  drivers/gpu/drm/i915/i915_drv.c               |   8 +
> > >  drivers/gpu/drm/i915/i915_drv.h               |   7 +-
> > >  drivers/gpu/drm/i915/i915_gem.c               |   1 +
> > >  drivers/gpu/drm/i915/i915_globals.c           |   1 -
> > >  drivers/gpu/drm/i915/i915_globals.h           |   1 -
> > >  drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
> > >  drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
> > >  drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
> > >  drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
> > >  drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
> > >  drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
> > >  drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------
> > > --
> > > ----
> > >  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
> > >  .../drm/i915/selftests/intel_memory_region.c  | 133 +--
> > >  drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
> > >  drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
> > >  include/drm/ttm/ttm_bo_driver.h               |  23 +
> > >  31 files changed, 715 insertions(+), 1771 deletions(-)
> > >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
> > >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
> > >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
> > >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
> > >  delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c
> > > 
> > > diff --git a/drivers/gpu/drm/i915/Kconfig
> > > b/drivers/gpu/drm/i915/Kconfig
> > > index 1e1cb245fca7..b63d374dff23 100644
> > > --- a/drivers/gpu/drm/i915/Kconfig
> > > +++ b/drivers/gpu/drm/i915/Kconfig
> > > @@ -26,6 +26,7 @@ config DRM_I915
> > >         select SND_HDA_I915 if SND_HDA_CORE
> > >         select CEC_CORE if CEC_NOTIFIER
> > >         select VMAP_PFN
> > > +       select DRM_TTM
> > >         help
> > >           Choose this option if you have a system that has "Intel
> > > Graphics
> > >           Media Accelerator" or "HD Graphics" integrated
> > > graphics,
> > > diff --git a/drivers/gpu/drm/i915/Makefile
> > > b/drivers/gpu/drm/i915/Makefile
> > > index d0d936d9137b..cb8823570996 100644
> > > --- a/drivers/gpu/drm/i915/Makefile
> > > +++ b/drivers/gpu/drm/i915/Makefile
> > > @@ -50,6 +50,7 @@ i915-y += i915_drv.o \
> > >           intel_memory_region.o \
> > >           intel_pch.o \
> > >           intel_pm.o \
> > > +         intel_region_ttm.o \
> > >           intel_runtime_pm.o \
> > >           intel_sideband.o \
> > >           intel_step.o \
> > > @@ -160,7 +161,6 @@ gem-y += \
> > >  i915-y += \
> > >           $(gem-y) \
> > >           i915_active.o \
> > > -         i915_buddy.o \
> > >           i915_cmd_parser.o \
> > >           i915_gem_evict.o \
> > >           i915_gem_gtt.o \
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > index f44bdd08f7cb..f42803ea48f2 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > @@ -4,16 +4,70 @@
> > >   */
> > > 
> > >  #include "intel_memory_region.h"
> > > +#include "intel_region_ttm.h"
> > >  #include "gem/i915_gem_region.h"
> > >  #include "gem/i915_gem_lmem.h"
> > >  #include "i915_drv.h"
> > > 
> > > +static void lmem_put_pages(struct drm_i915_gem_object *obj,
> > > +                                 struct sg_table *pages)
> > > +{
> > > +       intel_region_ttm_node_free(obj->mm.region, obj-
> > > > mm.st_mm_node);
> > > +       obj->mm.dirty = false;
> > > +       sg_free_table(pages);
> > > +       kfree(pages);
> > > +}
> > > +
> > > +static int lmem_get_pages(struct drm_i915_gem_object *obj)
> > > +{
> > > +       unsigned int flags;
> > > +       struct sg_table *pages;
> > > +
> > > +       flags = I915_ALLOC_MIN_PAGE_SIZE;
> > > +       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> > > +               flags |= I915_ALLOC_CONTIGUOUS;
> > > +
> > > +       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj-
> > > > mm.region,
> > > +                                                        obj-
> > > > base.size,
> > > +                                                        flags);
> > > +       if (IS_ERR(obj->mm.st_mm_node))
> > > +               return PTR_ERR(obj->mm.st_mm_node);
> > > +
> > > +       /* Range manager is always contigous */
> > > +       if (obj->mm.region->is_range_manager)
> > > +               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> > > +       pages = intel_region_ttm_node_to_st(obj->mm.region, obj-
> > > > mm.st_mm_node);
> > > +       if (IS_ERR(pages))
> > > +               return PTR_ERR(pages);
> > 
> > error unwind?
> > 
> > > +
> > > +       __i915_gem_object_set_pages(obj, pages,
> > > +                                   i915_sg_dma_page_sizes(pages-
> > > > sgl));
> > > +
> > > +       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> > > +               void __iomem *vaddr =
> > > +                       i915_gem_object_lmem_io_map(obj, 0, obj-
> > > > base.size);
> > > +
> > > +               if (!vaddr) {
> > > +                       struct sg_table *pages =
> > > +                              
> > > __i915_gem_object_unset_pages(obj);
> > > +
> > > +                       if (!IS_ERR_OR_NULL(pages))
> > > +                               lmem_put_pages(obj, pages);
> > > +               }
> > > +
> > > +               memset_io(vaddr, 0, obj->base.size);
> > > +               io_mapping_unmap(vaddr);
> > > +       }
> > > +
> > > +       return 0;
> > > +}
> > 
> > <snip>
> > 
> > > +/**
> > > + * i915_sg_dma_page_sizes - Calculate page sizes from a
> > > scatterlist
> > > + * @sg: The scatterlist from which to calculate page sizes
> > > + *
> > > + * Return: a value with bits sets for relevant page sizes.
> > > + */
> > > +static inline unsigned int i915_sg_dma_page_sizes(struct
> > > scatterlist *sg)
> > > +{
> > > +       unsigned int page_sizes;
> > > +
> > > +       page_sizes = 0;
> > > +       while (sg) {
> > > +               GEM_BUG_ON(sg->offset);
> > > +               GEM_BUG_ON(!IS_ALIGNED(sg->dma_length,
> > > PAGE_SIZE));
> > > +               page_sizes |= sg->dma_length;
> > > +               sg = __sg_next(sg);
> > > +       }
> > > +
> > > +       /*
> > > +        * Is this necessary to support building large GPU pages
> > > from
> > > +        * even larger segments?
> > > +        */
> > 
> > We just need to know the above sg page_sizes, which is the mask of
> > sg->dma_length for each sg. Later in __i915_gem_object_set_pages()
> > we
> > use this to determine the potential GPU page sizes for the object,
> > depending on what the device supports. So the below stuff shouldn't
> > be
> > needed. Also we can just use i915_sg_page_sizes() here.
> 
> I noticed that i915_sg_page_sizes() uses sg->length() instead of sg-
> > dma_length(). That doesn't look like what we're after here. Do you
> know if there is a reason for that?

Actually, looking at the users, that seems like a bug. I'll make a
separate patch out of it.

/Thomas

> 
> Thanks,
> Thomas
> 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers.
@ 2021-05-17  7:28         ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-17  7:28 UTC (permalink / raw)
  To: Matthew Auld
  Cc: Intel Graphics Development, Christian König, ML dri-devel

On Mon, 2021-05-17 at 09:18 +0200, Thomas Hellström wrote:
> On Wed, 2021-05-12 at 09:57 +0100, Matthew Auld wrote:
> > On Tue, 11 May 2021 at 14:26, Thomas Hellström
> > <thomas.hellstrom@linux.intel.com> wrote:
> > > 
> > > Temporarily remove the buddy allocator and related selftests
> > > and hook up the TTM range manager for i915 regions.
> > > 
> > > In order to support some of the mock region-related selftests, we
> > > need to
> > > be able to initialize the TTM range-manager standalone without a
> > > struct
> > > ttm_device. Add two functions to allow that to the TTM api.
> > > 
> > > Finally modify the mock region selftests somewhat to account for
> > > a
> > > fragmenting manager.
> > > 
> > > Cc: Christian König <christian.koenig@amd.com>
> > > Signed-off-by: Thomas Hellström
> > > <thomas.hellstrom@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/Kconfig                  |   1 +
> > >  drivers/gpu/drm/i915/Makefile                 |   2 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_lmem.c      |  58 +-
> > >  .../gpu/drm/i915/gem/i915_gem_object_types.h  |   6 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_pages.c     |   3 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_region.c    | 120 ---
> > >  drivers/gpu/drm/i915/gem/i915_gem_region.h    |   4 -
> > >  drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |   4 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_stolen.c    |  10 +-
> > >  drivers/gpu/drm/i915/gem/i915_gem_stolen.h    |   9 +-
> > >  drivers/gpu/drm/i915/gt/intel_gt.c            |   2 -
> > >  drivers/gpu/drm/i915/gt/intel_region_lmem.c   |  27 +-
> > >  drivers/gpu/drm/i915/i915_buddy.c             | 435 ----------
> > >  drivers/gpu/drm/i915/i915_buddy.h             | 131 ---
> > >  drivers/gpu/drm/i915/i915_drv.c               |   8 +
> > >  drivers/gpu/drm/i915/i915_drv.h               |   7 +-
> > >  drivers/gpu/drm/i915/i915_gem.c               |   1 +
> > >  drivers/gpu/drm/i915/i915_globals.c           |   1 -
> > >  drivers/gpu/drm/i915/i915_globals.h           |   1 -
> > >  drivers/gpu/drm/i915/i915_scatterlist.c       |  70 ++
> > >  drivers/gpu/drm/i915/i915_scatterlist.h       |  35 +
> > >  drivers/gpu/drm/i915/intel_memory_region.c    | 180 ++--
> > >  drivers/gpu/drm/i915/intel_memory_region.h    |  44 +-
> > >  drivers/gpu/drm/i915/intel_region_ttm.c       | 246 ++++++
> > >  drivers/gpu/drm/i915/intel_region_ttm.h       |  29 +
> > >  drivers/gpu/drm/i915/selftests/i915_buddy.c   | 789 ------------
> > > --
> > > ----
> > >  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
> > >  .../drm/i915/selftests/intel_memory_region.c  | 133 +--
> > >  drivers/gpu/drm/i915/selftests/mock_region.c  |  51 +-
> > >  drivers/gpu/drm/ttm/ttm_range_manager.c       |  55 +-
> > >  include/drm/ttm/ttm_bo_driver.h               |  23 +
> > >  31 files changed, 715 insertions(+), 1771 deletions(-)
> > >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
> > >  delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
> > >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.c
> > >  create mode 100644 drivers/gpu/drm/i915/intel_region_ttm.h
> > >  delete mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c
> > > 
> > > diff --git a/drivers/gpu/drm/i915/Kconfig
> > > b/drivers/gpu/drm/i915/Kconfig
> > > index 1e1cb245fca7..b63d374dff23 100644
> > > --- a/drivers/gpu/drm/i915/Kconfig
> > > +++ b/drivers/gpu/drm/i915/Kconfig
> > > @@ -26,6 +26,7 @@ config DRM_I915
> > >         select SND_HDA_I915 if SND_HDA_CORE
> > >         select CEC_CORE if CEC_NOTIFIER
> > >         select VMAP_PFN
> > > +       select DRM_TTM
> > >         help
> > >           Choose this option if you have a system that has "Intel
> > > Graphics
> > >           Media Accelerator" or "HD Graphics" integrated
> > > graphics,
> > > diff --git a/drivers/gpu/drm/i915/Makefile
> > > b/drivers/gpu/drm/i915/Makefile
> > > index d0d936d9137b..cb8823570996 100644
> > > --- a/drivers/gpu/drm/i915/Makefile
> > > +++ b/drivers/gpu/drm/i915/Makefile
> > > @@ -50,6 +50,7 @@ i915-y += i915_drv.o \
> > >           intel_memory_region.o \
> > >           intel_pch.o \
> > >           intel_pm.o \
> > > +         intel_region_ttm.o \
> > >           intel_runtime_pm.o \
> > >           intel_sideband.o \
> > >           intel_step.o \
> > > @@ -160,7 +161,6 @@ gem-y += \
> > >  i915-y += \
> > >           $(gem-y) \
> > >           i915_active.o \
> > > -         i915_buddy.o \
> > >           i915_cmd_parser.o \
> > >           i915_gem_evict.o \
> > >           i915_gem_gtt.o \
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > index f44bdd08f7cb..f42803ea48f2 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
> > > @@ -4,16 +4,70 @@
> > >   */
> > > 
> > >  #include "intel_memory_region.h"
> > > +#include "intel_region_ttm.h"
> > >  #include "gem/i915_gem_region.h"
> > >  #include "gem/i915_gem_lmem.h"
> > >  #include "i915_drv.h"
> > > 
> > > +static void lmem_put_pages(struct drm_i915_gem_object *obj,
> > > +                                 struct sg_table *pages)
> > > +{
> > > +       intel_region_ttm_node_free(obj->mm.region, obj-
> > > > mm.st_mm_node);
> > > +       obj->mm.dirty = false;
> > > +       sg_free_table(pages);
> > > +       kfree(pages);
> > > +}
> > > +
> > > +static int lmem_get_pages(struct drm_i915_gem_object *obj)
> > > +{
> > > +       unsigned int flags;
> > > +       struct sg_table *pages;
> > > +
> > > +       flags = I915_ALLOC_MIN_PAGE_SIZE;
> > > +       if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
> > > +               flags |= I915_ALLOC_CONTIGUOUS;
> > > +
> > > +       obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj-
> > > > mm.region,
> > > +                                                        obj-
> > > > base.size,
> > > +                                                        flags);
> > > +       if (IS_ERR(obj->mm.st_mm_node))
> > > +               return PTR_ERR(obj->mm.st_mm_node);
> > > +
> > > +       /* Range manager is always contigous */
> > > +       if (obj->mm.region->is_range_manager)
> > > +               obj->flags |= I915_BO_ALLOC_CONTIGUOUS;
> > > +       pages = intel_region_ttm_node_to_st(obj->mm.region, obj-
> > > > mm.st_mm_node);
> > > +       if (IS_ERR(pages))
> > > +               return PTR_ERR(pages);
> > 
> > error unwind?
> > 
> > > +
> > > +       __i915_gem_object_set_pages(obj, pages,
> > > +                                   i915_sg_dma_page_sizes(pages-
> > > > sgl));
> > > +
> > > +       if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
> > > +               void __iomem *vaddr =
> > > +                       i915_gem_object_lmem_io_map(obj, 0, obj-
> > > > base.size);
> > > +
> > > +               if (!vaddr) {
> > > +                       struct sg_table *pages =
> > > +                              
> > > __i915_gem_object_unset_pages(obj);
> > > +
> > > +                       if (!IS_ERR_OR_NULL(pages))
> > > +                               lmem_put_pages(obj, pages);
> > > +               }
> > > +
> > > +               memset_io(vaddr, 0, obj->base.size);
> > > +               io_mapping_unmap(vaddr);
> > > +       }
> > > +
> > > +       return 0;
> > > +}
> > 
> > <snip>
> > 
> > > +/**
> > > + * i915_sg_dma_page_sizes - Calculate page sizes from a
> > > scatterlist
> > > + * @sg: The scatterlist from which to calculate page sizes
> > > + *
> > > + * Return: a value with bits sets for relevant page sizes.
> > > + */
> > > +static inline unsigned int i915_sg_dma_page_sizes(struct
> > > scatterlist *sg)
> > > +{
> > > +       unsigned int page_sizes;
> > > +
> > > +       page_sizes = 0;
> > > +       while (sg) {
> > > +               GEM_BUG_ON(sg->offset);
> > > +               GEM_BUG_ON(!IS_ALIGNED(sg->dma_length,
> > > PAGE_SIZE));
> > > +               page_sizes |= sg->dma_length;
> > > +               sg = __sg_next(sg);
> > > +       }
> > > +
> > > +       /*
> > > +        * Is this necessary to support building large GPU pages
> > > from
> > > +        * even larger segments?
> > > +        */
> > 
> > We just need to know the above sg page_sizes, which is the mask of
> > sg->dma_length for each sg. Later in __i915_gem_object_set_pages()
> > we
> > use this to determine the potential GPU page sizes for the object,
> > depending on what the device supports. So the below stuff shouldn't
> > be
> > needed. Also we can just use i915_sg_page_sizes() here.
> 
> I noticed that i915_sg_page_sizes() uses sg->length() instead of sg-
> > dma_length(). That doesn't look like what we're after here. Do you
> know if there is a reason for that?

Actually, looking at the users, that seems like a bug. I'll make a
separate patch out of it.

/Thomas

> 
> Thanks,
> Thomas
> 


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 5/7] drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
  2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
@ 2021-05-17 10:57     ` Jani Nikula
  -1 siblings, 0 replies; 55+ messages in thread
From: Jani Nikula @ 2021-05-17 10:57 UTC (permalink / raw)
  To: Thomas Hellström, intel-gfx, dri-devel
  Cc: Thomas Hellström, Christian König

On Tue, 11 May 2021, Thomas Hellström <thomas.hellstrom@linux.intel.com> wrote:
> The internal ttm_bo_util memcpy uses vmap functionality, and while it
> probably might be possible to use it for copying in- and out of
> sglist represented io memory, using io_mem_reserve() / io_mem_free()
> callbacks, that would cause problems with fault().
> Instead, implement a method mapping page-by-page using kmap_local()
> semantics. As an additional benefit we then avoid the occasional global
> TLB flushes of vmap() and consuming vmap space, elimination of a critical
> point of failure and with a slight change of semantics we could also push
> the memcpy out async for testing and async driver develpment purposes.
> Pushing out async can be done since there is no memory allocation going on
> that could violate the dma_fence lockdep rules.
>
> Note that drivers that don't want to use struct io_mapping but relies on
> memremap functionality, and that don't want to use scatterlists for
> VRAM may well define specialized (hopefully reusable) iterators for their
> particular environment.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++++++++++++++++
>  .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++++++++++++++
>  drivers/gpu/drm/ttm/ttm_bo.c                  |   1 +
>  4 files changed, 298 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index cb8823570996..958ccc1edfed 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -155,6 +155,7 @@ gem-y += \
>  	gem/i915_gem_stolen.o \
>  	gem/i915_gem_throttle.o \
>  	gem/i915_gem_tiling.o \
> +	gem/i915_gem_ttm_bo_util.o \
>  	gem/i915_gem_userptr.o \
>  	gem/i915_gem_wait.o \
>  	gem/i915_gemfs.o
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
> new file mode 100644
> index 000000000000..1116d7df1461
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
> @@ -0,0 +1,155 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +/**
> + * DOC: Usage and intentions.
> + *
> + * This file contains functionality that we might want to move into
> + * ttm_bo_util.c if there is a common interest.
> + * Currently a kmap_local only memcpy with support for page-based iomem regions,
> + * and fast memcpy from write-combined memory.
> + */
> +
> +#include <linux/dma-buf-map.h>
> +#include <linux/highmem.h>
> +#include <linux/io-mapping.h>
> +#include <linux/scatterlist.h>
> +
> +#include "i915_memcpy.h"
> +
> +#include "gem/i915_gem_ttm_bo_util.h"
> +
> +static void i915_ttm_kmap_iter_tt_kmap_local(struct i915_ttm_kmap_iter *iter,
> +					     struct dma_buf_map *dmap,
> +					     pgoff_t i)
> +{
> +	struct i915_ttm_kmap_iter_tt *iter_tt =
> +		container_of(iter, typeof(*iter_tt), base);
> +
> +	dma_buf_map_set_vaddr(dmap, kmap_local_page(iter_tt->tt->pages[i]));
> +}
> +
> +static void i915_ttm_kmap_iter_iomap_kmap_local(struct i915_ttm_kmap_iter *iter,
> +						struct dma_buf_map *dmap,
> +						pgoff_t i)
> +{
> +	struct i915_ttm_kmap_iter_iomap *iter_io =
> +		container_of(iter, typeof(*iter_io), base);
> +	void __iomem *addr;
> +
> +retry:
> +	while (i >= iter_io->cache.end) {
> +		iter_io->cache.sg = iter_io->cache.sg ?
> +			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
> +		iter_io->cache.i = iter_io->cache.end;
> +		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
> +			PAGE_SHIFT;
> +		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
> +			iter_io->start;
> +	}
> +
> +	if (i < iter_io->cache.i) {
> +		iter_io->cache.end = 0;
> +		iter_io->cache.sg = NULL;
> +		goto retry;
> +	}
> +
> +	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
> +				       (((resource_size_t)i - iter_io->cache.i)
> +					<< PAGE_SHIFT));
> +	dma_buf_map_set_vaddr_iomem(dmap, addr);
> +}
> +
> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops = {
> +	.kmap_local = i915_ttm_kmap_iter_tt_kmap_local
> +};
> +
> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops = {
> +	.kmap_local =  i915_ttm_kmap_iter_iomap_kmap_local
> +};
> +
> +static void kunmap_local_dma_buf_map(struct dma_buf_map *map)
> +{
> +	if (map->is_iomem)
> +		io_mapping_unmap_local(map->vaddr_iomem);
> +	else
> +		kunmap_local(map->vaddr);
> +}
> +
> +/**
> + * i915_ttm_move_memcpy - Helper to perform a memcpy ttm move operation.
> + * @bo: The struct ttm_buffer_object.
> + * @new_mem: The struct ttm_resource we're moving to (copy destination).
> + * @new_kmap: A struct i915_ttm_kmap_iter representing the destination resource.
> + * @old_kmap: A struct i915_ttm_kmap_iter representing the source resource.
> + */
> +void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
> +			  struct ttm_resource *new_mem,
> +			  struct i915_ttm_kmap_iter *new_kmap,
> +			  struct i915_ttm_kmap_iter *old_kmap)
> +{
> +	struct ttm_device *bdev = bo->bdev;
> +	struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
> +	struct ttm_tt *ttm = bo->ttm;
> +	struct ttm_resource *old_mem = &bo->mem;
> +	struct ttm_resource old_copy = *old_mem;
> +	struct ttm_resource_manager *old_man = ttm_manager_type(bdev, old_mem->mem_type);
> +	struct dma_buf_map old_map, new_map;
> +	pgoff_t i;
> +
> +	/* For the page-based allocator we need sgtable iterators as well.*/
> +
> +	/* Single TTM move. NOP */
> +	if (old_man->use_tt && man->use_tt)
> +		goto done;
> +
> +	/* Don't move nonexistent data. Clear destination instead. */
> +	if (old_man->use_tt && !man->use_tt &&
> +	    (ttm == NULL || !ttm_tt_is_populated(ttm))) {
> +		if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC))
> +			goto done;
> +
> +		for (i = 0; i < new_mem->num_pages; ++i) {
> +			new_kmap->ops->kmap_local(new_kmap, &new_map, i);
> +			memset_io(new_map.vaddr_iomem, 0, PAGE_SIZE);
> +			kunmap_local_dma_buf_map(&new_map);
> +		}
> +		goto done;
> +	}
> +
> +	for (i = 0; i < new_mem->num_pages; ++i) {
> +		new_kmap->ops->kmap_local(new_kmap, &new_map, i);
> +		old_kmap->ops->kmap_local(old_kmap, &old_map, i);
> +		if (!old_map.is_iomem ||
> +		    !i915_memcpy_from_wc(new_map.vaddr, old_map.vaddr, PAGE_SIZE)) {
> +			if (!old_map.is_iomem) {
> +				dma_buf_map_memcpy_to(&new_map, old_map.vaddr,
> +						      PAGE_SIZE);
> +			} else if (!new_map.is_iomem) {
> +				memcpy_fromio(new_map.vaddr, old_map.vaddr_iomem,
> +					      PAGE_SIZE);
> +			} else {
> +				pgoff_t j;
> +				u32 __iomem *src = old_map.vaddr_iomem;
> +				u32 __iomem *dst = new_map.vaddr_iomem;
> +
> +				for (j = 0; j < (PAGE_SIZE >> 2); ++j)
> +					iowrite32(ioread32(src++), dst++);
> +			}
> +		}
> +		kunmap_local_dma_buf_map(&old_map);
> +		kunmap_local_dma_buf_map(&new_map);
> +	}
> +
> +done:
> +	old_copy = *old_mem;
> +
> +	ttm_bo_assign_mem(bo, new_mem);
> +
> +	if (!man->use_tt)
> +		ttm_bo_tt_destroy(bo);
> +
> +	ttm_resource_free(bo, &old_copy);
> +}
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
> new file mode 100644
> index 000000000000..82c92176718d
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
> @@ -0,0 +1,141 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +/*
> + * This files contains functionality that we might want to move into
> + * ttm_bo_util.c if there is a common interest.
> + */
> +#ifndef _I915_GEM_TTM_BO_UTIL_H_
> +#define _I915_GEM_TTM_BO_UTIL_H_
> +
> +#include <drm/ttm/ttm_bo_driver.h>
> +struct dma_buf_map;
> +struct io_mapping;
> +struct sg_table;
> +struct scatterlist;
> +
> +struct ttm_tt;
> +struct i915_ttm_kmap_iter;
> +
> +/**
> + * struct i915_ttm_kmap_iter_ops - Ops structure for a struct
> + * i915_ttm_kmap_iter.
> + */
> +struct i915_ttm_kmap_iter_ops {
> +	/**
> +	 * kmap_local - Map a PAGE_SIZE part of the resource using
> +	 * kmap_local semantics.
> +	 * @res_kmap: Pointer to the struct i915_ttm_kmap_iter representing
> +	 * the resource.
> +	 * @dmap: The struct dma_buf_map holding the virtual address after
> +	 * the operation.
> +	 * @i: The location within the resource to map. PAGE_SIZE granularity.
> +	 */
> +	void (*kmap_local)(struct i915_ttm_kmap_iter *res_kmap,
> +			   struct dma_buf_map *dmap, pgoff_t i);
> +};
> +
> +/**
> + * struct i915_ttm_kmap_iter - Iterator for kmap_local type operations on a
> + * resource.
> + * @ops: Pointer to the operations struct.
> + *
> + * This struct is intended to be embedded in a resource-specific specialization
> + * implementing operations for the resource.
> + *
> + * Nothing stops us from extending the operations to vmap, vmap_pfn etc,
> + * replacing some or parts of the ttm_bo_util. cpu-map functionality.
> + */
> +struct i915_ttm_kmap_iter {
> +	const struct i915_ttm_kmap_iter_ops *ops;
> +};
> +
> +/**
> + * struct i915_ttm_kmap_iter_tt - Specialization for a tt (page) backed struct
> + * ttm_resource.
> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface
> + * @tt: Cached struct ttm_tt.
> + */
> +struct i915_ttm_kmap_iter_tt {
> +	struct i915_ttm_kmap_iter base;
> +	struct ttm_tt *tt;
> +};
> +
> +/**
> + * struct i915_ttm_kmap_iter_iomap - Specialization for a struct io_mapping +
> + * struct sg_table backed struct ttm_resource.
> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface.
> + * @iomap: struct io_mapping representing the underlying linear io_memory.
> + * @st: sg_table into @iomap, representing the memory of the struct ttm_resource.
> + * @start: Offset that needs to be subtracted from @st to make
> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
> + * @cache: Scatterlist traversal cache for fast lookups.
> + * @cache.sg: Pointer to the currently cached scatterlist segment.
> + * @cache.i: First index of @sg. PAGE_SIZE granularity.
> + * @cache.end: Last index + 1 of @sg. PAGE_SIZE granularity.
> + * @cache.offs: First offset into @iomap of @sg. PAGE_SIZE granularity.
> + */
> +struct i915_ttm_kmap_iter_iomap {
> +	struct i915_ttm_kmap_iter base;
> +	struct io_mapping *iomap;
> +	struct sg_table *st;
> +	resource_size_t start;
> +	struct {
> +		struct scatterlist *sg;
> +		pgoff_t i;
> +		pgoff_t end;
> +		pgoff_t offs;
> +	} cache;
> +};
> +
> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops;
> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops;
> +
> +/**
> + * i915_ttm_kmap_iter_iomap_init - Initialize a struct i915_ttm_kmap_iter_iomap
> + * @iter_io: The struct i915_ttm_kmap_iter_iomap to initialize.
> + * @iomap: The struct io_mapping representing the underlying linear io_memory.
> + * @st: sg_table into @iomap, representing the memory of the struct
> + * ttm_resource.
> + * @start: Offset that needs to be subtracted from @st to make
> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
> + *
> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
> + */
> +static inline struct i915_ttm_kmap_iter *
> +i915_ttm_kmap_iter_iomap_init(struct i915_ttm_kmap_iter_iomap *iter_io,
> +			      struct io_mapping *iomap,
> +			      struct sg_table *st,
> +			      resource_size_t start)
> +{
> +	iter_io->base.ops = &i915_ttm_kmap_iter_io_ops;
> +	iter_io->iomap = iomap;
> +	iter_io->st = st;
> +	iter_io->start = start;
> +	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
> +	return &iter_io->base;
> +}
> +
> +/**
> + * ttm_kmap_iter_tt_init - Initialize a struct i915_ttm_kmap_iter_tt
> + * @iter_tt: The struct i915_ttm_kmap_iter_tt to initialize.
> + * @tt: Struct ttm_tt holding page pointers of the struct ttm_resource.
> + *
> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
> + */
> +static inline struct i915_ttm_kmap_iter *
> +i915_ttm_kmap_iter_tt_init(struct i915_ttm_kmap_iter_tt *iter_tt,
> +			   struct ttm_tt *tt)
> +{
> +	iter_tt->base.ops = &i915_ttm_kmap_iter_tt_ops;
> +	iter_tt->tt = tt;
> +	return &iter_tt->base;
> +}

Do there functions have a valid *performance* reason to be inline? I
think that's pretty much the only valid reason.

Having these inline forces i915_ttm_kmap_iter_*_ops extern, and they
should really be static. Inline functions complicate header dependencies
and leak the abstractions.

BR,
Jani.


> +
> +void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
> +			  struct ttm_resource *new_mem,
> +			  struct i915_ttm_kmap_iter *new_iter,
> +			  struct i915_ttm_kmap_iter *old_iter);
> +#endif
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index ca1b098b6a56..4479c55aaa1d 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -1221,3 +1221,4 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo)
>  	ttm_tt_destroy(bo->bdev, bo->ttm);
>  	bo->ttm = NULL;
>  }
> +EXPORT_SYMBOL(ttm_bo_tt_destroy);

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 5/7] drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
@ 2021-05-17 10:57     ` Jani Nikula
  0 siblings, 0 replies; 55+ messages in thread
From: Jani Nikula @ 2021-05-17 10:57 UTC (permalink / raw)
  To: Thomas Hellström, intel-gfx, dri-devel
  Cc: Thomas Hellström, Christian König

On Tue, 11 May 2021, Thomas Hellström <thomas.hellstrom@linux.intel.com> wrote:
> The internal ttm_bo_util memcpy uses vmap functionality, and while it
> probably might be possible to use it for copying in- and out of
> sglist represented io memory, using io_mem_reserve() / io_mem_free()
> callbacks, that would cause problems with fault().
> Instead, implement a method mapping page-by-page using kmap_local()
> semantics. As an additional benefit we then avoid the occasional global
> TLB flushes of vmap() and consuming vmap space, elimination of a critical
> point of failure and with a slight change of semantics we could also push
> the memcpy out async for testing and async driver develpment purposes.
> Pushing out async can be done since there is no memory allocation going on
> that could violate the dma_fence lockdep rules.
>
> Note that drivers that don't want to use struct io_mapping but relies on
> memremap functionality, and that don't want to use scatterlists for
> VRAM may well define specialized (hopefully reusable) iterators for their
> particular environment.
>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++++++++++++++++
>  .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++++++++++++++
>  drivers/gpu/drm/ttm/ttm_bo.c                  |   1 +
>  4 files changed, 298 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>  create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index cb8823570996..958ccc1edfed 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -155,6 +155,7 @@ gem-y += \
>  	gem/i915_gem_stolen.o \
>  	gem/i915_gem_throttle.o \
>  	gem/i915_gem_tiling.o \
> +	gem/i915_gem_ttm_bo_util.o \
>  	gem/i915_gem_userptr.o \
>  	gem/i915_gem_wait.o \
>  	gem/i915_gemfs.o
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
> new file mode 100644
> index 000000000000..1116d7df1461
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
> @@ -0,0 +1,155 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +/**
> + * DOC: Usage and intentions.
> + *
> + * This file contains functionality that we might want to move into
> + * ttm_bo_util.c if there is a common interest.
> + * Currently a kmap_local only memcpy with support for page-based iomem regions,
> + * and fast memcpy from write-combined memory.
> + */
> +
> +#include <linux/dma-buf-map.h>
> +#include <linux/highmem.h>
> +#include <linux/io-mapping.h>
> +#include <linux/scatterlist.h>
> +
> +#include "i915_memcpy.h"
> +
> +#include "gem/i915_gem_ttm_bo_util.h"
> +
> +static void i915_ttm_kmap_iter_tt_kmap_local(struct i915_ttm_kmap_iter *iter,
> +					     struct dma_buf_map *dmap,
> +					     pgoff_t i)
> +{
> +	struct i915_ttm_kmap_iter_tt *iter_tt =
> +		container_of(iter, typeof(*iter_tt), base);
> +
> +	dma_buf_map_set_vaddr(dmap, kmap_local_page(iter_tt->tt->pages[i]));
> +}
> +
> +static void i915_ttm_kmap_iter_iomap_kmap_local(struct i915_ttm_kmap_iter *iter,
> +						struct dma_buf_map *dmap,
> +						pgoff_t i)
> +{
> +	struct i915_ttm_kmap_iter_iomap *iter_io =
> +		container_of(iter, typeof(*iter_io), base);
> +	void __iomem *addr;
> +
> +retry:
> +	while (i >= iter_io->cache.end) {
> +		iter_io->cache.sg = iter_io->cache.sg ?
> +			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
> +		iter_io->cache.i = iter_io->cache.end;
> +		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
> +			PAGE_SHIFT;
> +		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
> +			iter_io->start;
> +	}
> +
> +	if (i < iter_io->cache.i) {
> +		iter_io->cache.end = 0;
> +		iter_io->cache.sg = NULL;
> +		goto retry;
> +	}
> +
> +	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
> +				       (((resource_size_t)i - iter_io->cache.i)
> +					<< PAGE_SHIFT));
> +	dma_buf_map_set_vaddr_iomem(dmap, addr);
> +}
> +
> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops = {
> +	.kmap_local = i915_ttm_kmap_iter_tt_kmap_local
> +};
> +
> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops = {
> +	.kmap_local =  i915_ttm_kmap_iter_iomap_kmap_local
> +};
> +
> +static void kunmap_local_dma_buf_map(struct dma_buf_map *map)
> +{
> +	if (map->is_iomem)
> +		io_mapping_unmap_local(map->vaddr_iomem);
> +	else
> +		kunmap_local(map->vaddr);
> +}
> +
> +/**
> + * i915_ttm_move_memcpy - Helper to perform a memcpy ttm move operation.
> + * @bo: The struct ttm_buffer_object.
> + * @new_mem: The struct ttm_resource we're moving to (copy destination).
> + * @new_kmap: A struct i915_ttm_kmap_iter representing the destination resource.
> + * @old_kmap: A struct i915_ttm_kmap_iter representing the source resource.
> + */
> +void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
> +			  struct ttm_resource *new_mem,
> +			  struct i915_ttm_kmap_iter *new_kmap,
> +			  struct i915_ttm_kmap_iter *old_kmap)
> +{
> +	struct ttm_device *bdev = bo->bdev;
> +	struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
> +	struct ttm_tt *ttm = bo->ttm;
> +	struct ttm_resource *old_mem = &bo->mem;
> +	struct ttm_resource old_copy = *old_mem;
> +	struct ttm_resource_manager *old_man = ttm_manager_type(bdev, old_mem->mem_type);
> +	struct dma_buf_map old_map, new_map;
> +	pgoff_t i;
> +
> +	/* For the page-based allocator we need sgtable iterators as well.*/
> +
> +	/* Single TTM move. NOP */
> +	if (old_man->use_tt && man->use_tt)
> +		goto done;
> +
> +	/* Don't move nonexistent data. Clear destination instead. */
> +	if (old_man->use_tt && !man->use_tt &&
> +	    (ttm == NULL || !ttm_tt_is_populated(ttm))) {
> +		if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC))
> +			goto done;
> +
> +		for (i = 0; i < new_mem->num_pages; ++i) {
> +			new_kmap->ops->kmap_local(new_kmap, &new_map, i);
> +			memset_io(new_map.vaddr_iomem, 0, PAGE_SIZE);
> +			kunmap_local_dma_buf_map(&new_map);
> +		}
> +		goto done;
> +	}
> +
> +	for (i = 0; i < new_mem->num_pages; ++i) {
> +		new_kmap->ops->kmap_local(new_kmap, &new_map, i);
> +		old_kmap->ops->kmap_local(old_kmap, &old_map, i);
> +		if (!old_map.is_iomem ||
> +		    !i915_memcpy_from_wc(new_map.vaddr, old_map.vaddr, PAGE_SIZE)) {
> +			if (!old_map.is_iomem) {
> +				dma_buf_map_memcpy_to(&new_map, old_map.vaddr,
> +						      PAGE_SIZE);
> +			} else if (!new_map.is_iomem) {
> +				memcpy_fromio(new_map.vaddr, old_map.vaddr_iomem,
> +					      PAGE_SIZE);
> +			} else {
> +				pgoff_t j;
> +				u32 __iomem *src = old_map.vaddr_iomem;
> +				u32 __iomem *dst = new_map.vaddr_iomem;
> +
> +				for (j = 0; j < (PAGE_SIZE >> 2); ++j)
> +					iowrite32(ioread32(src++), dst++);
> +			}
> +		}
> +		kunmap_local_dma_buf_map(&old_map);
> +		kunmap_local_dma_buf_map(&new_map);
> +	}
> +
> +done:
> +	old_copy = *old_mem;
> +
> +	ttm_bo_assign_mem(bo, new_mem);
> +
> +	if (!man->use_tt)
> +		ttm_bo_tt_destroy(bo);
> +
> +	ttm_resource_free(bo, &old_copy);
> +}
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
> new file mode 100644
> index 000000000000..82c92176718d
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
> @@ -0,0 +1,141 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +/*
> + * This files contains functionality that we might want to move into
> + * ttm_bo_util.c if there is a common interest.
> + */
> +#ifndef _I915_GEM_TTM_BO_UTIL_H_
> +#define _I915_GEM_TTM_BO_UTIL_H_
> +
> +#include <drm/ttm/ttm_bo_driver.h>
> +struct dma_buf_map;
> +struct io_mapping;
> +struct sg_table;
> +struct scatterlist;
> +
> +struct ttm_tt;
> +struct i915_ttm_kmap_iter;
> +
> +/**
> + * struct i915_ttm_kmap_iter_ops - Ops structure for a struct
> + * i915_ttm_kmap_iter.
> + */
> +struct i915_ttm_kmap_iter_ops {
> +	/**
> +	 * kmap_local - Map a PAGE_SIZE part of the resource using
> +	 * kmap_local semantics.
> +	 * @res_kmap: Pointer to the struct i915_ttm_kmap_iter representing
> +	 * the resource.
> +	 * @dmap: The struct dma_buf_map holding the virtual address after
> +	 * the operation.
> +	 * @i: The location within the resource to map. PAGE_SIZE granularity.
> +	 */
> +	void (*kmap_local)(struct i915_ttm_kmap_iter *res_kmap,
> +			   struct dma_buf_map *dmap, pgoff_t i);
> +};
> +
> +/**
> + * struct i915_ttm_kmap_iter - Iterator for kmap_local type operations on a
> + * resource.
> + * @ops: Pointer to the operations struct.
> + *
> + * This struct is intended to be embedded in a resource-specific specialization
> + * implementing operations for the resource.
> + *
> + * Nothing stops us from extending the operations to vmap, vmap_pfn etc,
> + * replacing some or parts of the ttm_bo_util. cpu-map functionality.
> + */
> +struct i915_ttm_kmap_iter {
> +	const struct i915_ttm_kmap_iter_ops *ops;
> +};
> +
> +/**
> + * struct i915_ttm_kmap_iter_tt - Specialization for a tt (page) backed struct
> + * ttm_resource.
> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface
> + * @tt: Cached struct ttm_tt.
> + */
> +struct i915_ttm_kmap_iter_tt {
> +	struct i915_ttm_kmap_iter base;
> +	struct ttm_tt *tt;
> +};
> +
> +/**
> + * struct i915_ttm_kmap_iter_iomap - Specialization for a struct io_mapping +
> + * struct sg_table backed struct ttm_resource.
> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface.
> + * @iomap: struct io_mapping representing the underlying linear io_memory.
> + * @st: sg_table into @iomap, representing the memory of the struct ttm_resource.
> + * @start: Offset that needs to be subtracted from @st to make
> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
> + * @cache: Scatterlist traversal cache for fast lookups.
> + * @cache.sg: Pointer to the currently cached scatterlist segment.
> + * @cache.i: First index of @sg. PAGE_SIZE granularity.
> + * @cache.end: Last index + 1 of @sg. PAGE_SIZE granularity.
> + * @cache.offs: First offset into @iomap of @sg. PAGE_SIZE granularity.
> + */
> +struct i915_ttm_kmap_iter_iomap {
> +	struct i915_ttm_kmap_iter base;
> +	struct io_mapping *iomap;
> +	struct sg_table *st;
> +	resource_size_t start;
> +	struct {
> +		struct scatterlist *sg;
> +		pgoff_t i;
> +		pgoff_t end;
> +		pgoff_t offs;
> +	} cache;
> +};
> +
> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops;
> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops;
> +
> +/**
> + * i915_ttm_kmap_iter_iomap_init - Initialize a struct i915_ttm_kmap_iter_iomap
> + * @iter_io: The struct i915_ttm_kmap_iter_iomap to initialize.
> + * @iomap: The struct io_mapping representing the underlying linear io_memory.
> + * @st: sg_table into @iomap, representing the memory of the struct
> + * ttm_resource.
> + * @start: Offset that needs to be subtracted from @st to make
> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
> + *
> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
> + */
> +static inline struct i915_ttm_kmap_iter *
> +i915_ttm_kmap_iter_iomap_init(struct i915_ttm_kmap_iter_iomap *iter_io,
> +			      struct io_mapping *iomap,
> +			      struct sg_table *st,
> +			      resource_size_t start)
> +{
> +	iter_io->base.ops = &i915_ttm_kmap_iter_io_ops;
> +	iter_io->iomap = iomap;
> +	iter_io->st = st;
> +	iter_io->start = start;
> +	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
> +	return &iter_io->base;
> +}
> +
> +/**
> + * ttm_kmap_iter_tt_init - Initialize a struct i915_ttm_kmap_iter_tt
> + * @iter_tt: The struct i915_ttm_kmap_iter_tt to initialize.
> + * @tt: Struct ttm_tt holding page pointers of the struct ttm_resource.
> + *
> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
> + */
> +static inline struct i915_ttm_kmap_iter *
> +i915_ttm_kmap_iter_tt_init(struct i915_ttm_kmap_iter_tt *iter_tt,
> +			   struct ttm_tt *tt)
> +{
> +	iter_tt->base.ops = &i915_ttm_kmap_iter_tt_ops;
> +	iter_tt->tt = tt;
> +	return &iter_tt->base;
> +}

Do there functions have a valid *performance* reason to be inline? I
think that's pretty much the only valid reason.

Having these inline forces i915_ttm_kmap_iter_*_ops extern, and they
should really be static. Inline functions complicate header dependencies
and leak the abstractions.

BR,
Jani.


> +
> +void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
> +			  struct ttm_resource *new_mem,
> +			  struct i915_ttm_kmap_iter *new_iter,
> +			  struct i915_ttm_kmap_iter *old_iter);
> +#endif
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index ca1b098b6a56..4479c55aaa1d 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -1221,3 +1221,4 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo)
>  	ttm_tt_destroy(bo->bdev, bo->ttm);
>  	bo->ttm = NULL;
>  }
> +EXPORT_SYMBOL(ttm_bo_tt_destroy);

-- 
Jani Nikula, Intel Open Source Graphics Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 5/7] drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
  2021-05-17 10:57     ` Jani Nikula
@ 2021-05-18  6:53       ` Thomas Hellström
  -1 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-18  6:53 UTC (permalink / raw)
  To: Jani Nikula, intel-gfx, dri-devel; +Cc: Christian König


On 5/17/21 12:57 PM, Jani Nikula wrote:
> On Tue, 11 May 2021, Thomas Hellström <thomas.hellstrom@linux.intel.com> wrote:
>> The internal ttm_bo_util memcpy uses vmap functionality, and while it
>> probably might be possible to use it for copying in- and out of
>> sglist represented io memory, using io_mem_reserve() / io_mem_free()
>> callbacks, that would cause problems with fault().
>> Instead, implement a method mapping page-by-page using kmap_local()
>> semantics. As an additional benefit we then avoid the occasional global
>> TLB flushes of vmap() and consuming vmap space, elimination of a critical
>> point of failure and with a slight change of semantics we could also push
>> the memcpy out async for testing and async driver develpment purposes.
>> Pushing out async can be done since there is no memory allocation going on
>> that could violate the dma_fence lockdep rules.
>>
>> Note that drivers that don't want to use struct io_mapping but relies on
>> memremap functionality, and that don't want to use scatterlists for
>> VRAM may well define specialized (hopefully reusable) iterators for their
>> particular environment.
>>
>> Cc: Christian König <christian.koenig@amd.com>
>> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>> ---
>>   drivers/gpu/drm/i915/Makefile                 |   1 +
>>   .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++++++++++++++++
>>   .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++++++++++++++
>>   drivers/gpu/drm/ttm/ttm_bo.c                  |   1 +
>>   4 files changed, 298 insertions(+)
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index cb8823570996..958ccc1edfed 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -155,6 +155,7 @@ gem-y += \
>>   	gem/i915_gem_stolen.o \
>>   	gem/i915_gem_throttle.o \
>>   	gem/i915_gem_tiling.o \
>> +	gem/i915_gem_ttm_bo_util.o \
>>   	gem/i915_gem_userptr.o \
>>   	gem/i915_gem_wait.o \
>>   	gem/i915_gemfs.o
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>> new file mode 100644
>> index 000000000000..1116d7df1461
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>> @@ -0,0 +1,155 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright © 2021 Intel Corporation
>> + */
>> +
>> +/**
>> + * DOC: Usage and intentions.
>> + *
>> + * This file contains functionality that we might want to move into
>> + * ttm_bo_util.c if there is a common interest.
>> + * Currently a kmap_local only memcpy with support for page-based iomem regions,
>> + * and fast memcpy from write-combined memory.
>> + */
>> +
>> +#include <linux/dma-buf-map.h>
>> +#include <linux/highmem.h>
>> +#include <linux/io-mapping.h>
>> +#include <linux/scatterlist.h>
>> +
>> +#include "i915_memcpy.h"
>> +
>> +#include "gem/i915_gem_ttm_bo_util.h"
>> +
>> +static void i915_ttm_kmap_iter_tt_kmap_local(struct i915_ttm_kmap_iter *iter,
>> +					     struct dma_buf_map *dmap,
>> +					     pgoff_t i)
>> +{
>> +	struct i915_ttm_kmap_iter_tt *iter_tt =
>> +		container_of(iter, typeof(*iter_tt), base);
>> +
>> +	dma_buf_map_set_vaddr(dmap, kmap_local_page(iter_tt->tt->pages[i]));
>> +}
>> +
>> +static void i915_ttm_kmap_iter_iomap_kmap_local(struct i915_ttm_kmap_iter *iter,
>> +						struct dma_buf_map *dmap,
>> +						pgoff_t i)
>> +{
>> +	struct i915_ttm_kmap_iter_iomap *iter_io =
>> +		container_of(iter, typeof(*iter_io), base);
>> +	void __iomem *addr;
>> +
>> +retry:
>> +	while (i >= iter_io->cache.end) {
>> +		iter_io->cache.sg = iter_io->cache.sg ?
>> +			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
>> +		iter_io->cache.i = iter_io->cache.end;
>> +		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
>> +			PAGE_SHIFT;
>> +		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
>> +			iter_io->start;
>> +	}
>> +
>> +	if (i < iter_io->cache.i) {
>> +		iter_io->cache.end = 0;
>> +		iter_io->cache.sg = NULL;
>> +		goto retry;
>> +	}
>> +
>> +	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
>> +				       (((resource_size_t)i - iter_io->cache.i)
>> +					<< PAGE_SHIFT));
>> +	dma_buf_map_set_vaddr_iomem(dmap, addr);
>> +}
>> +
>> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops = {
>> +	.kmap_local = i915_ttm_kmap_iter_tt_kmap_local
>> +};
>> +
>> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops = {
>> +	.kmap_local =  i915_ttm_kmap_iter_iomap_kmap_local
>> +};
>> +
>> +static void kunmap_local_dma_buf_map(struct dma_buf_map *map)
>> +{
>> +	if (map->is_iomem)
>> +		io_mapping_unmap_local(map->vaddr_iomem);
>> +	else
>> +		kunmap_local(map->vaddr);
>> +}
>> +
>> +/**
>> + * i915_ttm_move_memcpy - Helper to perform a memcpy ttm move operation.
>> + * @bo: The struct ttm_buffer_object.
>> + * @new_mem: The struct ttm_resource we're moving to (copy destination).
>> + * @new_kmap: A struct i915_ttm_kmap_iter representing the destination resource.
>> + * @old_kmap: A struct i915_ttm_kmap_iter representing the source resource.
>> + */
>> +void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
>> +			  struct ttm_resource *new_mem,
>> +			  struct i915_ttm_kmap_iter *new_kmap,
>> +			  struct i915_ttm_kmap_iter *old_kmap)
>> +{
>> +	struct ttm_device *bdev = bo->bdev;
>> +	struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
>> +	struct ttm_tt *ttm = bo->ttm;
>> +	struct ttm_resource *old_mem = &bo->mem;
>> +	struct ttm_resource old_copy = *old_mem;
>> +	struct ttm_resource_manager *old_man = ttm_manager_type(bdev, old_mem->mem_type);
>> +	struct dma_buf_map old_map, new_map;
>> +	pgoff_t i;
>> +
>> +	/* For the page-based allocator we need sgtable iterators as well.*/
>> +
>> +	/* Single TTM move. NOP */
>> +	if (old_man->use_tt && man->use_tt)
>> +		goto done;
>> +
>> +	/* Don't move nonexistent data. Clear destination instead. */
>> +	if (old_man->use_tt && !man->use_tt &&
>> +	    (ttm == NULL || !ttm_tt_is_populated(ttm))) {
>> +		if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC))
>> +			goto done;
>> +
>> +		for (i = 0; i < new_mem->num_pages; ++i) {
>> +			new_kmap->ops->kmap_local(new_kmap, &new_map, i);
>> +			memset_io(new_map.vaddr_iomem, 0, PAGE_SIZE);
>> +			kunmap_local_dma_buf_map(&new_map);
>> +		}
>> +		goto done;
>> +	}
>> +
>> +	for (i = 0; i < new_mem->num_pages; ++i) {
>> +		new_kmap->ops->kmap_local(new_kmap, &new_map, i);
>> +		old_kmap->ops->kmap_local(old_kmap, &old_map, i);
>> +		if (!old_map.is_iomem ||
>> +		    !i915_memcpy_from_wc(new_map.vaddr, old_map.vaddr, PAGE_SIZE)) {
>> +			if (!old_map.is_iomem) {
>> +				dma_buf_map_memcpy_to(&new_map, old_map.vaddr,
>> +						      PAGE_SIZE);
>> +			} else if (!new_map.is_iomem) {
>> +				memcpy_fromio(new_map.vaddr, old_map.vaddr_iomem,
>> +					      PAGE_SIZE);
>> +			} else {
>> +				pgoff_t j;
>> +				u32 __iomem *src = old_map.vaddr_iomem;
>> +				u32 __iomem *dst = new_map.vaddr_iomem;
>> +
>> +				for (j = 0; j < (PAGE_SIZE >> 2); ++j)
>> +					iowrite32(ioread32(src++), dst++);
>> +			}
>> +		}
>> +		kunmap_local_dma_buf_map(&old_map);
>> +		kunmap_local_dma_buf_map(&new_map);
>> +	}
>> +
>> +done:
>> +	old_copy = *old_mem;
>> +
>> +	ttm_bo_assign_mem(bo, new_mem);
>> +
>> +	if (!man->use_tt)
>> +		ttm_bo_tt_destroy(bo);
>> +
>> +	ttm_resource_free(bo, &old_copy);
>> +}
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>> new file mode 100644
>> index 000000000000..82c92176718d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>> @@ -0,0 +1,141 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright © 2021 Intel Corporation
>> + */
>> +
>> +/*
>> + * This files contains functionality that we might want to move into
>> + * ttm_bo_util.c if there is a common interest.
>> + */
>> +#ifndef _I915_GEM_TTM_BO_UTIL_H_
>> +#define _I915_GEM_TTM_BO_UTIL_H_
>> +
>> +#include <drm/ttm/ttm_bo_driver.h>
>> +struct dma_buf_map;
>> +struct io_mapping;
>> +struct sg_table;
>> +struct scatterlist;
>> +
>> +struct ttm_tt;
>> +struct i915_ttm_kmap_iter;
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter_ops - Ops structure for a struct
>> + * i915_ttm_kmap_iter.
>> + */
>> +struct i915_ttm_kmap_iter_ops {
>> +	/**
>> +	 * kmap_local - Map a PAGE_SIZE part of the resource using
>> +	 * kmap_local semantics.
>> +	 * @res_kmap: Pointer to the struct i915_ttm_kmap_iter representing
>> +	 * the resource.
>> +	 * @dmap: The struct dma_buf_map holding the virtual address after
>> +	 * the operation.
>> +	 * @i: The location within the resource to map. PAGE_SIZE granularity.
>> +	 */
>> +	void (*kmap_local)(struct i915_ttm_kmap_iter *res_kmap,
>> +			   struct dma_buf_map *dmap, pgoff_t i);
>> +};
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter - Iterator for kmap_local type operations on a
>> + * resource.
>> + * @ops: Pointer to the operations struct.
>> + *
>> + * This struct is intended to be embedded in a resource-specific specialization
>> + * implementing operations for the resource.
>> + *
>> + * Nothing stops us from extending the operations to vmap, vmap_pfn etc,
>> + * replacing some or parts of the ttm_bo_util. cpu-map functionality.
>> + */
>> +struct i915_ttm_kmap_iter {
>> +	const struct i915_ttm_kmap_iter_ops *ops;
>> +};
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter_tt - Specialization for a tt (page) backed struct
>> + * ttm_resource.
>> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface
>> + * @tt: Cached struct ttm_tt.
>> + */
>> +struct i915_ttm_kmap_iter_tt {
>> +	struct i915_ttm_kmap_iter base;
>> +	struct ttm_tt *tt;
>> +};
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter_iomap - Specialization for a struct io_mapping +
>> + * struct sg_table backed struct ttm_resource.
>> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface.
>> + * @iomap: struct io_mapping representing the underlying linear io_memory.
>> + * @st: sg_table into @iomap, representing the memory of the struct ttm_resource.
>> + * @start: Offset that needs to be subtracted from @st to make
>> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
>> + * @cache: Scatterlist traversal cache for fast lookups.
>> + * @cache.sg: Pointer to the currently cached scatterlist segment.
>> + * @cache.i: First index of @sg. PAGE_SIZE granularity.
>> + * @cache.end: Last index + 1 of @sg. PAGE_SIZE granularity.
>> + * @cache.offs: First offset into @iomap of @sg. PAGE_SIZE granularity.
>> + */
>> +struct i915_ttm_kmap_iter_iomap {
>> +	struct i915_ttm_kmap_iter base;
>> +	struct io_mapping *iomap;
>> +	struct sg_table *st;
>> +	resource_size_t start;
>> +	struct {
>> +		struct scatterlist *sg;
>> +		pgoff_t i;
>> +		pgoff_t end;
>> +		pgoff_t offs;
>> +	} cache;
>> +};
>> +
>> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops;
>> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops;
>> +
>> +/**
>> + * i915_ttm_kmap_iter_iomap_init - Initialize a struct i915_ttm_kmap_iter_iomap
>> + * @iter_io: The struct i915_ttm_kmap_iter_iomap to initialize.
>> + * @iomap: The struct io_mapping representing the underlying linear io_memory.
>> + * @st: sg_table into @iomap, representing the memory of the struct
>> + * ttm_resource.
>> + * @start: Offset that needs to be subtracted from @st to make
>> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
>> + *
>> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
>> + */
>> +static inline struct i915_ttm_kmap_iter *
>> +i915_ttm_kmap_iter_iomap_init(struct i915_ttm_kmap_iter_iomap *iter_io,
>> +			      struct io_mapping *iomap,
>> +			      struct sg_table *st,
>> +			      resource_size_t start)
>> +{
>> +	iter_io->base.ops = &i915_ttm_kmap_iter_io_ops;
>> +	iter_io->iomap = iomap;
>> +	iter_io->st = st;
>> +	iter_io->start = start;
>> +	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
>> +	return &iter_io->base;
>> +}
>> +
>> +/**
>> + * ttm_kmap_iter_tt_init - Initialize a struct i915_ttm_kmap_iter_tt
>> + * @iter_tt: The struct i915_ttm_kmap_iter_tt to initialize.
>> + * @tt: Struct ttm_tt holding page pointers of the struct ttm_resource.
>> + *
>> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
>> + */
>> +static inline struct i915_ttm_kmap_iter *
>> +i915_ttm_kmap_iter_tt_init(struct i915_ttm_kmap_iter_tt *iter_tt,
>> +			   struct ttm_tt *tt)
>> +{
>> +	iter_tt->base.ops = &i915_ttm_kmap_iter_tt_ops;
>> +	iter_tt->tt = tt;
>> +	return &iter_tt->base;
>> +}
> Do there functions have a valid *performance* reason to be inline? I
> think that's pretty much the only valid reason.
>
> Having these inline forces i915_ttm_kmap_iter_*_ops extern, and they
> should really be static. Inline functions complicate header dependencies
> and leak the abstractions.
>
> BR,
> Jani.

Hi,

Thanks for reviewing. I don't think there really is a performance reason 
for keeping these functions inline. While in this case there is not 
really much change either in leaking abstractions nor in header 
dependencies I agree keeping those ops static is probably a better 
choice. I'll respin.

Thanks,

Thomas



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Intel-gfx] [PATCH 5/7] drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem
@ 2021-05-18  6:53       ` Thomas Hellström
  0 siblings, 0 replies; 55+ messages in thread
From: Thomas Hellström @ 2021-05-18  6:53 UTC (permalink / raw)
  To: Jani Nikula, intel-gfx, dri-devel; +Cc: Christian König


On 5/17/21 12:57 PM, Jani Nikula wrote:
> On Tue, 11 May 2021, Thomas Hellström <thomas.hellstrom@linux.intel.com> wrote:
>> The internal ttm_bo_util memcpy uses vmap functionality, and while it
>> probably might be possible to use it for copying in- and out of
>> sglist represented io memory, using io_mem_reserve() / io_mem_free()
>> callbacks, that would cause problems with fault().
>> Instead, implement a method mapping page-by-page using kmap_local()
>> semantics. As an additional benefit we then avoid the occasional global
>> TLB flushes of vmap() and consuming vmap space, elimination of a critical
>> point of failure and with a slight change of semantics we could also push
>> the memcpy out async for testing and async driver develpment purposes.
>> Pushing out async can be done since there is no memory allocation going on
>> that could violate the dma_fence lockdep rules.
>>
>> Note that drivers that don't want to use struct io_mapping but relies on
>> memremap functionality, and that don't want to use scatterlists for
>> VRAM may well define specialized (hopefully reusable) iterators for their
>> particular environment.
>>
>> Cc: Christian König <christian.koenig@amd.com>
>> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>> ---
>>   drivers/gpu/drm/i915/Makefile                 |   1 +
>>   .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.c   | 155 ++++++++++++++++++
>>   .../gpu/drm/i915/gem/i915_gem_ttm_bo_util.h   | 141 ++++++++++++++++
>>   drivers/gpu/drm/ttm/ttm_bo.c                  |   1 +
>>   4 files changed, 298 insertions(+)
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>>   create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index cb8823570996..958ccc1edfed 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -155,6 +155,7 @@ gem-y += \
>>   	gem/i915_gem_stolen.o \
>>   	gem/i915_gem_throttle.o \
>>   	gem/i915_gem_tiling.o \
>> +	gem/i915_gem_ttm_bo_util.o \
>>   	gem/i915_gem_userptr.o \
>>   	gem/i915_gem_wait.o \
>>   	gem/i915_gemfs.o
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>> new file mode 100644
>> index 000000000000..1116d7df1461
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.c
>> @@ -0,0 +1,155 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright © 2021 Intel Corporation
>> + */
>> +
>> +/**
>> + * DOC: Usage and intentions.
>> + *
>> + * This file contains functionality that we might want to move into
>> + * ttm_bo_util.c if there is a common interest.
>> + * Currently a kmap_local only memcpy with support for page-based iomem regions,
>> + * and fast memcpy from write-combined memory.
>> + */
>> +
>> +#include <linux/dma-buf-map.h>
>> +#include <linux/highmem.h>
>> +#include <linux/io-mapping.h>
>> +#include <linux/scatterlist.h>
>> +
>> +#include "i915_memcpy.h"
>> +
>> +#include "gem/i915_gem_ttm_bo_util.h"
>> +
>> +static void i915_ttm_kmap_iter_tt_kmap_local(struct i915_ttm_kmap_iter *iter,
>> +					     struct dma_buf_map *dmap,
>> +					     pgoff_t i)
>> +{
>> +	struct i915_ttm_kmap_iter_tt *iter_tt =
>> +		container_of(iter, typeof(*iter_tt), base);
>> +
>> +	dma_buf_map_set_vaddr(dmap, kmap_local_page(iter_tt->tt->pages[i]));
>> +}
>> +
>> +static void i915_ttm_kmap_iter_iomap_kmap_local(struct i915_ttm_kmap_iter *iter,
>> +						struct dma_buf_map *dmap,
>> +						pgoff_t i)
>> +{
>> +	struct i915_ttm_kmap_iter_iomap *iter_io =
>> +		container_of(iter, typeof(*iter_io), base);
>> +	void __iomem *addr;
>> +
>> +retry:
>> +	while (i >= iter_io->cache.end) {
>> +		iter_io->cache.sg = iter_io->cache.sg ?
>> +			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
>> +		iter_io->cache.i = iter_io->cache.end;
>> +		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
>> +			PAGE_SHIFT;
>> +		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
>> +			iter_io->start;
>> +	}
>> +
>> +	if (i < iter_io->cache.i) {
>> +		iter_io->cache.end = 0;
>> +		iter_io->cache.sg = NULL;
>> +		goto retry;
>> +	}
>> +
>> +	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
>> +				       (((resource_size_t)i - iter_io->cache.i)
>> +					<< PAGE_SHIFT));
>> +	dma_buf_map_set_vaddr_iomem(dmap, addr);
>> +}
>> +
>> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops = {
>> +	.kmap_local = i915_ttm_kmap_iter_tt_kmap_local
>> +};
>> +
>> +struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops = {
>> +	.kmap_local =  i915_ttm_kmap_iter_iomap_kmap_local
>> +};
>> +
>> +static void kunmap_local_dma_buf_map(struct dma_buf_map *map)
>> +{
>> +	if (map->is_iomem)
>> +		io_mapping_unmap_local(map->vaddr_iomem);
>> +	else
>> +		kunmap_local(map->vaddr);
>> +}
>> +
>> +/**
>> + * i915_ttm_move_memcpy - Helper to perform a memcpy ttm move operation.
>> + * @bo: The struct ttm_buffer_object.
>> + * @new_mem: The struct ttm_resource we're moving to (copy destination).
>> + * @new_kmap: A struct i915_ttm_kmap_iter representing the destination resource.
>> + * @old_kmap: A struct i915_ttm_kmap_iter representing the source resource.
>> + */
>> +void i915_ttm_move_memcpy(struct ttm_buffer_object *bo,
>> +			  struct ttm_resource *new_mem,
>> +			  struct i915_ttm_kmap_iter *new_kmap,
>> +			  struct i915_ttm_kmap_iter *old_kmap)
>> +{
>> +	struct ttm_device *bdev = bo->bdev;
>> +	struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
>> +	struct ttm_tt *ttm = bo->ttm;
>> +	struct ttm_resource *old_mem = &bo->mem;
>> +	struct ttm_resource old_copy = *old_mem;
>> +	struct ttm_resource_manager *old_man = ttm_manager_type(bdev, old_mem->mem_type);
>> +	struct dma_buf_map old_map, new_map;
>> +	pgoff_t i;
>> +
>> +	/* For the page-based allocator we need sgtable iterators as well.*/
>> +
>> +	/* Single TTM move. NOP */
>> +	if (old_man->use_tt && man->use_tt)
>> +		goto done;
>> +
>> +	/* Don't move nonexistent data. Clear destination instead. */
>> +	if (old_man->use_tt && !man->use_tt &&
>> +	    (ttm == NULL || !ttm_tt_is_populated(ttm))) {
>> +		if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC))
>> +			goto done;
>> +
>> +		for (i = 0; i < new_mem->num_pages; ++i) {
>> +			new_kmap->ops->kmap_local(new_kmap, &new_map, i);
>> +			memset_io(new_map.vaddr_iomem, 0, PAGE_SIZE);
>> +			kunmap_local_dma_buf_map(&new_map);
>> +		}
>> +		goto done;
>> +	}
>> +
>> +	for (i = 0; i < new_mem->num_pages; ++i) {
>> +		new_kmap->ops->kmap_local(new_kmap, &new_map, i);
>> +		old_kmap->ops->kmap_local(old_kmap, &old_map, i);
>> +		if (!old_map.is_iomem ||
>> +		    !i915_memcpy_from_wc(new_map.vaddr, old_map.vaddr, PAGE_SIZE)) {
>> +			if (!old_map.is_iomem) {
>> +				dma_buf_map_memcpy_to(&new_map, old_map.vaddr,
>> +						      PAGE_SIZE);
>> +			} else if (!new_map.is_iomem) {
>> +				memcpy_fromio(new_map.vaddr, old_map.vaddr_iomem,
>> +					      PAGE_SIZE);
>> +			} else {
>> +				pgoff_t j;
>> +				u32 __iomem *src = old_map.vaddr_iomem;
>> +				u32 __iomem *dst = new_map.vaddr_iomem;
>> +
>> +				for (j = 0; j < (PAGE_SIZE >> 2); ++j)
>> +					iowrite32(ioread32(src++), dst++);
>> +			}
>> +		}
>> +		kunmap_local_dma_buf_map(&old_map);
>> +		kunmap_local_dma_buf_map(&new_map);
>> +	}
>> +
>> +done:
>> +	old_copy = *old_mem;
>> +
>> +	ttm_bo_assign_mem(bo, new_mem);
>> +
>> +	if (!man->use_tt)
>> +		ttm_bo_tt_destroy(bo);
>> +
>> +	ttm_resource_free(bo, &old_copy);
>> +}
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>> new file mode 100644
>> index 000000000000..82c92176718d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_bo_util.h
>> @@ -0,0 +1,141 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright © 2021 Intel Corporation
>> + */
>> +
>> +/*
>> + * This files contains functionality that we might want to move into
>> + * ttm_bo_util.c if there is a common interest.
>> + */
>> +#ifndef _I915_GEM_TTM_BO_UTIL_H_
>> +#define _I915_GEM_TTM_BO_UTIL_H_
>> +
>> +#include <drm/ttm/ttm_bo_driver.h>
>> +struct dma_buf_map;
>> +struct io_mapping;
>> +struct sg_table;
>> +struct scatterlist;
>> +
>> +struct ttm_tt;
>> +struct i915_ttm_kmap_iter;
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter_ops - Ops structure for a struct
>> + * i915_ttm_kmap_iter.
>> + */
>> +struct i915_ttm_kmap_iter_ops {
>> +	/**
>> +	 * kmap_local - Map a PAGE_SIZE part of the resource using
>> +	 * kmap_local semantics.
>> +	 * @res_kmap: Pointer to the struct i915_ttm_kmap_iter representing
>> +	 * the resource.
>> +	 * @dmap: The struct dma_buf_map holding the virtual address after
>> +	 * the operation.
>> +	 * @i: The location within the resource to map. PAGE_SIZE granularity.
>> +	 */
>> +	void (*kmap_local)(struct i915_ttm_kmap_iter *res_kmap,
>> +			   struct dma_buf_map *dmap, pgoff_t i);
>> +};
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter - Iterator for kmap_local type operations on a
>> + * resource.
>> + * @ops: Pointer to the operations struct.
>> + *
>> + * This struct is intended to be embedded in a resource-specific specialization
>> + * implementing operations for the resource.
>> + *
>> + * Nothing stops us from extending the operations to vmap, vmap_pfn etc,
>> + * replacing some or parts of the ttm_bo_util. cpu-map functionality.
>> + */
>> +struct i915_ttm_kmap_iter {
>> +	const struct i915_ttm_kmap_iter_ops *ops;
>> +};
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter_tt - Specialization for a tt (page) backed struct
>> + * ttm_resource.
>> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface
>> + * @tt: Cached struct ttm_tt.
>> + */
>> +struct i915_ttm_kmap_iter_tt {
>> +	struct i915_ttm_kmap_iter base;
>> +	struct ttm_tt *tt;
>> +};
>> +
>> +/**
>> + * struct i915_ttm_kmap_iter_iomap - Specialization for a struct io_mapping +
>> + * struct sg_table backed struct ttm_resource.
>> + * @base: Embedded struct i915_ttm_kmap_iter providing the usage interface.
>> + * @iomap: struct io_mapping representing the underlying linear io_memory.
>> + * @st: sg_table into @iomap, representing the memory of the struct ttm_resource.
>> + * @start: Offset that needs to be subtracted from @st to make
>> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
>> + * @cache: Scatterlist traversal cache for fast lookups.
>> + * @cache.sg: Pointer to the currently cached scatterlist segment.
>> + * @cache.i: First index of @sg. PAGE_SIZE granularity.
>> + * @cache.end: Last index + 1 of @sg. PAGE_SIZE granularity.
>> + * @cache.offs: First offset into @iomap of @sg. PAGE_SIZE granularity.
>> + */
>> +struct i915_ttm_kmap_iter_iomap {
>> +	struct i915_ttm_kmap_iter base;
>> +	struct io_mapping *iomap;
>> +	struct sg_table *st;
>> +	resource_size_t start;
>> +	struct {
>> +		struct scatterlist *sg;
>> +		pgoff_t i;
>> +		pgoff_t end;
>> +		pgoff_t offs;
>> +	} cache;
>> +};
>> +
>> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_tt_ops;
>> +extern struct i915_ttm_kmap_iter_ops i915_ttm_kmap_iter_io_ops;
>> +
>> +/**
>> + * i915_ttm_kmap_iter_iomap_init - Initialize a struct i915_ttm_kmap_iter_iomap
>> + * @iter_io: The struct i915_ttm_kmap_iter_iomap to initialize.
>> + * @iomap: The struct io_mapping representing the underlying linear io_memory.
>> + * @st: sg_table into @iomap, representing the memory of the struct
>> + * ttm_resource.
>> + * @start: Offset that needs to be subtracted from @st to make
>> + * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
>> + *
>> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
>> + */
>> +static inline struct i915_ttm_kmap_iter *
>> +i915_ttm_kmap_iter_iomap_init(struct i915_ttm_kmap_iter_iomap *iter_io,
>> +			      struct io_mapping *iomap,
>> +			      struct sg_table *st,
>> +			      resource_size_t start)
>> +{
>> +	iter_io->base.ops = &i915_ttm_kmap_iter_io_ops;
>> +	iter_io->iomap = iomap;
>> +	iter_io->st = st;
>> +	iter_io->start = start;
>> +	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
>> +	return &iter_io->base;
>> +}
>> +
>> +/**
>> + * ttm_kmap_iter_tt_init - Initialize a struct i915_ttm_kmap_iter_tt
>> + * @iter_tt: The struct i915_ttm_kmap_iter_tt to initialize.
>> + * @tt: Struct ttm_tt holding page pointers of the struct ttm_resource.
>> + *
>> + * Return: Pointer to the embedded struct i915_ttm_kmap_iter.
>> + */
>> +static inline struct i915_ttm_kmap_iter *
>> +i915_ttm_kmap_iter_tt_init(struct i915_ttm_kmap_iter_tt *iter_tt,
>> +			   struct ttm_tt *tt)
>> +{
>> +	iter_tt->base.ops = &i915_ttm_kmap_iter_tt_ops;
>> +	iter_tt->tt = tt;
>> +	return &iter_tt->base;
>> +}
> Do there functions have a valid *performance* reason to be inline? I
> think that's pretty much the only valid reason.
>
> Having these inline forces i915_ttm_kmap_iter_*_ops extern, and they
> should really be static. Inline functions complicate header dependencies
> and leak the abstractions.
>
> BR,
> Jani.

Hi,

Thanks for reviewing. I don't think there really is a performance reason 
for keeping these functions inline. While in this case there is not 
really much change either in leaking abstractions nor in header 
dependencies I agree keeping those ops static is probably a better 
choice. I'll respin.

Thanks,

Thomas


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2021-05-18  6:54 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-11 13:25 [PATCH 0/7] drm/i915: Move LMEM (VRAM) management over to TTM Thomas Hellström
2021-05-11 13:25 ` [Intel-gfx] " Thomas Hellström
2021-05-11 13:25 ` [PATCH 1/7] drm/i915: Untangle the vma pages_mutex Thomas Hellström
2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
2021-05-11 13:25 ` [PATCH 2/7] drm/i915: Don't free shared locks while shared Thomas Hellström
2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
2021-05-11 13:25 ` [PATCH 3/7] drm/i915/ttm, drm/ttm: Initialize the ttm device and memory managers Thomas Hellström
2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
2021-05-12  8:57   ` Matthew Auld
2021-05-12  8:57     ` Matthew Auld
2021-05-17  7:18     ` Thomas Hellström
2021-05-17  7:18       ` Thomas Hellström
2021-05-17  7:28       ` Thomas Hellström
2021-05-17  7:28         ` Thomas Hellström
2021-05-11 13:25 ` [PATCH 4/7] drm/i915/ttm: Embed a ttm buffer object in the i915 gem object Thomas Hellström
2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
2021-05-11 13:25 ` [PATCH 5/7] drm/i915/ttm, drm/ttm: Add a generic TTM memcpy move for page-based iomem Thomas Hellström
2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
2021-05-17 10:57   ` Jani Nikula
2021-05-17 10:57     ` Jani Nikula
2021-05-18  6:53     ` Thomas Hellström
2021-05-18  6:53       ` Thomas Hellström
2021-05-11 13:25 ` [PATCH 6/7] drm/i915/ttm, drm/ttm: Introduce a TTM i915 gem object backend Thomas Hellström
2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
2021-05-11 13:58   ` Christian König
2021-05-11 13:58     ` [Intel-gfx] " Christian König
2021-05-11 14:06     ` Thomas Hellström (Intel)
2021-05-11 14:06       ` [Intel-gfx] " Thomas Hellström (Intel)
2021-05-11 14:09       ` Christian König
2021-05-11 14:09         ` [Intel-gfx] " Christian König
2021-05-11 14:28         ` Thomas Hellström
2021-05-11 14:28           ` [Intel-gfx] " Thomas Hellström
2021-05-12  6:57           ` Christian König
2021-05-12  6:57             ` [Intel-gfx] " Christian König
2021-05-12  7:05             ` Thomas Hellström
2021-05-12  7:05               ` [Intel-gfx] " Thomas Hellström
2021-05-12  7:09               ` Christian König
2021-05-12  7:09                 ` [Intel-gfx] " Christian König
2021-05-12 13:02                 ` Thomas Hellström
2021-05-12 13:02                   ` [Intel-gfx] " Thomas Hellström
2021-05-12 13:05                   ` Christian König
2021-05-12 13:05                     ` [Intel-gfx] " Christian König
2021-05-12 13:25                     ` Thomas Hellström
2021-05-12 13:25                       ` [Intel-gfx] " Thomas Hellström
2021-05-12 11:45   ` Matthew Auld
2021-05-12 11:45     ` Matthew Auld
2021-05-12 11:50     ` Thomas Hellström
2021-05-12 11:50       ` Thomas Hellström
2021-05-11 13:25 ` [PATCH 7/7] drm/i915/lmem: Verify checks for lmem residency Thomas Hellström
2021-05-11 13:25   ` [Intel-gfx] " Thomas Hellström
2021-05-12  7:58   ` Matthew Auld
2021-05-12  7:58     ` Matthew Auld
2021-05-11 16:21 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Move LMEM (VRAM) management over to TTM Patchwork
2021-05-11 16:24 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-05-11 16:48 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.