Commit f9cde5ff authored by Gary Hade's avatar Gary Hade Committed by Jesse Barnes

x86/ACPI: Correct maximum allowed _CRS returned resources and warn if exceeded

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: default avatarGary Hade <garyhade@us.ibm.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent ab7de999
...@@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data) ...@@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data)
struct acpi_resource_address64 addr; struct acpi_resource_address64 addr;
acpi_status status; acpi_status status;
if (info->res_num >= PCI_BUS_NUM_RESOURCES)
return AE_OK;
status = resource_to_addr(acpi_res, &addr); status = resource_to_addr(acpi_res, &addr);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
info->res_num++; info->res_num++;
return AE_OK; 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 static acpi_status
setup_resource(struct acpi_resource *acpi_res, void *data) setup_resource(struct acpi_resource *acpi_res, void *data)
{ {
...@@ -56,9 +67,7 @@ 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; acpi_status status;
unsigned long flags; unsigned long flags;
struct resource *root; struct resource *root;
int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
if (info->res_num >= PCI_BUS_NUM_RESOURCES)
return AE_OK;
status = resource_to_addr(acpi_res, &addr); status = resource_to_addr(acpi_res, &addr);
if (!ACPI_SUCCESS(status)) if (!ACPI_SUCCESS(status))
...@@ -82,6 +91,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data) ...@@ -82,6 +91,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
res->end = res->start + addr.address_length - 1; res->end = res->start + addr.address_length - 1;
res->child = NULL; 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)) { if (insert_resource(root, res)) {
printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx " printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
"from %s for %s\n", (unsigned long) res->start, "from %s for %s\n", (unsigned long) res->start,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment