Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/amd/display: Add Idle state manager(ISM)

[Why]

Rapid allow/disallow of idle optimization calls, whether it be IPS or
self-refresh features, can end up using more power if actual
time-in-idle is low. It can also spam DMUB command submission in a way
that prevents it from servicing other requestors.

[How]

Introduce the Idle State Manager (ISM) to amdgpu. It maintains a finite
state machine that uses a hysteresis to determine if a delay should be
inserted between a caller allowing idle, and when the actual idle
optimizations are programmed.

A second timer is also introduced to enable static screen optimizations
(SSO) such as PSR1 and Replay low HZ idle mode. Rapid SSO enable/disable
can have a negative power impact on some low hz video playback, and can
introduce user lag for PSR1 (due to up to 3 frames of sync latency).

This effectively rate-limits idle optimizations, based on hysteresis.

This also replaces the existing delay logic used for PSR1, allowing
drm_vblank_crtc_config.disable_immediate = true, and thus allowing
drm_crtc_vblank_restore().

v2:
* Loosen criteria for ISM to exit idle optimizations; it failed to exit
idle correctly on cursor updates when there are no drm_vblank
requestors,
* Document default_ism_config
* Convert pr_debug to trace events to reduce overhead on frequent
codepaths
* checkpatch.pl fixes

Link: https://gitlab.freedesktop.org/drm/amd/-/issues/4527
Link: https://gitlab.freedesktop.org/drm/amd/-/issues/3709
Fixes: 58a261bfc967 ("drm/amd/display: use a more lax vblank enable policy for older ASICs")
Signed-off-by: Ray Wu <ray.wu@amd.com>
Signed-off-by: Leo Li <sunpeng.li@amd.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Ray Wu and committed by
Alex Deucher
75400348 e4b1715a

