Skip to content

Commit 9f737cc

Browse files
damien-lemoalbjorn-helgaas
authored andcommitted
PCI: rockchip-ep: Fix MSI IRQ data mapping
The call to rockchip_pcie_prog_ep_ob_atu() used to map the PCI address of MSI data to the memory window allocated on probe for IRQs is done in rockchip_pcie_ep_send_msi_irq() assuming a fixed alignment to a 256B boundary of the PCI address. This is not correct as the alignment constraint for the RK3399 PCI mapping depends on the number of bits of address changing in the mapped region. This leads to an unstable system which sometimes work and sometimes does not (crashing on paging faults when memcpy_toio() or memcpy_fromio() are used). Similar to regular data mapping, the MSI data mapping must thus be handled according to the information provided by rockchip_pcie_ep_align_addr(). Modify rockchip_pcie_ep_send_msi_irq() to use rockchip_pcie_ep_align_addr() to correctly program entry 0 of the ATU for sending MSI IRQs. Link: https://lore.kernel.org/r/20241017015849.190271-7-dlemoal@kernel.org Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
1 parent b212553 commit 9f737cc

File tree

1 file changed

+13
-9
lines changed

1 file changed

+13
-9
lines changed

drivers/pci/controller/pcie-rockchip-ep.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,10 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
382382
{
383383
struct rockchip_pcie *rockchip = &ep->rockchip;
384384
u32 flags, mme, data, data_mask;
385+
size_t irq_pci_size, offset;
386+
u64 irq_pci_addr;
385387
u8 msi_count;
386388
u64 pci_addr;
387-
u32 r;
388389

389390
/* Check MSI enable bit */
390391
flags = rockchip_pcie_read(&ep->rockchip,
@@ -420,18 +421,21 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
420421
PCI_MSI_ADDRESS_LO);
421422

422423
/* Set the outbound region if needed. */
423-
if (unlikely(ep->irq_pci_addr != (pci_addr & PCIE_ADDR_MASK) ||
424+
irq_pci_size = ~PCIE_ADDR_MASK + 1;
425+
irq_pci_addr = rockchip_pcie_ep_align_addr(ep->epc,
426+
pci_addr & PCIE_ADDR_MASK,
427+
&irq_pci_size, &offset);
428+
if (unlikely(ep->irq_pci_addr != irq_pci_addr ||
424429
ep->irq_pci_fn != fn)) {
425-
r = rockchip_ob_region(ep->irq_phys_addr);
426-
rockchip_pcie_prog_ep_ob_atu(rockchip, fn, r,
427-
ep->irq_phys_addr,
428-
pci_addr & PCIE_ADDR_MASK,
429-
~PCIE_ADDR_MASK + 1);
430-
ep->irq_pci_addr = (pci_addr & PCIE_ADDR_MASK);
430+
rockchip_pcie_prog_ep_ob_atu(rockchip, fn,
431+
rockchip_ob_region(ep->irq_phys_addr),
432+
ep->irq_phys_addr,
433+
irq_pci_addr, irq_pci_size);
434+
ep->irq_pci_addr = irq_pci_addr;
431435
ep->irq_pci_fn = fn;
432436
}
433437

434-
writew(data, ep->irq_cpu_addr + (pci_addr & ~PCIE_ADDR_MASK));
438+
writew(data, ep->irq_cpu_addr + offset + (pci_addr & ~PCIE_ADDR_MASK));
435439
return 0;
436440
}
437441

0 commit comments

Comments
 (0)