From: Alex Hung <[email protected]>
[WHAT]
Add KUnit tests for the two writeback vblanks in dm_crtc_high_irq(): the
first disables frame capture and marks wb_frame_done, the second signals
the out fence and clears the pending state.
[HOW]
dc_stream_fc_disable_writeback() dereferences dc->res_pool before its
NULL-stream check, so supply a dc with a fake IRQ service. The
completion test queues a bare drm_writeback_job and holds a vblank
reference for the completion's drm_crtc_vblank_put().
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Ivan Lipski <[email protected]>
---
.../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 97 +++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
index 0bf46e856f5a2..4cb52093987f3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
@@ -10,6 +10,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
+#include <drm/drm_writeback.h>
#include "dc.h"
#include "inc/core_types.h"
@@ -3524,6 +3525,100 @@ static void dm_test_crtc_high_irq_vrr_ai_no_stream(struct kunit *test)
KUNIT_EXPECT_EQ(test, acrtc->pflip_status, AMDGPU_FLIP_NONE);
}
+/**
+ * dm_test_crtc_high_irq_writeback_disables - Test first writeback vblank
+ * @test: The KUnit test context
+ *
+ * The first vblank after a writeback is armed must disable frame capture so the
+ * hardware cannot overwrite the buffer, and defer signalling completion to the
+ * next vblank by marking wb_frame_done.
+ */
+static void dm_test_crtc_high_irq_writeback_disables(struct kunit *test)
+{
+ struct drm_writeback_connector *wb_conn;
+ struct common_irq_params params = { 0 };
+ struct amdgpu_device *adev;
+ struct amdgpu_crtc *acrtc;
+ struct dc *dc;
+
+ adev = dm_kunit_alloc_adev(test);
+ KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0);
+
+ /* dc_stream_fc_disable_writeback() dereferences dc->res_pool. */
+ dc = dm_test_alloc_dc_with_irq_service(test,
+ &dm_test_irq_service_funcs_dcn10);
+ adev->dm.dc = dc;
+ /* Pre-AI family returns right after CRC handling. */
+ adev->family = AMDGPU_FAMILY_SI;
+
+ acrtc = dm_test_add_crtc(test, adev);
+
+ wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb_conn);
+ acrtc->wb_conn = wb_conn;
+ acrtc->wb_pending = true;
+
+ params.adev = adev;
+ params.irq_src = (enum dc_irq_source)IRQ_TYPE_VBLANK;
+
+ dm_crtc_high_irq(¶ms);
+
+ KUNIT_EXPECT_TRUE(test, acrtc->wb_frame_done);
+ KUNIT_EXPECT_TRUE(test, acrtc->wb_pending);
+}
+
+/**
+ * dm_test_crtc_high_irq_writeback_completes - Test second writeback vblank
+ * @test: The KUnit test context
+ *
+ * Once wb_frame_done is set the DMA has had a full frame period to flush, so
+ * the next vblank must signal the writeback out fence and clear the pending
+ * state.
+ */
+static void dm_test_crtc_high_irq_writeback_completes(struct kunit *test)
+{
+ struct drm_writeback_connector *wb_conn;
+ struct common_irq_params params = { 0 };
+ struct drm_writeback_job *job;
+ struct amdgpu_device *adev;
+ struct amdgpu_crtc *acrtc;
+
+ adev = dm_kunit_alloc_adev(test);
+ KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0);
+ adev->family = AMDGPU_FAMILY_SI;
+
+ acrtc = dm_test_add_crtc(test, adev);
+
+ wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb_conn);
+ spin_lock_init(&wb_conn->job_lock);
+ INIT_LIST_HEAD(&wb_conn->job_queue);
+
+ /*
+ * The job carries no framebuffer or fence, so the deferred DRM cleanup
+ * work only kfree()s it; it needs nothing from this test.
+ */
+ job = kzalloc_obj(*job, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, job);
+ list_add_tail(&job->list_entry, &wb_conn->job_queue);
+
+ acrtc->wb_conn = wb_conn;
+ acrtc->wb_pending = true;
+ acrtc->wb_frame_done = true;
+
+ /* Balance the drm_crtc_vblank_put() done on completion. */
+ adev->ddev.vblank[0].enabled = true;
+ KUNIT_ASSERT_EQ(test, drm_crtc_vblank_get(&acrtc->base), 0);
+
+ params.adev = adev;
+ params.irq_src = (enum dc_irq_source)IRQ_TYPE_VBLANK;
+
+ dm_crtc_high_irq(¶ms);
+
+ KUNIT_EXPECT_FALSE(test, acrtc->wb_pending);
+ KUNIT_EXPECT_FALSE(test, acrtc->wb_frame_done);
+}
+
/* Tests for dm_handle_hpd_work() */
/**
@@ -4154,6 +4249,8 @@ static struct kunit_case amdgpu_dm_irq_tests[] = {
KUNIT_CASE(dm_test_crtc_high_irq_no_crtc),
KUNIT_CASE(dm_test_crtc_high_irq_vrr_pre_ai),
KUNIT_CASE(dm_test_crtc_high_irq_vrr_ai_no_stream),
+ KUNIT_CASE(dm_test_crtc_high_irq_writeback_disables),
+ KUNIT_CASE(dm_test_crtc_high_irq_writeback_completes),
/* dm_handle_hpd_work */
KUNIT_CASE(dm_test_handle_hpd_work_out_of_range),
/* dm_dmub_outbox1_low_irq */
--
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.