From: Alex Hung <[email protected]>

[WHAT]
Add KUnit tests for the DM CRTC helpers: the no-writeback and
non-pending writeback paths of amdgpu_dm_crtc_complete_writeback, the
out-of-range and no-stream paths of dm_vblank_get_counter, and the
invalid-CRTC and no-stream paths of dm_crtc_get_scanoutpos.

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 |   9 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   3 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 112 ++++++++++++++++++
 3 files changed, 121 insertions(+), 3 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 80778d7e7337..4b60d7343dec 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -169,7 +169,7 @@ static inline void amdgpu_dm_exit_ips_for_hw_access(struct 
dc *dc)
  * @return
  * Counter for vertical blanks
  */
-static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+STATIC_IFN_KUNIT u32 dm_vblank_get_counter(struct amdgpu_device *adev, int 
crtc)
 {
        struct amdgpu_crtc *acrtc = NULL;
 
@@ -186,9 +186,10 @@ static u32 dm_vblank_get_counter(struct amdgpu_device 
*adev, int crtc)
 
        return dc_stream_get_vblank_counter(acrtc->dm_irq_params.stream);
 }
+EXPORT_IF_KUNIT(dm_vblank_get_counter);
 
-static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
-                                 u32 *vbl, u32 *position)
+STATIC_IFN_KUNIT int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int 
crtc,
+                                           u32 *vbl, u32 *position)
 {
        u32 v_blank_start = 0, v_blank_end = 0, h_position = 0, v_position = 0;
        struct amdgpu_crtc *acrtc = NULL;
@@ -223,6 +224,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device 
*adev, int crtc,
 
        return 0;
 }
+EXPORT_IF_KUNIT(dm_crtc_get_scanoutpos);
 
 STATIC_IFN_KUNIT bool dm_is_idle(struct amdgpu_ip_block *ip_block)
 {
@@ -4686,6 +4688,7 @@ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc 
*acrtc)
 
        return true;
 }
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_complete_writeback);
 
 static void dm_clear_writeback(struct amdgpu_display_manager *dm,
                              struct amdgpu_crtc *acrtc,
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 7bb552d1ddba..cbe95fb3c0d6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1149,6 +1149,9 @@ int dm_set_clockgating_state(struct amdgpu_ip_block 
*ip_block,
 int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
                             enum amd_powergating_state state);
 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);
 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 d4e37580316f..7b92078d95bc 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
@@ -77,6 +77,112 @@ static void dm_test_bandwidth_update(struct kunit *test)
        dm_bandwidth_update(NULL);
 }
 
+/**
+ * dm_test_crtc_complete_writeback_no_connector - Test no writeback connector 
returns false
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_complete_writeback_no_connector(struct kunit *test)
+{
+       struct amdgpu_crtc *acrtc;
+
+       acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+       KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_complete_writeback(acrtc));
+}
+
+/**
+ * dm_test_crtc_complete_writeback_not_pending - Test non-pending writeback 
returns false
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_complete_writeback_not_pending(struct kunit *test)
+{
+       struct amdgpu_crtc *acrtc;
+       struct drm_writeback_connector *wb_conn;
+
+       acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, acrtc);
+       wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, wb_conn);
+
+       spin_lock_init(&wb_conn->job_lock);
+       acrtc->wb_conn = wb_conn;
+       acrtc->wb_pending = false;
+
+       KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_complete_writeback(acrtc));
+}
+
+/**
+ * dm_test_vblank_get_counter_out_of_range - Test out-of-range CRTC returns 
zero
+ * @test: The KUnit test context
+ */
+static void dm_test_vblank_get_counter_out_of_range(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       adev->mode_info.num_crtc = 1;
+
+       KUNIT_EXPECT_EQ(test, dm_vblank_get_counter(adev, 1), 0U);
+}
+
+/**
+ * dm_test_vblank_get_counter_no_stream - Test missing stream returns zero
+ * @test: The KUnit test context
+ */
+static void dm_test_vblank_get_counter_no_stream(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       struct amdgpu_crtc *acrtc;
+
+       acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+       adev->mode_info.num_crtc = 1;
+       adev->mode_info.crtcs[0] = acrtc;
+
+       KUNIT_EXPECT_EQ(test, dm_vblank_get_counter(adev, 0), 0U);
+}
+
+/**
+ * dm_test_crtc_get_scanoutpos_invalid_crtc - Test invalid CRTC returns -EINVAL
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_get_scanoutpos_invalid_crtc(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       u32 vbl = 0;
+       u32 position = 0;
+
+       adev->mode_info.num_crtc = 1;
+
+       KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, -1, &vbl, &position),
+                       -EINVAL);
+       KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, 1, &vbl, &position),
+                       -EINVAL);
+}
+
+/**
+ * dm_test_crtc_get_scanoutpos_no_stream - Test missing stream returns zero
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_get_scanoutpos_no_stream(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       struct amdgpu_crtc *acrtc;
+       u32 vbl = 0;
+       u32 position = 0;
+
+       acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+       adev->mode_info.num_crtc = 1;
+       adev->mode_info.crtcs[0] = acrtc;
+
+       KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, 0, &vbl, &position), 
0);
+       KUNIT_EXPECT_EQ(test, vbl, 0U);
+       KUNIT_EXPECT_EQ(test, position, 0U);
+}
+
 /* Tests for dm_plane_layer_index_cmp() */
 
 /**
@@ -957,6 +1063,12 @@ static struct kunit_case amdgpu_dm_tests[] = {
        KUNIT_CASE(dm_test_set_clockgating_state),
        KUNIT_CASE(dm_test_set_powergating_state),
        KUNIT_CASE(dm_test_bandwidth_update),
+       KUNIT_CASE(dm_test_crtc_complete_writeback_no_connector),
+       KUNIT_CASE(dm_test_crtc_complete_writeback_not_pending),
+       KUNIT_CASE(dm_test_vblank_get_counter_out_of_range),
+       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),
        /* 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