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); + 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