mirror of
https://github.com/torvalds/linux.git
synced 2026-07-29 02:31:27 +02:00
drm/amd/display: Add more KUnit tests for amdgpu_dm_ism
[Why & How] Add 8 more KUnit tests: - dm_ism_get_idle_allow_delay: add a case where filter_entry_count exceeds filter_history_size, exercising the max() branch in the history_size calculation. - amdgpu_dm_ism_init: verify all fields are initialised to expected values after construction. - amdgpu_dm_ism_fini: smoke-test cancellation of never-scheduled delayed work items paired with a preceding init. - dm_ism_set_last_idle_ts: verify last_idle_timestamp_ns is updated to at least the value captured before the call. - dm_ism_insert_record: verify index increment and duration calculation; verify out-of-bounds index wraps to slot 0. - dm_ism_trigger_event: verify current_state and previous_state are updated on a valid transition and left unchanged on an invalid one. Assisted-by: Copilot:Claude-Sonnet-4.6 Reviewed-by: Ray Wu <ray.wu@amd.com> Signed-off-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Ray Wu <ray.wu@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
2da6b0b28f
commit
a3142b13fe
|
|
@ -230,7 +230,8 @@ EXPORT_IF_KUNIT(dm_ism_get_idle_allow_delay);
|
||||||
* dm_ism_insert_record - Insert a record into the circular history buffer
|
* dm_ism_insert_record - Insert a record into the circular history buffer
|
||||||
* @ism: ISM instance
|
* @ism: ISM instance
|
||||||
*/
|
*/
|
||||||
static void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
|
STATIC_IFN_KUNIT
|
||||||
|
void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
|
||||||
{
|
{
|
||||||
struct amdgpu_dm_ism_record *record;
|
struct amdgpu_dm_ism_record *record;
|
||||||
|
|
||||||
|
|
@ -245,15 +246,19 @@ static void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
|
||||||
record->duration_ns =
|
record->duration_ns =
|
||||||
record->timestamp_ns - ism->last_idle_timestamp_ns;
|
record->timestamp_ns - ism->last_idle_timestamp_ns;
|
||||||
}
|
}
|
||||||
|
EXPORT_IF_KUNIT(dm_ism_insert_record);
|
||||||
|
|
||||||
|
|
||||||
static void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism)
|
STATIC_IFN_KUNIT
|
||||||
|
void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism)
|
||||||
{
|
{
|
||||||
ism->last_idle_timestamp_ns = ktime_get_ns();
|
ism->last_idle_timestamp_ns = ktime_get_ns();
|
||||||
}
|
}
|
||||||
|
EXPORT_IF_KUNIT(dm_ism_set_last_idle_ts);
|
||||||
|
|
||||||
|
|
||||||
static bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
|
STATIC_IFN_KUNIT
|
||||||
|
bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
|
||||||
enum amdgpu_dm_ism_event event)
|
enum amdgpu_dm_ism_event event)
|
||||||
{
|
{
|
||||||
enum amdgpu_dm_ism_state next_state;
|
enum amdgpu_dm_ism_state next_state;
|
||||||
|
|
@ -268,6 +273,7 @@ static bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
|
||||||
|
|
||||||
return gotNextState;
|
return gotNextState;
|
||||||
}
|
}
|
||||||
|
EXPORT_IF_KUNIT(dm_ism_trigger_event);
|
||||||
|
|
||||||
|
|
||||||
static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism,
|
static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism,
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,10 @@ uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
|
||||||
const struct dc_stream_state *stream);
|
const struct dc_stream_state *stream);
|
||||||
uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
|
uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
|
||||||
const struct dc_stream_state *stream);
|
const struct dc_stream_state *stream);
|
||||||
|
void dm_ism_insert_record(struct amdgpu_dm_ism *ism);
|
||||||
|
void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism);
|
||||||
|
bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
|
||||||
|
enum amdgpu_dm_ism_event event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -579,6 +579,208 @@ static void dm_test_ism_idle_delay_mixed_durations(struct kunit *test)
|
||||||
(uint64_t)0);
|
(uint64_t)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_idle_delay_entry_count_exceeds_history_size - entry_count > history_size sets delay
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_idle_delay_entry_count_exceeds_history_size(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||||
|
uint64_t one_frame_ns, expected;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* filter_entry_count (5) > filter_history_size (3), so history_size
|
||||||
|
* is determined by filter_entry_count via max(). All 5 records are
|
||||||
|
* short idles, triggering the delay.
|
||||||
|
*/
|
||||||
|
stream->timing.v_total = 1125;
|
||||||
|
stream->timing.h_total = 2200;
|
||||||
|
stream->timing.pix_clk_100hz = 1485000;
|
||||||
|
|
||||||
|
one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
|
||||||
|
1485000);
|
||||||
|
|
||||||
|
ism->config.filter_num_frames = 5;
|
||||||
|
ism->config.filter_entry_count = 5;
|
||||||
|
ism->config.filter_history_size = 3;
|
||||||
|
ism->config.activation_num_delay_frames = 10;
|
||||||
|
ism->config.filter_old_history_threshold = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
ism->records[i].duration_ns = one_frame_ns;
|
||||||
|
ism->records[i].timestamp_ns = 0;
|
||||||
|
}
|
||||||
|
ism->next_record_idx = 5;
|
||||||
|
|
||||||
|
expected = 10 * one_frame_ns;
|
||||||
|
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tests for amdgpu_dm_ism_init ===== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_init_sets_initial_state - all ISM fields initialized to expected values
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_init_sets_initial_state(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
struct amdgpu_dm_ism_config config = {
|
||||||
|
.filter_num_frames = 5,
|
||||||
|
.filter_entry_count = 3,
|
||||||
|
.activation_num_delay_frames = 10,
|
||||||
|
.filter_history_size = 8,
|
||||||
|
.filter_old_history_threshold = 20,
|
||||||
|
.sso_num_frames = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
amdgpu_dm_ism_init(ism, &config);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
|
||||||
|
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||||
|
KUNIT_EXPECT_EQ(test, (int)ism->previous_state,
|
||||||
|
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->next_record_idx, 0);
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->last_idle_timestamp_ns, (uint64_t)0);
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->config.filter_num_frames,
|
||||||
|
config.filter_num_frames);
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->config.filter_entry_count,
|
||||||
|
config.filter_entry_count);
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->config.activation_num_delay_frames,
|
||||||
|
config.activation_num_delay_frames);
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->config.sso_num_frames, config.sso_num_frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tests for amdgpu_dm_ism_fini ===== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_fini_after_init - fini cancels never-scheduled work without error
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_fini_after_init(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
struct amdgpu_dm_ism_config config = {
|
||||||
|
.filter_num_frames = 5,
|
||||||
|
.filter_entry_count = 3,
|
||||||
|
.activation_num_delay_frames = 10,
|
||||||
|
.sso_num_frames = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
amdgpu_dm_ism_init(ism, &config);
|
||||||
|
/* Work was never scheduled; cancel_delayed_work_sync is a no-op. */
|
||||||
|
amdgpu_dm_ism_fini(ism);
|
||||||
|
|
||||||
|
/* FSM state is untouched by fini */
|
||||||
|
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
|
||||||
|
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tests for dm_ism_set_last_idle_ts ===== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_set_last_idle_ts_updates_timestamp - last_idle_timestamp_ns updated to current time
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_set_last_idle_ts_updates_timestamp(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
uint64_t before;
|
||||||
|
|
||||||
|
ism->last_idle_timestamp_ns = 0;
|
||||||
|
before = ktime_get_ns();
|
||||||
|
dm_ism_set_last_idle_ts(ism);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_GE(test, ism->last_idle_timestamp_ns, before);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tests for dm_ism_insert_record ===== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_insert_record_basic - record inserted with correct index and duration
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_insert_record_basic(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
|
||||||
|
ism->last_idle_timestamp_ns = 0;
|
||||||
|
ism->next_record_idx = 0;
|
||||||
|
|
||||||
|
dm_ism_insert_record(ism);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->next_record_idx, 1);
|
||||||
|
KUNIT_EXPECT_GT(test, ism->records[0].timestamp_ns, (uint64_t)0);
|
||||||
|
/* duration = timestamp - last_idle_timestamp_ns (0) */
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->records[0].duration_ns,
|
||||||
|
ism->records[0].timestamp_ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_insert_record_wraps_around - out-of-bounds index wraps to slot 0
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_insert_record_wraps_around(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
|
||||||
|
ism->last_idle_timestamp_ns = 0;
|
||||||
|
/* Out-of-bounds index triggers reset to 0 */
|
||||||
|
ism->next_record_idx = AMDGPU_DM_IDLE_HIST_LEN;
|
||||||
|
|
||||||
|
dm_ism_insert_record(ism);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, ism->next_record_idx, 1);
|
||||||
|
KUNIT_EXPECT_GT(test, ism->records[0].timestamp_ns, (uint64_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tests for dm_ism_trigger_event ===== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_trigger_event_valid_transition - valid event advances current and previous state
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_trigger_event_valid_transition(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
ism->current_state = DM_ISM_STATE_FULL_POWER_RUNNING;
|
||||||
|
ism->previous_state = DM_ISM_STATE_FULL_POWER_RUNNING;
|
||||||
|
|
||||||
|
ok = dm_ism_trigger_event(ism, DM_ISM_EVENT_ENTER_IDLE_REQUESTED);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_TRUE(test, ok);
|
||||||
|
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
|
||||||
|
(int)DM_ISM_STATE_HYSTERESIS_WAITING);
|
||||||
|
KUNIT_EXPECT_EQ(test, (int)ism->previous_state,
|
||||||
|
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dm_test_ism_trigger_event_invalid_transition - invalid event leaves state unchanged
|
||||||
|
* @test: KUnit test context
|
||||||
|
*/
|
||||||
|
static void dm_test_ism_trigger_event_invalid_transition(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
ism->current_state = DM_ISM_STATE_FULL_POWER_RUNNING;
|
||||||
|
ism->previous_state = DM_ISM_STATE_FULL_POWER_RUNNING;
|
||||||
|
|
||||||
|
/* EXIT_IDLE_REQUESTED is not valid from FULL_POWER_RUNNING */
|
||||||
|
ok = dm_ism_trigger_event(ism, DM_ISM_EVENT_EXIT_IDLE_REQUESTED);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_FALSE(test, ok);
|
||||||
|
/* State must remain unchanged on invalid transition */
|
||||||
|
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
|
||||||
|
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||||
|
KUNIT_EXPECT_EQ(test, (int)ism->previous_state,
|
||||||
|
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
static struct kunit_case dm_ism_test_cases[] = {
|
static struct kunit_case dm_ism_test_cases[] = {
|
||||||
/* dm_ism_next_state — FULL_POWER_RUNNING */
|
/* dm_ism_next_state — FULL_POWER_RUNNING */
|
||||||
KUNIT_CASE(dm_test_ism_next_state_running_enter_idle),
|
KUNIT_CASE(dm_test_ism_next_state_running_enter_idle),
|
||||||
|
|
@ -621,6 +823,19 @@ static struct kunit_case dm_ism_test_cases[] = {
|
||||||
KUNIT_CASE(dm_test_ism_idle_delay_wraps_around_buffer),
|
KUNIT_CASE(dm_test_ism_idle_delay_wraps_around_buffer),
|
||||||
KUNIT_CASE(dm_test_ism_idle_delay_old_history_cutoff),
|
KUNIT_CASE(dm_test_ism_idle_delay_old_history_cutoff),
|
||||||
KUNIT_CASE(dm_test_ism_idle_delay_mixed_durations),
|
KUNIT_CASE(dm_test_ism_idle_delay_mixed_durations),
|
||||||
|
KUNIT_CASE(dm_test_ism_idle_delay_entry_count_exceeds_history_size),
|
||||||
|
/* amdgpu_dm_ism_init */
|
||||||
|
KUNIT_CASE(dm_test_ism_init_sets_initial_state),
|
||||||
|
/* amdgpu_dm_ism_fini */
|
||||||
|
KUNIT_CASE(dm_test_ism_fini_after_init),
|
||||||
|
/* dm_ism_set_last_idle_ts */
|
||||||
|
KUNIT_CASE(dm_test_ism_set_last_idle_ts_updates_timestamp),
|
||||||
|
/* dm_ism_insert_record */
|
||||||
|
KUNIT_CASE(dm_test_ism_insert_record_basic),
|
||||||
|
KUNIT_CASE(dm_test_ism_insert_record_wraps_around),
|
||||||
|
/* dm_ism_trigger_event */
|
||||||
|
KUNIT_CASE(dm_test_ism_trigger_event_valid_transition),
|
||||||
|
KUNIT_CASE(dm_test_ism_trigger_event_invalid_transition),
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user