From: Alex Hung <[email protected]>

[WHAT]
handle_hpd_rx_irq() left its whole post-detect block untested
apart from a failing re-detect, and never dispatched a CP_IRQ.

[HOW]
Add four tests covering a failing connection-type probe, a
connector forced on that is emulated instead of detected, a successful
re-detect that notifies userspace, and a CP_IRQ that must be handed to
the HDCP work queue for the connector that raised it.

Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: George Zhang <[email protected]>
---
 .../amdgpu_dm/tests/amdgpu_dm_irq_test.c      | 134 ++++++++++++++++++
 1 file changed, 134 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
index 5f877c50b120..a4fd30613419 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
@@ -231,6 +231,19 @@ static bool dm_test_handle_hpd_rx_result_true(struct 
dc_link *link,
        return true;
 }
 
+static bool dm_test_handle_hpd_rx_cp_irq(struct dc_link *link,
+                                        union hpd_irq_data *hpd_irq_data,
+                                        bool *link_loss,
+                                        bool defer_handling,
+                                        bool *has_left_work)
+{
+       *link_loss = false;
+       *has_left_work = false;
+       hpd_irq_data->bytes.device_service_irq.bits.CP_IRQ = 1;
+
+       return false;
+}
+
 static bool dm_test_allow_hpd_rx_irq_true(const struct dc_link *link)
 {
        return true;
@@ -3594,6 +3607,123 @@ static void 
dm_test_handle_hpd_rx_irq_downstream_change(struct kunit *test)
        KUNIT_EXPECT_TRUE(test, aconn->fake_enable);
 }
 
+/**
+ * dm_test_handle_hpd_rx_irq_detect_type_fails - Test HPDRX detect failure 
logging
+ * @test: The KUnit test context
+ *
+ * A handled HPD RX IRQ on a connector that is not an MST root means a
+ * downstream port status change, so the handler must re-detect the link. The
+ * connection-type probe is stubbed to fail, so it logs an error and continues
+ * into the re-detect branch, and a non-MST-branch link also exercises the
+ * trailing CEC IRQ dispatch.
+ */
+static void dm_test_handle_hpd_rx_irq_detect_type_fails(struct kunit *test)
+{
+       struct amdgpu_dm_connector *aconn;
+       struct link_service *link_srv;
+
+       dm_test_detect_link_count = 0;
+
+       aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
+       link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_result_true;
+       link_srv->detect_connection_type = dm_test_detect_connection_fail;
+       link_srv->detect_link = dm_test_detect_link_false_count;
+
+       aconn->mst_mgr.mst_state = false;
+       aconn->dc_link->type = dc_connection_single;
+
+       handle_hpd_rx_irq(aconn);
+
+       KUNIT_EXPECT_EQ(test, dm_test_detect_link_count, 1);
+}
+
+/**
+ * dm_test_handle_hpd_rx_irq_forced_detect - Test HPDRX forced-connector branch
+ * @test: The KUnit test context
+ *
+ * A connector forced on but reporting no connection is emulated rather than
+ * detected, and userspace is always notified. An unset connector signal keeps
+ * amdgpu_dm_emulated_link_detect() to its unsupported-signal early return, and
+ * a sink-less link keeps amdgpu_dm_update_connector_after_detect() to its
+ * unchanged-sink early return.
+ */
+static void dm_test_handle_hpd_rx_irq_forced_detect(struct kunit *test)
+{
+       struct amdgpu_dm_connector *aconn;
+       struct link_service *link_srv;
+
+       dm_test_detect_link_count = 0;
+
+       aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
+       dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev));
+
+       link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_result_true;
+       link_srv->detect_connection_type = dm_test_detect_connection_none;
+       link_srv->detect_link = dm_test_detect_link_false_count;
+
+       aconn->mst_mgr.mst_state = false;
+       aconn->base.force = DRM_FORCE_ON;
+       aconn->dc_link->ctx->driver_context = drm_to_adev(aconn->base.dev);
+       aconn->fake_enable = true;
+
+       handle_hpd_rx_irq(aconn);
+
+       KUNIT_EXPECT_FALSE(test, aconn->fake_enable);
+       KUNIT_EXPECT_EQ(test, dm_test_detect_link_count, 0);
+}
+
+/**
+ * dm_test_handle_hpd_rx_irq_detect_true - Test HPDRX connected detect branch
+ * @test: The KUnit test context
+ *
+ * A downstream-port change that re-detects a display refreshes the connector
+ * and notifies userspace. A sink-less link keeps
+ * amdgpu_dm_update_connector_after_detect() to its unchanged-sink early 
return.
+ */
+static void dm_test_handle_hpd_rx_irq_detect_true(struct kunit *test)
+{
+       struct amdgpu_dm_connector *aconn;
+       struct link_service *link_srv;
+
+       aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
+       dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev));
+
+       link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_result_true;
+       link_srv->detect_connection_type = dm_test_detect_connection_single;
+       link_srv->detect_link = dm_test_detect_link_true;
+
+       aconn->mst_mgr.mst_state = false;
+       aconn->fake_enable = true;
+
+       handle_hpd_rx_irq(aconn);
+
+       KUNIT_EXPECT_FALSE(test, aconn->fake_enable);
+}
+
+/**
+ * dm_test_handle_hpd_rx_irq_cp_irq - Test HPDRX content-protection dispatch
+ * @test: The KUnit test context
+ *
+ * A CP_IRQ in the device service field must be handed to the HDCP work queue
+ * for the connector that raised it.
+ */
+static void dm_test_handle_hpd_rx_irq_cp_irq(struct kunit *test)
+{
+       struct amdgpu_dm_connector *aconn;
+       struct hdcp_workqueue *hdcp_work;
+       struct link_service *link_srv;
+
+       aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
+       link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_cp_irq;
+
+       hdcp_work = dm_test_alloc_hdcp_workqueue(test);
+       drm_to_adev(aconn->base.dev)->dm.hdcp_workqueue = hdcp_work;
+
+       handle_hpd_rx_irq(aconn);
+
+       dm_test_flush_hdcp_workqueue(hdcp_work);
+}
+
 /* Tests for dmub_hpd_callback()/dmub_hpd_sense_callback() */
 
 /**
@@ -5545,6 +5675,10 @@ static struct kunit_case amdgpu_dm_irq_tests[] = {
        KUNIT_CASE(dm_test_handle_hpd_rx_irq_msg_rdy),
        KUNIT_CASE(dm_test_handle_hpd_rx_irq_link_loss),
        KUNIT_CASE(dm_test_handle_hpd_rx_irq_downstream_change),
+       KUNIT_CASE(dm_test_handle_hpd_rx_irq_detect_type_fails),
+       KUNIT_CASE(dm_test_handle_hpd_rx_irq_forced_detect),
+       KUNIT_CASE(dm_test_handle_hpd_rx_irq_detect_true),
+       KUNIT_CASE(dm_test_handle_hpd_rx_irq_cp_irq),
        KUNIT_CASE(dm_test_schedule_hpd_rx_offload_work),
        /* dmub_hpd_callback/dmub_hpd_sense_callback */
        KUNIT_CASE(dm_test_dmub_hpd_callback_null_inputs),
-- 
2.55.0

Reply via email to