+903 -63
+5
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
··· 44 44 #include <drm/display/drm_dp_mst_helper.h> 45 45 #include "modules/inc/mod_freesync.h" 46 46 #include "amdgpu_dm_irq_params.h" 47 + #include "amdgpu_dm_ism.h" 47 48 48 49 struct amdgpu_bo; 49 50 struct amdgpu_device; ··· 487 486 int deferred_flip_completion; 488 487 /* parameters access from DM IRQ handler */ 489 488 struct dm_irq_params dm_irq_params; 489 + 490 + /* DM idle state manager */ 491 + struct amdgpu_dm_ism ism; 492 + 490 493 /* pll sharing */ 491 494 struct amdgpu_atom_ss ss; 492 495 bool ss_enabled;
+2 -1
drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
··· 40 40 amdgpu_dm_replay.o \ 41 41 amdgpu_dm_quirks.o \ 42 42 amdgpu_dm_wb.o \ 43 - amdgpu_dm_colorop.o 43 + amdgpu_dm_colorop.o \ 44 + amdgpu_dm_ism.o 44 45 45 46 ifdef CONFIG_DRM_AMD_DC_FP 46 47 AMDGPUDM += dc_fpu.o
+9 -25
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 3283 3283 3284 3284 mutex_lock(&dm->dc_lock); 3285 3285 3286 + amdgpu_dm_ism_disable(dm); 3286 3287 dc_allow_idle_optimizations(adev->dm.dc, false); 3287 3288 3288 3289 dm->cached_dc_state = dc_state_create_copy(dm->dc->current_state); ··· 3316 3315 s3_handle_mst(adev_to_drm(adev), true); 3317 3316 3318 3317 amdgpu_dm_irq_suspend(adev); 3318 + 3319 + scoped_guard(mutex, &dm->dc_lock) 3320 + amdgpu_dm_ism_disable(dm); 3319 3321 3320 3322 hpd_rx_irq_work_suspend(dm); 3321 3323 ··· 3610 3606 3611 3607 dc_resume(dm->dc); 3612 3608 3609 + amdgpu_dm_ism_enable(dm); 3613 3610 amdgpu_dm_irq_resume_early(adev); 3614 3611 3615 3612 for (i = 0; i < dc_state->stream_count; i++) { ··· 3670 3665 3671 3666 /* program HPD filter */ 3672 3667 dc_resume(dm->dc); 3668 + 3669 + scoped_guard(mutex, &dm->dc_lock) 3670 + amdgpu_dm_ism_enable(dm); 3673 3671 3674 3672 /* 3675 3673 * early enable HPD Rx IRQ, should be done before set mode as short ··· 9342 9334 if (acrtc_state) { 9343 9335 timing = &acrtc_state->stream->timing; 9344 9336 9345 - /* 9346 - * Depending on when the HW latching event of double-buffered 9347 - * registers happen relative to the PSR SDP deadline, and how 9348 - * bad the Panel clock has drifted since the last ALPM off 9349 - * event, there can be up to 3 frames of delay between sending 9350 - * the PSR exit cmd to DMUB fw, and when the panel starts 9351 - * displaying live frames. 9352 - * 9353 - * We can set: 9354 - * 9355 - * 20/100 * offdelay_ms = 3_frames_ms 9356 - * => offdelay_ms = 5 * 3_frames_ms 9357 - * 9358 - * This ensures that `3_frames_ms` will only be experienced as a 9359 - * 20% delay on top how long the display has been static, and 9360 - * thus make the delay less perceivable. 9361 - */ 9362 - if (acrtc_state->stream->link->psr_settings.psr_version < 9363 - DC_PSR_VERSION_UNSUPPORTED) { 9364 - offdelay = DIV64_U64_ROUND_UP((u64)5 * 3 * 10 * 9365 - timing->v_total * 9366 - timing->h_total, 9367 - timing->pix_clk_100hz); 9368 - config.offdelay_ms = offdelay ?: 30; 9369 - } else if (amdgpu_ip_version(adev, DCE_HWIP, 0) < 9337 + if (amdgpu_ip_version(adev, DCE_HWIP, 0) < 9370 9338 IP_VERSION(3, 5, 0) || 9371 9339 !(adev->flags & AMD_IS_APU)) { 9372 9340 /*
+53 -37
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
··· 124 124 * - Enable condition same as above 125 125 * - Disable when vblank counter is enabled 126 126 */ 127 - static void amdgpu_dm_crtc_set_panel_sr_feature( 128 - struct vblank_control_work *vblank_work, 127 + void amdgpu_dm_crtc_set_panel_sr_feature( 128 + struct amdgpu_display_manager *dm, 129 + struct amdgpu_crtc *acrtc, 130 + struct dc_stream_state *stream, 129 131 bool vblank_enabled, bool allow_sr_entry) 130 132 { 131 - struct dc_link *link = vblank_work->stream->link; 133 + struct dc_link *link = stream->link; 132 134 bool is_sr_active = (link->replay_settings.replay_allow_active || 133 135 link->psr_settings.psr_allow_active); 134 136 bool is_crc_window_active = false; 135 - bool vrr_active = amdgpu_dm_crtc_vrr_active_irq(vblank_work->acrtc); 137 + bool vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); 136 138 137 139 #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY 138 140 is_crc_window_active = 139 - amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base); 141 + amdgpu_dm_crc_window_is_activated(&acrtc->base); 140 142 #endif 141 143 142 144 if (link->replay_settings.replay_feature_enabled && !vrr_active && 143 145 allow_sr_entry && !is_sr_active && !is_crc_window_active) { 144 - amdgpu_dm_replay_enable(vblank_work->stream, true); 146 + amdgpu_dm_replay_enable(stream, true); 145 147 } else if (vblank_enabled) { 146 148 if (link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && is_sr_active) 147 - amdgpu_dm_psr_disable(vblank_work->stream, false); 149 + amdgpu_dm_psr_disable(stream, false); 148 150 } else if (link->psr_settings.psr_feature_enabled && !vrr_active && 149 151 allow_sr_entry && !is_sr_active && !is_crc_window_active) { 150 152 151 153 struct amdgpu_dm_connector *aconn = 152 - (struct amdgpu_dm_connector *) vblank_work->stream->dm_stream_context; 154 + (struct amdgpu_dm_connector *) stream->dm_stream_context; 153 155 154 156 if (!aconn->disallow_edp_enter_psr) { 155 - struct amdgpu_display_manager *dm = vblank_work->dm; 156 - 157 - amdgpu_dm_psr_enable(vblank_work->stream); 157 + amdgpu_dm_psr_enable(stream); 158 158 if (dm->idle_workqueue && 159 159 (dm->dc->config.disable_ips == DMUB_IPS_ENABLE) && 160 160 dm->dc->idle_optimizations_allowed && ··· 251 251 252 252 mutex_lock(&dm->dc_lock); 253 253 254 - if (vblank_work->enable) 254 + if (vblank_work->enable) { 255 255 dm->active_vblank_irq_count++; 256 - else if (dm->active_vblank_irq_count) 257 - dm->active_vblank_irq_count--; 258 - 259 - if (dm->active_vblank_irq_count > 0) 260 - dc_allow_idle_optimizations(dm->dc, false); 261 - 262 - /* 263 - * Control PSR based on vblank requirements from OS 264 - * 265 - * If panel supports PSR SU, there's no need to disable PSR when OS is 266 - * submitting fast atomic commits (we infer this by whether the OS 267 - * requests vblank events). Fast atomic commits will simply trigger a 268 - * full-frame-update (FFU); a specific case of selective-update (SU) 269 - * where the SU region is the full hactive*vactive region. See 270 - * fill_dc_dirty_rects(). 271 - */ 272 - if (vblank_work->stream && vblank_work->stream->link && vblank_work->acrtc) { 273 - amdgpu_dm_crtc_set_panel_sr_feature( 274 - vblank_work, vblank_work->enable, 275 - vblank_work->acrtc->dm_irq_params.allow_sr_entry); 276 - } 277 - 278 - if (dm->active_vblank_irq_count == 0) { 279 - dc_post_update_surfaces_to_stream(dm->dc); 280 - dc_allow_idle_optimizations(dm->dc, true); 256 + amdgpu_dm_ism_commit_event(&vblank_work->acrtc->ism, 257 + DM_ISM_EVENT_EXIT_IDLE_REQUESTED); 258 + } else { 259 + if (dm->active_vblank_irq_count > 0) 260 + dm->active_vblank_irq_count--; 261 + amdgpu_dm_ism_commit_event(&vblank_work->acrtc->ism, 262 + DM_ISM_EVENT_ENTER_IDLE_REQUESTED); 281 263 } 282 264 283 265 mutex_unlock(&dm->dc_lock); ··· 458 476 459 477 static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc) 460 478 { 479 + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); 480 + 481 + amdgpu_dm_ism_fini(&acrtc->ism); 461 482 drm_crtc_cleanup(crtc); 462 483 kfree(crtc); 463 484 } ··· 704 719 .get_scanout_position = amdgpu_crtc_get_scanout_position, 705 720 }; 706 721 722 + /* 723 + * This hysteresis filter as configured will: 724 + * 725 + * * Search through the latest 8[filter_history_size] entries in history, 726 + * skipping entries that are older than [filter_old_history_threshold] frames 727 + * (0 means ignore age) 728 + * * Searches for short-idle-periods that lasted shorter than 729 + * 4[filter_num_frames] frames-times 730 + * * If there is at least 1[filter_entry_count] short-idle-period, then a delay 731 + * of 4[activation_num_delay_frames] will applied before allowing idle 732 + * optimizations again. 733 + * * An additional delay of 11[sso_num_frames] is applied before enabling 734 + * panel-specific optimizations. 735 + * 736 + * The values were determined empirically on another OS, optimizing for Z8 737 + * residency on APUs when running a productivity + web browsing test. 738 + * 739 + * TODO: Run similar tests to determine if these values are also optimal for 740 + * Linux, and if each APU generation benefits differently. 741 + */ 742 + static struct amdgpu_dm_ism_config default_ism_config = { 743 + .filter_num_frames = 4, 744 + .filter_history_size = 8, 745 + .filter_entry_count = 1, 746 + .activation_num_delay_frames = 4, 747 + .filter_old_history_threshold = 0, 748 + .sso_num_frames = 11, 749 + }; 750 + 707 751 int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, 708 752 struct drm_plane *plane, 709 753 uint32_t crtc_index) ··· 762 748 763 749 if (res) 764 750 goto fail; 751 + 752 + amdgpu_dm_ism_init(&acrtc->ism, &default_ism_config); 765 753 766 754 drm_crtc_helper_add(&acrtc->base, &amdgpu_dm_crtc_helper_funcs); 767 755
+6
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h
··· 27 27 #ifndef __AMDGPU_DM_CRTC_H__ 28 28 #define __AMDGPU_DM_CRTC_H__ 29 29 30 + void amdgpu_dm_crtc_set_panel_sr_feature( 31 + struct amdgpu_display_manager *dm, 32 + struct amdgpu_crtc *acrtc, 33 + struct dc_stream_state *stream, 34 + bool vblank_enabled, bool allow_sr_entry); 35 + 30 36 void amdgpu_dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc); 31 37 32 38 bool amdgpu_dm_crtc_modeset_required(struct drm_crtc_state *crtc_state,
+598
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
··· 1 + // SPDX-License-Identifier: MIT 2 + /* 3 + * Copyright 2026 Advanced Micro Devices, Inc. 4 + * 5 + * Permission is hereby granted, free of charge, to any person obtaining a 6 + * copy of this software and associated documentation files (the "Software"), 7 + * to deal in the Software without restriction, including without limitation 8 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 + * and/or sell copies of the Software, and to permit persons to whom the 10 + * Software is furnished to do so, subject to the following conditions: 11 + * 12 + * The above copyright notice and this permission notice shall be included in 13 + * all copies or substantial portions of the Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 + * OTHER DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: AMD 24 + * 25 + */ 26 + 27 + #include <linux/types.h> 28 + #include <drm/drm_vblank.h> 29 + 30 + #include "dc.h" 31 + #include "amdgpu.h" 32 + #include "amdgpu_dm_ism.h" 33 + #include "amdgpu_dm_crtc.h" 34 + #include "amdgpu_dm_trace.h" 35 + 36 + /** 37 + * dm_ism_next_state - Get next state based on current state and event 38 + * 39 + * This function defines the idle state management FSM. Invalid transitions 40 + * are ignored and will not progress the FSM. 41 + */ 42 + static bool dm_ism_next_state(enum amdgpu_dm_ism_state current_state, 43 + enum amdgpu_dm_ism_event event, 44 + enum amdgpu_dm_ism_state *next_state) 45 + { 46 + switch (STATE_EVENT(current_state, event)) { 47 + case STATE_EVENT(DM_ISM_STATE_FULL_POWER_RUNNING, 48 + DM_ISM_EVENT_ENTER_IDLE_REQUESTED): 49 + *next_state = DM_ISM_STATE_HYSTERESIS_WAITING; 50 + break; 51 + case STATE_EVENT(DM_ISM_STATE_FULL_POWER_RUNNING, 52 + DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 53 + *next_state = DM_ISM_STATE_FULL_POWER_BUSY; 54 + break; 55 + 56 + case STATE_EVENT(DM_ISM_STATE_FULL_POWER_BUSY, 57 + DM_ISM_EVENT_ENTER_IDLE_REQUESTED): 58 + *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 59 + break; 60 + case STATE_EVENT(DM_ISM_STATE_FULL_POWER_BUSY, 61 + DM_ISM_EVENT_END_CURSOR_UPDATE): 62 + *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 63 + break; 64 + 65 + case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 66 + DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 67 + *next_state = DM_ISM_STATE_TIMER_ABORTED; 68 + break; 69 + case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 70 + DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 71 + *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 72 + break; 73 + case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 74 + DM_ISM_EVENT_TIMER_ELAPSED): 75 + *next_state = DM_ISM_STATE_OPTIMIZED_IDLE; 76 + break; 77 + case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 78 + DM_ISM_EVENT_IMMEDIATE): 79 + *next_state = DM_ISM_STATE_OPTIMIZED_IDLE; 80 + break; 81 + 82 + case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_BUSY, 83 + DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 84 + *next_state = DM_ISM_STATE_FULL_POWER_BUSY; 85 + break; 86 + case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_BUSY, 87 + DM_ISM_EVENT_END_CURSOR_UPDATE): 88 + *next_state = DM_ISM_STATE_HYSTERESIS_WAITING; 89 + break; 90 + 91 + case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 92 + DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 93 + *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 94 + break; 95 + case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 96 + DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 97 + *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 98 + break; 99 + case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 100 + DM_ISM_EVENT_SSO_TIMER_ELAPSED): 101 + case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 102 + DM_ISM_EVENT_IMMEDIATE): 103 + *next_state = DM_ISM_STATE_OPTIMIZED_IDLE_SSO; 104 + break; 105 + 106 + case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE_SSO, 107 + DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 108 + *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 109 + break; 110 + case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE_SSO, 111 + DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 112 + *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 113 + break; 114 + 115 + case STATE_EVENT(DM_ISM_STATE_TIMER_ABORTED, 116 + DM_ISM_EVENT_IMMEDIATE): 117 + *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 118 + break; 119 + 120 + default: 121 + return false; 122 + } 123 + return true; 124 + } 125 + 126 + static uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism, 127 + const struct dc_stream_state *stream) 128 + { 129 + const struct amdgpu_dm_ism_config *config = &ism->config; 130 + uint32_t v_total, h_total; 131 + uint64_t one_frame_ns, sso_delay_ns; 132 + 133 + if (!stream) 134 + return 0; 135 + 136 + if (!config->sso_num_frames) 137 + return 0; 138 + 139 + v_total = stream->timing.v_total; 140 + h_total = stream->timing.h_total; 141 + 142 + one_frame_ns = div64_u64(v_total * h_total * 10000000ull, 143 + stream->timing.pix_clk_100hz); 144 + sso_delay_ns = config->sso_num_frames * one_frame_ns; 145 + 146 + return sso_delay_ns; 147 + } 148 + 149 + /** 150 + * dm_ism_get_idle_allow_delay - Calculate hysteresis-based idle allow delay 151 + */ 152 + static uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism, 153 + const struct dc_stream_state *stream) 154 + { 155 + const struct amdgpu_dm_ism_config *config = &ism->config; 156 + uint32_t v_total, h_total; 157 + uint64_t one_frame_ns, short_idle_ns, old_hist_ns; 158 + uint32_t history_size; 159 + int pos; 160 + uint32_t short_idle_count = 0; 161 + uint64_t ret_ns = 0; 162 + 163 + if (!stream) 164 + return 0; 165 + 166 + if (!config->filter_num_frames) 167 + return 0; 168 + if (!config->filter_entry_count) 169 + return 0; 170 + if (!config->activation_num_delay_frames) 171 + return 0; 172 + 173 + v_total = stream->timing.v_total; 174 + h_total = stream->timing.h_total; 175 + 176 + one_frame_ns = div64_u64(v_total * h_total * 10000000ull, 177 + stream->timing.pix_clk_100hz); 178 + 179 + short_idle_ns = config->filter_num_frames * one_frame_ns; 180 + old_hist_ns = config->filter_old_history_threshold * one_frame_ns; 181 + 182 + /* 183 + * Look back into the recent history and count how many times we entered 184 + * idle power state for a short duration of time 185 + */ 186 + history_size = min( 187 + max(config->filter_history_size, config->filter_entry_count), 188 + AMDGPU_DM_IDLE_HIST_LEN); 189 + pos = ism->next_record_idx; 190 + 191 + for (int k = 0; k < history_size; k++) { 192 + if (pos <= 0 || pos > AMDGPU_DM_IDLE_HIST_LEN) 193 + pos = AMDGPU_DM_IDLE_HIST_LEN; 194 + pos -= 1; 195 + 196 + if (ism->records[pos].duration_ns <= short_idle_ns) 197 + short_idle_count += 1; 198 + 199 + if (short_idle_count >= config->filter_entry_count) 200 + break; 201 + 202 + if (old_hist_ns > 0 && 203 + ism->last_idle_timestamp_ns - ism->records[pos].timestamp_ns > old_hist_ns) 204 + break; 205 + } 206 + 207 + if (short_idle_count >= config->filter_entry_count) 208 + ret_ns = config->activation_num_delay_frames * one_frame_ns; 209 + 210 + return ret_ns; 211 + } 212 + 213 + /** 214 + * dm_ism_insert_record - Insert a record into the circular history buffer 215 + */ 216 + static void dm_ism_insert_record(struct amdgpu_dm_ism *ism) 217 + { 218 + struct amdgpu_dm_ism_record *record; 219 + 220 + if (ism->next_record_idx < 0 || 221 + ism->next_record_idx >= AMDGPU_DM_IDLE_HIST_LEN) 222 + ism->next_record_idx = 0; 223 + 224 + record = &ism->records[ism->next_record_idx]; 225 + ism->next_record_idx += 1; 226 + 227 + record->timestamp_ns = ktime_get_ns(); 228 + record->duration_ns = 229 + record->timestamp_ns - ism->last_idle_timestamp_ns; 230 + } 231 + 232 + 233 + static void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism) 234 + { 235 + ism->last_idle_timestamp_ns = ktime_get_ns(); 236 + } 237 + 238 + 239 + static bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism, 240 + enum amdgpu_dm_ism_event event) 241 + { 242 + enum amdgpu_dm_ism_state next_state; 243 + 244 + bool gotNextState = dm_ism_next_state(ism->current_state, event, 245 + &next_state); 246 + 247 + if (gotNextState) { 248 + ism->previous_state = ism->current_state; 249 + ism->current_state = next_state; 250 + } 251 + 252 + return gotNextState; 253 + } 254 + 255 + 256 + static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism, 257 + struct dc_stream_state *stream, 258 + bool vblank_enabled, 259 + bool allow_panel_sso) 260 + { 261 + struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 262 + struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 263 + struct amdgpu_display_manager *dm = &adev->dm; 264 + int r; 265 + 266 + trace_amdgpu_dm_ism_commit(dm->active_vblank_irq_count, 267 + vblank_enabled, 268 + allow_panel_sso); 269 + 270 + /* 271 + * If there is an active vblank requestor, or if SSO is being engaged, 272 + * then disallow idle optimizations. 273 + */ 274 + if (vblank_enabled || allow_panel_sso) 275 + dc_allow_idle_optimizations(dm->dc, false); 276 + 277 + /* 278 + * Control PSR based on vblank requirements from OS 279 + * 280 + * If panel supports PSR SU/Replay, there's no need to exit self-refresh 281 + * when OS is submitting fast atomic commits, as they can allow 282 + * self-refresh during vblank periods. 283 + */ 284 + if (stream && stream->link) { 285 + /* 286 + * If allow_panel_sso is true when disabling vblank, allow 287 + * deeper panel sleep states such as PSR1 and Replay static 288 + * screen optimization. 289 + */ 290 + if (!vblank_enabled && allow_panel_sso) { 291 + amdgpu_dm_crtc_set_panel_sr_feature( 292 + dm, acrtc, stream, false, 293 + acrtc->dm_irq_params.allow_sr_entry); 294 + } else if (vblank_enabled) { 295 + /* Make sure to exit SSO on vblank enable */ 296 + amdgpu_dm_crtc_set_panel_sr_feature( 297 + dm, acrtc, stream, true, 298 + acrtc->dm_irq_params.allow_sr_entry); 299 + } 300 + /* 301 + * Else, vblank_enabled == false and allow_panel_sso == false; 302 + * do nothing here. 303 + */ 304 + } 305 + 306 + /* 307 + * Check for any active drm vblank requestors on other CRTCs 308 + * (dm->active_vblank_irq_count) before allowing HW-wide idle 309 + * optimizations. 310 + * 311 + * There's no need to have a "balanced" check when disallowing idle 312 + * optimizations at the start of this func -- we should disallow 313 + * whenever there's *an* active CRTC. 314 + */ 315 + if (!vblank_enabled && dm->active_vblank_irq_count == 0) { 316 + dc_post_update_surfaces_to_stream(dm->dc); 317 + 318 + r = amdgpu_dpm_pause_power_profile(adev, true); 319 + if (r) 320 + dev_warn(adev->dev, "failed to set default power profile mode\n"); 321 + 322 + dc_allow_idle_optimizations(dm->dc, true); 323 + 324 + r = amdgpu_dpm_pause_power_profile(adev, false); 325 + if (r) 326 + dev_warn(adev->dev, "failed to restore the power profile mode\n"); 327 + } 328 + } 329 + 330 + 331 + static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state( 332 + struct amdgpu_dm_ism *ism, 333 + struct dm_crtc_state *acrtc_state, 334 + enum amdgpu_dm_ism_event event) 335 + { 336 + enum amdgpu_dm_ism_event ret = event; 337 + const struct amdgpu_dm_ism_config *config = &ism->config; 338 + uint64_t delay_ns, sso_delay_ns; 339 + 340 + switch (ism->previous_state) { 341 + case DM_ISM_STATE_HYSTERESIS_WAITING: 342 + /* 343 + * Stop the timer if it was set, and we're not running from the 344 + * idle allow worker. 345 + */ 346 + if (ism->current_state != DM_ISM_STATE_OPTIMIZED_IDLE && 347 + ism->current_state != DM_ISM_STATE_OPTIMIZED_IDLE_SSO) 348 + cancel_delayed_work(&ism->delayed_work); 349 + break; 350 + case DM_ISM_STATE_OPTIMIZED_IDLE: 351 + if (ism->current_state == DM_ISM_STATE_OPTIMIZED_IDLE_SSO) 352 + break; 353 + /* If idle disallow, cancel SSO work and insert record */ 354 + cancel_delayed_work(&ism->sso_delayed_work); 355 + dm_ism_insert_record(ism); 356 + dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 357 + true, false); 358 + break; 359 + case DM_ISM_STATE_OPTIMIZED_IDLE_SSO: 360 + /* Disable idle optimization */ 361 + dm_ism_insert_record(ism); 362 + dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 363 + true, false); 364 + break; 365 + default: 366 + break; 367 + } 368 + 369 + switch (ism->current_state) { 370 + case DM_ISM_STATE_HYSTERESIS_WAITING: 371 + dm_ism_set_last_idle_ts(ism); 372 + 373 + /* CRTC can be disabled; allow immediate idle */ 374 + if (!acrtc_state->stream) { 375 + ret = DM_ISM_EVENT_IMMEDIATE; 376 + break; 377 + } 378 + 379 + delay_ns = dm_ism_get_idle_allow_delay(ism, 380 + acrtc_state->stream); 381 + if (delay_ns == 0) { 382 + ret = DM_ISM_EVENT_IMMEDIATE; 383 + break; 384 + } 385 + 386 + /* Schedule worker */ 387 + mod_delayed_work(system_unbound_wq, &ism->delayed_work, 388 + nsecs_to_jiffies(delay_ns)); 389 + 390 + break; 391 + case DM_ISM_STATE_OPTIMIZED_IDLE: 392 + sso_delay_ns = dm_ism_get_sso_delay(ism, acrtc_state->stream); 393 + if (sso_delay_ns == 0) 394 + ret = DM_ISM_EVENT_IMMEDIATE; 395 + else if (config->sso_num_frames < config->filter_num_frames) { 396 + /* 397 + * If sso_num_frames is less than hysteresis frames, it 398 + * indicates that allowing idle here, then disallowing 399 + * idle after sso_num_frames has expired, will likely 400 + * have a negative power impact. Skip idle allow here, 401 + * and let the sso_delayed_work handle it. 402 + */ 403 + mod_delayed_work(system_unbound_wq, 404 + &ism->sso_delayed_work, 405 + nsecs_to_jiffies(sso_delay_ns)); 406 + } else { 407 + /* Enable idle optimization without SSO */ 408 + dm_ism_commit_idle_optimization_state( 409 + ism, acrtc_state->stream, false, false); 410 + mod_delayed_work(system_unbound_wq, 411 + &ism->sso_delayed_work, 412 + nsecs_to_jiffies(sso_delay_ns)); 413 + } 414 + break; 415 + case DM_ISM_STATE_OPTIMIZED_IDLE_SSO: 416 + /* Enable static screen optimizations. */ 417 + dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 418 + false, true); 419 + break; 420 + case DM_ISM_STATE_TIMER_ABORTED: 421 + dm_ism_insert_record(ism); 422 + dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 423 + true, false); 424 + ret = DM_ISM_EVENT_IMMEDIATE; 425 + break; 426 + default: 427 + break; 428 + } 429 + 430 + return ret; 431 + } 432 + 433 + static char *dm_ism_events_str[DM_ISM_NUM_EVENTS] = { 434 + [DM_ISM_EVENT_IMMEDIATE] = "IMMEDIATE", 435 + [DM_ISM_EVENT_ENTER_IDLE_REQUESTED] = "ENTER_IDLE_REQUESTED", 436 + [DM_ISM_EVENT_EXIT_IDLE_REQUESTED] = "EXIT_IDLE_REQUESTED", 437 + [DM_ISM_EVENT_BEGIN_CURSOR_UPDATE] = "BEGIN_CURSOR_UPDATE", 438 + [DM_ISM_EVENT_END_CURSOR_UPDATE] = "END_CURSOR_UPDATE", 439 + [DM_ISM_EVENT_TIMER_ELAPSED] = "TIMER_ELAPSED", 440 + [DM_ISM_EVENT_SSO_TIMER_ELAPSED] = "SSO_TIMER_ELAPSED", 441 + }; 442 + 443 + static char *dm_ism_states_str[DM_ISM_NUM_STATES] = { 444 + [DM_ISM_STATE_FULL_POWER_RUNNING] = "FULL_POWER_RUNNING", 445 + [DM_ISM_STATE_FULL_POWER_BUSY] = "FULL_POWER_BUSY", 446 + [DM_ISM_STATE_HYSTERESIS_WAITING] = "HYSTERESIS_WAITING", 447 + [DM_ISM_STATE_HYSTERESIS_BUSY] = "HYSTERESIS_BUSY", 448 + [DM_ISM_STATE_OPTIMIZED_IDLE] = "OPTIMIZED_IDLE", 449 + [DM_ISM_STATE_OPTIMIZED_IDLE_SSO] = "OPTIMIZED_IDLE_SSO", 450 + [DM_ISM_STATE_TIMER_ABORTED] = "TIMER_ABORTED", 451 + }; 452 + 453 + 454 + void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism, 455 + enum amdgpu_dm_ism_event event) 456 + { 457 + enum amdgpu_dm_ism_event next_event = event; 458 + struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 459 + struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 460 + struct amdgpu_display_manager *dm = &adev->dm; 461 + struct dm_crtc_state *acrtc_state = to_dm_crtc_state(acrtc->base.state); 462 + 463 + /* ISM transitions must be called with mutex acquired */ 464 + ASSERT(mutex_is_locked(&dm->dc_lock)); 465 + 466 + if (!acrtc_state) { 467 + trace_amdgpu_dm_ism_event(acrtc->crtc_id, "NO_STATE", 468 + "NO_STATE", "N/A"); 469 + return; 470 + } 471 + 472 + do { 473 + bool transition = dm_ism_trigger_event(ism, event); 474 + 475 + next_event = DM_ISM_NUM_EVENTS; 476 + if (transition) { 477 + trace_amdgpu_dm_ism_event( 478 + acrtc->crtc_id, 479 + dm_ism_states_str[ism->previous_state], 480 + dm_ism_states_str[ism->current_state], 481 + dm_ism_events_str[event]); 482 + next_event = dm_ism_dispatch_power_state( 483 + ism, acrtc_state, next_event); 484 + } else { 485 + trace_amdgpu_dm_ism_event( 486 + acrtc->crtc_id, 487 + dm_ism_states_str[ism->current_state], 488 + dm_ism_states_str[ism->current_state], 489 + dm_ism_events_str[event]); 490 + } 491 + 492 + event = next_event; 493 + 494 + } while (next_event < DM_ISM_NUM_EVENTS); 495 + } 496 + 497 + 498 + static void dm_ism_delayed_work_func(struct work_struct *work) 499 + { 500 + struct amdgpu_dm_ism *ism = 501 + container_of(work, struct amdgpu_dm_ism, delayed_work.work); 502 + struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 503 + struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 504 + struct amdgpu_display_manager *dm = &adev->dm; 505 + 506 + guard(mutex)(&dm->dc_lock); 507 + 508 + amdgpu_dm_ism_commit_event(ism, DM_ISM_EVENT_TIMER_ELAPSED); 509 + } 510 + 511 + static void dm_ism_sso_delayed_work_func(struct work_struct *work) 512 + { 513 + struct amdgpu_dm_ism *ism = 514 + container_of(work, struct amdgpu_dm_ism, sso_delayed_work.work); 515 + struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 516 + struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 517 + struct amdgpu_display_manager *dm = &adev->dm; 518 + 519 + guard(mutex)(&dm->dc_lock); 520 + 521 + amdgpu_dm_ism_commit_event(ism, DM_ISM_EVENT_SSO_TIMER_ELAPSED); 522 + } 523 + 524 + /** 525 + * amdgpu_dm_ism_disable - Disable the ISM 526 + * 527 + * @dm: The amdgpu display manager 528 + * 529 + * Disable the idle state manager by disabling any ISM work, canceling pending 530 + * work, and waiting for in-progress work to finish. After disabling, the system 531 + * is left in DM_ISM_STATE_FULL_POWER_RUNNING state. 532 + */ 533 + void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm) 534 + { 535 + struct drm_crtc *crtc; 536 + struct amdgpu_crtc *acrtc; 537 + struct amdgpu_dm_ism *ism; 538 + 539 + drm_for_each_crtc(crtc, dm->ddev) { 540 + acrtc = to_amdgpu_crtc(crtc); 541 + ism = &acrtc->ism; 542 + 543 + /* Cancel and disable any pending work */ 544 + disable_delayed_work_sync(&ism->delayed_work); 545 + disable_delayed_work_sync(&ism->sso_delayed_work); 546 + 547 + /* 548 + * When disabled, leave in FULL_POWER_RUNNING state. 549 + * EXIT_IDLE will not queue any work 550 + */ 551 + amdgpu_dm_ism_commit_event(ism, 552 + DM_ISM_EVENT_EXIT_IDLE_REQUESTED); 553 + } 554 + } 555 + 556 + /** 557 + * amdgpu_dm_ism_enable - enable the ISM 558 + * 559 + * @dm: The amdgpu display manager 560 + * 561 + * Re-enable the idle state manager by enabling work that was disabled by 562 + * amdgpu_dm_ism_disable. 563 + */ 564 + void amdgpu_dm_ism_enable(struct amdgpu_display_manager *dm) 565 + { 566 + struct drm_crtc *crtc; 567 + struct amdgpu_crtc *acrtc; 568 + struct amdgpu_dm_ism *ism; 569 + 570 + drm_for_each_crtc(crtc, dm->ddev) { 571 + acrtc = to_amdgpu_crtc(crtc); 572 + ism = &acrtc->ism; 573 + 574 + enable_delayed_work(&ism->delayed_work); 575 + enable_delayed_work(&ism->sso_delayed_work); 576 + } 577 + } 578 + 579 + void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism, 580 + struct amdgpu_dm_ism_config *config) 581 + { 582 + ism->config = *config; 583 + 584 + ism->current_state = DM_ISM_STATE_FULL_POWER_RUNNING; 585 + ism->previous_state = DM_ISM_STATE_FULL_POWER_RUNNING; 586 + ism->next_record_idx = 0; 587 + ism->last_idle_timestamp_ns = 0; 588 + 589 + INIT_DELAYED_WORK(&ism->delayed_work, dm_ism_delayed_work_func); 590 + INIT_DELAYED_WORK(&ism->sso_delayed_work, dm_ism_sso_delayed_work_func); 591 + } 592 + 593 + 594 + void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism) 595 + { 596 + cancel_delayed_work_sync(&ism->sso_delayed_work); 597 + cancel_delayed_work_sync(&ism->delayed_work); 598 + }
+151
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h
··· 1 + /* SPDX-License-Identifier: MIT */ 2 + /* 3 + * Copyright 2026 Advanced Micro Devices, Inc. 4 + * 5 + * Permission is hereby granted, free of charge, to any person obtaining a 6 + * copy of this software and associated documentation files (the "Software"), 7 + * to deal in the Software without restriction, including without limitation 8 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 + * and/or sell copies of the Software, and to permit persons to whom the 10 + * Software is furnished to do so, subject to the following conditions: 11 + * 12 + * The above copyright notice and this permission notice shall be included in 13 + * all copies or substantial portions of the Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 + * OTHER DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: AMD 24 + * 25 + */ 26 + 27 + #ifndef __AMDGPU_DM_ISM_H__ 28 + #define __AMDGPU_DM_ISM_H__ 29 + 30 + #include <linux/workqueue.h> 31 + 32 + struct amdgpu_crtc; 33 + struct amdgpu_display_manager; 34 + 35 + #define AMDGPU_DM_IDLE_HIST_LEN 16 36 + 37 + enum amdgpu_dm_ism_state { 38 + DM_ISM_STATE_FULL_POWER_RUNNING, 39 + DM_ISM_STATE_FULL_POWER_BUSY, 40 + DM_ISM_STATE_HYSTERESIS_WAITING, 41 + DM_ISM_STATE_HYSTERESIS_BUSY, 42 + DM_ISM_STATE_OPTIMIZED_IDLE, 43 + DM_ISM_STATE_OPTIMIZED_IDLE_SSO, 44 + DM_ISM_STATE_TIMER_ABORTED, 45 + DM_ISM_NUM_STATES, 46 + }; 47 + 48 + enum amdgpu_dm_ism_event { 49 + DM_ISM_EVENT_IMMEDIATE, 50 + DM_ISM_EVENT_ENTER_IDLE_REQUESTED, 51 + DM_ISM_EVENT_EXIT_IDLE_REQUESTED, 52 + DM_ISM_EVENT_BEGIN_CURSOR_UPDATE, 53 + DM_ISM_EVENT_END_CURSOR_UPDATE, 54 + DM_ISM_EVENT_TIMER_ELAPSED, 55 + DM_ISM_EVENT_SSO_TIMER_ELAPSED, 56 + DM_ISM_NUM_EVENTS, 57 + }; 58 + 59 + #define STATE_EVENT(state, event) (((state) << 8) | (event)) 60 + 61 + struct amdgpu_dm_ism_config { 62 + 63 + /** 64 + * @filter_num_frames: Idle periods shorter than this number of frames 65 + * will be considered a "short idle period" for filtering. 66 + * 67 + * 0 indicates no filtering (i.e. no idle allow delay will be applied) 68 + */ 69 + unsigned int filter_num_frames; 70 + 71 + /** 72 + * @filter_history_size: Number of recent idle periods to consider when 73 + * counting the number of short idle periods. 74 + */ 75 + unsigned int filter_history_size; 76 + 77 + /** 78 + * @filter_entry_count: When the number of short idle periods within 79 + * recent &filter_history_size reaches this count, the idle allow delay 80 + * will be applied. 81 + * 82 + * 0 indicates no filtering (i.e. no idle allow delay will be applied) 83 + */ 84 + unsigned int filter_entry_count; 85 + 86 + /** 87 + * @activation_num_delay_frames: Defines the number of frames to wait 88 + * for the idle allow delay. 89 + * 90 + * 0 indicates no filtering (i.e. no idle allow delay will be applied) 91 + */ 92 + unsigned int activation_num_delay_frames; 93 + 94 + /** 95 + * @filter_old_history_threshold: A time-based restriction on top of 96 + * &filter_history_size. Idle periods older than this threshold (in 97 + * number of frames) will be ignored when counting the number of short 98 + * idle periods. 99 + * 100 + * 0 indicates no time-based restriction, i.e. history is limited only 101 + * by &filter_history_size. 102 + */ 103 + unsigned int filter_old_history_threshold; 104 + 105 + /** 106 + * @sso_num_frames: Number of frames to delay before enabling static 107 + * screen optimizations, such as PSR1 and Replay low HZ idle mode. 108 + * 109 + * 0 indicates immediate SSO enable upon allowing idle. 110 + */ 111 + unsigned int sso_num_frames; 112 + }; 113 + 114 + struct amdgpu_dm_ism_record { 115 + /** 116 + * @timestamp_ns: When idle was allowed 117 + */ 118 + unsigned long long timestamp_ns; 119 + 120 + /** 121 + * @duration_ns: How long idle was allowed 122 + */ 123 + unsigned long long duration_ns; 124 + }; 125 + 126 + struct amdgpu_dm_ism { 127 + struct amdgpu_dm_ism_config config; 128 + unsigned long long last_idle_timestamp_ns; 129 + 130 + enum amdgpu_dm_ism_state current_state; 131 + enum amdgpu_dm_ism_state previous_state; 132 + 133 + struct amdgpu_dm_ism_record records[AMDGPU_DM_IDLE_HIST_LEN]; 134 + int next_record_idx; 135 + 136 + struct delayed_work delayed_work; 137 + struct delayed_work sso_delayed_work; 138 + }; 139 + 140 + #define ism_to_amdgpu_crtc(ism_ptr) \ 141 + container_of(ism_ptr, struct amdgpu_crtc, ism) 142 + 143 + void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism, 144 + struct amdgpu_dm_ism_config *config); 145 + void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism); 146 + void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism, 147 + enum amdgpu_dm_ism_event event); 148 + void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm); 149 + void amdgpu_dm_ism_enable(struct amdgpu_display_manager *dm); 150 + 151 + #endif
+16
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
··· 1374 1374 /* turn off cursor */ 1375 1375 if (crtc_state && crtc_state->stream) { 1376 1376 mutex_lock(&adev->dm.dc_lock); 1377 + amdgpu_dm_ism_commit_event( 1378 + &amdgpu_crtc->ism, 1379 + DM_ISM_EVENT_BEGIN_CURSOR_UPDATE); 1380 + 1377 1381 dc_stream_program_cursor_position(crtc_state->stream, 1378 1382 &position); 1383 + 1384 + amdgpu_dm_ism_commit_event( 1385 + &amdgpu_crtc->ism, 1386 + DM_ISM_EVENT_END_CURSOR_UPDATE); 1379 1387 mutex_unlock(&adev->dm.dc_lock); 1380 1388 } 1381 1389 return; ··· 1413 1405 1414 1406 if (crtc_state->stream) { 1415 1407 mutex_lock(&adev->dm.dc_lock); 1408 + amdgpu_dm_ism_commit_event( 1409 + &amdgpu_crtc->ism, 1410 + DM_ISM_EVENT_BEGIN_CURSOR_UPDATE); 1411 + 1416 1412 if (!dc_stream_program_cursor_attributes(crtc_state->stream, 1417 1413 &attributes)) 1418 1414 DRM_ERROR("DC failed to set cursor attributes\n"); ··· 1424 1412 if (!dc_stream_program_cursor_position(crtc_state->stream, 1425 1413 &position)) 1426 1414 DRM_ERROR("DC failed to set cursor position\n"); 1415 + 1416 + amdgpu_dm_ism_commit_event( 1417 + &amdgpu_crtc->ism, 1418 + DM_ISM_EVENT_END_CURSOR_UPDATE); 1427 1419 mutex_unlock(&adev->dm.dc_lock); 1428 1420 } 1429 1421 }
+63
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
··· 753 753 ) 754 754 ); 755 755 756 + TRACE_EVENT(amdgpu_dm_ism_commit, 757 + TP_PROTO( 758 + int active_vblank_irq_count, 759 + bool vblank_enabled, 760 + bool allow_panel_sso 761 + ), 762 + TP_ARGS( 763 + active_vblank_irq_count, 764 + vblank_enabled, 765 + allow_panel_sso 766 + ), 767 + TP_STRUCT__entry( 768 + __field(int, active_vblank_irq_count) 769 + __field(bool, vblank_enabled) 770 + __field(bool, allow_panel_sso) 771 + ), 772 + TP_fast_assign( 773 + __entry->active_vblank_irq_count = active_vblank_irq_count; 774 + __entry->vblank_enabled = vblank_enabled; 775 + __entry->allow_panel_sso = allow_panel_sso; 776 + ), 777 + TP_printk( 778 + "active_vblank_irq_count=%d vblank_enabled=%d allow_panel_sso=%d", 779 + __entry->active_vblank_irq_count, 780 + __entry->vblank_enabled, 781 + __entry->allow_panel_sso 782 + ) 783 + ); 784 + 785 + TRACE_EVENT(amdgpu_dm_ism_event, 786 + TP_PROTO( 787 + int crtc_id, 788 + const char *prev_state, 789 + const char *curr_state, 790 + const char *event 791 + ), 792 + TP_ARGS( 793 + crtc_id, 794 + prev_state, 795 + curr_state, 796 + event 797 + ), 798 + TP_STRUCT__entry( 799 + __field(int, crtc_id) 800 + __string(prev_state, prev_state) 801 + __string(curr_state, curr_state) 802 + __string(event, event) 803 + ), 804 + TP_fast_assign( 805 + __entry->crtc_id = crtc_id; 806 + __assign_str(prev_state); 807 + __assign_str(curr_state); 808 + __assign_str(event); 809 + ), 810 + TP_printk( 811 + "[CRTC %d] %s -> %s on event %s", 812 + __entry->crtc_id, 813 + __get_str(prev_state), 814 + __get_str(curr_state), 815 + __get_str(event)) 816 + ); 817 + 818 + 756 819 #endif /* _AMDGPU_DM_TRACE_H_ */ 757 820 758 821 #undef TRACE_INCLUDE_PATH