aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/setup-bus.c
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2009-04-23 23:48:32 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-06-11 15:04:06 -0400
commit1f82de10d6b1d845155363c895c552e61b36b51a (patch)
tree3e93b9d1c97ae48509133fbbec9c81b4823816a5 /drivers/pci/setup-bus.c
parent67b5db6502ddd27d65dea43bf036abbd82d0dfc9 (diff)
PCI/x86: don't assume prefetchable ranges are 64bit
We should not assign 64bit ranges to PCI devices that only take 32bit prefetchable addresses. Try to set IORESOURCE_MEM_64 in 64bit resource of pci_device/pci_bridge and make the bus resource only have that bit set when all devices under it support 64bit prefetchable memory. Use that flag to allocate resources from that range. Reported-by: Yannick <yannick.roehlly@free.fr> Reviewed-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r--drivers/pci/setup-bus.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index a00f85471b6e..e1c360a5b0db 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -143,6 +143,7 @@ static void pci_setup_bridge(struct pci_bus *bus)
143 struct pci_dev *bridge = bus->self; 143 struct pci_dev *bridge = bus->self;
144 struct pci_bus_region region; 144 struct pci_bus_region region;
145 u32 l, bu, lu, io_upper16; 145 u32 l, bu, lu, io_upper16;
146 int pref_mem64;
146 147
147 if (pci_is_enabled(bridge)) 148 if (pci_is_enabled(bridge))
148 return; 149 return;
@@ -198,16 +199,22 @@ static void pci_setup_bridge(struct pci_bus *bus)
198 pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); 199 pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
199 200
200 /* Set up PREF base/limit. */ 201 /* Set up PREF base/limit. */
202 pref_mem64 = 0;
201 bu = lu = 0; 203 bu = lu = 0;
202 pcibios_resource_to_bus(bridge, &region, bus->resource[2]); 204 pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
203 if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { 205 if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
206 int width = 8;
204 l = (region.start >> 16) & 0xfff0; 207 l = (region.start >> 16) & 0xfff0;
205 l |= region.end & 0xfff00000; 208 l |= region.end & 0xfff00000;
206 bu = upper_32_bits(region.start); 209 if (bus->resource[2]->flags & IORESOURCE_MEM_64) {
207 lu = upper_32_bits(region.end); 210 pref_mem64 = 1;
208 dev_info(&bridge->dev, " PREFETCH window: %#016llx-%#016llx\n", 211 bu = upper_32_bits(region.start);
209 (unsigned long long)region.start, 212 lu = upper_32_bits(region.end);
210 (unsigned long long)region.end); 213 width = 16;
214 }
215 dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n",
216 width, (unsigned long long)region.start,
217 width, (unsigned long long)region.end);
211 } 218 }
212 else { 219 else {
213 l = 0x0000fff0; 220 l = 0x0000fff0;
@@ -215,9 +222,11 @@ static void pci_setup_bridge(struct pci_bus *bus)
215 } 222 }
216 pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); 223 pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
217 224
218 /* Set the upper 32 bits of PREF base & limit. */ 225 if (pref_mem64) {
219 pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); 226 /* Set the upper 32 bits of PREF base & limit. */
220 pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); 227 pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
228 pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
229 }
221 230
222 pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); 231 pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
223} 232}
@@ -255,8 +264,25 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
255 pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); 264 pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
256 pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); 265 pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
257 } 266 }
258 if (pmem) 267 if (pmem) {
259 b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; 268 b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
269 if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64)
270 b_res[2].flags |= IORESOURCE_MEM_64;
271 }
272
273 /* double check if bridge does support 64 bit pref */
274 if (b_res[2].flags & IORESOURCE_MEM_64) {
275 u32 mem_base_hi, tmp;
276 pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32,
277 &mem_base_hi);
278 pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
279 0xffffffff);
280 pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
281 if (!tmp)
282 b_res[2].flags &= ~IORESOURCE_MEM_64;
283 pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
284 mem_base_hi);
285 }
260} 286}
261 287
262/* Helper function for sizing routines: find first available 288/* Helper function for sizing routines: find first available
@@ -336,6 +362,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
336 resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ 362 resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
337 int order, max_order; 363 int order, max_order;
338 struct resource *b_res = find_free_bus_resource(bus, type); 364 struct resource *b_res = find_free_bus_resource(bus, type);
365 unsigned int mem64_mask = 0;
339 366
340 if (!b_res) 367 if (!b_res)
341 return 0; 368 return 0;
@@ -344,9 +371,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
344 max_order = 0; 371 max_order = 0;
345 size = 0; 372 size = 0;
346 373
374 mem64_mask = b_res->flags & IORESOURCE_MEM_64;
375 b_res->flags &= ~IORESOURCE_MEM_64;
376
347 list_for_each_entry(dev, &bus->devices, bus_list) { 377 list_for_each_entry(dev, &bus->devices, bus_list) {
348 int i; 378 int i;
349 379
350 for (i = 0; i < PCI_NUM_RESOURCES; i++) { 380 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
351 struct resource *r = &dev->resource[i]; 381 struct resource *r = &dev->resource[i];
352 resource_size_t r_size; 382 resource_size_t r_size;
@@ -372,6 +402,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
372 aligns[order] += align; 402 aligns[order] += align;
373 if (order > max_order) 403 if (order > max_order)
374 max_order = order; 404 max_order = order;
405 mem64_mask &= r->flags & IORESOURCE_MEM_64;
375 } 406 }
376 } 407 }
377 408
@@ -396,6 +427,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
396 b_res->start = min_align; 427 b_res->start = min_align;
397 b_res->end = size + min_align - 1; 428 b_res->end = size + min_align - 1;
398 b_res->flags |= IORESOURCE_STARTALIGN; 429 b_res->flags |= IORESOURCE_STARTALIGN;
430 b_res->flags |= mem64_mask;
399 return 1; 431 return 1;
400} 432}
401 433