diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 557585f1be41..8e65832fb510 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -669,7 +669,7 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
 	struct pci_bus *b;
 	int i;
-	struct resource *res, *pr;
+	struct resource *res, *pr = NULL;
 
 	pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
 		 pci_domain_nr(bus), bus->number);
@@ -688,7 +688,7 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 			 * and as such ensure proper re-allocation
 			 * later.
 			 */
-			pr = pci_find_parent_resource(bus->self, res);
+			pci_find_parent_resource(bus->self, res, &pr, NULL);
 			if (pr == res) {
 				/* this happens when the generic PCI
 				 * code (wrongly) decides that this
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 001e90cd8948..f865354b746d 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1196,7 +1196,7 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
 	struct pci_bus *b;
 	int i;
-	struct resource *res, *pr;
+	struct resource *res, *pr = NULL;
 
 	pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
 		 pci_domain_nr(bus), bus->number);
@@ -1213,7 +1213,7 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 			pr = (res->flags & IORESOURCE_IO) ?
 				&ioport_resource : &iomem_resource;
 		else {
-			pr = pci_find_parent_resource(bus->self, res);
+			pci_find_parent_resource(bus->self, res, &pr, NULL);
 			if (pr == res) {
 				/* this happens when the generic PCI
 				 * code (wrongly) decides that this
@@ -1265,12 +1265,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 
 static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
-	struct resource *pr, *r = &dev->resource[idx];
+	struct resource *pr = NULL, *r = &dev->resource[idx];
 
 	pr_debug("PCI: Allocating %s: Resource %d: %pR\n",
 		 pci_name(dev), idx, r);
 
-	pr = pci_find_parent_resource(dev, r);
+	pci_find_parent_resource(dev, r, &pr, NULL);
 	if (!pr || (pr->flags & IORESOURCE_UNSET) ||
 	    request_resource(pr, r) < 0) {
 		printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 9c2b720bfd20..b4006798e4e1 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -621,7 +621,7 @@ static void pci_bus_register_of_sysfs(struct pci_bus *bus)
 static void pci_claim_legacy_resources(struct pci_dev *dev)
 {
 	struct pci_bus_region region;
-	struct resource *p, *root, *conflict;
+	struct resource *p, *root = NULL, *conflict;
 
 	if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
 		return;
@@ -637,7 +637,7 @@ static void pci_claim_legacy_resources(struct pci_dev *dev)
 	region.end = region.start + 0x1ffffUL;
 	pcibios_bus_to_resource(dev->bus, p, &region);
 
-	root = pci_find_parent_resource(dev, p);
+	pci_find_parent_resource(dev, p, &root, NULL);
 	if (!root) {
 		pci_info(dev, "can't claim VGA legacy %pR: no compatible bridge window\n", p);
 		goto err;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 16a17215f633..abbcd2dcdc02 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -693,20 +693,25 @@ u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
 EXPORT_SYMBOL_GPL(pci_find_ht_capability);
 
 /**
- * pci_find_parent_resource - return resource region of parent bus of given
+ * pci_find_parent_resource - find resource region of parent bus of given
  *			      region
  * @dev: PCI device structure contains resources to be searched
  * @res: child resource record for which parent is sought
+ * @first: the first region that contains the child resource
+ * @second: the second region that combines with the first region to fully
+ * contains the child resource
  *
  * For given resource region of given device, return the resource region of
  * parent bus the given region is contained in.
  */
-struct resource *pci_find_parent_resource(const struct pci_dev *dev,
-					  struct resource *res)
+void pci_find_parent_resource(const struct pci_dev *dev,
+					  struct resource *res,
+					  struct resource **first,
+					  struct resource **second)
 {
 	const struct pci_bus *bus = dev->bus;
 	struct resource *r;
-	int i;
+	int i, overlaps = 0;
 
 	pci_bus_for_each_resource(bus, r, i) {
 		if (!r)
@@ -718,8 +723,10 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev,
 			 * not, the allocator made a mistake.
 			 */
 			if (r->flags & IORESOURCE_PREFETCH &&
-			    !(res->flags & IORESOURCE_PREFETCH))
-				return NULL;
+			    !(res->flags & IORESOURCE_PREFETCH)) {
+				*first = NULL;
+				return;
+			}
 
 			/*
 			 * If we're below a transparent bridge, there may
@@ -729,10 +736,47 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev,
 			 * on pci_bus_for_each_resource() giving us those
 			 * first.
 			 */
-			return r;
+			*first = r;
+			return;
 		}
 	}
