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 | |
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')
-rw-r--r-- | drivers/pci/pci.c | 10 | ||||
-rw-r--r-- | drivers/pci/probe.c | 18 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 22 |
3 files changed, 45 insertions, 5 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index bd993351db45..8c663d628d03 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -41,6 +41,12 @@ int pci_domains_supported = 1; | |||
41 | unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE; | 41 | unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE; |
42 | unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; | 42 | unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; |
43 | 43 | ||
44 | #define DEFAULT_HOTPLUG_IO_SIZE (256) | ||
45 | #define DEFAULT_HOTPLUG_MEM_SIZE (2*1024*1024) | ||
46 | /* pci=hpmemsize=nnM,hpiosize=nn can override this */ | ||
47 | unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; | ||
48 | unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; | ||
49 | |||
44 | /** | 50 | /** |
45 | * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children | 51 | * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children |
46 | * @bus: pointer to PCI bus structure to search | 52 | * @bus: pointer to PCI bus structure to search |
@@ -2732,6 +2738,10 @@ static int __init pci_setup(char *str) | |||
2732 | strlen(str + 19)); | 2738 | strlen(str + 19)); |
2733 | } else if (!strncmp(str, "ecrc=", 5)) { | 2739 | } else if (!strncmp(str, "ecrc=", 5)) { |
2734 | pcie_ecrc_get_policy(str + 5); | 2740 | pcie_ecrc_get_policy(str + 5); |
2741 | } else if (!strncmp(str, "hpiosize=", 9)) { | ||
2742 | pci_hotplug_io_size = memparse(str + 9, &str); | ||
2743 | } else if (!strncmp(str, "hpmemsize=", 10)) { | ||
2744 | pci_hotplug_mem_size = memparse(str + 10, &str); | ||
2735 | } else { | 2745 | } else { |
2736 | printk(KERN_ERR "PCI: Unknown option `%s'\n", | 2746 | printk(KERN_ERR "PCI: Unknown option `%s'\n", |
2737 | str); | 2747 | str); |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ab52840f4753..882383b61d30 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -697,6 +697,23 @@ static void set_pcie_port_type(struct pci_dev *pdev) | |||
697 | pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; | 697 | pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; |
698 | } | 698 | } |
699 | 699 | ||
700 | static void set_pcie_hotplug_bridge(struct pci_dev *pdev) | ||
701 | { | ||
702 | int pos; | ||
703 | u16 reg16; | ||
704 | u32 reg32; | ||
705 | |||
706 | pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); | ||
707 | if (!pos) | ||
708 | return; | ||
709 | pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); | ||
710 | if (!(reg16 & PCI_EXP_FLAGS_SLOT)) | ||
711 | return; | ||
712 | pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, ®32); | ||
713 | if (reg32 & PCI_EXP_SLTCAP_HPC) | ||
714 | pdev->is_hotplug_bridge = 1; | ||
715 | } | ||
716 | |||
700 | #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) | 717 | #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) |
701 | 718 | ||
702 | /** | 719 | /** |
@@ -804,6 +821,7 @@ int pci_setup_device(struct pci_dev *dev) | |||
804 | pci_read_irq(dev); | 821 | pci_read_irq(dev); |
805 | dev->transparent = ((dev->class & 0xff) == 1); | 822 | dev->transparent = ((dev->class & 0xff) == 1); |
806 | pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); | 823 | pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); |
824 | set_pcie_hotplug_bridge(dev); | ||
807 | break; | 825 | break; |
808 | 826 | ||
809 | case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ | 827 | case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ |
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 | } |