diff mbox series

[v2] drm/i915/region: fix max size calculation

Message ID 20201021103606.241395-1-matthew.auld@intel.com (mailing list archive)
State New, archived
Headers show
Series [v2] drm/i915/region: fix max size calculation | expand

Commit Message

Matthew Auld Oct. 21, 2020, 10:36 a.m. UTC
We are incorrectly limiting the max allocation size as per the mm
max_order, which is effectively the largest power-of-two that we can fit
in the region size. However, it's normal to setup the region or
allocator with a non-power-of-two size(for example 3G), which we should
already handle correctly, except it seems for the early too-big-check.

v2: make sure we also exercise the I915_BO_ALLOC_CONTIGUOUS path, which
is quite different, since for that we are actually limited by the
largest power-of-two that we can fit within the region size. (Chris)

Fixes: b908be543e44 ("drm/i915: support creating LMEM objects")
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: CQ Tang <cq.tang@intel.com>
---
 drivers/gpu/drm/i915/intel_memory_region.c    |  2 +-
 .../drm/i915/selftests/intel_memory_region.c  | 77 +++++++++++++++++++
 drivers/gpu/drm/i915/selftests/mock_region.c  |  2 +-
 3 files changed, 79 insertions(+), 2 deletions(-)

Comments

Chris Wilson Oct. 21, 2020, 5:20 p.m. UTC | #1
Quoting Matthew Auld (2020-10-21 11:36:06)
> We are incorrectly limiting the max allocation size as per the mm
> max_order, which is effectively the largest power-of-two that we can fit
> in the region size. However, it's normal to setup the region or
> allocator with a non-power-of-two size(for example 3G), which we should
> already handle correctly, except it seems for the early too-big-check.
> 
> v2: make sure we also exercise the I915_BO_ALLOC_CONTIGUOUS path, which
> is quite different, since for that we are actually limited by the
> largest power-of-two that we can fit within the region size. (Chris)
> 
> Fixes: b908be543e44 ("drm/i915: support creating LMEM objects")
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: CQ Tang <cq.tang@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_memory_region.c    |  2 +-
>  .../drm/i915/selftests/intel_memory_region.c  | 77 +++++++++++++++++++
>  drivers/gpu/drm/i915/selftests/mock_region.c  |  2 +-
>  3 files changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
> index 6b5e9d88646d..180e1078ef7c 100644
> --- a/drivers/gpu/drm/i915/intel_memory_region.c
> +++ b/drivers/gpu/drm/i915/intel_memory_region.c
> @@ -87,7 +87,7 @@ __intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
>                 min_order = ilog2(size) - ilog2(mem->mm.chunk_size);
>         }
>  
> -       if (size > BIT(mem->mm.max_order) * mem->mm.chunk_size)
> +       if (size > mem->mm.size)
>                 return -E2BIG;
>  
>         n_pages = size >> ilog2(mem->mm.chunk_size);
> diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
> index 334b0648e253..0aeba8e3af28 100644
> --- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
> +++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
> @@ -261,6 +261,82 @@ static int igt_mock_contiguous(void *arg)
>         return err;
>  }
>  
> +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;
> +       unsigned int expected_order;
> +       LIST_HEAD(objects);
> +       u64 size;
> +       int err = 0;
> +
> +       /*
> +        * Sanity check we can still allocate everything even if the
> +        * mm.max_order != mm.size. i.e our starting address space size is not a
> +        * power-of-two.
> +        */
> +
> +       size = (SZ_4G - 1) & PAGE_MASK;
> +       mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0);
> +       if (IS_ERR(mem))
> +               return PTR_ERR(mem);
> +
> +       if (mem->mm.size != size) {
> +               pr_err("%s size mismatch(%llu != %llu)\n",
> +                      __func__, mem->mm.size, size);
> +               err = -EINVAL;
> +               goto out_put;
> +       }
> +
> +       expected_order = get_order(rounddown_pow_of_two(size));
> +       if (mem->mm.max_order != expected_order) {
> +               pr_err("%s order mismatch(%u != %u)\n",
> +                      __func__, mem->mm.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;
> +       }
> +
> +       close_objects(mem, &objects);
> +
> +       /*
> +        * While we should be able allocate everything without any flag
> +        * restrictions, if we consider I915_BO_ALLOC_CONTIGUOUS then we are
> +        * actually limited to the largest power-of-two for the region size i.e
> +        * max_order, due to the inner workings of the buddy allocator. So make
> +        * sure that does indeed hold true.
> +        */
> +
> +       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),
> +                               I915_BO_ALLOC_CONTIGUOUS);
> +       if (IS_ERR(obj)) {
> +               pr_err("%s largest possible contiguous allocation failed\n",
> +                      __func__);
> +               err = PTR_ERR(obj);
> +               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,
> @@ -771,6 +847,7 @@ int intel_memory_region_mock_selftests(void)
>         static const struct i915_subtest tests[] = {
>                 SUBTEST(igt_mock_fill),
>                 SUBTEST(igt_mock_contiguous),
> +               SUBTEST(igt_mock_splintered_region),
>         };
>         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 09660f5a0a4c..979d96f27c43 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_region.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_region.c
> @@ -24,7 +24,7 @@ mock_object_create(struct intel_memory_region *mem,
>         struct drm_i915_private *i915 = mem->i915;
>         struct drm_i915_gem_object *obj;
>  
> -       if (size > BIT(mem->mm.max_order) * mem->mm.chunk_size)
> +       if (size > mem->mm.size)
>                 return ERR_PTR(-E2BIG);

Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
-Chris
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index 6b5e9d88646d..180e1078ef7c 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -87,7 +87,7 @@  __intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
 		min_order = ilog2(size) - ilog2(mem->mm.chunk_size);
 	}
 
-	if (size > BIT(mem->mm.max_order) * mem->mm.chunk_size)
+	if (size > mem->mm.size)
 		return -E2BIG;
 
 	n_pages = size >> ilog2(mem->mm.chunk_size);
diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
index 334b0648e253..0aeba8e3af28 100644
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -261,6 +261,82 @@  static int igt_mock_contiguous(void *arg)
 	return err;
 }
 
