* [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan
@ 2012-01-21 10:24 Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 1/3] PCI: Add iobusn_resource and insert root bus range to that tree Yinghai Lu
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Yinghai Lu @ 2012-01-21 10:24 UTC (permalink / raw)
To: Jesse Barnes
Cc: Bjorn Helgaas, Linus Torvalds, linux-pci, linux-kernel,
Yinghai Lu
2632ed3: PCI: kill pci_fixup_parent_subordinate_busnr()
5b951ec: PCI: Allocate bus range instead of use max blindly
b9459d8: PCI: Add iobusn_resource and insert root bus range to that tree.
set up iobusn_resource tree, and register bus number range it.
later when need to find bus range, will try to allocate from the tree
need to test on arches other than x86, to verify if root bus end finding
is right.
could be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-pci-busn-alloc
Thanks
Yinghai
arch/ia64/pci/pci.c | 9 +
arch/powerpc/kernel/pci-common.c | 12 ++-
arch/x86/include/asm/topology.h | 3 +-
arch/x86/pci/acpi.c | 15 ++-
arch/x86/pci/bus_numa.c | 8 +-
arch/x86/pci/common.c | 11 +-
drivers/parisc/dino.c | 9 +
drivers/parisc/lba_pci.c | 8 +
drivers/pci/probe.c | 298 +++++++++++++++++++++++++++++---------
drivers/pci/remove.c | 1 +
include/linux/ioport.h | 1 +
include/linux/pci.h | 5 +
kernel/resource.c | 8 +
13 files changed, 310 insertions(+), 78 deletions(-)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [RFC PATCH 1/3] PCI: Add iobusn_resource and insert root bus range to that tree.
2012-01-21 10:24 [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
@ 2012-01-21 10:24 ` Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 2/3] PCI: Allocate bus range instead of use max blindly Yinghai Lu
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Yinghai Lu @ 2012-01-21 10:24 UTC (permalink / raw)
To: Jesse Barnes
Cc: Bjorn Helgaas, Linus Torvalds, linux-pci, linux-kernel,
Yinghai Lu
now only root bus number range is in that tree.
later every bus will have extra busn_res, and linked them toghter to iobusn_resource.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
arch/ia64/pci/pci.c | 9 +++++++
arch/powerpc/kernel/pci-common.c | 12 ++++++++-
arch/x86/include/asm/topology.h | 3 +-
arch/x86/pci/acpi.c | 15 +++++++++--
arch/x86/pci/bus_numa.c | 8 +++++-
arch/x86/pci/common.c | 11 +++++---
drivers/parisc/dino.c | 9 +++++++
drivers/parisc/lba_pci.c | 8 ++++++
drivers/pci/probe.c | 49 ++++++++++++++++++++++++++++++++++---
drivers/pci/remove.c | 1 +
include/linux/ioport.h | 1 +
include/linux/pci.h | 5 ++++
kernel/resource.c | 8 ++++++
13 files changed, 125 insertions(+), 14 deletions(-)
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index f82f5d4..20c43cc 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -331,6 +331,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;
@@ -384,6 +385,14 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
return NULL;
}
+ /* init busn_res */
+ pbus->busn_res.start = (domain << 8) | busnum;
+ pbus->busn_res.end = (domain << 8) | busmax;
+ pbus->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &pbus->busn_res);
+ dev_printk(KERN_DEBUG, &pbus->dev, "busn_res: %06llx-%06llx inserted\n", (unsigned long long)pbus->busn_res.start, (unsigned long long)pbus->busn_res.end);
+
pbus->subordinate = pci_scan_child_bus(pbus);
return pbus;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index cce98d7..4146f11 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1731,6 +1731,13 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
}
bus->secondary = hose->first_busno;
hose->bus = bus;
+ /* init busn_res */
+ bus->busn_res.start = (pci_domain_nr(bus) << 8) | host->first_busno;
+ bus->busn_res.end = (pci_domain_nr(bus) << 8) | host->last_busno;
+ bus->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &bus->busn_res);
+ dev_printk(KERN_DEBUG, &bus->dev, "busn_res: %06llx-%06llx inserted\n", (unsigned long long)bus->busn_res.start, (unsigned long long)bus->busn_res.end);
/* Get probe mode and perform scan */
mode = PCI_PROBE_NORMAL;
@@ -1742,8 +1749,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) {
+ bus->busn_res.end = (pci_domain_nr(bus) << 8) | 255;
hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+ bus->busn_res.end = (pci_domain_nr(bus) << 8) | bus->subordinate;
+ }
/* Platform gets a chance to do some global fixups before
* we proceed to resource allocation
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index b9676ae..ad4060e 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 a312e76..1929c3f 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -348,6 +348,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
struct acpi_device *device = root->device;
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;
@@ -405,12 +406,20 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
} else {
get_current_resources(device, busnum, domain, &resources);
if (list_empty(&resources))
- 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) {
+ /* init busn_res */
+ bus->busn_res.start = (domain << 8) | busnum;
+ bus->busn_res.end = (domain << 8) | busmax;
+ bus->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &bus->busn_res);
+ dev_printk(KERN_DEBUG, &bus->dev, "busn_res: %06llx-%06llx inserted\n", (unsigned long long)bus->busn_res.start, (unsigned long long)bus->busn_res.end);
+
bus->subordinate = pci_scan_child_bus(bus);
- else
+ } else
pci_free_resource_list(&resources);
}
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index fd3f655..5213cd8 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -7,7 +7,8 @@
int pci_root_num;
struct pci_root_info pci_root_info[PCI_ROOT_NR];
-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)
{
int i;
int j;
@@ -28,6 +29,7 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources)
bus);
info = &pci_root_info[i];
+ *bus_max = info->bus_max;
for (j = 0; j < info->res_num; j++) {
struct resource *res;
struct resource *root;
@@ -51,6 +53,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;
}
void __devinit update_res(struct pci_root_info *info, resource_size_t start,
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 323481e..ce0aefc 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -433,6 +433,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
LIST_HEAD(resources);
struct pci_bus *bus = NULL;
struct pci_sysdata *sd;
+ int bus_max;
while ((bus = pci_find_next_bus(bus)) != NULL) {
if (bus->number == busnum) {
@@ -454,8 +455,9 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
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);
+ x86_pci_root_bus_resources(busnum, &bus_max, &resources);
+ bus = pci_scan_root_bus_max(NULL, busnum, bus_max, &pci_root_ops, sd,
+ &resources);
if (!bus) {
pci_free_resource_list(&resources);
kfree(sd);
@@ -643,6 +645,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.
@@ -655,8 +658,8 @@ 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);
- bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
+ x86_pci_root_bus_resources(busno, &bus_max, &resources);
+ bus = pci_scan_root_bus_max(NULL, busno, bus_max, ops, sd, &resources);
if (!bus) {
pci_free_resource_list(&resources);
kfree(sd);
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 7ff10c1..8959332 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -1014,7 +1014,16 @@ static int __init dino_probe(struct parisc_device *dev)
return 0;
}
+ /* init busn_res */
+ bus->busn_res.start = (pci_domain_nr(bus) << 8) | busnum;
+ bus->busn_res.end = (pci_domain_nr(bus) << 8) | 255;
+ bus->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &bus->busn_res);
+ dev_printk(KERN_DEBUG, &bus->dev, "busn_res: %06llx-%06llx inserted\n", (unsigned long long)bus->busn_res.start, (unsigned long long)bus->busn_res.end);
+
bus->subordinate = pci_scan_child_bus(bus);
+ bus->busn_res.end = (pci_domain_nr(bus) << 8) | 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 d5f3d75..7c2b60a 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1531,6 +1531,14 @@ lba_driver_probe(struct parisc_device *dev)
return 0;
}
+ /* init busn_res */
+ lba_bus->busn_res.start = (pci_domain_nr(lba_bus) << 8) | lba_dev->hba.bus_num.start;
+ lba_bus->busn_res.end = (pci_domain_nr(lba_bus) << 8) | lba_dev->hba.bus_num.end;
+ lba_bus->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &lba_bus->busn_res);
+ dev_printk(KERN_DEBUG, &lba_bus->dev, "busn_res: %06llx-%06llx inserted\n", (unsigned long long)lba_bus->busn_res.start, (unsigned long long)lba_bus->busn_res.end);
+
lba_bus->subordinate = pci_scan_child_bus(lba_bus);
/* This is in lieu of calling pci_assign_unassigned_resources() */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 7cc9e2f..3e08207 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1608,8 +1608,9 @@ err_out:
return NULL;
}
-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 * __devinit pci_scan_root_bus_max(struct device *parent, int bus,
+ int bus_max, struct pci_ops *ops, void *sysdata,
+ struct list_head *resources)
{
struct pci_bus *b;
@@ -1617,10 +1618,32 @@ struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
if (!b)
return NULL;
+ /* init busn_res */
+ b->busn_res.start = (pci_domain_nr(b) << 8) | bus;
+ b->busn_res.end = (pci_domain_nr(b) << 8) | bus_max;
+ b->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &b->busn_res);
+
b->subordinate = pci_scan_child_bus(b);
pci_bus_add_devices(b);
return b;
}
+EXPORT_SYMBOL(pci_scan_root_bus_max);
+
+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;
+
+ b = pci_scan_root_bus_max(parent, bus, 255, ops, sysdata, resources);
+
+ if (b)
+ b->busn_res.end = (pci_domain_nr(b) << 8) | b->subordinate;
+
+ return b;
+}
EXPORT_SYMBOL(pci_scan_root_bus);
/* Deprecated; use pci_scan_root_bus() instead */
@@ -1633,9 +1656,18 @@ 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) {
+ /* init busn_res */
+ b->busn_res.start = (pci_domain_nr(b) << 8) | bus;
+ b->busn_res.end = (pci_domain_nr(b) << 8) | 255;
+ b->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &b->busn_res);
+
b->subordinate = pci_scan_child_bus(b);
- else
+
+ b->busn_res.end = (pci_domain_nr(b) << 8) | b->subordinate;
+ } else
pci_free_resource_list(&resources);
return b;
}
@@ -1651,7 +1683,16 @@ 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) {
+ /* init busn_res */
+ b->busn_res.start = (pci_domain_nr(b) << 8) | bus;
+ b->busn_res.end = (pci_domain_nr(b) << 8) | 255;
+ b->busn_res.flags = IORESOURCE_BUS;
+
+ insert_resource(&iobusn_resource, &b->busn_res);
+
b->subordinate = pci_scan_child_bus(b);
+
+ b->busn_res.end = (pci_domain_nr(b) << 8) | 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 6def362..a4cbe0e 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);
+ release_resource(&pci_bus->busn_res);
up_write(&pci_bus_sem);
if (!pci_bus->is_added)
return;
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 9d57a71..c96781c 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -142,6 +142,7 @@ struct resource_list {
/* PC/ISA/whatever - the normal PC address spaces: IO and memory */
extern struct resource ioport_resource;
extern struct resource iomem_resource;
+extern struct resource iobusn_resource;
extern struct resource *request_resource_conflict(struct resource *root, struct resource *new);
extern int request_resource(struct resource *root, struct resource *new);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a16b1df..4598cf5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -420,6 +420,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 */
@@ -665,6 +666,10 @@ 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);
+struct pci_bus * __devinit pci_scan_root_bus_max(struct device *parent, int bus,
+ int busmax, struct pci_ops *ops,
+ void *sysdata,
+ struct list_head *resources);
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/kernel/resource.c b/kernel/resource.c
index 7640b3a..53b42f0 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -38,6 +38,14 @@ struct resource iomem_resource = {
};
EXPORT_SYMBOL(iomem_resource);
+struct resource iobusn_resource = {
+ .name = "PCI busn",
+ .start = 0,
+ .end = 0xffffff,
+ .flags = IORESOURCE_BUS,
+};
+EXPORT_SYMBOL(iobusn_resource);
+
/* constraints to be met while allocating resources */
struct resource_constraint {
resource_size_t min, max, align;
--
1.7.7
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH 2/3] PCI: Allocate bus range instead of use max blindly
2012-01-21 10:24 [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 1/3] PCI: Add iobusn_resource and insert root bus range to that tree Yinghai Lu
@ 2012-01-21 10:24 ` Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 3/3] PCI: kill pci_fixup_parent_subordinate_busnr() Yinghai Lu
2012-01-22 19:22 ` [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
3 siblings, 0 replies; 5+ messages in thread
From: Yinghai Lu @ 2012-01-21 10:24 UTC (permalink / raw)
To: Jesse Barnes
Cc: Bjorn Helgaas, Linus Torvalds, linux-pci, linux-kernel,
Yinghai Lu
every bus have extra busn_res, and linked them toghter to iobusn_resource.
when need to find usabled bus number range, try allocate from
iobusn_resource tree.
-v3: support extend buses top.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/probe.c | 220 ++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 184 insertions(+), 36 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 3e08207..e20fe45 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -624,6 +624,124 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
}
}
+static void __devinit pci_bus_extend_top(struct pci_bus *parent,
+ resource_size_t needed_size, struct resource *parent_res)
+{
+ while (parent) {
+ if (&parent->busn_res == parent_res)
+ break;
+ parent->busn_res.end += needed_size;
+ parent->subordinate += needed_size;
+ pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS,
+ parent->subordinate);
+ dev_printk(KERN_DEBUG, &parent->dev, "busn_res: %06llx-%06llx extended\n", (unsigned long long)parent->busn_res.start, (unsigned long long)parent->busn_res.end);
+ parent = parent->parent;
+ }
+}
+
+static void __devinit pci_bus_shrink_top(struct pci_bus *parent,
+ resource_size_t needed_size, struct resource *parent_res)
+{
+ while (parent) {
+ if (&parent->busn_res == parent_res)
+ break;
+ parent->busn_res.end -= needed_size;
+ parent->subordinate -= needed_size;
+ pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS,
+ parent->subordinate);
+ dev_printk(KERN_DEBUG, &parent->dev, "busn_res: %06llx-%06llx shrinked\n", (unsigned long long)parent->busn_res.start, (unsigned long long)parent->busn_res.end);
+ parent = parent->parent;
+ }
+}
+
+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;
+ resource_size_t tmp = bus->busn_res.end + 1;
+
+ parent_res = NULL;
+
+again:
+ /* find bigest range in bus->busn_res that we can use in the middle */
+ 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: %06llx-%06llx\n", (unsigned long long)bus->busn_res.start, (unsigned long long)bus->busn_res.end);
+ 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) {
+ /* release busn_res */
+ release_resource(busn_res);
+
+ return ret;
+ }
+ n_size--;
+ }
+
+ /*
+ * try extend the top of parent buss
+ * find out number below bus->busn_res, that we can use at first
+ */
+ ret = -ENOMEM;
+ 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: %06llx-%06llx near top \n", (unsigned long long)bus->busn_res.start, (unsigned long long)bus->busn_res.end);
+ while (n_size > 0) {
+ ret = allocate_resource(&bus->busn_res, busn_res, n_size,
+ bus->busn_res.end - n_size + 1, bus->busn_res.end,
+ 1, NULL, NULL);
+ if (ret == 0) {
+ /* release busn_res */
+ release_resource(busn_res);
+ break;
+ }
+ n_size--;
+ }
+
+ /* check if extend could cross domain boundary */
+ ret = -ENOMEM;
+ if ((bus->busn_res.end & 0xff) == 0xff)
+ goto reduce_needed_size;
+ if ((0x100 - (tmp & 0xff)) < (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, NULL, NULL);
+ if (ret == 0)
+ break;
+ parent = parent->parent;
+ }
+
+reduce_needed_size:
+ if (ret != 0) {
+ needed_size--;
+ if (!needed_size)
+ return ret;
+
+ goto again;
+ }
+
+ parent_res = busn_res->parent;
+ /* release busn_res */
+ release_resource(busn_res);
+ busn_res->start -= n_size;
+
+ /* extend */
+ 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
@@ -638,10 +756,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;
@@ -653,11 +772,30 @@ 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) {
+ struct resource busn_res;
+ int ret;
+
+ memset(&busn_res, 0, sizeof(struct resource));
+ dev_printk(KERN_DEBUG, &dev->dev, "try to check if busn %02x-%02x is in busn_res: %06llx-%06llx \n", secondary, subordinate, (unsigned long long)bus->busn_res.start, (unsigned long long)bus->busn_res.end);
+ ret = allocate_resource(&bus->busn_res, &busn_res,
+ (subordinate - secondary + 1),
+ (pci_domain_nr(bus)<<8) | secondary,
+ (pci_domain_nr(bus)<<8) | subordinate,
+ 1, NULL, NULL);
+ if (ret)
+ broken = 1;
+ else
+ release_resource(&busn_res);
}
+ if (broken)
+ dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
+
/* Disable MasterAbortMode during probing to avoid reporting
of bus errors (in some architectures) */
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
@@ -689,6 +827,12 @@ 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;
+
+ child->busn_res.start = (pci_domain_nr(bus) << 8) | secondary;
+ child->busn_res.end = (pci_domain_nr(bus) << 8) | subordinate;
+ child->busn_res.flags = IORESOURCE_BUS | IORESOURCE_BUSY;
+ dev_printk(KERN_DEBUG, &child->dev, "busn_res: %06llx-%06llx inserted\n", (unsigned long long)child->busn_res.start, (unsigned long long)child->busn_res.end);
+ insert_resource(&bus->busn_res, &child->busn_res);
}
cmax = pci_scan_child_bus(child);
@@ -701,6 +845,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.
*/
+ resource_size_t 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
@@ -717,20 +866,31 @@ 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;
- }
+ 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 & 0xff);
+ if (!child)
+ goto out;
+
+ child->subordinate = busn_res.end & 0xff;
+ child->busn_res.start = busn_res.start;
+ child->busn_res.end = busn_res.end;
+ child->busn_res.flags = IORESOURCE_BUS | IORESOURCE_BUSY;
+ dev_printk(KERN_DEBUG, &child->dev, "busn_res: %06llx-%06llx inserted\n", child->busn_res.start, child->busn_res.end);
+ insert_resource(&bus->busn_res, &child->busn_res);
+
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.
@@ -761,43 +921,31 @@ 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);
+ child->busn_res.end &= ~0xff;
+ child->busn_res.end |= max;
+ dev_printk(KERN_DEBUG, &child->dev, "busn_res: %06llx-%06llx adjusted\n", (unsigned long long)child->busn_res.start, (unsigned long long)child->busn_res.end);
+
+ /* 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
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH 3/3] PCI: kill pci_fixup_parent_subordinate_busnr()
2012-01-21 10:24 [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 1/3] PCI: Add iobusn_resource and insert root bus range to that tree Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 2/3] PCI: Allocate bus range instead of use max blindly Yinghai Lu
@ 2012-01-21 10:24 ` Yinghai Lu
2012-01-22 19:22 ` [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
3 siblings, 0 replies; 5+ messages in thread
From: Yinghai Lu @ 2012-01-21 10:24 UTC (permalink / raw)
To: Jesse Barnes
Cc: Bjorn Helgaas, Linus Torvalds, linux-pci, linux-kernel,
Yinghai Lu
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 <yinghai@kernel.org>
---
drivers/pci/probe.c | 45 +++++++++------------------------------------
1 files changed, 9 insertions(+), 36 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index e20fe45..85cb6d0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -608,22 +608,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_extend_top(struct pci_bus *parent,
resource_size_t needed_size, struct resource *parent_res)
{
@@ -866,6 +850,13 @@ 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);
+ /*
+ * 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);
@@ -907,29 +898,11 @@ 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 {
- /*
- * For CardBus bridges, we leave 4 bus numbers
- * as cards with a PCI-to-PCI bridge can be
- * inserted later.
- */
- pci_fixup_parent_subordinate_busnr(child, max);
}
+
/*
* Set the subordinate bus number to its real value.
*/
--
1.7.7
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan
2012-01-21 10:24 [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
` (2 preceding siblings ...)
2012-01-21 10:24 ` [RFC PATCH 3/3] PCI: kill pci_fixup_parent_subordinate_busnr() Yinghai Lu
@ 2012-01-22 19:22 ` Yinghai Lu
3 siblings, 0 replies; 5+ messages in thread
From: Yinghai Lu @ 2012-01-22 19:22 UTC (permalink / raw)
To: Jesse Barnes
Cc: Bjorn Helgaas, Linus Torvalds, linux-pci, linux-kernel,
Yinghai Lu
On Sat, Jan 21, 2012 at 2:24 AM, Yinghai Lu <yinghai@kernel.org> wrote:
>
> could be found at:
> git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-pci-busn-alloc
>
>
> arch/ia64/pci/pci.c | 9 +
> arch/powerpc/kernel/pci-common.c | 12 ++-
> arch/x86/include/asm/topology.h | 3 +-
> arch/x86/pci/acpi.c | 15 ++-
> arch/x86/pci/bus_numa.c | 8 +-
> arch/x86/pci/common.c | 11 +-
> drivers/parisc/dino.c | 9 +
> drivers/parisc/lba_pci.c | 8 +
> drivers/pci/probe.c | 298 +++++++++++++++++++++++++++++---------
> drivers/pci/remove.c | 1 +
> include/linux/ioport.h | 1 +
> include/linux/pci.h | 5 +
> kernel/resource.c | 8 +
> 13 files changed, 310 insertions(+), 78 deletions(-)
update the branch to have less change to other arch and add one patch
to separate
pci_scan_child_bus to two passes.
5cb2147: PCI: Seperate child bus scanning to two passes overall
0cfebdb: PCI: kill pci_fixup_parent_subordinate_busnr()
cd03e86: PCI: Allocate bus range instead of use max blindly
e3edd5b: PCI: Add iobusn_resource and insert root bus range to that tree.
arch/ia64/pci/pci.c | 2 +
arch/powerpc/kernel/pci-common.c | 7 +-
arch/x86/include/asm/topology.h | 3 +-
arch/x86/pci/acpi.c | 8 +-
arch/x86/pci/bus_numa.c | 8 +-
arch/x86/pci/common.c | 11 +-
drivers/parisc/dino.c | 2 +
drivers/parisc/lba_pci.c | 3 +
drivers/pci/probe.c | 427 ++++++++++++++++++++++++++++++--------
drivers/pci/remove.c | 1 +
include/linux/ioport.h | 1 +
include/linux/pci.h | 8 +
kernel/resource.c | 8 +
13 files changed, 395 insertions(+), 94 deletions(-)
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-01-22 19:22 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-21 10:24 [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 1/3] PCI: Add iobusn_resource and insert root bus range to that tree Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 2/3] PCI: Allocate bus range instead of use max blindly Yinghai Lu
2012-01-21 10:24 ` [RFC PATCH 3/3] PCI: kill pci_fixup_parent_subordinate_busnr() Yinghai Lu
2012-01-22 19:22 ` [RFC PATCH 0/3] PCI: allocate pci bus num range for bridge scan Yinghai Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).