Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Vinod Govindapillai <vinod.govindapillai@intel.com>
To: intel-xe@lists.freedesktop.org, intel-gfx@lists.freedesktop.org
Cc: vinod.govindapillai@intel.com, imre.deak@intel.com,
	pranay.samala@intel.com
Subject: [PATCH 1/4] drm/i915/hpd: plumb keep_hpd through irq reset
Date: Thu, 27 Aug 2026 01:53:34 +0300	[thread overview]
Message-ID: <20260826225338.804902-2-vinod.govindapillai@intel.com> (raw)
In-Reply-To: <20260826225338.804902-1-vinod.govindapillai@intel.com>

xe_irq_suspend() resets all display interrupt registers, including the
HPD enable/mask registers. When runtime suspending to D3hot with PME
armed, this leaves the display unable to generate the hotplug event that
would wake the device, so a plug goes unnoticed until something else
resumes it.

As we are going to support PME and avoid HPD polling during the runtime
suspend, we need a way to preserve the HPD related interrupt registers.
A keep_hpd flag is used for that purpose and the HPD related interrupt
registers are reset / preserved based on this flag. But we need to plug
this keep_hpd in the existing IRQ suspend / reset mechanism. At this
point this flag is set to false until the PME capability is implemented.

Assisted-by: GitHub_Copilot:claude-opus-5
Signed-off-by: Vinod Govindapillai <vinod.govindapillai@intel.com>
---
 .../gpu/drm/i915/display/intel_display_irq.c  | 46 +++++++++++++------
 .../gpu/drm/i915/display/intel_display_irq.h  |  2 +-
 drivers/gpu/drm/i915/i915_irq.c               | 16 +++----
 drivers/gpu/drm/xe/display/xe_display.c       |  4 +-
 drivers/gpu/drm/xe/display/xe_display.h       |  4 +-
 drivers/gpu/drm/xe/xe_device.c                |  2 +-
 drivers/gpu/drm/xe/xe_irq.c                   | 18 +++++---
 drivers/gpu/drm/xe/xe_irq.h                   |  2 +-
 drivers/gpu/drm/xe/xe_pm.c                    |  4 +-
 9 files changed, 59 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c
index a59b75830bd1..26fc90ff7299 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -1976,16 +1976,20 @@ static void _vlv_display_irq_reset(struct intel_display *display)
 	display->irq.vlv_imr_mask = ~0u;
 }
 
-static void vlv_display_irq_reset(struct intel_display *display)
+static void vlv_display_irq_reset(struct intel_display *display, bool keep_hpd)
 {
+	drm_WARN_ON(display->drm, keep_hpd);
+
 	spin_lock_irq(&display->irq.lock);
 	if (display->irq.vlv_display_irqs_enabled)
 		_vlv_display_irq_reset(display);
 	spin_unlock_irq(&display->irq.lock);
 }
 
