aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/pci.h1
-rw-r--r--drivers/pci/bus.c111
-rw-r--r--include/linux/pci.h4
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/** 101static 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 103static 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 */
116int 113static void pci_clip_resource_to_region(struct pci_bus *bus,
117pci_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
131static 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 */
201int
202pci_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
168void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } 223void __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)