[WHAT]
Add KUnit tests for amdgpu_dm_crtc_mem_type_changed() covering an empty
plane mask, a plane missing one of its states, framebuffers in the same
memory domain, and a framebuffer migrated between domains.

[HOW]
Back the framebuffers with fake buffer objects carrying a TTM resource, so
get_mem_type() resolves a memory domain without a live TTM device.

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 |   7 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   3 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 138 ++++++++++++++++++
 3 files changed, 145 insertions(+), 3 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 4650b5f09c08..70f50fa17366 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6044,9 +6044,9 @@ STATIC_IFN_KUNIT int add_affected_mst_dsc_crtcs(struct 
drm_atomic_commit *state,
 }
 EXPORT_IF_KUNIT(add_affected_mst_dsc_crtcs);
 
-static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
-                                           struct drm_atomic_commit *state,
-                                           struct drm_crtc_state *crtc_state)
+STATIC_IFN_KUNIT bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
+                                                     struct drm_atomic_commit 
*state,
+                                                     struct drm_crtc_state 
*crtc_state)
 {
        struct drm_plane *plane;
        struct drm_plane_state *new_plane_state, *old_plane_state;
@@ -6065,6 +6065,7 @@ static bool amdgpu_dm_crtc_mem_type_changed(struct 
drm_device *dev,
 
        return false;
 }
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_mem_type_changed);
 
 /**
  * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM.
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 c22266f534e3..ca19977cf788 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1186,6 +1186,9 @@ void dm_arm_vblank_event_pre_programming(struct 
amdgpu_crtc *acrtc,
                                         bool pflip_update, bool cursor_update);
 int add_affected_mst_dsc_crtcs(struct drm_atomic_commit *state,
                               struct drm_crtc *crtc);
+bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
+                                    struct drm_atomic_commit *state,
+                                    struct drm_crtc_state *crtc_state);
 int dm_plane_layer_index_cmp(const void *a, const void *b);
 int fill_plane_color_attributes(const struct drm_plane_state *plane_state,
                                const enum surface_pixel_format format,
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 845638fed223..0c57b3cc47fe 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
@@ -1804,6 +1804,139 @@ static void dm_test_update_pflip_irq_state_dce(struct 
kunit *test)
                        (int)AMDGPU_IRQ_STATE_DISABLE);
 }
 
+/* Tests for amdgpu_dm_crtc_mem_type_changed() */
+
+struct dm_test_mem_type_ctx {
+       struct amdgpu_device *adev;
+       struct drm_atomic_commit *state;
+       struct drm_crtc_state *crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *old_plane_state;
+       struct drm_plane_state *new_plane_state;
+};
+
+/*
+ * Register a single plane on the CRTC's plane mask. get_mem_type() walks
+ * fb->obj[0] back to an amdgpu_bo, so the framebuffers are backed by fake
+ * buffer objects with a TTM resource instead of a live TTM device.
+ */
+static struct drm_framebuffer *dm_test_alloc_fb(struct kunit *test,
+                                               u32 mem_type)
+{
+       struct drm_framebuffer *fb;
+       struct ttm_resource *res;
+       struct amdgpu_bo *abo;
+
+       fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, fb);
+       abo = kunit_kzalloc(test, sizeof(*abo), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, abo);
+       res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, res);
+
+       res->mem_type = mem_type;
+       abo->tbo.resource = res;
+       fb->obj[0] = &abo->tbo.base;
+
+       return fb;
+}
+
+static struct dm_test_mem_type_ctx *dm_test_mem_type_ctx_alloc(struct kunit 
*test)
+{
+       struct dm_test_mem_type_ctx *ctx;
+
+       ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+       ctx->adev = dm_kunit_alloc_adev(test);
+       ctx->state = dm_test_alloc_commit(test, ctx->adev);
+       ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+       ctx->plane = drm_kunit_helper_create_primary_plane(test, 
&ctx->adev->ddev,
+                                                          NULL, NULL, NULL, 0, 
NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->plane);
+       ctx->old_plane_state = kunit_kzalloc(test, 
sizeof(*ctx->old_plane_state),
+                                            GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->old_plane_state);
+       ctx->new_plane_state = kunit_kzalloc(test, 
sizeof(*ctx->new_plane_state),
+                                            GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->new_plane_state);
+       ctx->state->planes = kunit_kcalloc(test, ctx->plane->index + 1,
+                                          sizeof(*ctx->state->planes), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->state->planes);
+
+       ctx->crtc_state->plane_mask = drm_plane_mask(ctx->plane);
+       ctx->state->planes[ctx->plane->index].ptr = ctx->plane;
+
+       return ctx;
+}
+
+/**
+ * dm_test_mem_type_changed_no_planes - Test an empty plane mask reports no 
change
+ * @test: The KUnit test context
+ */
+static void dm_test_mem_type_changed_no_planes(struct kunit *test)
+{
+       struct dm_test_mem_type_ctx *ctx = dm_test_mem_type_ctx_alloc(test);
+
+       ctx->crtc_state->plane_mask = 0;
+
+       KUNIT_EXPECT_FALSE(test, 
amdgpu_dm_crtc_mem_type_changed(&ctx->adev->ddev,
+                                                               ctx->state,
+                                                               
ctx->crtc_state));
+}
+
+/**
+ * dm_test_mem_type_changed_missing_state - Test a plane without both states 
is skipped
+ * @test: The KUnit test context
+ */
+static void dm_test_mem_type_changed_missing_state(struct kunit *test)
+{
+       struct dm_test_mem_type_ctx *ctx = dm_test_mem_type_ctx_alloc(test);
+
+       ctx->state->planes[ctx->plane->index].new_state = ctx->new_plane_state;
+
+       KUNIT_EXPECT_FALSE(test, 
amdgpu_dm_crtc_mem_type_changed(&ctx->adev->ddev,
+                                                               ctx->state,
+                                                               
ctx->crtc_state));
+}
+
+/**
+ * dm_test_mem_type_changed_same_domain - Test identical memory domains report 
no change
+ * @test: The KUnit test context
+ */
+static void dm_test_mem_type_changed_same_domain(struct kunit *test)
+{
+       struct dm_test_mem_type_ctx *ctx = dm_test_mem_type_ctx_alloc(test);
+
+       ctx->old_plane_state->fb = dm_test_alloc_fb(test, TTM_PL_VRAM);
+       ctx->new_plane_state->fb = dm_test_alloc_fb(test, TTM_PL_VRAM);
+       ctx->state->planes[ctx->plane->index].old_state = ctx->old_plane_state;
+       ctx->state->planes[ctx->plane->index].new_state = ctx->new_plane_state;
+
+       KUNIT_EXPECT_FALSE(test, 
amdgpu_dm_crtc_mem_type_changed(&ctx->adev->ddev,
+                                                               ctx->state,
+                                                               
ctx->crtc_state));
+}
+
+/**
+ * dm_test_mem_type_changed_different_domain - Test a domain migration is 
detected
+ * @test: The KUnit test context
+ */
+static void dm_test_mem_type_changed_different_domain(struct kunit *test)
+{
+       struct dm_test_mem_type_ctx *ctx = dm_test_mem_type_ctx_alloc(test);
+
+       ctx->old_plane_state->fb = dm_test_alloc_fb(test, TTM_PL_TT);
+       ctx->new_plane_state->fb = dm_test_alloc_fb(test, TTM_PL_VRAM);
+       ctx->state->planes[ctx->plane->index].old_state = ctx->old_plane_state;
+       ctx->state->planes[ctx->plane->index].new_state = ctx->new_plane_state;
+
+       KUNIT_EXPECT_TRUE(test, 
amdgpu_dm_crtc_mem_type_changed(&ctx->adev->ddev,
+                                                              ctx->state,
+                                                              
ctx->crtc_state));
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
        /* Simple DM callbacks */
        KUNIT_CASE(dm_test_wait_for_idle),
@@ -1900,6 +2033,11 @@ static struct kunit_case amdgpu_dm_tests[] = {
        /* dm_update_pflip_irq_state */
        KUNIT_CASE(dm_test_update_pflip_irq_state_dcn),
        KUNIT_CASE(dm_test_update_pflip_irq_state_dce),
+       /* amdgpu_dm_crtc_mem_type_changed */
+       KUNIT_CASE(dm_test_mem_type_changed_no_planes),
+       KUNIT_CASE(dm_test_mem_type_changed_missing_state),
+       KUNIT_CASE(dm_test_mem_type_changed_same_domain),
+       KUNIT_CASE(dm_test_mem_type_changed_different_domain),
        {}
 };
 
-- 
2.43.0

Reply via email to