}
 }
 
-/**
- * pci_bus_alloc_resource - allocate a resource from a parent bus
- * @bus: PCI bus
- * @res: resource to allocate
- * @size: size of resource to allocate
- * @align: alignment of resource to allocate
- * @min: minimum /proc/iomem address to allocate
- * @type_mask: IORESOURCE_* type flags
- * @alignf: resource alignment function
- * @alignf_data: data argument for resource alignment function
- *
- * Given the PCI bus a device resides on, the size, minimum address,
- * alignment and type, try to find an acceptable resource allocation
- * for a specific device resource.
+static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL};
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+static struct pci_bus_region pci_64_bit = {0,
+                               (dma_addr_t) 0xffffffffffffffffULL};
+#endif
+
+/*
+ * @res contains CPU addresses.  Clip it so the corresponding bus addresses
+ * on @bus are entirely within @region.  This is used to control the bus
+ * addresses of resources we allocate, e.g., we may need a resource that
+ * can be mapped by a 32-bit BAR.
  */
-int
-pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+static void pci_clip_resource_to_region(struct pci_bus *bus,
+                                       struct resource *res,
+                                       struct pci_bus_region *region)
+{
+       struct pci_bus_region r;
+
+       pcibios_resource_to_bus(bus, &r, res);
+       if (r.start < region->start)
+               r.start = region->start;
+       if (r.end > region->end)
+               r.end = region->end;
+
+       if (r.end < r.start)
+               res->end = res->start - 1;
+       else
+               pcibios_bus_to_resource(bus, res, &r);
+}
+
+static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
                resource_size_t size, resource_size_t align,
                resource_size_t min, unsigned int type_mask,
                resource_size_t (*alignf)(void *,
                                          const struct resource *,
                                          resource_size_t,
                                          resource_size_t),
-               void *alignf_data)
+               void *alignf_data,
+               struct pci_bus_region *region)
 {
-       int i, ret = -ENOMEM;
-       struct resource *r;
-       resource_size_t max = -1;
+       int i, ret;
+       struct resource *r, avail;
+       resource_size_t max;
 
        type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
 
-       /* don't allocate too high if the pref mem doesn't support 64bit*/
-       if (!(res->flags & IORESOURCE_MEM_64))
-               max = PCIBIOS_MAX_MEM_32;
-
        pci_bus_for_each_resource(bus, r, i) {
                if (!r)
                        continue;
                    !(res->flags & IORESOURCE_PREFETCH))
                        continue;
 
+               avail = *r;
+               pci_clip_resource_to_region(bus, &avail, region);
+               if (!resource_size(&avail))
+                       continue;
+
                /*
                 * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
                 * protect badly documented motherboard resources, but if
                 * this is an already-configured bridge window, its start
                 * overrides "min".
                 */
-               if (r->start)
-                       min = r->start;
+               if (avail.start)
+                       min = avail.start;
+
+               max = avail.end;
 
                /* Ok, try it out.. */
                ret = allocate_resource(r, res, size, min, max,
                                        align, alignf, alignf_data);
                if (ret == 0)
-                       break;
+                       return 0;
        }
-       return ret;
+       return -ENOMEM;
+}
+
+/**
+ * pci_bus_alloc_resource - allocate a resource from a parent bus
+ * @bus: PCI bus
+ * @res: resource to allocate
+ * @size: size of resource to allocate
+ * @align: alignment of resource to allocate
+ * @min: minimum /proc/iomem address to allocate
+ * @type_mask: IORESOURCE_* type flags
+ * @alignf: resource alignment function
+ * @alignf_data: data argument for resource alignment function
+ *
+ * Given the PCI bus a device resides on, the size, minimum address,
+ * alignment and type, try to find an acceptable resource allocation
+ * for a specific device resource.
+ */
+int
+pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+               resource_size_t size, resource_size_t align,
+               resource_size_t min, unsigned int type_mask,
+               resource_size_t (*alignf)(void *,
+                                         const struct resource *,
+                                         resource_size_t,
+                                         resource_size_t),
+               void *alignf_data)
+{
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+       if (res->flags & IORESOURCE_MEM_64)
+               return pci_bus_alloc_from_region(bus, res, size, align, min,
+                                                type_mask, alignf, alignf_data,
+                                                &pci_64_bit);
+#endif
+
+       return pci_bus_alloc_from_region(bus, res, size, align, min,
+                                        type_mask, alignf, alignf_data,
+                                        &pci_32_bit);
 }
 
 void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }