2012-02-28 02:11:21

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH -v8 0/18] PCI: allocate pci bus num range for unassigned bridge busn

be1ba9d: PCI, pciehp: Remove not needed bus number range checking
131d47a: PCI: Double checking setting for bus register and bus struct.
5932e47: pcmcia: remove workaround for fixing pci parent bus subordinate
ea33b11: PCI: Seperate child bus scanning to two passes overall
00ca2e7: PCI: kill pci_fixup_parent_subordinate_busnr()
596d4a6: PCI: Allocate bus range instead of use max blindly
64bfcda: PCI: Strict checking of valid range for bridge
d4ed872: PCI: Probe safe range that we can use for unassigned bridge.
31e4760: PCI: Add pci_bus_extend/shrink_top()
74b8f25: PCI, parisc: Register busn_res for root buses
de71ada: PCI, powerpc: Register busn_res for root buses
e810285: PCI, sparc: Register busn_res for root buses
8912504: PCI, ia64: Register busn_res for root buses
82de8a8: PCI, x86: Register busn_res for root buses
2e8d3bf: PCI: Add busn_res tracking in core
a9a5832: PCI: Add busn_res operation functions
6122ad8: PCI: Add busn_res into struct pci_bus.
b362780: x86, PCI: Merge pcibios_scan_root and pci_scan_bus_on_node

Set up iobusn_resource tree, and register bus number range to it.
Later when need to find bus range, will try to allocate from the tree

Need to test on arches other than x86. esp for ia64 and powerpc that support
more than on peer root buses.

could be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-pci-busn-alloc

need to apply to top of pci/for-linus plus pci/linux-next plus
[PATCH -v2] PCI: pci_host_bridge related cleanup

-v2: according to Jesse, split to more small patches.
-v3: address some request from Bjorn. like make use %pR for busn_res debug print
out, and move the comment change with code change.
-v4: fixes the problem about rescan that Bjorn found.
-v5: add /proc/iobusn that is requested by Bjorn.
remove old workaround from pciehp.
add rescan_bridge for pci bridge in /sys
-v6: remove global iobusn_resource, and every root bus's busn_res will be root
of children buses' busn_res.
pc cardbus change is tested by pcmcia maintainter.
-v7: remove pci_scan_root_bus_max requested by Bjorn and Jesse.
-v8: rebase on top other patches with arch/x86/pci/bus_numa.c changes
also only include busn_res related changes.

Thanks

Yinghai

arch/ia64/pci/pci.c | 2 +
arch/powerpc/kernel/pci-common.c | 7 +-
arch/sparc/kernel/pci.c | 1 +
arch/x86/include/asm/topology.h | 3 +-
arch/x86/pci/acpi.c | 8 +-
arch/x86/pci/bus_numa.c | 9 +-
arch/x86/pci/common.c | 37 +---
drivers/parisc/dino.c | 2 +
drivers/parisc/lba_pci.c | 3 +
drivers/pci/hotplug/pciehp_pci.c | 12 +-
drivers/pci/probe.c | 430 +++++++++++++++++++++++++++++++-------
drivers/pci/remove.c | 1 +
drivers/pcmcia/yenta_socket.c | 75 -------
include/linux/pci.h | 4 +
14 files changed, 396 insertions(+), 198 deletions(-)


2012-02-28 02:11:30

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 13/18] PCI: Allocate bus range instead of use max blindly

every bus have extra busn_res, and linked them toghter to iobusn_resource.

when need to find usable bus number range, try probe from iobusn_resource tree.

To avoid falling to small hole in the middle, we try from 8 spare bus.
if can not find 8 or more in the middle, will try to append 8 on top later.
then if can not append, will try to find 7 from the middle, then will try to append 7 on top.
then if can not append, will try to find 6 from the middle...

for cardbus will only find 4 spare.

if extend from top, at last will shrink back to really needed range...

-v4: fix checking with pci rescan. Found by Bjorn.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 100 ++++++++++++++++++++++++++++++---------------------
1 files changed, 59 insertions(+), 41 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 1d36a2a..85266e6 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -832,10 +832,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
{
struct pci_bus *child;
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
- u32 buses, i, j = 0;
+ u32 buses;
u16 bctl;
u8 primary, secondary, subordinate;
int broken = 0;
+ struct resource *parent_res = NULL;

pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
primary = buses & 0xFF;
@@ -852,10 +853,16 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,

/* Check if setup is sensible at all */
if (!pass &&
- (primary != bus->number || secondary <= bus->number)) {
- dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
+ (primary != bus->number || secondary <= bus->number))
broken = 1;
- }
+
+ /* more strict checking */
+ if (!pass && !broken && !dev->subordinate)
+ broken = pci_bridge_check_busn_broken(bus, dev,
+ secondary, subordinate);
+
+ if (broken)
+ dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");

/* Disable MasterAbortMode during probing to avoid reporting
of bus errors (in some architectures) */
@@ -888,6 +895,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
child->primary = primary;
child->subordinate = subordinate;
child->bridge_ctl = bctl;
+
+ pci_bus_insert_busn_res(child, secondary, subordinate);
}

cmax = pci_scan_child_bus(child);
@@ -900,6 +909,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
* We need to assign a number to this bus which we always
* do in the second pass.
*/
+ long shrink_size;
+ struct resource busn_res;
+ int ret = -ENOMEM;
+ int old_max = max;
+
if (!pass) {
if (pcibios_assign_all_busses() || broken)
/* Temporarily disable forwarding of the
@@ -916,20 +930,43 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
/* Clear errors */
pci_write_config_word(dev, PCI_STATUS, 0xffff);

- /* 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);
- if (!child) {
- child = pci_add_new_bus(bus, dev, ++max);
- if (!child)
- goto out;
+ if (dev->subordinate) {
+ /* We get here only for cardbus */
+ child = dev->subordinate;
+ if (!is_cardbus)
+ dev_warn(&dev->dev,
+ "rescan scaned bridge as broken one again ?");
+
+ goto out;
}
+ /*
+ * For CardBus bridges, we leave 4 bus numbers
+ * as cards with a PCI-to-PCI bridge can be
+ * inserted later.
+ * other just allocate 8 bus to avoid we fall into
+ * small hole in the middle.
+ */
+ ret = pci_bridge_probe_busn_res(bus, dev, &busn_res,
+ is_cardbus ? (CARDBUS_RESERVE_BUSNR + 1) : 8,
+ &parent_res);
+
+ if (ret != 0)
+ goto out;
+
+ child = pci_add_new_bus(bus, dev, busn_res.start);
+ if (!child)
+ goto out;
+
+ child->subordinate = busn_res.end;
+ pci_bus_insert_busn_res(child, busn_res.start, busn_res.end);
+
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->secondary) << 8)
| ((unsigned int)(child->subordinate) << 16);

+ max = child->subordinate;
+
/*
* yenta.c forces a secondary latency timer of 176.
* Copy that behaviour here.
@@ -960,43 +997,24 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
* the real value of max.
*/
pci_fixup_parent_subordinate_busnr(child, max);
+
} else {
- /*
- * For CardBus bridges, we leave 4 bus numbers
- * as cards with a PCI-to-PCI bridge can be
- * inserted later.
- */
- for (i=0; i<CARDBUS_RESERVE_BUSNR; i++) {
- struct pci_bus *parent = bus;
- if (pci_find_bus(pci_domain_nr(bus),
- max+i+1))
- break;
- while (parent->parent) {
- if ((!pcibios_assign_all_busses()) &&
- (parent->subordinate > max) &&
- (parent->subordinate <= max+i)) {
- j = 1;
- }
- parent = parent->parent;
- }
- if (j) {
- /*
- * Often, there are two cardbus bridges
- * -- try to leave one valid bus number
- * for each one.
- */
- i /= 2;
- break;
- }
- }
- max += i;
pci_fixup_parent_subordinate_busnr(child, max);
}
/*
* Set the subordinate bus number to its real value.
*/
+ shrink_size = child->subordinate - max;
child->subordinate = max;
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+ pci_bus_update_busn_res_end(child, max);
+
+ /* shrink some back, if we extend top before */
+ if (!is_cardbus && (shrink_size > 0) && parent_res)
+ pci_bus_shrink_top(bus, shrink_size, parent_res);
+
+ if (old_max > max)
+ max = old_max;
}

sprintf(child->name,
--
1.7.7

2012-02-28 02:11:41

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 17/18] PCI: Double checking setting for bus register and bus struct.

User could use setpci change bridge's bus register. that could make value of register
and struct is out of sync.
User later will use rescan to see the devices is moving.

In the rescaning, we need to double check the range and remove the old struct at first.

to make thing working user may need have script to remove children devices under bridge
at first, and then use setpci update bus register and then rescan.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a4ecae0..554839e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -843,6 +843,46 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
(primary != bus->number || secondary <= bus->number))
broken = 1;

+ if (!pass && dev->subordinate) {
+ child = dev->subordinate;
+ /*
+ * User could change bus register in bridge manually with
+ * setpci and rescan. So double check the setting, and remove
+ * old structs. Don't set broken yet, let following check
+ * to see if the new setting good.
+ */
+ if (primary != child->primary ||
+ secondary != child->secondary ||
+ subordinate != child->subordinate) {
+ dev_info(&dev->dev,
+ "someone changed bus register from pri:%02x, sec:%02x, sub:%02x to pri:%02x, sec:%02x, sub:%02x\n",
+ child->primary, child->secondary, child->subordinate,
+ primary, secondary, subordinate);
+ if (!list_empty(&dev->subordinate->devices)) {
+ u32 old_buses;
+
+ dev_info(&dev->dev,
+ "but children devices are not removed manually before that.\n");
+ /*
+ * Try best to remove left children devices
+ * but we need to set bus register back, otherwise
+ * We can not access children device and stop them
+ */
+ old_buses = (buses & 0xff000000)
+ | ((unsigned int)(child->primary) << 0)
+ | ((unsigned int)(child->secondary) << 8)
+ | ((unsigned int)(child->subordinate) << 16);
+ pci_write_config_dword(dev, PCI_PRIMARY_BUS,
+ old_buses);
+ pci_stop_and_remove_behind_bridge(dev);
+ pci_write_config_dword(dev, PCI_PRIMARY_BUS,
+ buses);
+ }
+ pci_remove_bus(dev->subordinate);
+ dev->subordinate = NULL;
+ }
+ }
+
/* more strict checking */
if (!pass && !broken && !dev->subordinate)
broken = pci_bridge_check_busn_broken(bus, dev,
--
1.7.7

2012-02-28 02:11:47

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 16/18] pcmcia: remove workaround for fixing pci parent bus subordinate

Now pci busn allocation code is there, and it will preallocate bus number and it
will make sure parent buses subordinate is right.

So remove workaround here.

Signed-off-by: Yinghai Lu <[email protected]>
Tested-by: Dominik Brodowski <[email protected]>
Cc: Rusty Russell <[email protected]>
Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
---
drivers/pcmcia/yenta_socket.c | 75 -----------------------------------------
1 files changed, 0 insertions(+), 75 deletions(-)

diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 849c0c1..5757cae 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1064,79 +1064,6 @@ static void yenta_config_init(struct yenta_socket *socket)
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
}

