[21/25] drm/i915: switch over to ttm_buddy_man
Matthew Auld
matthew.auld at intel.com
Tue May 25 08:08:31 UTC 2021
On 24/05/2021 17:21, Thomas Hellström (Intel) wrote:
>
> 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.
Ok, I can try to keep around the range based path also. Using it for
stolen I think makes sense at some point.
>
> 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