[21/25] drm/i915: switch over to ttm_buddy_man

Thomas Hellström (Intel) thomas_os at shipmail.org
Mon May 24 16:21:16 UTC 2021


On 5/19/21 9:51 AM, Matthew Auld wrote:
> Move back to the buddy allocator for managing device local memory, and
> restore the lost mock selftests.

Hmm, I figure if we choose to manage stolen memory and in the future 
GGTT with TTM and then would like to use the range manager, and since 
the intel_region_ttm code is operating on the ttm_resource_manager 
interface, can't we just Initialize the buddy manager instead of range, 
perhaps based on a region->use_buddy pool, and then keep the 
region->is_range_manager to select codepath.

I figure that way you'd only need to do some minor modifications in the 
intel_region_ttm code to hook up the buddy manager, except of course for 
the reserve interface, unless that very special call pattern can be 
intercepted in the buddy_man interface?

/Thomas



>
> 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       | 112 ++----------
>   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(+), 309 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> index 6e43025a5089..48600cc16ef6 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -136,11 +136,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,
> @@ -283,7 +279,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
>   	if (man->use_tt)
>   		return i915_ttm_tt_get_st(bo->ttm);
>   
> -	return intel_region_ttm_node_to_st(obj->mm.region, res->mm_node);
> +	return i915_sg_from_buddy_blocks(res->mm_node, obj->base.size,
> +					 obj->mm.region->region.start);
>   }
>   
>   static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
> @@ -628,20 +625,8 @@ 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);
> @@ -653,7 +638,7 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
>   	mutex_init(&obj->ttm.get_io_page.lock);
>   
>   	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);
>   
>   	/* i915 wants -ENXIO when out of memory region space. */
> 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 25f9803ddd5e..7cefb82e872a 100644
> --- a/drivers/gpu/drm/i915/i915_scatterlist.h
> +++ b/drivers/gpu/drm/i915/i915_scatterlist.h
> @@ -143,9 +143,6 @@ static inline unsigned int i915_sg_segment_size(void)
>   
>   bool i915_sg_trim(struct sg_table *orig_st);
>   
> -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 e429c9a38371..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,17 +78,12 @@ 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;
>   
>   	/*
> @@ -169,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
> @@ -222,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 8a217a592ec6..a97c34d18b2a 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,13 +36,20 @@ 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_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 = {


More information about the Intel-gfx-trybot mailing list