-/**
- * yenta_fixup_parent_bridge - Fix subordinate bus# of the parent bridge
- * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to
- *
- * Checks if devices on the bus which the CardBus bridge bridges to would be
- * invisible during PCI scans because of a misconfigured subordinate number
- * of the parent brige - some BIOSes seem to be too lazy to set it right.
- * Does the fixup carefully by checking how far it can go without conflicts.
- * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
- */
-static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
-{
- struct list_head *tmp;
- unsigned char upper_limit;
- /*
- * We only check and fix the parent bridge: All systems which need
- * this fixup that have been reviewed are laptops and the only bridge
- * which needed fixing was the parent bridge of the CardBus bridge:
- */
- struct pci_bus *bridge_to_fix = cardbus_bridge->parent;
-
- /* Check bus numbers are already set up correctly: */
- if (bridge_to_fix->subordinate >= cardbus_bridge->subordinate)
- return; /* The subordinate number is ok, nothing to do */
-
- if (!bridge_to_fix->parent)
- return; /* Root bridges are ok */
-
- /* stay within the limits of the bus range of the parent: */
- upper_limit = bridge_to_fix->parent->subordinate;
-
- /* check the bus ranges of all silbling bridges to prevent overlap */
- list_for_each(tmp, &bridge_to_fix->parent->children) {
- struct pci_bus *silbling = pci_bus_b(tmp);
- /*
- * If the silbling has a higher secondary bus number
- * and it's secondary is equal or smaller than our
- * current upper limit, set the new upper limit to
- * the bus number below the silbling's range:
- */
- if (silbling->secondary > bridge_to_fix->subordinate
- && silbling->secondary <= upper_limit)
- upper_limit = silbling->secondary - 1;
- }
-
- /* Show that the wanted subordinate number is not possible: */
- if (cardbus_bridge->subordinate > upper_limit)
- dev_printk(KERN_WARNING, &cardbus_bridge->dev,
- "Upper limit for fixing this "
- "bridge's parent bridge: #%02x\n", upper_limit);
-
- /* If we have room to increase the bridge's subordinate number, */
- if (bridge_to_fix->subordinate < upper_limit) {
-
- /* use the highest number of the hidden bus, within limits */
- unsigned char subordinate_to_assign =
- min(cardbus_bridge->subordinate, upper_limit);
-
- dev_printk(KERN_INFO, &bridge_to_fix->dev,
- "Raising subordinate bus# of parent "
- "bus (#%02x) from #%02x to #%02x\n",
- bridge_to_fix->number,
- bridge_to_fix->subordinate, subordinate_to_assign);
-
- /* Save the new subordinate in the bus struct of the bridge */
- bridge_to_fix->subordinate = subordinate_to_assign;
-
- /* and update the PCI config space with the new subordinate */
- pci_write_config_byte(bridge_to_fix->self,
- PCI_SUBORDINATE_BUS, bridge_to_fix->subordinate);
- }
-}
-
/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
@@ -1257,8 +1184,6 @@ static int __devinit yenta_probe(struct pci_dev *dev, const struct pci_device_id
dev_printk(KERN_INFO, &dev->dev,
"Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));

- yenta_fixup_parent_bridge(dev->subordinate);
-
/* Register it with the pcmcia layer.. */
ret = pcmcia_register_socket(&socket->socket);
if (ret == 0) {
--
1.7.7

2012-02-28 02:11:39

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 09/18] PCI, parisc: Register busn_res for root buses

Signed-off-by: Yinghai Lu <[email protected]>
Cc: Kyle McMartin <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: [email protected]
---
drivers/parisc/dino.c | 2 ++
drivers/parisc/lba_pci.c | 3 +++
2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 0610e91..ea3f483 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -999,7 +999,9 @@ static int __init dino_probe(struct parisc_device *dev)
return 0;
}

+ pci_bus_insert_busn_res(bus, dino_current_bus, 255);
bus->subordinate = pci_scan_child_bus(bus);
+ pci_bus_update_busn_res_end(bus, bus->subordinate);

/* This code *depends* on scanning being single threaded
* if it isn't, this global bus number count will fail
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index e885764..84fa239 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1512,6 +1512,9 @@ lba_driver_probe(struct parisc_device *dev)
return 0;
}

+ pci_bus_insert_busn_res(lba_bus, lba_dev->hba.bus_num.start,
+ lba_dev->hba.bus_num.end);
+
lba_bus->subordinate = pci_scan_child_bus(lba_bus);

/* This is in lieu of calling pci_assign_unassigned_resources() */
--
1.7.7

2012-02-28 02:11:37

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 15/18] PCI: Seperate child bus scanning to two passes overall

In extreme case: Two bridges are properly setup.
bridge A
bridge AA
bridge AB
bridge B
bridge BA
bridge BB
but AA, AB are not setup properly.
bridge A has small range, and bridge AB could need more, when do the
first pass0 for bridge A, it will do pass0 and pass1 for AA and AB,
during that process, it will extend range of A for AB blindly.
because bridge B is not registered yet.
that could overlap range that is used by bridge B.

Right way should be:
do pass0 for all good bridges at first.
So we could do pass0 for bridge B before pass1 for bridge AB.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 50 ++++++++++++++++++++++++++++++++++----------------
1 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 2aee87b..a4ecae0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -802,6 +802,9 @@ static int __devinit pci_bridge_check_busn_broken(struct pci_bus *bus,

return broken;
}
+
+static unsigned int __devinit __pci_scan_child_bus(struct pci_bus *bus,
+ int pass);
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
@@ -858,11 +861,10 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
!is_cardbus && !broken) {
unsigned int cmax;
/*
- * Bus already configured by firmware, process it in the first
- * pass and just note the configuration.
+ * Bus already configured by firmware, still process it in two
+ * passes in extreme case like two adjaced bridges have children
+ * bridges that are not setup properly.
*/
- if (pass)
- goto out;

/*
* If we already got to this bus through a different bridge,
@@ -883,7 +885,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
pci_bus_insert_busn_res(child, secondary, subordinate);
}

- cmax = pci_scan_child_bus(child);
+ cmax = __pci_scan_child_bus(child, pass);
if (cmax > max)
max = cmax;
if (child->subordinate > max)
@@ -1697,12 +1699,13 @@ void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
}
EXPORT_SYMBOL_GPL(pcie_bus_configure_settings);

-unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
+static unsigned int __devinit __pci_scan_child_bus(struct pci_bus *bus,
+ int pass)
{
- unsigned int devfn, pass, max = bus->secondary;
+ unsigned int devfn, max = bus->secondary;
struct pci_dev *dev;

- dev_dbg(&bus->dev, "scanning bus\n");
+ dev_dbg(&bus->dev, "scanning bus pass %d\n", pass);

/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8)
@@ -1716,18 +1719,16 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
* all PCI-to-PCI bridges on this bus.
*/
if (!bus->is_added) {
- dev_dbg(&bus->dev, "fixups for bus\n");
+ dev_dbg(&bus->dev, "fixups for bus pass %d\n", pass);
pcibios_fixup_bus(bus);
if (pci_is_root_bus(bus))
bus->is_added = 1;
}

- for (pass=0; pass < 2; pass++)
- list_for_each_entry(dev, &bus->devices, bus_list) {
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
- dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
- max = pci_scan_bridge(bus, dev, max, pass);
- }
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+ max = pci_scan_bridge(bus, dev, max, pass);

/*
* We've scanned the bus and so we know all about what's on
@@ -1736,7 +1737,24 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
*
* Return how far we've got finding sub-buses.
*/
- dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max);
+ dev_dbg(&bus->dev, "bus scan returning with max=%02x pass %d\n",
+ max, pass);
+
+ return max;
+}
+
+unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
+{
+ int pass;
+ unsigned int max = 0, tmp;
+
+ for (pass = 0; pass < 2; pass++) {
+ tmp = __pci_scan_child_bus(bus, pass);
+
+ if (tmp > max)
+ max = tmp;
+ }
+
return max;
}

--
1.7.7

2012-02-28 02:11:34

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 18/18] PCI, pciehp: Remove not needed bus number range checking

Found hotplug adding one EM with bridge fail, bios only leave one bus range
for slot.

[ 1169.621444] pciehp: No bus number available for hot-added bridge 0000:55:00.0
[ 1169.633277] pcieport 0000:40:03.0: PCI bridge to [bus 55-55]

With busn_res tracking and allocating, we don't need that checking anymore.

Parent bridges' bus number will be extended safely.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/hotplug/pciehp_pci.c | 12 +-----------
1 files changed, 1 insertions(+), 11 deletions(-)

diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 47d9dc0..e21171c 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -37,18 +37,8 @@
static int __ref pciehp_add_bridge(struct pci_dev *dev)
{
struct pci_bus *parent = dev->bus;
- int pass, busnr, start = parent->secondary;
- int end = parent->subordinate;
+ int pass, busnr = parent->secondary;

- for (busnr = start; busnr <= end; busnr++) {
- if (!pci_find_bus(pci_domain_nr(parent), busnr))
- break;
- }
- if (busnr-- > end) {
- err("No bus number available for hot-added bridge %s\n",
- pci_name(dev));
- return -1;
- }
for (pass = 0; pass < 2; pass++)
busnr = pci_scan_bridge(parent, dev, busnr, pass);
if (!dev->subordinate)
--
1.7.7

2012-02-28 02:11:29

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 12/18] PCI: Strict checking of valid range for bridge

children bridges busn range should be able to be allocated from parent bus range.

to avoid overlapping between sibling bridges on same bus.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 24 ++++++++++++++++++++++++
1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index d483a3d..1d36a2a 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -794,6 +794,30 @@ reduce_needed_size:
return ret;
}

+static int __devinit pci_bridge_check_busn_broken(struct pci_bus *bus,
+ struct pci_dev *dev,
+ int secondary, int subordinate)
+{
+ int broken = 0;
+
+ struct resource busn_res;
+ int ret;
+
+ memset(&busn_res, 0, sizeof(struct resource));
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "check if busn %02x-%02x is in busn_res: %pR\n",
+ secondary, subordinate, &bus->busn_res);
+ ret = allocate_resource(&bus->busn_res, &busn_res,
+ (subordinate - secondary + 1),
+ secondary, subordinate,
+ 1, NULL, NULL);
+ if (ret)
+ broken = 1;
+ else
+ release_resource(&busn_res);
+
+ return broken;
+}
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
--
1.7.7

2012-02-28 02:13:00

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 08/18] PCI, powerpc: Register busn_res for root buses

Signed-off-by: Yinghai Lu <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: [email protected]
---
arch/powerpc/kernel/pci-common.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 910b9de..ae5ae5f 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1660,6 +1660,8 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
bus->secondary = hose->first_busno;
hose->bus = bus;

+ pci_bus_insert_busn_res(bus, hose->first_busno, hose->last_busno);
+
/* Get probe mode and perform scan */
mode = PCI_PROBE_NORMAL;
if (node && ppc_md.pci_probe_mode)
@@ -1670,8 +1672,11 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
of_scan_bus(node, bus);
}

- if (mode == PCI_PROBE_NORMAL)
+ if (mode == PCI_PROBE_NORMAL) {
+ pci_bus_update_busn_res_end(bus, 255);
hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+ pci_bus_update_busn_res_end(bus, bus->subordinate);
+ }

/* Platform gets a chance to do some global fixups before
* we proceed to resource allocation
--
1.7.7

2012-02-28 02:11:27

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 11/18] PCI: Probe safe range that we can use for unassigned bridge.

Try to allocate from parent bus busn_res. if can not find any big enough, will try
to extend parent bus top. even the extending is through allocating, after allocating
will pad the range to parent buses top.

When extending happens, We will record the parent_res, so could use it as stopper
for really extend/shrink top later.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 110 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c03d3ff..d483a3d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -684,6 +684,116 @@ static void __devinit pci_bus_shrink_top(struct pci_bus *parent,
pci_bus_update_top(parent, -size, parent_res);
}

+static resource_size_t __devinit find_res_top_free_size(struct resource *res)
+{
+ resource_size_t n_size;
+ struct resource tmp_res;
+
+ /*
+ * find out number below res->end, that we can use at first
+ * res->start can not be used.
+ */
+ n_size = resource_size(res) - 1;
+ memset(&tmp_res, 0, sizeof(struct resource));
+ while (n_size > 0) {
+ int ret;
+
+ ret = allocate_resource(res, &tmp_res, n_size,
+ res->end - n_size + 1, res->end,
+ 1, NULL, NULL);
+ if (ret == 0) {
+ release_resource(&tmp_res);
+ break;
+ }
+ n_size--;
+ }
+
+ return n_size;
+}
+
+static int __devinit pci_bridge_probe_busn_res(struct pci_bus *bus,
+ struct pci_dev *dev, struct resource *busn_res,
+ resource_size_t needed_size, struct resource **p)
+{
+ int ret = -ENOMEM;
+ resource_size_t n_size;
+ struct pci_bus *parent;
+ struct resource *parent_res = NULL;
+ resource_size_t tmp = bus->busn_res.end + 1;
+ int free_sz = -1;
+
+again:
+ /*
+ * find bigest range in bus->busn_res that we can use in the middle
+ * and we can not use bus->busn_res.start.
+ */
+ n_size = resource_size(&bus->busn_res) - 1;
+ memset(busn_res, 0, sizeof(struct resource));
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "find free busn in busn_res: %pR\n", &bus->busn_res);
+ while (n_size >= needed_size) {
+ ret = allocate_resource(&bus->busn_res, busn_res, n_size,
+ bus->busn_res.start + 1, bus->busn_res.end,
+ 1, NULL, NULL);
+ if (ret == 0) {
+ /* found one, prepare to return */
+ release_resource(busn_res);
+
+ return ret;
+ }
+ n_size--;
+ }
+
+ /* try extend the top of parent bus, find free under top af first */
+ if (free_sz < 0) {
+ free_sz = find_res_top_free_size(&bus->busn_res);
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "found free busn %d in busn_res: %pR top\n",
+ free_sz, &bus->busn_res);
+ }
+ n_size = free_sz;
+
+ /* can not extend cross domain boundary */
+ if ((0xff - bus->busn_res.end) < (needed_size - n_size))
+ goto reduce_needed_size;
+
+ /* find exteded range */
+ memset(busn_res, 0, sizeof(struct resource));
+ parent = bus->parent;
+ while (parent) {
+ ret = allocate_resource(&parent->busn_res, busn_res,
+ needed_size - n_size,
+ tmp, tmp + needed_size - n_size - 1,
+ 1, NULL, NULL);
+ if (ret == 0)
+ break;
+ parent = parent->parent;
+ }
+
+reduce_needed_size:
+ if (ret != 0) {
+ needed_size--;
+ if (!needed_size)
+ return ret;
+
+ goto again;
+ }
+
+ /* save parent_res, we need it as stopper later */
+ parent_res = busn_res->parent;
+
+ /* prepare busn_res for return */
+ release_resource(busn_res);
+ busn_res->start -= n_size;
+
+ /* extend parent bus top*/
+ pci_bus_extend_top(bus, needed_size - n_size, parent_res);
+
+ *p = parent_res;
+
+ return ret;
+}
+
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
--
1.7.7

2012-02-28 02:13:38

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 14/18] PCI: kill pci_fixup_parent_subordinate_busnr()

Now we can safely extend parent top and shrink them according iobusn_resource tree.

