
Currently pci_bus_read_config() and pci_bus_write_config() are called with bus number masked off in the parameter bdf, and bus number is supposed to be added back in the bridge driver's pci config read/write ops if the device is behind a pci bridge. However this logic only works for a pci topology where there is only one bridge off the root controller. If there is addtional bridge in the system, the logic will create a non-existent bdf where its bus number gets accumulated across bridges.
To correct this, we change all pci config read/write routines to use complete bdf all the way up to the root controller.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
drivers/pci/pci-uclass.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 5b91fe3..e92e4f3 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -199,8 +199,7 @@ int pci_write_config(pci_dev_t bdf, int offset, unsigned long value, if (ret) return ret;
- return pci_bus_write_config(bus, PCI_MASK_BUS(bdf), offset, value, - size); + return pci_bus_write_config(bus, bdf, offset, value, size); }
int pci_write_config32(pci_dev_t bdf, int offset, u32 value) @@ -239,8 +238,7 @@ int pci_read_config(pci_dev_t bdf, int offset, unsigned long *valuep, if (ret) return ret;
- return pci_bus_read_config(bus, PCI_MASK_BUS(bdf), offset, valuep, - size); + return pci_bus_read_config(bus, bdf, offset, valuep, size); }
int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep) @@ -357,41 +355,43 @@ int pci_bind_bus_devices(struct udevice *bus) { ulong vendor, device; ulong header_type; - pci_dev_t devfn, end; + pci_dev_t bdf, end; bool found_multi; int ret;
found_multi = false; - end = PCI_DEVFN(PCI_MAX_PCI_DEVICES - 1, PCI_MAX_PCI_FUNCTIONS - 1); - for (devfn = PCI_DEVFN(0, 0); devfn < end; devfn += PCI_DEVFN(0, 1)) { + end = PCI_BDF(bus->seq, PCI_MAX_PCI_DEVICES - 1, + PCI_MAX_PCI_FUNCTIONS - 1); + for (bdf = PCI_BDF(bus->seq, 0, 0); bdf < end; + bdf += PCI_BDF(0, 0, 1)) { struct pci_child_platdata *pplat; struct udevice *dev; ulong class;
- if (PCI_FUNC(devfn) && !found_multi) + if (PCI_FUNC(bdf) && !found_multi) continue; /* Check only the first access, we don't expect problems */ - ret = pci_bus_read_config(bus, devfn, PCI_HEADER_TYPE, + ret = pci_bus_read_config(bus, bdf, PCI_HEADER_TYPE, &header_type, PCI_SIZE_8); if (ret) goto error; - pci_bus_read_config(bus, devfn, PCI_VENDOR_ID, &vendor, + pci_bus_read_config(bus, bdf, PCI_VENDOR_ID, &vendor, PCI_SIZE_16); if (vendor == 0xffff || vendor == 0x0000) continue;
- if (!PCI_FUNC(devfn)) + if (!PCI_FUNC(bdf)) found_multi = header_type & 0x80;
debug("%s: bus %d/%s: found device %x, function %d\n", __func__, - bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn)); - pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device, + bus->seq, bus->name, PCI_DEV(bdf), PCI_FUNC(bdf)); + pci_bus_read_config(bus, bdf, PCI_DEVICE_ID, &device, PCI_SIZE_16); - pci_bus_read_config(bus, devfn, PCI_CLASS_DEVICE, &class, + pci_bus_read_config(bus, bdf, PCI_CLASS_DEVICE, &class, PCI_SIZE_16);
/* Find this device in the device tree */ - ret = pci_bus_find_devfn(bus, devfn, &dev); + ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
/* If nothing in the device tree, bind a generic device */ if (ret == -ENODEV) { @@ -399,7 +399,7 @@ int pci_bind_bus_devices(struct udevice *bus) const char *drv;
sprintf(name, "pci_%x:%x.%x", bus->seq, - PCI_DEV(devfn), PCI_FUNC(devfn)); + PCI_DEV(bdf), PCI_FUNC(bdf)); str = strdup(name); if (!str) return -ENOMEM; @@ -412,7 +412,7 @@ int pci_bind_bus_devices(struct udevice *bus)
/* Update the platform data */ pplat = dev_get_parent_platdata(dev); - pplat->devfn = devfn; + pplat->devfn = PCI_MASK_BUS(bdf); pplat->vendor = vendor; pplat->device = device; pplat->class = class; @@ -583,20 +583,20 @@ static int pci_uclass_child_post_bind(struct udevice *dev) return 0; }
-int pci_bridge_read_config(struct udevice *bus, pci_dev_t devfn, uint offset, - ulong *valuep, enum pci_size_t size) +static int pci_bridge_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) { struct pci_controller *hose = bus->uclass_priv; - pci_dev_t bdf = PCI_ADD_BUS(bus->seq, devfn);
return pci_bus_read_config(hose->ctlr, bdf, offset, valuep, size); }
-int pci_bridge_write_config(struct udevice *bus, pci_dev_t devfn, uint offset, - ulong value, enum pci_size_t size) +static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) { struct pci_controller *hose = bus->uclass_priv; - pci_dev_t bdf = PCI_ADD_BUS(bus->seq, devfn);
return pci_bus_write_config(hose->ctlr, bdf, offset, value, size); }