From: Alex Hung <[email protected]> Add KUnit tests for amdgpu_dm_dmub.c covering the following functions:
- dm_register_dmub_notify_callback(): NULL callback rejection, out-of-range type, valid registration with offload flag - dm_dmub_aux_setconfig_callback(): copy and complete on AUX reply, non-AUX skip, NULL dm_notify, SET_CONFIG reply - dm_dmub_aux_fused_io_callback(): copy reply and complete, max ddc_line boundary - dm_get_default_ips_mode(): IPS mode per DCN version (3.5, 3.5.1, 3.6, 4.2), disabled for older ASICs, default enabled for unhandled newer ASICs - dm_dmub_hw_init(): early returns for no dmub_srv, no fb_info, no firmware - dm_dmub_hw_resume(): no-op when dmub_srv is NULL - dm_dmub_sw_init(): returns 0 for unsupported ASIC - dm_init_microcode(): returns 0 for unsupported ASIC Assisted-by: Copilot:Claude-Opus-4.6 Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Hung <[email protected]> Signed-off-by: Chenyu Chen <[email protected]> --- .../amd/display/amdgpu_dm/amdgpu_dm_dmub.c | 9 + .../drm/amd/display/amdgpu_dm/tests/Makefile | 1 + .../amdgpu_dm/tests/amdgpu_dm_dmub_test.c | 600 ++++++++++++++++++ 3 files changed, 610 insertions(+) create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c index 54b3b884968b..579a435dcefc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c @@ -38,6 +38,7 @@ #include "amdgpu_ucode.h" #include "amdgpu_dm.h" #include "amdgpu_dm_dmub.h" +#include "amdgpu_dm_kunit_helpers.h" #include <linux/component.h> #include <linux/firmware.h> @@ -80,6 +81,7 @@ void dm_dmub_aux_setconfig_callback(struct amdgpu_device *adev, if (notify->type == DMUB_NOTIFICATION_AUX_REPLY) complete(&adev->dm.dmub_aux_transfer_done); } +EXPORT_IF_KUNIT(dm_dmub_aux_setconfig_callback); void dm_dmub_aux_fused_io_callback(struct amdgpu_device *adev, struct dmub_notification *notify) @@ -103,6 +105,7 @@ void dm_dmub_aux_fused_io_callback(struct amdgpu_device *adev, memcpy(sync->reply_data, req, sizeof(*req)); complete(&sync->replied); } +EXPORT_IF_KUNIT(dm_dmub_aux_fused_io_callback); /** * dm_register_dmub_notify_callback - Sets callback for DMUB notify @@ -129,6 +132,7 @@ bool dm_register_dmub_notify_callback(struct amdgpu_device *adev, return true; } +EXPORT_IF_KUNIT(dm_register_dmub_notify_callback); int dm_dmub_hw_init(struct amdgpu_device *adev) { @@ -318,6 +322,7 @@ int dm_dmub_hw_init(struct amdgpu_device *adev) return 0; } +EXPORT_IF_KUNIT(dm_dmub_hw_init); void dm_dmub_hw_resume(struct amdgpu_device *adev) { @@ -347,6 +352,7 @@ void dm_dmub_hw_resume(struct amdgpu_device *adev) drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r); } } +EXPORT_IF_KUNIT(dm_dmub_hw_resume); static enum dmub_status dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev, @@ -460,6 +466,7 @@ enum dmub_ips_disable_type dm_get_default_ips_mode( return ret; } +EXPORT_IF_KUNIT(dm_get_default_ips_mode); static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address) { @@ -678,6 +685,7 @@ int dm_dmub_sw_init(struct amdgpu_device *adev) return 0; } +EXPORT_IF_KUNIT(dm_dmub_sw_init); int dm_init_microcode(struct amdgpu_device *adev) { @@ -750,6 +758,7 @@ int dm_init_microcode(struct amdgpu_device *adev) "%s", fw_name_dmub); return r; } +EXPORT_IF_KUNIT(dm_init_microcode); int amdgpu_dm_process_dmub_aux_transfer_sync( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile index 5bb43b3bc439..4bd8d1fa0fee 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_audio_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_color_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_colorop_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_backlight_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_dmub_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_psr_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_replay_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_ism_test.o 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 new file mode 100644 index 000000000000..b82dd301a896 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_dmub.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include <kunit/test.h> + +#include "dc.h" +#include "dc/inc/core_types.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "dmub/dmub_srv.h" +#include "amdgpu_dm_dmub.h" + +/* Tests for dm_register_dmub_notify_callback() */ + +static void dummy_callback(struct amdgpu_device *adev, + struct dmub_notification *notify) +{ +} + +/** + * dm_test_register_dmub_notify_callback_null_callback - Test null callback is rejected + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_null_callback(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev, + DMUB_NOTIFICATION_AUX_REPLY, NULL, false)); +} + +/** + * dm_test_register_dmub_notify_callback_type_out_of_range - Test out-of-range type is rejected + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_type_out_of_range(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev, + AMDGPU_DMUB_NOTIFICATION_MAX, dummy_callback, false)); +} + +/** + * dm_test_register_dmub_notify_callback_valid - Test Register dmub notify callback valid + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_valid(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev, + DMUB_NOTIFICATION_AUX_REPLY, dummy_callback, true)); + + KUNIT_EXPECT_TRUE(test, + adev->dm.dmub_callback[DMUB_NOTIFICATION_AUX_REPLY] == dummy_callback); + KUNIT_EXPECT_TRUE(test, + adev->dm.dmub_thread_offload[DMUB_NOTIFICATION_AUX_REPLY]); +} + +/** + * dm_test_register_dmub_notify_callback_offload_false - Test registration with offload disabled + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_offload_false(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev, + DMUB_NOTIFICATION_HPD, dummy_callback, false)); + + KUNIT_EXPECT_TRUE(test, + adev->dm.dmub_callback[DMUB_NOTIFICATION_HPD] == dummy_callback); + KUNIT_EXPECT_FALSE(test, + adev->dm.dmub_thread_offload[DMUB_NOTIFICATION_HPD]); +} + +/* Tests for dm_dmub_aux_setconfig_callback() */ + +/** + * dm_test_dmub_aux_setconfig_callback_copies_and_completes - Test copy and complete on AUX reply + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_copies_and_completes(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification *dm_notify; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = dm_notify; + + notify.type = DMUB_NOTIFICATION_AUX_REPLY; + notify.result = AUX_RET_SUCCESS; + notify.aux_reply.command = 0xA5; + notify.aux_reply.length = 3; + notify.aux_reply.data[0] = 0x11; + notify.aux_reply.data[1] = 0x22; + notify.aux_reply.data[2] = 0x33; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_EQ(test, dm_notify->type, notify.type); + KUNIT_EXPECT_EQ(test, dm_notify->result, notify.result); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.command, notify.aux_reply.command); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.length, notify.aux_reply.length); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.data[0], notify.aux_reply.data[0]); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.data[1], notify.aux_reply.data[1]); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.data[2], notify.aux_reply.data[2]); + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/** + * dm_test_dmub_aux_setconfig_callback_non_aux_no_complete - Test non-AUX type skips completion + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_non_aux_no_complete(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification *dm_notify; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = dm_notify; + + notify.type = DMUB_NOTIFICATION_HPD; + notify.result = AUX_RET_ERROR_TIMEOUT; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_EQ(test, dm_notify->type, notify.type); + KUNIT_EXPECT_FALSE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/** + * dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify - Test AUX with NULL dm_notify + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = NULL; + + notify.type = DMUB_NOTIFICATION_AUX_REPLY; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/** + * dm_test_dmub_aux_setconfig_callback_set_config_reply - Test SET_CONFIG reply copies status + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_set_config_reply(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification *dm_notify; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = dm_notify; + + notify.type = DMUB_NOTIFICATION_SET_CONFIG_REPLY; + notify.sc_status = SET_CONFIG_RX_TIMEOUT; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_EQ(test, dm_notify->type, notify.type); + KUNIT_EXPECT_EQ(test, dm_notify->sc_status, notify.sc_status); + KUNIT_EXPECT_FALSE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/* Tests for dm_dmub_aux_fused_io_callback() */ + +/** + * dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes - Test copy and complete + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification notify = {}; + struct dmub_cmd_fused_request *reply; + u32 reply_ddc_line; + u32 notify_ddc_line; + u32 reply_address; + u32 notify_address; + u32 reply_length; + u32 notify_length; + uint8_t ddc_line = 2; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + init_completion(&adev->dm.fused_io[ddc_line].replied); + + notify.fused_request.identifier = 0x34; + notify.fused_request.status = FUSED_REQUEST_STATUS_SUCCESS; + notify.fused_request.u.aux.ddc_line = ddc_line; + notify.fused_request.u.aux.address = 0x50; + notify.fused_request.u.aux.length = 4; + + dm_dmub_aux_fused_io_callback(adev, ¬ify); + + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.fused_io[ddc_line].replied)); + + reply = (struct dmub_cmd_fused_request *)adev->dm.fused_io[ddc_line].reply_data; + reply_ddc_line = reply->u.aux.ddc_line; + notify_ddc_line = notify.fused_request.u.aux.ddc_line; + reply_address = reply->u.aux.address; + notify_address = notify.fused_request.u.aux.address; + reply_length = reply->u.aux.length; + notify_length = notify.fused_request.u.aux.length; + + KUNIT_EXPECT_EQ(test, reply->identifier, notify.fused_request.identifier); + KUNIT_EXPECT_EQ(test, reply->status, notify.fused_request.status); + KUNIT_EXPECT_EQ(test, reply_ddc_line, notify_ddc_line); + KUNIT_EXPECT_EQ(test, reply_address, notify_address); + KUNIT_EXPECT_EQ(test, reply_length, notify_length); +} + +/** + * dm_test_dmub_aux_fused_io_callback_max_ddc_line - Test Dmub aux fused io callback max ddc line + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_fused_io_callback_max_ddc_line(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification notify = {}; + struct dmub_cmd_fused_request *reply; + u32 reply_ddc_line; + u32 notify_ddc_line; + uint8_t ddc_line; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + ddc_line = ARRAY_SIZE(adev->dm.fused_io) - 1; + init_completion(&adev->dm.fused_io[ddc_line].replied); + + notify.fused_request.identifier = 0x56; + notify.fused_request.status = FUSED_REQUEST_STATUS_SUCCESS; + notify.fused_request.u.aux.ddc_line = ddc_line; + notify.fused_request.u.aux.address = 0x50; + notify.fused_request.u.aux.length = 1; + + dm_dmub_aux_fused_io_callback(adev, ¬ify); + + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.fused_io[ddc_line].replied)); + + reply = (struct dmub_cmd_fused_request *)adev->dm.fused_io[ddc_line].reply_data; + reply_ddc_line = reply->u.aux.ddc_line; + notify_ddc_line = notify.fused_request.u.aux.ddc_line; + + KUNIT_EXPECT_EQ(test, reply->identifier, notify.fused_request.identifier); + KUNIT_EXPECT_EQ(test, reply_ddc_line, notify_ddc_line); +} + +/* Tests for dm_get_default_ips_mode() */ + +/** + * dm_test_get_default_ips_mode_dcn35 - Test Get default ips mode dcn35 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_dcn35(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF); +} + +/** + * dm_test_get_default_ips_mode_dcn351 - Test Get default ips mode dcn351 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_dcn351(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 1); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF); +} + +/** + * dm_test_get_default_ips_mode_dcn36 - Test Get default ips mode dcn36 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_dcn36(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 6, 0); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF); +} + +/** + * dm_test_get_default_ips_mode_dcn42 - Test Get default ips mode dcn42 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_dcn42(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 2, 0); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_DISABLE_ALL); +} + +/** + * dm_test_get_default_ips_mode_older_than_dcn35 - Test Get default ips mode older than dcn35 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_older_than_dcn35(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 2, 0); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_DISABLE_ALL); +} + +/** + * dm_test_get_default_ips_mode_newer_default - Test Get default ips mode newer default + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_newer_default(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + /* DCN 4.0.1 is >= 3.5 but has no explicit case, returns ENABLE */ + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 0, 1); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_ENABLE); +} + +/* Tests for dm_dmub_hw_init() */ + +/* + * Build an amdgpu_device with the minimal dc/res_pool pointers that + * dm_dmub_hw_init() and dm_dmub_hw_resume() dereference before their + * early-return checks. + */ +static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct resource_pool *res_pool; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + + res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + + dc->res_pool = res_pool; + adev->dm.dc = dc; + + return adev; +} + +/** + * dm_test_dmub_hw_init_no_dmub_srv - Test hw init returns 0 when DMUB unsupported + * @test: The KUnit test context + * + * When adev->dm.dmub_srv is NULL the ASIC does not support DMUB and + * dm_dmub_hw_init() should return 0 without touching the hardware. + */ +static void dm_test_dmub_hw_init_no_dmub_srv(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test); + + adev->dm.dmub_srv = NULL; + + KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0); +} + +/** + * dm_test_dmub_hw_init_no_fb_info - Test hw init fails without framebuffer info + * @test: The KUnit test context + * + * With a DMUB service present but no framebuffer info, dm_dmub_hw_init() + * should return -EINVAL. + */ +static void dm_test_dmub_hw_init_no_fb_info(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(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); + + adev->dm.dmub_srv = dmub_srv; + adev->dm.dmub_fb_info = NULL; + + KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL); +} + +/** + * dm_test_dmub_hw_init_no_firmware - Test hw init fails without firmware + * @test: The KUnit test context + * + * With a DMUB service and framebuffer info present but no firmware, + * dm_dmub_hw_init() should return -EINVAL. + */ +static void dm_test_dmub_hw_init_no_firmware(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test); + struct dmub_srv *dmub_srv; + struct dmub_srv_fb_info *fb_info; + + dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + + fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info); + + adev->dm.dmub_srv = dmub_srv; + adev->dm.dmub_fb_info = fb_info; + adev->dm.dmub_fw = NULL; + + KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL); +} + +/* Tests for dm_dmub_hw_resume() */ + +/** + * dm_test_dmub_hw_resume_no_dmub_srv - Test hw resume is a no-op when DMUB unsupported + * @test: The KUnit test context + * + * When adev->dm.dmub_srv is NULL, dm_dmub_hw_resume() should return early + * without dereferencing the (absent) DMUB service. + */ +static void dm_test_dmub_hw_resume_no_dmub_srv(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test); + + adev->dm.dmub_srv = NULL; + + /* Must not crash. */ + dm_dmub_hw_resume(adev); +} + +/* Tests for dm_dmub_sw_init() */ + +/** + * dm_test_dmub_sw_init_unsupported_asic - Test sw init returns 0 for unsupported ASIC + * @test: The KUnit test context + * + * For an IP version with no DMUB support, dm_dmub_sw_init() should return 0 + * before attempting to access the firmware. + */ +static void dm_test_dmub_sw_init_unsupported_asic(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); + + KUNIT_EXPECT_EQ(test, dm_dmub_sw_init(adev), 0); +} + +/* Tests for dm_init_microcode() */ + +/** + * dm_test_init_microcode_unsupported_asic - Test microcode init returns 0 for unsupported ASIC + * @test: The KUnit test context + * + * For an IP version with no DMUB support, dm_init_microcode() should return 0 + * without requesting any firmware. + */ +static void dm_test_init_microcode_unsupported_asic(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); + + KUNIT_EXPECT_EQ(test, dm_init_microcode(adev), 0); +} + +static struct kunit_case amdgpu_dm_dmub_tests[] = { + /* dm_register_dmub_notify_callback() */ + KUNIT_CASE(dm_test_register_dmub_notify_callback_null_callback), + KUNIT_CASE(dm_test_register_dmub_notify_callback_type_out_of_range), + KUNIT_CASE(dm_test_register_dmub_notify_callback_valid), + KUNIT_CASE(dm_test_register_dmub_notify_callback_offload_false), + /* dm_dmub_aux_setconfig_callback() */ + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_copies_and_completes), + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_non_aux_no_complete), + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify), + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_set_config_reply), + /* dm_dmub_aux_fused_io_callback() */ + KUNIT_CASE(dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes), + KUNIT_CASE(dm_test_dmub_aux_fused_io_callback_max_ddc_line), + /* dm_get_default_ips_mode() */ + KUNIT_CASE(dm_test_get_default_ips_mode_dcn35), + KUNIT_CASE(dm_test_get_default_ips_mode_dcn351), + KUNIT_CASE(dm_test_get_default_ips_mode_dcn36), + KUNIT_CASE(dm_test_get_default_ips_mode_dcn42), + KUNIT_CASE(dm_test_get_default_ips_mode_older_than_dcn35), + KUNIT_CASE(dm_test_get_default_ips_mode_newer_default), + /* dm_dmub_hw_init() */ + 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), + /* dm_dmub_hw_resume() */ + KUNIT_CASE(dm_test_dmub_hw_resume_no_dmub_srv), + /* dm_dmub_sw_init() */ + KUNIT_CASE(dm_test_dmub_sw_init_unsupported_asic), + /* dm_init_microcode() */ + KUNIT_CASE(dm_test_init_microcode_unsupported_asic), + {} +}; + +static struct kunit_suite amdgpu_dm_dmub_test_suite = { + .name = "amdgpu_dm_dmub", + .test_cases = amdgpu_dm_dmub_tests, +}; + +kunit_test_suite(amdgpu_dm_dmub_test_suite); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_dmub"); +MODULE_LICENSE("Dual MIT/GPL"); -- 2.43.0