-static void i9xx_display_irq_reset(struct intel_display *display)
+static void i9xx_display_irq_reset(struct intel_display *display, bool keep_hpd)
 {
+	drm_WARN_ON(display->drm, keep_hpd);
+
 	if (HAS_HOTPLUG(display)) {
 		i915_hotplug_interrupt_update(display, 0xffffffff, 0);
 		intel_de_rmw(display, PORT_HOTPLUG_STAT(display), 0, 0);
@@ -2177,8 +2181,10 @@ static void ibx_display_irq_reset(struct intel_display *display)
 		intel_de_write(display, SERR_INT, 0xffffffff);
 }
 
-static void ilk_display_irq_reset(struct intel_display *display)
+static void ilk_display_irq_reset(struct intel_display *display, bool keep_hpd)
 {
+	drm_WARN_ON(display->drm, keep_hpd);
+
 	irq_reset(display, DE_IRQ_REGS);
 	display->irq.ilk_de_imr_mask = ~0u;
 
@@ -2193,10 +2199,12 @@ static void ilk_display_irq_reset(struct intel_display *display)
 	ibx_display_irq_reset(display);
 }
 
-static void gen8_display_irq_reset(struct intel_display *display)
+static void gen8_display_irq_reset(struct intel_display *display, bool keep_hpd)
 {
 	enum pipe pipe;
 
+	drm_WARN_ON(display->drm, keep_hpd);
+
 	intel_de_write(display, EDP_PSR_IMR, 0xffffffff);
 	intel_de_write(display, EDP_PSR_IIR, 0xffffffff);
 
@@ -2212,13 +2220,14 @@ static void gen8_display_irq_reset(struct intel_display *display)
 		ibx_display_irq_reset(display);
 }
 
-static void gen11_display_irq_reset(struct intel_display *display)
+static void gen11_display_irq_reset(struct intel_display *display, bool keep_hpd)
 {
 	enum pipe pipe;
 	u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) |
 		BIT(TRANSCODER_C) | BIT(TRANSCODER_D);
 
-	intel_de_write(display, GEN11_DISPLAY_INT_CTL, 0);
+	if (!keep_hpd)
+		intel_de_write(display, GEN11_DISPLAY_INT_CTL, 0);
 
 	if (DISPLAY_VER(display) >= 12) {
 		enum transcoder trans;
@@ -2250,13 +2259,20 @@ static void gen11_display_irq_reset(struct intel_display *display)
 	irq_reset(display, GEN8_DE_PORT_IRQ_REGS);
 	irq_reset(display, GEN8_DE_MISC_IRQ_REGS);
 
-	if (DISPLAY_VER(display) >= 14)
-		irq_reset(display, PICAINTERRUPT_IRQ_REGS);
-	else
-		irq_reset(display, GEN11_DE_HPD_IRQ_REGS);
+	/*
+	 * When runtime suspending to D3hot with PME armed, leave the HPD
+	 * interrupt registers programmed so that a hotplug can still
+	 * generate the wake event. Everything else is reset as usual.
+	 */
+	if (!keep_hpd) {
+		if (DISPLAY_VER(display) >= 14)
+			irq_reset(display, PICAINTERRUPT_IRQ_REGS);
+		else
+			irq_reset(display, GEN11_DE_HPD_IRQ_REGS);
 
-	if (INTEL_PCH_TYPE(display) >= PCH_ICP)
-		irq_reset(display, SDE_IRQ_REGS);
+		if (INTEL_PCH_TYPE(display) >= PCH_ICP)
+			irq_reset(display, SDE_IRQ_REGS);
+	}
 }
 
 void gen8_irq_power_well_post_enable(struct intel_display *display,
@@ -2542,7 +2558,7 @@ static void gen11_de_irq_postinstall(struct intel_display *display)
 }
 
 struct intel_display_irq_funcs {
-	void (*reset)(struct intel_display *display);
+	void (*reset)(struct intel_display *display, bool keep_hpd);
 	void (*postinstall)(struct intel_display *display);
 	void (*ack)(struct intel_display *display, struct intel_display_irq_state *state);
 	bool (*handler)(struct intel_display *display, const struct intel_display_irq_state *state);
@@ -2587,12 +2603,12 @@ static const struct intel_display_irq_funcs i915_display_irq_funcs = {
 	.handler = i915_display_irq_handler,
 };
 
-void intel_display_irq_reset(struct intel_display *display)
+void intel_display_irq_reset(struct intel_display *display, bool keep_hpd)
 {
 	if (!HAS_DISPLAY(display))
 		return;
 
-	display->irq.funcs->reset(display);
+	display->irq.funcs->reset(display, keep_hpd);
 }
 
 void intel_display_irq_postinstall(struct intel_display *display)
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h
index 84446bf53401..106f6d979f71 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.h
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.h
@@ -64,7 +64,7 @@ struct intel_display_irq_state {
 	u32 pipe_stats[I915_MAX_PIPES];
 };
 
-void intel_display_irq_reset(struct intel_display *display);
+void intel_display_irq_reset(struct intel_display *display, bool keep_hpd);
 void intel_display_irq_postinstall(struct intel_display *display);
 void intel_display_irq_ack(struct intel_display *display, struct intel_display_irq_state *state);
 bool intel_display_irq_handler(struct intel_display *display, const struct intel_display_irq_state *state);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 932409b943ad..db53b6e82d8e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -599,7 +599,7 @@ static void ilk_irq_reset(struct drm_i915_private *dev_priv)
 	struct intel_display *display = dev_priv->display;
 
 	/* The master interrupt enable is in DEIER, reset display irq first */
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 	gen5_gt_irq_reset(to_gt(dev_priv));
 }
 
@@ -612,7 +612,7 @@ static void valleyview_irq_reset(struct drm_i915_private *dev_priv)
 
 	gen5_gt_irq_reset(to_gt(dev_priv));
 
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 }
 
 static void gen8_irq_reset(struct drm_i915_private *dev_priv)
@@ -623,7 +623,7 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv)
 	gen8_master_intr_disable(intel_uncore_regs(uncore));
 
 	gen8_gt_irq_reset(to_gt(dev_priv));
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 	gen2_irq_reset(uncore, GEN8_PCU_IRQ_REGS);
 }
 
@@ -636,7 +636,7 @@ static void gen11_irq_reset(struct drm_i915_private *dev_priv)
 	gen11_master_intr_disable(intel_uncore_regs(&dev_priv->uncore));
 
 	gen11_gt_irq_reset(gt);
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 
 	gen2_irq_reset(uncore, GEN11_GU_MISC_IRQ_REGS);
 	gen2_irq_reset(uncore, GEN8_PCU_IRQ_REGS);
