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
next prev parent 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