[PATCH 39/59] drm/amd/display: Test HDCP update

Alex Hung <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
[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
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.