[PATCH v2 2/2] PCI: dwc: ep: Fix unmap potentially unmapping the wrong iATU
Niklas Cassel <[email protected]> Thu, 30 Jul 2026 15:31:26 +0200
| Newsgroups | org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
The persistent MSI iATU mapping can conflict with the dynamic MSI-X iATU mapping, since they are both using ep->msi_mem_phys. If dw_pcie_ep_raise_msi_irq() caches the iATU mapping, and then dw_pcie_ep_raise_msix_irq() is called, it maps the same address to a new window/iATU. When dw_pcie_ep_raise_msix_irq() later calls dw_pcie_ep_unmap_addr(), the lookup function, dw_pcie_find_index(), returns the first iATU index which has the address mapped. This means that dw_pcie_ep_raise_msix_irq() can unmap the address mapped by dw_pcie_ep_raise_msi_irq(), without clearing ep->msi_iatu_mapped. If there is a cached MSI iATU mapping, let dw_pcie_ep_raise_msix_irq() unmap it first, so that we won't have two different iATUs mapping the same address. Reported-by: Sashiko <[email protected]> Link: https://lore.kernel.org/linux-pci/[email protected]/ Fixes: 8719c64e76bf ("PCI: dwc: ep: Cache MSI outbound iATU mapping") Signed-off-by: Niklas Cassel <[email protected]> --- drivers/pci/controller/dwc/pcie-designware-ep.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 3128e7ae8c5f..7cd169d45890 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -1127,6 +1127,17 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return -EPERM; } + /* + * ep->msi_iatu_mapped means that an MSI target address is cached, + * unmap it first so that we can reuse ep->msi_mem_phys for MSI-X. + */ + if (ep->msi_iatu_mapped) { + /* flush posted write before unmap */ + readl(ep->msi_mem + ep->msi_iatu_mapped_offset); + dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); + ep->msi_iatu_mapped = false; + } + msg_addr = dw_pcie_ep_align_addr(epc, msg_addr, &map_size, &offset); ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, map_size); -- 2.55.0