On Tue, Jul 15, 2025 at 06:38:15PM +0530, Dibin Moolakadan Subrahmanian wrote: > > On 15-07-2025 15:10, Imre Deak wrote: > > On Tue, Jul 15, 2025 at 11:22:19AM +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 a new `ignore_dig_port` flag in the > > > hotplug in structure. This flag is checked in the interrupt handler to > > > prevent queuing of `dig_port_work` while the system is mid-suspend. > > > This behavior is consistent with the existing approach of suppressing > > > hotplug_work during suspend. > > > > > > Signed-off-by: Dibin Moolakadan Subrahmanian > > > <dibin.moolakadan.subrahman...@intel.com> > > > --- > > > .../gpu/drm/i915/display/intel_display_core.h | 3 +++ > > > drivers/gpu/drm/i915/display/intel_hotplug.c | 22 ++++++++++++++++++- > > > drivers/gpu/drm/i915/display/intel_hotplug.h | 2 ++ > > > drivers/gpu/drm/xe/display/xe_display.c | 4 ++++ > > > 4 files changed, 30 insertions(+), 1 deletion(-) > > > > > > diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h > > > b/drivers/gpu/drm/i915/display/intel_display_core.h > > > index 8c226406c5cd..376682c53798 100644 > > > --- a/drivers/gpu/drm/i915/display/intel_display_core.h > > > +++ b/drivers/gpu/drm/i915/display/intel_display_core.h > > > @@ -209,6 +209,9 @@ struct intel_hotplug { > > > * cue to ignore the long HPDs and can be set / unset using > > > debugfs. > > > */ > > > bool ignore_long_hpd; > > > + > > > + /* Flag to ignore dig_port work , used in suspend*/ > > > + bool ignore_dig_port; > > > }; > > > struct intel_vbt_data { > > > diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c > > > b/drivers/gpu/drm/i915/display/intel_hotplug.c > > > index 265aa97fcc75..b2891b7c3205 100644 > > > --- a/drivers/gpu/drm/i915/display/intel_hotplug.c > > > +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c > > > @@ -223,6 +223,26 @@ queue_detection_work(struct intel_display *display, > > > struct work_struct *work) > > > return queue_work(display->wq.unordered, work); > > > } > > > +void intel_hpd_ignore_dig_port_work(struct intel_display *display, bool > > > value) > > > +{ > > > + if (!HAS_DISPLAY(display)) > > > + return; > > > + > > > + spin_lock_irq(&display->irq.lock); > > > + display->hotplug.ignore_dig_port = value; > > > + spin_unlock_irq(&display->irq.lock); > > > +} > > > + > > > +bool intel_hpd_can_queue_dig_port(struct intel_display *display) > > > +{ > > > + if (!HAS_DISPLAY(display)) > > > + return FALSE; > > > + > > > + lockdep_assert_held(&display->irq.lock); > > > + > > > + return !display->hotplug.ignore_dig_port; > > > +} > > > + > > > static void > > > intel_hpd_irq_storm_switch_to_polling(struct intel_display *display) > > > { > > > @@ -691,7 +711,7 @@ void intel_hpd_irq_handler(struct intel_display > > > *display, > > > * queue for otherwise the flush_work in the pageflip code will > > > * deadlock. > > > */ > > > - if (queue_dig) > > > + if (queue_dig && intel_hpd_can_queue_dig_port(display)) > > > queue_work(display->hotplug.dp_wq, > > > &display->hotplug.dig_port_work); > > > if (queue_hp) > > > queue_delayed_detection_work(display, > > > diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h > > > b/drivers/gpu/drm/i915/display/intel_hotplug.h > > > index edc41c9d3d65..9dc40ec7074c 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_ignore_dig_port_work(struct intel_display *display, bool > > > value); > > > +bool intel_hpd_can_queue_dig_port(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..2db71bd07c9f 100644 > > > --- a/drivers/gpu/drm/xe/display/xe_display.c > > > +++ b/drivers/gpu/drm/xe/display/xe_display.c > > > @@ -342,6 +342,8 @@ void xe_display_pm_suspend(struct xe_device *xe) > > > intel_hpd_cancel_work(display); > > > + intel_hpd_ignore_dig_port_work(display, 1); > > > + > > The actual problem is that HPD IRQs are disabled too late in xe, this > > should happen already before intel_hpd_cancel_work() is called. > > You're right — the HPD IRQs appear to be disabled only later via > xe_irq_suspend(xe), > which is not early enough to prevent unwanted behavior during suspend. > > But unlike the HPD IRQ enable path, which uses function pointers from > struct intel_hotplug_funcs, there doesn't appear to be a hook to disable IRQs > early. > > The proposed approach mirrors how we're already handling hotplug_work, > which is gated by the detection_work_enabled flag. This flag is cleared > during suspend > by intel_display_driver_disable_user_access().
The work should not run after intel_hpd_cancel_work() returns. To ensure that it's the IRQs scheduling the work which should be disabled, before intel_hpd_cancel_work() is called. For now, calling intel_hpd_block() on all the encoders would be enough for that. intel_hpd_cancel_work() will see then blocked IRQs, so the WARN about that should be removed from it. > Regards, > Dibin > > > > if (has_display(xe)) { > > > intel_display_driver_suspend_access(display); > > > intel_encoder_suspend_all(display); > > > @@ -469,6 +471,8 @@ void xe_display_pm_resume(struct xe_device *xe) > > > if (has_display(xe)) > > > intel_display_driver_resume_access(display); > > > + intel_hpd_ignore_dig_port_work(display, 0); > > > + > > > intel_hpd_init(display); > > > if (has_display(xe)) { > > > -- > > > 2.43.0 > > >