The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v2 0/3] x86/irq: Fix lost interrupts on CPU hot-unplug for Hyper-V PCI/MSI
@ 2026-08-10  9:07 Naman Jain
  2026-08-10  9:07 ` [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip Naman Jain
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Naman Jain @ 2026-08-10  9:07 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	Joerg Roedel (AMD), Will Deacon, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, Long Li, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Helgaas
  Cc: H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde, Robin Murphy,
	Rob Herring, Shradha Gupta, Aditya Garg, iommu, linux-hyperv,
	linux-pci, linux-kernel

On CPU hot-unplug, fixup_irqs() re-injects interrupts that are still
pending in the outgoing CPU's IRR via the irqchip's irq_retrigger()
callback. The Hyper-V vPCI MSI irqchip never installs one, so such a
pending interrupt is silently dropped, leading to lost interrupts, stalls
and "No irq handler for vector" messages.

Patch 1 is the minimal, backportable fix (Fixes:/Cc: stable) that installs
irq_chip_retrigger_hierarchy() on the Hyper-V PCI/MSI chip. Patch 2 then
switches fixup_irqs() to call irq_chip_retrigger_hierarchy() directly, so
the retrigger works for any stacked irqchip without a per-chip callback.
Patch 3 drops the now-redundant irq_retrigger() initializations.
This way, patch 2 and 3 do not need to be backported.

Changes since v1:
https://lore.kernel.org/all/20260728135117.2888175-1-namjain@linux.microsoft.com/#t
* Added Review tags
* Adding minor clarification in commit msg of patch 2 (Shradha)

Original RFC: https://lore.kernel.org/all/87y0f3jhd6.ffs@fw13/

Naman Jain (3):
  PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
  x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
  x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits

 arch/x86/kernel/apic/io_apic.c |  2 --
 arch/x86/kernel/apic/msi.c     |  4 +---
 arch/x86/kernel/hpet.c         |  1 -
 arch/x86/kernel/irq.c          | 23 +++++++----------------
 drivers/iommu/amd/init.c       |  1 -
 5 files changed, 8 insertions(+), 23 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
  2026-08-10  9:07 [PATCH v2 0/3] x86/irq: Fix lost interrupts on CPU hot-unplug for Hyper-V PCI/MSI Naman Jain
@ 2026-08-10  9:07 ` Naman Jain
  2026-08-10  9:07 ` [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs() Naman Jain
  2026-08-10  9:07 ` [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits Naman Jain
  2 siblings, 0 replies; 4+ messages in thread
From: Naman Jain @ 2026-08-10  9:07 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	Joerg Roedel (AMD), Will Deacon, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, Long Li, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Helgaas
  Cc: H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde, Robin Murphy,
	Rob Herring, Shradha Gupta, Aditya Garg, iommu, linux-hyperv,
	linux-pci, linux-kernel

The Hyper-V vPCI MSI irqchip never installs an irq_retrigger() callback.

On CPU hot-unplug fixup_irqs() migrates the interrupts which are affine to
the outgoing CPU to a new target. If an interrupt still has its pending bit
set in the outgoing CPU's IRR at that point, fixup_irqs() resends it on the
new target through the irqchip's irq_retrigger() callback. As the Hyper-V
PCI/MSI chip does not provide that callback, the pending interrupt is
silently dropped, which can result in lost interrupts, stalls and "No irq
handler for vector" messages during CPU hotplug.

Install irq_chip_retrigger_hierarchy() as the irq_retrigger() callback for
the Hyper-V PCI/MSI irqchip, so that a pending interrupt is resent on its
new target CPU via the parent x86 vector domain.

Fixes: 4daace0d8ce85 ("PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs")
Cc: stable@vger.kernel.org
Suggested-by: Long Li <longli@microsoft.com>
Suggested-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Aditya Garg <gargaditya@linux.microsoft.com>
Reviewed-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
---
 drivers/pci/controller/pci-hyperv.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index cfc8fa403dad6..89816a2bd7cd3 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -2119,6 +2119,7 @@ static bool hv_pcie_init_dev_msi_info(struct device *dev, struct irq_domain *dom
 	info->ops->msi_prepare = hv_msi_prepare;
 
 	chip->irq_set_affinity = irq_chip_set_affinity_parent;
+	chip->irq_retrigger = irq_chip_retrigger_hierarchy;
 
 	if (IS_ENABLED(CONFIG_X86))
 		chip->flags |= IRQCHIP_MOVE_DEFERRED;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
  2026-08-10  9:07 [PATCH v2 0/3] x86/irq: Fix lost interrupts on CPU hot-unplug for Hyper-V PCI/MSI Naman Jain
  2026-08-10  9:07 ` [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip Naman Jain
@ 2026-08-10  9:07 ` Naman Jain
  2026-08-10  9:07 ` [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits Naman Jain
  2 siblings, 0 replies; 4+ messages in thread
From: Naman Jain @ 2026-08-10  9:07 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	Joerg Roedel (AMD), Will Deacon, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, Long Li, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Helgaas
  Cc: H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde, Robin Murphy,
	Rob Herring, Shradha Gupta, Aditya Garg, iommu, linux-hyperv,
	linux-pci, linux-kernel

fixup_irqs() re-injects a pending interrupt on its new target CPU by
looking at the outermost domain chip and invoking its irq_retrigger()
callback directly. That only works when the outermost chip happens to
install an irq_retrigger() callback, which is not guaranteed for every
irqchip and could lead to lost interrupts on CPU hot-unplug.

Use irq_chip_retrigger_hierarchy() instead, which walks up the interrupt
hierarchy until it finds a chip that implements irq_retrigger().

While at it, move the loop-local variables into the loop scope and use a
scoped guard for desc->lock.

VECTOR_RETRIGGERED is now set only when the retrigger succeeds
(irq_chip_retrigger_hierarchy() returns non-zero) instead of
unconditionally. This is harmless today since apic_retrigger_irq()
always returns 1, and arguably more correct. No functional change
intended for chips which already provide an irq_retrigger() callback
on the outermost domain.

Suggested-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
---
 arch/x86/kernel/irq.c | 23 +++++++----------------
 1 file changed, 7 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 30122f0b3af96..ef1bdd3c4659a 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -466,11 +466,6 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_posted_msi_notification)
 /* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
 void fixup_irqs(void)
 {
-	unsigned int vector;
-	struct irq_desc *desc;
-	struct irq_data *data;
-	struct irq_chip *chip;
-
 	irq_migrate_all_off_this_cpu();
 
 	/*
@@ -489,22 +484,18 @@ void fixup_irqs(void)
 	 * vector_lock because the cpu is already marked !online, so
 	 * nothing else will touch it.
 	 */
-	for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
-		if (IS_ERR_OR_NULL(__this_cpu_read(vector_irq[vector])))
+	for (unsigned int vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
+		struct irq_desc *desc = __this_cpu_read(vector_irq[vector]);
+
+		if (IS_ERR_OR_NULL(desc))
 			continue;
 
 		if (is_vector_pending(vector)) {
-			desc = __this_cpu_read(vector_irq[vector]);
-
-			raw_spin_lock(&desc->lock);
-			data = irq_desc_get_irq_data(desc);
-			chip = irq_data_get_irq_chip(data);
-			if (chip->irq_retrigger) {
-				chip->irq_retrigger(data);
+			guard(raw_spinlock)(&desc->lock);
+			if (irq_chip_retrigger_hierarchy(&desc->irq_data))
 				__this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED);
-			}
-			raw_spin_unlock(&desc->lock);
 		}
+
 		if (__this_cpu_read(vector_irq[vector]) != VECTOR_RETRIGGERED)
 			__this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits
  2026-08-10  9:07 [PATCH v2 0/3] x86/irq: Fix lost interrupts on CPU hot-unplug for Hyper-V PCI/MSI Naman Jain
  2026-08-10  9:07 ` [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip Naman Jain
  2026-08-10  9:07 ` [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs() Naman Jain
@ 2026-08-10  9:07 ` Naman Jain
  2 siblings, 0 replies; 4+ messages in thread
From: Naman Jain @ 2026-08-10  9:07 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	Joerg Roedel (AMD), Will Deacon, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, Long Li, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Helgaas
  Cc: H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde, Robin Murphy,
	Rob Herring, Shradha Gupta, Aditya Garg, iommu, linux-hyperv,
	linux-pci, linux-kernel

With fixup_irqs() now using irq_chip_retrigger_hierarchy() and the generic
resend path (try_retrigger()) already falling back to it, installing
irq_chip_retrigger_hierarchy() as the irq_retrigger() callback on the
outermost domain chips is no longer required. The hierarchy walk reaches
the x86 vector domain's apic_retrigger_irq() for all of these stacked
domain chips.

Remove the now redundant irq_retrigger() initializations from the outermost
domain interrupt chips.
msi_set_affinity() is the only site that invoked the outermost chip's
irq_retrigger() directly. Convert it to irq_chip_retrigger_hierarchy() so
the x86_init_dev_msi_info() initialization can be dropped as well.

No functional change intended.

Suggested-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
---
 arch/x86/kernel/apic/io_apic.c      | 2 --
 arch/x86/kernel/apic/msi.c          | 4 +---
 arch/x86/kernel/hpet.c              | 1 -
 drivers/iommu/amd/init.c            | 1 -
 drivers/pci/controller/pci-hyperv.c | 1 -
 5 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 7d7175d012288..18f49a251f23b 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1857,7 +1857,6 @@ static struct irq_chip ioapic_chip __read_mostly = {
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
-	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_get_irqchip_state	= ioapic_irq_get_chip_state,
 	.flags			= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MOVE_DEFERRED |
 				  IRQCHIP_AFFINITY_PRE_STARTUP,
@@ -1871,7 +1870,6 @@ static struct irq_chip ioapic_ir_chip __read_mostly = {
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ir_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
-	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_get_irqchip_state	= ioapic_irq_get_chip_state,
 	.flags			= IRQCHIP_SKIP_SET_WAKE |
 				  IRQCHIP_AFFINITY_PRE_STARTUP,
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 66bc5d3e79db3..aad2f15eb2176 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -137,7 +137,7 @@ msi_set_affinity(struct irq_data *irqd, const struct cpumask *mask, bool force)
 	 * IRR.
 	 */
 	if (lapic_vector_set_in_irr(cfg->vector))
-		irq_data_get_irq_chip(irqd)->irq_retrigger(irqd);
+		irq_chip_retrigger_hierarchy(irqd);
 
 	return ret;
 }
@@ -246,7 +246,6 @@ static bool x86_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
 	info->ops->msi_prepare		= x86_msi_prepare;
 
 	info->chip->irq_ack		= irq_chip_ack_parent;
-	info->chip->irq_retrigger	= irq_chip_retrigger_hierarchy;
 	info->chip->flags		|= IRQCHIP_SKIP_SET_WAKE |
 					   IRQCHIP_AFFINITY_PRE_STARTUP;
 
@@ -313,7 +312,6 @@ static struct irq_chip dmar_msi_controller = {
 	.irq_mask		= dmar_msi_mask,
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_set_affinity	= msi_domain_set_affinity,
-	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_compose_msi_msg	= dmar_msi_compose_msg,
 	.irq_write_msi_msg	= dmar_msi_write_msg,
 	.flags			= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MOVE_DEFERRED |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 8dc7b710e1250..2bb7a6f466af3 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -509,7 +509,6 @@ static struct irq_chip hpet_msi_controller __ro_after_init = {
 	.irq_mask = hpet_msi_mask,
 	.irq_ack = irq_chip_ack_parent,
 	.irq_set_affinity = msi_domain_set_affinity,
-	.irq_retrigger = irq_chip_retrigger_hierarchy,
 	.irq_write_msi_msg = hpet_msi_write_msg,
 	.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_AFFINITY_PRE_STARTUP,
 };
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index ea3377e61aa5c..0c362e86a09d9 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -2468,7 +2468,6 @@ static struct irq_chip intcapxt_controller = {
 	.irq_unmask		= intcapxt_unmask_irq,
 	.irq_mask		= intcapxt_mask_irq,
 	.irq_ack		= irq_chip_ack_parent,
-	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_set_affinity       = intcapxt_set_affinity,
 	.irq_set_wake		= intcapxt_set_wake,
 	.flags			= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_MOVE_DEFERRED,
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 89816a2bd7cd3..cfc8fa403dad6 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -2119,7 +2119,6 @@ static bool hv_pcie_init_dev_msi_info(struct device *dev, struct irq_domain *dom
 	info->ops->msi_prepare = hv_msi_prepare;
 
 	chip->irq_set_affinity = irq_chip_set_affinity_parent;
-	chip->irq_retrigger = irq_chip_retrigger_hierarchy;
 
 	if (IS_ENABLED(CONFIG_X86))
 		chip->flags |= IRQCHIP_MOVE_DEFERRED;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-10  9:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10  9:07 [PATCH v2 0/3] x86/irq: Fix lost interrupts on CPU hot-unplug for Hyper-V PCI/MSI Naman Jain
2026-08-10  9:07 ` [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip Naman Jain
2026-08-10  9:07 ` [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs() Naman Jain
2026-08-10  9:07 ` [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits Naman Jain

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox