[PATCH 04/49] drm/amd/display: Add KUnit tests for link_lock and psp SRM helpers

Fangzhi Zuo <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Bhawanpreet Lakha <[email protected]>

Cover link_lock() across all links (lock then unlock) and the
max_link == 0 no-op path, checking each per-link mutex ends in
the expected state.

Also cover the psp_get_srm() and psp_set_srm() guard paths when
the HDCP TA context is uninitialized: psp_get_srm() returns NULL
and psp_set_srm() returns -EINVAL, both leaving their output
parameters untouched. The post-guard paths invoke real PSP
firmware and are not unit-testable in UML.

Reviewed-by: Alex Hung <[email protected]>
Signed-off-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Fangzhi Zuo <[email protected]>
Tested-by: Dan Wheeler <[email protected]>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c    |  12 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h    |   4 +
 .../amdgpu_dm/tests/amdgpu_dm_hdcp_test.c     | 127 ++++++++++++++++++
 3 files changed, 140 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 0dee603ecfaa..3b5e0e64adde 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -106,7 +106,8 @@ static bool lp_atomic_write_poll_read_aux(
 	return dm_atomic_write_poll_read_aux(link, write, poll, read, poll_timeout_us, poll_mask_msb);
 }
 
-static uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size)
+STATIC_IFN_KUNIT
+uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size)
 {
 	struct ta_hdcp_shared_memory *hdcp_cmd;
 
@@ -129,8 +130,10 @@ static uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint
 
 	return hdcp_cmd->out_msg.hdcp_get_srm.srm_buf;
 }
+EXPORT_IF_KUNIT(psp_get_srm);
 
