diff options
author | Eric W. Biederman <ebiederm@aristanetworks.com> | 2009-09-09 17:09:24 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-09-09 17:10:24 -0400 |
commit | 28760489a3f1e136c5ae8581c0fa8f63511f2f4c (patch) | |
tree | a3c890e9c8d9e98385691d56f5c007d280514fe5 /drivers/pci/setup-bus.c | |
parent | 0ba379ec0fb182a87b8891c5754abbcd9c035b4f (diff) |
PCI: pcie: Ensure hotplug ports have a minimum number of resources
In general a BIOS may goof or we may hotplug in a hotplug controller.
In either case the kernel needs to reserve resources for plugging
in more devices in the future instead of creating a minimal resource
assignment.
We already do this for cardbus bridges I am just adding a variant
for pcie bridges.
v2: Make testing for pcie hotplug bridges based on a flag.
So far we only set the flag for pcie but a header_quirk
could easily be added for the non-standard pci hotplug
bridges.
Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 7c443b4583ab..cb1a027eb552 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -309,7 +309,7 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon | |||
309 | since these windows have 4K granularity and the IO ranges | 309 | since these windows have 4K granularity and the IO ranges |
310 | of non-bridge PCI devices are limited to 256 bytes. | 310 | of non-bridge PCI devices are limited to 256 bytes. |
311 | We must be careful with the ISA aliasing though. */ | 311 | We must be careful with the ISA aliasing though. */ |
312 | static void pbus_size_io(struct pci_bus *bus) | 312 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) |
313 | { | 313 | { |
314 | struct pci_dev *dev; | 314 | struct pci_dev *dev; |
315 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 315 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
@@ -336,6 +336,8 @@ static void pbus_size_io(struct pci_bus *bus) | |||
336 | size1 += r_size; | 336 | size1 += r_size; |
337 | } | 337 | } |
338 | } | 338 | } |
339 | if (size < min_size) | ||
340 | size = min_size; | ||
339 | /* To be fixed in 2.5: we should have sort of HAVE_ISA | 341 | /* To be fixed in 2.5: we should have sort of HAVE_ISA |
340 | flag in the struct pci_bus. */ | 342 | flag in the struct pci_bus. */ |
341 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) | 343 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) |
@@ -354,7 +356,8 @@ static void pbus_size_io(struct pci_bus *bus) | |||
354 | 356 | ||
355 | /* Calculate the size of the bus and minimal alignment which | 357 | /* Calculate the size of the bus and minimal alignment which |
356 | guarantees that all child resources fit in this size. */ | 358 | guarantees that all child resources fit in this size. */ |
357 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) | 359 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, |
360 | unsigned long type, resource_size_t min_size) | ||
358 | { | 361 | { |
359 | struct pci_dev *dev; | 362 | struct pci_dev *dev; |
360 | resource_size_t min_align, align, size; | 363 | resource_size_t min_align, align, size; |
@@ -404,6 +407,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
404 | mem64_mask &= r->flags & IORESOURCE_MEM_64; | 407 | mem64_mask &= r->flags & IORESOURCE_MEM_64; |
405 | } | 408 | } |
406 | } | 409 | } |
410 | if (size < min_size) | ||
411 | size = min_size; | ||
407 | 412 | ||
408 | align = 0; | 413 | align = 0; |
409 | min_align = 0; | 414 | min_align = 0; |
@@ -483,6 +488,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
483 | { | 488 | { |
484 | struct pci_dev *dev; | 489 | struct pci_dev *dev; |
485 | unsigned long mask, prefmask; | 490 | unsigned long mask, prefmask; |
491 | resource_size_t min_mem_size = 0, min_io_size = 0; | ||
486 | 492 | ||
487 | list_for_each_entry(dev, &bus->devices, bus_list) { | 493 | list_for_each_entry(dev, &bus->devices, bus_list) { |
488 | struct pci_bus *b = dev->subordinate; | 494 | struct pci_bus *b = dev->subordinate; |
@@ -512,8 +518,12 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
512 | 518 | ||
513 | case PCI_CLASS_BRIDGE_PCI: | 519 | case PCI_CLASS_BRIDGE_PCI: |
514 | pci_bridge_check_ranges(bus); | 520 | pci_bridge_check_ranges(bus); |
521 | if (bus->self->is_hotplug_bridge) { | ||
522 | min_io_size = pci_hotplug_io_size; | ||
523 | min_mem_size = pci_hotplug_mem_size; | ||
524 | } | ||
515 | default: | 525 | default: |
516 | pbus_size_io(bus); | 526 | pbus_size_io(bus, min_io_size); |
517 | /* If the bridge supports prefetchable range, size it | 527 | /* If the bridge supports prefetchable range, size it |
518 | separately. If it doesn't, or its prefetchable window | 528 | separately. If it doesn't, or its prefetchable window |
519 | has already been allocated by arch code, try | 529 | has already been allocated by arch code, try |
@@ -521,9 +531,11 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
521 | resources. */ | 531 | resources. */ |
522 | mask = IORESOURCE_MEM; | 532 | mask = IORESOURCE_MEM; |
523 | prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; | 533 | prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; |
524 | if (pbus_size_mem(bus, prefmask, prefmask)) | 534 | if (pbus_size_mem(bus, prefmask, prefmask, min_mem_size)) |
525 | mask = prefmask; /* Success, size non-prefetch only. */ | 535 | mask = prefmask; /* Success, size non-prefetch only. */ |
526 | pbus_size_mem(bus, mask, IORESOURCE_MEM); | 536 | else |
537 | min_mem_size += min_mem_size; | ||
538 | pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size); | ||
527 | break; | 539 | break; |
528 | } | 540 | } |
529 | } | 541 | } |