From: Bhawanpreet Lakha <[email protected]> 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 <[email protected]> Signed-off-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Fangzhi Zuo <[email protected]> Tested-by: Dan Wheeler <[email protected]> --- .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 4 +- .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h | 1 + .../amdgpu_dm/tests/amdgpu_dm_hdcp_test.c | 144 ++++++++++++++++++ 3 files changed, 148 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index 7115cc0c7746..560bfa43dc8a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -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 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h index b8ba2888a2ef..30c1e7b1af1a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h @@ -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_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c index 1580562727cd..b75fadd4e14e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c @@ -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), {} }; -- 2.53.0