-	return NULL;
+
+	if (!second)
+		return;
+
+	pci_bus_for_each_resource(bus, r, i) {
+		if (!r)
+			continue;
+		if (resource_overlaps(r, res)) {
+			if (r->flags & IORESOURCE_PREFETCH &&
+			    !(res->flags & IORESOURCE_PREFETCH))
+				continue;
+
+			if (!overlaps++)
+				*first = r;
+			else {
+				*second = r;
+				break;
+			}
+		}
+	}
+
+	if (overlaps != 2)
+		goto out;
+
+	if ((*first)->start > (*second)->start)
+		swap(*first, *second);
+
+	if ((*first)->end + 1 != (*second)->start)
+		goto out;
+
+	if ((*first)->start <= res->start && (*second)->end >= res->end)
+		return;
+out:
+
+	*first = NULL;
+	*second = NULL;
+	return;
 }
 EXPORT_SYMBOL(pci_find_parent_resource);
 
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 7f1acb3918d0..e39615321d81 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -131,7 +131,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)
 int pci_claim_resource(struct pci_dev *dev, int resource)
 {
 	struct resource *res = &dev->resource[resource];
-	struct resource *root, *conflict;
+	struct resource *first = NULL, *second = NULL, *conflict;
 
 	if (res->flags & IORESOURCE_UNSET) {
 		pci_info(dev, "can't claim BAR %d %pR: no address assigned\n",
@@ -147,21 +147,28 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
 	if (res->flags & IORESOURCE_ROM_SHADOW)
 		return 0;
 
-	root = pci_find_parent_resource(dev, res);
-	if (!root) {
+	pci_find_parent_resource(dev, res, &first, &second);
+	if (!first) {
 		pci_info(dev, "can't claim BAR %d %pR: no compatible bridge window\n",
 			 resource, res);
 		res->flags |= IORESOURCE_UNSET;
 		return -EINVAL;
 	}
 
-	conflict = request_resource_conflict(root, res);
+	if (second)
+		first->end = second->end;
+
+	conflict = request_resource_conflict(first, res);
 	if (conflict) {
+		if (second)
+			first->end = second->start - 1;
+
 		pci_info(dev, "can't claim BAR %d %pR: address conflict with %s %pR\n",
 			 resource, res, conflict->name, conflict);
 		res->flags |= IORESOURCE_UNSET;
 		return -EBUSY;
-	}
+	} else if (second)
+		second->start = second->end = 0;
 
 	return 0;
 }
@@ -195,7 +202,7 @@ resource_size_t __weak pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
 static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
 		int resno, resource_size_t size)
 {
-	struct resource *root, *conflict;
+	struct resource *root = NULL, *conflict;
 	resource_size_t fw_addr, start, end;
 
 	fw_addr = pcibios_retrieve_fw_addr(dev, resno);
@@ -208,7 +215,7 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
 	res->end = res->start + size - 1;
 	res->flags &= ~IORESOURCE_UNSET;
 
-	root = pci_find_parent_resource(dev, res);
+	pci_find_parent_resource(dev, res, &root, NULL);
 	if (!root) {
 		if (res->flags & IORESOURCE_IO)
 			root = &ioport_resource;
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 3b05760e69d6..2fba42d7486e 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -73,7 +73,7 @@ static struct resource *
 claim_region(struct pcmcia_socket *s, resource_size_t base,
 		resource_size_t size, int type, char *name)
 {
-	struct resource *res, *parent;
+	struct resource *res, *parent = NULL;
 
 	parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
 	res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
@@ -81,7 +81,7 @@ claim_region(struct pcmcia_socket *s, resource_size_t base,
 	if (res) {
 #ifdef CONFIG_PCI
 		if (s && s->cb_dev)
-			parent = pci_find_parent_resource(s->cb_dev, res);
+			pci_find_parent_resource(s->cb_dev, res, &parent, NULL);
 #endif
 		if (!parent || request_resource(parent, res)) {
 			kfree(res);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 86c799c97b77..dd1455be5247 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1049,8 +1049,10 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
 unsigned int pci_scan_child_bus(struct pci_bus *bus);
 void pci_bus_add_device(struct pci_dev *dev);
 void pci_read_bridge_bases(struct pci_bus *child);
-struct resource *pci_find_parent_resource(const struct pci_dev *dev,
-					  struct resource *res);
+void pci_find_parent_resource(const struct pci_dev *dev,
+					  struct resource *res,
+					  struct resource **first,
+					  struct resource **second);
 u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin);
 int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
 u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
