From: Alex Hung <[email protected]>

[WHAT]
Add KUnit tests for the DM atomic private-state accessors
(dm_atomic_get_new_state, dm_atomic_destroy_state), the native
cursor-mode selector (dm_should_update_native_cursor) and
amdgpu_dm_smu_write_watermarks_table. Cover the empty and matching
private-object lookups, the NULL-context destroy path, the NULL,
native and overlay cursor-mode paths, and the non-Navi1x watermark
table early return.

Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Wayne Lin <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  20 ++-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   8 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 155 ++++++++++++++++++
 3 files changed, 175 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 4b60d7343dec..7806b3405c3d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1404,7 +1404,7 @@ static void s3_handle_mst(struct drm_device *dev, bool 
suspend)
        drm_connector_list_iter_end(&iter);
 }
 
-static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
+STATIC_IFN_KUNIT int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device 
*adev)
 {
        int ret = 0;
 
@@ -1454,6 +1454,7 @@ static int amdgpu_dm_smu_write_watermarks_table(struct 
amdgpu_device *adev)
 
        return 0;
 }
+EXPORT_IF_KUNIT(amdgpu_dm_smu_write_watermarks_table);
 
 static int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
 {
@@ -2285,7 +2286,7 @@ int dm_atomic_get_state(struct drm_atomic_state *state,
        return 0;
 }
 
-static struct dm_atomic_state *
+STATIC_IFN_KUNIT struct dm_atomic_state *
 dm_atomic_get_new_state(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
@@ -2302,6 +2303,7 @@ dm_atomic_get_new_state(struct drm_atomic_state *state)
 
        return NULL;
 }
+EXPORT_IF_KUNIT(dm_atomic_get_new_state);
 
 static struct drm_private_state *
 dm_atomic_duplicate_state(struct drm_private_obj *obj)
@@ -2327,8 +2329,8 @@ dm_atomic_duplicate_state(struct drm_private_obj *obj)
        return &new_state->base;
 }
 
-static void dm_atomic_destroy_state(struct drm_private_obj *obj,
-                                   struct drm_private_state *state)
+STATIC_IFN_KUNIT void dm_atomic_destroy_state(struct drm_private_obj *obj,
+                                             struct drm_private_state *state)
 {
        struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
 
@@ -2337,6 +2339,7 @@ static void dm_atomic_destroy_state(struct 
drm_private_obj *obj,
 
        kfree(dm_state);
 }
+EXPORT_IF_KUNIT(dm_atomic_destroy_state);
 
 static struct drm_private_state_funcs dm_atomic_state_funcs = {
        .atomic_duplicate_state = dm_atomic_duplicate_state,
@@ -6360,10 +6363,10 @@ static int dm_check_native_cursor_state(struct drm_crtc 
*new_plane_crtc,
        return 0;
 }
 
-static bool dm_should_update_native_cursor(struct drm_atomic_state *state,
-                                          struct drm_crtc *old_plane_crtc,
-                                          struct drm_crtc *new_plane_crtc,
-                                          bool enable)
+STATIC_IFN_KUNIT bool dm_should_update_native_cursor(struct drm_atomic_state 
*state,
+                                                    struct drm_crtc 
*old_plane_crtc,
+                                                    struct drm_crtc 
*new_plane_crtc,
+                                                    bool enable)
 {
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
@@ -6388,6 +6391,7 @@ static bool dm_should_update_native_cursor(struct 
drm_atomic_state *state,
                return dm_new_crtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE;
        }
 }
+EXPORT_IF_KUNIT(dm_should_update_native_cursor);
 
 static int dm_update_plane_state(struct dc *dc,
                                 struct drm_atomic_state *state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index cbe95fb3c0d6..bef9663caf6e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1152,6 +1152,14 @@ void dm_bandwidth_update(struct amdgpu_device *adev);
 u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc);
 int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
                           u32 *vbl, u32 *position);
+struct dm_atomic_state *dm_atomic_get_new_state(struct drm_atomic_state 
*state);
+void dm_atomic_destroy_state(struct drm_private_obj *obj,
+                            struct drm_private_state *state);
+int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev);
+bool dm_should_update_native_cursor(struct drm_atomic_state *state,
+                                   struct drm_crtc *old_plane_crtc,
+                                   struct drm_crtc *new_plane_crtc,
+                                   bool enable);
 int dm_plane_layer_index_cmp(const void *a, const void *b);
 int fill_plane_color_attributes(const struct drm_plane_state *plane_state,
                                const enum surface_pixel_format format,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
index 7b92078d95bc..92056f4147d3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
@@ -183,6 +183,154 @@ static void dm_test_crtc_get_scanoutpos_no_stream(struct 
kunit *test)
        KUNIT_EXPECT_EQ(test, position, 0U);
 }
 
