From: Alex Hung <[email protected]>

[Why]
Add KUnit tests for dm_clear_writeback() removing stream writeback
state and dm_set_writeback() leaving a job unarmed when no DC pipe
matches.

[How]
Use the real DC removal helper with a state-only update_bandwidth
fake, and construct the minimal DRM writeback objects needed to reach
the no-pipe cleanup path.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Ray Wu <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 ++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  7 ++
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 77 +++++++++++++++++++
 3 files changed, 94 insertions(+), 7 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 42e2ef74c687..d94d18e884ef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4375,9 +4375,9 @@ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc 
*acrtc)
 }
 EXPORT_IF_KUNIT(amdgpu_dm_crtc_complete_writeback);
 
-static void dm_clear_writeback(struct amdgpu_display_manager *dm,
-                             struct amdgpu_crtc *acrtc,
-                             struct dm_crtc_state *crtc_state)
+STATIC_IFN_KUNIT void dm_clear_writeback(struct amdgpu_display_manager *dm,
+                                        struct amdgpu_crtc *acrtc,
+                                        struct dm_crtc_state *crtc_state)
 {
        dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0);
 
@@ -4389,6 +4389,7 @@ static void dm_clear_writeback(struct 
amdgpu_display_manager *dm,
         */
        amdgpu_dm_crtc_complete_writeback(acrtc);
 }
+EXPORT_IF_KUNIT(dm_clear_writeback);
 
 /**
  * amdgpu_dm_mod_power_update_streams - update mod_power stream state on 
modeset
@@ -4722,10 +4723,11 @@ static void amdgpu_dm_commit_streams(struct 
drm_atomic_commit *state,
        }
 }
 
-static void dm_set_writeback(struct amdgpu_display_manager *dm,
-                             struct dm_crtc_state *crtc_state,
-                             struct drm_connector *connector,
-                             struct drm_connector_state *new_con_state)
+STATIC_IFN_KUNIT void
+dm_set_writeback(struct amdgpu_display_manager *dm,
+                struct dm_crtc_state *crtc_state,
+                struct drm_connector *connector,
+                struct drm_connector_state *new_con_state)
 {
        struct drm_writeback_connector *wb_conn = 
drm_connector_to_writeback(connector);
        struct amdgpu_device *adev = dm->adev;
@@ -4842,6 +4844,7 @@ static void dm_set_writeback(struct 
amdgpu_display_manager *dm,
 cleanup:
        kfree(wb_info);
 }
+EXPORT_IF_KUNIT(dm_set_writeback);
 
 STATIC_IFN_KUNIT void amdgpu_dm_update_hdcp(struct drm_atomic_commit *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 4d12632d048f..3c63dfcc2343 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1278,6 +1278,13 @@ void dm_gpureset_toggle_interrupts(struct amdgpu_device 
*adev, struct dc_state *
 enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc);
 int dm_cache_state(struct amdgpu_device *adev);
 void dm_destroy_cached_state(struct amdgpu_device *adev);
+void dm_clear_writeback(struct amdgpu_display_manager *dm,
+                       struct amdgpu_crtc *acrtc,
+                       struct dm_crtc_state *crtc_state);
+void dm_set_writeback(struct amdgpu_display_manager *dm,
+                     struct dm_crtc_state *crtc_state,
+                     struct drm_connector *connector,
+                     struct drm_connector_state *new_con_state);
 int dm_early_init(struct amdgpu_ip_block *ip_block);
 int fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
                                const struct drm_plane_state *plane_state,
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 61fa553c7a99..3209608a41b8 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
@@ -4422,6 +4422,81 @@ static void dm_test_destroy_cached_state_none(struct 
kunit *test)
        KUNIT_EXPECT_NULL(test, adev->dm.cached_state);
 }
 
+static bool dm_test_update_bandwidth(struct dc *dc, struct dc_state *context)
+{
+       return true;
+}
+
+/**
+ * dm_test_clear_writeback_removes_stream - Test teardown removes the stream 
writeback
+ * @test: The KUnit test context
+ */
+static void dm_test_clear_writeback_removes_stream(struct kunit *test)
+{
+       struct amdgpu_display_manager *dm;
+       struct dm_crtc_state *crtc_state;
+       struct amdgpu_crtc *acrtc;
+       struct dc_stream_state *stream;
+
+       dm = dm_kunit_alloc_dm(test);
+       crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, crtc_state);
+       acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, acrtc);
+       stream = dm_kunit_alloc_stream(test, NULL);
+       dm->dc->hwss.update_bandwidth = dm_test_update_bandwidth;
+       crtc_state->stream = stream;
+       stream->num_wb_info = 1;
+       stream->writeback_info[0].dwb_pipe_inst = 0;
+
+       dm_clear_writeback(dm, acrtc, crtc_state);
+
+       KUNIT_EXPECT_EQ(test, stream->num_wb_info, 0U);
+}
+
+/**
+ * dm_test_set_writeback_no_pipe - Test a stream without a DC pipe is not armed
+ * @test: The KUnit test context
+ */
+static void dm_test_set_writeback_no_pipe(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       struct drm_writeback_connector *wb_conn;
+       struct drm_connector_state *conn_state;
+       struct drm_writeback_job *job;
+       struct amdgpu_framebuffer *afb;
+       struct dm_crtc_state *crtc_state;
+       struct amdgpu_crtc *acrtc;
+       struct dc *dc;
+
+       wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, wb_conn);
+       conn_state = kunit_kzalloc(test, sizeof(*conn_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, conn_state);
+       job = kunit_kzalloc(test, sizeof(*job), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, job);
+       afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, afb);
+       crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, crtc_state);
+       acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, acrtc);
+       dc = dm_kunit_alloc_dc_with_ctx(test);
+       dc->current_state = dm_kunit_alloc_dc_state(test);
+
+       adev->dm.adev = adev;
+       adev->dm.dc = dc;
+       wb_conn->encoder.crtc = &acrtc->base;
+       job->fb = &afb->base;
+       conn_state->writeback_job = job;
+       crtc_state->stream = dm_kunit_alloc_stream(test, NULL);
+
+       dm_set_writeback(&adev->dm, crtc_state, &wb_conn->base, conn_state);
+
+       KUNIT_EXPECT_NULL(test, acrtc->wb_conn);
+       KUNIT_EXPECT_FALSE(test, acrtc->wb_pending);
+}
+
 /* Tests for dm_update_mst_vcpi_slots_for_dsc() */
 
 /**
@@ -5237,6 +5312,8 @@ static struct kunit_case amdgpu_dm_tests[] = {
        KUNIT_CASE(dm_test_cache_state_empty_device),
        KUNIT_CASE(dm_test_cache_state_error),
        KUNIT_CASE(dm_test_destroy_cached_state_none),
+       KUNIT_CASE(dm_test_clear_writeback_removes_stream),
+       KUNIT_CASE(dm_test_set_writeback_no_pipe),
        /* dm_update_mst_vcpi_slots_for_dsc */
        KUNIT_CASE(dm_test_mst_vcpi_slots_no_connector),
        KUNIT_CASE(dm_test_mst_vcpi_slots_skips_writeback),
-- 
2.43.0

Reply via email to