[PATCH 14/18] drm/i915: switch over to ttm_buddy_man

Matthew Auld matthew.auld at intel.com
Wed May 12 15:16:11 UTC 2021


Move back to the buddy allocator for managing device local memory, and
restore the lost mock selftests.

Signed-off-by: Matthew Auld <matthew.auld at intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c       |  23 +--
 drivers/gpu/drm/i915/i915_scatterlist.c       |  66 -------
 drivers/gpu/drm/i915/i915_scatterlist.h       |   3 -
 drivers/gpu/drm/i915/intel_memory_region.c    |  54 +-----
 drivers/gpu/drm/i915/intel_memory_region.h    |  19 --
 drivers/gpu/drm/i915/intel_region_ttm.c       | 113 ++----------
 drivers/gpu/drm/i915/intel_region_ttm.h       |   3 -
 .../drm/i915/selftests/intel_memory_region.c  | 170 ++++++++++++------
 drivers/gpu/drm/i915/selftests/mock_region.c  |  17 +-
 9 files changed, 158 insertions(+), 310 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index aa142677c44b..e70f03994905 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -135,11 +135,7 @@ static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo,
 	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);
+	return i915_gem_object_evictable(obj);
 }
 
 static void i915_ttm_evict_flags(struct ttm_buffer_object *bo,
@@ -278,7 +274,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
 	if (man->use_tt)
 		return i915_ttm_tt_get_st(bo->ttm);
 
-	st = intel_region_ttm_node_to_st(obj->mm.region, res->mm_node);
+	st = i915_sg_from_buddy_blocks(res->mm_node, obj->base.size,
+				       obj->mm.region->region.start);
 	if (IS_ERR(st))
 		return ERR_CAST(st);
 
@@ -534,27 +531,15 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
 {
 	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,
+			  ttm_bo_type_kernel, &i915_sys_placement, PAGE_SIZE,
 			  true, NULL, NULL, i915_ttm_bo_destroy);
 
 	obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
index 5a8361616625..37c79844917c 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -41,72 +41,6 @@ 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;
-}
-
 /**
  * i915_sg_from_buddy_blocks - Create an sg_table from a struct i915_buddy_block list
  * @node: The list of i915_buddy_block.
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h
index 2271a8364073..c380198aa9ab 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.h
+++ b/drivers/gpu/drm/i915/i915_scatterlist.h
@@ -166,9 +166,6 @@ static inline unsigned int i915_sg_dma_page_sizes(struct scatterlist *sg)
 	return page_sizes;
 }
 
-struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
-				      u64 region_start);
-
 struct sg_table *i915_sg_from_buddy_blocks(struct list_head *blocks,
 					   u64 size,
 					   u64 region_start);
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index bd27e897d4d0..198ce79d146a 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -5,6 +5,7 @@
 
 #include "intel_memory_region.h"
 #include "i915_drv.h"
+#include "i915_ttm_buddy_manager.h"
 
 static const struct {
 	u16 class;
@@ -28,11 +29,6 @@ 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)
@@ -63,26 +59,6 @@ intel_memory_region_by_type(struct drm_i915_private *i915,
 	return NULL;
 }
 
-/**
- * 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 intel_region_reserve *reserve, *next;
-
-	if (!mem->priv_ops || !mem->priv_ops->free)
-		return;
-
-	mutex_lock(&mem->mm_lock);
-	list_for_each_entry_safe(reserve, next, &mem->reserved, link) {
-		list_del(&reserve->link);
-		mem->priv_ops->free(mem, reserve->node);
-		kfree(reserve);
-	}
-	mutex_unlock(&mem->mm_lock);
-}
 
 /**
  * intel_memory_region_reserve - Reserve a memory range
@@ -96,28 +72,9 @@ int intel_memory_region_reserve(struct intel_memory_region *mem,
 				resource_size_t offset,
 				resource_size_t size)
 {
-	int ret;
-	struct intel_region_reserve *reserve;
-
-	if (!mem->priv_ops || !mem->priv_ops->reserve)
-		return -EINVAL;
-
-	reserve = kzalloc(sizeof(*reserve), GFP_KERNEL);
-	if (!reserve)
-		return -ENOMEM;
-
-	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);
-	list_add_tail(&reserve->link, &mem->reserved);
-	mutex_unlock(&mem->mm_lock);
+	struct ttm_resource_manager *man = mem->region_private;
 
-	return 0;
+	return i915_ttm_buddy_man_reserve_nodev(man, offset, size);
 }
 
 struct intel_memory_region *
@@ -149,9 +106,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->reserved);
-
-	mutex_init(&mem->mm_lock);
 
 	if (ops->init) {
 		err = ops->init(mem);
@@ -182,11 +136,9 @@ 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);
 
-	mutex_destroy(&mem->mm_lock);
 	mutex_destroy(&mem->objects.lock);
 	kfree(mem);
 }
diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
index 7b5fa97c0b59..8c7fd49bdca6 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.h
+++ b/drivers/gpu/drm/i915/intel_memory_region.h
@@ -58,19 +58,10 @@ 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;
@@ -78,8 +69,6 @@ struct intel_memory_region {
 	/* For fake LMEM */
 	struct drm_mm_node fake_mappable;
 