-static int psp_set_srm(struct psp_context *psp,
+STATIC_IFN_KUNIT
+int psp_set_srm(struct psp_context *psp,
 		       u8 *srm, uint32_t srm_size, uint32_t *srm_version)
 {
 	struct ta_hdcp_shared_memory *hdcp_cmd;
@@ -157,6 +160,7 @@ static int psp_set_srm(struct psp_context *psp,
 	*srm_version = hdcp_cmd->out_msg.hdcp_set_srm.srm_version;
 	return 0;
 }
+EXPORT_IF_KUNIT(psp_set_srm);
 
 STATIC_IFN_KUNIT
 void process_output(struct hdcp_workqueue *hdcp_work)
@@ -245,7 +249,8 @@ void hdcp_get_link_display_adjustments(
 }
 EXPORT_IF_KUNIT(hdcp_get_link_display_adjustments);
 
-static void link_lock(struct hdcp_workqueue *work, bool lock)
+STATIC_IFN_KUNIT
+void link_lock(struct hdcp_workqueue *work, bool lock)
 {
 	int i = 0;
 
@@ -256,6 +261,7 @@ static void link_lock(struct hdcp_workqueue *work, bool lock)
 			mutex_unlock(&work[i].mutex);
 	}
 }
+EXPORT_IF_KUNIT(link_lock);
 
 STATIC_IFN_KUNIT
 void hdcp_update_display_encryption_control(struct hdcp_workqueue *hdcp_work,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index a82a20b80518..fb66f48d7297 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -44,6 +44,7 @@ struct mod_hdcp_link;
 struct mod_hdcp_display;
 struct cp_psp;
 struct amdgpu_device;
+struct psp_context;
 
 struct hdcp_workqueue {
 	struct work_struct cpirq_work;
@@ -113,6 +114,9 @@ void hdcp_update_display_encryption_control(struct hdcp_workqueue *hdcp_work,
 					    unsigned int conn_index,
 					    bool enable_encryption);
 void event_property_update(struct work_struct *work);
+void link_lock(struct hdcp_workqueue *work, bool lock);
+uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size);
+int psp_set_srm(struct psp_context *psp, u8 *srm, uint32_t srm_size, uint32_t *srm_version);
 #endif
 
 #endif /* AMDGPU_DM_AMDGPU_DM_HDCP_H_ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
index dbcff92672e6..43c7efcdd22c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
@@ -8,6 +8,7 @@
 #include <kunit/test.h>
 #include <linux/workqueue.h>
 
+#include "amdgpu.h"
 #include "amdgpu_dm_hdcp.h"
 
 static void dummy_work_fn(struct work_struct *work) {}
@@ -632,6 +633,126 @@ static void dm_test_hdcp_create_workqueue_zero_max_links_returns_null(struct kun
 
 /* End of tests for hdcp_create_workqueue() */
 
+/* Tests for link_lock() */
+
+/**
+ * dm_test_link_lock_locks_and_unlocks_all_links - lock/unlock spans every link
+ * @test: KUnit test context
+ *
+ * link_lock() should acquire the mutex of every entry from 0 to max_link
+ * when locking, and release all of them when unlocking. A subsequent
+ * lock/unlock cycle must succeed, proving the mutexes were left released.
+ */
+static void dm_test_link_lock_locks_and_unlocks_all_links(struct kunit *test)
+{
+	const int num_links = 3;
+	struct hdcp_workqueue *work;
+	int i;
+
+	work = kunit_kcalloc(test, num_links, sizeof(*work), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, work);
+
+	/* max_link is read from the first element. */
+	work[0].max_link = num_links;
+	for (i = 0; i < num_links; i++)
+		mutex_init(&work[i].mutex);
+
+	link_lock(work, true);
+	for (i = 0; i < num_links; i++)
+		KUNIT_EXPECT_TRUE(test, mutex_is_locked(&work[i].mutex));
+
+	link_lock(work, false);
+	for (i = 0; i < num_links; i++)
+		KUNIT_EXPECT_FALSE(test, mutex_is_locked(&work[i].mutex));
+
+	/* Mutexes must be re-acquirable after being released. */
+	link_lock(work, true);
+	for (i = 0; i < num_links; i++)
+		KUNIT_EXPECT_TRUE(test, mutex_is_locked(&work[i].mutex));
+	link_lock(work, false);
+}
+
+/**
+ * dm_test_link_lock_zero_links_is_noop - zero max_link touches no mutexes
+ * @test: KUnit test context
+ *
+ * When max_link is zero, link_lock() must not touch any mutex and simply
+ * return, leaving the (single) entry's mutex unlocked.
+ */
+static void dm_test_link_lock_zero_links_is_noop(struct kunit *test)
+{
+	struct hdcp_workqueue *work;
+
+	work = kunit_kzalloc(test, sizeof(*work), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, work);
+
+	mutex_init(&work->mutex);
+	work->max_link = 0;
+
+	link_lock(work, true);
+
+	KUNIT_EXPECT_FALSE(test, mutex_is_locked(&work->mutex));
+}
+
+/* End of tests for link_lock() */
+
+/* Tests for psp_get_srm() and psp_set_srm() */
+
+/**
+ * dm_test_psp_get_srm_uninitialized_returns_null - GET fails when TA not initialized
+ * @test: KUnit test context
+ *
+ * When the HDCP TA context is not initialized, psp_get_srm() must take the
+ * guard path and return NULL without touching the output parameters or
+ * invoking the (real) firmware path.
+ */
+static void dm_test_psp_get_srm_uninitialized_returns_null(struct kunit *test)
+{
+	struct psp_context *psp;
+	uint32_t srm_version = 0xdead;
+	uint32_t srm_size = 0xbeef;
+	uint8_t *srm;
+
+	psp = kunit_kzalloc(test, sizeof(*psp), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, psp);
+
+	/* kzalloc leaves hdcp_context.context.initialized == false */
+	srm = psp_get_srm(psp, &srm_version, &srm_size);
+
+	KUNIT_EXPECT_PTR_EQ(test, srm, NULL);
+	/* Output parameters must be left untouched on the guard path. */
+	KUNIT_EXPECT_EQ(test, srm_version, 0xdead);
+	KUNIT_EXPECT_EQ(test, srm_size, 0xbeef);
+}
+
+/**
+ * dm_test_psp_set_srm_uninitialized_returns_einval - SET fails when TA not initialized
+ * @test: KUnit test context
+ *
+ * When the HDCP TA context is not initialized, psp_set_srm() must take the
+ * guard path and return -EINVAL without updating srm_version or invoking
+ * the (real) firmware path.
+ */
+static void dm_test_psp_set_srm_uninitialized_returns_einval(struct kunit *test)
+{
+	struct psp_context *psp;
+	uint32_t srm_version = 0xdead;
+	u8 srm_buf[4] = {0};
+	int ret;
+
+	psp = kunit_kzalloc(test, sizeof(*psp), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, psp);
+
+	/* kzalloc leaves hdcp_context.context.initialized == false */
+	ret = psp_set_srm(psp, srm_buf, sizeof(srm_buf), &srm_version);
+
+	KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+	/* srm_version must be left untouched on the guard path. */
+	KUNIT_EXPECT_EQ(test, srm_version, 0xdead);
+}
+
+/* End of tests for psp_get_srm() and psp_set_srm() */
+
 static struct kunit_case dm_hdcp_test_cases[] = {
 	/* hdcp_get_content_protection_from_status() */
 	KUNIT_CASE(dm_test_hdcp_get_cp_disabled_returns_desired),
@@ -663,6 +784,12 @@ static struct kunit_case dm_hdcp_test_cases[] = {
 	KUNIT_CASE(dm_test_hdcp_update_display_disable_resets_status_and_cancels_validate),
 	/* hdcp_create_workqueue() */
 	KUNIT_CASE(dm_test_hdcp_create_workqueue_zero_max_links_returns_null),
+	/* link_lock() */
+	KUNIT_CASE(dm_test_link_lock_locks_and_unlocks_all_links),
+	KUNIT_CASE(dm_test_link_lock_zero_links_is_noop),
+	/* psp_get_srm() / psp_set_srm() */
+	KUNIT_CASE(dm_test_psp_get_srm_uninitialized_returns_null),
+	KUNIT_CASE(dm_test_psp_set_srm_uninitialized_returns_einval),
 	{}
 };
 
-- 
2.53.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.