Commit 54fd3149 authored by Dhinakaran Pandiyan's avatar Dhinakaran Pandiyan Committed by Rodrigo Vivi

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: default avatarDhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Reviewed-by: default avatarJose Roberto de Souza <jose.souza@intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180405013717.24254-1-dhinakaran.pandiyan@intel.com
parent e04f7ece
...@@ -2690,6 +2690,39 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) ...@@ -2690,6 +2690,39 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
return 0; 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) static int i915_sink_crc(struct seq_file *m, void *data)
{ {
struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_i915_private *dev_priv = node_to_i915(m->private);
...@@ -4862,7 +4895,8 @@ static const struct i915_debugfs_files { ...@@ -4862,7 +4895,8 @@ static const struct i915_debugfs_files {
{"i915_guc_log_relay", &i915_guc_log_relay_fops}, {"i915_guc_log_relay", &i915_guc_log_relay_fops},
{"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops}, {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
{"i915_ipc_status", &i915_ipc_status_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) int i915_debugfs_register(struct drm_i915_private *dev_priv)
......
...@@ -610,6 +610,7 @@ struct i915_psr { ...@@ -610,6 +610,7 @@ struct i915_psr {
bool has_hw_tracking; bool has_hw_tracking;
bool psr2_enabled; bool psr2_enabled;
u8 sink_sync_latency; u8 sink_sync_latency;
bool debug;
void (*enable_source)(struct intel_dp *, void (*enable_source)(struct intel_dp *,
const struct intel_crtc_state *); const struct intel_crtc_state *);
......
...@@ -2452,40 +2452,6 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, ...@@ -2452,40 +2452,6 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
ironlake_rps_change_irq_handler(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, static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
u32 de_iir) u32 de_iir)
{ {
...@@ -2498,8 +2464,12 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, ...@@ -2498,8 +2464,12 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
if (de_iir & DE_ERR_INT_IVB) if (de_iir & DE_ERR_INT_IVB)
ivb_err_int_handler(dev_priv); ivb_err_int_handler(dev_priv);
if (de_iir & DE_EDP_PSR_INT_HSW) if (de_iir & DE_EDP_PSR_INT_HSW) {
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);
}
if (de_iir & DE_AUX_CHANNEL_A_IVB) if (de_iir & DE_AUX_CHANNEL_A_IVB)
dp_aux_irq_handler(dev_priv); dp_aux_irq_handler(dev_priv);
...@@ -2641,7 +2611,10 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) ...@@ -2641,7 +2611,10 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
} }
if (iir & GEN8_DE_EDP_PSR) { 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; found = true;
} }
...@@ -3820,7 +3793,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ...@@ -3820,7 +3793,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
if (IS_HASWELL(dev_priv)) { if (IS_HASWELL(dev_priv)) {
gen3_assert_iir_is_zero(dev_priv, EDP_PSR_IIR); 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; display_mask |= DE_EDP_PSR_INT_HSW;
} }
...@@ -3960,7 +3933,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) ...@@ -3960,7 +3933,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
de_port_enables |= GEN8_PORT_DP_A_HOTPLUG; de_port_enables |= GEN8_PORT_DP_A_HOTPLUG;
gen3_assert_iir_is_zero(dev_priv, EDP_PSR_IIR); 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) { for_each_pipe(dev_priv, pipe) {
dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; dev_priv->de_irq_mask[pipe] = ~de_pipe_masked;
......
...@@ -1899,6 +1899,8 @@ void intel_psr_single_frame_update(struct drm_i915_private *dev_priv, ...@@ -1899,6 +1899,8 @@ void intel_psr_single_frame_update(struct drm_i915_private *dev_priv,
unsigned frontbuffer_bits); unsigned frontbuffer_bits);
void intel_psr_compute_config(struct intel_dp *intel_dp, void intel_psr_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state); 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 */ /* intel_runtime_pm.c */
int intel_power_domains_init(struct drm_i915_private *); int intel_power_domains_init(struct drm_i915_private *);
......
...@@ -93,6 +93,64 @@ static void psr_aux_io_power_put(struct intel_dp *intel_dp) ...@@ -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)); 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) static bool intel_dp_get_y_coord_required(struct intel_dp *intel_dp)
{ {
uint8_t psr_caps = 0; uint8_t psr_caps = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment