aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/bus.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 7f0af0e9b826..172bf26e0680 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -64,6 +64,49 @@ void pci_bus_remove_resources(struct pci_bus *bus)
64 } 64 }
65} 65}
66 66
67/*
68 * Find the highest-address bus resource below the cursor "res". If the
69 * cursor is NULL, return the highest resource.
70 */
71static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
72 unsigned int type,
73 struct resource *res)
74{
75 struct resource *r, *prev = NULL;
76 int i;
77
78 pci_bus_for_each_resource(bus, r, i) {
79 if (!r)
80 continue;
81
82 if ((r->flags & IORESOURCE_TYPE_BITS) != type)
83 continue;
84
85 /* If this resource is at or past the cursor, skip it */
86 if (res) {
87 if (r == res)
88 continue;
89 if (r->end > res->end)
90 continue;
91 if (r->end == res->end && r->start > res->start)
92 continue;
93 }
94
95 if (!prev)
96 prev = r;
97
98 /*
99 * A small resource is higher than a large one that ends at
100 * the same address.
101 */
102 if (r->end > prev->end ||
103 (r->end == prev->end && r->start > prev->start))
104 prev = r;
105 }
106
107 return prev;
108}
109
67/** 110/**
68 * pci_bus_alloc_resource - allocate a resource from a parent bus 111 * pci_bus_alloc_resource - allocate a resource from a parent bus
69 * @bus: PCI bus 112 * @bus: PCI bus
@@ -89,9 +132,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
89 resource_size_t), 132 resource_size_t),
90 void *alignf_data) 133 void *alignf_data)
91{ 134{
92 int i, ret = -ENOMEM; 135 int ret = -ENOMEM;
93 struct resource *r; 136 struct resource *r;
94 resource_size_t max = -1; 137 resource_size_t max = -1;
138 unsigned int type = res->flags & IORESOURCE_TYPE_BITS;
95 139
96 type_mask |= IORESOURCE_IO | IORESOURCE_MEM; 140 type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
97 141
@@ -99,10 +143,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
99 if (!(res->flags & IORESOURCE_MEM_64)) 143 if (!(res->flags & IORESOURCE_MEM_64))
100 max = PCIBIOS_MAX_MEM_32; 144 max = PCIBIOS_MAX_MEM_32;
101 145
102 pci_bus_for_each_resource(bus, r, i) { 146 /* Look for space at highest addresses first */
103 if (!r) 147 r = pci_bus_find_resource_prev(bus, type, NULL);
104 continue; 148 for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) {
105
106 /* type_mask must match */ 149 /* type_mask must match */
107 if ((res->flags ^ r->flags) & type_mask) 150 if ((res->flags ^ r->flags) & type_mask)
108 continue; 151 continue;