From: <IVAN.LIPSKI@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>,
Leo Li <sunpeng.li@amd.com>,
Aurabindo Pillai <aurabindo.pillai@amd.com>,
Roman Li <roman.li@amd.com>, Wayne Lin <wayne.lin@amd.com>,
Tom Chung <chiahsuan.chung@amd.com>,
"Fangzhi Zuo" <jerry.zuo@amd.com>,
Dan Wheeler <daniel.wheeler@amd.com>, Ray Wu <Ray.Wu@amd.com>,
Ivan Lipski <ivan.lipski@amd.com>, Alex Hung <alex.hung@amd.com>,
James Lin <PingLei.Lin@amd.com>,
Chenyu Chen <Chen-Yu.Chen@amd.com>
Subject: [PATCH 07/82] drm/amd/display: Test writeback connector
Date: Tue, 18 Aug 2026 16:14:59 -0400 [thread overview]
Message-ID: <20260818202139.4172592-8-IVAN.LIPSKI@amd.com> (raw)
In-Reply-To: <20260818202139.4172592-1-IVAN.LIPSKI@amd.com>
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for the writeback connector. The tests cover the
encoder atomic check (missing job, missing framebuffer, matching mode,
width, height and combined size mismatches, and an unsupported pixel
format), mode enumeration and its 3840x2160 bound, connector
initialization, and buffer object preparation and cleanup including
the reserve, fence slot, pin and GART allocation failure paths.
[HOW]
Add struct amdgpu_dm_wb_kunit_ops, a KUnit-only indirection table for
the buffer object calls that would otherwise need a live TTM device.
Tests install their own table to force error returns and to count
calls, which makes the failure and cleanup ordering paths reachable in
the UML test environment. The default table points at the existing
AMDGPU, TTM and DMA reservation functions, so no test-only wrapper is
introduced.
Route the affected calls through wb_* wrappers, so the KUnit build
dispatches through the table while non-KUnit builds call the same
functions directly.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
---
.../drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c | 72 +++-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h | 16 +
.../amdgpu_dm/tests/amdgpu_dm_wb_test.c | 330 ++++++++++++++++++
3 files changed, 405 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c
index a7594012a0b2e..6f91a992d43f8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c
@@ -41,6 +41,52 @@ static const u32 amdgpu_dm_wb_formats[] = {
DRM_FORMAT_XRGB2101010,
};
+#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+static const struct amdgpu_dm_wb_kunit_ops amdgpu_dm_wb_default_ops = {
+ .reserve = amdgpu_bo_reserve,
+ .reserve_fences = dma_resv_reserve_fences,
+ .pin = amdgpu_bo_pin,
+ .alloc_gart = amdgpu_ttm_alloc_gart,
+ .unreserve = amdgpu_bo_unreserve,
+ .gpu_offset = amdgpu_bo_gpu_offset,
+ .ref = amdgpu_bo_ref,
+ .unpin = amdgpu_bo_unpin,
+ .unref = amdgpu_bo_unref,
+};
+
+static const struct amdgpu_dm_wb_kunit_ops *amdgpu_dm_wb_ops =
+ &amdgpu_dm_wb_default_ops;
+
+void amdgpu_dm_wb_kunit_set_ops(const struct amdgpu_dm_wb_kunit_ops *ops)
+{
+ amdgpu_dm_wb_ops = ops ? ops : &amdgpu_dm_wb_default_ops;
+}
+EXPORT_IF_KUNIT(amdgpu_dm_wb_kunit_set_ops);
+
+#define wb_bo_reserve amdgpu_dm_wb_ops->reserve
+#define wb_dma_resv_reserve_fences amdgpu_dm_wb_ops->reserve_fences
+#define wb_bo_pin amdgpu_dm_wb_ops->pin
+#define wb_ttm_alloc_gart amdgpu_dm_wb_ops->alloc_gart
+#define wb_bo_unreserve amdgpu_dm_wb_ops->unreserve
+#define wb_bo_gpu_offset amdgpu_dm_wb_ops->gpu_offset
+#define wb_bo_ref amdgpu_dm_wb_ops->ref
+#define wb_bo_unpin amdgpu_dm_wb_ops->unpin
+#define wb_bo_unref amdgpu_dm_wb_ops->unref
+
+#else
+
+#define wb_bo_reserve amdgpu_bo_reserve
+#define wb_dma_resv_reserve_fences dma_resv_reserve_fences
+#define wb_bo_pin amdgpu_bo_pin
+#define wb_ttm_alloc_gart amdgpu_ttm_alloc_gart
+#define wb_bo_unreserve amdgpu_bo_unreserve
+#define wb_bo_gpu_offset amdgpu_bo_gpu_offset
+#define wb_bo_ref amdgpu_bo_ref
+#define wb_bo_unpin amdgpu_bo_unpin
+#define wb_bo_unref amdgpu_bo_unref
+
+#endif
+
STATIC_IFN_KUNIT int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
@@ -105,13 +151,13 @@ STATIC_IFN_KUNIT int amdgpu_dm_wb_prepare_job(struct drm_writeback_connector *wb
rbo = gem_to_amdgpu_bo(obj);
adev = amdgpu_ttm_adev(rbo->tbo.bdev);
- r = amdgpu_bo_reserve(rbo, true);
+ r = wb_bo_reserve(rbo, true);
if (r) {
drm_err(adev_to_drm(adev), "fail to reserve bo: %pe\n", ERR_PTR(r));
return r;
}
- r = dma_resv_reserve_fences(rbo->tbo.base.resv, TTM_NUM_MOVE_FENCES);
+ r = wb_dma_resv_reserve_fences(rbo->tbo.base.resv, TTM_NUM_MOVE_FENCES);
if (r) {
drm_err(adev_to_drm(adev), "reserving fence slot failed: %pe\n", ERR_PTR(r));
goto error_unlock;
@@ -120,32 +166,32 @@ STATIC_IFN_KUNIT int amdgpu_dm_wb_prepare_job(struct drm_writeback_connector *wb
domain = amdgpu_display_supported_domains(adev, rbo->flags);
rbo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
- r = amdgpu_bo_pin(rbo, domain);
+ r = wb_bo_pin(rbo, domain);
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to pin framebuffer: %pe\n", ERR_PTR(r));
goto error_unlock;
}
- r = amdgpu_ttm_alloc_gart(&rbo->tbo);
+ r = wb_ttm_alloc_gart(&rbo->tbo);
if (unlikely(r != 0)) {
DRM_ERROR("%p bind failed: %pe\n", rbo, ERR_PTR(r));
goto error_unpin;
}
- amdgpu_bo_unreserve(rbo);
+ wb_bo_unreserve(rbo);
- afb->address = amdgpu_bo_gpu_offset(rbo);
+ afb->address = wb_bo_gpu_offset(rbo);
- amdgpu_bo_ref(rbo);
+ wb_bo_ref(rbo);
return 0;
error_unpin:
- amdgpu_bo_unpin(rbo);
+ wb_bo_unpin(rbo);
error_unlock:
- amdgpu_bo_unreserve(rbo);
+ wb_bo_unreserve(rbo);
return r;
}
EXPORT_IF_KUNIT(amdgpu_dm_wb_prepare_job);
@@ -160,15 +206,15 @@ STATIC_IFN_KUNIT void amdgpu_dm_wb_cleanup_job(struct drm_writeback_connector *c
return;
rbo = gem_to_amdgpu_bo(job->fb->obj[0]);
- r = amdgpu_bo_reserve(rbo, false);
+ r = wb_bo_reserve(rbo, false);
if (unlikely(r)) {
DRM_ERROR("failed to reserve rbo before unpin: %pe\n", ERR_PTR(r));
return;
}
- amdgpu_bo_unpin(rbo);
- amdgpu_bo_unreserve(rbo);
- amdgpu_bo_unref(&rbo);
+ wb_bo_unpin(rbo);
+ wb_bo_unreserve(rbo);
+ wb_bo_unref(&rbo);
}
EXPORT_IF_KUNIT(amdgpu_dm_wb_cleanup_job);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h
index 5fd616bc43b5c..8d39a37e80f0a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h
@@ -31,6 +31,9 @@
struct amdgpu_display_manager;
struct amdgpu_dm_wb_connector;
+struct amdgpu_bo;
+struct dma_resv;
+struct ttm_buffer_object;
int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm,
struct amdgpu_dm_wb_connector *dm_wbcon,
@@ -40,6 +43,18 @@ int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm,
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
+struct amdgpu_dm_wb_kunit_ops {
+ int (*reserve)(struct amdgpu_bo *bo, bool interruptible);
+ int (*reserve_fences)(struct dma_resv *resv, unsigned int num_fences);
+ int (*pin)(struct amdgpu_bo *bo, u32 domain);
+ int (*alloc_gart)(struct ttm_buffer_object *tbo);
+ void (*unreserve)(struct amdgpu_bo *bo);
+ u64 (*gpu_offset)(struct amdgpu_bo *bo);
+ struct amdgpu_bo *(*ref)(struct amdgpu_bo *bo);
+ void (*unpin)(struct amdgpu_bo *bo);
+ void (*unref)(struct amdgpu_bo **bo);
+};
+
int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
@@ -48,6 +63,7 @@ int amdgpu_dm_wb_prepare_job(struct drm_writeback_connector *wb_connector,
struct drm_writeback_job *job);
void amdgpu_dm_wb_cleanup_job(struct drm_writeback_connector *connector,
struct drm_writeback_job *job);
+void amdgpu_dm_wb_kunit_set_ops(const struct amdgpu_dm_wb_kunit_ops *ops);
#endif
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c
index 3454cf3714148..03036f9063854 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c
@@ -23,6 +23,151 @@
#include "amdgpu_dm_wb.h"
#include "amdgpu_dm_kunit_test_helpers.h"
+struct dm_wb_test_bo {
+ struct amdgpu_bo bo;
+ struct amdgpu_device *adev;
+ int reserve_ret;
+ int reserve_fences_ret;
+ int pin_ret;
+ int alloc_gart_ret;
+ u64 gpu_offset;
+ unsigned int reserve_count;
+ unsigned int reserve_fences_count;
+ unsigned int pin_count;
+ unsigned int alloc_gart_count;
+ unsigned int unreserve_count;
+ unsigned int ref_count;
+ unsigned int unpin_count;
+ unsigned int unref_count;
+ unsigned int call_seq;
+ unsigned int reserve_seq;
+ unsigned int unreserve_seq;
+ unsigned int unpin_seq;
+ unsigned int unref_seq;
+};
+
+static struct dm_wb_test_bo *to_dm_wb_test_bo(struct amdgpu_bo *bo)
+{
+ return container_of(bo, struct dm_wb_test_bo, bo);
+}
+
+static int dm_wb_test_reserve(struct amdgpu_bo *bo, bool interruptible)
+{
+ struct dm_wb_test_bo *test_bo = to_dm_wb_test_bo(bo);
+
+ test_bo->reserve_count++;
+ test_bo->reserve_seq = ++test_bo->call_seq;
+ return test_bo->reserve_ret;
+}
+
+static int dm_wb_test_reserve_fences(struct dma_resv *resv,
+ unsigned int num_fences)
+{
+ struct dm_wb_test_bo *test_bo;
+
+ test_bo = container_of(resv, struct dm_wb_test_bo, bo.tbo.base._resv);
+ test_bo->reserve_fences_count++;
+ return test_bo->reserve_fences_ret;
+}
+
+static int dm_wb_test_pin(struct amdgpu_bo *bo, u32 domain)
+{
+ struct dm_wb_test_bo *test_bo = to_dm_wb_test_bo(bo);
+
+ test_bo->pin_count++;
+ return test_bo->pin_ret;
+}
+
+static int dm_wb_test_alloc_gart(struct ttm_buffer_object *tbo)
+{
+ struct dm_wb_test_bo *test_bo = to_dm_wb_test_bo(ttm_to_amdgpu_bo(tbo));
+
+ test_bo->alloc_gart_count++;
+ return test_bo->alloc_gart_ret;
+}
+
+static void dm_wb_test_unreserve(struct amdgpu_bo *bo)
+{
+ struct dm_wb_test_bo *test_bo = to_dm_wb_test_bo(bo);
+
+ test_bo->unreserve_count++;
+ test_bo->unreserve_seq = ++test_bo->call_seq;
+}
+
+static u64 dm_wb_test_gpu_offset(struct amdgpu_bo *bo)
+{
+ return to_dm_wb_test_bo(bo)->gpu_offset;
+}
+
+static struct amdgpu_bo *dm_wb_test_ref(struct amdgpu_bo *bo)
+{
+ to_dm_wb_test_bo(bo)->ref_count++;
+ return bo;
+}
+
+static void dm_wb_test_unpin(struct amdgpu_bo *bo)
+{
+ struct dm_wb_test_bo *test_bo = to_dm_wb_test_bo(bo);
+
+ test_bo->unpin_count++;
+ test_bo->unpin_seq = ++test_bo->call_seq;
+}
+
+static void dm_wb_test_unref(struct amdgpu_bo **bo)
+{
+ struct dm_wb_test_bo *test_bo = to_dm_wb_test_bo(*bo);
+
+ test_bo->unref_count++;
+ test_bo->unref_seq = ++test_bo->call_seq;
+ *bo = NULL;
+}
+
+static const struct amdgpu_dm_wb_kunit_ops dm_wb_test_ops = {
+ .reserve = dm_wb_test_reserve,
+ .reserve_fences = dm_wb_test_reserve_fences,
+ .pin = dm_wb_test_pin,
+ .alloc_gart = dm_wb_test_alloc_gart,
+ .unreserve = dm_wb_test_unreserve,
+ .gpu_offset = dm_wb_test_gpu_offset,
+ .ref = dm_wb_test_ref,
+ .unpin = dm_wb_test_unpin,
+ .unref = dm_wb_test_unref,
+};
+
+static void dm_wb_test_reset_ops(void *unused)
+{
+ amdgpu_dm_wb_kunit_set_ops(NULL);
+}
+
+static struct drm_writeback_job *dm_wb_test_alloc_job(struct kunit *test,
+ struct dm_wb_test_bo **test_bo)
+{
+ struct amdgpu_framebuffer *afb;
+ struct drm_writeback_job *job;
+
+ *test_bo = kunit_kzalloc(test, sizeof(**test_bo), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, *test_bo);
+ (*test_bo)->adev = dm_kunit_alloc_adev(test);
+ KUNIT_ASSERT_NOT_NULL(test, (*test_bo)->adev);
+
+ /* Let the driver's real BO and device lookups resolve to the fake BO. */
+ (*test_bo)->bo.tbo.bdev = &(*test_bo)->adev->mman.bdev;
+ (*test_bo)->bo.tbo.base.resv = &(*test_bo)->bo.tbo.base._resv;
+
+ afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, afb);
+ afb->base.obj[0] = &(*test_bo)->bo.tbo.base;
+
+ job = kunit_kzalloc(test, sizeof(*job), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, job);
+ job->fb = &afb->base;
+
+ amdgpu_dm_wb_kunit_set_ops(&dm_wb_test_ops);
+ KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_wb_test_reset_ops, NULL), 0);
+
+ return job;
+}
+
/* Helper functions */
@@ -387,6 +532,134 @@ static void dm_test_wb_prepare_job_no_fb(struct kunit *test)
KUNIT_EXPECT_EQ(test, ret, 0);
}
+/**
+ * dm_test_wb_prepare_job_success - Verify successful BO preparation
+ * @test: KUnit test context
+ *
+ * The writeback BO should be reserved, pinned, mapped into GART, referenced,
+ * and assigned its GPU address.
+ */
+static void dm_test_wb_prepare_job_success(struct kunit *test)
+{
+ struct dm_wb_test_bo *test_bo;
+ struct drm_writeback_job *job;
+ struct amdgpu_framebuffer *afb;
+ int ret;
+
+ job = dm_wb_test_alloc_job(test, &test_bo);
+ afb = to_amdgpu_framebuffer(job->fb);
+ test_bo->gpu_offset = 0x12340000;
+
+ ret = amdgpu_dm_wb_prepare_job(NULL, job);
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, test_bo->reserve_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->reserve_fences_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->pin_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->alloc_gart_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->unreserve_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->ref_count, 1);
+ KUNIT_EXPECT_EQ(test, afb->address, test_bo->gpu_offset);
+ KUNIT_EXPECT_TRUE(test, test_bo->bo.flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS);
+}
+
+/**
+ * dm_test_wb_prepare_job_reserve_failure - Verify reserve errors are returned
+ * @test: KUnit test context
+ *
+ * A BO reserve failure should stop preparation without attempting cleanup on
+ * a BO that was never reserved.
+ */
+static void dm_test_wb_prepare_job_reserve_failure(struct kunit *test)
+{
+ struct dm_wb_test_bo *test_bo;
+ struct drm_writeback_job *job;
+ int ret;
+
+ job = dm_wb_test_alloc_job(test, &test_bo);
+ test_bo->reserve_ret = -EBUSY;
+
+ ret = amdgpu_dm_wb_prepare_job(NULL, job);
+
+ KUNIT_EXPECT_EQ(test, ret, -EBUSY);
+ KUNIT_EXPECT_EQ(test, test_bo->reserve_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->reserve_fences_count, 0);
+ KUNIT_EXPECT_EQ(test, test_bo->unreserve_count, 0);
+}
+
+/**
+ * dm_test_wb_prepare_job_fence_failure - Verify fence reservation cleanup
+ * @test: KUnit test context
+ *
+ * Failure to reserve fence slots should release the BO reservation without
+ * attempting to pin the BO.
+ */
+static void dm_test_wb_prepare_job_fence_failure(struct kunit *test)
+{
+ struct dm_wb_test_bo *test_bo;
+ struct drm_writeback_job *job;
+ int ret;
+
+ job = dm_wb_test_alloc_job(test, &test_bo);
+ test_bo->reserve_fences_ret = -ENOMEM;
+
+ ret = amdgpu_dm_wb_prepare_job(NULL, job);
+
+ KUNIT_EXPECT_EQ(test, ret, -ENOMEM);
+ KUNIT_EXPECT_EQ(test, test_bo->reserve_fences_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->pin_count, 0);
+ KUNIT_EXPECT_EQ(test, test_bo->unreserve_count, 1);
+}
+
+/**
+ * dm_test_wb_prepare_job_pin_failure - Verify pin failure cleanup
+ * @test: KUnit test context
+ *
+ * A pin failure should release the BO reservation without trying to unpin a
+ * BO that was not successfully pinned.
+ */
+static void dm_test_wb_prepare_job_pin_failure(struct kunit *test)
+{
+ struct dm_wb_test_bo *test_bo;
+ struct drm_writeback_job *job;
+ int ret;
+
+ job = dm_wb_test_alloc_job(test, &test_bo);
+ test_bo->pin_ret = -EINVAL;
+
+ ret = amdgpu_dm_wb_prepare_job(NULL, job);
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+ KUNIT_EXPECT_EQ(test, test_bo->pin_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->alloc_gart_count, 0);
+ KUNIT_EXPECT_EQ(test, test_bo->unpin_count, 0);
+ KUNIT_EXPECT_EQ(test, test_bo->unreserve_count, 1);
+}
+
+/**
+ * dm_test_wb_prepare_job_gart_failure - Verify GART allocation cleanup
+ * @test: KUnit test context
+ *
+ * A GART allocation failure should unpin and unreserve the BO.
+ */
+static void dm_test_wb_prepare_job_gart_failure(struct kunit *test)
+{
+ struct dm_wb_test_bo *test_bo;
+ struct drm_writeback_job *job;
+ int ret;
+
+ job = dm_wb_test_alloc_job(test, &test_bo);
+ test_bo->alloc_gart_ret = -ENOMEM;
+
+ ret = amdgpu_dm_wb_prepare_job(NULL, job);
+
+ KUNIT_EXPECT_EQ(test, ret, -ENOMEM);
+ KUNIT_EXPECT_EQ(test, test_bo->alloc_gart_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->unpin_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->unreserve_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->ref_count, 0);
+}
+
/**
* dm_test_wb_cleanup_job_no_fb - Verify cleanup_job early return without a framebuffer
* @test: KUnit test context
@@ -406,6 +679,56 @@ static void dm_test_wb_cleanup_job_no_fb(struct kunit *test)
amdgpu_dm_wb_cleanup_job(NULL, job);
}
+/**
+ * dm_test_wb_cleanup_job_success - Verify successful BO cleanup
+ * @test: KUnit test context
+ *
+ * Cleanup should reserve, unpin, unreserve, and drop the writeback BO
+ * reference in order.
+ */
+static void dm_test_wb_cleanup_job_success(struct kunit *test)
+{
+ struct dm_wb_test_bo *test_bo;
+ struct drm_writeback_job *job;
+
+ job = dm_wb_test_alloc_job(test, &test_bo);
+
+ amdgpu_dm_wb_cleanup_job(NULL, job);
+
+ KUNIT_EXPECT_EQ(test, test_bo->reserve_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->unpin_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->unreserve_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->unref_count, 1);
+
+ /* The BO stays reserved across the unpin, and is released last. */
+ KUNIT_EXPECT_LT(test, test_bo->reserve_seq, test_bo->unpin_seq);
+ KUNIT_EXPECT_LT(test, test_bo->unpin_seq, test_bo->unreserve_seq);
+ KUNIT_EXPECT_LT(test, test_bo->unreserve_seq, test_bo->unref_seq);
+}
+
+/**
+ * dm_test_wb_cleanup_job_reserve_failure - Verify cleanup reserve failure
+ * @test: KUnit test context
+ *
+ * If cleanup cannot reserve the BO, it should leave the pin and reference
+ * untouched for a later cleanup attempt.
+ */
+static void dm_test_wb_cleanup_job_reserve_failure(struct kunit *test)
+{
+ struct dm_wb_test_bo *test_bo;
+ struct drm_writeback_job *job;
+
+ job = dm_wb_test_alloc_job(test, &test_bo);
+ test_bo->reserve_ret = -EBUSY;
+
+ amdgpu_dm_wb_cleanup_job(NULL, job);
+
+ KUNIT_EXPECT_EQ(test, test_bo->reserve_count, 1);
+ KUNIT_EXPECT_EQ(test, test_bo->unpin_count, 0);
+ KUNIT_EXPECT_EQ(test, test_bo->unreserve_count, 0);
+ KUNIT_EXPECT_EQ(test, test_bo->unref_count, 0);
+}
+
static struct kunit_case dm_wb_test_cases[] = {
/* amdgpu_dm_wb_encoder_atomic_check */
KUNIT_CASE(dm_test_wb_atomic_check_no_job),
@@ -422,7 +745,14 @@ static struct kunit_case dm_wb_test_cases[] = {
KUNIT_CASE(dm_test_wb_connector_init_success),
/* amdgpu_dm_wb_prepare_job / amdgpu_dm_wb_cleanup_job */
KUNIT_CASE(dm_test_wb_prepare_job_no_fb),
+ KUNIT_CASE(dm_test_wb_prepare_job_success),
+ KUNIT_CASE(dm_test_wb_prepare_job_reserve_failure),
+ KUNIT_CASE(dm_test_wb_prepare_job_fence_failure),
+ KUNIT_CASE(dm_test_wb_prepare_job_pin_failure),
+ KUNIT_CASE(dm_test_wb_prepare_job_gart_failure),
KUNIT_CASE(dm_test_wb_cleanup_job_no_fb),
+ KUNIT_CASE(dm_test_wb_cleanup_job_success),
+ KUNIT_CASE(dm_test_wb_cleanup_job_reserve_failure),
{}
};
--
2.43.0
next prev parent reply other threads:[~2026-08-18 20:22 UTC|newest]
Thread overview: 86+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-18 20:14 [PATCH 00/82] DC Patches August 17, 2026 IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 01/82] drm/amd/display: Fall back to overlay cursor on dcn4x when top plane doesn't fill CRTC IVAN.LIPSKI
2026-08-19 7:27 ` Michel Dänzer
2026-08-20 10:04 ` Timur Kristóf
2026-08-18 20:14 ` [PATCH 02/82] drm/amd/display: Fixes for HPO test regressions IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 03/82] drm/amd/display: Refactor DPP_SET_INPUT_TRANSFER_FUNC to drop pipe_ctx IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 04/82] drm/amd/display: Use fast update path for address-only plane flips IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 05/82] drm/amd/display: Split OPTC_PIPE_CONTROL_LOCK into smaller HWSS blocks IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 06/82] drm/amd/display: Fix DPREFCLK override when SMU isn't present or ready for DCN315 IVAN.LIPSKI
2026-08-18 20:14 ` IVAN.LIPSKI [this message]
2026-08-18 20:15 ` [PATCH 08/82] drm/amd/display: Test GPU memory allocation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 09/82] drm/amd/display: Cover MST path in encoder atomic_check IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 10/82] drm/amd/display: Cover amdgpu_dm_encoder_init IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 11/82] drm/amd/display: Cover MST-start failure in detect_mst IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 12/82] drm/amd/display: Cover amdgpu_dm_update_connector_after_detect IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 13/82] drm/amd/display: Cover HDMI infoframe/freesync timing paths IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 14/82] drm/amd/display: Clear HUBPREQ_DEBUG_DB on DCN6 IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 15/82] drm/amd/display: Disable alt-ch until dependencies are ready IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 16/82] drm/amd/display: Fix CalculateFlipSchedule Calculation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 17/82] drm/amd/display: Test EDID quirks and ACPI EDID read IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 18/82] drm/amd/display: Test execute_synaptics_rc_command failures IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 19/82] drm/amd/display: Test MST stream feature read failure IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 20/82] drm/amd/display: Test dm_helpers_submit_i2c_over_aux IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 21/82] drm/amd/display: Test GPU memory allocate and free helpers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 22/82] drm/amd/display: Test dm_helpers_dmub_set_config_sync IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 23/82] drm/amd/display: Test dm_helpers_is_dp_sink_present IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 24/82] drm/amd/display: Test dm_helpers_read_local_edid IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 25/82] drm/amd/display: Test dp_handle_test_pattern_request patterns IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 26/82] drm/amd/display: Test DMUB reg callbacks IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 27/82] drm/amd/display: Test VBIOS bounding box IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 28/82] drm/amd/display: Test dm_init_microcode IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 29/82] drm/amd/display: Test dm_dmub_sw_init IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 30/82] drm/amd/display: Add hook to disable alt-ch in PMO IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 31/82] drm/amd/display: Update alt-ch size calculations IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 32/82] drm/amd/display: Enable min dispclk ODM on DCN42 IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 33/82] drm/amd/display: Add amdgpu_dm_connector_poll KUnit tests IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 34/82] drm/amd/display: Cover hide_secondary_tile_from_userspace IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 35/82] drm/amd/display: Cover dm_validate_stream_and_context IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 36/82] drm/amd/display: Cover amdgpu_dm_create_validate_stream_for_sink IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 37/82] drm/amd/display: Cover amdgpu_dm_connector_mode_valid IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 38/82] drm/amd/display: Test MST sideband message ack path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 39/82] drm/amd/display: Test dm_dp_mst_get_modes without a remote EDID IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 40/82] drm/amd/display: Test dm_dp_mst_get_modes with " IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 41/82] drm/amd/display: Test dm_dp_mst_detect DPCD probe and unplug IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 42/82] drm/amd/display: Test MST connector register and unregister IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 43/82] drm/amd/display: Test dm_dp_mst_connector_destroy IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 44/82] drm/amd/display: Test plane state duplicate and destroy IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 45/82] drm/amd/display: Test modifier list de-duplication IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 46/82] drm/amd/display: Test GFX6-8 tiling info from modifiers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 47/82] drm/amd/display: Test GFX6-8 tile mode and tile split lookups IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 48/82] drm/amd/display: Test GFX6-8 modifier calculation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 49/82] drm/amd/display: Test GFX6-8 modifier list generation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 50/82] drm/amd/display: Test framebuffer prepare and cleanup IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 51/82] drm/amd/display: Test cursor update and async plane update IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 52/82] drm/amd/display: Remove RMCM tetrahedral cube from dc_plane_state IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 53/82] drm/amd/display: Cover mode_valid EDID mgmt path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 54/82] drm/amd/display: Cover amdgpu_dm_fill_hdr_info_packet IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 55/82] drm/amd/display: Cover amdgpu_dm_connector_atomic_check IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 56/82] drm/amd/display: Cover atomic_check modeset triggers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 57/82] drm/amd/display: Cover funcs_force valid EDID path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 58/82] drm/amd/display: Cover amdgpu_dm_connector_get_modes IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 59/82] drm/amd/display: Cover create_eml_sink valid EDID path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 60/82] drm/amd/display: Cover amdgpu_set_panel_orientation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 61/82] drm/amd/display: Refactor amdgpu_dm_irq_test IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 62/82] drm/amd/display: Test pageflip completion in the high IRQ handlers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 63/82] drm/amd/display: Test writeback handling in dm_crtc_high_irq IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 64/82] drm/amd/display: Test schedule_dc_vmin_vmax IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 65/82] drm/amd/display: Test handle_hpd_irq_helper detect and debounce exits IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 66/82] drm/amd/display: Test HPD RX, HPD init and DMUB callback branches IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 67/82] drm/amd/display: Test dm_dmub_outbox1_low_irq drain and work guards IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 68/82] drm/amd/display: Test amdgpu_dm_dce110_register_irq_handlers IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 69/82] drm/amd/display: Test amdgpu_dm_dcn10_register_irq_handlers IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 70/82] drm/amd/display: Fix mismatch number of OPP/DPP accounting IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 71/82] drm/amd/display: Cover amdgpu_dm_prune_primary_tile_modes IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 72/82] drm/amd/display: Cover add_fs_modes mode generation IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 73/82] drm/amd/display: Cover add_fs_modes illegal timing skip IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 74/82] drm/amd/display: Refactor hdmi_frl_status_polling_work for Kunit testing IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 75/82] drm/amd/display: Cover hdmi_frl_status_polling_work IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 76/82] drm/amd/display: Cover amdgpu_dm_i2c_xfer IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 77/82] drm/amd/display: Cover amdgpu_dm_create_i2c IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 78/82] drm/amd/display: Add passthrough visual confirm IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 79/82] drm/amd/display: Populate vblank_nom according to bounding box IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 80/82] drm/amd/display: Adjust vblank_nom policy for HW SDP tranmission reqs IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 81/82] drm/amd/display: Guard amdgpu_dm_irq_schedule_work against NULL irq_wq IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 82/82] drm/amd/display: Promote DC to 3.2.395 IVAN.LIPSKI
2026-08-24 13:46 ` [PATCH 00/82] DC Patches August 17, 2026 Wheeler, Daniel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260818202139.4172592-8-IVAN.LIPSKI@amd.com \
--to=ivan.lipski@amd.com \
--cc=Chen-Yu.Chen@amd.com \
--cc=PingLei.Lin@amd.com \
--cc=Ray.Wu@amd.com \
--cc=alex.hung@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=aurabindo.pillai@amd.com \
--cc=chiahsuan.chung@amd.com \
--cc=daniel.wheeler@amd.com \
--cc=harry.wentland@amd.com \
--cc=jerry.zuo@amd.com \
--cc=roman.li@amd.com \
--cc=sunpeng.li@amd.com \
--cc=wayne.lin@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox