[PATCH 32/70] drm/amd/display: add KUnit tests for DM atomic state helpers

Wayne Lin <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.