-	struct mutex mm_lock;
-
 	struct kref kref;
 
 	resource_size_t io_start;
@@ -93,8 +82,6 @@ struct intel_memory_region {
 	char name[16];
 	bool private; /* not for userspace */
 
-	struct list_head reserved;
-
 	dma_addr_t remap_addr;
 
 	struct {
@@ -102,10 +89,6 @@ struct intel_memory_region {
 		struct list_head list;
 	} objects;
 
-	size_t chunk_size;
-	unsigned int max_order;
-	bool is_range_manager;
-
 	void *region_private;
 };
 
@@ -137,8 +120,6 @@ __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);
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
index a74cae4602b5..b4886cd7026e 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.c
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -7,6 +7,7 @@
 
 #include "i915_drv.h"
 #include "i915_scatterlist.h"
+#include "i915_ttm_buddy_manager.h"
 
 #include "intel_region_ttm.h"
 
@@ -62,57 +63,6 @@ static int intel_region_to_ttm_type(struct intel_memory_region *mem)
 	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.
@@ -128,20 +78,14 @@ 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);
+	man = i915_ttm_buddy_man_init_nodev(resource_size(&mem->region),
+					    PAGE_SIZE, 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.
@@ -170,33 +114,15 @@ void intel_region_ttm_fini(struct intel_memory_region *mem)
 	if (mem->type == INTEL_MEMORY_LOCAL) {
 		int ret;
 
-		ret = ttm_range_man_fini(&mem->i915->bdev,
-					 intel_region_to_ttm_type(mem));
+		ret = i915_ttm_buddy_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);
+		i915_ttm_buddy_man_fini_nodev(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);
-}
-
 #ifdef CONFIG_DRM_I915_SELFTEST
 /**
  * intel_region_ttm_node_alloc - Allocate memory resources from a region
@@ -223,25 +149,24 @@ void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
 	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;
-	}
+	mock_bo.page_alignment = PAGE_SIZE;
+	place.flags = flags;
 
 	ret = man->func->alloc(man, &mock_bo, &place, &res);
 	if (ret == -ENOSPC)
 		ret = -ENXIO;
 	return ret ? ERR_PTR(ret) : res.mm_node;
 }
+
 #endif
+
+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);
+}
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
index 9a5b0437d73f..d344e470d1b4 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.h
+++ b/drivers/gpu/drm/i915/intel_region_ttm.h
@@ -18,9 +18,6 @@ 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_free(struct intel_memory_region *mem,
 				void *node);
 
diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
index c85d516b85cd..3a5c399fc5fd 100644
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -20,6 +20,7 @@
 #include "gem/selftests/mock_context.h"
 #include "gt/intel_engine_user.h"
 #include "gt/intel_gt.h"
+#include "i915_buddy.h"
 #include "i915_memcpy.h"
 #include "selftests/igt_flush_test.h"
 #include "selftests/i915_random.h"
@@ -57,10 +58,9 @@ static int igt_mock_fill(void *arg)
 	LIST_HEAD(objects);
 	int err = 0;
 
-	page_size = mem->chunk_size;
+	page_size = PAGE_SIZE;
+	max_pages = div64_u64(total, page_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;
@@ -86,11 +86,6 @@ 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;
@@ -157,6 +152,7 @@ static bool is_contiguous(struct drm_i915_gem_object *obj)
 static int igt_mock_reserve(void *arg)
 {
 	struct intel_memory_region *mem = arg;
+	struct drm_i915_private *i915 = mem->i915;
 	resource_size_t avail = resource_size(&mem->region);
 	struct drm_i915_gem_object *obj;
 	const u32 chunk_size = SZ_32M;
@@ -166,16 +162,18 @@ static int igt_mock_reserve(void *arg)
 	LIST_HEAD(objects);
 	int err = 0;
 
-	if (!list_empty(&mem->reserved)) {
-		pr_err("%s region reserved list is not empty\n", __func__);
-		return -EINVAL;
-	}
-
 	count = avail / chunk_size;
 	order = i915_random_order(count, &prng);
 	if (!order)
 		return 0;
 
+	mem = mock_region_create(i915, 0, SZ_2G, I915_GTT_PAGE_SIZE_4K, 0);
+	if (IS_ERR(mem)) {
+		pr_err("failed to create memory region\n");
+		err = PTR_ERR(mem);
+		goto out_close;
+	}
+
 	/* Reserve a bunch of ranges within the region */
 	for (i = 0; i < count; ++i) {
 		u64 start = order[i] * chunk_size;
@@ -205,18 +203,12 @@ 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 (mem->is_range_manager &&
-				    size > mem->chunk_size) {
-					size >>= 1;
-					goto retry;
-				}
+			if (PTR_ERR(obj) == -ENXIO)
 				break;
-			}
+
 			err = PTR_ERR(obj);
 			goto out_close;
 		}
