dm: pci: Use complete bdf in all pci config read/write routines
authorBin Meng <bmeng.cn@gmail.com>
Sat, 18 Jul 2015 16:20:04 +0000 (00:20 +0800)
committerSimon Glass <sjg@chromium.org>
Tue, 28 Jul 2015 16:36:23 +0000 (10:36 -0600)
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

index 3be76c99ee471646dc5307164c6817d69563f793..6d0696a2884e1f4cb2bb0a5da36d744f4a13dff3 100644 (file)
@@ -207,8 +207,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)
@@ -247,8 +246,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)
@@ -383,7 +381,7 @@ static bool pci_match_one_id(const struct pci_device_id *id,
  * This only looks at certain fields in the descriptor.
  */
 static int pci_find_and_bind_driver(struct udevice *parent,
-                                   struct pci_device_id *find_id, int devfn,
+                                   struct pci_device_id *find_id, pci_dev_t bdf,
                                    struct udevice **devp)
 {
        struct pci_driver_entry *start, *entry;
@@ -430,8 +428,8 @@ static int pci_find_and_bind_driver(struct udevice *parent,
        }
 
        /* Bind a generic driver so that the device can be used */
-       sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(devfn),
-               PCI_FUNC(devfn));
+       sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(bdf),
+               PCI_FUNC(bdf));
        str = strdup(name);
        if (!str)
                return -ENOMEM;
@@ -455,42 +453,44 @@ 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_REVISION, &class,
+               pci_bus_read_config(bus, bdf, PCI_CLASS_REVISION, &class,
                                    PCI_SIZE_32);
                class >>= 8;
 
                /* 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);
 
                /* Search for a driver */
 
@@ -504,13 +504,13 @@ int pci_bind_bus_devices(struct udevice *bus)
                        find_id.device = device;
                        find_id.class = class;
                        if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
-                               pci_bus_read_config(bus, devfn,
+                               pci_bus_read_config(bus, bdf,
                                                    PCI_SUBSYSTEM_VENDOR_ID,
                                                    &val, PCI_SIZE_32);
                                find_id.subvendor = val & 0xffff;
                                find_id.subdevice = val >> 16;
                        }
-                       ret = pci_find_and_bind_driver(bus, &find_id, devfn,
+                       ret = pci_find_and_bind_driver(bus, &find_id, bdf,
                                                       &dev);
                }
                if (ret)
@@ -518,7 +518,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;
@@ -689,20 +689,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);
 }