diff options
Diffstat (limited to 'drivers/pci/setup-res.c')
-rw-r--r-- | drivers/pci/setup-res.c | 87 |
1 files changed, 67 insertions, 20 deletions
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 4be7ccf7e3ae..7d35cdf4579f 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c | |||
@@ -137,10 +137,16 @@ int pci_assign_resource(struct pci_dev *dev, int resno) | |||
137 | 137 | ||
138 | size = res->end - res->start + 1; | 138 | size = res->end - res->start + 1; |
139 | min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; | 139 | min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; |
140 | /* The bridge resources are special, as their | 140 | |
141 | size != alignment. Sizing routines return | 141 | align = resource_alignment(res); |
142 | required alignment in the "start" field. */ | 142 | if (!align) { |
143 | align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start; | 143 | printk(KERN_ERR "PCI: Cannot allocate resource (bogus " |
144 | "alignment) %d [%llx:%llx] (flags %lx) of %s\n", | ||
145 | resno, (unsigned long long)res->start, | ||
146 | (unsigned long long)res->end, res->flags, | ||
147 | pci_name(dev)); | ||
148 | return -EINVAL; | ||
149 | } | ||
144 | 150 | ||
145 | /* First, try exact prefetching match.. */ | 151 | /* First, try exact prefetching match.. */ |
146 | ret = pci_bus_alloc_resource(bus, res, size, align, min, | 152 | ret = pci_bus_alloc_resource(bus, res, size, align, min, |
@@ -164,14 +170,16 @@ int pci_assign_resource(struct pci_dev *dev, int resno) | |||
164 | res->flags & IORESOURCE_IO ? "I/O" : "mem", | 170 | res->flags & IORESOURCE_IO ? "I/O" : "mem", |
165 | resno, (unsigned long long)size, | 171 | resno, (unsigned long long)size, |
166 | (unsigned long long)res->start, pci_name(dev)); | 172 | (unsigned long long)res->start, pci_name(dev)); |
167 | } else if (resno < PCI_BRIDGE_RESOURCES) { | 173 | } else { |
168 | pci_update_resource(dev, res, resno); | 174 | res->flags &= ~IORESOURCE_STARTALIGN; |
175 | if (resno < PCI_BRIDGE_RESOURCES) | ||
176 | pci_update_resource(dev, res, resno); | ||
169 | } | 177 | } |
170 | 178 | ||
171 | return ret; | 179 | return ret; |
172 | } | 180 | } |
173 | 181 | ||
174 | #ifdef CONFIG_EMBEDDED | 182 | #if 0 |
175 | int pci_assign_resource_fixed(struct pci_dev *dev, int resno) | 183 | int pci_assign_resource_fixed(struct pci_dev *dev, int resno) |
176 | { | 184 | { |
177 | struct pci_bus *bus = dev->bus; | 185 | struct pci_bus *bus = dev->bus; |
@@ -226,29 +234,25 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | |||
226 | if (r->flags & IORESOURCE_PCI_FIXED) | 234 | if (r->flags & IORESOURCE_PCI_FIXED) |
227 | continue; | 235 | continue; |
228 | 236 | ||
229 | r_align = r->end - r->start; | ||
230 | |||
231 | if (!(r->flags) || r->parent) | 237 | if (!(r->flags) || r->parent) |
232 | continue; | 238 | continue; |
239 | |||
240 | r_align = resource_alignment(r); | ||
233 | if (!r_align) { | 241 | if (!r_align) { |
234 | printk(KERN_WARNING "PCI: Ignore bogus resource %d " | 242 | printk(KERN_WARNING "PCI: bogus alignment of resource " |
235 | "[%llx:%llx] of %s\n", | 243 | "%d [%llx:%llx] (flags %lx) of %s\n", |
236 | i, (unsigned long long)r->start, | 244 | i, (unsigned long long)r->start, |
237 | (unsigned long long)r->end, pci_name(dev)); | 245 | (unsigned long long)r->end, r->flags, |
246 | pci_name(dev)); | ||
238 | continue; | 247 | continue; |
239 | } | 248 | } |
240 | r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start; | ||
241 | for (list = head; ; list = list->next) { | 249 | for (list = head; ; list = list->next) { |
242 | resource_size_t align = 0; | 250 | resource_size_t align = 0; |
243 | struct resource_list *ln = list->next; | 251 | struct resource_list *ln = list->next; |
244 | int idx; | ||
245 | 252 | ||
246 | if (ln) { | 253 | if (ln) |
247 | idx = ln->res - &ln->dev->resource[0]; | 254 | align = resource_alignment(ln->res); |
248 | align = (idx < PCI_BRIDGE_RESOURCES) ? | 255 | |
249 | ln->res->end - ln->res->start + 1 : | ||
250 | ln->res->start; | ||
251 | } | ||
252 | if (r_align > align) { | 256 | if (r_align > align) { |
253 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | 257 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |
254 | if (!tmp) | 258 | if (!tmp) |
@@ -263,3 +267,46 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | |||
263 | } | 267 | } |
264 | } | 268 | } |
265 | } | 269 | } |
270 | |||
271 | int pci_enable_resources(struct pci_dev *dev, int mask) | ||
272 | { | ||
273 | u16 cmd, old_cmd; | ||
274 | int i; | ||
275 | struct resource *r; | ||
276 | |||
277 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
278 | old_cmd = cmd; | ||
279 | |||
280 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | ||
281 | if (!(mask & (1 << i))) | ||
282 | continue; | ||
283 | |||
284 | r = &dev->resource[i]; | ||
285 | |||
286 | if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) | ||
287 | continue; | ||
288 | if ((i == PCI_ROM_RESOURCE) && | ||
289 | (!(r->flags & IORESOURCE_ROM_ENABLE))) | ||
290 | continue; | ||
291 | |||
292 | if (!r->parent) { | ||
293 | dev_err(&dev->dev, "device not available because of " | ||
294 | "BAR %d [%llx:%llx] collisions\n", i, | ||
295 | (unsigned long long) r->start, | ||
296 | (unsigned long long) r->end); | ||
297 | return -EINVAL; | ||
298 | } | ||
299 | |||
300 | if (r->flags & IORESOURCE_IO) | ||
301 | cmd |= PCI_COMMAND_IO; | ||
302 | if (r->flags & IORESOURCE_MEM) | ||
303 | cmd |= PCI_COMMAND_MEMORY; | ||
304 | } | ||
305 | |||
306 | if (cmd != old_cmd) { | ||
307 | dev_info(&dev->dev, "enabling device (%04x -> %04x)\n", | ||
308 | old_cmd, cmd); | ||
309 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
310 | } | ||
311 | return 0; | ||
312 | } | ||