@@ -207,6 +207,7 @@ extern unsigned long pci_hotplug_io_size;
extern unsigned long pci_hotplug_mmio_size;
extern unsigned long pci_hotplug_mmio_pref_size;
extern unsigned long pci_hotplug_bus_size;
+extern bool pci_hotplug_expand;
/**
* pci_match_one_device - Tell if a PCI device structure has a matching
@@ -41,6 +41,7 @@ EXPORT_SYMBOL(pci_root_buses);
* were assigned before the rescan.
*/
static bool pci_try_failed_bars = true;
+bool pci_hotplug_expand = true;
bool pci_init_done;
static LIST_HEAD(pci_domain_busn_res_list);
@@ -3542,6 +3543,13 @@ static void pci_reassign_root_bus_resources(struct pci_bus *root)
if (pci_bus_check_bars_assigned(root, pci_try_failed_bars))
break;
+ if (pci_hotplug_expand) {
+ dev_warn(&root->dev, "failed to assign all BARs, retry without additional window size\n");
+
+ pci_hotplug_expand = false;
+ continue;
+ }
+
if (pci_try_failed_bars) {
dev_warn(&root->dev, "failed to assign all BARs, retry without those failed before\n");
@@ -3564,6 +3572,7 @@ static void pci_reassign_root_bus_resources(struct pci_bus *root)
} while (true);
pci_try_failed_bars = true;
+ pci_hotplug_expand = true;
}
/**
@@ -1058,6 +1058,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
resource_size_t children_add_size = 0;
resource_size_t children_add_align = 0;
resource_size_t add_align = 0;
+ bool size0_can_add = pci_can_move_bars && !realloc_head;
int idx;
struct resource *fixed_range;
resource_size_t fixed_size;
@@ -1141,7 +1142,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
min_align = calculate_mem_align(aligns, max_order);
min_align = max(min_align, window_alignment(bus, b_res->flags));
- size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), min_align);
+ size0 = calculate_memsize(size, min_size,
+ size0_can_add ? add_size : 0,
+ size0_can_add ? children_add_size : 0,
+ resource_size(b_res), min_align);
+
add_align = max(min_align, add_align);
size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 :
calculate_memsize(size, min_size, add_size, children_add_size,
@@ -1316,7 +1321,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
case PCI_HEADER_TYPE_BRIDGE:
pci_bridge_check_ranges(bus);
- if (bus->self->is_hotplug_bridge) {
+ if (bus->self->is_hotplug_bridge && pci_hotplug_expand) {
additional_io_size = pci_hotplug_io_size;
additional_mmio_size = pci_hotplug_mmio_size;
additional_mmio_pref_size = pci_hotplug_mmio_pref_size;
A hot-added bridge with many hotplug-capable ports may request reserving more IO space than the machine has. This could be overridden with the "hpiosize=" kernel argument though. But when BARs are movable, no need to reserve space anymore: new BARs are allocated not from reserved gaps, but via rearranging the existing BARs. Requesting a precise amount of space for bridge windows increases the chances of adding the new bridge successfully. Still, fixed BARs may interfere with an allocation, preventing it from happening. So it makes sense to reserve some space when it is possible, so movable BARs can be moved a bit more effectively later. If a BAR allocation fails with additional bridge size, retry without them. Signed-off-by: Sergei Miroshnichenko <s.miroshnichenko@yadro.com> --- drivers/pci/pci.h | 1 + drivers/pci/probe.c | 9 +++++++++ drivers/pci/setup-bus.c | 9 +++++++-- 3 files changed, 17 insertions(+), 2 deletions(-)