[PATCH v2 05/53] MIPS: PCI: xtalk-bridge: reassign slots whose devio window maps elsewhere

From: Imre Kaloz

Date: Tue Oct 13 2026 - 12:21:55 EST


The PROM may point the devio window covering a BAR elsewhere. On an
Octane, window 2 maps the IOC3 while the RAD1 BAR sits in it, so RAD1
writes land in the IOC3. Reassign such slots like unconfigured ones.

Signed-off-by: Imre Kaloz <kaloz@xxxxxxxxxx>
---
arch/mips/pci/pci-xtalk-bridge.c | 58 ++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)

diff --git a/arch/mips/pci/pci-xtalk-bridge.c b/arch/mips/pci/pci-xtalk-bridge.c
index 16c1ac2c2551..8b56c754245d 100644
--- a/arch/mips/pci/pci-xtalk-bridge.c
+++ b/arch/mips/pci/pci-xtalk-bridge.c
@@ -730,6 +730,63 @@ static struct resource *bridge_map_devio(struct bridge_controller *bc,
return res;
}

+/*
+ * Linux reaches a BAR through the devio window at the BAR's own address, but
+ * the PROM may point that window elsewhere: an Octane's window 2 maps the IOC3
+ * at 0x500000 while the RAD1 BAR sits at 0x600000. Only the offset matters;
+ * the PROM puts a slot's I/O and memory BARs at one address and maps the
+ * window for memory.
+ */
+static bool bridge_devio_reaches(struct bridge_controller *bc,
+ struct xtalk_bridge_platform_data *bd,
+ struct resource *res)
+{
+ resource_size_t base = bd->mem.start - BRIDGE_DEVIO0;
+ resource_size_t offset = res->flags & IORESOURCE_IO ? bd->io_offset :
+ bd->mem_offset;
+ resource_size_t addr = res->start;
+ u32 off;
+ int win;
+
+ while (addr <= res->end) {
+ addr -= base;
+ win = addr < BRIDGE_DEVIO2 ?
+ (addr - BRIDGE_DEVIO0) / BRIDGE_DEVIO_2MB :
+ 2 + (addr - BRIDGE_DEVIO2) / BRIDGE_DEVIO_1MB;
+ if (win >= bridge_nslots(bc))
+ return false;
+ off = bridge_read(bc, b_device[win].reg) & BRIDGE_DEV_OFF_MASK;
+ if (off != (base + BRIDGE_DEVIO(win) - offset) >>
+ BRIDGE_DEV_OFF_ADDR_SHFT)
+ return false;
+ addr = base + BRIDGE_DEVIO(win + 1);
+ }
+
+ return true;
+}
+
+/* Release slots with a BAR Linux cannot reach, for bridge_setup_slot(). */
+static void bridge_release_unreached(struct bridge_controller *bc,
+ struct xtalk_bridge_platform_data *bd,
+ struct pci_bus *bus)
+{
+ unsigned long unreached = 0;
+ struct pci_dev *pdev;
+ struct resource *res;
+ int i;
+
+ list_for_each_entry(pdev, &bus->devices, bus_list)
+ pci_dev_for_each_resource(pdev, res)
+ if (res->parent && !pdev->subordinate &&
+ !bridge_devio_reaches(bc, bd, res))
+ __set_bit(PCI_SLOT(pdev->devfn), &unreached);
+
+ list_for_each_entry(pdev, &bus->devices, bus_list)
+ if (test_bit(PCI_SLOT(pdev->devfn), &unreached))
+ pci_dev_for_each_resource(pdev, res, i)
+ pci_release_resource(pdev, i);
+}
+
/*
* A slot's BARs are reached only through a devio window, which Device(x)
* points at either PCI I/O or PCI memory space. The PROM leaves some slots
@@ -929,6 +986,7 @@ static int bridge_probe(struct platform_device *pdev)
pci_bus_claim_resources(host->bus);
list_for_each_entry(pcidev, &host->bus->devices, bus_list)
__set_bit(PCI_SLOT(pcidev->devfn), &busy);
+ bridge_release_unreached(bc, bd, host->bus);
for (slot = 0; slot < bridge_nslots(bc); slot++)
bridge_setup_slot(bc, bd, dev, host->bus, slot, &busy);
pci_bus_add_devices(host->bus);
--
2.47.3