* [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out
@ 2026-07-30 7:22 Sangwoo Han
2026-08-03 16:11 ` Manivannan Sadhasivam
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Sangwoo Han @ 2026-07-30 7:22 UTC (permalink / raw)
To: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas
Cc: bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel,
linux-arm-kernel, linux-kernel, sangwoo.han
brcm_msi_alloc() reserves a naturally aligned power-of-two region with
bitmap_find_free_region(order_base_2(nr_irqs)), but the irqdomain core
releases the vectors of a block one at a time:
/* irq_domain_free_irqs_hierarchy() */
for (i = 0; i < nr_irqs; i++)
if (irq_domain_get_irq_data(domain, irq_base + i))
domain->ops->free(domain, irq_base + i, 1);
That loop is the only caller of an irq_domain's ops->free(), so
brcm_irq_domain_free() always sees nr_irqs == 1 and
bitmap_release_region() clears exactly one bit per call. A request whose
vector count is not a power of two therefore reserves
roundup_pow_of_two(nr_irqs) bits but releases only nr_irqs of them, and
the difference stays set for the lifetime of the controller.
Multi-MSI regions are order-aligned and the controller has at most 32
MSIs, so the pool is quickly exhausted. Observed on a BCM2712 with a
5-vector endpoint behind a 4-port PCIe switch: the switch ports take
hwirq 0x0-0x3 and the endpoint's block walks 0x8 -> 0x10 -> 0x18 across
three driver reloads until no aligned order-3 region is left.
pci_alloc_irq_vectors() then falls back to a single vector for the rest
of the boot, silently multiplexing the endpoint's four completion
interrupts onto one hwirq.
Devices that ask for a non-power-of-two vector count are not exotic:
wil6210 asks for 3, the MHI modems for 5 (Quectel EM1xx, Foxconn SDX55,
Telit FN990, MediaTek MV3x) or 7 (Qualcomm v1), ath11k WCN6750 for 28
and ptp_ocp for 17. MSI-X is unaffected because it allocates one
descriptor per vector with nvec_used == 1, so the order is always zero.
Reserve exactly the vectors that are handed out, at a base found with
bitmap_find_next_zero_area(), and clear exactly the vectors that are
freed. The number of reserved bits then matches the number the core
releases, whatever arity it uses.
The base still has to be aligned: PCI Local Bus Specification 3.0
(section 6.8.1.6) lets the endpoint encode the vector number in the low
order_base_2(nr_irqs) bits of the Message Data register, and in this
controller those bits are the hwirq itself. The alignment mask has to be
roundup_pow_of_two(nr_irqs) - 1 rather than nr_irqs - 1:
bitmap_find_next_zero_area() requires a mask of the form 2^k - 1. No
align_offset is needed because the bitmap index is the value the
endpoint ORs in, see brcm_msi_compose_msi_msg().
For a power-of-two nr_irqs the alignment and the region length are both
nr_irqs, so the base returned is the same as before and those
allocations are unaffected.
Fixes: 198acab1772f ("PCI: brcmstb: Enable Multi-MSI")
Cc: stable@vger.kernel.org
Signed-off-by: Sangwoo Han <sangwoo.han@nearthlab.com>
---
Notes:
Tested on a BCM2712 (Raspberry Pi 5) with a 5-vector endpoint behind a
4-port PCIe switch, running 6.12.25 where brcm_msi_alloc() and
brcm_msi_free() are byte-identical to mainline. Without the patch the
endpoint's block walks 0x8 -> 0x10 -> 0x18 over three driver reloads and
then falls back to a single vector for the rest of the boot; with it the
block returns to 0x8 on all of eight reload cycles and the inner
domain's mapped count round-trips cleanly.
Compile-tested on mainline for arm64 with W=1 and C=1 (sparse); no new
warnings.
drivers/pci/controller/pcie-brcmstb.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index 8a0c353d2a..6c5166666d 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -595,11 +595,22 @@ static struct irq_chip brcm_msi_bottom_irq_chip = {
static int brcm_msi_alloc(struct brcm_msi *msi, unsigned int nr_irqs)
{
+ /*
+ * brcm_msi_compose_msi_msg() puts hwirq in the low order bits of the
+ * message data, which a Multi-MSI endpoint rewrites per vector, so a
+ * block's base must be aligned to the Multiple Message Enable count.
+ */
+ unsigned long align_mask = roundup_pow_of_two(nr_irqs) - 1;
int hwirq;
mutex_lock(&msi->lock);
- hwirq = bitmap_find_free_region(msi->used, msi->nr,
- order_base_2(nr_irqs));
+ hwirq = bitmap_find_next_zero_area(msi->used, msi->nr, 0, nr_irqs,
+ align_mask);
+ if (hwirq >= msi->nr) {
+ mutex_unlock(&msi->lock);
+ return -ENOSPC;
+ }
+ bitmap_set(msi->used, hwirq, nr_irqs);
mutex_unlock(&msi->lock);
return hwirq;
@@ -609,7 +620,7 @@ static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq,
unsigned int nr_irqs)
{
mutex_lock(&msi->lock);
- bitmap_release_region(msi->used, hwirq, order_base_2(nr_irqs));
+ bitmap_clear(msi->used, hwirq, nr_irqs);
mutex_unlock(&msi->lock);
}
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-07-30 7:22 [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out Sangwoo Han @ 2026-08-03 16:11 ` Manivannan Sadhasivam 2026-08-03 22:22 ` Bjorn Helgaas 2026-09-07 16:34 ` Bjorn Helgaas 2 siblings, 0 replies; 10+ messages in thread From: Manivannan Sadhasivam @ 2026-08-03 16:11 UTC (permalink / raw) To: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, Sangwoo Han Cc: bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel On Thu, 30 Jul 2026 16:22:15 +0900, Sangwoo Han wrote: > brcm_msi_alloc() reserves a naturally aligned power-of-two region with > bitmap_find_free_region(order_base_2(nr_irqs)), but the irqdomain core > releases the vectors of a block one at a time: > > /* irq_domain_free_irqs_hierarchy() */ > for (i = 0; i < nr_irqs; i++) > if (irq_domain_get_irq_data(domain, irq_base + i)) > domain->ops->free(domain, irq_base + i, 1); > > [...] Applied, thanks! [1/1] PCI: brcmstb: Reserve only the MSI vectors that are handed out commit: 92bf60fbb80f94c1b0fc24c7ff67d7aee936a58c Best regards, -- மணிவண்ணன் சதாசிவம் ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-07-30 7:22 [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out Sangwoo Han 2026-08-03 16:11 ` Manivannan Sadhasivam @ 2026-08-03 22:22 ` Bjorn Helgaas 2026-08-04 11:31 ` Han / 한상우Sangwoo 2026-09-07 16:34 ` Bjorn Helgaas 2 siblings, 1 reply; 10+ messages in thread From: Bjorn Helgaas @ 2026-08-03 22:22 UTC (permalink / raw) To: Sangwoo Han Cc: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel On Thu, Jul 30, 2026 at 04:22:15PM +0900, Sangwoo Han wrote: > brcm_msi_alloc() reserves a naturally aligned power-of-two region with > bitmap_find_free_region(order_base_2(nr_irqs)), but the irqdomain core > releases the vectors of a block one at a time: > > /* irq_domain_free_irqs_hierarchy() */ > for (i = 0; i < nr_irqs; i++) > if (irq_domain_get_irq_data(domain, irq_base + i)) > domain->ops->free(domain, irq_base + i, 1); > > That loop is the only caller of an irq_domain's ops->free(), so > brcm_irq_domain_free() always sees nr_irqs == 1 and > bitmap_release_region() clears exactly one bit per call. A request whose > vector count is not a power of two therefore reserves > roundup_pow_of_two(nr_irqs) bits but releases only nr_irqs of them, and > the difference stays set for the lifetime of the controller. > > Multi-MSI regions are order-aligned and the controller has at most 32 > MSIs, so the pool is quickly exhausted. Observed on a BCM2712 with a > 5-vector endpoint behind a 4-port PCIe switch: the switch ports take > hwirq 0x0-0x3 and the endpoint's block walks 0x8 -> 0x10 -> 0x18 across > three driver reloads until no aligned order-3 region is left. > pci_alloc_irq_vectors() then falls back to a single vector for the rest > of the boot, silently multiplexing the endpoint's four completion > interrupts onto one hwirq. > > Devices that ask for a non-power-of-two vector count are not exotic: > wil6210 asks for 3, the MHI modems for 5 (Quectel EM1xx, Foxconn SDX55, > Telit FN990, MediaTek MV3x) or 7 (Qualcomm v1), ath11k WCN6750 for 28 > and ptp_ocp for 17. MSI-X is unaffected because it allocates one > descriptor per vector with nvec_used == 1, so the order is always zero. > > Reserve exactly the vectors that are handed out, at a base found with > bitmap_find_next_zero_area(), and clear exactly the vectors that are > freed. The number of reserved bits then matches the number the core > releases, whatever arity it uses. > > The base still has to be aligned: PCI Local Bus Specification 3.0 > (section 6.8.1.6) lets the endpoint encode the vector number in the low > order_base_2(nr_irqs) bits of the Message Data register, and in this > controller those bits are the hwirq itself. The alignment mask has to be > roundup_pow_of_two(nr_irqs) - 1 rather than nr_irqs - 1: > bitmap_find_next_zero_area() requires a mask of the form 2^k - 1. No > align_offset is needed because the bitmap index is the value the > endpoint ORs in, see brcm_msi_compose_msi_msg(). > > For a power-of-two nr_irqs the alignment and the region length are both > nr_irqs, so the base returned is the same as before and those > allocations are unaffected. Several other PCI controller drivers have similar code. I think we should fix them all at once (or explain why they don't need similar fixes). Might be worth a little helper so they all work the same way (e.g., some use order_base_2(), others use get_count_order(), which seems like a pointless difference). > Fixes: 198acab1772f ("PCI: brcmstb: Enable Multi-MSI") > Cc: stable@vger.kernel.org > Signed-off-by: Sangwoo Han <sangwoo.han@nearthlab.com> > --- > > Notes: > Tested on a BCM2712 (Raspberry Pi 5) with a 5-vector endpoint behind a > 4-port PCIe switch, running 6.12.25 where brcm_msi_alloc() and > brcm_msi_free() are byte-identical to mainline. Without the patch the > endpoint's block walks 0x8 -> 0x10 -> 0x18 over three driver reloads and > then falls back to a single vector for the rest of the boot; with it the > block returns to 0x8 on all of eight reload cycles and the inner > domain's mapped count round-trips cleanly. > > Compile-tested on mainline for arm64 with W=1 and C=1 (sparse); no new > warnings. > > drivers/pci/controller/pcie-brcmstb.c | 17 ++++++++++++++--- > 1 file changed, 14 insertions(+), 3 deletions(-) > > diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c > index 8a0c353d2a..6c5166666d 100644 > --- a/drivers/pci/controller/pcie-brcmstb.c > +++ b/drivers/pci/controller/pcie-brcmstb.c > @@ -595,11 +595,22 @@ static struct irq_chip brcm_msi_bottom_irq_chip = { > > static int brcm_msi_alloc(struct brcm_msi *msi, unsigned int nr_irqs) > { > + /* > + * brcm_msi_compose_msi_msg() puts hwirq in the low order bits of the > + * message data, which a Multi-MSI endpoint rewrites per vector, so a > + * block's base must be aligned to the Multiple Message Enable count. > + */ > + unsigned long align_mask = roundup_pow_of_two(nr_irqs) - 1; > int hwirq; > > mutex_lock(&msi->lock); > - hwirq = bitmap_find_free_region(msi->used, msi->nr, > - order_base_2(nr_irqs)); > + hwirq = bitmap_find_next_zero_area(msi->used, msi->nr, 0, nr_irqs, > + align_mask); > + if (hwirq >= msi->nr) { > + mutex_unlock(&msi->lock); > + return -ENOSPC; > + } > + bitmap_set(msi->used, hwirq, nr_irqs); > mutex_unlock(&msi->lock); > > return hwirq; > @@ -609,7 +620,7 @@ static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq, > unsigned int nr_irqs) > { > mutex_lock(&msi->lock); > - bitmap_release_region(msi->used, hwirq, order_base_2(nr_irqs)); > + bitmap_clear(msi->used, hwirq, nr_irqs); > mutex_unlock(&msi->lock); > } > > -- > 2.53.0 > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-08-03 22:22 ` Bjorn Helgaas @ 2026-08-04 11:31 ` Han / 한상우Sangwoo 2026-08-04 12:50 ` Bjorn Helgaas 0 siblings, 1 reply; 10+ messages in thread From: Han / 한상우Sangwoo @ 2026-08-04 11:31 UTC (permalink / raw) To: Bjorn Helgaas Cc: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel > Several other PCI controller drivers have similar code. I agree - eleven of them look like they can have the same problem. > I think we should fix them all at once (or explain why they don't need > similar fixes). Might be worth a little helper so they all work the > same way (e.g., some use order_base_2(), others use get_count_order(), > which seems like a pointless difference). I am working on a related fix for drivers/irqchip/irq-bcm2712-mip.c, which I can test here. I would rather not send changes to drivers I cannot test, though, so I am leaving the eleven to whoever has the boards. What I looked at is in the appendix, in case it is useful to them. Two things seem more useful from where I am sitting. - The failure is silent. Appendix A describes the symptom, so that anyone who hits it later can find this thread. - The contract is not written down. It changed in 4615fbc3788d, where irq_domain_free_irqs_hierarchy() started freeing one vector at a time. order_base_2() and get_count_order() give the same answer for any nr_irqs >= 1, so consolidating those two is just cleanup. Where a shared helper should live I am not sure either. Thanks, Sangwoo Appendix A - the symptom ======================== A PCIe device whose driver is unbound and rebound a few times, or whose module is reloaded, ends up with fewer MSI vectors than it asked for. It does not recover until reboot. Two things have to be true for it to happen: the device uses multi-MSI, and the vector count it asks for is not a power of two. Devices that ask for a power of two are unaffected, and so is anything on MSI-X. I have only seen the reduced-vector case. A driver that insists on the full count would fail to probe instead, but I have not seen that happen. Appendix B - how I sorted the drivers ===================================== I went through drivers/pci/controller/ while working out what my own fix had to do, so this is that rather than a full audit. Twenty of the drivers own an MSI hwirq pool. I asked three things about each: - does .alloc reserve a rounded-up block, or a single slot - does the core hand .free one vector at a time - can nr_irqs > 1 reach the driver at all Eleven answer yes to all three: dwc/pcie-designware-host.c pci-aardvark.c pcie-apple.c pcie-aspeed.c pcie-iproc-msi.c pcie-mediatek-gen3.c pcie-rcar-host.c pcie-rzg3s-host.c pcie-xilinx-dma-pl.c pcie-xilinx-nwl.c pci-hyperv.c The other nine: - five reserve a single slot, so nothing rounds up: mobiveil/pcie-mobiveil-host.c, pci-xgene-msi.c, pcie-altera-msi.c, pcie-mediatek.c, plda/pcie-plda-host.c - vmd.c keeps a per-vector refcount instead of a bitmap - pci-tegra.c and pcie-xilinx.c reserve a rounded-up block, but neither lists MSI_FLAG_MULTI_PCI_MSI in msi_parent_ops.supported_flags - pcie-brcmstb.c is the one you applied ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-08-04 11:31 ` Han / 한상우Sangwoo @ 2026-08-04 12:50 ` Bjorn Helgaas 2026-08-10 23:30 ` Bjorn Helgaas 0 siblings, 1 reply; 10+ messages in thread From: Bjorn Helgaas @ 2026-08-04 12:50 UTC (permalink / raw) To: Han / 한상우Sangwoo Cc: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel, Marc Zyngier, Thomas Gleixner [+cc Marc, author of 4615fbc3788d ("genirq/irqdomain: Don't try to free an interrupt that has no mapping"), Thomas; beginning of thread about multiple MSI vector alloc/free: https://lore.kernel.org/all/20260730072215.2090974-1-sangwoo.han@nearthlab.com] On Tue, Aug 04, 2026 at 08:31:23PM +0900, Han / 한상우Sangwoo wrote: > > Several other PCI controller drivers have similar code. > > I agree - eleven of them look like they can have the same problem. > > > I think we should fix them all at once (or explain why they don't need > > similar fixes). Might be worth a little helper so they all work the > > same way (e.g., some use order_base_2(), others use get_count_order(), > > which seems like a pointless difference). > > I am working on a related fix for drivers/irqchip/irq-bcm2712-mip.c, Similar pattern there, but it uses ilog2(), which differs from order_base_2() and get_count_order() in more cases. > which I can test here. I would rather not send changes to drivers I > cannot test, though, so I am leaving the eleven to whoever has the boards. > What I looked at is in the appendix, in case it is useful to them. > > Two things seem more useful from where I am sitting. > > - The failure is silent. Appendix A describes the symptom, so that > anyone who hits it later can find this thread. > > - The contract is not written down. It changed in 4615fbc3788d, where > irq_domain_free_irqs_hierarchy() started freeing one vector at a time. > > order_base_2() and get_count_order() give the same answer for any > nr_irqs >= 1, so consolidating those two is just cleanup. Where a shared > helper should live I am not sure either. I don't know either, but I hate fixing an issue in one place and leaving the same issue unfixed nearby. > Appendix A - the symptom > ======================== > > A PCIe device whose driver is unbound and rebound a few times, or whose > module is reloaded, ends up with fewer MSI vectors than it asked for. It > does not recover until reboot. > > Two things have to be true for it to happen: the device uses multi-MSI, > and the vector count it asks for is not a power of two. Devices that ask > for a power of two are unaffected, and so is anything on MSI-X. > > I have only seen the reduced-vector case. A driver that insists on the > full count would fail to probe instead, but I have not seen that happen. > > > Appendix B - how I sorted the drivers > ===================================== > > I went through drivers/pci/controller/ while working out what my own fix > had to do, so this is that rather than a full audit. Twenty of the > drivers own an MSI hwirq pool. I asked three things about each: > > - does .alloc reserve a rounded-up block, or a single slot > - does the core hand .free one vector at a time > - can nr_irqs > 1 reach the driver at all > > Eleven answer yes to all three: > > dwc/pcie-designware-host.c pci-aardvark.c pcie-apple.c > pcie-aspeed.c pcie-iproc-msi.c pcie-mediatek-gen3.c > pcie-rcar-host.c pcie-rzg3s-host.c pcie-xilinx-dma-pl.c > pcie-xilinx-nwl.c pci-hyperv.c > > The other nine: > > - five reserve a single slot, so nothing rounds up: > mobiveil/pcie-mobiveil-host.c, pci-xgene-msi.c, pcie-altera-msi.c, > pcie-mediatek.c, plda/pcie-plda-host.c > > - vmd.c keeps a per-vector refcount instead of a bitmap > > - pci-tegra.c and pcie-xilinx.c reserve a rounded-up block, but neither > lists MSI_FLAG_MULTI_PCI_MSI in msi_parent_ops.supported_flags > > - pcie-brcmstb.c is the one you applied ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-08-04 12:50 ` Bjorn Helgaas @ 2026-08-10 23:30 ` Bjorn Helgaas 0 siblings, 0 replies; 10+ messages in thread From: Bjorn Helgaas @ 2026-08-10 23:30 UTC (permalink / raw) To: Han / 한상우Sangwoo Cc: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel, Marc Zyngier, Thomas Gleixner On Tue, Aug 04, 2026 at 07:50:57AM -0500, Bjorn Helgaas wrote: > [+cc Marc, author of 4615fbc3788d ("genirq/irqdomain: Don't try to > free an interrupt that has no mapping"), Thomas; beginning of thread > about multiple MSI vector alloc/free: > https://lore.kernel.org/all/20260730072215.2090974-1-sangwoo.han@nearthlab.com] > > On Tue, Aug 04, 2026 at 08:31:23PM +0900, Han / 한상우Sangwoo wrote: > > > Several other PCI controller drivers have similar code. > > > > I agree - eleven of them look like they can have the same problem. > > > > > I think we should fix them all at once (or explain why they don't need > > > similar fixes). Might be worth a little helper so they all work the > > > same way (e.g., some use order_base_2(), others use get_count_order(), > > > which seems like a pointless difference). > > > > I am working on a related fix for drivers/irqchip/irq-bcm2712-mip.c, > > Similar pattern there, but it uses ilog2(), which differs from > order_base_2() and get_count_order() in more cases. > > > which I can test here. I would rather not send changes to drivers I > > cannot test, though, so I am leaving the eleven to whoever has the boards. > > What I looked at is in the appendix, in case it is useful to them. > > > > Two things seem more useful from where I am sitting. > > > > - The failure is silent. Appendix A describes the symptom, so that > > anyone who hits it later can find this thread. > > > > - The contract is not written down. It changed in 4615fbc3788d, where > > irq_domain_free_irqs_hierarchy() started freeing one vector at a time. > > > > order_base_2() and get_count_order() give the same answer for any > > nr_irqs >= 1, so consolidating those two is just cleanup. Where a shared > > helper should live I am not sure either. > > I don't know either, but I hate fixing an issue in one place and > leaving the same issue unfixed nearby. Just to be clear here, I'm going to defer this until we can fix everything in drivers/pci at once. If we can add a fix early in the cycle, e.g., soon after -rc1, people with other controllers can help test it. If we only fix one driver, the pattern will continue as people copy and paste the bug into new drivers. So that's why I haven't pulled the pci/controller/brcmstb branch (which contains this patch) into pci/next. > > Appendix A - the symptom > > ======================== > > > > A PCIe device whose driver is unbound and rebound a few times, or whose > > module is reloaded, ends up with fewer MSI vectors than it asked for. It > > does not recover until reboot. > > > > Two things have to be true for it to happen: the device uses multi-MSI, > > and the vector count it asks for is not a power of two. Devices that ask > > for a power of two are unaffected, and so is anything on MSI-X. > > > > I have only seen the reduced-vector case. A driver that insists on the > > full count would fail to probe instead, but I have not seen that happen. > > > > > > Appendix B - how I sorted the drivers > > ===================================== > > > > I went through drivers/pci/controller/ while working out what my own fix > > had to do, so this is that rather than a full audit. Twenty of the > > drivers own an MSI hwirq pool. I asked three things about each: > > > > - does .alloc reserve a rounded-up block, or a single slot > > - does the core hand .free one vector at a time > > - can nr_irqs > 1 reach the driver at all > > > > Eleven answer yes to all three: > > > > dwc/pcie-designware-host.c pci-aardvark.c pcie-apple.c > > pcie-aspeed.c pcie-iproc-msi.c pcie-mediatek-gen3.c > > pcie-rcar-host.c pcie-rzg3s-host.c pcie-xilinx-dma-pl.c > > pcie-xilinx-nwl.c pci-hyperv.c > > > > The other nine: > > > > - five reserve a single slot, so nothing rounds up: > > mobiveil/pcie-mobiveil-host.c, pci-xgene-msi.c, pcie-altera-msi.c, > > pcie-mediatek.c, plda/pcie-plda-host.c > > > > - vmd.c keeps a per-vector refcount instead of a bitmap > > > > - pci-tegra.c and pcie-xilinx.c reserve a rounded-up block, but neither > > lists MSI_FLAG_MULTI_PCI_MSI in msi_parent_ops.supported_flags > > > > - pcie-brcmstb.c is the one you applied ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-07-30 7:22 [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out Sangwoo Han 2026-08-03 16:11 ` Manivannan Sadhasivam 2026-08-03 22:22 ` Bjorn Helgaas @ 2026-09-07 16:34 ` Bjorn Helgaas 2026-09-07 21:40 ` Thomas Gleixner 2 siblings, 1 reply; 10+ messages in thread From: Bjorn Helgaas @ 2026-09-07 16:34 UTC (permalink / raw) To: Sangwoo Han Cc: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel, Thomas Gleixner, Inochi Amaoto [+cc Thomas, Inochi for MSI expertise] On Thu, Jul 30, 2026 at 04:22:15PM +0900, Sangwoo Han wrote: > brcm_msi_alloc() reserves a naturally aligned power-of-two region with > bitmap_find_free_region(order_base_2(nr_irqs)), but the irqdomain core > releases the vectors of a block one at a time: > > /* irq_domain_free_irqs_hierarchy() */ > for (i = 0; i < nr_irqs; i++) > if (irq_domain_get_irq_data(domain, irq_base + i)) > domain->ops->free(domain, irq_base + i, 1); > > That loop is the only caller of an irq_domain's ops->free(), so > brcm_irq_domain_free() always sees nr_irqs == 1 and > bitmap_release_region() clears exactly one bit per call. A request whose > vector count is not a power of two therefore reserves > roundup_pow_of_two(nr_irqs) bits but releases only nr_irqs of them, and > the difference stays set for the lifetime of the controller. > > Multi-MSI regions are order-aligned and the controller has at most 32 > MSIs, so the pool is quickly exhausted. Observed on a BCM2712 with a > 5-vector endpoint behind a 4-port PCIe switch: the switch ports take > hwirq 0x0-0x3 and the endpoint's block walks 0x8 -> 0x10 -> 0x18 across > three driver reloads until no aligned order-3 region is left. > pci_alloc_irq_vectors() then falls back to a single vector for the rest > of the boot, silently multiplexing the endpoint's four completion > interrupts onto one hwirq. > > Devices that ask for a non-power-of-two vector count are not exotic: > wil6210 asks for 3, the MHI modems for 5 (Quectel EM1xx, Foxconn SDX55, > Telit FN990, MediaTek MV3x) or 7 (Qualcomm v1), ath11k WCN6750 for 28 > and ptp_ocp for 17. MSI-X is unaffected because it allocates one > descriptor per vector with nvec_used == 1, so the order is always zero. > > Reserve exactly the vectors that are handed out, at a base found with > bitmap_find_next_zero_area(), and clear exactly the vectors that are > freed. The number of reserved bits then matches the number the core > releases, whatever arity it uses. > > The base still has to be aligned: PCI Local Bus Specification 3.0 > (section 6.8.1.6) lets the endpoint encode the vector number in the low > order_base_2(nr_irqs) bits of the Message Data register, and in this > controller those bits are the hwirq itself. The alignment mask has to be > roundup_pow_of_two(nr_irqs) - 1 rather than nr_irqs - 1: > bitmap_find_next_zero_area() requires a mask of the form 2^k - 1. No > align_offset is needed because the bitmap index is the value the > endpoint ORs in, see brcm_msi_compose_msi_msg(). > > For a power-of-two nr_irqs the alignment and the region length are both > nr_irqs, so the base returned is the same as before and those > allocations are unaffected. > > Fixes: 198acab1772f ("PCI: brcmstb: Enable Multi-MSI") > Cc: stable@vger.kernel.org > Signed-off-by: Sangwoo Han <sangwoo.han@nearthlab.com> > --- > > Notes: > Tested on a BCM2712 (Raspberry Pi 5) with a 5-vector endpoint behind a > 4-port PCIe switch, running 6.12.25 where brcm_msi_alloc() and > brcm_msi_free() are byte-identical to mainline. Without the patch the > endpoint's block walks 0x8 -> 0x10 -> 0x18 over three driver reloads and > then falls back to a single vector for the rest of the boot; with it the > block returns to 0x8 on all of eight reload cycles and the inner > domain's mapped count round-trips cleanly. > > Compile-tested on mainline for arm64 with W=1 and C=1 (sparse); no new > warnings. > > drivers/pci/controller/pcie-brcmstb.c | 17 ++++++++++++++--- > 1 file changed, 14 insertions(+), 3 deletions(-) > > diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c > index 8a0c353d2a..6c5166666d 100644 > --- a/drivers/pci/controller/pcie-brcmstb.c > +++ b/drivers/pci/controller/pcie-brcmstb.c > @@ -595,11 +595,22 @@ static struct irq_chip brcm_msi_bottom_irq_chip = { > > static int brcm_msi_alloc(struct brcm_msi *msi, unsigned int nr_irqs) > { > + /* > + * brcm_msi_compose_msi_msg() puts hwirq in the low order bits of the > + * message data, which a Multi-MSI endpoint rewrites per vector, so a > + * block's base must be aligned to the Multiple Message Enable count. > + */ > + unsigned long align_mask = roundup_pow_of_two(nr_irqs) - 1; > int hwirq; > > mutex_lock(&msi->lock); > - hwirq = bitmap_find_free_region(msi->used, msi->nr, > - order_base_2(nr_irqs)); > + hwirq = bitmap_find_next_zero_area(msi->used, msi->nr, 0, nr_irqs, > + align_mask); > + if (hwirq >= msi->nr) { > + mutex_unlock(&msi->lock); > + return -ENOSPC; > + } > + bitmap_set(msi->used, hwirq, nr_irqs); > mutex_unlock(&msi->lock); > > return hwirq; > @@ -609,7 +620,7 @@ static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq, > unsigned int nr_irqs) > { > mutex_lock(&msi->lock); > - bitmap_release_region(msi->used, hwirq, order_base_2(nr_irqs)); > + bitmap_clear(msi->used, hwirq, nr_irqs); > mutex_unlock(&msi->lock); > } I want to revive this thread because I think there's a real problem here, and we should solve it for all the PCI controller drivers. There's nothing brcm-specific about the bitmap alloc/free except the size of the msi->used bitmap, so I don't want to copy/paste this sort of fix in all the affected drivers. I'd also like to avoid the extra align_mask and bitmap_find_next_zero_area() followed by manual bitmap_set(). bitmap_find_free_region() already takes care of the alignment and setting the allocated bits. The MSI Multiple Message Enable situation of enabling more vectors in the device than the driver wants is generic to all devices that advertise Multiple Message Capable, and I don't think we should have to deal with this in every host controller driver. If a driver requests 3 vectors, we have to enable 4 because MSI only supports power-of-two number of vectors. This tells the device it is allowed to use all 4 vectors, and I think the PCI MSI core should assume they all *will* be used instead of relying on the driver's claim that it will only use 3. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-09-07 16:34 ` Bjorn Helgaas @ 2026-09-07 21:40 ` Thomas Gleixner 2026-09-16 23:10 ` Bjorn Helgaas 0 siblings, 1 reply; 10+ messages in thread From: Thomas Gleixner @ 2026-09-07 21:40 UTC (permalink / raw) To: Bjorn Helgaas, Sangwoo Han Cc: jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel, Inochi Amaoto On Mon, Sep 07 2026 at 11:34, Bjorn Helgaas wrote: > [+cc Thomas, Inochi for MSI expertise] > > I want to revive this thread because I think there's a real problem > here, and we should solve it for all the PCI controller drivers. > > There's nothing brcm-specific about the bitmap alloc/free except the > size of the msi->used bitmap, so I don't want to copy/paste this sort > of fix in all the affected drivers. > > I'd also like to avoid the extra align_mask and > bitmap_find_next_zero_area() followed by manual bitmap_set(). > bitmap_find_free_region() already takes care of the alignment and > setting the allocated bits. > > The MSI Multiple Message Enable situation of enabling more vectors in > the device than the driver wants is generic to all devices that > advertise Multiple Message Capable, and I don't think we should have > to deal with this in every host controller driver. Correct. > If a driver requests 3 vectors, we have to enable 4 because MSI only > supports power-of-two number of vectors. This tells the device it is > allowed to use all 4 vectors, and I think the PCI MSI core should > assume they all *will* be used instead of relying on the driver's > claim that it will only use 3. That's not really a good idea because e.g. the irq affinity stuff relies on the accurate number of interrupts the driver requested with the minvec/maxvec range. We can't magically spread more interrupts than the driver is able/willing to handle. But we can fix that without changing the consumer side (device drivers) visible behaviour and handle it solely in the core code. 1) MSI interrupts are special because they have msi_desc::nvec_used > 1, so the allocation and the free path can take care of the power of two requirement. That just allocates more resources than the driver wants but they are just memory. 2) All MSI parent domain implementations should be able to handle domain_ops::free() with nr_irqs > 1. That's something which can be trivialy audited. I really have no memories why the bulk remove function iterates the interrupts one by one instead of doing in one go, but this is also used by non MSI domains, which might have issues with a bulk remove. If we establish that all MSI parent domain implementations can handle the free() callback with nr_irqs > 1, then irq_domain_free_irqs_hierarchy can check whether IRQ_DOMAIN_FLAG_MSI_PARENT is set in the domain_flags and avoid the loop for that case. Something like the completely untested below. Thanks, tglx --- diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 4fdcb6df5306..b3f6cc6ae2ce 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1611,6 +1611,13 @@ static void irq_domain_free_irqs_hierarchy(struct irq_domain *domain, if (!domain->ops->free) return; + /* CHECKME: Are all MSI parent domains capable ? */ + if (domain->flags & IRQ_DOMAIN_FLAG_MSI_PARENT) { + if (irq_domain_get_irq_data(domain, irq_base)) + domain->ops->free(domain, irq_base, nr_irqs); + return; + } + for (i = 0; i < nr_irqs; i++) { if (irq_domain_get_irq_data(domain, irq_base + i)) domain->ops->free(domain, irq_base + i, 1); diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index fb5f372215bf..2835b09899ea 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -1333,20 +1333,28 @@ static int __msi_domain_alloc_irqs(struct device *dev, struct irq_domain *domain ops->set_desc(&arg, desc); - virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, + /* Make sure a MULTI-MSI allocation is power of two */ + unsigned int nvec_aligned = roundup_pow_of_two(desc->nvec_used); + + virq = __irq_domain_alloc_irqs(domain, -1, nvec_aligned, dev_to_node(dev), &arg, false, desc->affinity); if (virq < 0) return msi_handle_pci_fail(domain, desc, allocated); - for (i = 0; i < desc->nvec_used; i++) { + for (i = 0; i < nvec_aligned; i++) { irq_set_msi_desc_off(virq, i, desc); irq_debugfs_copy_devname(virq + i, dev); ret = msi_init_virq(domain, virq + i, vflags); if (ret) return ret; } + if (info->flags & MSI_FLAG_DEV_SYSFS) { + /* + * This only exposes desc->nvec_used and ignores the + * overallocated MULTI-MSI ones. + */ ret = msi_sysfs_populate_desc(dev, desc); if (ret) return ret; @@ -1610,13 +1618,15 @@ static void __msi_domain_free_irqs(struct device *dev, struct irq_domain *domain continue; /* Make sure all interrupts are deactivated */ - for (i = 0; i < desc->nvec_used; i++) { + unsigned int nvec_aligned = roundup_pow_of_two(desc->nvec_used); + + for (i = 0; i < nvec_aligned; i++) { irqd = irq_domain_get_irq_data(domain, desc->irq + i); if (irqd && irqd_is_activated(irqd)) irq_domain_deactivate_irq(irqd); } - irq_domain_free_irqs(desc->irq, desc->nvec_used); + irq_domain_free_irqs(desc->irq, nvec_aligned); if (info->flags & MSI_FLAG_DEV_SYSFS) msi_sysfs_remove_desc(dev, desc); desc->irq = 0; ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-09-07 21:40 ` Thomas Gleixner @ 2026-09-16 23:10 ` Bjorn Helgaas 2026-09-21 9:05 ` Han / 한상우Sangwoo 0 siblings, 1 reply; 10+ messages in thread From: Bjorn Helgaas @ 2026-09-16 23:10 UTC (permalink / raw) To: Sangwoo Han Cc: Thomas Gleixner, jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel, Inochi Amaoto On Mon, Sep 07, 2026 at 11:40:34PM +0200, Thomas Gleixner wrote: > On Mon, Sep 07 2026 at 11:34, Bjorn Helgaas wrote: > > [+cc Thomas, Inochi for MSI expertise] > > > > I want to revive this thread because I think there's a real problem > > here, and we should solve it for all the PCI controller drivers. > > > > There's nothing brcm-specific about the bitmap alloc/free except the > > size of the msi->used bitmap, so I don't want to copy/paste this sort > > of fix in all the affected drivers. > > > > I'd also like to avoid the extra align_mask and > > bitmap_find_next_zero_area() followed by manual bitmap_set(). > > bitmap_find_free_region() already takes care of the alignment and > > setting the allocated bits. > > > > The MSI Multiple Message Enable situation of enabling more vectors in > > the device than the driver wants is generic to all devices that > > advertise Multiple Message Capable, and I don't think we should have > > to deal with this in every host controller driver. > > Correct. > > > If a driver requests 3 vectors, we have to enable 4 because MSI only > > supports power-of-two number of vectors. This tells the device it is > > allowed to use all 4 vectors, and I think the PCI MSI core should > > assume they all *will* be used instead of relying on the driver's > > claim that it will only use 3. > > That's not really a good idea because e.g. the irq affinity stuff relies > on the accurate number of interrupts the driver requested with the > minvec/maxvec range. We can't magically spread more interrupts than the > driver is able/willing to handle. > > But we can fix that without changing the consumer side (device drivers) > visible behaviour and handle it solely in the core code. > > 1) MSI interrupts are special because they have msi_desc::nvec_used > > 1, so the allocation and the free path can take care of the power of > two requirement. That just allocates more resources than the driver > wants but they are just memory. > > 2) All MSI parent domain implementations should be able to handle > domain_ops::free() with nr_irqs > 1. That's something which can be > trivialy audited. > > I really have no memories why the bulk remove function iterates the > interrupts one by one instead of doing in one go, but this is also > used by non MSI domains, which might have issues with a bulk remove. > > If we establish that all MSI parent domain implementations can > handle the free() callback with nr_irqs > 1, then > irq_domain_free_irqs_hierarchy can check whether > IRQ_DOMAIN_FLAG_MSI_PARENT is set in the domain_flags and avoid the > loop for that case. > > Something like the completely untested below. Sangwoo, is there any chance you can test this and see whether it fixes the issue? If it does, I guess we'll have to ask Thomas to post it with the appropriate Signed-off-by, etc. > --- > diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c > index 4fdcb6df5306..b3f6cc6ae2ce 100644 > --- a/kernel/irq/irqdomain.c > +++ b/kernel/irq/irqdomain.c > @@ -1611,6 +1611,13 @@ static void irq_domain_free_irqs_hierarchy(struct irq_domain *domain, > if (!domain->ops->free) > return; > > + /* CHECKME: Are all MSI parent domains capable ? */ > + if (domain->flags & IRQ_DOMAIN_FLAG_MSI_PARENT) { > + if (irq_domain_get_irq_data(domain, irq_base)) > + domain->ops->free(domain, irq_base, nr_irqs); > + return; > + } > + > for (i = 0; i < nr_irqs; i++) { > if (irq_domain_get_irq_data(domain, irq_base + i)) > domain->ops->free(domain, irq_base + i, 1); > diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c > index fb5f372215bf..2835b09899ea 100644 > --- a/kernel/irq/msi.c > +++ b/kernel/irq/msi.c > @@ -1333,20 +1333,28 @@ static int __msi_domain_alloc_irqs(struct device *dev, struct irq_domain *domain > > ops->set_desc(&arg, desc); > > - virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, > + /* Make sure a MULTI-MSI allocation is power of two */ > + unsigned int nvec_aligned = roundup_pow_of_two(desc->nvec_used); > + > + virq = __irq_domain_alloc_irqs(domain, -1, nvec_aligned, > dev_to_node(dev), &arg, false, > desc->affinity); > if (virq < 0) > return msi_handle_pci_fail(domain, desc, allocated); > > - for (i = 0; i < desc->nvec_used; i++) { > + for (i = 0; i < nvec_aligned; i++) { > irq_set_msi_desc_off(virq, i, desc); > irq_debugfs_copy_devname(virq + i, dev); > ret = msi_init_virq(domain, virq + i, vflags); > if (ret) > return ret; > } > + > if (info->flags & MSI_FLAG_DEV_SYSFS) { > + /* > + * This only exposes desc->nvec_used and ignores the > + * overallocated MULTI-MSI ones. > + */ > ret = msi_sysfs_populate_desc(dev, desc); > if (ret) > return ret; > @@ -1610,13 +1618,15 @@ static void __msi_domain_free_irqs(struct device *dev, struct irq_domain *domain > continue; > > /* Make sure all interrupts are deactivated */ > - for (i = 0; i < desc->nvec_used; i++) { > + unsigned int nvec_aligned = roundup_pow_of_two(desc->nvec_used); > + > + for (i = 0; i < nvec_aligned; i++) { > irqd = irq_domain_get_irq_data(domain, desc->irq + i); > if (irqd && irqd_is_activated(irqd)) > irq_domain_deactivate_irq(irqd); > } > > - irq_domain_free_irqs(desc->irq, desc->nvec_used); > + irq_domain_free_irqs(desc->irq, nvec_aligned); > if (info->flags & MSI_FLAG_DEV_SYSFS) > msi_sysfs_remove_desc(dev, desc); > desc->irq = 0; ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out 2026-09-16 23:10 ` Bjorn Helgaas @ 2026-09-21 9:05 ` Han / 한상우Sangwoo 0 siblings, 0 replies; 10+ messages in thread From: Han / 한상우Sangwoo @ 2026-09-21 9:05 UTC (permalink / raw) To: Bjorn Helgaas Cc: Thomas Gleixner, jim2101024, florian.fainelli, lpieralisi, kwilczynski, mani, bhelgaas, bcm-kernel-feedback-list, robh, linux-pci, linux-rpi-kernel, linux-arm-kernel, linux-kernel, Inochi Amaoto Hi Bjorn, Sorry for the delay in testing this. I tested Thomas's patch on the same hardware setup with the 5-vector MSI endpoint. The patch was applied as posted on top of 6.12.93 (rpi-6.12.y). With the patch applied: - The MSI base hwirq remained at 0x8 across 200 driver reload cycles. - The driver got all 5 requested vectors on every cycle, with no single-MSI fallback. Multiple Message Enable remained at 8. - The brcmstb inner-domain mapping returned to baseline after each unload/reload, with 12 mapped while the driver was loaded and 4 after unload. - A kprobe showed one allocation of 8 vectors followed by eight single-vector frees, with nothing left over. The MSI vector exhaustion issue I originally observed no longer reproduces with the patch. I also observed a KASAN report with managed affinity. Using a small out-of-tree test module bound to the same endpoint and requesting 1..3 vectors with PCI_IRQ_MSI | PCI_IRQ_AFFINITY, a request for 3 vectors resulted in: BUG: KASAN: slab-out-of-bounds in __irq_alloc_descs+0x158/0x460 Requests for 5 and 7 vectors were capped to 4 on this 4-CPU system and did not trigger the report. I have not checked this against the unpatched kernel yet, so I cannot tell whether it is related to the patch. Best regards, Sangwoo 2026년 9월 17일 (목) 오전 8:10, Bjorn Helgaas <helgaas@kernel.org>님이 작성: > > On Mon, Sep 07, 2026 at 11:40:34PM +0200, Thomas Gleixner wrote: > > On Mon, Sep 07 2026 at 11:34, Bjorn Helgaas wrote: > > > [+cc Thomas, Inochi for MSI expertise] > > > > > > I want to revive this thread because I think there's a real problem > > > here, and we should solve it for all the PCI controller drivers. > > > > > > There's nothing brcm-specific about the bitmap alloc/free except the > > > size of the msi->used bitmap, so I don't want to copy/paste this sort > > > of fix in all the affected drivers. > > > > > > I'd also like to avoid the extra align_mask and > > > bitmap_find_next_zero_area() followed by manual bitmap_set(). > > > bitmap_find_free_region() already takes care of the alignment and > > > setting the allocated bits. > > > > > > The MSI Multiple Message Enable situation of enabling more vectors in > > > the device than the driver wants is generic to all devices that > > > advertise Multiple Message Capable, and I don't think we should have > > > to deal with this in every host controller driver. > > > > Correct. > > > > > If a driver requests 3 vectors, we have to enable 4 because MSI only > > > supports power-of-two number of vectors. This tells the device it is > > > allowed to use all 4 vectors, and I think the PCI MSI core should > > > assume they all *will* be used instead of relying on the driver's > > > claim that it will only use 3. > > > > That's not really a good idea because e.g. the irq affinity stuff relies > > on the accurate number of interrupts the driver requested with the > > minvec/maxvec range. We can't magically spread more interrupts than the > > driver is able/willing to handle. > > > > But we can fix that without changing the consumer side (device drivers) > > visible behaviour and handle it solely in the core code. > > > > 1) MSI interrupts are special because they have msi_desc::nvec_used > > > 1, so the allocation and the free path can take care of the power of > > two requirement. That just allocates more resources than the driver > > wants but they are just memory. > > > > 2) All MSI parent domain implementations should be able to handle > > domain_ops::free() with nr_irqs > 1. That's something which can be > > trivialy audited. > > > > I really have no memories why the bulk remove function iterates the > > interrupts one by one instead of doing in one go, but this is also > > used by non MSI domains, which might have issues with a bulk remove. > > > > If we establish that all MSI parent domain implementations can > > handle the free() callback with nr_irqs > 1, then > > irq_domain_free_irqs_hierarchy can check whether > > IRQ_DOMAIN_FLAG_MSI_PARENT is set in the domain_flags and avoid the > > loop for that case. > > > > Something like the completely untested below. > > Sangwoo, is there any chance you can test this and see whether it > fixes the issue? > > If it does, I guess we'll have to ask Thomas to post it with the > appropriate Signed-off-by, etc. > > > --- > > diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c > > index 4fdcb6df5306..b3f6cc6ae2ce 100644 > > --- a/kernel/irq/irqdomain.c > > +++ b/kernel/irq/irqdomain.c > > @@ -1611,6 +1611,13 @@ static void irq_domain_free_irqs_hierarchy(struct irq_domain *domain, > > if (!domain->ops->free) > > return; > > > > + /* CHECKME: Are all MSI parent domains capable ? */ > > + if (domain->flags & IRQ_DOMAIN_FLAG_MSI_PARENT) { > > + if (irq_domain_get_irq_data(domain, irq_base)) > > + domain->ops->free(domain, irq_base, nr_irqs); > > + return; > > + } > > + > > for (i = 0; i < nr_irqs; i++) { > > if (irq_domain_get_irq_data(domain, irq_base + i)) > > domain->ops->free(domain, irq_base + i, 1); > > diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c > > index fb5f372215bf..2835b09899ea 100644 > > --- a/kernel/irq/msi.c > > +++ b/kernel/irq/msi.c > > @@ -1333,20 +1333,28 @@ static int __msi_domain_alloc_irqs(struct device *dev, struct irq_domain *domain > > > > ops->set_desc(&arg, desc); > > > > - virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, > > + /* Make sure a MULTI-MSI allocation is power of two */ > > + unsigned int nvec_aligned = roundup_pow_of_two(desc->nvec_used); > > + > > + virq = __irq_domain_alloc_irqs(domain, -1, nvec_aligned, > > dev_to_node(dev), &arg, false, > > desc->affinity); > > if (virq < 0) > > return msi_handle_pci_fail(domain, desc, allocated); > > > > - for (i = 0; i < desc->nvec_used; i++) { > > + for (i = 0; i < nvec_aligned; i++) { > > irq_set_msi_desc_off(virq, i, desc); > > irq_debugfs_copy_devname(virq + i, dev); > > ret = msi_init_virq(domain, virq + i, vflags); > > if (ret) > > return ret; > > } > > + > > if (info->flags & MSI_FLAG_DEV_SYSFS) { > > + /* > > + * This only exposes desc->nvec_used and ignores the > > + * overallocated MULTI-MSI ones. > > + */ > > ret = msi_sysfs_populate_desc(dev, desc); > > if (ret) > > return ret; > > @@ -1610,13 +1618,15 @@ static void __msi_domain_free_irqs(struct device *dev, struct irq_domain *domain > > continue; > > > > /* Make sure all interrupts are deactivated */ > > - for (i = 0; i < desc->nvec_used; i++) { > > + unsigned int nvec_aligned = roundup_pow_of_two(desc->nvec_used); > > + > > + for (i = 0; i < nvec_aligned; i++) { > > irqd = irq_domain_get_irq_data(domain, desc->irq + i); > > if (irqd && irqd_is_activated(irqd)) > > irq_domain_deactivate_irq(irqd); > > } > > > > - irq_domain_free_irqs(desc->irq, desc->nvec_used); > > + irq_domain_free_irqs(desc->irq, nvec_aligned); > > if (info->flags & MSI_FLAG_DEV_SYSFS) > > msi_sysfs_remove_desc(dev, desc); > > desc->irq = 0; ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-09-21 9:05 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-07-30 7:22 [PATCH] PCI: brcmstb: Reserve only the MSI vectors that are handed out Sangwoo Han 2026-08-03 16:11 ` Manivannan Sadhasivam 2026-08-03 22:22 ` Bjorn Helgaas 2026-08-04 11:31 ` Han / 한상우Sangwoo 2026-08-04 12:50 ` Bjorn Helgaas 2026-08-10 23:30 ` Bjorn Helgaas 2026-09-07 16:34 ` Bjorn Helgaas 2026-09-07 21:40 ` Thomas Gleixner 2026-09-16 23:10 ` Bjorn Helgaas 2026-09-21 9:05 ` Han / 한상우Sangwoo
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®