@@ -654,7 +654,7 @@ static void dg1_irq_reset(struct drm_i915_private *dev_priv)
 	for_each_gt(gt, dev_priv, i)
 		gen11_gt_irq_reset(gt);
 
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 
 	gen2_irq_reset(uncore, GEN11_GU_MISC_IRQ_REGS);
 	gen2_irq_reset(uncore, GEN8_PCU_IRQ_REGS);
@@ -674,7 +674,7 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv)
 
 	gen2_irq_reset(uncore, GEN8_PCU_IRQ_REGS);
 
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 }
 
 static void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -823,7 +823,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv)
 	struct intel_display *display = dev_priv->display;
 	struct intel_uncore *uncore = &dev_priv->uncore;
 
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 
 	gen2_error_reset(uncore, GEN2_ERROR_REGS);
 	gen2_irq_reset(uncore, GEN2_IRQ_REGS);
@@ -900,7 +900,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv)
 	struct intel_display *display = dev_priv->display;
 	struct intel_uncore *uncore = &dev_priv->uncore;
 
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, false);
 
 	gen2_error_reset(uncore, GEN2_ERROR_REGS);
 	gen2_irq_reset(uncore, GEN2_IRQ_REGS);
diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c
index 7b25c0814674..6f1f8e0b25b5 100644
--- a/drivers/gpu/drm/xe/display/xe_display.c
+++ b/drivers/gpu/drm/xe/display/xe_display.c
@@ -216,14 +216,14 @@ void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir)
 		intel_opregion_asle_intr(display);
 }
 
-void xe_display_irq_reset(struct xe_device *xe)
+void xe_display_irq_reset(struct xe_device *xe, bool keep_hpd)
 {
 	struct intel_display *display = xe->display;
 
 	if (!xe->info.probe_display)
 		return;
 
-	intel_display_irq_reset(display);
+	intel_display_irq_reset(display, keep_hpd);
 }
 
 void xe_display_irq_postinstall(struct xe_device *xe)
diff --git a/drivers/gpu/drm/xe/display/xe_display.h b/drivers/gpu/drm/xe/display/xe_display.h
index 0babb50bfc77..19f313eba6fb 100644
--- a/drivers/gpu/drm/xe/display/xe_display.h
+++ b/drivers/gpu/drm/xe/display/xe_display.h
@@ -34,7 +34,7 @@ void xe_display_shutdown_late(struct xe_device *xe);
 
 void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl);
 void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir);
-void xe_display_irq_reset(struct xe_device *xe);
+void xe_display_irq_reset(struct xe_device *xe, bool keep_hpd);
 void xe_display_irq_postinstall(struct xe_device *xe);
 
 void xe_display_pm_suspend(struct xe_device *xe);
@@ -72,7 +72,7 @@ static inline void xe_display_shutdown_late(struct xe_device *xe) {}
 
 static inline void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl) {}
 static inline void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir) {}
-static inline void xe_display_irq_reset(struct xe_device *xe) {}
+static inline void xe_display_irq_reset(struct xe_device *xe, bool keep_hpd) {}
 static inline void xe_display_irq_postinstall(struct xe_device *xe) {}
 
 static inline void xe_display_pm_suspend(struct xe_device *xe) {}
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 74d566693dfd..2c586dd3e187 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -1190,7 +1190,7 @@ void xe_device_shutdown(struct xe_device *xe)
 
 	xe_display_shutdown(xe);
 
-	xe_irq_suspend(xe);
+	xe_irq_suspend(xe, false);
 
 	for_each_gt(gt, xe, id)
 		xe_gt_shutdown(gt);
diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c
index 9e49e2241da4..eb240615455c 100644
--- a/drivers/gpu/drm/xe/xe_irq.c
+++ b/drivers/gpu/drm/xe/xe_irq.c
@@ -644,7 +644,7 @@ static void vf_irq_reset(struct xe_device *xe)
 	}
 }
 
