[PATCH 42/59] drm/amd/display: Test IP block teardown and link emulation

Alex Hung <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
[WHAT]
Add KUnit tests for amdgpu_dm_early_fini() with audio never enabled, for
dm_sw_fini() releasing the DMUB software state, for dm_oem_i2c_hw_init()
when the resource pool has no OEM device, for dm_gpureset_commit_state()
with an empty DC state, and for amdgpu_dm_emulated_link_detect() rejecting
an unknown connector signal.

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 | 15 ++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 86 +++++++++++++++++++
 3 files changed, 100 insertions(+), 5 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 13afd787c1b4..2085625f8509 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -830,7 +830,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
 	return -EINVAL;
 }
 
-static int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block)
+STATIC_IFN_KUNIT int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 
@@ -838,6 +838,7 @@ static int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block)
 
 	return 0;
 }
+EXPORT_IF_KUNIT(amdgpu_dm_early_fini);
 
 static void amdgpu_dm_fini(struct amdgpu_device *adev)
 {
@@ -1078,7 +1079,7 @@ static int dm_sw_init(struct amdgpu_ip_block *ip_block)
 	return load_dmcu_fw(adev);
 }
 
-static int dm_sw_fini(struct amdgpu_ip_block *ip_block)
+STATIC_IFN_KUNIT int dm_sw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 	struct dal_allocation *da;
@@ -1108,6 +1109,7 @@ static int dm_sw_fini(struct amdgpu_ip_block *ip_block)
 
 	return 0;
 }
+EXPORT_IF_KUNIT(dm_sw_fini);
 
 
 static void amdgpu_dm_boot_time_crc_init(struct amdgpu_device *adev)
@@ -1302,7 +1304,7 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
 	drm_connector_list_iter_end(&iter);
 }
 
-static int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
+STATIC_IFN_KUNIT int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
 {
 	struct amdgpu_display_manager *dm = &adev->dm;
 	struct amdgpu_i2c_adapter *oem_i2c;
@@ -1328,6 +1330,7 @@ static int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
 
 	return 0;
 }
+EXPORT_IF_KUNIT(dm_oem_i2c_hw_init);
 
 /**
  * dm_hw_init() - Initialize DC device
@@ -1710,9 +1713,10 @@ void amdgpu_dm_emulated_link_detect(struct dc_link *link)
 		drm_err(dev, "Failed to read EDID\n");
 
 }
+EXPORT_IF_KUNIT(amdgpu_dm_emulated_link_detect);
 
-static void dm_gpureset_commit_state(struct dc_state *dc_state,
-				     struct amdgpu_display_manager *dm)
+STATIC_IFN_KUNIT void dm_gpureset_commit_state(struct dc_state *dc_state,
+					       struct amdgpu_display_manager *dm)
 {
 	struct {
 		struct dc_surface_update surface_updates[MAX_SURFACES];
@@ -1748,6 +1752,7 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state,
 					 bundle->surface_updates);
 	}
 }
+EXPORT_IF_KUNIT(dm_gpureset_commit_state);
 
 void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev,
 											   struct dc_sink *sink)
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 cec86779b959..35b8725a63af 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1205,6 +1205,10 @@ 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 amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block);
+int dm_sw_fini(struct amdgpu_ip_block *ip_block);
+int dm_oem_i2c_hw_init(struct amdgpu_device *adev);
+void dm_gpureset_commit_state(struct dc_state *dc_state, struct amdgpu_display_manager *dm);
 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 f5c054422346..27182f65e5c3 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
@@ -3094,6 +3094,86 @@ static void dm_test_acpi_phy_transition_interlock(struct kunit *test)
 	dm_acpi_process_phy_transition_interlock(NULL, params);
 }
 
+/**
+ * dm_test_early_fini_audio_disabled - Test early fini with audio never enabled
+ * @test: The KUnit test context
+ */
+static void dm_test_early_fini_audio_disabled(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct amdgpu_ip_block ip_block = { .adev = adev };
+
+	KUNIT_EXPECT_EQ(test, amdgpu_dm_early_fini(&ip_block), 0);
+}
+
+/**
+ * dm_test_sw_fini_releases_state - Test sw fini drops the DMUB software state
+ * @test: The KUnit test context
+ */
+static void dm_test_sw_fini_releases_state(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct amdgpu_ip_block ip_block = { .adev = adev };
+
+	INIT_LIST_HEAD(&adev->dm.da_list);
+	adev->dm.dmub_fb_info = kzalloc_obj(*adev->dm.dmub_fb_info);
+	KUNIT_ASSERT_NOT_NULL(test, adev->dm.dmub_fb_info);
+
+	KUNIT_EXPECT_EQ(test, dm_sw_fini(&ip_block), 0);
+	KUNIT_EXPECT_NULL(test, adev->dm.dmub_fb_info);
+}
+
+/**
+ * dm_test_oem_i2c_hw_init_no_device - Test no OEM I2C device leaves the bus unset
+ * @test: The KUnit test context
+ */
+static void dm_test_oem_i2c_hw_init_no_device(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct dc *dc = dm_kunit_alloc_dc_with_ctx(test);
+
+	dc->res_pool = kunit_kzalloc(test, sizeof(*dc->res_pool), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, dc->res_pool);
+	adev->dm.dc = dc;
+
+	KUNIT_EXPECT_EQ(test, dm_oem_i2c_hw_init(adev), 0);
+	KUNIT_EXPECT_NULL(test, adev->dm.oem_i2c);
+}
+
+/**
+ * dm_test_gpureset_commit_state_no_streams - Test an empty DC state programs nothing
+ * @test: The KUnit test context
+ */
+static void dm_test_gpureset_commit_state_no_streams(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct dc_state *context = dm_kunit_alloc_dc_state(test);
+
+	KUNIT_ASSERT_NOT_NULL(test, context);
+	adev->dm.ddev = &adev->ddev;
+
+	dm_gpureset_commit_state(context, &adev->dm);
+}
+
+/**
+ * dm_test_emulated_link_detect_bad_signal - Test an unknown connector signal is rejected
+ * @test: The KUnit test context
+ */
+static void dm_test_emulated_link_detect_bad_signal(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct dc_link *link = dm_kunit_alloc_link_with_ctx(test);
+
+	link->ctx->driver_context = adev;
+	link->type = dc_connection_single;
+	link->connector_signal = SIGNAL_TYPE_VIRTUAL;
+
+	amdgpu_dm_emulated_link_detect(link);
+
+	KUNIT_EXPECT_EQ(test, (int)link->type, (int)dc_connection_none);
+	KUNIT_EXPECT_NULL(test, link->local_sink);
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
 	/* Simple DM callbacks */
 	KUNIT_CASE(dm_test_wait_for_idle),
@@ -3248,6 +3328,12 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_trigger_timing_sync_streams),
 	/* dm_acpi_process_phy_transition_interlock */
 	KUNIT_CASE(dm_test_acpi_phy_transition_interlock),
+	/* IP block lifecycle helpers */
+	KUNIT_CASE(dm_test_early_fini_audio_disabled),
+	KUNIT_CASE(dm_test_sw_fini_releases_state),
+	KUNIT_CASE(dm_test_oem_i2c_hw_init_no_device),
+	KUNIT_CASE(dm_test_gpureset_commit_state_no_streams),
+	KUNIT_CASE(dm_test_emulated_link_detect_bad_signal),
 	{}
 };
 
-- 
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.