PCI: Allow additional bus numbers for hotplug bridges

A user may hot add a switch requiring more than one bus to enumerate.  This
previously required a system reboot if BIOS did not sufficiently pad the
bus resource, which they frequently don't do.

Add a kernel parameter so a user can specify the minimum number of bus
numbers to reserve for a hotplug bridge's subordinate buses so rebooting
won't be necessary.

The default is 1, which is equivalent to previous behavior.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
Keith Busch 2016-07-21 21:40:28 -06:00 committed by Bjorn Helgaas
parent af8c34ce6a
commit e16b466059
4 changed files with 21 additions and 0 deletions

View File

@ -3016,6 +3016,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
hpmemsize=nn[KMG] The fixed amount of bus space which is hpmemsize=nn[KMG] The fixed amount of bus space which is
reserved for hotplug bridge's memory window. reserved for hotplug bridge's memory window.
Default size is 2 megabytes. Default size is 2 megabytes.
hpbussize=nn The minimum amount of additional bus numbers
reserved for buses below a hotplug bridge.
Default is 1.
realloc= Enable/disable reallocating PCI bridge resources realloc= Enable/disable reallocating PCI bridge resources
if allocations done by BIOS are too small to if allocations done by BIOS are too small to
accommodate resources required by all child accommodate resources required by all child

View File

@ -81,6 +81,9 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
#define DEFAULT_HOTPLUG_BUS_SIZE 1
unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT; enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT;
/* /*
@ -5021,6 +5024,11 @@ static int __init pci_setup(char *str)
pci_hotplug_io_size = memparse(str + 9, &str); pci_hotplug_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "hpmemsize=", 10)) { } else if (!strncmp(str, "hpmemsize=", 10)) {
pci_hotplug_mem_size = memparse(str + 10, &str); pci_hotplug_mem_size = memparse(str + 10, &str);
} else if (!strncmp(str, "hpbussize=", 10)) {
pci_hotplug_bus_size =
simple_strtoul(str + 10, &str, 0);
if (pci_hotplug_bus_size > 0xff)
pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
} else if (!strncmp(str, "pcie_bus_tune_off", 17)) { } else if (!strncmp(str, "pcie_bus_tune_off", 17)) {
pcie_bus_config = PCIE_BUS_TUNE_OFF; pcie_bus_config = PCIE_BUS_TUNE_OFF;
} else if (!strncmp(str, "pcie_bus_safe", 13)) { } else if (!strncmp(str, "pcie_bus_safe", 13)) {

View File

@ -2076,6 +2076,15 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
max = pci_scan_bridge(bus, dev, max, pass); max = pci_scan_bridge(bus, dev, max, pass);
} }
/*
* Make sure a hotplug bridge has at least the minimum requested
* number of buses.
*/
if (bus->self && bus->self->is_hotplug_bridge && pci_hotplug_bus_size) {
if (max - bus->busn_res.start < pci_hotplug_bus_size - 1)
max = bus->busn_res.start + pci_hotplug_bus_size - 1;
}
/* /*
* We've scanned the bus and so we know all about what's on * We've scanned the bus and so we know all about what's on
* the other side of any bridges that may be on this bus plus * the other side of any bridges that may be on this bus plus

View File

@ -1706,6 +1706,7 @@ extern u8 pci_cache_line_size;
extern unsigned long pci_hotplug_io_size; extern unsigned long pci_hotplug_io_size;
extern unsigned long pci_hotplug_mem_size; extern unsigned long pci_hotplug_mem_size;
extern unsigned long pci_hotplug_bus_size;
/* Architecture-specific versions may override these (weak) */ /* Architecture-specific versions may override these (weak) */
void pcibios_disable_device(struct pci_dev *dev); void pcibios_disable_device(struct pci_dev *dev);