[WHAT]
Add KUnit tests for amdgpu_dm_update_hdcp() covering a missing workqueue,
a skipped writeback connector, and an unchanged DisplayPort connector.

[HOW]
Keep content protection unchanged and provide only the sink, connector,
and CRTC state needed for the connector walk, avoiding HDCP operations.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6-Sol
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   3 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   1 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 100 ++++++++++++++++++
 3 files changed, 103 insertions(+), 1 deletion(-)

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 fc03fcca4c6a..5b69794acc58 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4778,7 +4778,7 @@ static void dm_set_writeback(struct 
amdgpu_display_manager *dm,
        kfree(wb_info);
 }
 
-static void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state)
+STATIC_IFN_KUNIT void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state)
 {
        struct drm_connector_state *old_con_state, *new_con_state;
        struct drm_device *dev = state->dev;
@@ -4892,6 +4892,7 @@ static void amdgpu_dm_update_hdcp(struct 
drm_atomic_commit *state)
                }
        }
 }
+EXPORT_IF_KUNIT(amdgpu_dm_update_hdcp);
 
 static int amdgpu_dm_atomic_setup_commit(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 7cb22915d18b..ed3210be7ab8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1202,6 +1202,7 @@ bool amdgpu_dm_crtc_mem_type_changed(struct drm_device 
*dev,
                                     struct drm_atomic_commit *state,
                                     struct drm_crtc_state *crtc_state);
 void amdgpu_dm_dump_links_and_sinks(struct amdgpu_device *adev);
+void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state);
 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 63d43f917273..de2f2f8af230 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
@@ -29,6 +29,7 @@
 #include "amdgpu.h"
 #include "amdgpu_mode.h"
 #include "amdgpu_dm.h"
+#include "amdgpu_dm_hdcp.h"
 #include "amdgpu_dm_kunit_test_helpers.h"
 
 /* Tests for simple DM callbacks */
@@ -2846,6 +2847,101 @@ static void dm_test_dump_links_unnamed_sinks(struct 
kunit *test)
        amdgpu_dm_dump_links_and_sinks(adev);
 }
 
+/**
+ * dm_test_update_hdcp_no_workqueue - Test HDCP update is skipped without a 
workqueue
+ * @test: The KUnit test context
+ */
+static void dm_test_update_hdcp_no_workqueue(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       amdgpu_dm_update_hdcp(dm_test_alloc_commit(test, adev));
+}
+
+/*
+ * A commit with one connector of @type bound to a CRTC that keeps its stream.
+ * The content protection state is unchanged, so amdgpu_dm_update_hdcp() walks
+ * the connector without reaching hdcp_update_display() or 
hdcp_reset_display(),
+ * which are the only users of the HDCP workqueue contents.
+ */
+static struct drm_atomic_commit *dm_test_hdcp_commit(struct kunit *test,
+                                                    struct amdgpu_device *adev,
+                                                    int type)
+{
+       struct drm_atomic_commit *state = dm_test_alloc_commit(test, adev);
+       struct dm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct dm_connector_state *old_dm, *new_dm;
+       struct amdgpu_dm_connector *aconnector;
+       struct amdgpu_crtc *acrtc;
+       struct dc_sink *sink;
+
+       adev->dm.hdcp_workqueue = kunit_kzalloc(test,
+                                               
sizeof(*adev->dm.hdcp_workqueue),
+                                               GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, adev->dm.hdcp_workqueue);
+       aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, aconnector);
+       acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, acrtc);
+       old_dm = kunit_kzalloc(test, sizeof(*old_dm), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, old_dm);
+       new_dm = kunit_kzalloc(test, sizeof(*new_dm), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, new_dm);
+       old_crtc_state = kunit_kzalloc(test, sizeof(*old_crtc_state), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, old_crtc_state);
+       new_crtc_state = kunit_kzalloc(test, sizeof(*new_crtc_state), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, new_crtc_state);
+       sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, sink);
+       state->connectors = kunit_kzalloc(test, sizeof(*state->connectors), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state->connectors);
+       state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
+
+       strscpy(sink->edid_caps.display_name, "panel");
+       sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
+       aconnector->dc_sink = sink;
+       aconnector->base.connector_type = type;
+       aconnector->base.dpms = DRM_MODE_DPMS_ON;
+       aconnector->base.state = &new_dm->base;
+       new_dm->base.crtc = &acrtc->base;
+       new_crtc_state->stream = dm_kunit_alloc_stream(test, NULL);
+
+       state->num_connector = 1;
+       state->connectors[0].ptr = &aconnector->base;
+       state->connectors[0].old_state = &old_dm->base;
+       state->connectors[0].new_state = &new_dm->base;
+       state->crtcs[0].ptr = &acrtc->base;
+       state->crtcs[0].old_state = &old_crtc_state->base;
+       state->crtcs[0].new_state = &new_crtc_state->base;
+
+       return state;
+}
+
+/**
+ * dm_test_update_hdcp_writeback_skipped - Test writeback connectors are 
skipped
+ * @test: The KUnit test context
+ */
+static void dm_test_update_hdcp_writeback_skipped(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       amdgpu_dm_update_hdcp(dm_test_hdcp_commit(test, adev,
+                                                 
DRM_MODE_CONNECTOR_WRITEBACK));
+}
+
+/**
+ * dm_test_update_hdcp_unchanged - Test an unchanged connector needs no HDCP 
update
+ * @test: The KUnit test context
+ */
+static void dm_test_update_hdcp_unchanged(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       amdgpu_dm_update_hdcp(dm_test_hdcp_commit(test, adev,
+                                                 
DRM_MODE_CONNECTOR_DisplayPort));
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
        /* Simple DM callbacks */
        KUNIT_CASE(dm_test_wait_for_idle),
@@ -2988,6 +3084,10 @@ static struct kunit_case amdgpu_dm_tests[] = {
        KUNIT_CASE(dm_test_dump_links_no_links),
        KUNIT_CASE(dm_test_dump_links_with_sinks),
        KUNIT_CASE(dm_test_dump_links_unnamed_sinks),
+       /* commit-tail helpers */
+       KUNIT_CASE(dm_test_update_hdcp_no_workqueue),
+       KUNIT_CASE(dm_test_update_hdcp_writeback_skipped),
+       KUNIT_CASE(dm_test_update_hdcp_unchanged),
        {}
 };
 
-- 
2.43.0

Reply via email to