2012-02-28 22:29:00

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH -v9 00/24] PCI: allocate pci bus num range for unassigned bridge busn

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.
-v9: Add busn into pci_root_info, and add it to resources list and pass it
to pci_create_root_bus.

Thanks

Yinghai

Yinghai Lu (24):
x86, PCI: add print all root info for nocrs path
x86, PCI: Merge pcibios_scan_root and pci_scan_bus_on_node
PCI: Add busn_res into struct pci_bus.
PCI: Add busn_res operation functions
PCI: release busn when removing bus
PCI: insert busn_res in pci_create_root_bus
PCI: checking busn_res in pci_scan_root_bus
PCI: default busn_resource
PCI: add default res for pci_scan_bus
x86, PCI: put busn resource in pci_root_info for acpi path
x86, PCI: put busn resource in pci_root_info for no_crs path
PCI, ia64: Register busn_res for root buses
PCI, sparc: Register busn_res for root buses
PCI, powerpc: Register busn_res for root buses
PCI, parisc: Register busn_res for root buses
PCI: Add pci_bus_extend/shrink_top()
PCI: Probe safe range that we can use for unassigned bridge.
PCI: Strict checking of valid range for bridge
PCI: Allocate bus range instead of use max blindly
PCI: kill pci_fixup_parent_subordinate_busnr()
PCI: Seperate child bus scanning to two passes overall
pcmcia: remove workaround for fixing pci parent bus subordinate
PCI: Double checking setting for bus register and bus struct.
PCI, pciehp: Remove not needed bus number range checking

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 | 17 +-
arch/x86/pci/amd_bus.c | 2 +-
arch/x86/pci/broadcom_bus.c | 4 +-
arch/x86/pci/bus_numa.c | 27 ++-
arch/x86/pci/bus_numa.h | 4 +-
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 +
19 files changed, 454 insertions(+), 209 deletions(-)

--
1.7.7


2012-02-28 22:08:29

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 06/24] PCI: insert busn_res in pci_create_root_bus

that busn_res is from resources list

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

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ed82369..25a7ef8 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1649,7 +1649,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
list_move_tail(&window->list, &bridge->windows);
res = window->res;
offset = window->offset;
- pci_bus_add_resource(b, res, 0);
+ if (res->flags & IORESOURCE_BUS)
+ pci_bus_insert_busn_res(b, res->start, res->end);
+ else
+ pci_bus_add_resource(b, res, 0);
if (offset) {
if (resource_type(res) == IORESOURCE_IO)
fmt = " (bus address [%#06llx-%#06llx])";
--
1.7.7

2012-02-28 22:08:34

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 07/24] PCI: checking busn_res in pci_scan_root_bus

some calling may not have end decided yet, and may not pass busn_res in
resources list.

try to do insert big one and shrink.

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

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 25a7ef8..6f3bdbc 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1735,12 +1735,34 @@ struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
struct pci_bus *b;
+ struct pci_host_bridge_window *window, *n;
+ struct resource *res;
+ bool found;
+
+ list_for_each_entry_safe(window, n, resources, list) {
+ res = window->res;
+ if (res->flags & IORESOURCE_BUS) {
+ found = true;
+ break;
+ }
+ }

b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
if (!b)
return NULL;

+ if (!found) {
+ dev_info(&b->dev,
+ "No busn resource found for root bus, will use [%02x, ff]\n",
+ bus);
+ pci_bus_insert_busn_res(b, bus, 255);
+ }
+
b->subordinate = pci_scan_child_bus(b);
+
+ if (!found)
+ pci_bus_update_busn_res_end(b, b->subordinate);
+
pci_bus_add_devices(b);
return b;
}
--
1.7.7

