summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlex Hung <alex.hung@amd.com>2026-08-11 17:08:06 -0600
committerAlex Deucher <alexander.deucher@amd.com>2026-08-25 18:32:57 -0400
commit3dcd57191e07a916618dca02e85643348f0165de (patch)
tree1f1ccf1dca559ff83c4eb07cd0d9d5bc3426870a /drivers
parentba495959a529de04e921036ca0e54372943107dd (diff)
downloadlinux-next-3dcd57191e07a916618dca02e85643348f0165de.tar.gz
linux-next-3dcd57191e07a916618dca02e85643348f0165de.zip
drm/amd/display: Test plane state duplicate and destroy
[WHAT] Add KUnit tests for amdgpu_dm_plane_drm_plane_duplicate_state() and amdgpu_dm_plane_drm_plane_destroy_state() covering the resource paths. Duplicating a state shares every color blob and takes an extra reference on the DC plane state, and destroying one drops a reference on each. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com> Signed-off-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Ivan Lipski <ivan.lipski@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c113
1 files changed, 113 insertions, 0 deletions
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 ba97092c7bb8..17789b3845b7 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
@@ -10,11 +10,14 @@
#include <drm/drm_blend.h>
#include "link_enc_cfg.h"
#include "amdgpu_dm_plane.h"
+#include "amdgpu_dm_kunit_test_helpers.h"
#include "amdgpu_rlc.h"
#include "gc/gc_11_0_0_offset.h"
#include "gc/gc_11_0_0_sh_mask.h"
#include <drm/amdgpu_drm.h>
+#include <drm/drm_mode_config.h>
#include <drm/drm_plane.h>
+#include <drm/drm_property.h>
struct dm_test_dcc_cap_ctx {
bool callback_ret;
@@ -3001,6 +3004,78 @@ static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
kfree(dup_state);
}
+/*
+ * Attach a blob to every color property of @state. Each blob starts with a
+ * single reference that the tested function is expected to drop or share.
+ */
+static void dm_test_attach_color_blobs(struct kunit *test, struct drm_device *dev,
+ struct dm_plane_state *state)
+{
+ struct drm_property_blob **blobs[] = {
+ &state->degamma_lut, &state->ctm, &state->lut3d,
+ &state->shaper_lut, &state->blend_lut,
+ };
+ u32 blob_data = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(blobs); i++) {
+ *blobs[i] = drm_property_create_blob(dev, sizeof(blob_data), &blob_data);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, *blobs[i]);
+ }
+}
+
+/**
+ * dm_test_plane_duplicate_state_copies_resources() - Verify blob and DC state sharing.
+ * @test: KUnit test context.
+ *
+ * Verify amdgpu_dm_plane_drm_plane_duplicate_state() shares the DC plane state
+ * and every color blob with the duplicate, taking an extra reference on each.
+ */
+static void dm_test_plane_duplicate_state_copies_resources(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dm_plane_state *old_state;
+ struct drm_plane_state *dup_base;
+ struct dm_plane_state *dup_state;
+ struct dc_plane_state *dc_plane_state;
+ struct drm_plane *plane;
+
+ KUNIT_ASSERT_EQ(test, drmm_mode_config_init(&adev->ddev), 0);
+
+ plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+ old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
+ dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, plane);
+ KUNIT_ASSERT_NOT_NULL(test, old_state);
+ KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
+
+ kref_init(&dc_plane_state->refcount);
+ old_state->dc_state = dc_plane_state;
+ dm_test_attach_color_blobs(test, &adev->ddev, old_state);
+ 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_PTR_EQ(test, dup_state->dc_state, dc_plane_state);
+ KUNIT_EXPECT_EQ(test, kref_read(&dc_plane_state->refcount), 2U);
+ KUNIT_EXPECT_PTR_EQ(test, dup_state->degamma_lut, old_state->degamma_lut);
+ KUNIT_EXPECT_PTR_EQ(test, dup_state->ctm, old_state->ctm);
+ KUNIT_EXPECT_PTR_EQ(test, dup_state->shaper_lut, old_state->shaper_lut);
+ KUNIT_EXPECT_PTR_EQ(test, dup_state->lut3d, old_state->lut3d);
+ KUNIT_EXPECT_PTR_EQ(test, dup_state->blend_lut, old_state->blend_lut);
+
+ /* Drops the duplicate's references; the originals are released below. */
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, dup_base);
+
+ drm_property_blob_put(old_state->degamma_lut);
+ drm_property_blob_put(old_state->ctm);
+ drm_property_blob_put(old_state->lut3d);
+ drm_property_blob_put(old_state->shaper_lut);
+ drm_property_blob_put(old_state->blend_lut);
+}
+
/**
* dm_test_plane_destroy_state_minimal() - Verify destroy of a minimal state.
* @test: KUnit test context.
@@ -3024,6 +3099,42 @@ static void dm_test_plane_destroy_state_minimal(struct kunit *test)
amdgpu_dm_plane_drm_plane_destroy_state(plane, &dm_plane_state->base);
}
+/**
+ * dm_test_plane_destroy_state_releases_resources() - Verify blob and DC state release.
+ * @test: KUnit test context.
+ *
+ * Verify amdgpu_dm_plane_drm_plane_destroy_state() drops a reference on every
+ * attached color blob and on the DC plane state.
+ */
+static void dm_test_plane_destroy_state_releases_resources(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dm_plane_state *dm_plane_state;
+ struct dc_plane_state *dc_plane_state;
+ struct drm_plane *plane;
+
+ KUNIT_ASSERT_EQ(test, drmm_mode_config_init(&adev->ddev), 0);
+
+ plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+ dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, plane);
+ KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
+
+ /* 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);
+
+ /* Hold an extra reference so the release does not free KUnit memory. */
+ kref_init(&dc_plane_state->refcount);
+ kref_get(&dc_plane_state->refcount);
+ dm_plane_state->dc_state = dc_plane_state;
+ dm_test_attach_color_blobs(test, &adev->ddev, dm_plane_state);
+
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, &dm_plane_state->base);
+
+ KUNIT_EXPECT_EQ(test, kref_read(&dc_plane_state->refcount), 1U);
+}
+
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),
@@ -3102,8 +3213,10 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_plane_reset_initializes_state),
/* amdgpu_dm_plane_drm_plane_duplicate_state() */
KUNIT_CASE(dm_test_plane_duplicate_state_copies_fields),
+ KUNIT_CASE(dm_test_plane_duplicate_state_copies_resources),
/* amdgpu_dm_plane_drm_plane_destroy_state() */
KUNIT_CASE(dm_test_plane_destroy_state_minimal),
+ KUNIT_CASE(dm_test_plane_destroy_state_releases_resources),
/* amdgpu_dm_plane_add_modifier() */
KUNIT_CASE(dm_test_add_modifier_appends_value),
KUNIT_CASE(dm_test_add_modifier_grows_capacity),