Skip to content

Commit 9e7e6a0

Browse files
hogandergregkh
authored andcommitted
drm/i915/psr: Use DC_OFF wake reference to block DC6 on vblank enable
commit 3549a96 upstream. We are observing following warnings: *ERROR* power well DC_off state mismatch (refcount 0/enabled 1) gen9_dc_off_power_well_enabled is considering target state DC_STATE_DISABLE as DC_OFF power well being enabled. Fix this by using wakeref for the purpose. To achieve this we need to modify notification code as well. Currently it is possible that PSR gets notified vblank enable/disable twice on same status. This is currently not a problem as it is just triggering call to intel_display_power_set_target_dc_state with same target state as a parameter. When using wakeref this becomes a problem due to reference counting. Fix this storing vbank status on last notification and use that to ensure there are no more than one notification with same vblank status. v2: ensure there is no subsequent notifications with same status Fixes: aa451ab ("drm/i915/display: Prevent DC6 while vblank is enabled for Panel Replay") Cc: <stable@vger.kernel.org> # v6.13+ Signed-off-by: Jouni Högander <jouni.hogander@intel.com> Reviewed-by: Michał Grzelak <michal.grzelak@intel.com> Link: https://patch.msgid.link/20260520104944.239797-2-jouni.hogander@intel.com (cherry picked from commit 35485ac) Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent eec1212 commit 9e7e6a0

4 files changed

Lines changed: 18 additions & 17 deletions

File tree

drivers/gpu/drm/i915/display/intel_display_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ struct intel_display {
494494
u8 vblank_enabled;
495495

496496
int vblank_enable_count;
497+
bool vblank_status_last_notified;
497498

498499
struct work_struct vblank_notify_work;
499500

drivers/gpu/drm/i915/display/intel_display_irq.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,8 +1773,12 @@ static void intel_display_vblank_notify_work(struct work_struct *work)
17731773
struct intel_display *display =
17741774
container_of(work, typeof(*display), irq.vblank_notify_work);
17751775
int vblank_enable_count = READ_ONCE(display->irq.vblank_enable_count);
1776+
bool vblank_status = !!vblank_enable_count;
17761777

1777-
intel_psr_notify_vblank_enable_disable(display, vblank_enable_count);
1778+
if (display->irq.vblank_status_last_notified != vblank_status) {
1779+
intel_psr_notify_vblank_enable_disable(display, vblank_status);
1780+
display->irq.vblank_status_last_notified = vblank_status;
1781+
}
17781782
}
17791783

17801784
int bdw_enable_vblank(struct drm_crtc *_crtc)
@@ -1787,10 +1791,10 @@ int bdw_enable_vblank(struct drm_crtc *_crtc)
17871791
if (gen11_dsi_configure_te(crtc, true))
17881792
return 0;
17891793

1794+
spin_lock_irqsave(&display->irq.lock, irqflags);
17901795
if (crtc->vblank_psr_notify && display->irq.vblank_enable_count++ == 0)
17911796
schedule_work(&display->irq.vblank_notify_work);
17921797

1793-
spin_lock_irqsave(&display->irq.lock, irqflags);
17941798
bdw_enable_pipe_irq(display, pipe, GEN8_PIPE_VBLANK);
17951799
spin_unlock_irqrestore(&display->irq.lock, irqflags);
17961800

drivers/gpu/drm/i915/display/intel_display_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,8 @@ struct intel_psr {
17851785
u8 active_non_psr_pipes;
17861786

17871787
const char *no_psr_reason;
1788+
1789+
struct ref_tracker *vblank_wakeref;
17881790
};
17891791

17901792
struct intel_dp {

drivers/gpu/drm/i915/display/intel_psr.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4141,33 +4141,27 @@ void intel_psr_notify_vblank_enable_disable(struct intel_display *display,
41414141
bool enable)
41424142
{
41434143
struct intel_encoder *encoder;
4144-
bool block_dc_states = false;
41454144

41464145
for_each_intel_encoder_with_psr(display->drm, encoder) {
41474146
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
41484147

41494148
mutex_lock(&intel_dp->psr.lock);
4150-
if (CAN_PANEL_REPLAY(intel_dp))
4151-
block_dc_states = true;
4149+
if (CAN_PANEL_REPLAY(intel_dp)) {
4150+
if (enable)
4151+
intel_dp->psr.vblank_wakeref =
4152+
intel_display_power_get(display,
4153+
POWER_DOMAIN_DC_OFF);
4154+
else
4155+
intel_display_power_put(display, POWER_DOMAIN_DC_OFF,
4156+
intel_dp->psr.vblank_wakeref);
4157+
}
41524158

41534159
if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled &&
41544160
intel_dp->psr.pkg_c_latency_used)
41554161
intel_psr_apply_underrun_on_idle_wa_locked(intel_dp);
41564162

41574163
mutex_unlock(&intel_dp->psr.lock);
41584164
}
4159-
4160-
/*
4161-
* NOTE: intel_display_power_set_target_dc_state is used
4162-
* only by PSR code for DC3CO handling. DC3CO target
4163-
* state is currently disabled in * PSR code. If DC3CO
4164-
* is taken into use we need take that into account here
4165-
* as well.
4166-
*/
4167-
if (block_dc_states)
4168-
intel_display_power_set_target_dc_state(display, enable ?
4169-
DC_STATE_DISABLE :
4170-
DC_STATE_EN_UPTO_DC6);
41714165
}
41724166

41734167
static void

0 commit comments

Comments
 (0)