From: Bhawanpreet Lakha <[email protected]> Add KUnit coverage for amdgpu_dm_connector_detect() and amdgpu_dm_connector_poll(): force on (analog/digital), force off, sink present/absent, and the DAC-load cached status path.
Assisted-by: Copilot:Claude-Opus-4.8 Reviewed-by: Alex Hung <[email protected]> Signed-off-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Wayne Lin <[email protected]> --- .../display/amdgpu_dm/amdgpu_dm_connector.c | 6 +- .../display/amdgpu_dm/amdgpu_dm_connector.h | 4 + .../tests/amdgpu_dm_connector_test.c | 157 ++++++++++++++++++ 3 files changed, 165 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c index 5c3dd1eb7878..94118f7f67c6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c @@ -1545,7 +1545,7 @@ EXPORT_IF_KUNIT(create_stream_for_sink); * * Return: The probed connector status (connected/disconnected/unknown). */ -static enum drm_connector_status +STATIC_IFN_KUNIT enum drm_connector_status amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) { struct drm_connector *connector = &aconnector->base; @@ -1597,6 +1597,7 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) mutex_unlock(&aconnector->hpd_lock); return status; } +EXPORT_IF_KUNIT(amdgpu_dm_connector_poll); /** * amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display @@ -1620,7 +1621,7 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) * Return: The connector status (connected, disconnected, or unknown). * */ -static enum drm_connector_status +STATIC_IFN_KUNIT enum drm_connector_status amdgpu_dm_connector_detect(struct drm_connector *connector, bool force) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); @@ -1644,6 +1645,7 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force) return (aconnector->dc_sink ? connector_status_connected : connector_status_disconnected); } +EXPORT_IF_KUNIT(amdgpu_dm_connector_detect); int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, struct drm_connector_state *connector_state, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h index 51858c92f922..8c4ba5a90ade 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h @@ -164,6 +164,10 @@ create_stream_for_sink(struct drm_connector *connector, const struct dm_connector_state *dm_state, const struct dc_stream_state *old_stream, int requested_bpc); +enum drm_connector_status +amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force); +enum drm_connector_status +amdgpu_dm_connector_detect(struct drm_connector *connector, bool force); enum display_content_type get_output_content_type(const struct drm_connector_state *connector_state); bool adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c index 2d58021b48f3..f38706e4d1c2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c @@ -3774,6 +3774,155 @@ static void dm_test_create_stream_existing_sink(struct kunit *test) dc_sink_release(sink); } +/* Tests for amdgpu_dm_connector_detect() */ + +/* + * A non-DisplayPort connector keeps update_subconnector_property() a no-op and, + * because the kunit thread is not the poll worker, the analog poll branch is + * skipped. That leaves the forced-state and dc_sink presence branches as the + * deterministic behaviour to exercise. + */ +static struct amdgpu_dm_connector *dm_test_detect_connector(struct kunit *test) +{ + struct drm_device *drm = dm_test_alloc_drm(test); + + return dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA); +} + +/** + * dm_test_detect_force_on - Test DRM_FORCE_ON reports connected + * @test: The KUnit test context + */ +static void dm_test_detect_force_on(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test); + + aconnector->base.force = DRM_FORCE_ON; + + KUNIT_EXPECT_EQ(test, + (int)amdgpu_dm_connector_detect(&aconnector->base, false), + (int)connector_status_connected); +} + +/** + * dm_test_detect_force_on_digital - Test DRM_FORCE_ON_DIGITAL reports connected + * @test: The KUnit test context + */ +static void dm_test_detect_force_on_digital(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test); + + aconnector->base.force = DRM_FORCE_ON_DIGITAL; + + KUNIT_EXPECT_EQ(test, + (int)amdgpu_dm_connector_detect(&aconnector->base, false), + (int)connector_status_connected); +} + +/** + * dm_test_detect_force_off - Test DRM_FORCE_OFF reports disconnected + * @test: The KUnit test context + */ +static void dm_test_detect_force_off(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test); + + aconnector->base.force = DRM_FORCE_OFF; + + KUNIT_EXPECT_EQ(test, + (int)amdgpu_dm_connector_detect(&aconnector->base, false), + (int)connector_status_disconnected); +} + +/** + * dm_test_detect_sink_present - Test a present dc_sink reports connected + * @test: The KUnit test context + */ +static void dm_test_detect_sink_present(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test); + struct dc_sink *sink; + + sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, sink); + + aconnector->base.force = DRM_FORCE_UNSPECIFIED; + aconnector->dc_sink = sink; + + KUNIT_EXPECT_EQ(test, + (int)amdgpu_dm_connector_detect(&aconnector->base, false), + (int)connector_status_connected); +} + +/** + * dm_test_detect_no_sink - Test a missing dc_sink reports disconnected + * @test: The KUnit test context + */ +static void dm_test_detect_no_sink(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test); + + aconnector->base.force = DRM_FORCE_UNSPECIFIED; + aconnector->dc_sink = NULL; + + KUNIT_EXPECT_EQ(test, + (int)amdgpu_dm_connector_detect(&aconnector->base, false), + (int)connector_status_disconnected); +} + +/* Tests for amdgpu_dm_connector_poll() */ + +/** + * dm_test_poll_dac_load_returns_cached - Test the DAC load detection shortcut + * @test: The KUnit test context + * + * When the previous connection was established by analog DAC load detection and + * polling is not forced, the connector is not re-detected and its cached status + * is returned unchanged. The connector is embedded in an amdgpu_device so that + * drm_to_adev() resolves. + */ +static void dm_test_poll_dac_load_returns_cached(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_dm_connector *aconnector; + struct dc_link *link; + struct dc_sink *local_sink; + struct drm_device *drm; + struct device *dev; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*adev), + offsetof(struct amdgpu_device, ddev), + DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + adev = drm_to_adev(drm); + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_EQ(test, + drmm_connector_init(drm, &aconnector->base, + &dm_test_connector_funcs, + DRM_MODE_CONNECTOR_VGA, NULL), 0); + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + local_sink = kunit_kzalloc(test, sizeof(*local_sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, local_sink); + + link->local_sink = local_sink; + link->type = dc_connection_analog_load; + aconnector->dc_link = link; + + /* The cached status that the shortcut must return unchanged. */ + aconnector->base.status = connector_status_connected; + + KUNIT_EXPECT_EQ(test, + (int)amdgpu_dm_connector_poll(aconnector, false), + (int)connector_status_connected); +} + static struct kunit_case amdgpu_dm_connector_tests[] = { /* get_subconnector_type */ KUNIT_CASE(dm_test_subconnector_type_none), @@ -3974,6 +4123,14 @@ static struct kunit_case amdgpu_dm_connector_tests[] = { KUNIT_CASE(dm_test_create_stream_virtual_signal), KUNIT_CASE(dm_test_create_stream_scaling_src), KUNIT_CASE(dm_test_create_stream_existing_sink), + /* amdgpu_dm_connector_detect */ + KUNIT_CASE(dm_test_detect_force_on), + KUNIT_CASE(dm_test_detect_force_on_digital), + KUNIT_CASE(dm_test_detect_force_off), + KUNIT_CASE(dm_test_detect_sink_present), + KUNIT_CASE(dm_test_detect_no_sink), + /* amdgpu_dm_connector_poll */ + KUNIT_CASE(dm_test_poll_dac_load_returns_cached), {} }; -- 2.43.0