Don't need that any more.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 32 --------------------------------
1 files changed, 0 insertions(+), 32 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 85266e6..2aee87b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -632,22 +632,6 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de
return child;
}

-static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
-{
- struct pci_bus *parent = child->parent;
-
- /* Attempts to fix that up are really dangerous unless
- we're going to re-assign all bus numbers. */
- if (!pcibios_assign_all_busses())
- return;
-
- while (parent->parent && parent->subordinate < max) {
- parent->subordinate = max;
- pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max);
- parent = parent->parent;
- }
-}
-
static void __devinit pci_bus_update_top(struct pci_bus *parent,
long size, struct resource *parent_res)
{
@@ -983,23 +967,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,

if (!is_cardbus) {
child->bridge_ctl = bctl;
- /*
- * Adjust subordinate busnr in parent buses.
- * We do this before scanning for children because
- * some devices may not be detected if the bios
- * was lazy.
- */
- pci_fixup_parent_subordinate_busnr(child, max);
- /* Now we can scan all subordinate buses... */
max = pci_scan_child_bus(child);
- /*
- * now fix it up again since we have found
- * the real value of max.
- */
- pci_fixup_parent_subordinate_busnr(child, max);
-
- } else {
- pci_fixup_parent_subordinate_busnr(child, max);
}
/*
* Set the subordinate bus number to its real value.
--
1.7.7

2012-02-28 02:11:23

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 05/18] PCI, x86: Register busn_res for root buses

update x86_pci_root_bus_resources() to get bus_max for non-acpi case.

update pci_acpi_scan_root_bus, and pci_scan_root_bus_on_node
to insert busn_res before scan child bus.
So could make root bus busn_res is kept the original large one.

Signed-off-by: Yinghai Lu <[email protected]>
---
arch/x86/include/asm/topology.h | 3 ++-
arch/x86/pci/acpi.c | 8 +++++---
arch/x86/pci/bus_numa.c | 9 ++++++++-
arch/x86/pci/common.c | 12 +++++++++---
4 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index b9676ae..8413481 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -172,7 +172,8 @@ static inline void arch_fix_phys_package_id(int num, u32 slot)
}

struct pci_bus;
-void x86_pci_root_bus_resources(int bus, struct list_head *resources);
+void x86_pci_root_bus_resources(int bus, int *bus_max,
+ struct list_head *resources);

#ifdef CONFIG_SMP
#define mc_capable() ((boot_cpu_data.x86_max_cores > 1) && \
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 7538fad..7bb327f 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -368,6 +368,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
struct pci_root_info *info = NULL;
int domain = root->segment;
int busnum = root->secondary.start;
+ int busmax = root->secondary.end;
LIST_HEAD(resources);
struct pci_bus *bus;
struct pci_sysdata *sd;
@@ -436,14 +437,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
add_resources(info, &resources);
else {
free_pci_root_info(info);
- x86_pci_root_bus_resources(busnum, &resources);
+ x86_pci_root_bus_resources(busnum, &busmax, &resources);
}

bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
&resources);
- if (bus)
+ if (bus) {
+ pci_bus_insert_busn_res(bus, busnum, busmax);
bus->subordinate = pci_scan_child_bus(bus);
- else
+ } else
pci_free_resource_list(&resources);

if (pci_use_crs) {
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index 7251011..91ce4dd 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -20,7 +20,8 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
return NULL;
}

-void x86_pci_root_bus_resources(int bus, struct list_head *resources)
+void x86_pci_root_bus_resources(int bus, int *bus_max,
+ struct list_head *resources)
{
struct pci_root_info *info = x86_find_pci_root_info(bus);
struct pci_root_res *root_res;
@@ -43,6 +44,8 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources)
root = &iomem_resource;
insert_resource(root, res);
}
+
+ *bus_max = info->bus_max;
return;

default_resources:
@@ -54,6 +57,10 @@ default_resources:
printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus);
pci_add_resource(resources, &ioport_resource);
pci_add_resource(resources, &iomem_resource);
+ if (!bus)
+ *bus_max = 0xff;
+ else if (!*bus_max)
+ *bus_max = bus;
}

struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 8e04ec5..5115606 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -623,6 +623,7 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
LIST_HEAD(resources);
struct pci_bus *bus = NULL;
struct pci_sysdata *sd;
+ int bus_max;

/*
* Allocate per-root-bus (not per bus) arch-specific data.
@@ -635,13 +636,18 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
return NULL;
}
sd->node = node;
- x86_pci_root_bus_resources(busno, &resources);
- printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno);
- bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
+ x86_pci_root_bus_resources(busno, &bus_max, &resources);
+ printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x-%02x)\n",
+ busno, bus_max);
+ bus = pci_create_root_bus(NULL, busno, &pci_root_ops, sd, &resources);
if (!bus) {
pci_free_resource_list(&resources);
kfree(sd);
+ return bus;
}
+ pci_bus_insert_busn_res(bus, busno, bus_max);
+ bus->subordinate = pci_scan_child_bus(bus);
+ pci_bus_add_devices(bus);

return bus;
}
--
1.7.7

2012-02-28 02:14:03

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 07/18] PCI, sparc: Register busn_res for root buses

Signed-off-by: Yinghai Lu <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
---
arch/sparc/kernel/pci.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 253e8ac..57ffe31 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -705,6 +705,7 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
}
bus->secondary = pbm->pci_first_busno;
bus->subordinate = pbm->pci_last_busno;
+ pci_bus_insert_busn_res(bus, pbm->pci_first_busno, pbm->pci_last_busno);

pci_of_scan_bus(pbm, node, bus);
pci_bus_add_devices(bus);
--
1.7.7

2012-02-28 02:14:24

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 10/18] PCI: Add pci_bus_extend/shrink_top()

extend or shrink bus and parent buses top (subordinate)

extended range is verified safe range, and stop at recorded parent_res.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 36 ++++++++++++++++++++++++++++++++++++
1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index e09f9b2..c03d3ff 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -648,6 +648,42 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
}
}

+static void __devinit pci_bus_update_top(struct pci_bus *parent,
+ long size, struct resource *parent_res)
+{
+ struct resource *res;
+
+ if (!size)
+ return;
+
+ while (parent) {
+ res = &parent->busn_res;
+ if (res == parent_res)
+ break;
+ res->end += size;
+ parent->subordinate += size;
+ pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS,
+ parent->subordinate);
+ dev_printk(KERN_DEBUG, &parent->dev,
+ "busn_res: %s %02lx to %pR\n",
+ (size > 0) ? "extended" : "shrunk",
+ abs(size), res);
+ parent = parent->parent;
+ }
+}
+
+static void __devinit pci_bus_extend_top(struct pci_bus *parent,
+ long size, struct resource *parent_res)
+{
+ pci_bus_update_top(parent, size, parent_res);
+}
+
+static void __devinit pci_bus_shrink_top(struct pci_bus *parent,
+ long size, struct resource *parent_res)
+{
+ pci_bus_update_top(parent, -size, parent_res);
+}
+
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
--
1.7.7

2012-02-28 02:11:20

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 01/18] x86, PCI: Merge pcibios_scan_root and pci_scan_bus_on_node

Those two almost the same.
Let pcibios_scan_root call pci_scan_bus_on_node instead.

Signed-off-by: Yinghai Lu <[email protected]>
---
arch/x86/pci/common.c | 27 ++++-----------------------
1 files changed, 4 insertions(+), 23 deletions(-)

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 323481e..8e04ec5 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -430,9 +430,7 @@ void __init dmi_check_pciprobe(void)

struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
- LIST_HEAD(resources);
struct pci_bus *bus = NULL;
- struct pci_sysdata *sd;

while ((bus = pci_find_next_bus(bus)) != NULL) {
if (bus->number == busnum) {
@@ -441,28 +439,10 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
}
}

- /* Allocate per-root-bus (not per bus) arch-specific data.
- * TODO: leak; this memory is never freed.
- * It's arguable whether it's worth the trouble to care.
- */
- sd = kzalloc(sizeof(*sd), GFP_KERNEL);
- if (!sd) {
- printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
- return NULL;
- }
-
- sd->node = get_mp_bus_to_node(busnum);
-
- printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
- x86_pci_root_bus_resources(busnum, &resources);
- bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
- if (!bus) {
- pci_free_resource_list(&resources);
- kfree(sd);
- }
-
- return bus;
+ return pci_scan_bus_on_node(busnum, &pci_root_ops,
+ get_mp_bus_to_node(busnum));
}
+
void __init pcibios_set_cache_line_size(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -656,6 +636,7 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
}
sd->node = node;
x86_pci_root_bus_resources(busno, &resources);
+ printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno);
bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
if (!bus) {
pci_free_resource_list(&resources);
--
1.7.7

2012-02-28 02:14:55

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 06/18] PCI, ia64: Register busn_res for root buses

