[PATCH 1/3] PCI: Refactor host bridge window coalescing loop to use prev

Ilpo Järvinen posted 3 patches 2 months, 1 week ago
[PATCH 1/3] PCI: Refactor host bridge window coalescing loop to use prev
Posted by Ilpo Järvinen 2 months, 1 week ago
pci_register_host_bridge() has loop for coalescing host bridge windows
that are contiguous. It loops through all but the last entry and if
necessary, coalesces the current entry with the next.

The resource coalescing modifies the resources in place which can cause
issues if other parts of the kernel hold a pointer to the same
resource. This problem was demonstrated to happen when trying to
address an issue with the host bridge window setup on R-Car M2-W (see
the link below).

An upcoming change will perform a safe merge of the resources within a
new function in resource.c. That results in removing both old resource
entries from the resources list and despite using
resource_list_for_each_entry_safe(), the loop will no longer hold valid
pointer to any resources list as the next entry is removed from the
list.

Alter the loop to look back instead of ahead. That is, change next to
prev. When merging previous with the current resource, the next
resource remains valid so resource_list_for_each_entry_safe() is able
to continue iterating the list.

Link: https://lore.kernel.org/linux-pci/CAMuHMdVgCHU80mRm1Vwo6GFgNAtQcf50yHBz_oAk4TrtjcMpYg@mail.gmail.com/
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 drivers/pci/probe.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f41128f91ca7..04523dea7d96 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -952,11 +952,11 @@ static bool pci_preserve_config(struct pci_host_bridge *host_bridge)
 static int pci_register_host_bridge(struct pci_host_bridge *bridge)
 {
 	struct device *parent = bridge->dev.parent;
-	struct resource_entry *window, *next, *n;
+	struct resource_entry *window, *prev, *n;
 	struct pci_bus *bus, *b;
-	resource_size_t offset, next_offset;
+	resource_size_t offset, prev_offset;
 	LIST_HEAD(resources);
-	struct resource *res, *next_res;
+	struct resource *res, *prev_res;
 	bool bus_registered = false;
 	char addr[64], *fmt;
 	const char *name;
@@ -1049,21 +1049,21 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
 
 	/* Coalesce contiguous windows */
 	resource_list_for_each_entry_safe(window, n, &resources) {
-		if (list_is_last(&window->node, &resources))
-			break;
+		if (list_is_first(&window->node, &resources))
+			continue;
 
-		next = list_next_entry(window, node);
+		prev = list_prev_entry(window, node);
 		offset = window->offset;
 		res = window->res;
-		next_offset = next->offset;
-		next_res = next->res;
+		prev_offset = prev->offset;
+		prev_res = prev->res;
 
-		if (res->flags != next_res->flags || offset != next_offset)
+		if (prev_res->flags != res->flags || prev_offset != offset)
 			continue;
 
-		if (res->end + 1 == next_res->start) {
-			next_res->start = res->start;
-			res->flags = res->start = res->end = 0;
+		if (prev_res->end + 1 == res->start) {
+			res->start = prev_res->start;
+			prev_res->flags = prev_res->start = prev_res->end = 0;
 		}
 	}
 
-- 
2.39.5