diff mbox

[Bug,15480,regression] Gigabyte GA-MA78GM-S2H boot fails without pci=nocrs

Message ID 201003101350.31554.bjorn.helgaas@hp.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Bjorn Helgaas March 10, 2010, 8:50 p.m. UTC
None
diff mbox

Patch

diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 6e22454..42d8f01 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -118,7 +118,7 @@  static acpi_status
 setup_resource(struct acpi_resource *acpi_res, void *data)
 {
 	struct pci_root_info *info = data;
-	struct resource *res;
+	struct resource *res, *conflict;
 	struct acpi_resource_address64 addr;
 	acpi_status status;
 	unsigned long flags;
@@ -157,21 +157,39 @@  setup_resource(struct acpi_resource *acpi_res, void *data)
 		return AE_OK;
 	}
 
-	if (insert_resource(root, res)) {
+	for (;;) {
+		conflict = insert_resource_conflict(root, res);
+		if (!conflict)
+			break;
+
 		dev_err(&info->bridge->dev,
-			"can't allocate host bridge window %pR\n", res);
-	} else {
-		pci_bus_add_resource(info->bus, res, 0);
-		info->res_num++;
-		if (addr.translation_offset)
-			dev_info(&info->bridge->dev, "host bridge window %pR "
-				 "(PCI address [%#llx-%#llx])\n",
-				 res, res->start - addr.translation_offset,
-				 res->end - addr.translation_offset);
-		else
-			dev_info(&info->bridge->dev,
-				 "host bridge window %pR\n", res);
+		        "host bridge window %pR conflicts with %pR\n",
+			res, conflict);
+		if (res->start < conflict->end && conflict->end < res->end)
+			res->start = conflict->end + 1;
+		if (res->start < conflict->start && conflict->start < res->end)
+			res->end = conflict->start - 1;
+
+		if (res->start >= res->end) {
+			dev_err(&info->bridge->dev,
+				"can't allocate host bridge window\n");
+			return AE_OK;
+		}
+
+		dev_info(&info->bridge->dev,
+			 "host bridge window trimmed to %pR\n", res);
 	}
+
+	pci_bus_add_resource(info->bus, res, 0);
+	info->res_num++;
+	if (addr.translation_offset)
+		dev_info(&info->bridge->dev, "host bridge window %pR "
+			 "(PCI address [%#llx-%#llx])\n",
+			 res, res->start - addr.translation_offset,
+			 res->end - addr.translation_offset);
+	else
+		dev_info(&info->bridge->dev,
+			 "host bridge window %pR\n", res);
 	return AE_OK;
 }
 
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index dda9841..9f88526 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -117,6 +117,7 @@  extern void reserve_region_with_split(struct resource *root,
 			     resource_size_t start, resource_size_t end,
 			     const char *name);
 extern int insert_resource(struct resource *parent, struct resource *new);
+extern struct resource *insert_resource_conflict(struct resource *parent, struct resource *new);
 extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
 			     resource_size_t size, resource_size_t min,
diff --git a/kernel/resource.c b/kernel/resource.c
index 2d5be5d..8ec71a2 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -496,6 +496,16 @@  int insert_resource(struct resource *parent, struct resource *new)
 	return conflict ? -EBUSY : 0;
 }
 
+struct resource *insert_resource_conflict(struct resource *parent, struct resource *new)
+{
+	struct resource *conflict;
+
+	write_lock(&resource_lock);
+	conflict = __insert_resource(parent, new);
+	write_unlock(&resource_lock);
+	return conflict;
+}
+
 /**
  * insert_resource_expand_to_fit - Insert a resource into the resource tree
  * @root: root resource descriptor