Signed-off-by: Yinghai Lu <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Fenghua Yu <[email protected]>
Cc: [email protected]
---
arch/ia64/pci/pci.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index d1ce320..bc59e950 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -332,6 +332,7 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
struct acpi_device *device = root->device;
int domain = root->segment;
int bus = root->secondary.start;
+ int busmax = root->secondary.end;
struct pci_controller *controller;
unsigned int windows = 0;
struct pci_root_info info;
@@ -385,6 +386,7 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
return NULL;
}

+ pci_bus_insert_busn_res(pbus, busnum, busmax);
pbus->subordinate = pci_scan_child_bus(pbus);
return pbus;

--
1.7.7

2012-02-28 02:15:19

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 02/18] PCI: Add busn_res into struct pci_bus.

will use it to have bus number resource tree.

-v2: remove iobusn_resource

Signed-off-by: Yinghai Lu <[email protected]>
Cc: Andrew Morton <[email protected]>
---
include/linux/pci.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/linux/pci.h b/include/linux/pci.h
index d93d3ae..7c03852 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -419,6 +419,7 @@ struct pci_bus {
struct list_head slots; /* list of slots on this bus */
struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
struct list_head resources; /* address space routed to this bus */
+ struct resource busn_res; /* track registered bus num range */

struct pci_ops *ops; /* configuration access functions */
void *sysdata; /* hook for sys-specific extension */
--
1.7.7

2012-02-28 02:15:44

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 03/18] PCI: Add busn_res operation functions

will use them insert/update busn res in pci_bus

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 3 +++
2 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 675d7ed..3c0eecb 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1678,6 +1678,53 @@ err_out:
return NULL;
}

+void pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
+{
+ struct resource *res = &b->busn_res;
+ struct resource *parent_res;
+ int ret;
+
+ res->start = bus;
+ res->end = bus_max;
+ res->flags = IORESOURCE_BUS;
+
+ /* no parent for root bus' busn_res */
+ if (!pci_is_root_bus(b)) {
+ parent_res = &b->parent->busn_res;
+
+ ret = insert_resource(parent_res, res);
+
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: %pR %s inserted under %pR\n",
+ res, ret ? "can not be" : "is", parent_res);
+ } else
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: %pR for root bus\n",
+ res);
+}
+
+void pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max)
+{
+ struct resource *res = &b->busn_res;
+ struct resource old_res = *res;
+
+ res->end = bus_max;
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: %pR end updated to %pR\n",
+ &old_res, res);
+}
+
+void pci_bus_release_busn_res(struct pci_bus *b)
+{
+ struct resource *res = &b->busn_res;
+ int ret;
+
+ ret = release_resource(res);
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: %pR %s released\n",
+ res, ret ? "can not be" : "is");
+}
+
struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7c03852..e494759 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -669,6 +669,9 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
+void pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
+void pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
+void pci_bus_release_busn_res(struct pci_bus *b);
struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
--
1.7.7

2012-02-28 02:16:00

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 04/18] PCI: Add busn_res tracking in core

update pci_scan_root_bus, and pci_scan_bus to insert root bus busn into
iobusn_resource tree.

-v2: not add pci_scan_root_bus_max...

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 11 +++++++++--
drivers/pci/remove.c | 1 +
2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 3c0eecb..e09f9b2 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1734,7 +1734,9 @@ struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
if (!b)
return NULL;

+ pci_bus_insert_busn_res(b, bus, 255);
b->subordinate = pci_scan_child_bus(b);
+ pci_bus_update_busn_res_end(b, b->subordinate);
pci_bus_add_devices(b);
return b;
}
@@ -1750,9 +1752,11 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
- if (b)
+ if (b) {
+ pci_bus_insert_busn_res(b, bus, 255);
b->subordinate = pci_scan_child_bus(b);
- else
+ pci_bus_update_busn_res_end(b, b->subordinate);
+ } else
pci_free_resource_list(&resources);
return b;
}
@@ -1768,7 +1772,10 @@ struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
pci_add_resource(&resources, &iomem_resource);
b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
if (b) {
+ pci_bus_insert_busn_res(b, bus, 255);
b->subordinate = pci_scan_child_bus(b);
+ pci_bus_update_busn_res_end(b, b->subordinate);
+
pci_bus_add_devices(b);
} else {
pci_free_resource_list(&resources);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index fd77e2b..04a4861 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -68,6 +68,7 @@ void pci_remove_bus(struct pci_bus *pci_bus)

down_write(&pci_bus_sem);
list_del(&pci_bus->node);
+ pci_bus_release_busn_res(pci_bus);
up_write(&pci_bus_sem);
if (!pci_bus->is_added)
return;
--
1.7.7

2012-02-28 05:37:12

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH 08/18] PCI, powerpc: Register busn_res for root buses