@@ -232,7 +224,7 @@ static int igt_mock_reserve(void *arg)
 out_close:
 	kfree(order);
 	close_objects(mem, &objects);
-	intel_memory_region_unreserve(mem);
+	intel_memory_region_put(mem);
 	return err;
 }
 
@@ -252,7 +244,7 @@ static int igt_mock_contiguous(void *arg)
 	total = resource_size(&mem->region);
 
 	/* Min size */
-	obj = igt_object_create(mem, &objects, mem->chunk_size,
+	obj = igt_object_create(mem, &objects, PAGE_SIZE,
 				I915_BO_ALLOC_CONTIGUOUS);
 	if (IS_ERR(obj))
 		return PTR_ERR(obj);
@@ -333,17 +325,15 @@ static int igt_mock_contiguous(void *arg)
 	min = target;
 	target = total >> 1;
 
-	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);
+	/* 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);
+
 	/*
 	 * Even though we have enough free space, we don't have a big enough
 	 * contiguous block. Make sure that holds true.
@@ -362,7 +352,7 @@ static int igt_mock_contiguous(void *arg)
 		}
 
 		target >>= 1;
-	} while (target >= mem->chunk_size);
+	} while (target >= PAGE_SIZE);
 
 err_close_objects:
 	list_splice_tail(&holes, &objects);
@@ -375,14 +365,17 @@ static int igt_mock_splintered_region(void *arg)
 	struct intel_memory_region *mem = arg;
 	struct drm_i915_private *i915 = mem->i915;
 	struct drm_i915_gem_object *obj;
+	struct i915_buddy_mm *mm;
+	struct i915_buddy_block *block;
 	unsigned int expected_order;
+	struct list_head *blocks;
 	LIST_HEAD(objects);
 	u64 size;
 	int err = 0;
 
 	/*
 	 * Sanity check we can still allocate everything even if the
-	 * max_order != mm.size. i.e our starting address space size is not a
+	 * mm.max_order != mm.size. i.e our starting address space size is not a
 	 * power-of-two.
 	 */
 
