summaryrefslogtreecommitdiffstats
path: root/pci-v2-4-4-PCI-allocate-bus-resources-from-the-top-down.patch
diff options
context:
space:
mode:
authorChuck Ebbert <cebbert@redhat.com>2010-09-23 21:40:59 -0400
committerChuck Ebbert <cebbert@redhat.com>2010-09-23 21:40:59 -0400
commit121bfe2c6a61630a4c03891824204e28ebdd235f (patch)
tree76bd390d2bd9e4614b2a0cd6e5bec1e258b25dda /pci-v2-4-4-PCI-allocate-bus-resources-from-the-top-down.patch
parent9e5584957c9cc106f9775d9fdc52a8d1300d749e (diff)
downloadkernel-121bfe2c6a61630a4c03891824204e28ebdd235f.tar.gz
kernel-121bfe2c6a61630a4c03891824204e28ebdd235f.tar.xz
kernel-121bfe2c6a61630a4c03891824204e28ebdd235f.zip
Add patches to fix problems with PCI _CRS
Diffstat (limited to 'pci-v2-4-4-PCI-allocate-bus-resources-from-the-top-down.patch')
-rw-r--r--pci-v2-4-4-PCI-allocate-bus-resources-from-the-top-down.patch80
1 files changed, 80 insertions, 0 deletions
diff --git a/pci-v2-4-4-PCI-allocate-bus-resources-from-the-top-down.patch b/pci-v2-4-4-PCI-allocate-bus-resources-from-the-top-down.patch
new file mode 100644
index 000000000..c1412b5bd
--- /dev/null
+++ b/pci-v2-4-4-PCI-allocate-bus-resources-from-the-top-down.patch
@@ -0,0 +1,80 @@
+diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
+index 7f0af0e..172bf26 100644
+--- a/drivers/pci/bus.c
++++ b/drivers/pci/bus.c
+@@ -64,6 +64,49 @@ void pci_bus_remove_resources(struct pci_bus *bus)
+ }
+ }
+
++/*
++ * Find the highest-address bus resource below the cursor "res". If the
++ * cursor is NULL, return the highest resource.
++ */
++static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
++ unsigned int type,
++ struct resource *res)
++{
++ struct resource *r, *prev = NULL;
++ int i;
++
++ pci_bus_for_each_resource(bus, r, i) {
++ if (!r)
++ continue;
++
++ if ((r->flags & IORESOURCE_TYPE_BITS) != type)
++ continue;
++
++ /* If this resource is at or past the cursor, skip it */
++ if (res) {
++ if (r == res)
++ continue;
++ if (r->end > res->end)
++ continue;
++ if (r->end == res->end && r->start > res->start)
++ continue;
++ }
++
++ if (!prev)
++ prev = r;
++
++ /*
++ * A small resource is higher than a large one that ends at
++ * the same address.
++ */
++ if (r->end > prev->end ||
++ (r->end == prev->end && r->start > prev->start))
++ prev = r;
++ }
++
++ return prev;
++}
++
+ /**
+ * pci_bus_alloc_resource - allocate a resource from a parent bus
+ * @bus: PCI bus
+@@ -89,9 +132,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+ resource_size_t),
+ void *alignf_data)
+ {
+- int i, ret = -ENOMEM;
++ int ret = -ENOMEM;
+ struct resource *r;
+ resource_size_t max = -1;
++ unsigned int type = res->flags & IORESOURCE_TYPE_BITS;
+
+ type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
+
+@@ -99,10 +143,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+ if (!(res->flags & IORESOURCE_MEM_64))
+ max = PCIBIOS_MAX_MEM_32;
+
+- pci_bus_for_each_resource(bus, r, i) {
+- if (!r)
+- continue;
+-
++ /* Look for space at highest addresses first */
++ r = pci_bus_find_resource_prev(bus, type, NULL);
++ for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) {
+ /* type_mask must match */
+ if ((res->flags ^ r->flags) & type_mask)
+ continue;