Do not trust our bookkeeping when reporting errors, and instead dump the register contents. In particular, this solves one particular issue when an error is reported before we finish setting up the outputs and have a complete mapping (i.e. during initialisation we set garbage state). If an error occurs at that early stage, it is vital that we get an accurate report of the hardware state and not conflated with our own inaccurate opinions. This fixes a panic for a large number of pre-Haswell machines that currently trigger an error during KMS takeover. Reported-by: Dustin King <daking at rescomp.stanford.edu> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=60021 Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk> Cc: stable at vger.kernel.org --- drivers/gpu/drm/i915/intel_display.c | 37 ++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5988bda..7ce4588 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10273,12 +10273,43 @@ struct intel_display_error_state { } plane[I915_MAX_PIPES]; }; +static enum transcoder +read_cpu_transcoder(struct drm_i915_private *dev_priv, int pipe) +{ + if (HAS_DDI(dev_priv->dev)) { + int edp_pipe; + + switch (I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)) & (TRANS_DDI_FUNC_ENABLE | TRANS_DDI_EDP_INPUT_MASK)) { + default: + edp_pipe = -1; + break; + + case TRANS_DDI_EDP_INPUT_A_ONOFF | TRANS_DDI_FUNC_ENABLE: + case TRANS_DDI_EDP_INPUT_A_ON | TRANS_DDI_FUNC_ENABLE: + edp_pipe = PIPE_A; + break; + + case TRANS_DDI_EDP_INPUT_B_ONOFF | TRANS_DDI_FUNC_ENABLE: + edp_pipe = PIPE_B; + break; + + case TRANS_DDI_EDP_INPUT_C_ONOFF | TRANS_DDI_FUNC_ENABLE: + edp_pipe = PIPE_C; + break; + } + + if (edp_pipe == pipe) + pipe = TRANSCODER_EDP; + } + + return pipe; +} + struct intel_display_error_state * intel_display_capture_error_state(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_display_error_state *error; - enum transcoder cpu_transcoder; int i; error = kmalloc(sizeof(*error), GFP_ATOMIC); @@ -10289,7 +10320,9 @@ intel_display_capture_error_state(struct drm_device *dev) error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER); for_each_pipe(i) { - cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i); + enum transcoder cpu_transcoder; + + cpu_transcoder = read_cpu_transcoder(dev_priv, i); error->pipe[i].cpu_transcoder = cpu_transcoder; if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { -- 1.8.3.1