* [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