* [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; 22+ 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] 22+ 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-17 3:38 ` Michael Kelley
` (2 more replies)
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, 3 replies; 22+ 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 [flat|nested] 22+ 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-18 5:10 ` Michael Kelley
2026-08-10 9:07 ` [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits Naman Jain
2 siblings, 1 reply; 22+ 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 [flat|nested] 22+ 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
2026-08-18 5:10 ` Michael Kelley
2026-09-09 10:24 ` Thomas Gleixner
2 siblings, 2 replies; 22+ 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 [flat|nested] 22+ messages in thread
* RE: [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
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-17 3:38 ` Michael Kelley
2026-08-17 12:15 ` Naman Jain
2026-08-18 5:10 ` Michael Kelley
2026-08-24 0:22 ` Wei Liu
2 siblings, 1 reply; 22+ messages in thread
From: Michael Kelley @ 2026-08-17 3:38 UTC (permalink / raw)
To: Naman Jain, 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
From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>
> 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.
The RFC version of this patch set listed the asynchronous nature
of the HVCALL_RETARGET_INTERRUPT hypercall as a cause of the
problem. Is that hypercall still believed to be asynchronous?
My understanding of "asynchronous" would be that Hyper-V
does not guarantee that the retargeting of the interrupt to a new
vCPU has occurred when the hypercall returns. There is an
unspecified time period during which the interrupt could still be
directed to the vCPU that is going offline. Furthermore, Hyper-V
provides no rendezvous mechanism for the guest to know when
the interrupt is guaranteed to go to the new vCPU.
If the async behavior is indeed present, isn't it a problem, even
after this patch? irq_migrate_all_off_this_cpu() causes the
RETARGET_INTERRUPT hypercall to be made, but a new interrupt
could still be generated to the going-offline vCPU after fixup_irqs()
runs its loop searching for any pending interrupts. A new such
interrupt would be lost. The 1 millisecond delay in fixup_irqs()
probably mitigates this problem by giving Hyper-V time to complete
the retargeting. But it's not a 100% solution.
Assuming my thinking is correct, there isn't a 100% solution. But
the problem's existence, and the likely benefit of the 1 ms delay,
should be called out in the commit message and/or code
comments for future readers.
I also wondered about arm64 where Hyper-V provides an
emulated GICv3. The RETARGET_INTERRUPT hypercall is not
used since the retargeting is done by writing to a GICD register.
Presumably on real GICv3 hardware, after the write the new
CPU is guaranteed to receive any subsequent interrupts. And if
an interrupt was pending at the time of the write, the appropriate
trigger happens in the new CPU, so everything works. As long
as Hyper-V is doing the emulation the same way (i.e., fully
synchronously), the problem would not occur on arm64
guests.
I'm reminded that a similar problem occurred with changing
the target CPU for a VMBus channel interrupt. The initial
Hyper-V implementation of the VMBus MODIFYCHANNEL
message was asynchronous, which caused the same problem
as seen here if a vCPU were to be taken offline. A later version
of the VMBus protocol added a notification that the change to
the target vCPU is complete, which solves the problem. See
vmbus_channel_set_cpu() and vmbus_send_modifychannel()
and the associated code comments.
Michael
>
> 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 [flat|nested] 22+ messages in thread
* Re: [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
2026-08-17 3:38 ` Michael Kelley
@ 2026-08-17 12:15 ` Naman Jain
2026-08-17 15:30 ` Naman Jain
0 siblings, 1 reply; 22+ messages in thread
From: Naman Jain @ 2026-08-17 12:15 UTC (permalink / raw)
To: Michael Kelley, 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 8/17/2026 9:08 AM, Michael Kelley wrote:
> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>>
>> 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.
>
> The RFC version of this patch set listed the asynchronous nature
> of the HVCALL_RETARGET_INTERRUPT hypercall as a cause of the
> problem. Is that hypercall still believed to be asynchronous?
> My understanding of "asynchronous" would be that Hyper-V
> does not guarantee that the retargeting of the interrupt to a new
> vCPU has occurred when the hypercall returns. There is an
> unspecified time period during which the interrupt could still be
> directed to the vCPU that is going offline. Furthermore, Hyper-V
> provides no rendezvous mechanism for the guest to know when
> the interrupt is guaranteed to go to the new vCPU.
>
> If the async behavior is indeed present, isn't it a problem, even
> after this patch? irq_migrate_all_off_this_cpu() causes the
> RETARGET_INTERRUPT hypercall to be made, but a new interrupt
> could still be generated to the going-offline vCPU after fixup_irqs()
> runs its loop searching for any pending interrupts. A new such
> interrupt would be lost. The 1 millisecond delay in fixup_irqs()
> probably mitigates this problem by giving Hyper-V time to complete
> the retargeting. But it's not a 100% solution.
> > Assuming my thinking is correct, there isn't a 100% solution. But
> the problem's existence, and the likely benefit of the 1 ms delay,
> should be called out in the commit message and/or code
> comments for future readers.
Please allow me to confirm with the Hyper-V team internally once. I may
have assumed asynchronous behavior because of the pending interrupt
after retarget. It could simply have been committed to the old route
before the retarget operation.
>
> I also wondered about arm64 where Hyper-V provides an
> emulated GICv3. The RETARGET_INTERRUPT hypercall is not
> used since the retargeting is done by writing to a GICD register.
> Presumably on real GICv3 hardware, after the write the new
> CPU is guaranteed to receive any subsequent interrupts. And if
> an interrupt was pending at the time of the write, the appropriate
> trigger happens in the new CPU, so everything works. As long
> as Hyper-V is doing the emulation the same way (i.e., fully
> synchronously), the problem would not occur on arm64
> guests.
>
> I'm reminded that a similar problem occurred with changing
> the target CPU for a VMBus channel interrupt. The initial
> Hyper-V implementation of the VMBus MODIFYCHANNEL
> message was asynchronous, which caused the same problem
> as seen here if a vCPU were to be taken offline. A later version
> of the VMBus protocol added a notification that the change to
> the target vCPU is complete, which solves the problem. See
> vmbus_channel_set_cpu() and vmbus_send_modifychannel()
> and the associated code comments.
>
Thanks for sharing this info. I'll check and get back.
Regards,
Naman
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
2026-08-17 12:15 ` Naman Jain
@ 2026-08-17 15:30 ` Naman Jain
2026-08-17 17:14 ` Michael Kelley
0 siblings, 1 reply; 22+ messages in thread
From: Naman Jain @ 2026-08-17 15:30 UTC (permalink / raw)
To: Michael Kelley, 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 8/17/2026 5:45 PM, Naman Jain wrote:
>
>
> On 8/17/2026 9:08 AM, Michael Kelley wrote:
>> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August
>> 10, 2026 2:07 AM
>>>
>>> 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.
>>
>> The RFC version of this patch set listed the asynchronous nature
>> of the HVCALL_RETARGET_INTERRUPT hypercall as a cause of the
>> problem. Is that hypercall still believed to be asynchronous?
>> My understanding of "asynchronous" would be that Hyper-V
>> does not guarantee that the retargeting of the interrupt to a new
>> vCPU has occurred when the hypercall returns. There is an
>> unspecified time period during which the interrupt could still be
>> directed to the vCPU that is going offline. Furthermore, Hyper-V
>> provides no rendezvous mechanism for the guest to know when
>> the interrupt is guaranteed to go to the new vCPU.
>>
>> If the async behavior is indeed present, isn't it a problem, even
>> after this patch? irq_migrate_all_off_this_cpu() causes the
>> RETARGET_INTERRUPT hypercall to be made, but a new interrupt
>> could still be generated to the going-offline vCPU after fixup_irqs()
>> runs its loop searching for any pending interrupts. A new such
>> interrupt would be lost. The 1 millisecond delay in fixup_irqs()
>> probably mitigates this problem by giving Hyper-V time to complete
>> the retargeting. But it's not a 100% solution.
> > > Assuming my thinking is correct, there isn't a 100% solution. But
>> the problem's existence, and the likely benefit of the 1 ms delay,
>> should be called out in the commit message and/or code
>> comments for future readers.
>
> Please allow me to confirm with the Hyper-V team internally once. I may
> have assumed asynchronous behavior because of the pending interrupt
> after retarget. It could simply have been committed to the old route
> before the retarget operation.
This is actually synchronous. So the fix in this series should suffice.
Sorry for the confusion.
I don't see any mentions of asynchronous behavior of that hypercall
anywhere in these 3 patches, so I think we should be good.
Regards,
Naman
>
>>
>> I also wondered about arm64 where Hyper-V provides an
>> emulated GICv3. The RETARGET_INTERRUPT hypercall is not
>> used since the retargeting is done by writing to a GICD register.
>> Presumably on real GICv3 hardware, after the write the new
>> CPU is guaranteed to receive any subsequent interrupts. And if
>> an interrupt was pending at the time of the write, the appropriate
>> trigger happens in the new CPU, so everything works. As long
>> as Hyper-V is doing the emulation the same way (i.e., fully
>> synchronously), the problem would not occur on arm64
>> guests.
>>
>> I'm reminded that a similar problem occurred with changing
>> the target CPU for a VMBus channel interrupt. The initial
>> Hyper-V implementation of the VMBus MODIFYCHANNEL
>> message was asynchronous, which caused the same problem
>> as seen here if a vCPU were to be taken offline. A later version
>> of the VMBus protocol added a notification that the change to
>> the target vCPU is complete, which solves the problem. See
>> vmbus_channel_set_cpu() and vmbus_send_modifychannel()
>> and the associated code comments.
>>
>
> Thanks for sharing this info. I'll check and get back.
>
> Regards,
> Naman
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
2026-08-17 15:30 ` Naman Jain
@ 2026-08-17 17:14 ` Michael Kelley
0 siblings, 0 replies; 22+ messages in thread
From: Michael Kelley @ 2026-08-17 17:14 UTC (permalink / raw)
To: Naman Jain, Michael Kelley, 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
From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 17, 2026 8:31 AM
>
> On 8/17/2026 5:45 PM, Naman Jain wrote:
> >
> > On 8/17/2026 9:08 AM, Michael Kelley wrote:
> >> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August
> >> 10, 2026 2:07 AM
> >>>
> >>> 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.
> >>
> >> The RFC version of this patch set listed the asynchronous nature
> >> of the HVCALL_RETARGET_INTERRUPT hypercall as a cause of the
> >> problem. Is that hypercall still believed to be asynchronous?
> >> My understanding of "asynchronous" would be that Hyper-V
> >> does not guarantee that the retargeting of the interrupt to a new
> >> vCPU has occurred when the hypercall returns. There is an
> >> unspecified time period during which the interrupt could still be
> >> directed to the vCPU that is going offline. Furthermore, Hyper-V
> >> provides no rendezvous mechanism for the guest to know when
> >> the interrupt is guaranteed to go to the new vCPU.
> >>
> >> If the async behavior is indeed present, isn't it a problem, even
> >> after this patch? irq_migrate_all_off_this_cpu() causes the
> >> RETARGET_INTERRUPT hypercall to be made, but a new interrupt
> >> could still be generated to the going-offline vCPU after fixup_irqs()
> >> runs its loop searching for any pending interrupts. A new such
> >> interrupt would be lost. The 1 millisecond delay in fixup_irqs()
> >> probably mitigates this problem by giving Hyper-V time to complete
> >> the retargeting. But it's not a 100% solution.
> > > > Assuming my thinking is correct, there isn't a 100% solution. But
> >> the problem's existence, and the likely benefit of the 1 ms delay,
> >> should be called out in the commit message and/or code
> >> comments for future readers.
> >
> > Please allow me to confirm with the Hyper-V team internally once. I may
> > have assumed asynchronous behavior because of the pending interrupt
> > after retarget. It could simply have been committed to the old route
> > before the retarget operation.
>
> This is actually synchronous. So the fix in this series should suffice.
> Sorry for the confusion.
> I don't see any mentions of asynchronous behavior of that hypercall
> anywhere in these 3 patches, so I think we should be good.
>
Thanks for getting the definitive answer. Having it be async was
initially plausible to me given the experience we had with the
VMBus MODIFYCHANNEL message. But upon further reflection,
the VMBus case was really more because it is a messaging protocol
instead of a "call". As a "call", the hypercall really should be
synchronous. And that's consistent with the arm64 behavior of
setting the GICD register.
With this top-level question now resolved, I'll review the patch
series at a more detailed level to see if anything else comes up,
but it looks pretty good in my initial read-through.
Michael
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
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-17 3:38 ` Michael Kelley
@ 2026-08-18 5:10 ` Michael Kelley
2026-08-24 0:22 ` Wei Liu
2 siblings, 0 replies; 22+ messages in thread
From: Michael Kelley @ 2026-08-18 5:10 UTC (permalink / raw)
To: Naman Jain, 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
From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>
> 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
>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
2026-08-10 9:07 ` [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs() Naman Jain
@ 2026-08-18 5:10 ` Michael Kelley
2026-08-18 7:31 ` Naman Jain
0 siblings, 1 reply; 22+ messages in thread
From: Michael Kelley @ 2026-08-18 5:10 UTC (permalink / raw)
To: Naman Jain, 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
From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>
> 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.
Moving the loop-local variables into the loop scope seems to be churn
with no real benefit. I know Thomas' suggested code made that change
and he's the maintainer, so it's his call. But still . . .
Changing to use the scoped guard seems OK since that's a new pattern
we want to be using.
>
> 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))
The existing code uses irq_desc_get_irq_data() instead of directly
accessing the irq_data field. I *think* using the function is preferred,
but maybe I'm out-of-date.
Sashiko pointed out that irq_chip_retrigger_hierarchy() doesn't check
the outermost domain -- it immediately goes the parent. In v1 of this patch
series, you categorized this as a false positive. But I don’t understand
your explanation. Even if there aren't currently any outermost domains
with a custom retrigger function, there could be at some point in the
future. So it seems wrong to skip it. But maybe I'm missing something.
Could you elaborate on your reasoning?
Michael
> __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 [flat|nested] 22+ messages in thread
* RE: [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits
2026-08-10 9:07 ` [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits Naman Jain
@ 2026-08-18 5:10 ` Michael Kelley
2026-08-18 7:31 ` Naman Jain
2026-09-09 10:24 ` Thomas Gleixner
1 sibling, 1 reply; 22+ messages in thread
From: Michael Kelley @ 2026-08-18 5:10 UTC (permalink / raw)
To: Naman Jain, 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
From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>
> 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);
Again, this will miss the outermost chip's retrigger function if it
is set to something custom.
Michael
>
> 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 [flat|nested] 22+ messages in thread
* Re: [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
2026-08-18 5:10 ` Michael Kelley
@ 2026-08-18 7:31 ` Naman Jain
2026-08-19 15:59 ` Michael Kelley
0 siblings, 1 reply; 22+ messages in thread
From: Naman Jain @ 2026-08-18 7:31 UTC (permalink / raw)
To: Michael Kelley, 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 8/18/2026 10:40 AM, Michael Kelley wrote:
> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>>
>> 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.
>
> Moving the loop-local variables into the loop scope seems to be churn
> with no real benefit. I know Thomas' suggested code made that change
> and he's the maintainer, so it's his call. But still . . .
>
> Changing to use the scoped guard seems OK since that's a new pattern
> we want to be using.
>
I can avoid moving this to loop-local variable in next version, if we
are moving ahead with changing the logic for below comments.
>>
>> 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))
>
> The existing code uses irq_desc_get_irq_data() instead of directly
> accessing the irq_data field. I *think* using the function is preferred,
> but maybe I'm out-of-date.
I can switch to irq_desc_get_irq_data().
static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc)
{
return &desc->irq_data;
}
>
> Sashiko pointed out that irq_chip_retrigger_hierarchy() doesn't check
> the outermost domain -- it immediately goes the parent. In v1 of this patch
> series, you categorized this as a false positive. But I don’t understand
> your explanation. Even if there aren't currently any outermost domains
> with a custom retrigger function, there could be at some point in the
> future. So it seems wrong to skip it. But maybe I'm missing something.
> Could you elaborate on your reasoning?
>
> Michael
>
irq_chip_retrigger_hierarchy() deliberately skips the chip passed to it
and begins with its parent, i.e. apic_retrigger_irq(). The new code was
doing the same. However, if someone adds a custom .irq_retrigger, hoping
that it would get executed, it would not.
Sashiko's example was valid in principle, but it is not relevant to
these device interrupts because desc->irq_data is the outer
MSI/IOAPIC/Hyper-V chip. The LAPIC data is its parent, not the starting
data. I found no device IRQ in this path whose descriptor starts
directly at lapic_controller.
I am all in for adding this as a fallback -
+ if (chip->irq_retrigger)
+ ret = chip->irq_retrigger(data);
+ else
+ ret = irq_chip_retrigger_hierarchy(data);
This should solve this problem while still covering the chips which can
forget to add a retrigger function.
Please let me know if this looks good to you.
>> __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
>>
>
Regards,
Naman
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits
2026-08-18 5:10 ` Michael Kelley
@ 2026-08-18 7:31 ` Naman Jain
0 siblings, 0 replies; 22+ messages in thread
From: Naman Jain @ 2026-08-18 7:31 UTC (permalink / raw)
To: Michael Kelley, 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 8/18/2026 10:40 AM, Michael Kelley wrote:
> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>>
>> 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);
>
> Again, this will miss the outermost chip's retrigger function if it
> is set to something custom.
>
> Michael
In case we all agree to adding a fallback in previous patch, I am
afraid, we will have to add it here as well.
Regards,
Naman
>
>>
>> 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 [flat|nested] 22+ messages in thread
* RE: [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
2026-08-18 7:31 ` Naman Jain
@ 2026-08-19 15:59 ` Michael Kelley
2026-08-20 4:47 ` Naman Jain
0 siblings, 1 reply; 22+ messages in thread
From: Michael Kelley @ 2026-08-19 15:59 UTC (permalink / raw)
To: Naman Jain, Michael Kelley, 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
From: Naman Jain <namjain@linux.microsoft.com> Sent: Tuesday, August 18, 2026 12:31 AM
>
> On 8/18/2026 10:40 AM, Michael Kelley wrote:
> > From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
[snip]
> >
> > Sashiko pointed out that irq_chip_retrigger_hierarchy() doesn't check
> > the outermost domain -- it immediately goes the parent. In v1 of this patch
> > series, you categorized this as a false positive. But I don't understand
> > your explanation. Even if there aren't currently any outermost domains
> > with a custom retrigger function, there could be at some point in the
> > future. So it seems wrong to skip it. But maybe I'm missing something.
> > Could you elaborate on your reasoning?
> >
> > Michael
> >
>
> irq_chip_retrigger_hierarchy() deliberately skips the chip passed to it
> and begins with its parent, i.e. apic_retrigger_irq(). The new code was
> doing the same. However, if someone adds a custom .irq_retrigger, hoping
> that it would get executed, it would not.
>
> Sashiko's example was valid in principle, but it is not relevant to
> these device interrupts because desc->irq_data is the outer
> MSI/IOAPIC/Hyper-V chip. The LAPIC data is its parent, not the starting
> data. I found no device IRQ in this path whose descriptor starts
> directly at lapic_controller.
>
> I am all in for adding this as a fallback -
> + if (chip->irq_retrigger)
> + ret = chip->irq_retrigger(data);
> + else
> + ret = irq_chip_retrigger_hierarchy(data);
>
> This should solve this problem while still covering the chips which can
> forget to add a retrigger function.
>
> Please let me know if this looks good to you.
In principle, I think what you have is correct. But there's a
problem in that irq_chip_retrigger_hierarchy() isn't defined
unless CONFIG_IRQ_DOMAIN_HIERARCHY=y. try_retrigger()
is what you want, but it's static. You could add the #ifdef's here
like in try_retrigger(), but the same problem will occur in Patch 3
with msi_set_affinity(). Really need a non-static version of
try_retrigger(). Or maybe just doing the #ifdef's here and in
msi_set_affinity() is the simplest approach. I don't have a
strong opinion either way. Sorry this is getting so messy ....
Michael
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
2026-08-19 15:59 ` Michael Kelley
@ 2026-08-20 4:47 ` Naman Jain
2026-08-20 4:53 ` Michael Kelley
2026-09-09 9:43 ` Thomas Gleixner
0 siblings, 2 replies; 22+ messages in thread
From: Naman Jain @ 2026-08-20 4:47 UTC (permalink / raw)
To: Michael Kelley, 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 8/19/2026 9:29 PM, Michael Kelley wrote:
> From: Naman Jain <namjain@linux.microsoft.com> Sent: Tuesday, August 18, 2026 12:31 AM
>>
>> On 8/18/2026 10:40 AM, Michael Kelley wrote:
>>> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
>
> [snip]
>
>>>
>>> Sashiko pointed out that irq_chip_retrigger_hierarchy() doesn't check
>>> the outermost domain -- it immediately goes the parent. In v1 of this patch
>>> series, you categorized this as a false positive. But I don't understand
>>> your explanation. Even if there aren't currently any outermost domains
>>> with a custom retrigger function, there could be at some point in the
>>> future. So it seems wrong to skip it. But maybe I'm missing something.
>>> Could you elaborate on your reasoning?
>>>
>>> Michael
>>>
>>
>> irq_chip_retrigger_hierarchy() deliberately skips the chip passed to it
>> and begins with its parent, i.e. apic_retrigger_irq(). The new code was
>> doing the same. However, if someone adds a custom .irq_retrigger, hoping
>> that it would get executed, it would not.
>>
>> Sashiko's example was valid in principle, but it is not relevant to
>> these device interrupts because desc->irq_data is the outer
>> MSI/IOAPIC/Hyper-V chip. The LAPIC data is its parent, not the starting
>> data. I found no device IRQ in this path whose descriptor starts
>> directly at lapic_controller.
>>
>> I am all in for adding this as a fallback -
>> + if (chip->irq_retrigger)
>> + ret = chip->irq_retrigger(data);
>> + else
>> + ret = irq_chip_retrigger_hierarchy(data);
>>
>> This should solve this problem while still covering the chips which can
>> forget to add a retrigger function.
>>
>> Please let me know if this looks good to you.
>
> In principle, I think what you have is correct. But there's a
> problem in that irq_chip_retrigger_hierarchy() isn't defined
> unless CONFIG_IRQ_DOMAIN_HIERARCHY=y. try_retrigger()
> is what you want, but it's static. You could add the #ifdef's here
> like in try_retrigger(), but the same problem will occur in Patch 3
> with msi_set_affinity(). Really need a non-static version of
> try_retrigger(). Or maybe just doing the #ifdef's here and in
> msi_set_affinity() is the simplest approach. I don't have a
> strong opinion either way. Sorry this is getting so messy ....
>
> Michael
Hi Michael,
Config dependencies make sure that CONFIG_IRQ_DOMAIN_HIERARCHY is
defined wherever irq_chip_retrigger_hierarchy() is getting called.
x86 SMP or x86-64 guarantees X86_LOCAL_APIC → IRQ_DOMAIN_HIERARCHY,
PCI_MSI guarantees it via GENERIC_MSI_IRQ. So the #ifdef may not be
required.
Hi Thomas,
Can you please comment if you are OK with me adding this fallback
mechanism in next version.
Regards,
Naman
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
2026-08-20 4:47 ` Naman Jain
@ 2026-08-20 4:53 ` Michael Kelley
2026-09-09 9:43 ` Thomas Gleixner
1 sibling, 0 replies; 22+ messages in thread
From: Michael Kelley @ 2026-08-20 4:53 UTC (permalink / raw)
To: Naman Jain, Michael Kelley, 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
From: Naman Jain <namjain@linux.microsoft.com> Sent: Wednesday, August 19, 2026 9:48 PM
>
> On 8/19/2026 9:29 PM, Michael Kelley wrote:
> > From: Naman Jain <namjain@linux.microsoft.com> Sent: Tuesday, August 18, 2026 12:31 AM
> >>
> >> On 8/18/2026 10:40 AM, Michael Kelley wrote:
> >>> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, August 10, 2026 2:07 AM
> >
> > [snip]
> >
> >>>
> >>> Sashiko pointed out that irq_chip_retrigger_hierarchy() doesn't check
> >>> the outermost domain -- it immediately goes the parent. In v1 of this patch
> >>> series, you categorized this as a false positive. But I don't understand
> >>> your explanation. Even if there aren't currently any outermost domains
> >>> with a custom retrigger function, there could be at some point in the
> >>> future. So it seems wrong to skip it. But maybe I'm missing something.
> >>> Could you elaborate on your reasoning?
> >>>
> >>> Michael
> >>>
> >>
> >> irq_chip_retrigger_hierarchy() deliberately skips the chip passed to it
> >> and begins with its parent, i.e. apic_retrigger_irq(). The new code was
> >> doing the same. However, if someone adds a custom .irq_retrigger, hoping
> >> that it would get executed, it would not.
> >>
> >> Sashiko's example was valid in principle, but it is not relevant to
> >> these device interrupts because desc->irq_data is the outer
> >> MSI/IOAPIC/Hyper-V chip. The LAPIC data is its parent, not the starting
> >> data. I found no device IRQ in this path whose descriptor starts
> >> directly at lapic_controller.
> >>
> >> I am all in for adding this as a fallback -
> >> + if (chip->irq_retrigger)
> >> + ret = chip->irq_retrigger(data);
> >> + else
> >> + ret = irq_chip_retrigger_hierarchy(data);
> >>
> >> This should solve this problem while still covering the chips which can
> >> forget to add a retrigger function.
> >>
> >> Please let me know if this looks good to you.
> >
> > In principle, I think what you have is correct. But there's a
> > problem in that irq_chip_retrigger_hierarchy() isn't defined
> > unless CONFIG_IRQ_DOMAIN_HIERARCHY=y. try_retrigger()
> > is what you want, but it's static. You could add the #ifdef's here
> > like in try_retrigger(), but the same problem will occur in Patch 3
> > with msi_set_affinity(). Really need a non-static version of
> > try_retrigger(). Or maybe just doing the #ifdef's here and in
> > msi_set_affinity() is the simplest approach. I don't have a
> > strong opinion either way. Sorry this is getting so messy ....
> >
> > Michael
>
> Hi Michael,
> Config dependencies make sure that CONFIG_IRQ_DOMAIN_HIERARCHY is
> defined wherever irq_chip_retrigger_hierarchy() is getting called.
>
> x86 SMP or x86-64 guarantees X86_LOCAL_APIC → IRQ_DOMAIN_HIERARCHY,
> PCI_MSI guarantees it via GENERIC_MSI_IRQ. So the #ifdef may not be
> required.
Indeed, I was just looking at this myself before I saw your reply.
I think you are right.
Michael
>
> Hi Thomas,
> Can you please comment if you are OK with me adding this fallback
> mechanism in next version.
>
> Regards,
> Naman
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
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-17 3:38 ` Michael Kelley
2026-08-18 5:10 ` Michael Kelley
@ 2026-08-24 0:22 ` Wei Liu
2 siblings, 0 replies; 22+ messages in thread
From: Wei Liu @ 2026-08-24 0:22 UTC (permalink / raw)
To: Naman Jain
Cc: 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,
H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde,
Robin Murphy, Rob Herring, Shradha Gupta, Aditya Garg, iommu,
linux-hyperv, linux-pci, linux-kernel
On Mon, Aug 10, 2026 at 09:07:13AM +0000, Naman Jain wrote:
> 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>
I applied this patch alone. It is a good bug fix. The rest still have
opens.
Wei
> ---
> 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 [flat|nested] 22+ messages in thread
* Re: [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
2026-08-20 4:47 ` Naman Jain
2026-08-20 4:53 ` Michael Kelley
@ 2026-09-09 9:43 ` Thomas Gleixner
1 sibling, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2026-09-09 9:43 UTC (permalink / raw)
To: Naman Jain, Michael Kelley, 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 Thu, Aug 20 2026 at 10:17, Naman Jain wrote:
> On 8/19/2026 9:29 PM, Michael Kelley wrote:
> Config dependencies make sure that CONFIG_IRQ_DOMAIN_HIERARCHY is
> defined wherever irq_chip_retrigger_hierarchy() is getting called.
>
> x86 SMP or x86-64 guarantees X86_LOCAL_APIC → IRQ_DOMAIN_HIERARCHY,
> PCI_MSI guarantees it via GENERIC_MSI_IRQ. So the #ifdef may not be
> required.
Correct. X86 depends hard on hierarchical interrupt domains.
> Can you please comment if you are OK with me adding this fallback
> mechanism in next version.
I assume you talk about this:
if (chip->irq_retrigger)
ret = chip->irq_retrigger(data);
else
ret = irq_chip_retrigger_hierarchy(data);
It won't hurt, but I can't see a case where the outermost chip which
descends in the hierarchy down to the vector domain would need that at
all.
The point is that any interrupt which is connected to a APIC vector,
i.e. the interrupt descriptor is in the per CPU vector array, will have
the vector domain as root interrupt domain in its hierarchy. Otherwise
it would not end up there.
Therefore retriggering it at the vector domain level is the right thing
to do. The important point is that the retrigger happens on the new
target CPU to ensure that the interrupt which arrived late on the
outgoing CPU is not lost.
When you look at it from a device level (outermost domain), then that
entity sent the message off already and relies on the rest of the system
to take care of it.
That's what the vector level retrigger does. It ensures that the new
target CPU processes the interrupt and keeps the machinery going.
So yes, it looks "safer" with the fallback in theory, but in practice
it's a purely academic exercise.
Thanks,
tglx
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits
2026-08-10 9:07 ` [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits Naman Jain
2026-08-18 5:10 ` Michael Kelley
@ 2026-09-09 10:24 ` Thomas Gleixner
2026-09-10 18:51 ` Michael Kelley
1 sibling, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2026-09-09 10:24 UTC (permalink / raw)
To: Naman Jain, 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 Mon, Aug 10 2026 at 09:07, Naman Jain wrote:
> --- 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);
That's broken because irqd points at the vector domain already, so there
is no parent and nothing gets retriggered.
Let's look at the hierarchy when interrupt remapping is enabled:
| --- [DMAR]
[VECTOR] --- | | -- [IOAPIC]
| --- [REMAP] ---| -- [HPET]
| -- [DEVICE MSI]
All outer domains have .irq_set_affinity = msi_domain_set_affinity,
which does:
msi_domain_set_affinity(irqdata, ....)
irqdata->parent->irq_set_affinity(irqdata->parent, ....);
In that case msi_set_affinity() is only reachable for the DMAR domain
and all others (IOAPIC, HPET, DEVICE MSI) end up in the REMAP domain
which handles irq_set_affinity and never ends up in the above code.
In the non-remapping case:
| -- [IOAPIC]
[VECTOR] --- | -- [HPET]
| -- [DEVICE MSI]
In this case the vector domain is the MSI parent domain for all of them
and all outer domains will end up in msi_set_affinity() via
msi_domain_set_affinity().
In any case 'irqd' in msi_set_affinity() will always point to the vector
domain and therefore the exiting code is correct and can't be changed to
retrigger hierarchy as that would see irqd->parent == NULL and do
nothing. Neither will adding a conditional there do anything useful
because the vector domain always has the retrigger callback set.
Thanks,
tglx
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits
2026-09-09 10:24 ` Thomas Gleixner
@ 2026-09-10 18:51 ` Michael Kelley
2026-09-11 8:11 ` Thomas Gleixner
0 siblings, 1 reply; 22+ messages in thread
From: Michael Kelley @ 2026-09-10 18:51 UTC (permalink / raw)
To: Thomas Gleixner, Naman Jain, 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,
namcao
Cc: H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde,
Robin Murphy, Rob Herring, Shradha Gupta, Aditya Garg, iommu,
linux-hyperv, linux-pci, linux-kernel
From: Thomas Gleixner <tglx@kernel.org> Sent: Wednesday, September 9, 2026 3:24 AM
>
> On Mon, Aug 10 2026 at 09:07, Naman Jain wrote:
> > --- 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);
>
> That's broken because irqd points at the vector domain already, so there
> is no parent and nothing gets retriggered.
>
> Let's look at the hierarchy when interrupt remapping is enabled:
>
> | --- [DMAR]
> [VECTOR] --- | | -- [IOAPIC]
> | --- [REMAP] ---| -- [HPET]
> | -- [DEVICE MSI]
>
> All outer domains have .irq_set_affinity = msi_domain_set_affinity,
> which does:
>
> msi_domain_set_affinity(irqdata, ....)
>
> irqdata->parent->irq_set_affinity(irqdata->parent, ....);
>
> In that case msi_set_affinity() is only reachable for the DMAR domain
> and all others (IOAPIC, HPET, DEVICE MSI) end up in the REMAP domain
> which handles irq_set_affinity and never ends up in the above code.
>
> In the non-remapping case:
>
> | -- [IOAPIC]
> [VECTOR] --- | -- [HPET]
> | -- [DEVICE MSI]
>
> In this case the vector domain is the MSI parent domain for all of them
> and all outer domains will end up in msi_set_affinity() via
> msi_domain_set_affinity().
>
> In any case 'irqd' in msi_set_affinity() will always point to the vector
> domain and therefore the exiting code is correct and can't be changed to
> retrigger hierarchy as that would see irqd->parent == NULL and do
> nothing. Neither will adding a conditional there do anything useful
> because the vector domain always has the retrigger callback set.
>
Hmmm. I've been staring at the code to try to understand it all,
and I'm not seeing that 'irqd' in msi_set_affinity() always points to
the VECTOR domain.
Starting with the non-remapping case for simplicity, the only place
.irq_set_affinity is set to msi_set_affinity() is in x86_init_dev_msi_info(),
and the chip in this case is for the about-to-be-created device MSI IRQ
domain. So when msi_set_affinity is called, won't the irqd be for the
device MSI domain? And in fact, msi_set_affinity() calls the parent
.set_affinity function (and the parent is the VECTOR domain).
Finally, in existing code (before this patch) msi_set_affinity() calls the
.irq_retrigger function for the device MSI domain, which was set to
irq_chip_retrigger_hierarchy() in x86_init_dev_msi_info().
irq_chip_retrigger_hierarchy() then finds the VECTOR domain
.irq_retrigger function and the right thing happens.
In the remapping case, the same thing happens -- the device MSI
domain has its .irq_set_affinity as msi_set_affinity(), as set by
x86_init_dev_msi_info(). And before this patch, the VECTOR domain
.irq_retrigger gets invoked the same way by going up the hierarchy
to VECTOR.
v4 of this patch set is here [1]. In Patch 3, it uses the most robust
way to invoke .irq_retrigger, which is to check the current irqchip
first, and if it doesn't implement .irq_retrigger, invoke
irq_chip_retrigger_hierarchy(). With this version, setting
.irq_retrigger in x86_init_dev_msi_info() could be dropped,
similar to the other places that setting .irq_retrigger is being
dropped in Patch 4 of the set.
This is what I see from looking at the code. But I don't have a
bare metal x86 system running Linux where I can confirm, so maybe
I've gone astray. In the Hyper-V guests I can access, device MSI
domains don't parent directly to VECTOR there, so they aren't
useful to confirm.
Thanks for your time looking at this. And thanks to Nam as
well. I've learned quite a bit about IRQ domains!
Michael
[1] https://lore.kernel.org/linux-hyperv/20260909064448.1004-1-namjain@linux.microsoft.com/
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits
2026-09-10 18:51 ` Michael Kelley
@ 2026-09-11 8:11 ` Thomas Gleixner
2026-09-11 16:32 ` Michael Kelley
0 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2026-09-11 8:11 UTC (permalink / raw)
To: Michael Kelley, Naman Jain, 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,
namcao
Cc: H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde,
Robin Murphy, Rob Herring, Shradha Gupta, Aditya Garg, iommu,
linux-hyperv, linux-pci, linux-kernel
On Thu, Sep 10 2026 at 18:51, Michael Kelley wrote:
> From: Thomas Gleixner <tglx@kernel.org> Sent: Wednesday, September 9, 2026 3:24 AM
>> In any case 'irqd' in msi_set_affinity() will always point to the vector
>> domain and therefore the exiting code is correct and can't be changed to
>> retrigger hierarchy as that would see irqd->parent == NULL and do
>> nothing. Neither will adding a conditional there do anything useful
>> because the vector domain always has the retrigger callback set.
>>
>
> Hmmm. I've been staring at the code to try to understand it all,
> and I'm not seeing that 'irqd' in msi_set_affinity() always points to
> the VECTOR domain.
You are right and I'm an idiot.
My brain was already melted from debating memory ordering issues, then I
ended up completely confusing the set affinity and the retrigger
logic. Let me try again.
What I completely messed up was that the MSI core sets by default
msi_domain_set_affinity(), which uses the parent domain, but only if the
template/chp does not provide an .irq_set_affinity() callback.
Which is not true when remapping is off because x86_init_dev_msi_info()
sets it to msi_set_affinity(). Duh!
So the change is _not_ broken.
Though my argument that retrigger has to happen at the vector level
still stands because the outermost chip is in fire and forget mode and
to the best of my knowledge none of them have a retrigger at the
interrupt chip level. And from a design perspective there won't be any
in the future (famous last words).
Devices might have a way to retrigger at the device level, but that's
not reachable from the interrupt chip.
So both places fixup_irq() and msi_set_affinity() can use retrigger
hierarchy safely without the conditional checking the outermost domain
chip.
Thanks,
tglx
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits
2026-09-11 8:11 ` Thomas Gleixner
@ 2026-09-11 16:32 ` Michael Kelley
0 siblings, 0 replies; 22+ messages in thread
From: Michael Kelley @ 2026-09-11 16:32 UTC (permalink / raw)
To: Thomas Gleixner, Naman Jain, 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,
namcao
Cc: H. Peter Anvin, Suravee Suthikulpanit, Vasant Hegde,
Robin Murphy, Rob Herring, Shradha Gupta, Aditya Garg, iommu,
linux-hyperv, linux-pci, linux-kernel
From: Thomas Gleixner <tglx@kernel.org> Sent: Friday, September 11, 2026 1:12 AM
>
> On Thu, Sep 10 2026 at 18:51, Michael Kelley wrote:
> > From: Thomas Gleixner <tglx@kernel.org> Sent: Wednesday, September 9, 2026 3:24 AM
> >> In any case 'irqd' in msi_set_affinity() will always point to the vector
> >> domain and therefore the exiting code is correct and can't be changed to
> >> retrigger hierarchy as that would see irqd->parent == NULL and do
> >> nothing. Neither will adding a conditional there do anything useful
> >> because the vector domain always has the retrigger callback set.
> >>
> >
> > Hmmm. I've been staring at the code to try to understand it all,
> > and I'm not seeing that 'irqd' in msi_set_affinity() always points to
> > the VECTOR domain.
>
> You are right and I'm an idiot.
>
> My brain was already melted from debating memory ordering issues, then I
> ended up completely confusing the set affinity and the retrigger
> logic. Let me try again.
>
> What I completely messed up was that the MSI core sets by default
> msi_domain_set_affinity(), which uses the parent domain, but only if the
> template/chp does not provide an .irq_set_affinity() callback.
>
> Which is not true when remapping is off because x86_init_dev_msi_info()
> sets it to msi_set_affinity(). Duh!
>
> So the change is _not_ broken.
>
> Though my argument that retrigger has to happen at the vector level
> still stands because the outermost chip is in fire and forget mode and
> to the best of my knowledge none of them have a retrigger at the
> interrupt chip level. And from a design perspective there won't be any
> in the future (famous last words).
OK. Good to know I'm on the right track! And I agree that having
fixup_irq() and msi_set_affinity() just do irq_chip_retrigger_hierarchy()
works today.
As for the future, you may remember my RFC patch set from a couple
years ago for the Synthetic Interrupt Controller (SynIC) that Hyper-V
provides to guests. The SynIC currently has special case nodes under
/sys/bus/vmbus to manage CPU affinity. As a better approach, the patch
set modelled the SynIC as an irqchip so standard Linux mechanisms could
manage affinity. You and I corresponded about per-cpu flow handler
tweaks to make it all work. The RFC patch set didn't get traction with
the Microsoft folks and I didn't push it. But it had a stand-alone IRQ
domain not parented to VECTOR because Hyper-V interrupts are hard
coded to HYPERVISOR_CALLBACK_VECTOR. As a stand-alone domain,
a .irq_retrigger function might have been useful in fixup_irqs(). That's
all speculative, but it was in the back of my head when I suggested to
Naman that the outermost chip .irq_retrigger function should be
checked. I'm fine with not doing that check now, and if a future case
like the Hyper-V SynIC arises, the check can be added.
>
> Devices might have a way to retrigger at the device level, but that's
> not reachable from the interrupt chip.
>
> So both places fixup_irq() and msi_set_affinity() can use retrigger
> hierarchy safely without the conditional checking the outermost domain
> chip.
And setting .irq_retrigger in x86_init_dev_msi_info() becomes
superfluous, right?
Michael
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2026-09-11 16:32 UTC | newest]
Thread overview: 22+ 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-17 3:38 ` Michael Kelley
2026-08-17 12:15 ` Naman Jain
2026-08-17 15:30 ` Naman Jain
2026-08-17 17:14 ` Michael Kelley
2026-08-18 5:10 ` Michael Kelley
2026-08-24 0:22 ` Wei Liu
2026-08-10 9:07 ` [PATCH v2 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs() Naman Jain
2026-08-18 5:10 ` Michael Kelley
2026-08-18 7:31 ` Naman Jain
2026-08-19 15:59 ` Michael Kelley
2026-08-20 4:47 ` Naman Jain
2026-08-20 4:53 ` Michael Kelley
2026-09-09 9:43 ` Thomas Gleixner
2026-08-10 9:07 ` [PATCH v2 3/3] x86/irq, iommu/amd, PCI: Drop redundant irq_retrigger inits Naman Jain
2026-08-18 5:10 ` Michael Kelley
2026-08-18 7:31 ` Naman Jain
2026-09-09 10:24 ` Thomas Gleixner
2026-09-10 18:51 ` Michael Kelley
2026-09-11 8:11 ` Thomas Gleixner
2026-09-11 16:32 ` Michael Kelley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®