From: Alex Hung <[email protected]> [WHAT] Add KUnit tests for amdgpu_dm_plane_atomic_async_check(), amdgpu_dm_plane_atomic_check(), amdgpu_dm_plane_panic_flush() and the DRM plane reset, duplicate-state and destroy-state hooks.
Add the dm_test_init_atomic_check_state() helper and plane reset vtable used by the new tests. Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5 Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Hung <[email protected]> Signed-off-by: George Zhang <[email protected]> --- .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 25 +- .../amd/display/amdgpu_dm/amdgpu_dm_plane.h | 9 + .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 457 ++++++++++++++++++ 3 files changed, 482 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 204b4641f07d..cc0a8e8b1ff5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1254,8 +1254,8 @@ int amdgpu_dm_plane_fill_dc_scaling_info(struct amdgpu_device *adev, } EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_dc_scaling_info); -static int amdgpu_dm_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) +STATIC_IFN_KUNIT int amdgpu_dm_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); @@ -1300,9 +1300,10 @@ static int amdgpu_dm_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_atomic_check); -static int amdgpu_dm_plane_atomic_async_check(struct drm_plane *plane, - struct drm_atomic_state *state, bool flip) +STATIC_IFN_KUNIT int amdgpu_dm_plane_atomic_async_check(struct drm_plane *plane, + struct drm_atomic_state *state, bool flip) { struct drm_crtc_state *new_crtc_state; struct drm_plane_state *new_plane_state; @@ -1324,6 +1325,7 @@ static int amdgpu_dm_plane_atomic_async_check(struct drm_plane *plane, return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_atomic_async_check); int amdgpu_dm_plane_get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc, struct dc_cursor_position *position) @@ -1483,7 +1485,7 @@ static void amdgpu_dm_plane_atomic_async_update(struct drm_plane *plane, amdgpu_dm_plane_handle_cursor_update(plane, old_state); } -static void amdgpu_dm_plane_panic_flush(struct drm_plane *plane) +STATIC_IFN_KUNIT void amdgpu_dm_plane_panic_flush(struct drm_plane *plane) { struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane->state); struct drm_framebuffer *fb = plane->state->fb; @@ -1496,6 +1498,7 @@ static void amdgpu_dm_plane_panic_flush(struct drm_plane *plane) dc_plane_force_dcc_and_tiling_disable(dc_plane_state, fb->modifier ? true : false); } +EXPORT_IF_KUNIT(amdgpu_dm_plane_panic_flush); static const struct drm_plane_helper_funcs dm_plane_helper_funcs = { .prepare_fb = amdgpu_dm_plane_helper_prepare_fb, @@ -1515,7 +1518,7 @@ static const struct drm_plane_helper_funcs dm_primary_plane_helper_funcs = { .panic_flush = amdgpu_dm_plane_panic_flush, }; -static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane) +STATIC_IFN_KUNIT void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane) { struct dm_plane_state *amdgpu_state; @@ -1532,8 +1535,10 @@ static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane) amdgpu_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; amdgpu_state->blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_drm_plane_reset); -static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane) +STATIC_IFN_KUNIT struct drm_plane_state * +amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane) { struct dm_plane_state *dm_plane_state, *old_dm_plane_state; @@ -1572,6 +1577,7 @@ static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct return &dm_plane_state->base; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_drm_plane_duplicate_state); STATIC_IFN_KUNIT bool amdgpu_dm_plane_format_mod_supported(struct drm_plane *plane, uint32_t format, @@ -1636,8 +1642,8 @@ STATIC_IFN_KUNIT bool amdgpu_dm_plane_format_mod_supported(struct drm_plane *pla } EXPORT_IF_KUNIT(amdgpu_dm_plane_format_mod_supported); -static void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) +STATIC_IFN_KUNIT void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) { struct dm_plane_state *dm_plane_state = to_dm_plane_state(state); @@ -1657,6 +1663,7 @@ static void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane, drm_atomic_helper_plane_destroy_state(plane, state); } +EXPORT_IF_KUNIT(amdgpu_dm_plane_drm_plane_destroy_state); #ifdef AMD_PRIVATE_COLOR static void diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h index 911fb2d73e22..be82e371bc08 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h @@ -115,5 +115,14 @@ void amdgpu_dm_plane_get_min_max_dc_plane_scaling(struct drm_device *dev, struct drm_framebuffer *fb, int *min_downscale, int *max_upscale); +int amdgpu_dm_plane_atomic_async_check(struct drm_plane *plane, + struct drm_atomic_state *state, bool flip); +int amdgpu_dm_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state); +void amdgpu_dm_plane_panic_flush(struct drm_plane *plane); +void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane); +struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane); +void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); #endif #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index f36c5c139554..eb15de64aa78 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -2726,6 +2726,446 @@ static void dm_test_format_mod_supported_d_swizzle_reject(struct kunit *test) listed_mod)); } +/** + * dm_test_atomic_async_check_rejects() - Verify async check rejections. + * @test: KUnit test context. + * + * Verify if async flip on non-overlay planes and async cursor update on + * non-cursor planes are rejected. + */ +static void dm_test_atomic_async_check_rejects(struct kunit *test) +{ + struct drm_plane *plane; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + + plane->type = DRM_PLANE_TYPE_PRIMARY; + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_atomic_async_check(plane, NULL, true), + -EINVAL); + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_atomic_async_check(plane, NULL, false), + -EINVAL); +} + +/** + * dm_test_atomic_async_check_overlay_cursor() - Verify overlay cursor rejection. + * @test: KUnit test context. + * + * Verify if async cursor updates are rejected while the CRTC is using an + * overlay cursor mode. + */ +static void dm_test_atomic_async_check_overlay_cursor(struct kunit *test) +{ + struct drm_atomic_state *state; + struct __drm_planes_state *planes; + struct __drm_crtcs_state *crtcs; + struct drm_plane *plane; + struct drm_plane_state *plane_state; + struct drm_crtc *crtc; + struct dm_crtc_state *dm_crtc_state; + + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + planes = kunit_kzalloc(test, sizeof(*planes), GFP_KERNEL); + crtcs = kunit_kzalloc(test, sizeof(*crtcs), GFP_KERNEL); + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + plane_state = kunit_kzalloc(test, sizeof(*plane_state), GFP_KERNEL); + crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); + dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, planes); + KUNIT_ASSERT_NOT_NULL(test, crtcs); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, plane_state); + KUNIT_ASSERT_NOT_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); + + plane->type = DRM_PLANE_TYPE_CURSOR; + plane->index = 0; + crtc->index = 0; + plane_state->crtc = crtc; + dm_crtc_state->cursor_mode = DM_CURSOR_OVERLAY_MODE; + state->planes = planes; + state->crtcs = crtcs; + state->planes[0].new_state = plane_state; + state->crtcs[0].new_state = &dm_crtc_state->base; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_atomic_async_check(plane, state, false), + -EINVAL); + + dm_crtc_state->cursor_mode = DM_CURSOR_NATIVE_MODE; + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_atomic_async_check(plane, state, false), + 0); +} + +static struct amdgpu_device *dm_test_init_atomic_check_state(struct kunit *test, + struct drm_atomic_state **state, + struct drm_plane **plane, + struct dm_plane_state **dm_plane_state, + struct drm_crtc_state **new_crtc_state, + struct drm_framebuffer **fb) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct __drm_planes_state *planes; + struct __drm_crtcs_state *crtcs; + struct dc_plane_state *dc_plane_state; + struct drm_crtc *crtc; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + *state = kunit_kzalloc(test, sizeof(**state), GFP_KERNEL); + planes = kunit_kzalloc(test, sizeof(*planes), GFP_KERNEL); + crtcs = kunit_kzalloc(test, sizeof(*crtcs), GFP_KERNEL); + *plane = kunit_kzalloc(test, sizeof(**plane), GFP_KERNEL); + *dm_plane_state = kunit_kzalloc(test, sizeof(**dm_plane_state), GFP_KERNEL); + dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL); + crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); + *new_crtc_state = kunit_kzalloc(test, sizeof(**new_crtc_state), GFP_KERNEL); + *fb = kunit_kzalloc(test, sizeof(**fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, *state); + KUNIT_ASSERT_NOT_NULL(test, planes); + KUNIT_ASSERT_NOT_NULL(test, crtcs); + KUNIT_ASSERT_NOT_NULL(test, *plane); + KUNIT_ASSERT_NOT_NULL(test, *dm_plane_state); + KUNIT_ASSERT_NOT_NULL(test, dc_plane_state); + KUNIT_ASSERT_NOT_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, *new_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, *fb); + + adev->dm.dc = dc; + dc->caps.planes[0].max_upscale_factor.argb8888 = 1000; + dc->caps.planes[0].max_downscale_factor.argb8888 = 1000; + dc->caps.planes[0].max_upscale_factor.nv12 = 1000; + dc->caps.planes[0].max_downscale_factor.nv12 = 1000; + + (*plane)->dev = &adev->ddev; + (*plane)->index = 0; + (*plane)->type = DRM_PLANE_TYPE_OVERLAY; + (*plane)->name = "kunit-plane"; + crtc->dev = &adev->ddev; + crtc->index = 0; + (*fb)->width = 100; + (*fb)->height = 100; + (*fb)->format = drm_format_info(DRM_FORMAT_XRGB8888); + KUNIT_ASSERT_NOT_NULL(test, (*fb)->format); + + (*dm_plane_state)->base.plane = *plane; + (*dm_plane_state)->base.state = *state; + (*dm_plane_state)->base.crtc = crtc; + (*dm_plane_state)->base.fb = *fb; + (*dm_plane_state)->base.src_w = 100 << 16; + (*dm_plane_state)->base.src_h = 100 << 16; + (*dm_plane_state)->base.crtc_w = 100; + (*dm_plane_state)->base.crtc_h = 100; + (*dm_plane_state)->dc_state = dc_plane_state; + + (*new_crtc_state)->crtc = crtc; + (*new_crtc_state)->enable = true; + (*new_crtc_state)->mode.crtc_hdisplay = 1920; + (*new_crtc_state)->mode.crtc_vdisplay = 1080; + + (*state)->planes = planes; + (*state)->crtcs = crtcs; + (*state)->planes[0].new_state = &(*dm_plane_state)->base; + (*state)->crtcs[0].new_state = *new_crtc_state; + + return adev; +} + +/** + * dm_test_atomic_check_no_dc_state() - Verify missing DC plane state succeeds. + * @test: KUnit test context. + * + * Verify if atomic_check exits before deeper validation when the DM plane state + * has no DC plane state attached. + */ +static void dm_test_atomic_check_no_dc_state(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_atomic_state *state; + struct __drm_planes_state *planes; + struct drm_plane *plane; + struct dm_plane_state *dm_plane_state; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + planes = kunit_kzalloc(test, sizeof(*planes), GFP_KERNEL); + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + dm_plane_state = kunit_kzalloc(test, sizeof(*dm_plane_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, planes); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, dm_plane_state); + + plane->dev = &adev->ddev; + plane->index = 0; + dm_plane_state->base.plane = plane; + state->planes = planes; + state->planes[0].new_state = &dm_plane_state->base; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), 0); +} + +/** + * dm_test_atomic_check_missing_crtc_state() - Verify missing CRTC state fails. + * @test: KUnit test context. + * + * Verify if atomic_check rejects a plane with DC state when the atomic CRTC + * state is absent. + */ +static void dm_test_atomic_check_missing_crtc_state(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_atomic_state *state; + struct __drm_planes_state *planes; + struct __drm_crtcs_state *crtcs; + struct drm_plane *plane; + struct dm_plane_state *dm_plane_state; + struct dc_plane_state *dc_plane_state; + struct drm_crtc *crtc; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + planes = kunit_kzalloc(test, sizeof(*planes), GFP_KERNEL); + crtcs = kunit_kzalloc(test, sizeof(*crtcs), GFP_KERNEL); + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + dm_plane_state = kunit_kzalloc(test, sizeof(*dm_plane_state), GFP_KERNEL); + dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL); + crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, planes); + KUNIT_ASSERT_NOT_NULL(test, crtcs); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, dm_plane_state); + KUNIT_ASSERT_NOT_NULL(test, dc_plane_state); + KUNIT_ASSERT_NOT_NULL(test, crtc); + + plane->dev = &adev->ddev; + plane->index = 0; + crtc->index = 0; + dm_plane_state->base.plane = plane; + dm_plane_state->base.crtc = crtc; + dm_plane_state->dc_state = dc_plane_state; + state->planes = planes; + state->crtcs = crtcs; + state->planes[0].new_state = &dm_plane_state->base; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), -EINVAL); +} + +/** + * dm_test_atomic_check_helper_failure() - Verify helper-check failures return. + * @test: KUnit test context. + * + * Verify if atomic_check returns before DC validation when the DRM helper state + * validation rejects the plane. + */ +static void dm_test_atomic_check_helper_failure(struct kunit *test) +{ + struct drm_atomic_state *state; + struct drm_plane *plane; + struct dm_plane_state *dm_plane_state; + struct drm_crtc_state *new_crtc_state; + struct drm_framebuffer *fb; + + dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state, + &new_crtc_state, &fb); + dm_plane_state->base.crtc_w = 10; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), -EINVAL); +} + +/** + * dm_test_atomic_check_color_pipeline_conflict() - Verify color conflict rejection. + * @test: KUnit test context. + * + * Verify if atomic_check rejects use of both plane COLOR_PIPELINE and CRTC + * DEGAMMA_LUT before DC validation. + */ +static void dm_test_atomic_check_color_pipeline_conflict(struct kunit *test) +{ + struct drm_atomic_state *state; + struct drm_plane *plane; + struct dm_plane_state *dm_plane_state; + struct drm_crtc_state *new_crtc_state; + struct drm_framebuffer *fb; + void *color_pipeline; + void *degamma_lut; + + dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state, + &new_crtc_state, &fb); + color_pipeline = kunit_kzalloc(test, 1, GFP_KERNEL); + degamma_lut = kunit_kzalloc(test, 1, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, color_pipeline); + KUNIT_ASSERT_NOT_NULL(test, degamma_lut); + + dm_plane_state->base.color_pipeline = color_pipeline; + new_crtc_state->degamma_lut = degamma_lut; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), -EINVAL); +} + +/** + * dm_test_atomic_check_scaling_failure() - Verify scaling-info failures return. + * @test: KUnit test context. + * + * Verify if atomic_check returns the scaling-info error before DC validation. + */ +static void dm_test_atomic_check_scaling_failure(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_atomic_state *state; + struct drm_plane *plane; + struct dm_plane_state *dm_plane_state; + struct drm_crtc_state *new_crtc_state; + struct drm_framebuffer *fb; + + adev = dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state, + &new_crtc_state, &fb); + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); + fb->width = 200; + fb->format = drm_format_info(DRM_FORMAT_NV12); + KUNIT_ASSERT_NOT_NULL(test, fb->format); + dm_plane_state->base.src_x = 1 << 16; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), -EINVAL); +} + +/** + * dm_test_panic_flush_no_dc_state() - Verify panic flush exits without DC state. + * @test: KUnit test context. + * + * Verify if panic_flush returns without dereferencing DC state when the current + * plane state has no DC plane state attached. + */ +static void dm_test_panic_flush_no_dc_state(struct kunit *test) +{ + struct drm_plane *plane; + struct dm_plane_state *dm_plane_state; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + dm_plane_state = kunit_kzalloc(test, sizeof(*dm_plane_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, dm_plane_state); + + plane->state = &dm_plane_state->base; + + amdgpu_dm_plane_panic_flush(plane); +} + +static const struct drm_plane_funcs dm_test_plane_reset_funcs = { + .atomic_destroy_state = amdgpu_dm_plane_drm_plane_destroy_state, +}; + +/** + * dm_test_plane_reset_initializes_state() - Verify reset installs default state. + * @test: KUnit test context. + * + * Verify amdgpu_dm_plane_drm_plane_reset() destroys the existing plane state, + * allocates a fresh dm_plane_state, and initializes the AMD-specific transfer + * function and HDR multiplier defaults. + */ +static void dm_test_plane_reset_initializes_state(struct kunit *test) +{ + struct dm_plane_state *old_state; + struct dm_plane_state *new_state; + struct drm_plane *plane; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + + /* + * Provide an existing state plus a funcs table so reset exercises the + * destroy-existing-state path. The destroy hook frees this state, so it + * must be a plain (non-KUnit-managed) allocation. + */ + old_state = kzalloc(sizeof(*old_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, old_state); + plane->funcs = &dm_test_plane_reset_funcs; + plane->state = &old_state->base; + + amdgpu_dm_plane_drm_plane_reset(plane); + + KUNIT_ASSERT_NOT_NULL(test, plane->state); + new_state = to_dm_plane_state(plane->state); + KUNIT_EXPECT_EQ(test, new_state->degamma_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT); + KUNIT_EXPECT_EQ(test, new_state->hdr_mult, AMDGPU_HDR_MULT_DEFAULT); + KUNIT_EXPECT_EQ(test, new_state->shaper_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT); + KUNIT_EXPECT_EQ(test, new_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT); + + kfree(new_state); +} + +/** + * dm_test_plane_duplicate_state_copies_fields() - Verify state duplication. + * @test: KUnit test context. + * + * Verify amdgpu_dm_plane_drm_plane_duplicate_state() allocates a new state and + * copies the transfer-function and HDR-multiplier fields from the current + * plane state when no DC state or color blob is attached. + */ +static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test) +{ + struct dm_plane_state *old_state; + struct drm_plane_state *dup_base; + struct dm_plane_state *dup_state; + struct drm_plane *plane; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, old_state); + + old_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_PQ_EOTF; + old_state->hdr_mult = 0x123456789ULL; + old_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_IDENTITY; + old_state->blend_tf = AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF; + plane->state = &old_state->base; + + dup_base = amdgpu_dm_plane_drm_plane_duplicate_state(plane); + KUNIT_ASSERT_NOT_NULL(test, dup_base); + + dup_state = to_dm_plane_state(dup_base); + KUNIT_EXPECT_EQ(test, dup_state->degamma_tf, AMDGPU_TRANSFER_FUNCTION_PQ_EOTF); + KUNIT_EXPECT_EQ(test, dup_state->hdr_mult, 0x123456789ULL); + KUNIT_EXPECT_EQ(test, dup_state->shaper_tf, AMDGPU_TRANSFER_FUNCTION_IDENTITY); + KUNIT_EXPECT_EQ(test, dup_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF); + KUNIT_EXPECT_NULL(test, dup_state->dc_state); + + kfree(dup_state); +} + +/** + * dm_test_plane_destroy_state_minimal() - Verify destroy of a minimal state. + * @test: KUnit test context. + * + * Verify amdgpu_dm_plane_drm_plane_destroy_state() tears down a plane state + * that has no color blobs or DC plane state attached without dereferencing + * NULL resources. + */ +static void dm_test_plane_destroy_state_minimal(struct kunit *test) +{ + struct dm_plane_state *dm_plane_state; + struct drm_plane *plane; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + + /* destroy_state frees the state itself, so use a plain allocation. */ + dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm_plane_state); + + amdgpu_dm_plane_drm_plane_destroy_state(plane, &dm_plane_state->base); +} + static struct kunit_case amdgpu_dm_plane_test_cases[] = { /* amdgpu_dm_plane_is_video_format() */ KUNIT_CASE(dm_test_plane_is_video_format_known_video), @@ -2790,6 +3230,23 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_helper_check_state_small_viewport_height), KUNIT_CASE(dm_test_helper_check_state_bottom_clipped_height), KUNIT_CASE(dm_test_helper_check_state_scaling_caps), + /* amdgpu_dm_plane_atomic_async_check() */ + KUNIT_CASE(dm_test_atomic_async_check_rejects), + KUNIT_CASE(dm_test_atomic_async_check_overlay_cursor), + /* amdgpu_dm_plane_atomic_check() */ + KUNIT_CASE(dm_test_atomic_check_no_dc_state), + KUNIT_CASE(dm_test_atomic_check_missing_crtc_state), + KUNIT_CASE(dm_test_atomic_check_helper_failure), + KUNIT_CASE(dm_test_atomic_check_color_pipeline_conflict), + KUNIT_CASE(dm_test_atomic_check_scaling_failure), + /* amdgpu_dm_plane_panic_flush() */ + KUNIT_CASE(dm_test_panic_flush_no_dc_state), + /* amdgpu_dm_plane_drm_plane_reset() */ + KUNIT_CASE(dm_test_plane_reset_initializes_state), + /* amdgpu_dm_plane_drm_plane_duplicate_state() */ + KUNIT_CASE(dm_test_plane_duplicate_state_copies_fields), + /* amdgpu_dm_plane_drm_plane_destroy_state() */ + KUNIT_CASE(dm_test_plane_destroy_state_minimal), /* amdgpu_dm_plane_add_modifier() */ KUNIT_CASE(dm_test_add_modifier_appends_value), KUNIT_CASE(dm_test_add_modifier_grows_capacity), -- 2.55.0
