[U-Boot] [PATCH 3/6] dm: pci: Use complete bdf in all pci config read/write routines

Bin Meng bmeng.cn at gmail.com
Sat Jul 18 18:20:04 CEST 2015


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 at 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);
 }
-- 
1.8.2.1



More information about the U-Boot mailing list