dm: pci: Use complete bdf in all pci config read/write routines

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>
This commit is contained in:
Bin Meng 2015-07-19 00:20:04 +08:00 committed by Simon Glass
parent 95f3aa209a
commit 4d8615cbf5
1 changed files with 27 additions and 27 deletions

View File

@ -207,8 +207,7 @@ int pci_write_config(pci_dev_t bdf, int offset, unsigned long value,
if (ret) if (ret)
return ret; return ret;
return pci_bus_write_config(bus, PCI_MASK_BUS(bdf), offset, value, return pci_bus_write_config(bus, bdf, offset, value, size);
size);
} }
int pci_write_config32(pci_dev_t bdf, int offset, u32 value) 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) if (ret)
return ret; return ret;
return pci_bus_read_config(bus, PCI_MASK_BUS(bdf), offset, valuep, return pci_bus_read_config(bus, bdf, offset, valuep, size);
size);
} }
int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep) 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. * This only looks at certain fields in the descriptor.
*/ */
static int pci_find_and_bind_driver(struct udevice *parent, 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 udevice **devp)
{ {
struct pci_driver_entry *start, *entry; 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 */ /* Bind a generic driver so that the device can be used */
sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(devfn), sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(bdf),
PCI_FUNC(devfn)); PCI_FUNC(bdf));
str = strdup(name); str = strdup(name);
if (!str) if (!str)
return -ENOMEM; return -ENOMEM;
@ -455,42 +453,44 @@ int pci_bind_bus_devices(struct udevice *bus)
{ {
ulong vendor, device; ulong vendor, device;
ulong header_type; ulong header_type;
pci_dev_t devfn, end; pci_dev_t bdf, end;
bool found_multi; bool found_multi;
int ret; int ret;
found_multi = false; found_multi = false;
end = PCI_DEVFN(PCI_MAX_PCI_DEVICES - 1, PCI_MAX_PCI_FUNCTIONS - 1); end = PCI_BDF(bus->seq, PCI_MAX_PCI_DEVICES - 1,
for (devfn = PCI_DEVFN(0, 0); devfn < end; devfn += PCI_DEVFN(0, 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 pci_child_platdata *pplat;
struct udevice *dev; struct udevice *dev;
ulong class; ulong class;
if (PCI_FUNC(devfn) && !found_multi) if (PCI_FUNC(bdf) && !found_multi)
continue; continue;
/* Check only the first access, we don't expect problems */ /* 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); &header_type, PCI_SIZE_8);
if (ret) if (ret)
goto error; 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); PCI_SIZE_16);
if (vendor == 0xffff || vendor == 0x0000) if (vendor == 0xffff || vendor == 0x0000)
continue; continue;
if (!PCI_FUNC(devfn)) if (!PCI_FUNC(bdf))
found_multi = header_type & 0x80; found_multi = header_type & 0x80;
debug("%s: bus %d/%s: found device %x, function %d\n", __func__, debug("%s: bus %d/%s: found device %x, function %d\n", __func__,
bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn)); bus->seq, bus->name, PCI_DEV(bdf), PCI_FUNC(bdf));
pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device, pci_bus_read_config(bus, bdf, PCI_DEVICE_ID, &device,
PCI_SIZE_16); 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); PCI_SIZE_32);
class >>= 8; class >>= 8;
/* Find this device in the device tree */ /* 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 */ /* Search for a driver */
@ -504,13 +504,13 @@ int pci_bind_bus_devices(struct udevice *bus)
find_id.device = device; find_id.device = device;
find_id.class = class; find_id.class = class;
if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) { if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
pci_bus_read_config(bus, devfn, pci_bus_read_config(bus, bdf,
PCI_SUBSYSTEM_VENDOR_ID, PCI_SUBSYSTEM_VENDOR_ID,
&val, PCI_SIZE_32); &val, PCI_SIZE_32);
find_id.subvendor = val & 0xffff; find_id.subvendor = val & 0xffff;
find_id.subdevice = val >> 16; 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); &dev);
} }
if (ret) if (ret)
@ -518,7 +518,7 @@ int pci_bind_bus_devices(struct udevice *bus)
/* Update the platform data */ /* Update the platform data */
pplat = dev_get_parent_platdata(dev); pplat = dev_get_parent_platdata(dev);
pplat->devfn = devfn; pplat->devfn = PCI_MASK_BUS(bdf);
pplat->vendor = vendor; pplat->vendor = vendor;
pplat->device = device; pplat->device = device;
pplat->class = class; pplat->class = class;
@ -689,20 +689,20 @@ static int pci_uclass_child_post_bind(struct udevice *dev)
return 0; return 0;
} }
int pci_bridge_read_config(struct udevice *bus, pci_dev_t devfn, uint offset, static int pci_bridge_read_config(struct udevice *bus, pci_dev_t bdf,
ulong *valuep, enum pci_size_t size) uint offset, ulong *valuep,
enum pci_size_t size)
{ {
struct pci_controller *hose = bus->uclass_priv; 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); 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, static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf,
ulong value, enum pci_size_t size) uint offset, ulong value,
enum pci_size_t size)
{ {
struct pci_controller *hose = bus->uclass_priv; 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); return pci_bus_write_config(hose->ctlr, bdf, offset, value, size);
} }