From: Alex Hung <[email protected]> [WHAT] Add KUnit coverage for dm_helpers_submit_i2c, dm_helper_dmub_aux_transfer_sync, the empty stub helpers, the MST null-connector early returns, dm_helpers_dmub_outbox_interrupt_control, dm_helpers_mst_enable_stream_features and dm_helpers_enable_periodic_detection.
Assisted-by: Copilot:Claude-Opus-4.8 Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Hung <[email protected]> Signed-off-by: George Zhang <[email protected]> --- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 18 + .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 541 ++++++++++++++++++ 2 files changed, 559 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index aa4bd99528a3..04e3c34b9e50 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -296,6 +296,7 @@ void dm_helpers_dp_update_branch_info( struct dc_context *ctx, const struct dc_link *link) {} +EXPORT_IF_KUNIT(dm_helpers_dp_update_branch_info); static void dm_helpers_construct_old_payload( struct drm_dp_mst_topology_mgr *mgr, @@ -380,6 +381,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( return true; } +EXPORT_IF_KUNIT(dm_helpers_dp_mst_write_payload_allocation_table); /* * poll pending down reply @@ -388,6 +390,7 @@ void dm_helpers_dp_mst_poll_pending_down_reply( struct dc_context *ctx, const struct dc_link *link) {} +EXPORT_IF_KUNIT(dm_helpers_dp_mst_poll_pending_down_reply); /* * Clear payload allocation table before enable MST DP link. @@ -396,6 +399,7 @@ void dm_helpers_dp_mst_clear_payload_allocation_table( struct dc_context *ctx, const struct dc_link *link) {} +EXPORT_IF_KUNIT(dm_helpers_dp_mst_clear_payload_allocation_table); /* * Polls for ACT (allocation change trigger) handled and sends @@ -426,6 +430,7 @@ enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger( return ACT_SUCCESS; } +EXPORT_IF_KUNIT(dm_helpers_dp_mst_poll_for_allocation_change_trigger); void dm_helpers_dp_mst_send_payload_allocation( struct dc_context *ctx, @@ -460,6 +465,7 @@ void dm_helpers_dp_mst_send_payload_allocation( clr_flag, false); } } +EXPORT_IF_KUNIT(dm_helpers_dp_mst_send_payload_allocation); void dm_helpers_dp_mst_update_mst_mgr_for_deallocation( struct dc_context *ctx, @@ -488,6 +494,7 @@ void dm_helpers_dp_mst_update_mst_mgr_for_deallocation( amdgpu_dm_set_mst_status(&aconnector->mst_status, set_flag, true); amdgpu_dm_set_mst_status(&aconnector->mst_status, clr_flag, false); } +EXPORT_IF_KUNIT(dm_helpers_dp_mst_update_mst_mgr_for_deallocation); void dm_dtn_log_begin(struct dc_context *ctx, struct dc_log_buffer_ctx *log_ctx) @@ -707,6 +714,7 @@ bool dm_helpers_submit_i2c( return result; } +EXPORT_IF_KUNIT(dm_helpers_submit_i2c); bool dm_helpers_execute_fused_io( struct dc_context *ctx, @@ -1023,6 +1031,7 @@ bool dm_helpers_is_dp_sink_present(struct dc_link *link) mutex_unlock(&aconnector->dm_dp_aux.aux.hw_mutex); return dp_sink_present; } +EXPORT_IF_KUNIT(dm_helpers_is_dp_sink_present); STATIC_IFN_KUNIT int dm_helpers_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len) @@ -1312,6 +1321,7 @@ int dm_helper_dmub_aux_transfer_sync( return amdgpu_dm_process_dmub_aux_transfer_sync(ctx, link->link_index, payload, operation_result); } +EXPORT_IF_KUNIT(dm_helper_dmub_aux_transfer_sync); int dm_helpers_dmub_set_config_sync(struct dc_context *ctx, const struct dc_link *link, @@ -1326,18 +1336,21 @@ void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks) { /* TODO: something */ } +EXPORT_IF_KUNIT(dm_set_dcn_clocks); void dm_helpers_dmu_timeout(struct dc_context *ctx) { // TODO: //amdgpu_device_gpu_recover(dc_context->driver-context, NULL); } +EXPORT_IF_KUNIT(dm_helpers_dmu_timeout); void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us) { // TODO: //amdgpu_device_gpu_recover(dc_context->driver-context, NULL); } +EXPORT_IF_KUNIT(dm_helpers_smu_timeout); void dm_helpers_init_panel_settings( struct dc_context *ctx, @@ -1410,6 +1423,7 @@ bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enabl enable ? "en" : "dis", ret); return ret; } +EXPORT_IF_KUNIT(dm_helpers_dmub_outbox_interrupt_control); void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream) { @@ -1435,6 +1449,7 @@ void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream) &new_downspread.raw, sizeof(new_downspread)); } +EXPORT_IF_KUNIT(dm_helpers_mst_enable_stream_features); bool dm_helpers_dp_handle_test_pattern_request( struct dc_context *ctx, @@ -1578,6 +1593,7 @@ void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz) { // TODO } +EXPORT_IF_KUNIT(dm_set_phyd32clk); void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable) { @@ -1589,6 +1605,7 @@ void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable) schedule_work(&adev->dm.idle_workqueue->work); } } +EXPORT_IF_KUNIT(dm_helpers_enable_periodic_detection); void dm_helpers_dp_mst_update_branch_bandwidth( struct dc_context *ctx, @@ -1596,6 +1613,7 @@ void dm_helpers_dp_mst_update_branch_bandwidth( { // TODO } +EXPORT_IF_KUNIT(dm_helpers_dp_mst_update_branch_bandwidth); STATIC_IFN_KUNIT const uint32_t dm_freesync_pcon_whitelist[] = { DP_BRANCH_DEVICE_ID_0060AD, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c index 599de8240bee..29feb8c3940b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c @@ -1421,6 +1421,14 @@ static ssize_t dm_test_synaptics_aux_transfer(struct drm_dp_aux *aux, return msg->size; } +static struct dm_test_synaptics_aux *dm_test_current_aux_recorder; + +static ssize_t dm_test_current_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + return dm_test_synaptics_aux_transfer(&dm_test_current_aux_recorder->aux, msg); +} + static struct dm_test_synaptics_aux *dm_test_alloc_synaptics_aux_with_dev(struct kunit *test, struct drm_device *drm_dev) { @@ -2022,6 +2030,507 @@ static void dm_test_fill_mst_payload_table_empty(struct kunit *test) KUNIT_EXPECT_EQ(test, table.stream_allocations[0].slot_count, 12); } +/* Tests for dm_helpers_submit_i2c() */ + +/** + * dm_test_submit_i2c_null_priv - Test i2c submit returns false without connector + * @test: The KUnit test context + */ +static void dm_test_submit_i2c_null_priv(struct kunit *test) +{ + struct dc_link *link; + struct i2c_command cmd = {0}; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + KUNIT_EXPECT_FALSE(test, dm_helpers_submit_i2c(NULL, link, &cmd)); +} + +struct dm_test_i2c_adapter { + struct i2c_adapter base; + struct kunit *test; + struct i2c_payload *expected_payloads; + int expected_num; + int ret; + int calls; +}; + +static void dm_test_i2c_lock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + rt_mutex_lock(&adapter->bus_lock); +} + +static int dm_test_i2c_trylock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + return rt_mutex_trylock(&adapter->bus_lock); +} + +static void dm_test_i2c_unlock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + rt_mutex_unlock(&adapter->bus_lock); +} + +static const struct i2c_lock_operations dm_test_i2c_lock_ops = { + .lock_bus = dm_test_i2c_lock_bus, + .trylock_bus = dm_test_i2c_trylock_bus, + .unlock_bus = dm_test_i2c_unlock_bus, +}; + +static int dm_test_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) +{ + struct dm_test_i2c_adapter *fake; + int i; + + fake = container_of(adapter, struct dm_test_i2c_adapter, base); + fake->calls++; + + KUNIT_EXPECT_EQ(fake->test, num, fake->expected_num); + + for (i = 0; i < num; i++) { + KUNIT_EXPECT_EQ(fake->test, msgs[i].flags, + fake->expected_payloads[i].write ? 0 : I2C_M_RD); + KUNIT_EXPECT_EQ(fake->test, msgs[i].addr, + (u16)fake->expected_payloads[i].address); + KUNIT_EXPECT_EQ(fake->test, msgs[i].len, + (u16)fake->expected_payloads[i].length); + KUNIT_EXPECT_PTR_EQ(fake->test, msgs[i].buf, + fake->expected_payloads[i].data); + } + + return fake->ret; +} + +static const struct i2c_algorithm dm_test_i2c_algorithm = { + .master_xfer = dm_test_i2c_master_xfer, +}; + +static void dm_test_submit_i2c_transfer(struct kunit *test, + bool full_transfer) +{ + struct amdgpu_dm_connector *aconnector; + struct dm_test_i2c_adapter *fake; + struct dc_link *link; + u8 write_data[2] = { 0x12, 0x34 }; + u8 read_data[3] = { 0 }; + struct i2c_payload payloads[] = { + { true, 0x50, sizeof(write_data), write_data }, + { false, 0x51, sizeof(read_data), read_data }, + }; + struct i2c_command cmd = { + .payloads = payloads, + .number_of_payloads = ARRAY_SIZE(payloads), + }; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + fake = kunit_kzalloc(test, sizeof(*fake), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fake); + + fake->test = test; + fake->expected_payloads = payloads; + fake->expected_num = ARRAY_SIZE(payloads); + fake->ret = full_transfer ? ARRAY_SIZE(payloads) : 1; + fake->base.algo = &dm_test_i2c_algorithm; + fake->base.lock_ops = &dm_test_i2c_lock_ops; + rt_mutex_init(&fake->base.bus_lock); + rt_mutex_init(&fake->base.mux_lock); + + aconnector->i2c = (struct amdgpu_i2c_adapter *)fake; + link->priv = aconnector; + + KUNIT_EXPECT_EQ(test, dm_helpers_submit_i2c(NULL, link, &cmd), full_transfer); + KUNIT_EXPECT_EQ(test, fake->calls, 1); +} + +/** + * dm_test_submit_i2c_success - Test payloads are mapped to i2c_msg array + * @test: The KUnit test context + */ +static void dm_test_submit_i2c_success(struct kunit *test) +{ + dm_test_submit_i2c_transfer(test, true); +} + +/** + * dm_test_submit_i2c_partial_transfer - Test short i2c transfer returns false + * @test: The KUnit test context + */ +static void dm_test_submit_i2c_partial_transfer(struct kunit *test) +{ + dm_test_submit_i2c_transfer(test, false); +} + +/* Tests for dm_helper_dmub_aux_transfer_sync() */ + +/** + * dm_test_dmub_aux_transfer_sync_hpd_discon - Test aux transfer with HPD disconnected + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_transfer_sync_hpd_discon(struct kunit *test) +{ + struct dc_link *link; + struct dc_context *ctx; + struct aux_payload payload = {0}; + enum aux_return_code_type result = AUX_RET_SUCCESS; + int ret; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + link->hpd_status = false; + + ret = dm_helper_dmub_aux_transfer_sync(ctx, link, &payload, &result); + + KUNIT_EXPECT_EQ(test, ret, -1); + KUNIT_EXPECT_EQ(test, (int)result, (int)AUX_RET_ERROR_HPD_DISCON); +} + +/* Tests for empty stub functions (must not crash) */ + +/** + * dm_test_dp_update_branch_info_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_dp_update_branch_info_no_crash(struct kunit *test) +{ + dm_helpers_dp_update_branch_info(NULL, NULL); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_mst_poll_pending_down_reply_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_mst_poll_pending_down_reply_no_crash(struct kunit *test) +{ + dm_helpers_dp_mst_poll_pending_down_reply(NULL, NULL); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_mst_clear_payload_alloc_table_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_mst_clear_payload_alloc_table_no_crash(struct kunit *test) +{ + dm_helpers_dp_mst_clear_payload_allocation_table(NULL, NULL); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_set_dcn_clocks_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_set_dcn_clocks_no_crash(struct kunit *test) +{ + dm_set_dcn_clocks(NULL, NULL); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_dmu_timeout_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_dmu_timeout_no_crash(struct kunit *test) +{ + dm_helpers_dmu_timeout(NULL); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_smu_timeout_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_smu_timeout_no_crash(struct kunit *test) +{ + dm_helpers_smu_timeout(NULL, 0, 0, 0); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_set_phyd32clk_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_set_phyd32clk_no_crash(struct kunit *test) +{ + dm_set_phyd32clk(NULL, 0); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_mst_update_branch_bandwidth_no_crash - Test empty stub does not crash + * @test: The KUnit test context + */ +static void dm_test_mst_update_branch_bandwidth_no_crash(struct kunit *test) +{ + dm_helpers_dp_mst_update_branch_bandwidth(NULL, NULL); + KUNIT_EXPECT_TRUE(test, true); +} + +/* Tests for MST functions null-connector early returns */ + +/** + * dm_test_mst_write_payload_alloc_table_null_ctx - Test null connector returns false + * @test: The KUnit test context + */ +static void dm_test_mst_write_payload_alloc_table_null_ctx(struct kunit *test) +{ + struct dc_stream_state *stream; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + /* dm_stream_context is NULL → aconnector is NULL → return false */ + KUNIT_EXPECT_FALSE(test, + dm_helpers_dp_mst_write_payload_allocation_table(NULL, stream, NULL, true)); +} + +/** + * dm_test_mst_poll_for_act_null_ctx - Test null connector returns ACT_FAILED + * @test: The KUnit test context + */ +static void dm_test_mst_poll_for_act_null_ctx(struct kunit *test) +{ + struct dc_stream_state *stream; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + KUNIT_EXPECT_EQ(test, + (int)dm_helpers_dp_mst_poll_for_allocation_change_trigger(NULL, stream), + (int)ACT_FAILED); +} + +/** + * dm_test_mst_send_payload_alloc_null_ctx - Test null connector does not crash + * @test: The KUnit test context + */ +static void dm_test_mst_send_payload_alloc_null_ctx(struct kunit *test) +{ + struct dc_stream_state *stream; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + /* Should early-return without crash */ + dm_helpers_dp_mst_send_payload_allocation(NULL, stream); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_mst_update_mgr_dealloc_null_ctx - Test null connector does not crash + * @test: The KUnit test context + */ +static void dm_test_mst_update_mgr_dealloc_null_ctx(struct kunit *test) +{ + struct dc_stream_state *stream; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + dm_helpers_dp_mst_update_mst_mgr_for_deallocation(NULL, stream); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_is_dp_sink_present_null_priv - Test null connector returns true + * @test: The KUnit test context + */ +static void dm_test_is_dp_sink_present_null_priv(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* NULL priv → DRM_ERROR + return true */ + KUNIT_EXPECT_TRUE(test, dm_helpers_is_dp_sink_present(link)); +} + +/* Tests for dm_helpers_dmub_outbox_interrupt_control() */ + +/** + * dm_test_dmub_outbox_interrupt_control_null_dc - Test outbox irq control with NULL dc + * @test: The KUnit test context + * + * dc_interrupt_set() is NULL-safe and returns false when dc is NULL, so the + * helper returns false without touching real interrupt hardware. + */ +static void dm_test_dmub_outbox_interrupt_control_null_dc(struct kunit *test) +{ + struct dc_context *ctx; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + /* ctx->dc is NULL → dc_interrupt_set returns false */ + KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, true)); + KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, false)); +} + +/* Tests for dm_helpers_mst_enable_stream_features() */ + +/** + * dm_test_mst_enable_stream_features_aux_disabled - Test early return when aux disabled + * @test: The KUnit test context + */ +static void dm_test_mst_enable_stream_features_aux_disabled(struct kunit *test) +{ + struct dc_stream_state *stream; + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + stream->link = link; + link->aux_access_disabled = true; + + /* aux_access_disabled → early return without DPCD access */ + dm_helpers_mst_enable_stream_features(stream); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_mst_enable_stream_features_writes_downspread - Test MSA ignore write + * @test: The KUnit test context + */ +static void dm_test_mst_enable_stream_features_writes_downspread(struct kunit *test) +{ + struct dm_test_synaptics_aux *fixture; + struct amdgpu_dm_connector *aconnector; + struct dc_stream_state *stream; + struct amdgpu_device *adev; + struct dc_link *link; + + adev = dm_kunit_alloc_adev(test); + fixture = dm_test_alloc_synaptics_aux_with_dev(test, &adev->ddev); + aconnector = dm_kunit_alloc_connector(test, adev, NULL); + link = dm_kunit_alloc_link(test); + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + dm_test_current_aux_recorder = fixture; + aconnector->dm_dp_aux.aux.drm_dev = &adev->ddev; + aconnector->dm_dp_aux.aux.transfer = dm_test_current_aux_transfer; + drm_dp_aux_init(&aconnector->dm_dp_aux.aux); + link->priv = aconnector; + stream->link = link; + stream->ignore_msa_timing_param = true; + + dm_helpers_mst_enable_stream_features(stream); + + KUNIT_EXPECT_EQ(test, fixture->downspread_reads, 1U); + KUNIT_EXPECT_EQ(test, fixture->downspread_writes, 1U); + KUNIT_EXPECT_EQ(test, fixture->last_dpcd_write_address, + DP_DOWNSPREAD_CTRL); + KUNIT_EXPECT_EQ(test, fixture->dpcd_write_value, (u8)BIT(7)); +} + +/* Tests for dm_helpers_enable_periodic_detection() */ + +struct dm_test_idle_work { + struct idle_workqueue base; + bool ran; +}; + +static void dm_test_idle_work_func(struct work_struct *work) +{ + struct dm_test_idle_work *idle_work; + + idle_work = container_of(work, struct dm_test_idle_work, base.work); + idle_work->ran = true; +} + +/** + * dm_test_enable_periodic_detection_no_workqueue - Test no-op without idle workqueue + * @test: The KUnit test context + */ +static void dm_test_enable_periodic_detection_no_workqueue(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_context *ctx; + + adev = dm_kunit_alloc_adev(test); + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + ctx->driver_context = adev; + + /* adev->dm.idle_workqueue is NULL → no-op, no crash */ + dm_helpers_enable_periodic_detection(ctx, true); + KUNIT_EXPECT_TRUE(test, true); +} + +/** + * dm_test_enable_periodic_detection_updates_enable - Test idle work enable flag + * @test: The KUnit test context + * + * Keeps idle_workqueue->running set so the helper only updates the enable flag + * and does not queue the idle worker. + */ +static void dm_test_enable_periodic_detection_updates_enable(struct kunit *test) +{ + struct idle_workqueue *idle_work; + struct amdgpu_device *adev; + struct dc_context *ctx; + + adev = dm_kunit_alloc_adev(test); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, idle_work); + + ctx->driver_context = adev; + adev->dm.idle_workqueue = idle_work; + idle_work->running = true; + + dm_helpers_enable_periodic_detection(ctx, true); + KUNIT_EXPECT_TRUE(test, idle_work->enable); + + dm_helpers_enable_periodic_detection(ctx, false); + KUNIT_EXPECT_FALSE(test, idle_work->enable); +} + +/** + * dm_test_enable_periodic_detection_schedules_work - Test headless schedule path + * @test: The KUnit test context + */ +static void dm_test_enable_periodic_detection_schedules_work(struct kunit *test) +{ + struct dm_test_idle_work *idle_work; + struct amdgpu_device *adev; + struct dc_context *ctx; + + adev = dm_kunit_alloc_adev(test); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, idle_work); + + ctx->driver_context = adev; + adev->dm.ddev = &adev->ddev; + adev->dm.idle_workqueue = &idle_work->base; + INIT_WORK(&idle_work->base.work, dm_test_idle_work_func); + + dm_helpers_enable_periodic_detection(ctx, true); + flush_work(&idle_work->base.work); + + KUNIT_EXPECT_TRUE(test, idle_work->base.enable); + KUNIT_EXPECT_TRUE(test, idle_work->ran); +} + static struct kunit_case amdgpu_dm_helpers_test_cases[] = { /* edid_extract_panel_id */ KUNIT_CASE(dm_test_edid_extract_panel_id_basic), @@ -2127,6 +2636,38 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = { KUNIT_CASE(dm_test_fill_mst_payload_table_enable), KUNIT_CASE(dm_test_fill_mst_payload_table_disable), KUNIT_CASE(dm_test_fill_mst_payload_table_empty), + /* dm_helpers_submit_i2c */ + KUNIT_CASE(dm_test_submit_i2c_null_priv), + KUNIT_CASE(dm_test_submit_i2c_success), + KUNIT_CASE(dm_test_submit_i2c_partial_transfer), + /* dm_helper_dmub_aux_transfer_sync */ + KUNIT_CASE(dm_test_dmub_aux_transfer_sync_hpd_discon), + /* Empty stub functions */ + KUNIT_CASE(dm_test_dp_update_branch_info_no_crash), + KUNIT_CASE(dm_test_mst_poll_pending_down_reply_no_crash), + KUNIT_CASE(dm_test_mst_clear_payload_alloc_table_no_crash), + KUNIT_CASE(dm_test_set_dcn_clocks_no_crash), + KUNIT_CASE(dm_test_dmu_timeout_no_crash), + KUNIT_CASE(dm_test_smu_timeout_no_crash), + KUNIT_CASE(dm_test_set_phyd32clk_no_crash), + KUNIT_CASE(dm_test_mst_update_branch_bandwidth_no_crash), + /* MST null-connector early returns */ + KUNIT_CASE(dm_test_mst_write_payload_alloc_table_null_ctx), + KUNIT_CASE(dm_test_mst_poll_for_act_null_ctx), + /* dm_helpers_dp_mst_poll_for_allocation_change_trigger success/fail */ + KUNIT_CASE(dm_test_mst_send_payload_alloc_null_ctx), + KUNIT_CASE(dm_test_mst_update_mgr_dealloc_null_ctx), + /* dm_helpers_is_dp_sink_present */ + KUNIT_CASE(dm_test_is_dp_sink_present_null_priv), + /* dm_helpers_dmub_outbox_interrupt_control */ + KUNIT_CASE(dm_test_dmub_outbox_interrupt_control_null_dc), + /* dm_helpers_mst_enable_stream_features */ + KUNIT_CASE(dm_test_mst_enable_stream_features_aux_disabled), + KUNIT_CASE(dm_test_mst_enable_stream_features_writes_downspread), + /* dm_helpers_enable_periodic_detection */ + KUNIT_CASE(dm_test_enable_periodic_detection_no_workqueue), + KUNIT_CASE(dm_test_enable_periodic_detection_updates_enable), + KUNIT_CASE(dm_test_enable_periodic_detection_schedules_work), {} }; -- 2.55.0
