[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