+/**
+ * dm_test_atomic_get_new_state_empty - Test empty atomic state has no DM state
+ * @test: The KUnit test context
+ */
+static void dm_test_atomic_get_new_state_empty(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       struct drm_atomic_state *state;
+
+       state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state);
+       state->dev = &adev->ddev;
+
+       KUNIT_EXPECT_NULL(test, dm_atomic_get_new_state(state));
+}
+
+/**
+ * dm_test_atomic_get_new_state_match - Test atomic state returns matching DM 
private state
+ * @test: The KUnit test context
+ */
+static void dm_test_atomic_get_new_state_match(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       struct dm_atomic_state *dm_state;
+       struct drm_atomic_state *state;
+
+       state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state);
+
+       dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+       state->private_objs = kunit_kzalloc(test, sizeof(*state->private_objs),
+                                           GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state->private_objs);
+
+       state->dev = &adev->ddev;
+       state->num_private_objs = 1;
+       state->private_objs[0].ptr = &adev->dm.atomic_obj;
+       state->private_objs[0].new_state = &dm_state->base;
+
+       KUNIT_EXPECT_PTR_EQ(test, dm_atomic_get_new_state(state), dm_state);
+}
+
+/**
+ * dm_test_should_update_native_cursor_without_crtc - Test NULL crtc cases 
update native cursor
+ * @test: The KUnit test context
+ */
+static void dm_test_should_update_native_cursor_without_crtc(struct kunit 
*test)
+{
+       KUNIT_EXPECT_TRUE(test, dm_should_update_native_cursor(NULL, NULL, 
NULL, false));
+       KUNIT_EXPECT_TRUE(test, dm_should_update_native_cursor(NULL, NULL, 
NULL, true));
+}
+
+/**
+ * dm_test_should_update_native_cursor_disable_native - Test disable path 
reads old crtc cursor mode
+ * @test: The KUnit test context
+ */
+static void dm_test_should_update_native_cursor_disable_native(struct kunit 
*test)
+{
+       struct dm_crtc_state *dm_crtc_state;
+       struct drm_atomic_state *state;
+       struct drm_crtc *crtc;
+
+       state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state);
+
+       crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, crtc);
+
+       dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
+
+       state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
+
+       crtc->index = 0;
+       dm_crtc_state->cursor_mode = DM_CURSOR_NATIVE_MODE;
+       state->crtcs[0].old_state = &dm_crtc_state->base;
+
+       KUNIT_EXPECT_TRUE(test,
+                         dm_should_update_native_cursor(state, crtc, NULL, 
false));
+}
+
+/**
+ * dm_test_should_update_native_cursor_enable_overlay - Test enable path reads 
new crtc cursor mode
+ * @test: The KUnit test context
+ */
+static void dm_test_should_update_native_cursor_enable_overlay(struct kunit 
*test)
+{
+       struct dm_crtc_state *dm_crtc_state;
+       struct drm_atomic_state *state;
+       struct drm_crtc *crtc;
+
+       state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state);
+
+       crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, crtc);
+
+       dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
+
+       state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
+
+       crtc->index = 0;
+       dm_crtc_state->cursor_mode = DM_CURSOR_OVERLAY_MODE;
+       state->crtcs[0].new_state = &dm_crtc_state->base;
+
+       KUNIT_EXPECT_FALSE(test,
+                          dm_should_update_native_cursor(state, NULL, crtc, 
true));
+}
+
+/**
+ * dm_test_atomic_destroy_state_no_context - Test destroying DM atomic state 
without a DC context
+ * @test: The KUnit test context
+ */
+static void dm_test_atomic_destroy_state_no_context(struct kunit *test)
+{
+       struct dm_atomic_state *dm_state;
+
+       /*
+        * Use kzalloc(), not kunit_kzalloc(): dm_atomic_destroy_state() frees
+        * the state itself, so KUnit-managed memory would be double-freed.
+        */
+       dm_state = kzalloc(sizeof(*dm_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+       /* context == NULL: dc_state_release() is skipped and the state is 
freed. */
+       dm_atomic_destroy_state(NULL, &dm_state->base);
+}
+
+/**
+ * dm_test_smu_write_watermarks_table_default - Test watermarks table skips 
non-Navi1x IP versions
+ * @test: The KUnit test context
+ */
+static void dm_test_smu_write_watermarks_table_default(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       /*
+        * A zeroed adev reports DCE IP version 0, which is not one of the
+        * Navi1x versions handled by the switch, so the function returns early.
+        */
+       KUNIT_EXPECT_EQ(test, amdgpu_dm_smu_write_watermarks_table(adev), 0);
+}
+
 /* Tests for dm_plane_layer_index_cmp() */
 
 /**
@@ -1069,6 +1217,13 @@ static struct kunit_case amdgpu_dm_tests[] = {
        KUNIT_CASE(dm_test_vblank_get_counter_no_stream),
        KUNIT_CASE(dm_test_crtc_get_scanoutpos_invalid_crtc),
        KUNIT_CASE(dm_test_crtc_get_scanoutpos_no_stream),
+       KUNIT_CASE(dm_test_atomic_get_new_state_empty),
+       KUNIT_CASE(dm_test_atomic_get_new_state_match),
+       KUNIT_CASE(dm_test_should_update_native_cursor_without_crtc),
+       KUNIT_CASE(dm_test_should_update_native_cursor_disable_native),
+       KUNIT_CASE(dm_test_should_update_native_cursor_enable_overlay),
+       KUNIT_CASE(dm_test_atomic_destroy_state_no_context),
+       KUNIT_CASE(dm_test_smu_write_watermarks_table_default),
        /* dm_plane_layer_index_cmp */
        KUNIT_CASE(dm_test_plane_layer_index_cmp_equal),
        KUNIT_CASE(dm_test_plane_layer_index_cmp_descending),
-- 
2.43.0

Reply via email to