summaryrefslogtreecommitdiff
path: root/arch/x86/pci
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/pci')
-rw-r--r--arch/x86/pci/acpi.c33
-rw-r--r--arch/x86/pci/bus_numa.c9
-rw-r--r--arch/x86/pci/bus_numa.h3
3 files changed, 34 insertions, 11 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index a2f8cdb8c1d5..959e548a7039 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -45,6 +45,20 @@ count_resource(struct acpi_resource *acpi_res, void *data)
return AE_OK;
}
+static int
+bus_has_transparent_bridge(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ u16 class = dev->class >> 8;
+
+ if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent)
+ return true;
+ }
+ return false;
+}
+
static void
align_resource(struct acpi_device *bridge, struct resource *res)
{
@@ -78,8 +92,12 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
acpi_status status;
unsigned long flags;
struct resource *root;
+ int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
u64 start, end;
+ if (bus_has_transparent_bridge(info->bus))
+ max_root_bus_resources -= 3;
+
status = resource_to_addr(acpi_res, &addr);
if (!ACPI_SUCCESS(status))
return AE_OK;
@@ -97,6 +115,15 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
start = addr.minimum + addr.translation_offset;
end = start + addr.address_length - 1;
+ if (info->res_num >= max_root_bus_resources) {
+ if (pci_probe & PCI_USE__CRS)
+ printk(KERN_WARNING "PCI: Failed to allocate "
+ "0x%lx-0x%lx from %s for %s due to _CRS "
+ "returning more than %d resource descriptors\n",
+ (unsigned long) start, (unsigned long) end,
+ root->name, info->name, max_root_bus_resources);
+ return AE_OK;
+ }
res = &info->res[info->res_num];
res->name = info->name;
@@ -116,7 +143,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
dev_err(&info->bridge->dev,
"can't allocate host bridge window %pR\n", res);
} else {
- pci_bus_add_resource(info->bus, res, 0);
+ info->bus->resource[info->res_num] = res;
info->res_num++;
if (addr.translation_offset)
dev_info(&info->bridge->dev, "host bridge window %pR "
@@ -137,9 +164,7 @@ get_current_resources(struct acpi_device *device, int busnum,
struct pci_root_info info;
size_t size;
- if (pci_probe & PCI_USE__CRS)
- pci_bus_remove_resources(bus);
- else
+ if (!(pci_probe & PCI_USE__CRS))
dev_info(&device->dev,
"ignoring host bridge windows from ACPI; "
"boot with \"pci=use_crs\" to use them\n");
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index 6999970ca753..f939d603adfa 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -12,12 +12,10 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
int i;
int j;
struct pci_root_info *info;
- struct pci_bus_resource *bus_res;
/* don't go for it if _CRS is used already */
- bus_res = list_first_entry(&b->resources, struct pci_bus_resource,
- list);
- if (bus_res->res != &ioport_resource)
+ if (b->resource[0] != &ioport_resource ||
+ b->resource[1] != &iomem_resource)
return;
if (!pci_root_num)
@@ -38,14 +36,13 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
b->number);
- pci_bus_remove_resources(b);
info = &pci_root_info[i];
for (j = 0; j < info->res_num; j++) {
struct resource *res;
struct resource *root;
res = &info->res[j];
- pci_bus_add_resource(b, res, 0);
+ b->resource[j] = res;
if (res->flags & IORESOURCE_IO)
root = &ioport_resource;
else
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
index 731b64ee8d84..adbc23fe82ac 100644
--- a/arch/x86/pci/bus_numa.h
+++ b/arch/x86/pci/bus_numa.h
@@ -2,7 +2,8 @@
/*
* sub bus (transparent) will use entres from 3 to store extra from
- * root, so need to make sure we have enough slot there.
+ * root, so need to make sure we have enough slot there, Should we
+ * increase PCI_BUS_NUM_RESOURCES?
*/
#define RES_NUM 16
struct pci_root_info {