@@ -325,6 +325,8 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
void pci_static_enum_set_opt(const char *str);
int pci_static_enum_exists(void);
void pci_static_enum_bus_nums(struct pci_bus *bus);
+int pci_static_enum_get_busnr(struct pci_bus *bus, struct pci_dev *dev,
+ int default_busnr);
/**
* pci_bus_subordinate() - return the subordinate bus number assigned
* to @dev by the static enumeration profile, or 0 if not set
@@ -337,6 +339,11 @@ static inline unsigned char pci_bus_subordinate(struct pci_bus *bus)
static inline void pci_static_enum_set_opt(const char *str) { return; }
static inline int pci_static_enum_exists(void) { return 0; }
static inline void pci_static_enum_bus_nums(struct pci_bus *bus) { return; }
+static inline int pci_static_enum_get_busnr(struct pci_bus *bus, struct pci_dev *dev,
+ int default_busnr)
+{
+ return default_busnr;
+}
static inline unsigned char pci_bus_subordinate(struct pci_bus *bus)
{
return 0;
@@ -225,3 +225,27 @@ void pci_static_enum_bus_nums(struct pci_bus *bus)
bus->number = bus->busn_res.start = setting->secondary_bus;
bus->subordinate = setting->subordinate_bus;
}
+
+/**
+ * pci_static_enum_get_busnr() - calculate bus number for a device
+ * @bus: bus contain @dev
+ * @dev: PCI device to lookup
+ * @default_num: default bus number
+ * Return: expected bus number for @dev, or @default_num if @dev has
+ * no if @dev has no static enumeration profile
+ */
+int pci_static_enum_get_busnr(struct pci_bus *bus, struct pci_dev *dev,
+ int default_num)
+{
+ struct pci_static_enum_setting *setting;
+
+ if (!bus || !dev)
+ return default_num;
+
+ setting =
+ pci_static_enum_find_setting(pci_domain_nr(bus), bus->number,
+ dev->devfn);
+ if (setting)
+ return setting->secondary_bus;
+ return default_num;
+}
@@ -777,6 +777,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
u16 bctl;
u8 primary, secondary, subordinate;
int broken = 0;
+ int child_busnr;
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
primary = buses & 0xFF;
@@ -867,9 +868,10 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
/* Prevent assigning a bus number that already exists.
* This can happen when a bridge is hot-plugged, so in
* this case we only re-scan this bus. */
- child = pci_find_bus(pci_domain_nr(bus), max+1);
+ child_busnr = pci_static_enum_get_busnr(bus, dev, max+1);
+ child = pci_find_bus(pci_domain_nr(bus), child_busnr);
if (!child) {
- child = pci_add_new_bus(bus, dev, max+1);
+ child = pci_add_new_bus(bus, dev, child_busnr);
if (!child)
goto out;
pci_bus_insert_busn_res(child, child->number, 0xff);
While scanning a bridge, pci_scan_bridge() checks if a child pci_bus already exists by looking up its bus number. It uses the value 'max+1' as the expected child bus number. If the child does not exist, pci_scan_bridge() will create a new pci_bus for the child. While rescanning the same bridge, pci_scan_bridge() assumes an existing child's bus number is 'max+1'. This is not always true, given a static enumeration profile. The profile may intentionally skip bus numbers. Thus, the child's number is not necessarily 'max+1'. This commit changes the scanning behavior slightly. If the device being scanned has an enumeration profile, then pci_scan_bridge() will use that number when searching for it. Otherwise it falls back to the default 'max+1' bus number. Signed-off-by: Jason Tang <jason.tang2@ngc.com> --- drivers/pci/pci.h | 7 +++++++ drivers/pci/pci_static_enum.c | 24 ++++++++++++++++++++++++ drivers/pci/probe.c | 6 ++++-- 3 files changed, 35 insertions(+), 2 deletions(-)