[WHAT]
Add KUnit tests for do_aquire_global_lock() covering a device without
CRTCs, a CRTC with no pending commit, and a CRTC whose commit has already
completed.

[HOW]
Pre-signal the commit completions so the waits return immediately. The
extra reference the loop takes is released again, so the commit never
reaches zero and stays test-managed.

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 |   5 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   2 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 101 ++++++++++++++++++
 3 files changed, 106 insertions(+), 2 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 5b69794acc58..72962c1c63e3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -5311,8 +5311,8 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_commit *state)
  * Grabs all modesetting locks to serialize against any blocking commits,
  * Waits for completion of all non blocking commits.
  */
-static int do_aquire_global_lock(struct drm_device *dev,
-                                struct drm_atomic_commit *state)
+STATIC_IFN_KUNIT int do_aquire_global_lock(struct drm_device *dev,
+                                          struct drm_atomic_commit *state)
 {
        struct drm_crtc *crtc;
        struct drm_crtc_commit *commit;
@@ -5357,6 +5357,7 @@ static int do_aquire_global_lock(struct drm_device *dev,
 
        return ret < 0 ? ret : 0;
 }
+EXPORT_IF_KUNIT(do_aquire_global_lock);
 
 static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
                         struct drm_atomic_commit *state,
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 ed3210be7ab8..cec86779b959 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1203,6 +1203,8 @@ bool amdgpu_dm_crtc_mem_type_changed(struct drm_device 
*dev,
                                     struct drm_crtc_state *crtc_state);
 void amdgpu_dm_dump_links_and_sinks(struct amdgpu_device *adev);
 void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state);
+int do_aquire_global_lock(struct drm_device *dev,
+                         struct drm_atomic_commit *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 de2f2f8af230..97ff91dd7e0f 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
@@ -2942,6 +2942,104 @@ static void dm_test_update_hdcp_unchanged(struct kunit 
*test)
                                                  
DRM_MODE_CONNECTOR_DisplayPort));
 }
 
+/*
+ * Run do_aquire_global_lock() with a fresh acquire context, releasing the 
locks
+ * it leaves held on @state->acquire_ctx.
+ */
+static int dm_test_run_global_lock(struct kunit *test,
+                                  struct amdgpu_device *adev)
+{
+       struct drm_atomic_commit *state = dm_test_alloc_commit(test, adev);
+       struct drm_modeset_acquire_ctx acquire_ctx;
+       int ret;
+
+       drm_modeset_acquire_init(&acquire_ctx, 0);
+       state->acquire_ctx = &acquire_ctx;
+
+       ret = do_aquire_global_lock(&adev->ddev, state);
+
+       drm_modeset_drop_locks(&acquire_ctx);
+       drm_modeset_acquire_fini(&acquire_ctx);
+
+       return ret;
+}
+
+/**
+ * dm_test_aquire_global_lock_no_crtc - Test the global lock is taken without 
CRTCs
+ * @test: The KUnit test context
+ */
+static void dm_test_aquire_global_lock_no_crtc(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       KUNIT_EXPECT_EQ(test, dm_test_run_global_lock(test, adev), 0);
+}
+
+/*
+ * A CRTC registered on @adev, needed to walk the per-CRTC commit loop.
+ */
+static struct drm_crtc *dm_test_alloc_crtc(struct kunit *test,
+                                          struct amdgpu_device *adev)
+{
+       struct drm_plane *primary;
+       struct drm_crtc *crtc;
+
+       primary = drm_kunit_helper_create_primary_plane(test, &adev->ddev, NULL,
+                                                       NULL, NULL, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+       crtc = drm_kunit_helper_create_crtc(test, &adev->ddev, primary, NULL,
+                                           NULL, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+       return crtc;
+}
+
+/**
+ * dm_test_aquire_global_lock_no_commit - Test a CRTC without a pending commit
+ * @test: The KUnit test context
+ */
+static void dm_test_aquire_global_lock_no_commit(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       dm_test_alloc_crtc(test, adev);
+
+       KUNIT_EXPECT_EQ(test, dm_test_run_global_lock(test, adev), 0);
+}
+
+/**
+ * dm_test_aquire_global_lock_waits_commit - Test a completed commit is waited 
on
+ * @test: The KUnit test context
+ */
+static void dm_test_aquire_global_lock_waits_commit(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       struct drm_crtc_commit *commit;
+       struct drm_crtc *crtc;
+       int ret;
+
+       crtc = dm_test_alloc_crtc(test, adev);
+       commit = kunit_kzalloc(test, sizeof(*commit), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, commit);
+
+       /*
+        * The extra reference taken by the loop is dropped again, so the commit
+        * never reaches zero and stays KUnit-managed.
+        */
+       kref_init(&commit->ref);
+       init_completion(&commit->hw_done);
+       init_completion(&commit->flip_done);
+       complete_all(&commit->hw_done);
+       complete_all(&commit->flip_done);
+       list_add_tail(&commit->commit_entry, &crtc->commit_list);
+
+       ret = dm_test_run_global_lock(test, adev);
+
+       list_del(&commit->commit_entry);
+
+       KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
        /* Simple DM callbacks */
        KUNIT_CASE(dm_test_wait_for_idle),
@@ -3088,6 +3186,9 @@ static struct kunit_case amdgpu_dm_tests[] = {
        KUNIT_CASE(dm_test_update_hdcp_no_workqueue),
        KUNIT_CASE(dm_test_update_hdcp_writeback_skipped),
        KUNIT_CASE(dm_test_update_hdcp_unchanged),
+       KUNIT_CASE(dm_test_aquire_global_lock_no_crtc),
+       KUNIT_CASE(dm_test_aquire_global_lock_no_commit),
+       KUNIT_CASE(dm_test_aquire_global_lock_waits_commit),
        {}
 };
 
-- 
2.43.0

Reply via email to