Add a KUnit test to validate offset-aligned allocations in the DRM buddy
allocator.

The test covers allocations with sizes smaller than the alignment constraint
and verifies correct size preservation, offset alignment, and behavior across
multiple allocation sizes. It also exercises fragmentation by freeing
alternating blocks and confirms that allocation fails once all aligned offsets
are consumed.

Signed-off-by: Arunpravin Paneer Selvam <[email protected]>
---
 drivers/gpu/drm/tests/drm_buddy_test.c | 74 ++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c 
b/drivers/gpu/drm/tests/drm_buddy_test.c
index 5f40b5343bd8..9467496ff0e5 100644
--- a/drivers/gpu/drm/tests/drm_buddy_test.c
+++ b/drivers/gpu/drm/tests/drm_buddy_test.c
@@ -21,6 +21,79 @@ static inline u64 get_size(int order, u64 chunk_size)
        return (1 << order) * chunk_size;
 }
 
+static void drm_test_buddy_offset_aligned_allocation(struct kunit *test)
+{
+       struct drm_buddy_block *block, *tmp;
+       int num_blocks, i, count = 0;
+       LIST_HEAD(allocated);
+       struct drm_buddy mm;
+       u64 mm_size = SZ_4M;
+       LIST_HEAD(freed);
+
+       KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, SZ_4K),
+                              "buddy_init failed\n");
+
+       num_blocks = mm_size / SZ_256K;
+
+       /*
+        * Allocate multiple sizes under a fixed offset alignment.
+        * Ensures alignment handling is independent of allocation size and
+        * exercises subtree max-alignment pruning for small requests.
+        */
+       for (i = 0; i < num_blocks; i++)
+               KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, 
mm_size, SZ_8K, SZ_256K,
+                                                                   &allocated, 
0),
+                                       "buddy_alloc hit an error size=%u\n", 
SZ_8K);
+
+       list_for_each_entry(block, &allocated, link) {
+               /* Ensure the allocated block uses the expected 8 KB size */
+               KUNIT_EXPECT_EQ(test, drm_buddy_block_size(&mm, block), SZ_8K);
+               /* Ensure the block starts at a 256 KB-aligned offset for 
proper alignment */
+               KUNIT_EXPECT_EQ(test, drm_buddy_block_offset(block) & (SZ_256K 
- 1), 0ULL);
+       }
+       drm_buddy_free_list(&mm, &allocated, 0);
+
+       for (i = 0; i < num_blocks; i++)
+               KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, 
mm_size, SZ_16K, SZ_256K,
+                                                                   &allocated, 
0),
+                                       "buddy_alloc hit an error size=%u\n", 
SZ_16K);
+
+       list_for_each_entry(block, &allocated, link) {
+               /* Ensure the allocated block uses the expected 16 KB size */
+               KUNIT_EXPECT_EQ(test, drm_buddy_block_size(&mm, block), SZ_16K);
+               /* Ensure the block starts at a 256 KB-aligned offset for 
proper alignment */
+               KUNIT_EXPECT_EQ(test, drm_buddy_block_offset(block) & (SZ_256K 
- 1), 0ULL);
+       }
+
+       /*
+        * Free alternating aligned blocks to introduce fragmentation.
+        * Ensures offset-aligned allocations remain valid after frees and
+        * verifies subtree max-alignment metadata is correctly maintained.
+        */
+       list_for_each_entry_safe(block, tmp, &allocated, link) {
+               if (count % 2 == 0)
+                       list_move_tail(&block->link, &freed);
+               count++;
+       }
+       drm_buddy_free_list(&mm, &freed, 0);
+
+       for (i = 0; i < num_blocks / 2; i++)
+               KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, 
mm_size, SZ_16K, SZ_256K,
+                                                                   &allocated, 
0),
+                                       "buddy_alloc hit an error size=%u\n", 
SZ_16K);
+
+       /*
+        * Allocate with offset alignment after all slots are used; must fail.
+        * Confirms that no aligned offsets remain.
+        */
+       KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, 
SZ_16K, SZ_256K,
+                                                          &allocated, 0),
+                               "buddy_alloc hit an error size=%u\n", SZ_16K);
+
+       drm_buddy_free_list(&mm, &allocated, 0);
+       drm_buddy_fini(&mm);
+}
+
 static void drm_test_buddy_fragmentation_performance(struct kunit *test)
 {
        struct drm_buddy_block *block, *tmp;
@@ -877,6 +950,7 @@ static struct kunit_case drm_buddy_tests[] = {
        KUNIT_CASE(drm_test_buddy_alloc_clear),
        KUNIT_CASE(drm_test_buddy_alloc_range_bias),
        KUNIT_CASE(drm_test_buddy_fragmentation_performance),
+       KUNIT_CASE(drm_test_buddy_offset_aligned_allocation),
        {}
 };
 
-- 
2.34.1

Reply via email to