Commit 83ebef47 authored by Matthew Auld's avatar Matthew Auld Committed by Chris Wilson
Browse files

drm/i915/region: fix max size calculation



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: b908be54 ("drm/i915: support creating LMEM objects")
Signed-off-by: default avatarMatthew Auld <matthew.auld@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: CQ Tang <cq.tang@intel.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20201021103606.241395-1-matthew.auld@intel.com
parent 8f2b4b68
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+77 −0
Original line number Diff line number Diff line
@@ -261,6 +261,82 @@ err_close_objects:
	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;
+1 −1
Original line number Diff line number Diff line
@@ -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();