diff mbox series

[v9,20/26] PCI: hotplug: Retry bus assignment without reserved space

Message ID 20201218174011.340514-21-s.miroshnichenko@yadro.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show
Series PCI: Allow BAR movement during boot and hotplug | expand

Commit Message

Sergei Miroshnichenko Dec. 18, 2020, 5:40 p.m. UTC
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(-)
diff mbox series

Patch

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f7460ddd196a..685284c57a28 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -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
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b8873ee82a4b..24793766b4b7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -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;
 }
 
 /**
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index f98772474421..4b37815a9fcf 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -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;