[PATCH 06/34] drm/amd/display: Add reset_state existing-state branch test

Tom Chung <[email protected]> Wed, 5 Aug 2026 14:36:18 +0800
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Bhawanpreet Lakha <[email protected]>

why:
amdgpu_dm_crtc_reset_state has a branch that destroys an already-installed
crtc state before allocating a new one. Only the NULL-state branch was
covered, leaving the state-replacement path untested.

how:
Add dm_test_crtc_reset_state_replaces_existing, which installs a plain
dm_crtc_state holding an extra stream reference, calls reset_state, and
verifies the old state was destroyed (stream ref dropped) and a fresh
non-NULL state was installed. Register the new case under the existing
reset_state group.

Reviewed-by: Alex Hung <[email protected]>
Signed-off-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Tom Chung <[email protected]>
---
 .../amdgpu_dm/tests/amdgpu_dm_crtc_test.c     | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
index 1af819113168..430765dd87a3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
@@ -1531,6 +1531,48 @@ static void dm_test_crtc_reset_state_allocates_state(struct kunit *test)
 		amdgpu_dm_crtc_destroy_state(crtc, crtc->state);
 }
 
+/**
+ * dm_test_crtc_reset_state_replaces_existing - Test reset frees the old state
+ * @test: The KUnit test context
+ *
+ * Resetting a CRTC that already carries a state must destroy the existing
+ * state before installing a fresh one. The old state holds a stream reference,
+ * so a successful reset drops that reference (via amdgpu_dm_crtc_destroy_state)
+ * and leaves the CRTC with a new, non-NULL state.
+ */
+static void dm_test_crtc_reset_state_replaces_existing(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct dc_stream_state *stream;
+	struct dm_crtc_state *old;
+	struct drm_crtc *crtc;
+	struct dc_link *link;
+
+	crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+	crtc->dev = &adev->ddev;
+
+	link = dm_kunit_alloc_link(test);
+	stream = dm_kunit_alloc_stream(test, link);
+	/* Extra ref so destroying the old state drops back to the managed one. */
+	kref_get(&stream->refcount);
+
+	/* reset_state kfree()s the old state, so use a plain (unmanaged) alloc. */
+	old = kzalloc_obj(*old, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old);
+	old->stream = stream;
+	crtc->state = &old->base;
+
+	amdgpu_dm_crtc_reset_state(crtc);
+
+	/* Old state was destroyed (stream ref dropped) and a new one installed. */
+	KUNIT_EXPECT_EQ(test, kref_read(&stream->refcount), 1);
+	KUNIT_EXPECT_NOT_NULL(test, crtc->state);
+
+	if (crtc->state)
+		amdgpu_dm_crtc_destroy_state(crtc, crtc->state);
+}
+
 /* Tests for amdgpu_dm_crtc_destroy_state() */
 
 /**
@@ -2013,6 +2055,7 @@ static struct kunit_case amdgpu_dm_crtc_tests[] = {
 	KUNIT_CASE(dm_test_crtc_destroy_cleans_up_and_frees),
 	/* amdgpu_dm_crtc_reset_state */
 	KUNIT_CASE(dm_test_crtc_reset_state_allocates_state),
+	KUNIT_CASE(dm_test_crtc_reset_state_replaces_existing),
 	/* amdgpu_dm_crtc_destroy_state */
 	KUNIT_CASE(dm_test_crtc_destroy_state_no_stream),
 	KUNIT_CASE(dm_test_crtc_destroy_state_releases_stream),
-- 
2.43.0