On Mon, Feb 27, 2012 at 7:09 PM, Yinghai Lu <[email protected]> wrote:
> Signed-off-by: Yinghai Lu <[email protected]>
> Cc: Benjamin Herrenschmidt <[email protected]>
> Cc: Paul Mackerras <[email protected]>
> Cc: [email protected]
> ---
> ?arch/powerpc/kernel/pci-common.c | ? ?7 ++++++-
> ?1 files changed, 6 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> index 910b9de..ae5ae5f 100644
> --- a/arch/powerpc/kernel/pci-common.c
> +++ b/arch/powerpc/kernel/pci-common.c
> @@ -1660,6 +1660,8 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
> ? ? ? ?bus->secondary = hose->first_busno;
> ? ? ? ?hose->bus = bus;
>
> + ? ? ? pci_bus_insert_busn_res(bus, hose->first_busno, hose->last_busno);
> +
> ? ? ? ?/* Get probe mode and perform scan */
> ? ? ? ?mode = PCI_PROBE_NORMAL;
> ? ? ? ?if (node && ppc_md.pci_probe_mode)
> @@ -1670,8 +1672,11 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
> ? ? ? ? ? ? ? ?of_scan_bus(node, bus);
> ? ? ? ?}
>
> - ? ? ? if (mode == PCI_PROBE_NORMAL)
> + ? ? ? if (mode == PCI_PROBE_NORMAL) {
> + ? ? ? ? ? ? ? pci_bus_update_busn_res_end(bus, 255);
> ? ? ? ? ? ? ? ?hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
> + ? ? ? ? ? ? ? pci_bus_update_busn_res_end(bus, bus->subordinate);
> + ? ? ? }

There's a lot of powerpc code that does this:

bus_range = of_get_property(pcictrl, "bus-range", &len);
hose->first_busno = bus_range[0];
hose->last_busno = bus_range[1];

That *looks* like it is discovering the bus number aperture. Is it?
If it is, why are we using the largest bus number found by
pci_scan_child_bus() rather than "last_busno"?

Bjorn

2012-02-28 08:55:01

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: [PATCH 08/18] PCI, powerpc: Register busn_res for root buses

On Mon, 2012-02-27 at 22:36 -0700, Bjorn Helgaas wrote:
>
> There's a lot of powerpc code that does this:
>
> bus_range = of_get_property(pcictrl, "bus-range", &len);
> hose->first_busno = bus_range[0];
> hose->last_busno = bus_range[1];
>
> That *looks* like it is discovering the bus number aperture. Is it?
> If it is, why are we using the largest bus number found by
> pci_scan_child_bus() rather than "last_busno"?

We do that but we somewhat -also- rely on the core bumping it if it
needs to make room :-)

As I said, we are swimming in dirty waters between reverse engineered
stuff we don't know 100% and "designed" stuff.

I think we should have ways to more explicitely define what we want tho,
ie whether hose->last_busno is just what happens to be the "current" bus
number assigned by the firmware or the hard max. Maybe a pci flag ?

On the other hand some platforms (all the ppc4xx ones for example) set
the flag to reassign all busses ... but have limit on bus numbers simply
because they have a memory mapped only config space and we don't have
enough address space to ioremap it all on 32-bit.

We need to fix them to use a fixmap entry to do atomic on-demand mapping
of the config space and lift that restriction, but that isn't done yet.

So I think those patches will need really careful handling on our side.

Cheers,
Ben.

2012-02-28 10:03:47

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH -v8 0/23] PCI: allocate pci bus num range for unassigned bridge busn

On Mon, Feb 27, 2012 at 6:09 PM, Yinghai Lu <[email protected]> wrote:
>
> Set up iobusn_resource tree, and register bus number range to it.
> Later when need to find bus range, will try to allocate from the tree
>
> Need to test on arches other than x86. esp for ia64 and powerpc that support
> ?more than on peer root buses.

could be found at:
? ? ? ?git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git
for-pci-busn-alloc

update to v9, and will pass bus resource through resources list.

will not send to the LKML, please check for-pci-busn-alloc branch.

or you can browse them from
http://git.kernel.org/?p=linux/kernel/git/yinghai/linux-yinghai.git;a=shortlog;h=refs/heads/for-pci-busn-alloc

4d92227: PCI, pciehp: Remove not needed bus number range checking
edccefd: PCI: Double checking setting for bus register and bus struct.
d1d6372: pcmcia: remove workaround for fixing pci parent bus subordinate
5bb9418: PCI: Seperate child bus scanning to two passes overall
d0fd5ac: PCI: kill pci_fixup_parent_subordinate_busnr()
b86867f: PCI: Allocate bus range instead of use max blindly
8d0fbe4: PCI: Strict checking of valid range for bridge
8c26011: PCI: Probe safe range that we can use for unassigned bridge.
a7b217b: PCI: Add pci_bus_extend/shrink_top()
d8f54cd: PCI, parisc: Register busn_res for root buses
e02e198: PCI, powerpc: Register busn_res for root buses
d10c14b: PCI, sparc: Register busn_res for root buses
4977b59: PCI, ia64: Register busn_res for root buses
d169b44: x86, PCI: put busn resource in pci_root_info for no_crs path
c77a824: x86, PCI: put busn resource in pci_root_info for acpi path
1909435: PCI: add default res for pci_scan_bus
948a438: PCI: default busn_resource
5e2711b: PCI: checking busn_res in pci_scan_root_bus
c10e4a1: PCI: insert busn_res in pci_create_root_bus
fc176a9: PCI: release busn when removing bus
0eae1b6: PCI: Add busn_res operation functions
1e6215a: PCI: Add busn_res into struct pci_bus.
1f1fd3e: x86, PCI: Merge pcibios_scan_root and pci_scan_bus_on_node


>
> need to apply to top of pci/for-linus plus pci/linux-next plus
> ? ? ? ?[PATCH -v2] PCI: pci_host_bridge related cleanup
>
> -v2: according to Jesse, split to more small patches.
> -v3: address some request from Bjorn. like make use %pR for busn_res debug print
> ? ? ? ?out, and move the comment change with code change.
> -v4: fixes the problem about rescan that Bjorn found.
> -v5: add /proc/iobusn that is requested by Bjorn.
> ? ? remove old workaround from pciehp.
> ? ? add rescan_bridge for pci bridge in /sys
> -v6: remove global iobusn_resource, and every root bus's busn_res will be root
> ? ? of children buses' busn_res.
> ? ? pc cardbus change is tested by pcmcia maintainter.
> -v7: remove pci_scan_root_bus_max requested by Bjorn and Jesse.
> -v8: rebase on top other patches with arch/x86/pci/bus_numa.c changes
> ? ? also only include busn_res related changes.

