From: Alex Hung <[email protected]>

[WHAT]
amdgpu_dm_hdmi_hpd_debounce_work() only ran with detection
failing, so neither outcome of the sink comparison that decides whether
an HPD toggle was spurious was covered.

[HOW]
Add a fixture for the debounce work item and two tests: a
re-detect finding the same sink, which re-enables internally without
notifying userspace, and one finding a different sink, which sends the
hotplug event.

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      | 114 ++++++++++++++++++
 1 file changed, 114 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 352ec7773e32..04cc5dd5812b 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
@@ -61,6 +61,12 @@ static bool dm_test_detect_link_false(struct dc_link *link,
        return false;
 }
 
+static bool dm_test_detect_link_true(struct dc_link *link,
+                                    enum dc_detect_reason reason)
+{
+       return true;
+}
+
 /* Spy on dc_link_detect() to prove the debounce early-return skipped it. */
 static int dm_test_detect_link_count;
 
@@ -2764,6 +2770,51 @@ static void dm_test_hpd_rx_offload_work_link_loss(struct 
kunit *test)
 
 /* Tests for amdgpu_dm_hdmi_hpd_debounce_work() */
 
+/*
+ * Build an aconnector wired for amdgpu_dm_hdmi_hpd_debounce_work(): an HPD
+ * lock, the debounce work item and a dc/link pair whose re-detect fails.
+ * Caller sets the link_srv stubs and any sinks the branch under test needs.
+ */
+static struct amdgpu_dm_connector *dm_test_setup_hdmi_debounce(struct kunit 
*test,
+                                                              struct 
link_service **link_srv_out)
+{
+       struct amdgpu_dm_connector *aconn;
+       struct link_service *link_srv;
+       struct amdgpu_device *adev;
+       struct dc_context *ctx;
+       struct dc_link *link;
+       struct dc *dc;
+
+       adev = dm_kunit_alloc_adev(test);
+       mutex_init(&adev->dm.dc_lock);
+
+       aconn = dm_kunit_alloc_connector(test, adev, NULL);
+       mutex_init(&aconn->hpd_lock);
+       INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work,
+                         amdgpu_dm_hdmi_hpd_debounce_work);
+
+       dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+       ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+       link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+
+       link_srv->detect_link = dm_test_detect_link_false;
+       dc->ctx = ctx;
+       dc->link_srv = link_srv;
+       ctx->dc = dc;
+       link->dc = dc;
+       link->ctx = ctx;
+       aconn->dc_link = link;
+
+       *link_srv_out = link_srv;
+
+       return aconn;
+}
+
 /**
  * dm_test_hdmi_hpd_debounce_detect_false - Test debounce false detect path
  * @test: The KUnit test context
@@ -2874,6 +2925,67 @@ static void 
dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit *test)
        KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink);
 }
 
+/**
+ * dm_test_hdmi_hpd_debounce_sink_unchanged - Test the spontaneous-toggle path
+ * @test: The KUnit test context
+ *
+ * A re-detect that finds the same sink as before the HPD toggle is an internal
+ * re-enable, so the connector state is refreshed but no hotplug event is sent
+ * to userspace. An MST-state connector keeps
+ * amdgpu_dm_update_connector_after_detect() to its early return.
+ */
+static void dm_test_hdmi_hpd_debounce_sink_unchanged(struct kunit *test)
+{
+       struct amdgpu_dm_connector *aconn;
+       struct link_service *link_srv;
+       struct dc_link *link;
+
+       aconn = dm_test_setup_hdmi_debounce(test, &link_srv);
+       link_srv->detect_link = dm_test_detect_link_true;
+       aconn->mst_mgr.mst_state = true;
+       link = aconn->dc_link;
+
+       /* Two identically zeroed sinks compare equal, i.e. a spurious toggle. 
*/
+       link->local_sink = dm_test_sink_create(link);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link->local_sink);
+       aconn->hdmi_prev_sink = dm_test_sink_create(link);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn->hdmi_prev_sink);
+
+       amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work);
+
+       KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink);
+
+       dm_test_sink_release(link->local_sink);
+}
+
+/**
+ * dm_test_hdmi_hpd_debounce_sink_changed - Test the real-hotplug path
+ * @test: The KUnit test context
+ *
+ * A re-detect that finds a different sink than the one cached before the HPD
+ * toggle is a real hotplug, so userspace must be notified. Sending the uevent
+ * needs a registered DRM device.
+ */
+static void dm_test_hdmi_hpd_debounce_sink_changed(struct kunit *test)
+{
+       struct amdgpu_dm_connector *aconn;
+       struct link_service *link_srv;
+
+       aconn = dm_test_setup_hdmi_debounce(test, &link_srv);
+       dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev));
+
+       link_srv->detect_link = dm_test_detect_link_true;
+       aconn->mst_mgr.mst_state = true;
+
+       /* The link lost its sink, so it cannot match the cached one. */
+       aconn->hdmi_prev_sink = dm_test_sink_create(aconn->dc_link);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn->hdmi_prev_sink);
+
+       amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work);
+
+       KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink);
+}
+
 /* Tests for handle_hpd_irq()/handle_hpd_irq_helper() */
 
 /**
@@ -5298,6 +5410,8 @@ static struct kunit_case amdgpu_dm_irq_tests[] = {
        /* amdgpu_dm_hdmi_hpd_debounce_work */
        KUNIT_CASE(dm_test_hdmi_hpd_debounce_detect_false),
        KUNIT_CASE(dm_test_hdmi_hpd_debounce_reallow_idle),
+       KUNIT_CASE(dm_test_hdmi_hpd_debounce_sink_unchanged),
+       KUNIT_CASE(dm_test_hdmi_hpd_debounce_sink_changed),
        /* handle_hpd_irq/handle_hpd_irq_helper */
        KUNIT_CASE(dm_test_handle_hpd_irq_disabled),
        KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_schedule),
-- 
2.55.0

Reply via email to