[PATCH 33/59] drm/amd/display: Test vblank event arming
Alex Hung <[email protected]>
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
[WHAT] Add KUnit tests for dm_arm_vblank_event() and dm_arm_vblank_event_pre_programming() covering missing events, inactive CRTCs, page-flip and cursor updates, and vblank reference acquisition. [HOW] Use one pending-event fixture. Initialize DRM vblank state only for the pre-programming tests and release every acquired reference. Assisted-by: Copilot:Claude-Opus-5 GPT-5.6-Sol Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Hung <[email protected]> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 18 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 + .../display/amdgpu_dm/tests/amdgpu_dm_test.c | 185 ++++++++++++++++++ 3 files changed, 201 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 08f2cc7fec68..1eb2f0973aac 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3723,10 +3723,10 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm, } } -static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc, - struct dm_crtc_state *acrtc_state, - bool pflip_update, - bool cursor_update) +STATIC_IFN_KUNIT void dm_arm_vblank_event(struct amdgpu_crtc *acrtc, + struct dm_crtc_state *acrtc_state, + bool pflip_update, + bool cursor_update) { assert_spin_locked(&acrtc->base.dev->event_lock); @@ -3749,6 +3749,7 @@ static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc, acrtc->base.state->event = NULL; } } +EXPORT_IF_KUNIT(dm_arm_vblank_event); /** * dm_arm_vblank_event_pre_programming - Prepare for programming @@ -3761,10 +3762,10 @@ static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc, * be programmed. Do this before programming so the HW is not in any * idle-optimized state (such as PSR). */ -static void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc, - struct dm_crtc_state *acrtc_state, - bool pflip_update, - bool cursor_update) +STATIC_IFN_KUNIT void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc, + struct dm_crtc_state *acrtc_state, + bool pflip_update, + bool cursor_update) { assert_spin_locked(&acrtc->base.dev->event_lock); @@ -3774,6 +3775,7 @@ static void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc, if (pflip_update || cursor_update) drm_crtc_vblank_get(&acrtc->base); } +EXPORT_IF_KUNIT(dm_arm_vblank_event_pre_programming); static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, struct drm_device *dev, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index ed2341b387d9..e4b67a0b98c3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -1176,6 +1176,12 @@ void amdgpu_dm_commit_cursors(struct drm_atomic_commit *state); void amdgpu_dm_update_cursor(struct drm_plane *plane, struct drm_plane_state *old_plane_state, struct dc_stream_update *update); +void dm_arm_vblank_event(struct amdgpu_crtc *acrtc, + struct dm_crtc_state *acrtc_state, + bool pflip_update, bool cursor_update); +void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc, + struct dm_crtc_state *acrtc_state, + bool pflip_update, bool cursor_update); int add_affected_mst_dsc_crtcs(struct drm_atomic_commit *state, struct drm_crtc *crtc); int dm_plane_layer_index_cmp(const void *a, const void *b); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c index a2671ad90bfe..648db4a58509 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c @@ -1552,6 +1552,183 @@ static void dm_test_update_cursor_disables_stream(struct kunit *test) KUNIT_EXPECT_NULL(test, update->cursor_attributes); } +/* Tests for dm_arm_vblank_event() */ + +struct dm_test_vblank_ctx { + struct amdgpu_device *adev; + struct amdgpu_crtc *acrtc; + struct dm_crtc_state *acrtc_state; + struct drm_pending_vblank_event *event; +}; + +/* + * A CRTC with one active plane and a pending vblank event. There is no + * initialised vblank, so drm_crtc_vblank_get() fails, which the function under + * test ignores. + */ +static struct dm_test_vblank_ctx *dm_test_vblank_ctx_alloc(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + ctx->adev = dm_kunit_alloc_adev(test); + ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc); + ctx->acrtc_state = kunit_kzalloc(test, sizeof(*ctx->acrtc_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc_state); + ctx->event = kunit_kzalloc(test, sizeof(*ctx->event), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->event); + + ctx->acrtc->base.dev = &ctx->adev->ddev; + ctx->acrtc->base.state = &ctx->acrtc_state->base; + ctx->acrtc_state->base.event = ctx->event; + ctx->acrtc_state->active_planes = 1; + + return ctx; +} + +static void dm_test_arm_vblank(struct dm_test_vblank_ctx *ctx, bool pflip_update, + bool cursor_update) +{ + unsigned long flags; + + spin_lock_irqsave(&ctx->adev->ddev.event_lock, flags); + dm_arm_vblank_event(ctx->acrtc, ctx->acrtc_state, pflip_update, + cursor_update); + spin_unlock_irqrestore(&ctx->adev->ddev.event_lock, flags); +} + +static void dm_test_arm_vblank_pre_programming(struct dm_test_vblank_ctx *ctx, + bool pflip_update, bool cursor_update) +{ + struct dm_crtc_state *state = ctx->acrtc_state; + struct amdgpu_crtc *acrtc = ctx->acrtc; + unsigned long flags; + + spin_lock_irqsave(&ctx->adev->ddev.event_lock, flags); + dm_arm_vblank_event_pre_programming(acrtc, state, pflip_update, cursor_update); + spin_unlock_irqrestore(&ctx->adev->ddev.event_lock, flags); +} + +/** + * dm_test_arm_vblank_pre_programming_no_event - Test missing event takes no reference + * @test: The KUnit test context + */ +static void dm_test_arm_vblank_pre_programming_no_event(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx = dm_test_vblank_ctx_alloc(test); + struct drm_vblank_crtc *vblank; + + KUNIT_ASSERT_EQ(test, drm_vblank_init(&ctx->adev->ddev, 1), 0); + vblank = drm_crtc_vblank_crtc(&ctx->acrtc->base); + ctx->acrtc_state->base.event = NULL; + + dm_test_arm_vblank_pre_programming(ctx, true, false); + + KUNIT_EXPECT_EQ(test, atomic_read(&vblank->refcount), 0); +} + +/** + * dm_test_arm_vblank_pre_programming_no_planes - Test inactive CRTC takes no reference + * @test: The KUnit test context + */ +static void dm_test_arm_vblank_pre_programming_no_planes(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx = dm_test_vblank_ctx_alloc(test); + struct drm_vblank_crtc *vblank; + + KUNIT_ASSERT_EQ(test, drm_vblank_init(&ctx->adev->ddev, 1), 0); + vblank = drm_crtc_vblank_crtc(&ctx->acrtc->base); + ctx->acrtc_state->active_planes = 0; + + dm_test_arm_vblank_pre_programming(ctx, false, true); + + KUNIT_EXPECT_EQ(test, atomic_read(&vblank->refcount), 0); +} + +/** + * dm_test_arm_vblank_pre_programming_update - Test an update takes a vblank reference + * @test: The KUnit test context + */ +static void dm_test_arm_vblank_pre_programming_update(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx = dm_test_vblank_ctx_alloc(test); + struct drm_vblank_crtc *vblank; + + KUNIT_ASSERT_EQ(test, drm_vblank_init(&ctx->adev->ddev, 1), 0); + vblank = drm_crtc_vblank_crtc(&ctx->acrtc->base); + + dm_test_arm_vblank_pre_programming(ctx, true, false); + + KUNIT_EXPECT_EQ(test, atomic_read(&vblank->refcount), 1); + drm_crtc_vblank_put(&ctx->acrtc->base); +} + +/** + * dm_test_arm_vblank_event_no_event - Test a commit without an event is a no-op + * @test: The KUnit test context + */ +static void dm_test_arm_vblank_event_no_event(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx = dm_test_vblank_ctx_alloc(test); + + ctx->acrtc_state->base.event = NULL; + + dm_test_arm_vblank(ctx, true, false); + + KUNIT_EXPECT_NULL(test, ctx->acrtc->event); +} + +/** + * dm_test_arm_vblank_event_no_active_planes - Test an event is left armed without planes + * @test: The KUnit test context + */ +static void dm_test_arm_vblank_event_no_active_planes(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx = dm_test_vblank_ctx_alloc(test); + + ctx->acrtc_state->active_planes = 0; + + dm_test_arm_vblank(ctx, false, true); + + KUNIT_EXPECT_NULL(test, ctx->acrtc->event); + KUNIT_EXPECT_PTR_EQ(test, ctx->acrtc_state->base.event, ctx->event); +} + +/** + * dm_test_arm_vblank_event_pflip - Test a page flip arms the flip ISR + * @test: The KUnit test context + */ +static void dm_test_arm_vblank_event_pflip(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx = dm_test_vblank_ctx_alloc(test); + + dm_test_arm_vblank(ctx, true, false); + + KUNIT_EXPECT_PTR_EQ(test, ctx->acrtc->event, ctx->event); + KUNIT_EXPECT_NULL(test, ctx->acrtc_state->base.event); + KUNIT_EXPECT_EQ(test, (int)ctx->acrtc->pflip_status, + (int)AMDGPU_FLIP_SUBMITTED); +} + +/** + * dm_test_arm_vblank_event_cursor - Test a cursor update consumes the event + * @test: The KUnit test context + */ +static void dm_test_arm_vblank_event_cursor(struct kunit *test) +{ + struct dm_test_vblank_ctx *ctx = dm_test_vblank_ctx_alloc(test); + + dm_test_arm_vblank(ctx, false, true); + + KUNIT_EXPECT_PTR_EQ(test, ctx->acrtc->event, ctx->event); + KUNIT_EXPECT_NULL(test, ctx->acrtc_state->base.event); + KUNIT_EXPECT_EQ(test, (int)ctx->acrtc->pflip_status, + (int)AMDGPU_FLIP_NONE); +} + static struct kunit_case amdgpu_dm_tests[] = { /* Simple DM callbacks */ KUNIT_CASE(dm_test_wait_for_idle), @@ -1637,6 +1814,14 @@ static struct kunit_case amdgpu_dm_tests[] = { KUNIT_CASE(dm_test_commit_cursors_updates_cursor), KUNIT_CASE(dm_test_update_cursor_no_framebuffer), KUNIT_CASE(dm_test_update_cursor_disables_stream), + /* dm_arm_vblank_event */ + KUNIT_CASE(dm_test_arm_vblank_event_no_event), + KUNIT_CASE(dm_test_arm_vblank_event_no_active_planes), + KUNIT_CASE(dm_test_arm_vblank_event_pflip), + KUNIT_CASE(dm_test_arm_vblank_event_cursor), + KUNIT_CASE(dm_test_arm_vblank_pre_programming_no_event), + KUNIT_CASE(dm_test_arm_vblank_pre_programming_no_planes), + KUNIT_CASE(dm_test_arm_vblank_pre_programming_update), {} }; -- 2.43.0