From: Bhawanpreet Lakha <[email protected]> Add KUnit coverage for create_stream_for_sink(): fake sink success, dm context setup, virtual signal handling, scaling source, and reuse of an existing sink.
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 | 3 +- .../display/amdgpu_dm/amdgpu_dm_connector.h | 6 + .../tests/amdgpu_dm_connector_test.c | 176 ++++++++++++++++++ drivers/gpu/drm/amd/display/dc/core/dc_sink.c | 2 + .../gpu/drm/amd/display/dc/core/dc_stream.c | 2 + 5 files changed, 188 insertions(+), 1 deletion(-) 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 c7d8810958f6..5c3dd1eb7878 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 @@ -1345,7 +1345,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, } #endif -static struct dc_stream_state * +STATIC_IFN_KUNIT struct dc_stream_state * create_stream_for_sink(struct drm_connector *connector, const struct drm_display_mode *drm_mode, const struct dm_connector_state *dm_state, @@ -1529,6 +1529,7 @@ create_stream_for_sink(struct drm_connector *connector, return stream; } +EXPORT_IF_KUNIT(create_stream_for_sink); /** * amdgpu_dm_connector_poll - Poll a connector to see if it's connected to a display 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 ad277fff57de..51858c92f922 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 @@ -158,6 +158,12 @@ void fill_stream_properties_from_drm_display_mode( const struct drm_connector_state *connector_state, const struct dc_stream_state *old_stream, int requested_bpc); +struct dc_stream_state * +create_stream_for_sink(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + const struct dm_connector_state *dm_state, + const struct dc_stream_state *old_stream, + int requested_bpc); 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 b3d16123402d..2d58021b48f3 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 @@ -3604,6 +3604,176 @@ static void dm_test_fill_stream_aspect_ratio(struct kunit *test) (int)ASPECT_RATIO_16_9); } +/* Tests for create_stream_for_sink() */ + +/* + * Build the inputs for create_stream_for_sink(). The connector is registered + * against a real kunit drm_device so that to_amdgpu_dm_connector() and the drm + * debug helpers resolve. The DC link carries a zeroed dc_context so that + * dc_create_stream_for_sink() can allocate and construct a stream. + * + * By default no dc_sink is attached, so create_stream_for_sink() builds a fake + * VIRTUAL sink. The VIRTUAL signal keeps the DSC, audio and DP/HDMI infoframe + * paths as no-ops, making the exercised behaviour deterministic. + */ +struct dm_test_stream_ctx { + struct drm_device *drm; + struct amdgpu_dm_connector *aconnector; + struct dc_context *dc_ctx; + struct dc_link *link; + struct dm_connector_state *dm_state; + struct drm_display_mode *mode; +}; + +static struct dm_test_stream_ctx *dm_test_stream_ctx_alloc(struct kunit *test) +{ + struct dm_test_stream_ctx *ctx; + struct device *dev; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(*ctx->drm), 0, + DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm); + + ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector); + KUNIT_ASSERT_EQ(test, + drmm_connector_init(ctx->drm, &ctx->aconnector->base, + &dm_test_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort, NULL), 0); + + ctx->dc_ctx = kunit_kzalloc(test, sizeof(*ctx->dc_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->dc_ctx); + + ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->link); + ctx->link->ctx = ctx->dc_ctx; + ctx->link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; + + ctx->aconnector->dc_link = ctx->link; + ctx->aconnector->dc_sink = NULL; + + ctx->dm_state = kunit_kzalloc(test, sizeof(*ctx->dm_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->dm_state); + ctx->dm_state->scaling = RMX_OFF; + + ctx->mode = kunit_kzalloc(test, sizeof(*ctx->mode), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->mode); + ctx->mode->hdisplay = 1920; + ctx->mode->vdisplay = 1080; + ctx->mode->clock = 148500; + + return ctx; +} + +/** + * dm_test_create_stream_fake_sink_success - Test a stream is built from a fake sink + * @test: The KUnit test context + */ +static void dm_test_create_stream_fake_sink_success(struct kunit *test) +{ + struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test); + struct dc_stream_state *stream; + + stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode, + ctx->dm_state, NULL, 8); + + KUNIT_ASSERT_NOT_NULL(test, stream); + dc_stream_release(stream); +} + +/** + * dm_test_create_stream_sets_dm_context - Test dm_stream_context points to aconnector + * @test: The KUnit test context + */ +static void dm_test_create_stream_sets_dm_context(struct kunit *test) +{ + struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test); + struct dc_stream_state *stream; + + stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode, + ctx->dm_state, NULL, 8); + + KUNIT_ASSERT_NOT_NULL(test, stream); + KUNIT_EXPECT_PTR_EQ(test, stream->dm_stream_context, ctx->aconnector); + dc_stream_release(stream); +} + +/** + * dm_test_create_stream_virtual_signal - Test the fake sink yields a VIRTUAL signal + * @test: The KUnit test context + */ +static void dm_test_create_stream_virtual_signal(struct kunit *test) +{ + struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test); + struct dc_stream_state *stream; + + stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode, + ctx->dm_state, NULL, 8); + + KUNIT_ASSERT_NOT_NULL(test, stream); + KUNIT_EXPECT_EQ(test, (int)stream->signal, (int)SIGNAL_TYPE_VIRTUAL); + dc_stream_release(stream); +} + +/** + * dm_test_create_stream_scaling_src - Test the source rect follows the mode + * @test: The KUnit test context + * + * With scaling off the full-screen source viewport matches the requested mode. + */ +static void dm_test_create_stream_scaling_src(struct kunit *test) +{ + struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test); + struct dc_stream_state *stream; + + stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode, + ctx->dm_state, NULL, 8); + + KUNIT_ASSERT_NOT_NULL(test, stream); + KUNIT_EXPECT_EQ(test, (int)stream->src.width, 1920); + KUNIT_EXPECT_EQ(test, (int)stream->src.height, 1080); + dc_stream_release(stream); +} + +/** + * dm_test_create_stream_existing_sink - Test the existing-sink retain path + * @test: The KUnit test context + * + * When the connector already has a dc_sink, create_stream_for_sink() reuses it + * instead of building a fake sink. + */ +static void dm_test_create_stream_existing_sink(struct kunit *test) +{ + struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test); + struct dc_sink_init_data sink_init = { 0 }; + struct dc_stream_state *stream; + struct dc_sink *sink; + + sink_init.link = ctx->link; + sink_init.sink_signal = SIGNAL_TYPE_VIRTUAL; + sink = dc_sink_create(&sink_init); + KUNIT_ASSERT_NOT_NULL(test, sink); + sink->sink_signal = SIGNAL_TYPE_VIRTUAL; + + ctx->aconnector->dc_sink = sink; + + stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode, + ctx->dm_state, NULL, 8); + + KUNIT_ASSERT_NOT_NULL(test, stream); + KUNIT_EXPECT_PTR_EQ(test, stream->sink, sink); + + dc_stream_release(stream); + dc_sink_release(sink); +} + static struct kunit_case amdgpu_dm_connector_tests[] = { /* get_subconnector_type */ KUNIT_CASE(dm_test_subconnector_type_none), @@ -3798,6 +3968,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = { KUNIT_CASE(dm_test_fill_stream_color_depth_requested_bpc), KUNIT_CASE(dm_test_fill_stream_content_type), KUNIT_CASE(dm_test_fill_stream_aspect_ratio), + /* create_stream_for_sink */ + KUNIT_CASE(dm_test_create_stream_fake_sink_success), + KUNIT_CASE(dm_test_create_stream_sets_dm_context), + KUNIT_CASE(dm_test_create_stream_virtual_signal), + KUNIT_CASE(dm_test_create_stream_scaling_src), + KUNIT_CASE(dm_test_create_stream_existing_sink), {} }; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c index 455fa5dd1420..436d033361ab 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c @@ -73,6 +73,7 @@ void dc_sink_release(struct dc_sink *sink) { kref_put(&sink->refcount, dc_sink_free); } +EXPORT_IF_KUNIT(dc_sink_release); struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params) { @@ -94,6 +95,7 @@ struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params) alloc_fail: return NULL; } +EXPORT_IF_KUNIT(dc_sink_create); /******************************************************************************* * Protected functions - visible only inside of DC (not visible in DM) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index ce045ef6347c..a32b6eb796f7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -24,6 +24,7 @@ */ #include "dm_services.h" +#include "dm_helpers.h" #include "basics/dc_common.h" #include "dc.h" #include "core_types.h" @@ -203,6 +204,7 @@ void dc_stream_release(struct dc_stream_state *stream) kref_put(&stream->refcount, dc_stream_free); } } +EXPORT_IF_KUNIT(dc_stream_release); struct dc_stream_state *dc_create_stream_for_sink( struct dc_sink *sink) -- 2.43.0
