On Thu, 2025-01-16 at 19:47 +0200, Ville Syrjala wrote: > From: Ville Syrjälä <ville.syrj...@linux.intel.com> > > Decode the display faults a bit more extensively so that one > doesn't have translate the bitmask to planes/etc. manually. > Also for plane faults we can read out a bit of state from the > relevant plane(s) and dump that out. > > Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com> > --- > .../gpu/drm/i915/display/intel_atomic_plane.c | 2 +- > .../gpu/drm/i915/display/intel_atomic_plane.h | 2 + > .../gpu/drm/i915/display/intel_display_irq.c | 156 +++++++++++++++++- > 3 files changed, 155 insertions(+), 5 deletions(-)
Reviewed-by: Vinod Govindapillai <vinod.govindapil...@intel.com> > > diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c > b/drivers/gpu/drm/i915/display/intel_atomic_plane.c > index 612e9b0ec14a..0aeb5f00d9c4 100644 > --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c > +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c > @@ -663,7 +663,7 @@ int intel_plane_atomic_check_with_state(const struct > intel_crtc_state > *old_crtc_ > old_plane_state, > new_plane_state); > } > > -static struct intel_plane * > +struct intel_plane * > intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id) > { > struct drm_i915_private *i915 = to_i915(crtc->base.dev); > diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h > b/drivers/gpu/drm/i915/display/intel_atomic_plane.h > index 0f982f452ff3..298bb97b37a4 100644 > --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h > +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h > @@ -19,6 +19,8 @@ struct intel_plane; > struct intel_plane_state; > enum plane_id; > > +struct intel_plane * > +intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id); > unsigned int intel_adjusted_rate(const struct drm_rect *src, > const struct drm_rect *dst, > unsigned int rate); > diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c > b/drivers/gpu/drm/i915/display/intel_display_irq.c > index f06273d9bc8c..1b3b6b8bc794 100644 > --- a/drivers/gpu/drm/i915/display/intel_display_irq.c > +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c > @@ -10,6 +10,7 @@ > #include "i915_irq.h" > #include "i915_reg.h" > #include "icl_dsi_regs.h" > +#include "intel_atomic_plane.h" > #include "intel_crtc.h" > #include "intel_de.h" > #include "intel_display_irq.h" > @@ -26,6 +27,52 @@ > #include "intel_psr.h" > #include "intel_psr_regs.h" > > +struct pipe_fault_handler { > + bool (*handle)(struct intel_crtc *crtc, enum plane_id plane_id); > + u32 fault; > + enum plane_id plane_id; > +}; > + > +static bool handle_plane_fault(struct intel_crtc *crtc, enum plane_id > plane_id) > +{ > + struct intel_display *display = to_intel_display(crtc); > + struct intel_plane_error error = {}; > + struct intel_plane *plane; > + > + plane = intel_crtc_get_plane(crtc, plane_id); > + if (!plane || !plane->capture_error) > + return false; > + > + plane->capture_error(crtc, plane, &error); > + > + drm_err_ratelimited(display->drm, > + "[CRTC:%d:%s][PLANE:%d:%s] fault (CTL=0x%x, > SURF=0x%x, > SURFLIVE=0x%x)\n", > + crtc->base.base.id, crtc->base.name, > + plane->base.base.id, plane->base.name, > + error.ctl, error.surf, error.surflive); > + > + return true; > +} > + > +static void intel_pipe_fault_irq_handler(struct intel_display *display, > + const struct pipe_fault_handler > *handlers, > + enum pipe pipe, u32 fault_errors) > +{ > + struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); > + const struct pipe_fault_handler *handler; > + > + for (handler = handlers; handler && handler->fault; handler++) { > + if ((fault_errors & handler->fault) == 0) > + continue; > + > + if (handler->handle(crtc, handler->plane_id)) > + fault_errors &= ~handler->fault; > + } > + > + WARN_ONCE(fault_errors, "[CRTC:%d:%s] unreported faults 0x%x\n", > + crtc->base.base.id, crtc->base.name, fault_errors); > +} > + > static void > intel_handle_vblank(struct drm_i915_private *dev_priv, enum pipe pipe) > { > @@ -895,6 +942,108 @@ static u32 gen8_de_pipe_fault_mask(struct > drm_i915_private *dev_priv) > GEN8_PIPE_PRIMARY_FAULT; > } > > +static bool handle_plane_ats_fault(struct intel_crtc *crtc, enum plane_id > plane_id) > +{ > + struct intel_display *display = to_intel_display(crtc); > + > + drm_err_ratelimited(display->drm, > + "[CRTC:%d:%s] PLANE ATS fault\n", > + crtc->base.base.id, crtc->base.name); > + > + return false; > +} > + > +static bool handle_pipedmc_ats_fault(struct intel_crtc *crtc, enum plane_id > plane_id) > +{ > + struct intel_display *display = to_intel_display(crtc); > + > + drm_err_ratelimited(display->drm, > + "[CRTC:%d:%s] PIPEDMC ATS fault\n", > + crtc->base.base.id, crtc->base.name); > + > + return false; > +} > + > +static bool handle_pipedmc_fault(struct intel_crtc *crtc, enum plane_id > plane_id) > +{ > + struct intel_display *display = to_intel_display(crtc); > + > + drm_err_ratelimited(display->drm, > + "[CRTC:%d:%s] PIPEDMC fault\n", > + crtc->base.base.id, crtc->base.name); > + > + return false; > +} > + > +static const struct pipe_fault_handler mtl_pipe_fault_handlers[] = { > + { .fault = MTL_PLANE_ATS_FAULT, .handle = handle_plane_ats_fault, }, > + { .fault = MTL_PIPEDMC_ATS_FAULT, .handle = handle_pipedmc_ats_fault, > }, > + { .fault = GEN12_PIPEDMC_FAULT, .handle = handle_pipedmc_fault, }, > + { .fault = GEN11_PIPE_PLANE5_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_5, }, > + { .fault = GEN9_PIPE_PLANE4_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_4, }, > + { .fault = GEN9_PIPE_PLANE3_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_3, }, > + { .fault = GEN9_PIPE_PLANE2_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_2, }, > + { .fault = GEN9_PIPE_PLANE1_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_1, }, > + { .fault = GEN9_PIPE_CURSOR_FAULT, .handle = handle_plane_fault, > .plane_id = > PLANE_CURSOR, }, > + {} > +}; > + > +static const struct pipe_fault_handler tgl_pipe_fault_handlers[] = { > + { .fault = GEN12_PIPEDMC_FAULT, .handle = handle_pipedmc_fault, }, > + { .fault = GEN11_PIPE_PLANE7_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_7, }, > + { .fault = GEN11_PIPE_PLANE6_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_6, }, > + { .fault = GEN11_PIPE_PLANE5_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_5, }, > + { .fault = GEN9_PIPE_PLANE4_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_4, }, > + { .fault = GEN9_PIPE_PLANE3_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_3, }, > + { .fault = GEN9_PIPE_PLANE2_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_2, }, > + { .fault = GEN9_PIPE_PLANE1_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_1, }, > + { .fault = GEN9_PIPE_CURSOR_FAULT, .handle = handle_plane_fault, > .plane_id = > PLANE_CURSOR, }, > + {} > +}; > + > +static const struct pipe_fault_handler icl_pipe_fault_handlers[] = { > + { .fault = GEN11_PIPE_PLANE7_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_7, }, > + { .fault = GEN11_PIPE_PLANE6_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_6, }, > + { .fault = GEN11_PIPE_PLANE5_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_5, }, > + { .fault = GEN9_PIPE_PLANE4_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_4, }, > + { .fault = GEN9_PIPE_PLANE3_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_3, }, > + { .fault = GEN9_PIPE_PLANE2_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_2, }, > + { .fault = GEN9_PIPE_PLANE1_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_1, }, > + { .fault = GEN9_PIPE_CURSOR_FAULT, .handle = handle_plane_fault, > .plane_id = > PLANE_CURSOR, }, > + {} > +}; > + > +static const struct pipe_fault_handler skl_pipe_fault_handlers[] = { > + { .fault = GEN9_PIPE_PLANE4_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_4, }, > + { .fault = GEN9_PIPE_PLANE3_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_3, }, > + { .fault = GEN9_PIPE_PLANE2_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_2, }, > + { .fault = GEN9_PIPE_PLANE1_FAULT, .handle = handle_plane_fault, > .plane_id = PLANE_1, }, > + { .fault = GEN9_PIPE_CURSOR_FAULT, .handle = handle_plane_fault, > .plane_id = > PLANE_CURSOR, }, > + {} > +}; > + > +static const struct pipe_fault_handler bdw_pipe_fault_handlers[] = { > + { .fault = GEN8_PIPE_SPRITE_FAULT, .handle = handle_plane_fault, > .plane_id = > PLANE_SPRITE0, }, > + { .fault = GEN8_PIPE_PRIMARY_FAULT, .handle = handle_plane_fault, > .plane_id = > PLANE_PRIMARY, }, > + { .fault = GEN8_PIPE_CURSOR_FAULT, .handle = handle_plane_fault, > .plane_id = > PLANE_CURSOR, }, > + {} > +}; > + > +static const struct pipe_fault_handler * > +gen8_pipe_fault_handlers(struct intel_display *display) > +{ > + if (DISPLAY_VER(display) >= 14) > + return mtl_pipe_fault_handlers; > + else if (DISPLAY_VER(display) >= 12) > + return tgl_pipe_fault_handlers; > + else if (DISPLAY_VER(display) >= 11) > + return icl_pipe_fault_handlers; > + else if (DISPLAY_VER(display) >= 9) > + return skl_pipe_fault_handlers; > + else > + return bdw_pipe_fault_handlers; > +} > + > static void intel_pmdemand_irq_handler(struct drm_i915_private *dev_priv) > { > wake_up_all(&dev_priv->display.pmdemand.waitqueue); > @@ -1182,10 +1331,9 @@ void gen8_de_irq_handler(struct drm_i915_private > *dev_priv, u32 master_ctl) > > fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv); > if (fault_errors) > - drm_err_ratelimited(&dev_priv->drm, > - "Fault errors on pipe %c: 0x%08x\n", > - pipe_name(pipe), > - fault_errors); > + intel_pipe_fault_irq_handler(display, > + > gen8_pipe_fault_handlers(display), > + pipe, fault_errors); > } > > if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&