drm/amd/display: Add KUnit tests for update_config

Expose update_config() for KUnit and cover the NULL connector and NULL
dc_link early returns, the dpms_off removal path and the active path
that builds the display/link state and registers the connector. The
active path leaves the DTM TA uninitialized so add_display_to_topology()
returns early without touching firmware.

Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Bhawanpreet Lakha 2026-07-14 10:34:20 -04:00 committed by Alex Deucher
parent 354bfcbd05
commit e1460b1047
3 changed files with 148 additions and 1 deletions

View File

@ -606,7 +606,8 @@ bool enable_assr(void *handle, struct dc_link *link)
}
EXPORT_IF_KUNIT(enable_assr);
static void update_config(void *handle, struct cp_psp_stream_config *config)
STATIC_IFN_KUNIT
void update_config(void *handle, struct cp_psp_stream_config *config)
{
struct hdcp_workqueue *hdcp_work = handle;
struct amdgpu_dm_connector *aconnector;
@ -692,6 +693,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
hdcp_w->aconnector[conn_index] = aconnector;
process_output(hdcp_w);
}
EXPORT_IF_KUNIT(update_config);
/**
* DOC: Add sysfs interface for set/get srm

View File

@ -124,6 +124,7 @@ void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, unsigned int link_ind
uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size);
int psp_set_srm(struct psp_context *psp, u8 *srm, uint32_t srm_size, uint32_t *srm_version);
bool enable_assr(void *handle, struct dc_link *link);
void update_config(void *handle, struct cp_psp_stream_config *config);
#endif
#endif /* AMDGPU_DM_AMDGPU_DM_HDCP_H_ */

View File

@ -1580,6 +1580,145 @@ static void dm_test_enable_assr_initialized_builds_command_and_fails(struct kuni
/* End of tests for enable_assr() */
/* Tests for update_config() */
/**
* dm_test_update_config_null_connector_is_noop - NULL stream ctx returns early
* @test: KUnit test context
*
* When config->dm_stream_ctx is NULL, update_config() must return before
* touching the workqueue, leaving the per-link aconnector array untouched.
*/
static void dm_test_update_config_null_connector_is_noop(struct kunit *test)
{
struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
struct cp_psp_stream_config config = {0};
config.dm_stream_ctx = NULL;
update_config(work, &config);
KUNIT_EXPECT_PTR_EQ(test, work->aconnector[0], NULL);
}
/**
* dm_test_update_config_null_dc_link_is_noop - NULL dc_link returns early
* @test: KUnit test context
*
* A connector without a dc_link must cause update_config() to return before
* registering the connector, leaving the aconnector array untouched.
*/
static void dm_test_update_config_null_dc_link_is_noop(struct kunit *test)
{
struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
struct amdgpu_dm_connector *aconnector;
struct cp_psp_stream_config config = {0};
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, aconnector);
aconnector->dc_link = NULL;
config.dm_stream_ctx = aconnector;
update_config(work, &config);
KUNIT_EXPECT_PTR_EQ(test, work->aconnector[0], NULL);
}
/**
* dm_test_update_config_dpms_off_removes_display - dpms_off path removes display
* @test: KUnit test context
*
* With config->dpms_off set, update_config() must take the removal path:
* hdcp_remove_display() reverts an ENABLED connector to DESIRED and clears
* its per-link aconnector entry.
*/
static void dm_test_update_config_dpms_off_removes_display(struct kunit *test)
{
struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
struct drm_connector_state *conn_state;
struct cp_psp_stream_config config = {0};
conn_state = kunit_kzalloc(test, sizeof(*conn_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, conn_state);
conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
aconnector->base.state = conn_state;
work->aconnector[0] = aconnector;
config.dm_stream_ctx = aconnector;
config.dpms_off = true;
update_config(work, &config);
KUNIT_EXPECT_EQ(test, conn_state->content_protection,
DRM_MODE_CONTENT_PROTECTION_DESIRED);
KUNIT_EXPECT_PTR_EQ(test, work->aconnector[0], NULL);
cancel_delayed_work_sync(&work->property_validate_dwork);
cancel_delayed_work_sync(&work->callback_dwork);
cancel_delayed_work_sync(&work->watchdog_timer_dwork);
}
/**
* dm_test_update_config_populates_display_and_link - active path fills state
* @test: KUnit test context
*
* With dpms_off clear, update_config() must build the display and link from
* @config, reset the connector's encryption_status to HDCP_OFF, register the
* connector and reach process_output() (which enqueues property_validate).
*
* mod_hdcp_add_display() reaches add_display_to_topology(), which returns
* early because the DTM TA is left uninitialized, so no firmware is touched.
*/
static void dm_test_update_config_populates_display_and_link(struct kunit *test)
{
struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
struct psp_context *psp;
struct cp_psp_stream_config config = {0};
/* add_display_to_topology() dereferences the psp handle. */
psp = kunit_kzalloc(test, sizeof(*psp), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, psp);
work->hdcp.config.psp.handle = psp;
config.dm_stream_ctx = aconnector;
config.dpms_off = false;
config.otg_inst = 1;
config.dig_fe = 4;
config.dig_be = 5;
config.stream_enc_idx = 6;
config.link_enc_idx = 7;
config.dio_output_idx = 8;
config.phy_idx = 2;
update_config(work, &config);
KUNIT_EXPECT_EQ(test, work->encryption_status[0],
MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF);
KUNIT_EXPECT_PTR_EQ(test, work->aconnector[0], aconnector);
KUNIT_EXPECT_EQ(test, work->display.state, MOD_HDCP_DISPLAY_ACTIVE);
KUNIT_EXPECT_EQ(test, work->display.controller,
CONTROLLER_ID_D0 + config.otg_inst);
KUNIT_EXPECT_EQ(test, work->display.dig_fe, config.dig_fe);
KUNIT_EXPECT_EQ(test, work->display.stream_enc_idx, config.stream_enc_idx);
KUNIT_EXPECT_EQ(test, work->link.dig_be, config.dig_be);
KUNIT_EXPECT_EQ(test, work->link.link_enc_idx, config.link_enc_idx);
KUNIT_EXPECT_EQ(test, work->link.dio_output_id, config.dio_output_idx);
KUNIT_EXPECT_EQ(test, work->link.phy_idx, config.phy_idx);
KUNIT_EXPECT_TRUE(test, work_pending(&work->property_validate_dwork.work));
cancel_delayed_work_sync(&work->property_validate_dwork);
cancel_delayed_work_sync(&work->callback_dwork);
cancel_delayed_work_sync(&work->watchdog_timer_dwork);
}
/* End of tests for update_config() */
static struct kunit_case dm_hdcp_test_cases[] = {
/* hdcp_get_content_protection_from_status() */
KUNIT_CASE(dm_test_hdcp_get_cp_disabled_returns_desired),
@ -1645,6 +1784,11 @@ static struct kunit_case dm_hdcp_test_cases[] = {
KUNIT_CASE(dm_test_enable_assr_uninitialized_dtm_returns_false),
KUNIT_CASE(dm_test_enable_assr_uninitialized_dtm_ignores_link),
KUNIT_CASE(dm_test_enable_assr_initialized_builds_command_and_fails),
/* update_config() */
KUNIT_CASE(dm_test_update_config_null_connector_is_noop),
KUNIT_CASE(dm_test_update_config_null_dc_link_is_noop),
KUNIT_CASE(dm_test_update_config_dpms_off_removes_display),
KUNIT_CASE(dm_test_update_config_populates_display_and_link),
{}
};