diff options
author | Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> | 2018-04-04 18:37:17 -0700 |
---|---|---|
committer | Rodrigo Vivi <rodrigo.vivi@intel.com> | 2018-04-20 14:28:16 -0700 |
commit | 54fd3149598cc2f74cf0708d614470da2331a374 (patch) | |
tree | 62130a352a1b15a3affa2ee5e62a962478d0b6b6 /drivers | |
parent | e04f7ece1c4530b4f0db182b5596fadf48628f22 (diff) |
drm/i915/psr: Control PSR interrupts via debugfs
Interrupts other than the one for AUX errors are required only for debug,
so unmask them via debugfs when the user requests debug.
User can make such a request with
echo 1 > <DEBUG_FS>/dri/0/i915_edp_psr_debug
There are no locks to serialize PSR debug enabling from
irq_postinstall() and debugfs for simplicity. As irq_postinstall() is
called only during module initialization/resume and IGT subtests
aren't expected to modify PSR debug at those times, we should be safe.
v2: Unroll loops (Ville)
Avoid resetting error mask bits.
v3: Unmask interrupts in postinstall() if debug was still enabled.
Avoid RMW (Ville)
v4: Avoid extra IMR write introduced in the previous version.(Jose)
Style changes, renames (Jose).
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Reviewed-by: Jose Roberto de Souza <jose.souza@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180405013717.24254-1-dhinakaran.pandiyan@intel.com
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_psr.c | 58 |
5 files changed, 108 insertions, 40 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e0274f41bc76..a6c70ff4ae5a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2690,6 +2690,39 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) return 0; } +static int +i915_edp_psr_debug_set(void *data, u64 val) +{ + struct drm_i915_private *dev_priv = data; + + if (!CAN_PSR(dev_priv)) + return -ENODEV; + + DRM_DEBUG_KMS("PSR debug %s\n", enableddisabled(val)); + + intel_runtime_pm_get(dev_priv); + intel_psr_irq_control(dev_priv, !!val); + intel_runtime_pm_put(dev_priv); + + return 0; +} + +static int +i915_edp_psr_debug_get(void *data, u64 *val) +{ + struct drm_i915_private *dev_priv = data; + + if (!CAN_PSR(dev_priv)) + return -ENODEV; + + *val = READ_ONCE(dev_priv->psr.debug); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(i915_edp_psr_debug_fops, + i915_edp_psr_debug_get, i915_edp_psr_debug_set, + "%llu\n"); + static int i915_sink_crc(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = node_to_i915(m->private); @@ -4862,7 +4895,8 @@ static const struct i915_debugfs_files { {"i915_guc_log_relay", &i915_guc_log_relay_fops}, {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops}, {"i915_ipc_status", &i915_ipc_status_fops}, - {"i915_drrs_ctl", &i915_drrs_ctl_fops} + {"i915_drrs_ctl", &i915_drrs_ctl_fops}, + {"i915_edp_psr_debug", &i915_edp_psr_debug_fops} }; int i915_debugfs_register(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 028691108125..e67e21799f37 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -610,6 +610,7 @@ struct i915_psr { bool has_hw_tracking; bool psr2_enabled; u8 sink_sync_latency; + bool debug; void (*enable_source)(struct intel_dp *, const struct intel_crtc_state *); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ab9aac88a00b..96547e091e23 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2452,40 +2452,6 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, ironlake_rps_change_irq_handler(dev_priv); } -static void hsw_edp_psr_irq_handler(struct drm_i915_private *dev_priv) -{ - u32 edp_psr_iir = I915_READ(EDP_PSR_IIR); - u32 edp_psr_imr = I915_READ(EDP_PSR_IMR); - u32 mask = BIT(TRANSCODER_EDP); - enum transcoder cpu_transcoder; - - if (INTEL_GEN(dev_priv) >= 8) - mask |= BIT(TRANSCODER_A) | - BIT(TRANSCODER_B) | - BIT(TRANSCODER_C); - - for_each_cpu_transcoder_masked(dev_priv, cpu_transcoder, mask) { - if (edp_psr_iir & EDP_PSR_ERROR(cpu_transcoder)) - DRM_DEBUG_KMS("Transcoder %s PSR error\n", - transcoder_name(cpu_transcoder)); - - if (edp_psr_iir & EDP_PSR_PRE_ENTRY(cpu_transcoder)) { - DRM_DEBUG_KMS("Transcoder %s PSR prepare entry in 2 vblanks\n", - transcoder_name(cpu_transcoder)); - edp_psr_imr |= EDP_PSR_PRE_ENTRY(cpu_transcoder); - } - - if (edp_psr_iir & EDP_PSR_POST_EXIT(cpu_transcoder)) { - DRM_DEBUG_KMS("Transcoder %s PSR exit completed\n", - transcoder_name(cpu_transcoder)); - edp_psr_imr &= ~EDP_PSR_PRE_ENTRY(cpu_transcoder); - } - } - - I915_WRITE(EDP_PSR_IMR, edp_psr_imr); - I915_WRITE(EDP_PSR_IIR, edp_psr_iir); -} - static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) { @@ -2498,8 +2464,12 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, if (de_iir & DE_ERR_INT_IVB) ivb_err_int_handler(dev_priv); - if (de_iir & DE_EDP_PSR_INT_HSW) - hsw_edp_psr_irq_handler(dev_priv); + if (de_iir & DE_EDP_PSR_INT_HSW) { + u32 psr_iir = I915_READ(EDP_PSR_IIR); + + intel_psr_irq_handler(dev_priv, psr_iir); + I915_WRITE(EDP_PSR_IIR, psr_iir); + } if (de_iir & DE_AUX_CHANNEL_A_IVB) dp_aux_irq_handler(dev_priv); @@ -2641,7 +2611,10 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) } if (iir & GEN8_DE_EDP_PSR) { - hsw_edp_psr_irq_handler(dev_priv); + u32 psr_iir = I915_READ(EDP_PSR_IIR); + + intel_psr_irq_handler(dev_priv, psr_iir); + I915_WRITE(EDP_PSR_IIR, psr_iir); found = true; } @@ -3820,7 +3793,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) if (IS_HASWELL(dev_priv)) { gen3_assert_iir_is_zero(dev_priv, EDP_PSR_IIR); - I915_WRITE(EDP_PSR_IMR, 0); + intel_psr_irq_control(dev_priv, dev_priv->psr.debug); display_mask |= DE_EDP_PSR_INT_HSW; } @@ -3960,7 +3933,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) de_port_enables |= GEN8_PORT_DP_A_HOTPLUG; gen3_assert_iir_is_zero(dev_priv, EDP_PSR_IIR); - I915_WRITE(EDP_PSR_IMR, 0); + intel_psr_irq_control(dev_priv, dev_priv->psr.debug); for_each_pipe(dev_priv, pipe) { dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8b20824e806e..44ed248f1fe9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1899,6 +1899,8 @@ void intel_psr_single_frame_update(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits); void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state); +void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug); +void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir); /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 69a5b276f4d8..ae6a916523c2 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -93,6 +93,64 @@ static void psr_aux_io_power_put(struct intel_dp *intel_dp) intel_display_power_put(dev_priv, psr_aux_domain(intel_dp)); } +void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug) +{ + u32 debug_mask, mask; + + /* No PSR interrupts on VLV/CHV */ + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + return; + + mask = EDP_PSR_ERROR(TRANSCODER_EDP); + debug_mask = EDP_PSR_POST_EXIT(TRANSCODER_EDP) | + EDP_PSR_PRE_ENTRY(TRANSCODER_EDP); + + if (INTEL_GEN(dev_priv) >= 8) { + mask |= EDP_PSR_ERROR(TRANSCODER_A) | + EDP_PSR_ERROR(TRANSCODER_B) | + EDP_PSR_ERROR(TRANSCODER_C); + + debug_mask |= EDP_PSR_POST_EXIT(TRANSCODER_A) | + EDP_PSR_PRE_ENTRY(TRANSCODER_A) | + EDP_PSR_POST_EXIT(TRANSCODER_B) | + EDP_PSR_PRE_ENTRY(TRANSCODER_B) | + EDP_PSR_POST_EXIT(TRANSCODER_C) | + EDP_PSR_PRE_ENTRY(TRANSCODER_C); + } + + if (debug) + mask |= debug_mask; + + WRITE_ONCE(dev_priv->psr.debug, debug); + I915_WRITE(EDP_PSR_IMR, ~mask); +} + +void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) +{ + u32 transcoders = BIT(TRANSCODER_EDP); + enum transcoder cpu_transcoder; + + if (INTEL_GEN(dev_priv) >= 8) + transcoders |= BIT(TRANSCODER_A) | + BIT(TRANSCODER_B) | + BIT(TRANSCODER_C); + + for_each_cpu_transcoder_masked(dev_priv, cpu_transcoder, transcoders) { + /* FIXME: Exit PSR and link train manually when this happens. */ + if (psr_iir & EDP_PSR_ERROR(cpu_transcoder)) + DRM_DEBUG_KMS("[transcoder %s] PSR aux error\n", + transcoder_name(cpu_transcoder)); + + if (psr_iir & EDP_PSR_PRE_ENTRY(cpu_transcoder)) + DRM_DEBUG_KMS("[transcoder %s] PSR entry attempt in 2 vblanks\n", + transcoder_name(cpu_transcoder)); + + if (psr_iir & EDP_PSR_POST_EXIT(cpu_transcoder)) + DRM_DEBUG_KMS("[transcoder %s] PSR exit completed\n", + transcoder_name(cpu_transcoder)); + } +} + static bool intel_dp_get_y_coord_required(struct intel_dp *intel_dp) { uint8_t psr_caps = 0; |