2012-02-28 22:08:39

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 16/24] 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 1c07aba..96259f8 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -655,6 +655,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 22:08:47

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 14/24] 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/include/asm/pci-bridge.h | 1 +
arch/powerpc/kernel/pci-common.c | 10 +++++++++-
2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 5d48765..11cebf0 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -30,6 +30,7 @@ struct pci_controller {
int first_busno;
int last_busno;
int self_busno;
+ struct resource busn;

void __iomem *io_base_virt;
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 910b9de..ee8c0c9 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1648,6 +1648,11 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
/* Wire up PHB bus resources */
pcibios_setup_phb_resources(hose, &resources);

+ hose->busn.start = hose->first_busno;
+ hose->busn.end = hose->last_busno;
+ hose->busn.flags = IORESOURCE_BUS;
+ pci_add_resource(&resources, &hose->busn);
+
/* Create an empty bus for the toplevel */
bus = pci_create_root_bus(hose->parent, hose->first_busno,
hose->ops, hose, &resources);
@@ -1670,8 +1675,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 22:08:56

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 22/24] 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 22:09:08

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 15/24] 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 | 5 +++++
drivers/parisc/lba_pci.c | 3 +++
2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 0610e91..def94af 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -984,6 +984,10 @@ static int __init dino_probe(struct parisc_device *dev)
if (dino_dev->hba.gmmio_space.flags)
pci_add_resource(&resources, &dino_dev->hba.gmmio_space);

+ dino_dev->hba.bus_num.start = dino_current_bus;
+ dino_dev->hba.bus_num.end = 255;
+ dino_dev->hba.bus_num.flags |= IORESOURCE_BUS;
+ pci_add_resource(&resources, &dino_dev->hba.bus_num);
/*
** It's not used to avoid chicken/egg problems
** with configuration accessor functions.
@@ -999,6 +1003,7 @@ static int __init dino_probe(struct parisc_device *dev)
return 0;
}

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

/* This code *depends* on scanning being single threaded
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index e885764..df1e9f9 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1503,6 +1503,9 @@ lba_driver_probe(struct parisc_device *dev)
if (lba_dev->hba.gmmio_space.flags)
pci_add_resource(&resources, &lba_dev->hba.gmmio_space);

+ lba_dev->hba.bus_num.flags |= IORESOURCE_BUS;
+ pci_add_resource(&resources, &lba_dev->hba.bus_num);
+
dev->dev.platform_data = lba_dev;
lba_bus = lba_dev->hba.hba_bus =
pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start,
--
1.7.7

2012-02-28 22:09:32

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 05/24] PCI: release busn when removing bus

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

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 22:09:44

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 19/24] 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 5c031f0..f22a209 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -839,10 +839,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;
@@ -859,10 +860,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) */
@@ -895,6 +902,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);
@@ -907,6 +916,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
@@ -923,20 +937,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.
@@ -967,43 +1004,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 22:09:56

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 10/24] x86, PCI: put busn resource in pci_root_info for acpi path

will put it in resources list and pass it for create_root_bus

-v2: still have busn setting when no host bridge window setting from ACPI.

Signed-off-by: Yinghai Lu <[email protected]>
---
arch/x86/pci/acpi.c | 17 ++++++++++++-----
1 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 7538fad..2eafc2a 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -12,7 +12,7 @@ struct pci_root_info {
char name[16];
unsigned int res_num;
struct resource *res;
- int busnum;
+ struct resource busn;
};

static bool pci_use_crs = true;
@@ -282,6 +282,9 @@ static void add_resources(struct pci_root_info *info,
int i;
struct resource *res, *root, *conflict;

+ if (info->busn.flags & IORESOURCE_BUS)
+ pci_add_resource(resources, &info->busn);
+
coalesce_windows(info, IORESOURCE_MEM);
coalesce_windows(info, IORESOURCE_IO);

@@ -339,11 +342,16 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)

static void
probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
- int busnum, int domain)
+ int busnum, int busmax, int domain)
{
size_t size;

+ sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
info->bridge = device;
+ info->busn.start = busnum;
+ info->busn.end = busmax;
+ info->busn.flags = IORESOURCE_BUS;
+
info->res_num = 0;
acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
info);
@@ -356,8 +364,6 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
if (!info->res)
return;

- sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
-
acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
info);
}
@@ -368,6 +374,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;
@@ -426,7 +433,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
kfree(info);
kfree(sd);
} else {
- probe_pci_root_info(info, device, busnum, domain);
+ probe_pci_root_info(info, device, busnum, busmax, domain);

/*
* _CRS with no apertures is normal, so only fall back to
--
1.7.7

2012-02-28 22:10:38

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 13/24] 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 | 4 ++++
arch/sparc/kernel/pci_impl.h | 1 +
2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 253e8ac..1687fed 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -695,6 +695,10 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
pbm->io_space.start);
pci_add_resource_offset(&resources, &pbm->mem_space,
pbm->mem_space.start);
+ pbm->busn.start = pbm->pci_first_busno;
+ pbm->busn.end = pbm->pci_last_busn;
+ pbm->busn.flags = IORESOURCE_BUS;
+ pci_add_resource(&resources, &pbm->busn);
bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
pbm, &resources);
if (!bus) {
diff --git a/arch/sparc/kernel/pci_impl.h b/arch/sparc/kernel/pci_impl.h
index 6beb60d..918a203 100644
--- a/arch/sparc/kernel/pci_impl.h
+++ b/arch/sparc/kernel/pci_impl.h
@@ -97,6 +97,7 @@ struct pci_pbm_info {
/* PBM I/O and Memory space resources. */
struct resource io_space;
struct resource mem_space;
+ struct resource busn;

/* Base of PCI Config space, can be per-PBM or shared. */
unsigned long config_space;
--
1.7.7

2012-02-28 22:10:36

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 12/24] 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/include/asm/pci.h | 1 +
arch/ia64/pci/pci.c | 5 +++++
2 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index b22e5f5..6e54220 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -94,6 +94,7 @@ struct pci_controller {

unsigned int windows;
struct pci_window *window;
+ struct resource busn;

void *platform_data;
};
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index d1ce320..b250f0f 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;
@@ -372,6 +373,10 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
acpi_walk_resources(device->handle, METHOD_NAME__CRS,
add_window, &info);
}
+ controller->busn.start = bus;
+ controller->busn.end = busmax;
+ conttoller->busn.flags = IORESOURCE_BUS;
+ pci_add_resource(&info.resources, &controller->busn);
/*
* See arch/x86/pci/acpi.c.
* The desired pci bus might already be scanned in a quirk. We
--
1.7.7

2012-02-28 22:11:10

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 23/24] 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 4a38ef4..67071b0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -850,6 +850,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 22:09:30

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 04/24] 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 | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 3 +++
2 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 675d7ed..ed82369 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1678,6 +1678,56 @@ 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;
+
+ if (!res->flags)
+ return;
+
+ 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 22:08:45

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 17/24] 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 96259f8..c540022 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -691,6 +691,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 22:11:57

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 20/24] 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 f22a209..ba51902 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -639,22 +639,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)
{
@@ -990,23 +974,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 22:08:32

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 01/24] x86, PCI: add print all root info for nocrs path

Signed-off-by: Yinghai Lu <[email protected]>
---
arch/x86/pci/amd_bus.c | 2 +-
arch/x86/pci/bus_numa.c | 8 ++++++++
arch/x86/pci/bus_numa.h | 1 +
3 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 0b6abbe..5f30a98 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -291,7 +291,7 @@ static int __init early_fill_mp_bus_info(void)
}
}

- print_pci_root_info(info, "bus:", true);
+ print_all_pci_root_info("ht link", true);

return 0;
}
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index 7251011..df0c552 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -94,6 +94,14 @@ void print_pci_root_info(struct pci_root_info *info, char *name, bool nodelink)
&root_res->res);
}

+void print_all_pci_root_info(char *name, bool nodelink)
+{
+ struct pci_root_info *info;
+
+ list_for_each_entry(info, pci_root_infos, list)
+ print_pci_root_info(info, name, nodelink);
+}
+
void __devinit update_res(struct pci_root_info *info, resource_size_t start,
resource_size_t end, unsigned long flags, int merge)
{
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
index d19ac93..deada6a 100644
--- a/arch/x86/pci/bus_numa.h
+++ b/arch/x86/pci/bus_numa.h
@@ -23,6 +23,7 @@ extern struct list_head pci_root_infos;
struct pci_root_info *alloc_pci_root_info(int bus_min, int bus_max,
int node, int link);
void print_pci_root_info(struct pci_root_info *info, char *name, bool nodelink);
+void print_all_pci_root_info(char *name, bool nodelink);
extern void update_res(struct pci_root_info *info, resource_size_t start,
resource_size_t end, unsigned long flags, int merge);
#endif
--
1.7.7

2012-02-28 22:12:43

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 11/24] x86, PCI: put busn resource in pci_root_info for no_crs path

will put it in resources list and pass it for create_root_bus

Signed-off-by: Yinghai Lu <[email protected]>
---
arch/x86/pci/broadcom_bus.c | 4 +---
arch/x86/pci/bus_numa.c | 19 +++++++++++--------
arch/x86/pci/bus_numa.h | 3 +--
3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c
index ec5c66f..1f7223b 100644
--- a/arch/x86/pci/broadcom_bus.c
+++ b/arch/x86/pci/broadcom_bus.c
@@ -27,13 +27,11 @@ static void __init cnb20le_res(u8 bus, u8 slot, u8 func)
u16 word1, word2;
u8 fbus, lbus;

- info = alloc_pci_root_info(0, 0, 0, 0);

/* read the PCI bus numbers */
fbus = read_pci_config_byte(bus, slot, func, 0x44);
lbus = read_pci_config_byte(bus, slot, func, 0x45);
- info->bus_min = fbus;
- info->bus_max = lbus;
+ info = alloc_pci_root_info(fbus, lbus, 0, 0);

