[PATCH 05/70] drm/amd/display: add dm_dmub_hw_init KUnit coverage

Wayne Lin <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Alex Hung <[email protected]>

[WHAT]
Add KUnit coverage for dm_dmub_hw_init() beyond the existing
early-return cases. Introduce reusable fake-DMUB fixtures (fake
dmub_srv/firmware, DMCU/ABM stubs, and adev builders) so the init path
runs without real register access, TTM allocation, or firmware loading.

New cases cover the fake-DMUB success path, unsupported hardware, BSS
data copy, hardware-init failure, auto-load timeout, the APU/DPIA DCN3.5
params, the DCN3.1.x sanity-check ranges, and DMCU/ABM initialization.

Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Wayne Lin <[email protected]>
---
 .../amdgpu_dm/tests/amdgpu_dm_dmub_test.c     | 315 ++++++++++++++++++
 1 file changed, 315 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
index bf90ccfbf431..4c01f7919170 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
@@ -6,14 +6,20 @@
  */
 
 #include <kunit/test.h>
+#include <linux/firmware.h>
 
 #include "dc.h"
 #include "dc/inc/core_types.h"
+#include "dc/inc/hw/dmcu.h"
+#include "dc/inc/hw/abm.h"
 #include "amdgpu_mode.h"
 #include "amdgpu_dm.h"
+#include "dm_services.h"
 #include "dmub/dmub_srv.h"
 #include "amdgpu_dm_dmub.h"
 
