diff mbox

PCI: fix pci_bus_alloc_resource() hang

Message ID 20101105023609.27340.3879.stgit@bob.kio (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Bjorn Helgaas Nov. 5, 2010, 2:36 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 5624db8..794c890 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -64,6 +64,24 @@  void pci_bus_remove_resources(struct pci_bus *bus)
 	}
 }
 
+static int resource_compare(struct resource *res1, struct resource *res2)
+{
+	if (res1->end < res2->end)
+		return -1;
+
+	if (res1->end > res2->end)
+		return 1;
+
+	if (res1->start < res2->start)
+		return -1;
+
+	if (res1->start > res2->start)
+		return 1;
+
+	/* If start/end are identical, order them to avoid loops */
+	return res1 - res2;
+}
+
 /*
  * Find the highest-address bus resource below the cursor "res".  If the
  * cursor is NULL, return the highest resource.
@@ -82,26 +100,12 @@  static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
 		if ((r->flags & IORESOURCE_TYPE_BITS) != type)
 			continue;
 
-		/* If this resource is at or past the cursor, skip it */
-		if (res) {
-			if (r == res)
-				continue;
-			if (r->end > res->end)
-				continue;
-			if (r->end == res->end && r->start > res->start)
-				continue;
+		/* Only look at resources before the cursor */
+		if (!res || resource_compare(r, res) < 0) {
+			/* Keep the highest one we find */
+			if (!prev || resource_compare(r, prev) > 0)
+				prev = r;
 		}
-
-		if (!prev)
-			prev = r;
-
-		/*
-		 * A small resource is higher than a large one that ends at
-		 * the same address.
-		 */
-		if (r->end > prev->end ||
-		    (r->end == prev->end && r->start > prev->start))
-			prev = r;
 	}
 
 	return prev;