mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 09:20:13 -04:00
drm/amd/display: add dm_dmub_hw_init KUnit coverage
[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 <bhawanpreet.lakha@amd.com> Signed-off-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Wayne Lin <wayne.lin@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
@@ -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() */
|
||||
|
||||
Reference in New Issue
Block a user