Skip to content

Commit

Permalink
drm/i915/display: Prevent DC6 while vblank is enabled for Panel Replay
Browse files Browse the repository at this point in the history
We need to block DC6 entry in case of Panel Replay as enabling VBI doesn't
prevent DC6 in case of Panel Replay. This causes problems if user-space is
polling for vblank events.

Fix this by setting target DC state as DC_STATE_EN_UPTO_DC5 when both
source and sink are supporting eDP Panel Replay and VBI is enabled.

v4:
  - s/vblank_work/vblank_dc_work/
  - changed type of block_dc_for_vblank to bool
v3:
  - do flush_work for vblank_work on intel_crtc_vblank_off
  - no need to use READ_ONCE in bdw_enable_vblank
  - check crtc->block_dc_for_vblank in bdw_disable_vblank as well
  - move adding block_dc_for_vblank into this patch
v2:
  - use READ_ONCE in intel_display_vblank_work
  - use DC_STATE_DISABLE instead of DC_STATE_EN_UPTO_DC6
  - use intel_crtc->block_dc6_needed

Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/2296
Signed-off-by: Jouni Högander <jouni.hogander@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240920062340.1333777-3-jouni.hogander@intel.com
  • Loading branch information
Jouni Högander committed Sep 23, 2024
1 parent 1007610 commit aa451ab
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 0 deletions.
7 changes: 7 additions & 0 deletions drivers/gpu/drm/i915/display/intel_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);

crtc->block_dc_for_vblank = intel_psr_needs_block_dc_vblank(crtc_state);

assert_vblank_disabled(&crtc->base);
drm_crtc_set_max_vblank_count(&crtc->base,
intel_crtc_max_vblank_count(crtc_state));
Expand All @@ -140,6 +142,7 @@ void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct intel_display *display = to_intel_display(crtc);

/*
* Should really happen exactly when we disable the pipe
Expand All @@ -150,6 +153,10 @@ void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)

drm_crtc_vblank_off(&crtc->base);
assert_vblank_disabled(&crtc->base);

crtc->block_dc_for_vblank = false;

flush_work(&display->irq.vblank_dc_work);
}

struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/display/intel_display_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ struct intel_display {
/* For i915gm/i945gm vblank irq workaround */
u8 vblank_enabled;

struct work_struct vblank_dc_work;

u32 de_irq_mask[I915_MAX_PIPES];
u32 pipestat_irq_mask[I915_MAX_PIPES];
} irq;
Expand Down
28 changes: 28 additions & 0 deletions drivers/gpu/drm/i915/display/intel_display_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1360,16 +1360,37 @@ static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc,
return true;
}

static void intel_display_vblank_dc_work(struct work_struct *work)
{
struct intel_display *display =
container_of(work, typeof(*display), irq.vblank_dc_work);
struct drm_i915_private *i915 = to_i915(display->drm);
u8 vblank_enabled = READ_ONCE(display->irq.vblank_enabled);

/*
* NOTE: intel_display_power_set_target_dc_state is used only by PSR
* code for DC3CO handling. DC3CO target state is currently disabled in
* PSR code. If DC3CO is taken into use we need take that into account
* here as well.
*/
intel_display_power_set_target_dc_state(i915, vblank_enabled ? DC_STATE_DISABLE :
DC_STATE_EN_UPTO_DC6);
}

int bdw_enable_vblank(struct drm_crtc *_crtc)
{
struct intel_crtc *crtc = to_intel_crtc(_crtc);
struct intel_display *display = to_intel_display(crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
unsigned long irqflags;

if (gen11_dsi_configure_te(crtc, true))
return 0;

if (display->irq.vblank_enabled++ == 0 && crtc->block_dc_for_vblank)
schedule_work(&display->irq.vblank_dc_work);

spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
Expand Down Expand Up @@ -1435,6 +1456,7 @@ void ilk_disable_vblank(struct drm_crtc *crtc)
void bdw_disable_vblank(struct drm_crtc *_crtc)
{
struct intel_crtc *crtc = to_intel_crtc(_crtc);
struct intel_display *display = to_intel_display(crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
unsigned long irqflags;
Expand All @@ -1445,6 +1467,9 @@ void bdw_disable_vblank(struct drm_crtc *_crtc)
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);

if (--display->irq.vblank_enabled == 0 && crtc->block_dc_for_vblank)
schedule_work(&display->irq.vblank_dc_work);
}

void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
Expand Down Expand Up @@ -1881,4 +1906,7 @@ void intel_display_irq_init(struct drm_i915_private *i915)
i915->display.irq.display_irqs_enabled = false;

intel_hotplug_irq_init(i915);

INIT_WORK(&i915->display.irq.vblank_dc_work,
intel_display_vblank_dc_work);
}
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/display/intel_display_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,8 @@ struct intel_crtc {
#ifdef CONFIG_DEBUG_FS
struct intel_pipe_crc pipe_crc;
#endif

bool block_dc_for_vblank;
};

struct intel_plane {
Expand Down

0 comments on commit aa451ab

Please sign in to comment.