AMD-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] drm/buddy: Fix alloc_range() error handling code
@ 2024-02-13 13:52 Arunpravin Paneer Selvam
  2024-02-13 13:52 ` [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test Arunpravin Paneer Selvam
  0 siblings, 1 reply; 5+ messages in thread
From: Arunpravin Paneer Selvam @ 2024-02-13 13:52 UTC (permalink / raw)
  To: dri-devel, amd-gfx, intel-gfx
  Cc: christian.koenig, alexander.deucher, matthew.auld,
	mario.limonciello, daniel, Arunpravin Paneer Selvam, stable

Few users have observed display corruption when they boot
the machine to KDE Plasma or playing games. We have root
caused the problem that whenever alloc_range() couldn't
find the required memory blocks the function was returning
SUCCESS in some of the corner cases.

The right approach would be if the total allocated size
is less than the required size, the function should
return -ENOSPC.

Cc: <stable@vger.kernel.org> # 6.7+
Fixes: 0a1844bf0b53 ("drm/buddy: Improve contiguous memory allocation")
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3097
Tested-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://patchwork.kernel.org/project/dri-devel/patch/20240207174456.341121-1-Arunpravin.PaneerSelvam@amd.com/
Acked-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
---
 drivers/gpu/drm/drm_buddy.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c
index f57e6d74fb0e..c1a99bf4dffd 100644
--- a/drivers/gpu/drm/drm_buddy.c
+++ b/drivers/gpu/drm/drm_buddy.c
@@ -539,6 +539,12 @@ static int __alloc_range(struct drm_buddy *mm,
 	} while (1);
 
 	list_splice_tail(&allocated, blocks);
+
+	if (total_allocated < size) {
+		err = -ENOSPC;
+		goto err_free;
+	}
+
 	return 0;
 
 err_undo:

base-commit: 2c80a2b715df75881359d07dbaacff8ad411f40e
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test
  2024-02-13 13:52 [PATCH 1/2] drm/buddy: Fix alloc_range() error handling code Arunpravin Paneer Selvam
@ 2024-02-13 13:52 ` Arunpravin Paneer Selvam
  2024-02-13 14:28   ` Matthew Auld
  0 siblings, 1 reply; 5+ messages in thread
From: Arunpravin Paneer Selvam @ 2024-02-13 13:52 UTC (permalink / raw)
  To: dri-devel, amd-gfx, intel-gfx
  Cc: christian.koenig, alexander.deucher, matthew.auld,
	mario.limonciello, daniel, Arunpravin Paneer Selvam

Sanity check DRM_BUDDY_CONTIGUOUS_ALLOCATION.

References: https://gitlab.freedesktop.org/drm/amd/-/issues/3097
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Cc: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Cc: Limonciello <mario.limonciello@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
---
 drivers/gpu/drm/tests/drm_buddy_test.c | 89 ++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c
index ea2af6bd9abe..fee6bec757d1 100644
--- a/drivers/gpu/drm/tests/drm_buddy_test.c
+++ b/drivers/gpu/drm/tests/drm_buddy_test.c
@@ -8,6 +8,7 @@
 
 #include <linux/prime_numbers.h>
 #include <linux/sched/signal.h>
+#include <linux/sizes.h>
 
 #include <drm/drm_buddy.h>
 
@@ -18,6 +19,93 @@ static inline u64 get_size(int order, u64 chunk_size)
 	return (1 << order) * chunk_size;
 }
 
+static void drm_test_buddy_alloc_contiguous(struct kunit *test)
+{
+	u64 mm_size, ps = SZ_4K, i, n_pages, total;
+	struct drm_buddy_block *block;
+	struct drm_buddy mm;
+	LIST_HEAD(left);
+	LIST_HEAD(middle);
+	LIST_HEAD(right);
+	LIST_HEAD(allocated);
+
+	mm_size = 16 * 3 * SZ_4K;
+
+	KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
+
+	/*
+	 * Idea is to fragment the address space by alternating block
+	 * allocations between three different lists; one for left, middle and
+	 * right. We can then free a list to simulate fragmentation. In
+	 * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION,
+	 * including the try_harder path.
+	 */
+
+	i = 0;
+	n_pages = mm_size / ps;
+	do {
+		struct list_head *list;
+		int slot = i % 3;
+
+		if (slot == 0)
+			list = &left;
+		else if (slot == 1)
+			list = &middle;
+		else
+			list = &right;
+		KUNIT_ASSERT_FALSE_MSG(test,
+				       drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							      ps, ps, list, 0),
+				       "buddy_alloc hit an error size=%d\n",
+				       ps);
+	} while (++i < n_pages);
+
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   3 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%d\n", 3 * ps);
+
+	drm_buddy_free_list(&mm, &middle);
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   3 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%llu\n", 3 * ps);
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   2 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%llu\n", 2 * ps);
+
+	drm_buddy_free_list(&mm, &right);
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   3 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%llu\n", 3 * ps);
+	/*
+	 * At this point we should have enough contiguous space for 2 blocks,
+	 * however they are never buddies (since we freed middle and right) so
+	 * will require the try_harder logic to find them.
+	 */
+	KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							    2 * ps, ps, &allocated,
+							    DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc hit an error size=%d\n", 2 * ps);
+
+	drm_buddy_free_list(&mm, &left);
+	KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							    3 * ps, ps, &allocated,
+							    DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc hit an error size=%d\n", 3 * ps);
+
+	total = 0;
+	list_for_each_entry(block, &allocated, link)
+		total += drm_buddy_block_size(&mm, block);
+
+	KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
+
+	drm_buddy_free_list(&mm, &allocated);
+	drm_buddy_fini(&mm);
+}
+
 static void drm_test_buddy_alloc_pathological(struct kunit *test)
 {
 	u64 mm_size, size, start = 0;
@@ -280,6 +368,7 @@ static struct kunit_case drm_buddy_tests[] = {
 	KUNIT_CASE(drm_test_buddy_alloc_optimistic),
 	KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
 	KUNIT_CASE(drm_test_buddy_alloc_pathological),
+	KUNIT_CASE(drm_test_buddy_alloc_contiguous),
 	{}
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test
  2024-02-13 13:52 ` [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test Arunpravin Paneer Selvam
@ 2024-02-13 14:28   ` Matthew Auld
  2024-02-13 15:35     ` Christian König
  0 siblings, 1 reply; 5+ messages in thread
From: Matthew Auld @ 2024-02-13 14:28 UTC (permalink / raw)
  To: Arunpravin Paneer Selvam, dri-devel, amd-gfx, intel-gfx
  Cc: christian.koenig, alexander.deucher, mario.limonciello, daniel

On 13/02/2024 13:52, Arunpravin Paneer Selvam wrote:
> Sanity check DRM_BUDDY_CONTIGUOUS_ALLOCATION.
> 
> References: https://gitlab.freedesktop.org/drm/amd/-/issues/3097
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>

It looks like you changed the patch authorship here.

> Cc: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
> Cc: Limonciello <mario.limonciello@amd.com>
> Cc: Christian König <christian.koenig@amd.com>
> Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
> ---
>   drivers/gpu/drm/tests/drm_buddy_test.c | 89 ++++++++++++++++++++++++++
>   1 file changed, 89 insertions(+)
> 
> diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c
> index ea2af6bd9abe..fee6bec757d1 100644
> --- a/drivers/gpu/drm/tests/drm_buddy_test.c
> +++ b/drivers/gpu/drm/tests/drm_buddy_test.c
> @@ -8,6 +8,7 @@
>   
>   #include <linux/prime_numbers.h>
>   #include <linux/sched/signal.h>
> +#include <linux/sizes.h>
>   
>   #include <drm/drm_buddy.h>
>   
> @@ -18,6 +19,93 @@ static inline u64 get_size(int order, u64 chunk_size)
>   	return (1 << order) * chunk_size;
>   }
>   
> +static void drm_test_buddy_alloc_contiguous(struct kunit *test)
> +{
> +	u64 mm_size, ps = SZ_4K, i, n_pages, total;
> +	struct drm_buddy_block *block;
> +	struct drm_buddy mm;
> +	LIST_HEAD(left);
> +	LIST_HEAD(middle);
> +	LIST_HEAD(right);
> +	LIST_HEAD(allocated);
> +
> +	mm_size = 16 * 3 * SZ_4K;
> +
> +	KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
> +
> +	/*
> +	 * Idea is to fragment the address space by alternating block
> +	 * allocations between three different lists; one for left, middle and
> +	 * right. We can then free a list to simulate fragmentation. In
> +	 * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION,
> +	 * including the try_harder path.
> +	 */
> +
> +	i = 0;
> +	n_pages = mm_size / ps;
> +	do {
> +		struct list_head *list;
> +		int slot = i % 3;
> +
> +		if (slot == 0)
> +			list = &left;
> +		else if (slot == 1)
> +			list = &middle;
> +		else
> +			list = &right;
> +		KUNIT_ASSERT_FALSE_MSG(test,
> +				       drm_buddy_alloc_blocks(&mm, 0, mm_size,
> +							      ps, ps, list, 0),
> +				       "buddy_alloc hit an error size=%d\n",
> +				       ps);
> +	} while (++i < n_pages);
> +
> +	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
> +							   3 * ps, ps, &allocated,
> +							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
> +			       "buddy_alloc didn't error size=%d\n", 3 * ps);
> +
> +	drm_buddy_free_list(&mm, &middle);
> +	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
> +							   3 * ps, ps, &allocated,
> +							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
> +			       "buddy_alloc didn't error size=%llu\n", 3 * ps);
> +	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
> +							   2 * ps, ps, &allocated,
> +							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
> +			       "buddy_alloc didn't error size=%llu\n", 2 * ps);
> +
> +	drm_buddy_free_list(&mm, &right);
> +	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
> +							   3 * ps, ps, &allocated,
> +							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
> +			       "buddy_alloc didn't error size=%llu\n", 3 * ps);
> +	/*
> +	 * At this point we should have enough contiguous space for 2 blocks,
> +	 * however they are never buddies (since we freed middle and right) so
> +	 * will require the try_harder logic to find them.
> +	 */
> +	KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
> +							    2 * ps, ps, &allocated,
> +							    DRM_BUDDY_CONTIGUOUS_ALLOCATION),
> +			       "buddy_alloc hit an error size=%d\n", 2 * ps);
> +
> +	drm_buddy_free_list(&mm, &left);
> +	KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
> +							    3 * ps, ps, &allocated,
> +							    DRM_BUDDY_CONTIGUOUS_ALLOCATION),
> +			       "buddy_alloc hit an error size=%d\n", 3 * ps);
> +
> +	total = 0;
> +	list_for_each_entry(block, &allocated, link)
> +		total += drm_buddy_block_size(&mm, block);
> +
> +	KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
> +
> +	drm_buddy_free_list(&mm, &allocated);
> +	drm_buddy_fini(&mm);
> +}
> +
>   static void drm_test_buddy_alloc_pathological(struct kunit *test)
>   {
>   	u64 mm_size, size, start = 0;
> @@ -280,6 +368,7 @@ static struct kunit_case drm_buddy_tests[] = {
>   	KUNIT_CASE(drm_test_buddy_alloc_optimistic),
>   	KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
>   	KUNIT_CASE(drm_test_buddy_alloc_pathological),
> +	KUNIT_CASE(drm_test_buddy_alloc_contiguous),
>   	{}
>   };
>   

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test
  2024-02-13 14:28   ` Matthew Auld
@ 2024-02-13 15:35     ` Christian König
  0 siblings, 0 replies; 5+ messages in thread
From: Christian König @ 2024-02-13 15:35 UTC (permalink / raw)
  To: Matthew Auld, Arunpravin Paneer Selvam, dri-devel, amd-gfx,
	intel-gfx
  Cc: christian.koenig, alexander.deucher, mario.limonciello, daniel

Am 13.02.24 um 15:28 schrieb Matthew Auld:
> On 13/02/2024 13:52, Arunpravin Paneer Selvam wrote:
>> Sanity check DRM_BUDDY_CONTIGUOUS_ALLOCATION.
>>
>> References: https://gitlab.freedesktop.org/drm/amd/-/issues/3097
>> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
>> Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
>
> It looks like you changed the patch authorship here.

Going to fix this if I get tasked with pushing this to drm-misc-fixes.

But I still have hope that Arun will figure out how to do this himself.

Christian.

>
>> Cc: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
>> Cc: Limonciello <mario.limonciello@amd.com>
>> Cc: Christian König <christian.koenig@amd.com>
>> Signed-off-by: Arunpravin Paneer Selvam 
>> <Arunpravin.PaneerSelvam@amd.com>
>> ---
>>   drivers/gpu/drm/tests/drm_buddy_test.c | 89 ++++++++++++++++++++++++++
>>   1 file changed, 89 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c 
>> b/drivers/gpu/drm/tests/drm_buddy_test.c
>> index ea2af6bd9abe..fee6bec757d1 100644
>> --- a/drivers/gpu/drm/tests/drm_buddy_test.c
>> +++ b/drivers/gpu/drm/tests/drm_buddy_test.c
>> @@ -8,6 +8,7 @@
>>     #include <linux/prime_numbers.h>
>>   #include <linux/sched/signal.h>
>> +#include <linux/sizes.h>
>>     #include <drm/drm_buddy.h>
>>   @@ -18,6 +19,93 @@ static inline u64 get_size(int order, u64 
>> chunk_size)
>>       return (1 << order) * chunk_size;
>>   }
>>   +static void drm_test_buddy_alloc_contiguous(struct kunit *test)
>> +{
>> +    u64 mm_size, ps = SZ_4K, i, n_pages, total;
>> +    struct drm_buddy_block *block;
>> +    struct drm_buddy mm;
>> +    LIST_HEAD(left);
>> +    LIST_HEAD(middle);
>> +    LIST_HEAD(right);
>> +    LIST_HEAD(allocated);
>> +
>> +    mm_size = 16 * 3 * SZ_4K;
>> +
>> +    KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
>> +
>> +    /*
>> +     * Idea is to fragment the address space by alternating block
>> +     * allocations between three different lists; one for left, 
>> middle and
>> +     * right. We can then free a list to simulate fragmentation. In
>> +     * particular we want to exercise the 
>> DRM_BUDDY_CONTIGUOUS_ALLOCATION,
>> +     * including the try_harder path.
>> +     */
>> +
>> +    i = 0;
>> +    n_pages = mm_size / ps;
>> +    do {
>> +        struct list_head *list;
>> +        int slot = i % 3;
>> +
>> +        if (slot == 0)
>> +            list = &left;
>> +        else if (slot == 1)
>> +            list = &middle;
>> +        else
>> +            list = &right;
>> +        KUNIT_ASSERT_FALSE_MSG(test,
>> +                       drm_buddy_alloc_blocks(&mm, 0, mm_size,
>> +                                  ps, ps, list, 0),
>> +                       "buddy_alloc hit an error size=%d\n",
>> +                       ps);
>> +    } while (++i < n_pages);
>> +
>> +    KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
>> +                               3 * ps, ps, &allocated,
>> + DRM_BUDDY_CONTIGUOUS_ALLOCATION),
>> +                   "buddy_alloc didn't error size=%d\n", 3 * ps);
>> +
>> +    drm_buddy_free_list(&mm, &middle);
>> +    KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
>> +                               3 * ps, ps, &allocated,
>> + DRM_BUDDY_CONTIGUOUS_ALLOCATION),
>> +                   "buddy_alloc didn't error size=%llu\n", 3 * ps);
>> +    KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
>> +                               2 * ps, ps, &allocated,
>> + DRM_BUDDY_CONTIGUOUS_ALLOCATION),
>> +                   "buddy_alloc didn't error size=%llu\n", 2 * ps);
>> +
>> +    drm_buddy_free_list(&mm, &right);
>> +    KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
>> +                               3 * ps, ps, &allocated,
>> + DRM_BUDDY_CONTIGUOUS_ALLOCATION),
>> +                   "buddy_alloc didn't error size=%llu\n", 3 * ps);
>> +    /*
>> +     * At this point we should have enough contiguous space for 2 
>> blocks,
>> +     * however they are never buddies (since we freed middle and 
>> right) so
>> +     * will require the try_harder logic to find them.
>> +     */
>> +    KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, 
>> mm_size,
>> +                                2 * ps, ps, &allocated,
>> + DRM_BUDDY_CONTIGUOUS_ALLOCATION),
>> +                   "buddy_alloc hit an error size=%d\n", 2 * ps);
>> +
>> +    drm_buddy_free_list(&mm, &left);
>> +    KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, 
>> mm_size,
>> +                                3 * ps, ps, &allocated,
>> + DRM_BUDDY_CONTIGUOUS_ALLOCATION),
>> +                   "buddy_alloc hit an error size=%d\n", 3 * ps);
>> +
>> +    total = 0;
>> +    list_for_each_entry(block, &allocated, link)
>> +        total += drm_buddy_block_size(&mm, block);
>> +
>> +    KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
>> +
>> +    drm_buddy_free_list(&mm, &allocated);
>> +    drm_buddy_fini(&mm);
>> +}
>> +
>>   static void drm_test_buddy_alloc_pathological(struct kunit *test)
>>   {
>>       u64 mm_size, size, start = 0;
>> @@ -280,6 +368,7 @@ static struct kunit_case drm_buddy_tests[] = {
>>       KUNIT_CASE(drm_test_buddy_alloc_optimistic),
>>       KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
>>       KUNIT_CASE(drm_test_buddy_alloc_pathological),
>> +    KUNIT_CASE(drm_test_buddy_alloc_contiguous),
>>       {}
>>   };


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test
  2024-02-14  5:22 [PATCH 1/2] drm/buddy: Fix alloc_range() error handling code Arunpravin Paneer Selvam
@ 2024-02-14  5:22 ` Arunpravin Paneer Selvam
  0 siblings, 0 replies; 5+ messages in thread
From: Arunpravin Paneer Selvam @ 2024-02-14  5:22 UTC (permalink / raw)
  To: dri-devel, amd-gfx, intel-gfx
  Cc: christian.koenig, alexander.deucher, matthew.auld,
	mario.limonciello, daniel, Arunpravin Paneer Selvam

From: Matthew Auld <matthew.auld@intel.com>

Sanity check DRM_BUDDY_CONTIGUOUS_ALLOCATION.

References: https://gitlab.freedesktop.org/drm/amd/-/issues/3097
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Cc: Limonciello <mario.limonciello@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
---
 drivers/gpu/drm/tests/drm_buddy_test.c | 89 ++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c
index ea2af6bd9abe..4215d8b5fcf0 100644
--- a/drivers/gpu/drm/tests/drm_buddy_test.c
+++ b/drivers/gpu/drm/tests/drm_buddy_test.c
@@ -8,6 +8,7 @@
 
 #include <linux/prime_numbers.h>
 #include <linux/sched/signal.h>
+#include <linux/sizes.h>
 
 #include <drm/drm_buddy.h>
 
@@ -18,6 +19,93 @@ static inline u64 get_size(int order, u64 chunk_size)
 	return (1 << order) * chunk_size;
 }
 
+static void drm_test_buddy_alloc_contiguous(struct kunit *test)
+{
+	u64 mm_size, ps = SZ_4K, i, n_pages, total;
+	struct drm_buddy_block *block;
+	struct drm_buddy mm;
+	LIST_HEAD(left);
+	LIST_HEAD(middle);
+	LIST_HEAD(right);
+	LIST_HEAD(allocated);
+
+	mm_size = 16 * 3 * SZ_4K;
+
+	KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
+
+	/*
+	 * Idea is to fragment the address space by alternating block
+	 * allocations between three different lists; one for left, middle and
+	 * right. We can then free a list to simulate fragmentation. In
+	 * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION,
+	 * including the try_harder path.
+	 */
+
+	i = 0;
+	n_pages = mm_size / ps;
+	do {
+		struct list_head *list;
+		int slot = i % 3;
+
+		if (slot == 0)
+			list = &left;
+		else if (slot == 1)
+			list = &middle;
+		else
+			list = &right;
+		KUNIT_ASSERT_FALSE_MSG(test,
+				       drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							      ps, ps, list, 0),
+				       "buddy_alloc hit an error size=%d\n",
+				       ps);
+	} while (++i < n_pages);
+
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   3 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%d\n", 3 * ps);
+
+	drm_buddy_free_list(&mm, &middle);
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   3 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%llu\n", 3 * ps);
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   2 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%llu\n", 2 * ps);
+
+	drm_buddy_free_list(&mm, &right);
+	KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   3 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc didn't error size=%llu\n", 3 * ps);
+	/*
+	 * At this point we should have enough contiguous space for 2 blocks,
+	 * however they are never buddies (since we freed middle and right) so
+	 * will require the try_harder logic to find them.
+	 */
+	KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   2 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc hit an error size=%d\n", 2 * ps);
+
+	drm_buddy_free_list(&mm, &left);
+	KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+							   3 * ps, ps, &allocated,
+							   DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+			       "buddy_alloc hit an error size=%d\n", 3 * ps);
+
+	total = 0;
+	list_for_each_entry(block, &allocated, link)
+		total += drm_buddy_block_size(&mm, block);
+
+	KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
+
+	drm_buddy_free_list(&mm, &allocated);
+	drm_buddy_fini(&mm);
+}
+
 static void drm_test_buddy_alloc_pathological(struct kunit *test)
 {
 	u64 mm_size, size, start = 0;
@@ -280,6 +368,7 @@ static struct kunit_case drm_buddy_tests[] = {
 	KUNIT_CASE(drm_test_buddy_alloc_optimistic),
 	KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
 	KUNIT_CASE(drm_test_buddy_alloc_pathological),
+	KUNIT_CASE(drm_test_buddy_alloc_contiguous),
 	{}
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-02-14  5:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-13 13:52 [PATCH 1/2] drm/buddy: Fix alloc_range() error handling code Arunpravin Paneer Selvam
2024-02-13 13:52 ` [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test Arunpravin Paneer Selvam
2024-02-13 14:28   ` Matthew Auld
2024-02-13 15:35     ` Christian König
  -- strict thread matches above, loose matches on Subject: below --
2024-02-14  5:22 [PATCH 1/2] drm/buddy: Fix alloc_range() error handling code Arunpravin Paneer Selvam
2024-02-14  5:22 ` [PATCH 2/2] drm/tests/drm_buddy: add alloc_contiguous test Arunpravin Paneer Selvam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox