OSDN Git Service

x86/ACPI: Correct maximum allowed _CRS returned resources and warn if exceeded
authorGary Hade <garyhade@us.ibm.com>
Wed, 27 May 2009 19:41:44 +0000 (12:41 -0700)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Tue, 16 Jun 2009 21:53:32 +0000 (14:53 -0700)
Issue a warning if _CRS returns too many resource descriptors to be
accommodated by the fixed size resource array instances.  If there is no
transparent bridge on the root bus "too many" is the
PCI_BUS_NUM_RESOURCES size of the resource array.  Otherwise, the last 3
slots of the resource array must be excluded making the maximum
(PCI_BUS_NUM_RESOURCES - 3).

The current code:
 - is silent when _CRS returns too many resource descriptors and
 - incorrectly allows use of the last 3 slots of the resource array
   for a root bus with a transparent bridge

Signed-off-by: Gary Hade <garyhade@us.ibm.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
arch/x86/pci/acpi.c

index 8d898e0..16c3fda 100644 (file)
@@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data)
        struct acpi_resource_address64 addr;
        acpi_status status;
 
-       if (info->res_num >= PCI_BUS_NUM_RESOURCES)
-               return AE_OK;
-
        status = resource_to_addr(acpi_res, &addr);
        if (ACPI_SUCCESS(status))
                info->res_num++;
        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 acpi_status
 setup_resource(struct acpi_resource *acpi_res, void *data)
 {
@@ -56,9 +67,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        acpi_status status;
        unsigned long flags;
        struct resource *root;
-
-       if (info->res_num >= PCI_BUS_NUM_RESOURCES)
-               return AE_OK;
+       int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
 
        status = resource_to_addr(acpi_res, &addr);
        if (!ACPI_SUCCESS(status))
@@ -82,6 +91,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        res->end = res->start + addr.address_length - 1;
        res->child = NULL;
 
+       if (bus_has_transparent_bridge(info->bus))
+               max_root_bus_resources -= 3;
+       if (info->res_num >= max_root_bus_resources) {
+               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) res->start,
+                       (unsigned long) res->end, root->name, info->name,
+                       max_root_bus_resources);
+               info->res_num++;
+               return AE_OK;
+       }
+
        if (insert_resource(root, res)) {
                printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
                        "from %s for %s\n", (unsigned long) res->start,