/*
* Add the legacy IDE ports on bus 0
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index df0c552..543086f 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -14,7 +14,7 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
return NULL;

list_for_each_entry(info, &pci_root_infos, list)
- if (info->bus_min == bus)
+ if (info->busn.start == bus)
return info;

return NULL;
@@ -31,6 +31,8 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources)
printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n",
bus);

+ pci_add_resource(resources, &info->busn);
+
list_for_each_entry(root_res, &info->resources, list) {
struct resource *res;
struct resource *root;
@@ -54,6 +56,7 @@ 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);
+ pci_add_resource(resources, &busn_resource);
}

struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
@@ -67,8 +70,9 @@ struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
return info;

INIT_LIST_HEAD(&info->resources);
- info->bus_min = bus_min;
- info->bus_max = bus_max;
+ info->busn.start = bus_min;
+ info->busn.end = bus_max;
+ info->busn.flags = IORESOURCE_BUS;
info->node = node;
info->link = link;

@@ -80,14 +84,13 @@ struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
void print_pci_root_info(struct pci_root_info *info, char *name, bool nodelink)
{
struct pci_root_res *root_res;
- int busnum = info->bus_min;
+ int busnum = info->busn.start;

if (!nodelink)
- printk(KERN_DEBUG "%s: [%02x, %02x]\n", name,
- info->bus_min, info->bus_max);
+ printk(KERN_DEBUG "%s: %pR\n", name, &info->busn);
else
- printk(KERN_DEBUG "%s: [%02x, %02x] on node %x link %x\n", name,
- info->bus_min, info->bus_max, info->node, info->link);
+ printk(KERN_DEBUG "%s: %pR on node %x link %x\n", name,
+ &info->busn, info->node, info->link);

list_for_each_entry(root_res, &info->resources, list)
printk(KERN_DEBUG "%s: %02x %pR\n", name, busnum,
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
index deada6a..f9919c3 100644
--- a/arch/x86/pci/bus_numa.h
+++ b/arch/x86/pci/bus_numa.h
@@ -13,8 +13,7 @@ struct pci_root_info {
struct list_head list;
char name[12];
struct list_head resources;
- int bus_min;
- int bus_max;
+ struct resource busn;
int node;
int link;
};
--
1.7.7

2012-02-28 22:13:00

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 09/24] PCI: add default res for pci_scan_bus

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

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 1149109..1c07aba 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1784,6 +1784,7 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,

pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
+ pci_add_resource(&resources, &busn_resource);
b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
if (b)
b->subordinate = pci_scan_child_bus(b);
@@ -1801,6 +1802,7 @@ struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,

pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
+ pci_add_resource(&resources, &busn_resource);
b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
if (b) {
b->subordinate = pci_scan_child_bus(b);
--
1.7.7

2012-02-28 22:08:27

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 02/24] 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 22:26:09

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 03/24] PCI: Add busn_res into struct pci_bus.

will use it to have bus number resource tree.

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 22:29:26

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 08/24] PCI: default busn_resource

We need to put into the resources list

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

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6f3bdbc..1149109 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -15,6 +15,13 @@
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3

+struct resource busn_resource = {
+ .name = "PCI busn",
+ .start = 0,
+ .end = 255,
+ .flags = IORESOURCE_BUS,
+};
+
/* Ugh. Need to stop exporting this to modules. */
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index e494759..40606c1 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -368,6 +368,8 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
return (pdev->error_state != pci_channel_io_normal);
}

+extern struct resource busn_resource;
+
struct pci_host_bridge_window {
struct list_head list;
struct resource *res; /* host bridge aperture (CPU address) */
--
1.7.7

2012-02-28 22:29:41

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 21/24] 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 ba51902..4a38ef4 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -809,6 +809,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
@@ -865,11 +868,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,
@@ -890,7 +892,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)
@@ -1704,12 +1706,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)
@@ -1723,18 +1726,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
@@ -1743,7 +1744,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 22:30:08

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 24/24] 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 23:10:04

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 18/24] 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 c540022..5c031f0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -801,6 +801,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-29 00:02:08

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH 12/24] PCI, ia64: Register busn_res for root buses

On Tue, Feb 28, 2012 at 3:07 PM, Yinghai Lu <[email protected]> wrote:
> Signed-off-by: Yinghai Lu <[email protected]>
> Cc: Tony Luck <[email protected]>
> Cc: Fenghua Yu <[email protected]>
> Cc: [email protected]
> ---
> ?arch/ia64/include/asm/pci.h | ? ?1 +
> ?arch/ia64/pci/pci.c ? ? ? ? | ? ?5 +++++
> ?2 files changed, 6 insertions(+), 0 deletions(-)
>
> diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
> index b22e5f5..6e54220 100644
> --- a/arch/ia64/include/asm/pci.h
> +++ b/arch/ia64/include/asm/pci.h
> @@ -94,6 +94,7 @@ struct pci_controller {
>
> ? ? ? ?unsigned int windows;
> ? ? ? ?struct pci_window *window;
> + ? ? ? struct resource busn;

Why do you add a new struct resource here? Can't you just use the one
passed in from acpi_pci_root_add()?

>
> ? ? ? ?void *platform_data;
> ?};
> diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
> index d1ce320..b250f0f 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;
> @@ -372,6 +373,10 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
> ? ? ? ? ? ? ? ?acpi_walk_resources(device->handle, METHOD_NAME__CRS,
> ? ? ? ? ? ? ? ? ? ? ? ?add_window, &info);
> ? ? ? ?}
> + ? ? ? controller->busn.start = bus;
> + ? ? ? controller->busn.end = busmax;
> + ? ? ? conttoller->busn.flags = IORESOURCE_BUS;

Typo here - "conttoller" should be "controller".

