diff options
| -rw-r--r-- | arch/x86/include/asm/pci.h | 1 | ||||
| -rw-r--r-- | drivers/pci/bus.c | 111 | ||||
| -rw-r--r-- | include/linux/pci.h | 4 |
3 files changed, 83 insertions, 33 deletions
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 947b5c417e83..122c299e90c8 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h | |||
| @@ -125,7 +125,6 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | |||
| 125 | 125 | ||
| 126 | /* generic pci stuff */ | 126 | /* generic pci stuff */ |
| 127 | #include <asm-generic/pci.h> | 127 | #include <asm-generic/pci.h> |
| 128 | #define PCIBIOS_MAX_MEM_32 0xffffffff | ||
| 129 | 128 | ||
| 130 | #ifdef CONFIG_NUMA | 129 | #ifdef CONFIG_NUMA |
| 131 | /* Returns the node based on pci bus */ | 130 | /* Returns the node based on pci bus */ |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 6f2f47a7b6c6..c30baae929f4 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
| @@ -98,41 +98,52 @@ void pci_bus_remove_resources(struct pci_bus *bus) | |||
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | /** | 101 | static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL}; |
| 102 | * pci_bus_alloc_resource - allocate a resource from a parent bus | 102 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT |
| 103 | * @bus: PCI bus | 103 | static struct pci_bus_region pci_64_bit = {0, |
| 104 | * @res: resource to allocate | 104 | (dma_addr_t) 0xffffffffffffffffULL}; |
| 105 | * @size: size of resource to allocate | 105 | #endif |
| 106 | * @align: alignment of resource to allocate | 106 | |
| 107 | * @min: minimum /proc/iomem address to allocate | 107 | /* |
| 108 | * @type_mask: IORESOURCE_* type flags | 108 | * @res contains CPU addresses. Clip it so the corresponding bus addresses |
| 109 | * @alignf: resource alignment function | 109 | * on @bus are entirely within @region. This is used to control the bus |
| 110 | * @alignf_data: data argument for resource alignment function | 110 | * addresses of resources we allocate, e.g., we may need a resource that |
| 111 | * | 111 | * can be mapped by a 32-bit BAR. |
| 112 | * Given the PCI bus a device resides on, the size, minimum address, | ||
| 113 | * alignment and type, try to find an acceptable resource allocation | ||
| 114 | * for a specific device resource. | ||
| 115 | */ | 112 | */ |
| 116 | int | 113 | static void pci_clip_resource_to_region(struct pci_bus *bus, |
| 117 | pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, | 114 | struct resource *res, |
| 115 | struct pci_bus_region *region) | ||
| 116 | { | ||
| 117 | struct pci_bus_region r; | ||
| 118 | |||
| 119 | pcibios_resource_to_bus(bus, &r, res); | ||
| 120 | if (r.start < region->start) | ||
| 121 | r.start = region->start; | ||
| 122 | if (r.end > region->end) | ||
| 123 | r.end = region->end; | ||
| 124 | |||
| 125 | if (r.end < r.start) | ||
| 126 | res->end = res->start - 1; | ||
| 127 | else | ||
| 128 | pcibios_bus_to_resource(bus, res, &r); | ||
| 129 | } | ||
| 130 | |||
| 131 | static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, | ||
| 118 | resource_size_t size, resource_size_t align, | 132 | resource_size_t size, resource_size_t align, |
| 119 | resource_size_t min, unsigned int type_mask, | 133 | resource_size_t min, unsigned int type_mask, |
| 120 | resource_size_t (*alignf)(void *, | 134 | resource_size_t (*alignf)(void *, |
| 121 | const struct resource *, | 135 | const struct resource *, |
| 122 | resource_size_t, | 136 | resource_size_t, |
| 123 | resource_size_t), | 137 | resource_size_t), |
| 124 | void *alignf_data) | 138 | void *alignf_data, |
| 139 | struct pci_bus_region *region) | ||
| 125 | { | 140 | { |
| 126 | int i, ret = -ENOMEM; | 141 | int i, ret; |
| 127 | struct resource *r; | 142 | struct resource *r, avail; |
| 128 | resource_size_t max = -1; | 143 | resource_size_t max; |
| 129 | 144 | ||
| 130 | type_mask |= IORESOURCE_IO | IORESOURCE_MEM; | 145 | type_mask |= IORESOURCE_IO | IORESOURCE_MEM; |
| 131 | 146 | ||
| 132 | /* don't allocate too high if the pref mem doesn't support 64bit*/ | ||
| 133 | if (!(res->flags & IORESOURCE_MEM_64)) | ||
| 134 | max = PCIBIOS_MAX_MEM_32; | ||
| 135 | |||
| 136 | pci_bus_for_each_resource(bus, r, i) { | 147 | pci_bus_for_each_resource(bus, r, i) { |
| 137 | if (!r) | 148 | if (!r) |
| 138 | continue; | 149 | continue; |
| @@ -147,22 +158,66 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, | |||
| 147 | !(res->flags & IORESOURCE_PREFETCH)) | 158 | !(res->flags & IORESOURCE_PREFETCH)) |
| 148 | continue; | 159 | continue; |
| 149 | 160 | ||
| 161 | avail = *r; | ||
| 162 | pci_clip_resource_to_region(bus, &avail, region); | ||
| 163 | if (!resource_size(&avail)) | ||
| 164 | continue; | ||
| 165 | |||
| 150 | /* | 166 | /* |
| 151 | * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to | 167 | * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to |
| 152 | * protect badly documented motherboard resources, but if | 168 | * protect badly documented motherboard resources, but if |
| 153 | * this is an already-configured bridge window, its start | 169 | * this is an already-configured bridge window, its start |
| 154 | * overrides "min". | 170 | * overrides "min". |
| 155 | */ | 171 | */ |
| 156 | if (r->start) | 172 | if (avail.start) |
| 157 | min = r->start; | 173 | min = avail.start; |
| 174 | |||
| 175 | max = avail.end; | ||
| 158 | 176 | ||
| 159 | /* Ok, try it out.. */ | 177 | /* Ok, try it out.. */ |
| 160 | ret = allocate_resource(r, res, size, min, max, | 178 | ret = allocate_resource(r, res, size, min, max, |
| 161 | align, alignf, alignf_data); | 179 | align, alignf, alignf_data); |
| 162 | if (ret == 0) | 180 | if (ret == 0) |
| 163 | break; | 181 | return 0; |
| 164 | } | 182 | } |
| 165 | return ret; | 183 | return -ENOMEM; |
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * pci_bus_alloc_resource - allocate a resource from a parent bus | ||
| 188 | * @bus: PCI bus | ||
| 189 | * @res: resource to allocate | ||
| 190 | * @size: size of resource to allocate | ||
| 191 | * @align: alignment of resource to allocate | ||
| 192 | * @min: minimum /proc/iomem address to allocate | ||
| 193 | * @type_mask: IORESOURCE_* type flags | ||
| 194 | * @alignf: resource alignment function | ||
| 195 | * @alignf_data: data argument for resource alignment function | ||
| 196 | * | ||
| 197 | * Given the PCI bus a device resides on, the size, minimum address, | ||
| 198 | * alignment and type, try to find an acceptable resource allocation | ||
| 199 | * for a specific device resource. | ||
| 200 | */ | ||
| 201 | int | ||
| 202 | pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, | ||
| 203 | resource_size_t size, resource_size_t align, | ||
| 204 | resource_size_t min, unsigned int type_mask, | ||
| 205 | resource_size_t (*alignf)(void *, | ||
| 206 | const struct resource *, | ||
| 207 | resource_size_t, | ||
| 208 | resource_size_t), | ||
| 209 | void *alignf_data) | ||
| 210 | { | ||
| 211 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
| 212 | if (res->flags & IORESOURCE_MEM_64) | ||
| 213 | return pci_bus_alloc_from_region(bus, res, size, align, min, | ||
| 214 | type_mask, alignf, alignf_data, | ||
| 215 | &pci_64_bit); | ||
| 216 | #endif | ||
| 217 | |||
| 218 | return pci_bus_alloc_from_region(bus, res, size, align, min, | ||
| 219 | type_mask, alignf, alignf_data, | ||
| 220 | &pci_32_bit); | ||
| 166 | } | 221 | } |
| 167 | 222 | ||
| 168 | void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } | 223 | void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 966b286b5d53..095eb44fcbb6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
| @@ -1493,10 +1493,6 @@ static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) | |||
| 1493 | 1493 | ||
| 1494 | #include <asm/pci.h> | 1494 | #include <asm/pci.h> |
| 1495 | 1495 | ||
| 1496 | #ifndef PCIBIOS_MAX_MEM_32 | ||
| 1497 | #define PCIBIOS_MAX_MEM_32 (-1) | ||
| 1498 | #endif | ||
| 1499 | |||
| 1500 | /* these helpers provide future and backwards compatibility | 1496 | /* these helpers provide future and backwards compatibility |
| 1501 | * for accessing popular PCI BAR info */ | 1497 | * for accessing popular PCI BAR info */ |
| 1502 | #define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) | 1498 | #define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) |