arch/ia64/include/asm/pci.h | 1 +
arch/ia64/pci/pci.c | 5 +
arch/powerpc/include/asm/pci-bridge.h | 1 +
arch/powerpc/kernel/pci-common.c | 10 +-
arch/sparc/kernel/pci.c | 4 +
arch/sparc/kernel/pci_impl.h | 1 +
arch/x86/pci/acpi.c | 12 +-
arch/x86/pci/broadcom_bus.c | 4 +-
arch/x86/pci/bus_numa.c | 19 +-
arch/x86/pci/bus_numa.h | 3 +-
arch/x86/pci/common.c | 27 +--
drivers/parisc/dino.c | 5 +
drivers/parisc/lba_pci.c | 3 +
drivers/pci/hotplug/pciehp_pci.c | 12 +-
drivers/pci/probe.c | 458 +++++++++++++++++++++++++++------
drivers/pci/remove.c | 1 +
drivers/pcmcia/yenta_socket.c | 75 ------
include/linux/pci.h | 6 +
18 files changed, 441 insertions(+), 206 deletions(-)

2012-02-28 23:31:27

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH 08/18] PCI, powerpc: Register busn_res for root buses

On Mon, Feb 27, 2012 at 10:36 PM, Bjorn Helgaas <[email protected]> wrote:
> On Mon, Feb 27, 2012 at 7:09 PM, Yinghai Lu <[email protected]> wrote:
>> Signed-off-by: Yinghai Lu <[email protected]>
>> Cc: Benjamin Herrenschmidt <[email protected]>
>> Cc: Paul Mackerras <[email protected]>
>> Cc: [email protected]
>> ---
>> ?arch/powerpc/kernel/pci-common.c | ? ?7 ++++++-
>> ?1 files changed, 6 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
>> index 910b9de..ae5ae5f 100644
>> --- a/arch/powerpc/kernel/pci-common.c
>> +++ b/arch/powerpc/kernel/pci-common.c
>> @@ -1660,6 +1660,8 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
>> ? ? ? ?bus->secondary = hose->first_busno;
>> ? ? ? ?hose->bus = bus;
>>
>> + ? ? ? pci_bus_insert_busn_res(bus, hose->first_busno, hose->last_busno);
>> +
>> ? ? ? ?/* Get probe mode and perform scan */
>> ? ? ? ?mode = PCI_PROBE_NORMAL;
>> ? ? ? ?if (node && ppc_md.pci_probe_mode)
>> @@ -1670,8 +1672,11 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
>> ? ? ? ? ? ? ? ?of_scan_bus(node, bus);
>> ? ? ? ?}
>>
>> - ? ? ? if (mode == PCI_PROBE_NORMAL)
>> + ? ? ? if (mode == PCI_PROBE_NORMAL) {
>> + ? ? ? ? ? ? ? pci_bus_update_busn_res_end(bus, 255);
>> ? ? ? ? ? ? ? ?hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
>> + ? ? ? ? ? ? ? pci_bus_update_busn_res_end(bus, bus->subordinate);
>> + ? ? ? }
>
> There's a lot of powerpc code that does this:
>
> ? ?bus_range = of_get_property(pcictrl, "bus-range", &len);
> ? ?hose->first_busno = bus_range[0];
> ? ?hose->last_busno = bus_range[1];
>
> That *looks* like it is discovering the bus number aperture. ?Is it?
> If it is, why are we using the largest bus number found by
> pci_scan_child_bus() rather than "last_busno"?

Sorry, I missed the earlier hunk of the patch where you *do* use last_busno:

>> + ? ? ? pci_bus_insert_busn_res(bus, hose->first_busno, hose->last_busno);

I still think this part is wrong:

+ if (mode == PCI_PROBE_NORMAL) {
+ pci_bus_update_busn_res_end(bus, 255);
hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+ pci_bus_update_busn_res_end(bus, bus->subordinate);

I think there are two problems:

1) We can enumerate devices under the wrong PHB. Assume this:

PCI host bridge A to [bus 00]
pci 0000:00:01.0: PCI bridge
PCI host bridge B to [bus 01]
pci 0000:01:01.0: PCI endpoint

The P2P bridge at 00:01.0 has no devices below it, but of course we
can't tell that until we look behind it. To do that, we'll have to
assign a bus number, and since we forced the bus number aperture to
[bus 00-ff] instead of the correct [bus 00], we'll probably allocate
bus number 01 as the secondary bus. Then we'll generate a config
cycle for 01:01.0, which discovers a device. But we can't tell that
the cycle was actually claimed by host bridge B, not A. So now we
wrongly think that 01:01.0 is under A, so we can't handle its
resources correctly.

I think we should have failed when allocating a secondary bus number
for 00:01.0 and just skipped looking behind it.

2) We preclude hot-add in some cases. For example, if we scan this topology:

PCI host bridge C to [bus 00-7f]
pci 0000:00:01.0: PCI bridge to [bus 01]
pci 0000:01:01.0: PCI endpoint

we set the root bus's subordinate bus number to 01 (the highest bus
number we discovered), so we now think host bridge C leads only to
[bus 00-01]. Now let's remove 01:01.0 and plug in a card with a
bridge on it, e.g.,

pci 0000:01:01.0: PCI bridge to ...
pci 0000:xx:01.0: PCI endpoint

We can't allocate a bus number for 01:01.0's secondary bus because we
think we're out of space. But we're really not; the true bus number
aperture for C is [bus 00-7f], not [bus 00-01].

We may need mechanism to say "don't trust this info from the
firmware," but we should be able to figure out a way that doesn't
penalize platforms that do everything correctly. The current patch
breaks these scenarios even when the platform firmware is 100%
correct.

Bjorn

2012-02-28 23:42:04

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: [PATCH 08/18] PCI, powerpc: Register busn_res for root buses

On Tue, 2012-02-28 at 16:31 -0700, Bjorn Helgaas wrote:
> We may need mechanism to say "don't trust this info from the
> firmware," but we should be able to figure out a way that doesn't
> penalize platforms that do everything correctly. The current patch
> breaks these scenarios even when the platform firmware is 100%
> correct.

On the other hand, our firmwares tend not to be and the vast majority of
our platforms have separate bus number domains (In fact I'm not sure
whether we have one that actually splits bus numbers or not, maybe some
ancient Apple gear, I need to double check).

We did use to force renumbering on macs to avoid bus number collisions
between domains because of ancient X servers that didn't do domains
properly but I think we dropped that.

Cheers,
Ben.