On Thu, Jul 17, 2025 at 02:24:25PM +0530, Dibin Moolakadan Subrahmanian wrote: > It has been observed that during `xe_display_pm_suspend()` execution, > an HPD interrupt can still be triggered, resulting in `dig_port_work` > being scheduled. The issue arises when this work executes after > `xe_display_pm_suspend_late()`, by which time the display is fully > suspended. > > This can lead to errors such as "DC state mismatch", as the dig_port > work accesses display resources that are no longer available or > powered. > > To address this, introduce 'intel_hpd_block_all_encoders()' and > 'intel_hpd_unblock_all_encoders()' functions, which iterate over all > encoders and block/unblock HPD respectively. > > These are used to: > - Block HPD IRQs before calling 'intel_hpd_cancel_work' in suspend > - Unblock HPD IRQs after 'intel_hpd_init' in resume > > This will prevent 'dig_port_work' being scheduled during display > suspend. > > Continuation of previous patch discussion: > https://patchwork.freedesktop.org/patch/663964/ > > Signed-off-by: Dibin Moolakadan Subrahmanian > <dibin.moolakadan.subrahman...@intel.com> > --- > drivers/gpu/drm/i915/display/intel_hotplug.c | 24 ++++++++++++++++++-- > drivers/gpu/drm/i915/display/intel_hotplug.h | 2 ++ > drivers/gpu/drm/xe/display/xe_display.c | 4 ++++ > 3 files changed, 28 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c > b/drivers/gpu/drm/i915/display/intel_hotplug.c > index 265aa97fcc75..7ffd8ded1c26 100644 > --- a/drivers/gpu/drm/i915/display/intel_hotplug.c > +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c > @@ -223,6 +223,28 @@ queue_detection_work(struct intel_display *display, > struct work_struct *work) > return queue_work(display->wq.unordered, work); > } > > +void intel_hpd_unblock_all_encoders(struct intel_display *display) > +{ > + struct intel_encoder *encoder; > + > + if (!HAS_DISPLAY(display)) > + return; > + > + for_each_intel_encoder(display->drm, encoder) > + intel_hpd_unblock(encoder); > +} > + > +void intel_hpd_block_all_encoders(struct intel_display *display) > +{ > + struct intel_encoder *encoder; > + > + if (!HAS_DISPLAY(display)) > + return; > + > + for_each_intel_encoder(display->drm, encoder) > + intel_hpd_block(encoder); > +}
intel_encoder.c has the intel_encoder_{suspend,shutdown}_all() helpers called in the same suspend/shutdown paths, so I'd also add these to there calling them stg like intel_encoder_{block,unblock}_all_hpds(). > + > static void > intel_hpd_irq_storm_switch_to_polling(struct intel_display *display) > { > @@ -971,8 +993,6 @@ void intel_hpd_cancel_work(struct intel_display *display) > > spin_lock_irq(&display->irq.lock); > > - drm_WARN_ON(display->drm, get_blocked_hpd_pin_mask(display)); > - > display->hotplug.long_hpd_pin_mask = 0; > display->hotplug.short_hpd_pin_mask = 0; > display->hotplug.event_bits = 0; > diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h > b/drivers/gpu/drm/i915/display/intel_hotplug.h > index edc41c9d3d65..3938c93d2385 100644 > --- a/drivers/gpu/drm/i915/display/intel_hotplug.h > +++ b/drivers/gpu/drm/i915/display/intel_hotplug.h > @@ -34,5 +34,7 @@ void intel_hpd_debugfs_register(struct intel_display > *display); > void intel_hpd_enable_detection_work(struct intel_display *display); > void intel_hpd_disable_detection_work(struct intel_display *display); > bool intel_hpd_schedule_detection(struct intel_display *display); > +void intel_hpd_block_all_encoders(struct intel_display *display); > +void intel_hpd_unblock_all_encoders(struct intel_display *display); > > #endif /* __INTEL_HOTPLUG_H__ */ > diff --git a/drivers/gpu/drm/xe/display/xe_display.c > b/drivers/gpu/drm/xe/display/xe_display.c > index e2e0771cf274..51584ea3ed09 100644 > --- a/drivers/gpu/drm/xe/display/xe_display.c > +++ b/drivers/gpu/drm/xe/display/xe_display.c > @@ -340,6 +340,8 @@ void xe_display_pm_suspend(struct xe_device *xe) > > xe_display_flush_cleanup_work(xe); > > + intel_hpd_block_all_encoders(display); > + Yes, I still think blocking here only the HPD IRQs makes sense, disabling all the display IRQs suggested by Maarten only later. xe_display_pm_shutdown() also misses this. Also xe_display_fini_early() - which is called after disabling all IRQs - misses intel_hpd_cancel_work(). > intel_hpd_cancel_work(display); > > if (has_display(xe)) { > @@ -471,6 +473,8 @@ void xe_display_pm_resume(struct xe_device *xe) > > intel_hpd_init(display); > > + intel_hpd_unblock_all_encoders(display); > + > if (has_display(xe)) { > intel_display_driver_resume(display); > drm_kms_helper_poll_enable(&xe->drm); > -- > 2.43.0 >