> + ? ? ? pci_add_resource(&info.resources, &controller->busn);
> ? ? ? ?/*
> ? ? ? ? * See arch/x86/pci/acpi.c.
> ? ? ? ? * The desired pci bus might already be scanned in a quirk. We
> --
> 1.7.7
>

2012-02-29 00:12:12

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 12/24] PCI, ia64: Register busn_res for root buses

On Tue, Feb 28, 2012 at 4:01 PM, Bjorn Helgaas <[email protected]> wrote:
> On Tue, Feb 28, 2012 at 3:07 PM, Yinghai Lu <[email protected]> wrote:
>> Signed-off-by: Yinghai Lu <[email protected]>
>> Cc: Tony Luck <[email protected]>
>> Cc: Fenghua Yu <[email protected]>
>> Cc: [email protected]
>> ---
>> ?arch/ia64/include/asm/pci.h | ? ?1 +
>> ?arch/ia64/pci/pci.c ? ? ? ? | ? ?5 +++++
>> ?2 files changed, 6 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
>> index b22e5f5..6e54220 100644
>> --- a/arch/ia64/include/asm/pci.h
>> +++ b/arch/ia64/include/asm/pci.h
>> @@ -94,6 +94,7 @@ struct pci_controller {
>>
>> ? ? ? ?unsigned int windows;
>> ? ? ? ?struct pci_window *window;
>> + ? ? ? struct resource busn;
>
> Why do you add a new struct resource here? ?Can't you just use the one
> passed in from acpi_pci_root_add()?

not quite sure about the life cycle for that object.

>
>>
>> ? ? ? ?void *platform_data;
>> ?};
>> diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
>> index d1ce320..b250f0f 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;
>> @@ -372,6 +373,10 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
>> ? ? ? ? ? ? ? ?acpi_walk_resources(device->handle, METHOD_NAME__CRS,
>> ? ? ? ? ? ? ? ? ? ? ? ?add_window, &info);
>> ? ? ? ?}
>> + ? ? ? controller->busn.start = bus;
>> + ? ? ? controller->busn.end = busmax;
>> + ? ? ? conttoller->busn.flags = IORESOURCE_BUS;
>
> Typo here - "conttoller" should be "controller".

cool, sharp eyes.

>
>> + ? ? ? pci_add_resource(&info.resources, &controller->busn);
>> ? ? ? ?/*
>> ? ? ? ? * See arch/x86/pci/acpi.c.
>> ? ? ? ? * The desired pci bus might already be scanned in a quirk. We
>> --
>> 1.7.7
>>

2012-02-29 00:23:12

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH 12/24] PCI, ia64: Register busn_res for root buses

On Tue, Feb 28, 2012 at 5:12 PM, Yinghai Lu <[email protected]> wrote:
> On Tue, Feb 28, 2012 at 4:01 PM, Bjorn Helgaas <[email protected]> wrote:
>> On Tue, Feb 28, 2012 at 3:07 PM, Yinghai Lu <[email protected]> wrote:
>>> Signed-off-by: Yinghai Lu <[email protected]>
>>> Cc: Tony Luck <[email protected]>
>>> Cc: Fenghua Yu <[email protected]>
>>> Cc: [email protected]
>>> ---
>>> ?arch/ia64/include/asm/pci.h | ? ?1 +
>>> ?arch/ia64/pci/pci.c ? ? ? ? | ? ?5 +++++
>>> ?2 files changed, 6 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
>>> index b22e5f5..6e54220 100644
>>> --- a/arch/ia64/include/asm/pci.h
>>> +++ b/arch/ia64/include/asm/pci.h
>>> @@ -94,6 +94,7 @@ struct pci_controller {
>>>
>>> ? ? ? ?unsigned int windows;
>>> ? ? ? ?struct pci_window *window;
>>> + ? ? ? struct resource busn;
>>
>> Why do you add a new struct resource here? ?Can't you just use the one
>> passed in from acpi_pci_root_add()?
>
> not quite sure about the life cycle for that object.

The struct acpi_pci_root is allocated in acpi_pci_root_add() and freed
in acpi_pci_root_remove(), so it should be safe for PCI to use.

Same thing applies for x86, of course.

Bjorn

2012-02-29 04:26:51

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 12/24] PCI, ia64: Register busn_res for root buses

On Tue, Feb 28, 2012 at 4:22 PM, Bjorn Helgaas <[email protected]> wrote:
> On Tue, Feb 28, 2012 at 5:12 PM, Yinghai Lu <[email protected]> wrote:
>>>
>>> Why do you add a new struct resource here? ?Can't you just use the one
>>> passed in from acpi_pci_root_add()?
>>
>> not quite sure about the life cycle for that object.
>
> The struct acpi_pci_root is allocated in acpi_pci_root_add() and freed
> in acpi_pci_root_remove(), so it should be safe for PCI to use.

ok will change that for ia64.

>
> Same thing applies for x86, of course.

for x86, will have separate addon patch.

Thanks

Yinghai