@@ -391,20 +384,30 @@ static int igt_mock_splintered_region(void *arg)
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
-	expected_order = get_order(rounddown_pow_of_two(size));
-	if (mem->max_order != expected_order) {
-		pr_err("%s order mismatch(%u != %u)\n",
-		       __func__, mem->max_order, expected_order);
-		err = -EINVAL;
-		goto out_put;
-	}
-
 	obj = igt_object_create(mem, &objects, size, 0);
 	if (IS_ERR(obj)) {
 		err = PTR_ERR(obj);
 		goto out_close;
 	}
 
+	blocks = obj->mm.st_mm_node;
+	block = list_first_entry(blocks, struct i915_buddy_block, link);
+	mm = block->private;
+	if (mm->size != size) {
+		pr_err("%s size mismatch(%llu != %llu)\n",
+		       __func__, mm->size, size);
+		err = -EINVAL;
+		goto out_put;
+	}
+
+	expected_order = get_order(rounddown_pow_of_two(size));
+	if (mm->max_order != expected_order) {
+		pr_err("%s order mismatch(%u != %u)\n",
+		       __func__, mm->max_order, expected_order);
+		err = -EINVAL;
+		goto out_put;
+	}
+
 	close_objects(mem, &objects);
 
 	/*
@@ -415,15 +418,12 @@ static int igt_mock_splintered_region(void *arg)
 	 * sure that does indeed hold true.
 	 */
 
-	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, 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),
@@ -442,6 +442,73 @@ 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 list_head *blocks;
+	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;
+	blocks = obj->mm.st_mm_node;
+	list_for_each_entry(block, blocks, link) {
+		struct i915_buddy_mm *mm = block->private;
+
+		if (i915_buddy_block_size(mm, block) > size)
+			size = i915_buddy_block_size(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,
@@ -1046,6 +1113,7 @@ 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 9067601aa717..c0f47f380788 100644
--- a/drivers/gpu/drm/i915/selftests/mock_region.c
+++ b/drivers/gpu/drm/i915/selftests/mock_region.c
@@ -3,6 +3,7 @@
  * Copyright © 2019-2021 Intel Corporation
  */
 
+#include <drm/ttm/ttm_placement.h>
 #include <linux/scatterlist.h>
 
 #include "gem/i915_gem_region.h"
@@ -23,10 +24,11 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
 {
 	unsigned int flags;
 	struct sg_table *pages;
+	int err;
 
 	flags = I915_ALLOC_MIN_PAGE_SIZE;
 	if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
-		flags |= I915_ALLOC_CONTIGUOUS;
+		flags |= TTM_PL_FLAG_CONTIGUOUS;
 
 	obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
 							 obj->base.size,
@@ -34,14 +36,21 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
 	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);
+	pages = i915_sg_from_buddy_blocks(obj->mm.st_mm_node, obj->base.size,
+					  obj->mm.region->region.start);
+	if (IS_ERR(pages)) {
+		err = PTR_ERR(pages);
+		goto err_free_mm_node;
+	}
 
 	__i915_gem_object_set_pages(obj, pages,
 				    i915_sg_dma_page_sizes(pages->sgl));
 
 	return 0;
+
+err_free_mm_node:
+	intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
+	return err;
 }
 
 static const struct drm_i915_gem_object_ops mock_region_obj_ops = {
-- 
2.26.3



More information about the Intel-gfx-trybot mailing list