+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;
+	unsigned int expected_order;
+	LIST_HEAD(objects);
+	u64 size;
+	int err = 0;
+
+	/*
+	 * Sanity check we can still allocate everything even if the
+	 * mm.max_order != mm.size. i.e our starting address space size is not a
+	 * power-of-two.
+	 */
+
+	size = (SZ_4G - 1) & PAGE_MASK;
+	mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0);
+	if (IS_ERR(mem))
+		return PTR_ERR(mem);
+
+	if (mem->mm.size != size) {
+		pr_err("%s size mismatch(%llu != %llu)\n",
+		       __func__, mem->mm.size, size);
+		err = -EINVAL;
+		goto out_put;
+	}
+
+	expected_order = get_order(rounddown_pow_of_two(size));
+	if (mem->mm.max_order != expected_order) {
+		pr_err("%s order mismatch(%u != %u)\n",
+		       __func__, mem->mm.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;
+	}
+
+	close_objects(mem, &objects);
+
+	/*
+	 * While we should be able allocate everything without any flag
+	 * restrictions, if we consider I915_BO_ALLOC_CONTIGUOUS then we are
+	 * actually limited to the largest power-of-two for the region size i.e
+	 * max_order, due to the inner workings of the buddy allocator. So make
+	 * sure that does indeed hold true.
+	 */
+
+	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),
+				I915_BO_ALLOC_CONTIGUOUS);
+	if (IS_ERR(obj)) {
+		pr_err("%s largest possible contiguous allocation failed\n",
+		       __func__);
+		err = PTR_ERR(obj);
+		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,
@@ -771,6 +847,7 @@  int intel_memory_region_mock_selftests(void)
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_mock_fill),
 		SUBTEST(igt_mock_contiguous),
+		SUBTEST(igt_mock_splintered_region),
 	};
 	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 09660f5a0a4c..979d96f27c43 100644
--- a/drivers/gpu/drm/i915/selftests/mock_region.c
+++ b/drivers/gpu/drm/i915/selftests/mock_region.c
@@ -24,7 +24,7 @@  mock_object_create(struct intel_memory_region *mem,
 	struct drm_i915_private *i915 = mem->i915;
 	struct drm_i915_gem_object *obj;
 
-	if (size > BIT(mem->mm.max_order) * mem->mm.chunk_size)
+	if (size > mem->mm.size)
 		return ERR_PTR(-E2BIG);
 
 	obj = i915_gem_object_alloc();