* [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; 13+ 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] 13+ 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 2026-08-18 5:10 ` Michael Kelley 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, 2 replies; 13+ 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] 13+ 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 1 sibling, 1 reply; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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 1 sibling, 0 replies; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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; 13+ 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] 13+ 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; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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 0 siblings, 0 replies; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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 2 siblings, 1 reply; 13+ 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] 13+ 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 0 siblings, 1 reply; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ 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; 13+ 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@kernel.org, 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@lists.linux.dev, linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org 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] 13+ messages in thread
end of thread, other threads:[~2026-08-18 7:31 UTC | newest] Thread overview: 13+ 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-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-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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox