@@ -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;
}
@@ -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,
@@ -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