+#define DM_TEST_FW_SIZE	512
+
 /* Tests for dm_register_dmub_notify_callback() */
 
 static void dummy_callback(struct amdgpu_device *adev,
@@ -21,6 +27,99 @@ static void dummy_callback(struct amdgpu_device *adev,
 {
 }
 
+static bool dm_test_dmub_supported(struct dmub_srv *dmub)
+{
+	return true;
+}
+
+static bool dm_test_dmub_unsupported(struct dmub_srv *dmub)
+{
+	return false;
+}
+
+static bool dm_test_dmub_hw_initialized(struct dmub_srv *dmub)
+{
+	return true;
+}
+
+static union dmub_fw_boot_status dm_test_dmub_fw_ready(struct dmub_srv *dmub)
+{
+	union dmub_fw_boot_status status = { 0 };
+
+	status.bits.dal_fw = 1;
+	status.bits.mailbox_rdy = 1;
+	return status;
+}
+
+static union dmub_fw_boot_status dm_test_dmub_fw_not_ready(struct dmub_srv *dmub)
+{
+	union dmub_fw_boot_status status = { 0 };
+
+	return status;
+}
+
+static void dm_test_dmub_init_reg_offsets(struct dmub_srv *dmub,
+					  struct dc_context *ctx)
+{
+}
+
+static bool dm_test_dmcu_init(struct dmcu *dmcu)
+{
+	return true;
+}
+
+static bool dm_test_dmcu_is_initialized(struct dmcu *dmcu)
+{
+	return true;
+}
+
+static const struct dmcu_funcs dm_test_dmcu_funcs = {
+	.dmcu_init = dm_test_dmcu_init,
+	.is_dmcu_initialized = dm_test_dmcu_is_initialized,
+};
+
+static struct dmub_srv *dm_test_alloc_dmub_srv(struct kunit *test)
+{
+	struct dmub_srv *dmub_srv;
+
+	dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
+
+	dmub_srv->sw_init = true;
+	dmub_srv->hw_init = true;
+	dmub_srv->power_state = DMUB_POWER_STATE_D0;
+	dmub_srv->hw_funcs.is_supported = dm_test_dmub_supported;
+	dmub_srv->hw_funcs.is_hw_init = dm_test_dmub_hw_initialized;
+	dmub_srv->hw_funcs.get_fw_status = dm_test_dmub_fw_ready;
+	dmub_srv->hw_funcs.init_reg_offsets = dm_test_dmub_init_reg_offsets;
+
+	return dmub_srv;
+}
+
+static const struct firmware *dm_test_alloc_dmub_fw(struct kunit *test)
+{
+	struct dmcub_firmware_header_v1_0 *hdr;
+	struct firmware *fw;
+	u8 *data;
+
+	fw = kunit_kzalloc(test, sizeof(*fw), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fw);
+
+	data = kunit_kzalloc(test, DM_TEST_FW_SIZE, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, data);
+
+	hdr = (struct dmcub_firmware_header_v1_0 *)data;
+	hdr->header.ucode_array_offset_bytes = cpu_to_le32(0);
+	hdr->header.ucode_version = cpu_to_le32(DMUB_FW_VERSION(9, 9, 9));
+	hdr->inst_const_bytes = cpu_to_le32(PSP_HEADER_BYTES_256);
+	hdr->bss_data_bytes = cpu_to_le32(0);
+
+	fw->size = DM_TEST_FW_SIZE;
+	fw->data = data;
+
+	return fw;
+}
+
 /**
  * dm_test_register_dmub_notify_callback_null_callback - Test null callback is rejected
  * @test: The KUnit test context
@@ -395,6 +494,7 @@ static void dm_test_get_default_ips_mode_newer_default(struct kunit *test)
 static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test)
 {
 	struct amdgpu_device *adev;
+	struct dc_context *ctx;
 	struct dc *dc;
 	struct resource_pool *res_pool;
 
@@ -407,12 +507,47 @@ static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test)
 	res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
 
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
 	dc->res_pool = res_pool;
+	dc->ctx = ctx;
+	ctx->dc = dc;
+	ctx->driver_context = adev;
 	adev->dm.dc = dc;
 
 	return adev;
 }
 
+static struct amdgpu_device *dm_test_alloc_adev_with_dmub(struct kunit *test)
+{
+	struct amdgpu_device *adev;
+	struct dmub_srv_fb_info *fb_info;
+	int i;
+
+	adev = dm_test_alloc_adev_with_dc(test);
+
+	fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info);
+
+	fb_info->num_fb = DMUB_WINDOW_TOTAL;
+	for (i = 0; i < DMUB_WINDOW_TOTAL; i++) {
+		fb_info->fb[i].size = PAGE_SIZE;
+		fb_info->fb[i].cpu_addr = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL);
+		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info->fb[i].cpu_addr);
+	}
+
+	adev->dm.dmub_srv = dm_test_alloc_dmub_srv(test);
+	adev->dm.dmub_fb_info = fb_info;
+	adev->dm.dmub_fw = dm_test_alloc_dmub_fw(test);
+	adev->bios = kunit_kzalloc(test, 4, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->bios);
+	adev->bios_size = 4;
+	adev->dm.fw_inst_size = 0;
+
+	return adev;
+}
+
 /**
  * dm_test_dmub_hw_init_no_dmub_srv - Test hw init returns 0 when DMUB unsupported
  * @test: The KUnit test context
@@ -476,6 +611,177 @@ static void dm_test_dmub_hw_init_no_firmware(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL);
 }
 
+/**
+ * dm_test_dmub_hw_init_success_fake_dmub - Test hw init with a fake DMUB service
+ * @test: The KUnit test context
+ *
+ * With fake DMUB callbacks and preallocated framebuffer windows, the init path
+ * should reach DMUB service initialization without real register access.
+ */
+static void dm_test_dmub_hw_init_success_fake_dmub(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_TRUE(test, adev->dm.dmub_srv->hw_init);
+	KUNIT_EXPECT_NOT_NULL(test, adev->dm.dc->ctx->dmub_srv);
+}
+
+/**
+ * dm_test_dmub_hw_init_no_hw_support - Test hw init returns 0 when HW is unsupported
+ * @test: The KUnit test context
+ *
+ * When the DMUB service reports no hardware support, dm_dmub_hw_init() should
+ * log and return 0 without initializing the DMUB hardware.
+ */
+static void dm_test_dmub_hw_init_no_hw_support(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+	adev->dm.dmub_srv->hw_funcs.is_supported = dm_test_dmub_unsupported;
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_NULL(test, adev->dm.dc->ctx->dmub_srv);
+}
+
+/**
+ * dm_test_dmub_hw_init_bss_data - Test hw init copies BSS data into FB memory
+ * @test: The KUnit test context
+ *
+ * When the DMUB firmware declares a non-zero BSS data size, dm_dmub_hw_init()
+ * should copy that region into the BSS framebuffer window.
+ */
+static void dm_test_dmub_hw_init_bss_data(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+	struct dmcub_firmware_header_v1_0 *hdr;
+
+	hdr = (struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data;
+	hdr->bss_data_bytes = cpu_to_le32(16);
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_TRUE(test, adev->dm.dmub_srv->hw_init);
+}
+
+/**
+ * dm_test_dmub_hw_init_hw_init_fails - Test hw init returns -EINVAL on DMUB init failure
+ * @test: The KUnit test context
+ *
+ * A framebuffer-info window count below the required total makes
+ * dmub_srv_hw_init() reject the request, so dm_dmub_hw_init() logs and
+ * returns -EINVAL. (The rejection path emits a one-time WARN via ASSERT.)
+ */
+static void dm_test_dmub_hw_init_hw_init_fails(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+	adev->dm.dmub_fb_info->num_fb = 0;
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL);
+}
+
+/**
+ * dm_test_dmub_hw_init_auto_load_timeout - Test hw init tolerates an auto-load timeout
+ * @test: The KUnit test context
+ *
+ * When the DMUB firmware never reports ready, dmub_srv_wait_for_auto_load()
+ * times out; dm_dmub_hw_init() only warns and still completes successfully.
+ */
+static void dm_test_dmub_hw_init_auto_load_timeout(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+	adev->dm.dmub_srv->hw_funcs.get_fw_status = dm_test_dmub_fw_not_ready;
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_NOT_NULL(test, adev->dm.dc->ctx->dmub_srv);
+}
+
+/**
+ * dm_test_dmub_hw_init_apu_dpia_dcn35 - Test hw init APU DPIA and DCN35 hw params
+ * @test: The KUnit test context
+ *
+ * On a DCN3.5 APU with a USB4 DPIA link, dm_dmub_hw_init() should populate the
+ * DPIA hw params and the DCN3.5 IPS-sequential hw params before initializing
+ * the fake DMUB service.
+ */
+static void dm_test_dmub_hw_init_apu_dpia_dcn35(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+	adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
+	adev->dm.dc->caps.is_apu = true;
+	adev->dm.dc->res_pool->usb4_dpia_count = 1;
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_TRUE(test, adev->dm.dmub_srv->hw_init);
+}
+
+/**
+ * dm_test_dmub_hw_init_sanity_checks_dcn31 - Test hw init enables DCN31 sanity checks
+ * @test: The KUnit test context
+ *
+ * On DCN3.1.2 with a DMCUB firmware version in the affected range,
+ * dm_dmub_hw_init() should enable the DC sanity-check debug flag.
+ */
+static void dm_test_dmub_hw_init_sanity_checks_dcn31(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+	adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 2);
+	adev->dm.dmcub_fw_version = DMUB_FW_VERSION(4, 0, 10);
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_TRUE(test, adev->dm.dc->debug.sanity_checks);
+}
+
+/**
+ * dm_test_dmub_hw_init_sanity_checks_dcn314 - Test hw init enables DCN314 sanity checks
+ * @test: The KUnit test context
+ *
+ * On DCN3.1.4 with a DMCUB firmware version in the affected range,
+ * dm_dmub_hw_init() should enable the DC sanity-check debug flag.
+ */
+static void dm_test_dmub_hw_init_sanity_checks_dcn314(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+	adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 4);
+	adev->dm.dmcub_fw_version = DMUB_FW_VERSION(4, 0, 10);
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_TRUE(test, adev->dm.dc->debug.sanity_checks);
+}
+
+/**
+ * dm_test_dmub_hw_init_dmcu_abm - Test hw init initializes DMCU and ABM when present
+ * @test: The KUnit test context
+ *
+ * When the resource pool exposes a DMCU and ABM, dm_dmub_hw_init() should
+ * program the PSP version, invoke the DMCU init callback, and record the
+ * running state reported by the DMCU.
+ */
+static void dm_test_dmub_hw_init_dmcu_abm(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+	struct dmcu *dmcu;
+	struct abm *abm;
+
+	dmcu = kunit_kzalloc(test, sizeof(*dmcu), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmcu);
+
+	abm = kunit_kzalloc(test, sizeof(*abm), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, abm);
+
+	dmcu->funcs = &dm_test_dmcu_funcs;
+	dmcu->psp_version = 0x12345678;
+	adev->dm.dc->res_pool->dmcu = dmcu;
+	adev->dm.dc->res_pool->abm = abm;
+
+	KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+	KUNIT_EXPECT_TRUE(test, abm->dmcu_is_running);
+}
+
 /* Tests for dm_dmub_hw_resume() */
 
 /**
@@ -561,6 +867,15 @@ static struct kunit_case amdgpu_dm_dmub_tests[] = {
 	KUNIT_CASE(dm_test_dmub_hw_init_no_dmub_srv),
 	KUNIT_CASE(dm_test_dmub_hw_init_no_fb_info),
 	KUNIT_CASE(dm_test_dmub_hw_init_no_firmware),
+	KUNIT_CASE(dm_test_dmub_hw_init_success_fake_dmub),
+	KUNIT_CASE(dm_test_dmub_hw_init_no_hw_support),
+	KUNIT_CASE(dm_test_dmub_hw_init_bss_data),
+	KUNIT_CASE(dm_test_dmub_hw_init_hw_init_fails),
+	KUNIT_CASE(dm_test_dmub_hw_init_auto_load_timeout),
+	KUNIT_CASE(dm_test_dmub_hw_init_apu_dpia_dcn35),
+	KUNIT_CASE(dm_test_dmub_hw_init_sanity_checks_dcn31),
+	KUNIT_CASE(dm_test_dmub_hw_init_sanity_checks_dcn314),
+	KUNIT_CASE(dm_test_dmub_hw_init_dmcu_abm),
 	/* dm_dmub_hw_resume() */
 	KUNIT_CASE(dm_test_dmub_hw_resume_no_dmub_srv),
 	/* dm_dmub_sw_init() */
-- 
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.