[PATCH 14/18] drm/i915: switch over to ttm_buddy_man
Matthew Auld
matthew.auld at intel.com
Wed May 12 15:16:11 UTC 2021
Move back to the buddy allocator for managing device local memory, and
restore the lost mock selftests.
Signed-off-by: Matthew Auld <matthew.auld at intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 23 +--
drivers/gpu/drm/i915/i915_scatterlist.c | 66 -------
drivers/gpu/drm/i915/i915_scatterlist.h | 3 -
drivers/gpu/drm/i915/intel_memory_region.c | 54 +-----
drivers/gpu/drm/i915/intel_memory_region.h | 19 --
drivers/gpu/drm/i915/intel_region_ttm.c | 113 ++----------
drivers/gpu/drm/i915/intel_region_ttm.h | 3 -
.../drm/i915/selftests/intel_memory_region.c | 170 ++++++++++++------
drivers/gpu/drm/i915/selftests/mock_region.c | 17 +-
9 files changed, 158 insertions(+), 310 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index aa142677c44b..e70f03994905 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -135,11 +135,7 @@ static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo,
struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
/* Will do for now. Our pinned objects are still on TTM's LRU lists */
- if (!i915_gem_object_evictable(obj))
- return false;
-
- /* This isn't valid with a buddy allocator */
- return ttm_bo_eviction_valuable(bo, place);
+ return i915_gem_object_evictable(obj);
}
static void i915_ttm_evict_flags(struct ttm_buffer_object *bo,
@@ -278,7 +274,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
if (man->use_tt)
return i915_ttm_tt_get_st(bo->ttm);
- st = intel_region_ttm_node_to_st(obj->mm.region, res->mm_node);
+ st = i915_sg_from_buddy_blocks(res->mm_node, obj->base.size,
+ obj->mm.region->region.start);
if (IS_ERR(st))
return ERR_CAST(st);
@@ -534,27 +531,15 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
{
static struct lock_class_key lock_class;
struct drm_i915_private *i915 = mem->i915;
- size_t alignment = 0;
int ret;
- /* Adjust alignment to GPU- and CPU huge page sizes. */
-
- if (mem->is_range_manager) {
- if (size >= SZ_1G)
- alignment = SZ_1G >> PAGE_SHIFT;
- else if (size >= SZ_2M)
- alignment = SZ_2M >> PAGE_SHIFT;
- else if (size >= SZ_64K)
- alignment = SZ_64K >> PAGE_SHIFT;
- }
-
drm_gem_private_object_init(&i915->drm, &obj->base, size);
i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);
i915_gem_object_init_memory_region(obj, mem);
i915_gem_object_make_unshrinkable(obj);
ret = ttm_bo_init(&i915->bdev, i915_gem_to_ttm(obj), size,
- ttm_bo_type_kernel, &i915_sys_placement, alignment,
+ ttm_bo_type_kernel, &i915_sys_placement, PAGE_SIZE,
true, NULL, NULL, i915_ttm_bo_destroy);
obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT;
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
index 5a8361616625..37c79844917c 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -41,72 +41,6 @@ bool i915_sg_trim(struct sg_table *orig_st)
return true;
}
-/**
- * i915_sg_from_mm_node - Create an sg_table from a struct drm_mm_node
- * @node: The drm_mm_node.
- * @region_start: An offset to add to the dma addresses of the sg list.
- *
- * Create a struct sg_table, initializing it from a struct drm_mm_node,
- * taking a maximum segment length into account, splitting into segments
- * if necessary.
- *
- * Return: A pointer to a kmalloced struct sg_table on success, negative
- * error code cast to an error pointer on failure.
- */
-struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
- u64 region_start)
-{
- const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
- u64 segment_pages = max_segment >> PAGE_SHIFT;
- u64 block_size, offset, prev_end;
- struct sg_table *st;
- struct scatterlist *sg;
-
- st = kmalloc(sizeof(*st), GFP_KERNEL);
- if (!st)
- return ERR_PTR(-ENOMEM);
-
- if (sg_alloc_table(st, DIV_ROUND_UP(node->size, segment_pages),
- GFP_KERNEL)) {
- kfree(st);
- return ERR_PTR(-ENOMEM);
- }
-
- sg = st->sgl;
- st->nents = 0;
- prev_end = (resource_size_t)-1;
- block_size = node->size << PAGE_SHIFT;
- offset = node->start << PAGE_SHIFT;
-
- while (block_size) {
- u64 len;
-
- if (offset != prev_end || sg->length >= max_segment) {
- if (st->nents)
- sg = __sg_next(sg);
-
- sg_dma_address(sg) = region_start + offset;
- sg_dma_len(sg) = 0;
- sg->length = 0;
- st->nents++;
- }
-
- len = min(block_size, max_segment - sg->length);
- sg->length += len;
- sg_dma_len(sg) += len;
-
- offset += len;
- block_size -= len;
-
- prev_end = offset;
- }
-
- sg_mark_end(sg);
- i915_sg_trim(st);
-
- return st;
-}
-
/**
* i915_sg_from_buddy_blocks - Create an sg_table from a struct i915_buddy_block list
* @node: The list of i915_buddy_block.
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h
index 2271a8364073..c380198aa9ab 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.h
+++ b/drivers/gpu/drm/i915/i915_scatterlist.h
@@ -166,9 +166,6 @@ static inline unsigned int i915_sg_dma_page_sizes(struct scatterlist *sg)
return page_sizes;
}
-struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
- u64 region_start);
-
struct sg_table *i915_sg_from_buddy_blocks(struct list_head *blocks,
u64 size,
u64 region_start);
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index bd27e897d4d0..198ce79d146a 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -5,6 +5,7 @@
#include "intel_memory_region.h"
#include "i915_drv.h"
+#include "i915_ttm_buddy_manager.h"
static const struct {
u16 class;
@@ -28,11 +29,6 @@ static const struct {
},
};
-struct intel_region_reserve {
- struct list_head link;
- void *node;
-};
-
struct intel_memory_region *
intel_memory_region_lookup(struct drm_i915_private *i915,
u16 class, u16 instance)
@@ -63,26 +59,6 @@ intel_memory_region_by_type(struct drm_i915_private *i915,
return NULL;
}
-/**
- * intel_memory_region_unreserve - Unreserve all previously reserved
- * ranges
- * @mem: The region containing the reserved ranges.
- */
-void intel_memory_region_unreserve(struct intel_memory_region *mem)
-{
- struct intel_region_reserve *reserve, *next;
-
- if (!mem->priv_ops || !mem->priv_ops->free)
- return;
-
- mutex_lock(&mem->mm_lock);
- list_for_each_entry_safe(reserve, next, &mem->reserved, link) {
- list_del(&reserve->link);
- mem->priv_ops->free(mem, reserve->node);
- kfree(reserve);
- }
- mutex_unlock(&mem->mm_lock);
-}
/**
* intel_memory_region_reserve - Reserve a memory range
@@ -96,28 +72,9 @@ int intel_memory_region_reserve(struct intel_memory_region *mem,
resource_size_t offset,
resource_size_t size)
{
- int ret;
- struct intel_region_reserve *reserve;
-
- if (!mem->priv_ops || !mem->priv_ops->reserve)
- return -EINVAL;
-
- reserve = kzalloc(sizeof(*reserve), GFP_KERNEL);
- if (!reserve)
- return -ENOMEM;
-
- reserve->node = mem->priv_ops->reserve(mem, offset, size);
- if (IS_ERR(reserve->node)) {
- ret = PTR_ERR(reserve->node);
- kfree(reserve);
- return ret;
- }
-
- mutex_lock(&mem->mm_lock);
- list_add_tail(&reserve->link, &mem->reserved);
- mutex_unlock(&mem->mm_lock);
+ struct ttm_resource_manager *man = mem->region_private;
- return 0;
+ return i915_ttm_buddy_man_reserve_nodev(man, offset, size);
}
struct intel_memory_region *
@@ -149,9 +106,6 @@ intel_memory_region_create(struct drm_i915_private *i915,
mutex_init(&mem->objects.lock);
INIT_LIST_HEAD(&mem->objects.list);
- INIT_LIST_HEAD(&mem->reserved);
-
- mutex_init(&mem->mm_lock);
if (ops->init) {
err = ops->init(mem);
@@ -182,11 +136,9 @@ static void __intel_memory_region_destroy(struct kref *kref)
struct intel_memory_region *mem =
container_of(kref, typeof(*mem), kref);
- intel_memory_region_unreserve(mem);
if (mem->ops->release)
mem->ops->release(mem);
- mutex_destroy(&mem->mm_lock);
mutex_destroy(&mem->objects.lock);
kfree(mem);
}
diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
index 7b5fa97c0b59..8c7fd49bdca6 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.h
+++ b/drivers/gpu/drm/i915/intel_memory_region.h
@@ -58,19 +58,10 @@ struct intel_memory_region_ops {
unsigned int flags);
};
-struct intel_memory_region_private_ops {
- void *(*reserve)(struct intel_memory_region *mem,
- resource_size_t offset,
- resource_size_t size);
- void (*free)(struct intel_memory_region *mem,
- void *node);
-};
-
struct intel_memory_region {
struct drm_i915_private *i915;
const struct intel_memory_region_ops *ops;
- const struct intel_memory_region_private_ops *priv_ops;
struct io_mapping iomap;
struct resource region;
@@ -78,8 +69,6 @@ struct intel_memory_region {
/* For fake LMEM */
struct drm_mm_node fake_mappable;
- struct mutex mm_lock;
-
struct kref kref;
resource_size_t io_start;
@@ -93,8 +82,6 @@ struct intel_memory_region {
char name[16];
bool private; /* not for userspace */
- struct list_head reserved;
-
dma_addr_t remap_addr;
struct {
@@ -102,10 +89,6 @@ struct intel_memory_region {
struct list_head list;
} objects;
- size_t chunk_size;
- unsigned int max_order;
- bool is_range_manager;
-
void *region_private;
};
@@ -137,8 +120,6 @@ __printf(2, 3) void
intel_memory_region_set_name(struct intel_memory_region *mem,
const char *fmt, ...);
-void intel_memory_region_unreserve(struct intel_memory_region *mem);
-
int intel_memory_region_reserve(struct intel_memory_region *mem,
resource_size_t offset,
resource_size_t size);
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
index a74cae4602b5..b4886cd7026e 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.c
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -7,6 +7,7 @@
#include "i915_drv.h"
#include "i915_scatterlist.h"
+#include "i915_ttm_buddy_manager.h"
#include "intel_region_ttm.h"
@@ -62,57 +63,6 @@ static int intel_region_to_ttm_type(struct intel_memory_region *mem)
return type;
}
-static void *intel_region_ttm_node_reserve(struct intel_memory_region *mem,
- resource_size_t offset,
- resource_size_t size)
-{
- struct ttm_resource_manager *man = mem->region_private;
- struct ttm_place place = {};
- struct ttm_resource res = {};
- struct ttm_buffer_object mock_bo = {};
- int ret;
-
- /*
- * Having to use a mock_bo is unfortunate but stems from some
- * drivers having private managers that insist to know what the
- * allocate memory is intended for, using it to send private
- * data to the manager. Also recently the bo has been used to send
- * alignment info to the manager. Assume that apart from the latter,
- * none of the managers we use will ever access the buffer object
- * members, hoping we can pass the alignment info in the
- * struct ttm_place in the future.
- */
-
- place.fpfn = offset >> PAGE_SHIFT;
- place.lpfn = place.fpfn + (size >> PAGE_SHIFT);
- res.num_pages = size >> PAGE_SHIFT;
- ret = man->func->alloc(man, &mock_bo, &place, &res);
- if (ret == -ENOSPC)
- ret = -ENXIO;
-
- return ret ? ERR_PTR(ret) : res.mm_node;
-}
-
-/**
- * intel_region_ttm_node_free - Free a node allocated from a resource manager
- * @mem: The region the node was allocated from.
- * @node: The opaque node representing an allocation.
- */
-void intel_region_ttm_node_free(struct intel_memory_region *mem,
- void *node)
-{
- struct ttm_resource_manager *man = mem->region_private;
- struct ttm_resource res = {};
-
- res.mm_node = node;
- man->func->free(man, &res);
-}
-
-static const struct intel_memory_region_private_ops priv_ops = {
- .reserve = intel_region_ttm_node_reserve,
- .free = intel_region_ttm_node_free,
-};
-
/**
* intel_region_ttm_init - Initialize a memory region for TTM.
* @mem: The region to initialize.
@@ -128,20 +78,14 @@ int intel_region_ttm_init(struct intel_memory_region *mem)
{
struct ttm_resource_manager *man;
- man = ttm_range_man_init_standalone(resource_size(&mem->region) >>
- PAGE_SHIFT, false);
+ man = i915_ttm_buddy_man_init_nodev(resource_size(&mem->region),
+ PAGE_SIZE, false);
if (IS_ERR(man))
return PTR_ERR(man);
ttm_resource_manager_set_used(man, true);
- mem->chunk_size = PAGE_SIZE;
- mem->max_order =
- get_order(rounddown_pow_of_two(resource_size(&mem->region)));
- mem->is_range_manager = true;
- mem->priv_ops = &priv_ops;
mem->region_private = man;
-
/*
* Register only LOCAL memory with the device so that we can
* run the mock selftests using the manager.
@@ -170,33 +114,15 @@ void intel_region_ttm_fini(struct intel_memory_region *mem)
if (mem->type == INTEL_MEMORY_LOCAL) {
int ret;
- ret = ttm_range_man_fini(&mem->i915->bdev,
- intel_region_to_ttm_type(mem));
+ ret = i915_ttm_buddy_man_fini(&mem->i915->bdev,
+ intel_region_to_ttm_type(mem));
GEM_WARN_ON(ret);
} else {
ttm_resource_manager_set_used(man, false);
- ttm_range_man_fini_standalone(man);
+ i915_ttm_buddy_man_fini_nodev(man);
}
}
-/**
- * intel_region_ttm_node_to_st - Convert an opaque TTM resource manager node
- * to an sg_table.
- * @mem: The memory region.
- * @node: The resource manager node obtained from the TTM resource manager.
- *
- * The gem backends typically use sg-tables for operations on the underlying
- * io_memory. So provide a way for the backends to translate the
- * nodes they are handed from TTM to sg-tables.
- *
- * Return: A malloced sg_table on success, an error pointer on failure.
- */
-struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
- void *node)
-{
- return i915_sg_from_mm_node(node, mem->region.start);
-}
-
#ifdef CONFIG_DRM_I915_SELFTEST
/**
* intel_region_ttm_node_alloc - Allocate memory resources from a region
@@ -223,25 +149,24 @@ void *intel_region_ttm_node_alloc(struct intel_memory_region *mem,
struct ttm_buffer_object mock_bo = {};
int ret;
- /*
- * We ignore the flags for now since we're using the range
- * manager and contigous and min page size would be fulfilled
- * by default if size is min page size aligned.
- */
res.num_pages = size >> PAGE_SHIFT;
-
- if (mem->is_range_manager) {
- if (size >= SZ_1G)
- mock_bo.page_alignment = SZ_1G >> PAGE_SHIFT;
- else if (size >= SZ_2M)
- mock_bo.page_alignment = SZ_2M >> PAGE_SHIFT;
- else if (size >= SZ_64K)
- mock_bo.page_alignment = SZ_64K >> PAGE_SHIFT;
- }
+ mock_bo.page_alignment = PAGE_SIZE;
+ place.flags = flags;
ret = man->func->alloc(man, &mock_bo, &place, &res);
if (ret == -ENOSPC)
ret = -ENXIO;
return ret ? ERR_PTR(ret) : res.mm_node;
}
+
#endif
+
+void intel_region_ttm_node_free(struct intel_memory_region *mem,
+ void *node)
+{
+ struct ttm_resource_manager *man = mem->region_private;
+ struct ttm_resource res = {};
+
+ res.mm_node = node;
+ man->func->free(man, &res);
+}
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
index 9a5b0437d73f..d344e470d1b4 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.h
+++ b/drivers/gpu/drm/i915/intel_region_ttm.h
@@ -18,9 +18,6 @@ int intel_region_ttm_init(struct intel_memory_region *mem);
void intel_region_ttm_fini(struct intel_memory_region *mem);
-struct sg_table *intel_region_ttm_node_to_st(struct intel_memory_region *mem,
- void *node);
-
void intel_region_ttm_node_free(struct intel_memory_region *mem,
void *node);
diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
index c85d516b85cd..3a5c399fc5fd 100644
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -20,6 +20,7 @@
#include "gem/selftests/mock_context.h"
#include "gt/intel_engine_user.h"
#include "gt/intel_gt.h"
+#include "i915_buddy.h"
#include "i915_memcpy.h"
#include "selftests/igt_flush_test.h"
#include "selftests/i915_random.h"
@@ -57,10 +58,9 @@ static int igt_mock_fill(void *arg)
LIST_HEAD(objects);
int err = 0;
- page_size = mem->chunk_size;
+ page_size = PAGE_SIZE;
+ max_pages = div64_u64(total, page_size);
rem = total;
-retry:
- max_pages = div64_u64(rem, page_size);
for_each_prime_number_from(page_num, 1, max_pages) {
resource_size_t size = page_num * page_size;
@@ -86,11 +86,6 @@ static int igt_mock_fill(void *arg)
err = 0;
if (err == -ENXIO) {
if (page_num * page_size <= rem) {
- if (mem->is_range_manager && max_pages > 1) {
- max_pages >>= 1;
- goto retry;
- }
-
pr_err("%s failed, space still left in region\n",
__func__);
err = -EINVAL;
@@ -157,6 +152,7 @@ static bool is_contiguous(struct drm_i915_gem_object *obj)
static int igt_mock_reserve(void *arg)
{
struct intel_memory_region *mem = arg;
+ struct drm_i915_private *i915 = mem->i915;
resource_size_t avail = resource_size(&mem->region);
struct drm_i915_gem_object *obj;
const u32 chunk_size = SZ_32M;
@@ -166,16 +162,18 @@ static int igt_mock_reserve(void *arg)
LIST_HEAD(objects);
int err = 0;
- if (!list_empty(&mem->reserved)) {
- pr_err("%s region reserved list is not empty\n", __func__);
- return -EINVAL;
- }
-
count = avail / chunk_size;
order = i915_random_order(count, &prng);
if (!order)
return 0;
+ mem = mock_region_create(i915, 0, SZ_2G, I915_GTT_PAGE_SIZE_4K, 0);
+ if (IS_ERR(mem)) {
+ pr_err("failed to create memory region\n");
+ err = PTR_ERR(mem);
+ goto out_close;
+ }
+
/* Reserve a bunch of ranges within the region */
for (i = 0; i < count; ++i) {
u64 start = order[i] * chunk_size;
@@ -205,18 +203,12 @@ static int igt_mock_reserve(void *arg)
do {
u32 size = i915_prandom_u32_max_state(cur_avail, &prng);
-retry:
size = max_t(u32, round_up(size, PAGE_SIZE), PAGE_SIZE);
obj = igt_object_create(mem, &objects, size, 0);
if (IS_ERR(obj)) {
- if (PTR_ERR(obj) == -ENXIO) {
- if (mem->is_range_manager &&
- size > mem->chunk_size) {
- size >>= 1;
- goto retry;
- }
+ if (PTR_ERR(obj) == -ENXIO)
break;
- }
+
err = PTR_ERR(obj);
goto out_close;
}
@@ -232,7 +224,7 @@ static int igt_mock_reserve(void *arg)
out_close:
kfree(order);
close_objects(mem, &objects);
- intel_memory_region_unreserve(mem);
+ intel_memory_region_put(mem);
return err;
}
@@ -252,7 +244,7 @@ static int igt_mock_contiguous(void *arg)
total = resource_size(&mem->region);
/* Min size */
- obj = igt_object_create(mem, &objects, mem->chunk_size,
+ obj = igt_object_create(mem, &objects, PAGE_SIZE,
I915_BO_ALLOC_CONTIGUOUS);
if (IS_ERR(obj))
return PTR_ERR(obj);
@@ -333,17 +325,15 @@ static int igt_mock_contiguous(void *arg)
min = target;
target = total >> 1;
- if (!mem->is_range_manager) {
- /* Make sure we can still allocate all the fragmented space */
- obj = igt_object_create(mem, &objects, target, 0);
- if (IS_ERR(obj)) {
- err = PTR_ERR(obj);
- goto err_close_objects;
- }
-
- igt_object_release(obj);
+ /* Make sure we can still allocate all the fragmented space */
+ obj = igt_object_create(mem, &objects, target, 0);
+ if (IS_ERR(obj)) {
+ err = PTR_ERR(obj);
+ goto err_close_objects;
}
+ igt_object_release(obj);
+
/*
* Even though we have enough free space, we don't have a big enough
* contiguous block. Make sure that holds true.
@@ -362,7 +352,7 @@ static int igt_mock_contiguous(void *arg)
}
target >>= 1;
- } while (target >= mem->chunk_size);
+ } while (target >= PAGE_SIZE);
err_close_objects:
list_splice_tail(&holes, &objects);
@@ -375,14 +365,17 @@ static int igt_mock_splintered_region(void *arg)
struct intel_memory_region *mem = arg;
struct drm_i915_private *i915 = mem->i915;
struct drm_i915_gem_object *obj;
+ struct i915_buddy_mm *mm;
+ struct i915_buddy_block *block;
unsigned int expected_order;
+ struct list_head *blocks;
LIST_HEAD(objects);
u64 size;
int err = 0;
/*
* Sanity check we can still allocate everything even if the
- * max_order != mm.size. i.e our starting address space size is not a
+ * mm.max_order != mm.size. i.e our starting address space size is not a
* power-of-two.
*/
@@ -391,20 +384,30 @@ static int igt_mock_splintered_region(void *arg)
if (IS_ERR(mem))
return PTR_ERR(mem);
- expected_order = get_order(rounddown_pow_of_two(size));
- if (mem->max_order != expected_order) {
- pr_err("%s order mismatch(%u != %u)\n",
- __func__, mem->max_order, expected_order);
- err = -EINVAL;
- goto out_put;
- }
-
obj = igt_object_create(mem, &objects, size, 0);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
goto out_close;
}
+ blocks = obj->mm.st_mm_node;
+ block = list_first_entry(blocks, struct i915_buddy_block, link);
+ mm = block->private;
+ if (mm->size != size) {
+ pr_err("%s size mismatch(%llu != %llu)\n",
+ __func__, mm->size, size);
+ err = -EINVAL;
+ goto out_put;
+ }
+
+ expected_order = get_order(rounddown_pow_of_two(size));
+ if (mm->max_order != expected_order) {
+ pr_err("%s order mismatch(%u != %u)\n",
+ __func__, mm->max_order, expected_order);
+ err = -EINVAL;
+ goto out_put;
+ }
+
close_objects(mem, &objects);
/*
@@ -415,15 +418,12 @@ static int igt_mock_splintered_region(void *arg)
* sure that does indeed hold true.
*/
- if (!mem->is_range_manager) {
- obj = igt_object_create(mem, &objects, size,
- I915_BO_ALLOC_CONTIGUOUS);
- if (!IS_ERR(obj)) {
- pr_err("%s too large contiguous allocation was not rejected\n",
- __func__);
- err = -EINVAL;
- goto out_close;
- }
+ obj = igt_object_create(mem, &objects, size, I915_BO_ALLOC_CONTIGUOUS);
+ if (!IS_ERR(obj)) {
+ pr_err("%s too large contiguous allocation was not rejected\n",
+ __func__);
+ err = -EINVAL;
+ goto out_close;
}
obj = igt_object_create(mem, &objects, rounddown_pow_of_two(size),
@@ -442,6 +442,73 @@ static int igt_mock_splintered_region(void *arg)
return err;
}
+#ifndef SZ_8G
+#define SZ_8G BIT_ULL(33)
+#endif
+
+static int igt_mock_max_segment(void *arg)
+{
+ const unsigned int max_segment = i915_sg_segment_size();
+ struct intel_memory_region *mem = arg;
+ struct drm_i915_private *i915 = mem->i915;
+ struct drm_i915_gem_object *obj;
+ struct i915_buddy_block *block;
+ struct list_head *blocks;
+ struct scatterlist *sg;
+ LIST_HEAD(objects);
+ u64 size;
+ int err = 0;
+
+ /*
+ * While we may create very large contiguous blocks, we may need
+ * to break those down for consumption elsewhere. In particular,
+ * dma-mapping with scatterlist elements have an implicit limit of
+ * UINT_MAX on each element.
+ */
+
+ size = SZ_8G;
+ mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0);
+ if (IS_ERR(mem))
+ return PTR_ERR(mem);
+
+ obj = igt_object_create(mem, &objects, size, 0);
+ if (IS_ERR(obj)) {
+ err = PTR_ERR(obj);
+ goto out_put;
+ }
+
+
+ size = 0;
+ blocks = obj->mm.st_mm_node;
+ list_for_each_entry(block, blocks, link) {
+ struct i915_buddy_mm *mm = block->private;
+
+ if (i915_buddy_block_size(mm, block) > size)
+ size = i915_buddy_block_size(mm, block);
+ }
+ if (size < max_segment) {
+ pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n",
+ __func__, max_segment, size);
+ err = -EINVAL;
+ goto out_close;
+ }
+
+ for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
+ if (sg->length > max_segment) {
+ pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
+ __func__, sg->length, max_segment);
+ err = -EINVAL;
+ goto out_close;
+ }
+ }
+
+out_close:
+ close_objects(mem, &objects);
+out_put:
+ intel_memory_region_put(mem);
+ return err;
+}
+
static int igt_gpu_write_dw(struct intel_context *ce,
struct i915_vma *vma,
u32 dword,
@@ -1046,6 +1113,7 @@ int intel_memory_region_mock_selftests(void)
SUBTEST(igt_mock_fill),
SUBTEST(igt_mock_contiguous),
SUBTEST(igt_mock_splintered_region),
+ SUBTEST(igt_mock_max_segment),
};
struct intel_memory_region *mem;
struct drm_i915_private *i915;
diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c
index 9067601aa717..c0f47f380788 100644
--- a/drivers/gpu/drm/i915/selftests/mock_region.c
+++ b/drivers/gpu/drm/i915/selftests/mock_region.c
@@ -3,6 +3,7 @@
* Copyright © 2019-2021 Intel Corporation
*/
+#include <drm/ttm/ttm_placement.h>
#include <linux/scatterlist.h>
#include "gem/i915_gem_region.h"
@@ -23,10 +24,11 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
{
unsigned int flags;
struct sg_table *pages;
+ int err;
flags = I915_ALLOC_MIN_PAGE_SIZE;
if (obj->flags & I915_BO_ALLOC_CONTIGUOUS)
- flags |= I915_ALLOC_CONTIGUOUS;
+ flags |= TTM_PL_FLAG_CONTIGUOUS;
obj->mm.st_mm_node = intel_region_ttm_node_alloc(obj->mm.region,
obj->base.size,
@@ -34,14 +36,21 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
if (IS_ERR(obj->mm.st_mm_node))
return PTR_ERR(obj->mm.st_mm_node);
- pages = intel_region_ttm_node_to_st(obj->mm.region, obj->mm.st_mm_node);
- if (IS_ERR(pages))
- return PTR_ERR(pages);
+ pages = i915_sg_from_buddy_blocks(obj->mm.st_mm_node, obj->base.size,
+ obj->mm.region->region.start);
+ if (IS_ERR(pages)) {
+ err = PTR_ERR(pages);
+ goto err_free_mm_node;
+ }
__i915_gem_object_set_pages(obj, pages,
i915_sg_dma_page_sizes(pages->sgl));
return 0;
+
+err_free_mm_node:
+ intel_region_ttm_node_free(obj->mm.region, obj->mm.st_mm_node);
+ return err;
}
static const struct drm_i915_gem_object_ops mock_region_obj_ops = {
--
2.26.3
More information about the Intel-gfx-trybot
mailing list