From bb21700baf7bc7ff9db8085fb0f097e8f8bcc0c5 Mon Sep 17 00:00:00 2001 From: Arunpravin Paneer Selvam Date: Tue, 14 May 2024 20:26:35 +0530 Subject: drm/buddy: Fix the range bias clear memory allocation issue Problem statement: During the system boot time, an application request for the bulk volume of cleared range bias memory when the clear_avail is zero, we dont fallback into normal allocation method as we had an unnecessary clear_avail check which prevents the fallback method leads to fb allocation failure following system goes into unresponsive state. Solution: Remove the unnecessary clear_avail check in the range bias allocation function. v2: add a kunit for this corner case (Daniel Vetter) Signed-off-by: Arunpravin Paneer Selvam Fixes: 96950929eb23 ("drm/buddy: Implement tracking clear page feature") Reviewed-by: Matthew Auld Signed-off-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20240514145636.16253-1-Arunpravin.PaneerSelvam@amd.com --- drivers/gpu/drm/drm_buddy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 284ebae71cc4..1daf778cf6fa 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -249,6 +249,7 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) mm->size = size; mm->avail = size; + mm->clear_avail = 0; mm->chunk_size = chunk_size; mm->max_order = ilog2(size) - ilog2(chunk_size); @@ -574,7 +575,7 @@ __drm_buddy_alloc_range_bias(struct drm_buddy *mm, block = __alloc_range_bias(mm, start, end, order, flags, fallback); - if (IS_ERR(block) && mm->clear_avail) + if (IS_ERR(block)) return __alloc_range_bias(mm, start, end, order, flags, !fallback); -- cgit From 431c590c3ab0469dfedad3a832fe73556396ee52 Mon Sep 17 00:00:00 2001 From: Arunpravin Paneer Selvam Date: Tue, 14 May 2024 20:26:36 +0530 Subject: drm/tests: Add a unit test for range bias allocation Allocate cleared blocks in the bias range when the DRM buddy's clear avail is zero. This will validate the bias range allocation in scenarios like system boot when no cleared blocks are available and exercise the fallback path too. The resulting blocks should always be dirty. v1:(Matthew) - move the size to the variable declaration section. - move the mm.clear_avail init to allocator init. Signed-off-by: Arunpravin Paneer Selvam Reviewed-by: Matthew Auld Signed-off-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20240514145636.16253-2-Arunpravin.PaneerSelvam@amd.com --- drivers/gpu/drm/tests/drm_buddy_test.c | 36 +++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index e3b50e240d36..b3be68b03610 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -23,9 +23,11 @@ static inline u64 get_size(int order, u64 chunk_size) static void drm_test_buddy_alloc_range_bias(struct kunit *test) { - u32 mm_size, ps, bias_size, bias_start, bias_end, bias_rem; + u32 mm_size, size, ps, bias_size, bias_start, bias_end, bias_rem; DRM_RND_STATE(prng, random_seed); unsigned int i, count, *order; + struct drm_buddy_block *block; + unsigned long flags; struct drm_buddy mm; LIST_HEAD(allocated); @@ -222,6 +224,38 @@ static void drm_test_buddy_alloc_range_bias(struct kunit *test) drm_buddy_free_list(&mm, &allocated, 0); drm_buddy_fini(&mm); + + /* + * Allocate cleared blocks in the bias range when the DRM buddy's clear avail is + * zero. This will validate the bias range allocation in scenarios like system boot + * when no cleared blocks are available and exercise the fallback path too. The resulting + * blocks should always be dirty. + */ + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps), + "buddy_init failed\n"); + + bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps); + bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps); + bias_end = max(bias_end, bias_start + ps); + bias_rem = bias_end - bias_start; + + flags = DRM_BUDDY_CLEAR_ALLOCATION | DRM_BUDDY_RANGE_ALLOCATION; + size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); + + KUNIT_ASSERT_FALSE_MSG(test, + drm_buddy_alloc_blocks(&mm, bias_start, + bias_end, size, ps, + &allocated, + flags), + "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", + bias_start, bias_end, size, ps); + + list_for_each_entry(block, &allocated, link) + KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false); + + drm_buddy_free_list(&mm, &allocated, 0); + drm_buddy_fini(&mm); } static void drm_test_buddy_alloc_clear(struct kunit *test) -- cgit