-static void xe_irq_reset(struct xe_device *xe)
+static void xe_irq_reset(struct xe_device *xe, bool keep_hpd)
 {
 	struct xe_tile *tile;
 	u8 id;
@@ -666,7 +666,7 @@ static void xe_irq_reset(struct xe_device *xe)
 
 	tile = xe_device_get_root_tile(xe);
 	mask_and_disable(tile, GU_MISC_IRQ_OFFSET);
-	xe_display_irq_reset(xe);
+	xe_display_irq_reset(xe, keep_hpd);
 	xe_i2c_irq_reset(xe);
 
 	/*
@@ -789,7 +789,7 @@ static void irq_uninstall(void *arg)
 	if (!atomic_xchg(&xe->irq.enabled, 0))
 		return;
 
-	xe_irq_reset(xe);
+	xe_irq_reset(xe, false);
 
 	if (xe_device_has_msix(xe))
 		xe_irq_msix_free(xe);
@@ -813,7 +813,7 @@ int xe_irq_install(struct xe_device *xe)
 
 	xe_hw_error_init(xe);
 
-	xe_irq_reset(xe);
+	xe_irq_reset(xe, false);
 
 	if (xe_device_has_msix(xe)) {
 		nvec = xe->irq.msix.nvec;
@@ -843,7 +843,7 @@ static void xe_irq_msi_synchronize_irq(struct xe_device *xe)
 	synchronize_irq(to_pci_dev(xe->drm.dev)->irq);
 }
 
-void xe_irq_suspend(struct xe_device *xe)
+void xe_irq_suspend(struct xe_device *xe, bool keep_hpd)
 {
 	atomic_set(&xe->irq.enabled, 0); /* no new irqs */
 
@@ -852,7 +852,7 @@ void xe_irq_suspend(struct xe_device *xe)
 		xe_irq_msix_synchronize_irq(xe);
 	else
 		xe_irq_msi_synchronize_irq(xe);
-	xe_irq_reset(xe); /* turn irqs off */
+	xe_irq_reset(xe, keep_hpd); /* turn irqs off */
 }
 
 void xe_irq_resume(struct xe_device *xe)
@@ -866,7 +866,11 @@ void xe_irq_resume(struct xe_device *xe)
 	 * 2. display is not yet resumed
 	 */
 	atomic_set(&xe->irq.enabled, 1);
-	xe_irq_reset(xe);
+	/*
+	 * Always a full reset here: once awake, HPD is delivered as a normal
+	 * interrupt again and the postinstall below re-arms that path.
+	 */
+	xe_irq_reset(xe, false);
 	xe_irq_postinstall(xe); /* turn irqs on */
 
 	for_each_gt(gt, xe, id)
diff --git a/drivers/gpu/drm/xe/xe_irq.h b/drivers/gpu/drm/xe/xe_irq.h
index a28bd577ba52..eb9eb2060ff5 100644
--- a/drivers/gpu/drm/xe/xe_irq.h
+++ b/drivers/gpu/drm/xe/xe_irq.h
@@ -16,7 +16,7 @@ struct xe_gt;
 
 int xe_irq_init(struct xe_device *xe);
 int xe_irq_install(struct xe_device *xe);
-void xe_irq_suspend(struct xe_device *xe);
+void xe_irq_suspend(struct xe_device *xe, bool keep_hpd);
 void xe_irq_resume(struct xe_device *xe);
 void xe_irq_enable_hwe(struct xe_gt *gt);
 int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler, void *irq_buf,
diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
index f517bf453b54..1488c4dfcc05 100644
--- a/drivers/gpu/drm/xe/xe_pm.c
+++ b/drivers/gpu/drm/xe/xe_pm.c
@@ -202,7 +202,7 @@ int xe_pm_suspend(struct xe_device *xe)
 			goto err_display;
 	}
 
-	xe_irq_suspend(xe);
+	xe_irq_suspend(xe, false);
 
 	xe_display_pm_suspend_late(xe);
 
@@ -639,7 +639,7 @@ int xe_pm_runtime_suspend(struct xe_device *xe)
 			goto out_resume;
 	}
 
-	xe_irq_suspend(xe);
+	xe_irq_suspend(xe, false);
 
 	xe_display_pm_runtime_suspend_late(xe);
 
-- 
2.43.0


  reply	other threads:[~2026-08-26 22:54 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26 22:53 [PATCH 0/4] PM_PME support on display hotplug Vinod Govindapillai
2026-08-26 22:53 ` Vinod Govindapillai [this message]
2026-08-26 23:08   ` [PATCH 1/4] drm/i915/hpd: plumb keep_hpd through irq reset sashiko-bot
2026-08-26 22:53 ` [PATCH 2/4] drm/xe/pm: plumb PME capability to runtime suspend handler Vinod Govindapillai
2026-08-26 23:04   ` sashiko-bot
2026-08-26 22:53 ` [PATCH 3/4] drm/xe/pm: allow the device to signal PME from D3hot Vinod Govindapillai
2026-08-26 23:01   ` sashiko-bot
2026-08-26 22:53 ` [PATCH 4/4] drm/i915/display: Avoid HPD polling if the device is PME capable Vinod Govindapillai
2026-08-27  0:08 ` ✓ i915.CI.BAT: success for pm_pme support on display hotplug (rev2) Patchwork
2026-08-27  7:29 ` ✗ i915.CI.Full: failure " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260826225338.804902-2-vinod.govindapillai@intel.com \
    --to=vinod.govindapillai@intel.com \
    --cc=imre.deak@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=pranay.samala@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox