[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