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

Reply via email to