diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
| -rw-r--r-- | drivers/pci/setup-bus.c | 70 |
1 files changed, 53 insertions, 17 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 704608945780..7c443b4583ab 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
| @@ -25,9 +25,9 @@ | |||
| 25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
| 26 | #include <linux/cache.h> | 26 | #include <linux/cache.h> |
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include "pci.h" | ||
| 28 | 29 | ||
| 29 | 30 | static void pbus_assign_resources_sorted(const struct pci_bus *bus) | |
| 30 | static void pbus_assign_resources_sorted(struct pci_bus *bus) | ||
| 31 | { | 31 | { |
| 32 | struct pci_dev *dev; | 32 | struct pci_dev *dev; |
| 33 | struct resource *res; | 33 | struct resource *res; |
| @@ -58,7 +58,6 @@ static void pbus_assign_resources_sorted(struct pci_bus *bus) | |||
| 58 | res = list->res; | 58 | res = list->res; |
| 59 | idx = res - &list->dev->resource[0]; | 59 | idx = res - &list->dev->resource[0]; |
| 60 | if (pci_assign_resource(list->dev, idx)) { | 60 | if (pci_assign_resource(list->dev, idx)) { |
| 61 | /* FIXME: get rid of this */ | ||
| 62 | res->start = 0; | 61 | res->start = 0; |
| 63 | res->end = 0; | 62 | res->end = 0; |
| 64 | res->flags = 0; | 63 | res->flags = 0; |
| @@ -143,6 +142,10 @@ static void pci_setup_bridge(struct pci_bus *bus) | |||
| 143 | struct pci_dev *bridge = bus->self; | 142 | struct pci_dev *bridge = bus->self; |
| 144 | struct pci_bus_region region; | 143 | struct pci_bus_region region; |
| 145 | u32 l, bu, lu, io_upper16; | 144 | u32 l, bu, lu, io_upper16; |
| 145 | int pref_mem64; | ||
| 146 | |||
| 147 | if (pci_is_enabled(bridge)) | ||
| 148 | return; | ||
| 146 | 149 | ||
| 147 | dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", | 150 | dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", |
| 148 | pci_domain_nr(bus), bus->number); | 151 | pci_domain_nr(bus), bus->number); |
| @@ -195,16 +198,22 @@ static void pci_setup_bridge(struct pci_bus *bus) | |||
| 195 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); | 198 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); |
| 196 | 199 | ||
| 197 | /* Set up PREF base/limit. */ | 200 | /* Set up PREF base/limit. */ |
| 201 | pref_mem64 = 0; | ||
| 198 | bu = lu = 0; | 202 | bu = lu = 0; |
| 199 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); | 203 | pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); |
| 200 | if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { | 204 | if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { |
| 205 | int width = 8; | ||
| 201 | l = (region.start >> 16) & 0xfff0; | 206 | l = (region.start >> 16) & 0xfff0; |
| 202 | l |= region.end & 0xfff00000; | 207 | l |= region.end & 0xfff00000; |
| 203 | bu = upper_32_bits(region.start); | 208 | if (bus->resource[2]->flags & IORESOURCE_MEM_64) { |
| 204 | lu = upper_32_bits(region.end); | 209 | pref_mem64 = 1; |
| 205 | dev_info(&bridge->dev, " PREFETCH window: %#016llx-%#016llx\n", | 210 | bu = upper_32_bits(region.start); |
| 206 | (unsigned long long)region.start, | 211 | lu = upper_32_bits(region.end); |
| 207 | (unsigned long long)region.end); | 212 | width = 16; |
| 213 | } | ||
| 214 | dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n", | ||
| 215 | width, (unsigned long long)region.start, | ||
| 216 | width, (unsigned long long)region.end); | ||
| 208 | } | 217 | } |
| 209 | else { | 218 | else { |
| 210 | l = 0x0000fff0; | 219 | l = 0x0000fff0; |
| @@ -212,9 +221,11 @@ static void pci_setup_bridge(struct pci_bus *bus) | |||
| 212 | } | 221 | } |
| 213 | pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); | 222 | pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); |
| 214 | 223 | ||
| 215 | /* Set the upper 32 bits of PREF base & limit. */ | 224 | if (pref_mem64) { |
| 216 | pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); | 225 | /* Set the upper 32 bits of PREF base & limit. */ |
| 217 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); | 226 | pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); |
| 227 | pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); | ||
| 228 | } | ||
| 218 | 229 | ||
| 219 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); | 230 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); |
| 220 | } | 231 | } |
| @@ -252,8 +263,25 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) | |||
| 252 | pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); | 263 | pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); |
| 253 | pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); | 264 | pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); |
| 254 | } | 265 | } |
| 255 | if (pmem) | 266 | if (pmem) { |
| 256 | b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; | 267 | b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; |
| 268 | if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) | ||
| 269 | b_res[2].flags |= IORESOURCE_MEM_64; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* double check if bridge does support 64 bit pref */ | ||
| 273 | if (b_res[2].flags & IORESOURCE_MEM_64) { | ||
| 274 | u32 mem_base_hi, tmp; | ||
| 275 | pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, | ||
| 276 | &mem_base_hi); | ||
| 277 | pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, | ||
| 278 | 0xffffffff); | ||
| 279 | pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp); | ||
| 280 | if (!tmp) | ||
| 281 | b_res[2].flags &= ~IORESOURCE_MEM_64; | ||
| 282 | pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, | ||
| 283 | mem_base_hi); | ||
| 284 | } | ||
| 257 | } | 285 | } |
| 258 | 286 | ||
| 259 | /* Helper function for sizing routines: find first available | 287 | /* Helper function for sizing routines: find first available |
| @@ -333,6 +361,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
| 333 | resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ | 361 | resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ |
| 334 | int order, max_order; | 362 | int order, max_order; |
| 335 | struct resource *b_res = find_free_bus_resource(bus, type); | 363 | struct resource *b_res = find_free_bus_resource(bus, type); |
| 364 | unsigned int mem64_mask = 0; | ||
| 336 | 365 | ||
| 337 | if (!b_res) | 366 | if (!b_res) |
| 338 | return 0; | 367 | return 0; |
| @@ -341,9 +370,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
| 341 | max_order = 0; | 370 | max_order = 0; |
| 342 | size = 0; | 371 | size = 0; |
| 343 | 372 | ||
| 373 | mem64_mask = b_res->flags & IORESOURCE_MEM_64; | ||
| 374 | b_res->flags &= ~IORESOURCE_MEM_64; | ||
| 375 | |||
| 344 | list_for_each_entry(dev, &bus->devices, bus_list) { | 376 | list_for_each_entry(dev, &bus->devices, bus_list) { |
| 345 | int i; | 377 | int i; |
| 346 | 378 | ||
| 347 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | 379 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
| 348 | struct resource *r = &dev->resource[i]; | 380 | struct resource *r = &dev->resource[i]; |
| 349 | resource_size_t r_size; | 381 | resource_size_t r_size; |
| @@ -352,7 +384,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
| 352 | continue; | 384 | continue; |
| 353 | r_size = resource_size(r); | 385 | r_size = resource_size(r); |
| 354 | /* For bridges size != alignment */ | 386 | /* For bridges size != alignment */ |
| 355 | align = resource_alignment(r); | 387 | align = pci_resource_alignment(dev, r); |
| 356 | order = __ffs(align) - 20; | 388 | order = __ffs(align) - 20; |
| 357 | if (order > 11) { | 389 | if (order > 11) { |
| 358 | dev_warn(&dev->dev, "BAR %d bad alignment %llx: " | 390 | dev_warn(&dev->dev, "BAR %d bad alignment %llx: " |
| @@ -369,6 +401,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
| 369 | aligns[order] += align; | 401 | aligns[order] += align; |
| 370 | if (order > max_order) | 402 | if (order > max_order) |
| 371 | max_order = order; | 403 | max_order = order; |
| 404 | mem64_mask &= r->flags & IORESOURCE_MEM_64; | ||
| 372 | } | 405 | } |
| 373 | } | 406 | } |
| 374 | 407 | ||
| @@ -393,6 +426,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
| 393 | b_res->start = min_align; | 426 | b_res->start = min_align; |
| 394 | b_res->end = size + min_align - 1; | 427 | b_res->end = size + min_align - 1; |
| 395 | b_res->flags |= IORESOURCE_STARTALIGN; | 428 | b_res->flags |= IORESOURCE_STARTALIGN; |
| 429 | b_res->flags |= mem64_mask; | ||
| 396 | return 1; | 430 | return 1; |
| 397 | } | 431 | } |
| 398 | 432 | ||
| @@ -495,7 +529,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
| 495 | } | 529 | } |
| 496 | EXPORT_SYMBOL(pci_bus_size_bridges); | 530 | EXPORT_SYMBOL(pci_bus_size_bridges); |
| 497 | 531 | ||
| 498 | void __ref pci_bus_assign_resources(struct pci_bus *bus) | 532 | void __ref pci_bus_assign_resources(const struct pci_bus *bus) |
| 499 | { | 533 | { |
| 500 | struct pci_bus *b; | 534 | struct pci_bus *b; |
| 501 | struct pci_dev *dev; | 535 | struct pci_dev *dev; |
| @@ -533,11 +567,13 @@ static void pci_bus_dump_res(struct pci_bus *bus) | |||
| 533 | 567 | ||
| 534 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | 568 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { |
| 535 | struct resource *res = bus->resource[i]; | 569 | struct resource *res = bus->resource[i]; |
| 536 | if (!res) | 570 | if (!res || !res->end) |
| 537 | continue; | 571 | continue; |
| 538 | 572 | ||
| 539 | dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i, | 573 | dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i, |
| 540 | (res->flags & IORESOURCE_IO) ? "io: " : "mem:", res); | 574 | (res->flags & IORESOURCE_IO) ? "io: " : |
| 575 | ((res->flags & IORESOURCE_PREFETCH)? "pref mem":"mem:"), | ||
| 576 | res); | ||
| 541 | } | 577 | } |
| 542 | } | 578 | } |
| 543 | 579 | ||
