Commit 884525655d07fdee9245716b998ecdc45cdd8007
Committed by
Greg Kroah-Hartman
1 parent
d75b305295
Exists in
master
and in
4 other branches
PCI: clean up resource alignment management
Done per Linus' request and suggestions. Linus has explained that better than I'll be able to explain: On Thu, Mar 27, 2008 at 10:12:10AM -0700, Linus Torvalds wrote: > Actually, before we go any further, there might be a less intrusive > alternative: add just a couple of flags to the resource flags field (we > still have something like 8 unused bits on 32-bit), and use those to > implement a generic "resource_alignment()" routine. > > Two flags would do it: > > - IORESOURCE_SIZEALIGN: size indicates alignment (regular PCI device > resources) > > - IORESOURCE_STARTALIGN: start field is alignment (PCI bus resources > during probing) > > and then the case of both flags zero (or both bits set) would actually be > "invalid", and we would also clear the IORESOURCE_STARTALIGN flag when we > actually allocate the resource (so that we don't use the "start" field as > alignment incorrectly when it no longer indicates alignment). > > That wouldn't be totally generic, but it would have the nice property of > automatically at least add sanity checking for that whole "res->start has > the odd meaning of 'alignment' during probing" and remove the need for a > new field, and it would allow us to have a generic "resource_alignment()" > routine that just gets a resource pointer. Besides, I removed IORESOURCE_BUS_HAS_VGA flag which was unused for ages. Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Gary Hade <garyhade@us.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 5 changed files with 51 additions and 22 deletions Side-by-side Diff
drivers/pci/probe.c
... | ... | @@ -235,7 +235,7 @@ |
235 | 235 | res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; |
236 | 236 | } |
237 | 237 | res->end = res->start + (unsigned long) sz; |
238 | - res->flags |= pci_calc_resource_flags(l); | |
238 | + res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; | |
239 | 239 | if (is_64bit_memory(l)) { |
240 | 240 | u32 szhi, lhi; |
241 | 241 | |
... | ... | @@ -288,7 +288,8 @@ |
288 | 288 | if (sz) { |
289 | 289 | res->flags = (l & IORESOURCE_ROM_ENABLE) | |
290 | 290 | IORESOURCE_MEM | IORESOURCE_PREFETCH | |
291 | - IORESOURCE_READONLY | IORESOURCE_CACHEABLE; | |
291 | + IORESOURCE_READONLY | IORESOURCE_CACHEABLE | | |
292 | + IORESOURCE_SIZEALIGN; | |
292 | 293 | res->start = l & PCI_ROM_ADDRESS_MASK; |
293 | 294 | res->end = res->start + (unsigned long) sz; |
294 | 295 | } |
drivers/pci/setup-bus.c
... | ... | @@ -65,6 +65,7 @@ |
65 | 65 | res = list->res; |
66 | 66 | idx = res - &list->dev->resource[0]; |
67 | 67 | if (pci_assign_resource(list->dev, idx)) { |
68 | + /* FIXME: get rid of this */ | |
68 | 69 | res->start = 0; |
69 | 70 | res->end = 0; |
70 | 71 | res->flags = 0; |
... | ... | @@ -327,6 +328,7 @@ |
327 | 328 | /* Alignment of the IO window is always 4K */ |
328 | 329 | b_res->start = 4096; |
329 | 330 | b_res->end = b_res->start + size - 1; |
331 | + b_res->flags |= IORESOURCE_STARTALIGN; | |
330 | 332 | } |
331 | 333 | |
332 | 334 | /* Calculate the size of the bus and minimal alignment which |
... | ... | @@ -401,6 +403,7 @@ |
401 | 403 | } |
402 | 404 | b_res->start = min_align; |
403 | 405 | b_res->end = size + min_align - 1; |
406 | + b_res->flags |= IORESOURCE_STARTALIGN; | |
404 | 407 | return 1; |
405 | 408 | } |
406 | 409 |
drivers/pci/setup-res.c
... | ... | @@ -137,11 +137,17 @@ |
137 | 137 | |
138 | 138 | size = res->end - res->start + 1; |
139 | 139 | min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; |
140 | - /* The bridge resources are special, as their | |
141 | - size != alignment. Sizing routines return | |
142 | - required alignment in the "start" field. */ | |
143 | - align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start; | |
144 | 140 | |
141 | + align = resource_alignment(res); | |
142 | + if (!align) { | |
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 | + } | |
150 | + | |
145 | 151 | /* First, try exact prefetching match.. */ |
146 | 152 | ret = pci_bus_alloc_resource(bus, res, size, align, min, |
147 | 153 | IORESOURCE_PREFETCH, |
... | ... | @@ -164,8 +170,10 @@ |
164 | 170 | res->flags & IORESOURCE_IO ? "I/O" : "mem", |
165 | 171 | resno, (unsigned long long)size, |
166 | 172 | (unsigned long long)res->start, pci_name(dev)); |
167 | - } else if (resno < PCI_BRIDGE_RESOURCES) { | |
168 | - pci_update_resource(dev, res, resno); | |
173 | + } else { | |
174 | + res->flags &= ~IORESOURCE_STARTALIGN; | |
175 | + if (resno < PCI_BRIDGE_RESOURCES) | |
176 | + pci_update_resource(dev, res, resno); | |
169 | 177 | } |
170 | 178 | |
171 | 179 | return ret; |
172 | 180 | |
173 | 181 | |
174 | 182 | |
175 | 183 | |
176 | 184 | |
177 | 185 | |
... | ... | @@ -226,29 +234,25 @@ |
226 | 234 | if (r->flags & IORESOURCE_PCI_FIXED) |
227 | 235 | continue; |
228 | 236 | |
229 | - r_align = r->end - r->start; | |
230 | - | |
231 | 237 | if (!(r->flags) || r->parent) |
232 | 238 | continue; |
239 | + | |
240 | + r_align = resource_alignment(r); | |
233 | 241 | if (!r_align) { |
234 | - printk(KERN_WARNING "PCI: Ignore bogus resource %d " | |
235 | - "[%llx:%llx] of %s\n", | |
242 | + printk(KERN_WARNING "PCI: bogus alignment of resource " | |
243 | + "%d [%llx:%llx] (flags %lx) of %s\n", | |
236 | 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 | 247 | continue; |
239 | 248 | } |
240 | - r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start; | |
241 | 249 | for (list = head; ; list = list->next) { |
242 | 250 | resource_size_t align = 0; |
243 | 251 | struct resource_list *ln = list->next; |
244 | - int idx; | |
245 | 252 | |
246 | - if (ln) { | |
247 | - idx = ln->res - &ln->dev->resource[0]; | |
248 | - align = (idx < PCI_BRIDGE_RESOURCES) ? | |
249 | - ln->res->end - ln->res->start + 1 : | |
250 | - ln->res->start; | |
251 | - } | |
253 | + if (ln) | |
254 | + align = resource_alignment(ln->res); | |
255 | + | |
252 | 256 | if (r_align > align) { |
253 | 257 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |
254 | 258 | if (!tmp) |
include/linux/ioport.h
... | ... | @@ -44,8 +44,10 @@ |
44 | 44 | #define IORESOURCE_CACHEABLE 0x00004000 |
45 | 45 | #define IORESOURCE_RANGELENGTH 0x00008000 |
46 | 46 | #define IORESOURCE_SHADOWABLE 0x00010000 |
47 | -#define IORESOURCE_BUS_HAS_VGA 0x00080000 | |
48 | 47 | |
48 | +#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */ | |
49 | +#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ | |
50 | + | |
49 | 51 | #define IORESOURCE_DISABLED 0x10000000 |
50 | 52 | #define IORESOURCE_UNSET 0x20000000 |
51 | 53 | #define IORESOURCE_AUTO 0x40000000 |
... | ... | @@ -110,6 +112,7 @@ |
110 | 112 | void *alignf_data); |
111 | 113 | int adjust_resource(struct resource *res, resource_size_t start, |
112 | 114 | resource_size_t size); |
115 | +resource_size_t resource_alignment(struct resource *res); | |
113 | 116 | |
114 | 117 | /* Convenience shorthand with allocation */ |
115 | 118 | #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) |
kernel/resource.c
... | ... | @@ -486,6 +486,24 @@ |
486 | 486 | |
487 | 487 | EXPORT_SYMBOL(adjust_resource); |
488 | 488 | |
489 | +/** | |
490 | + * resource_alignment - calculate resource's alignment | |
491 | + * @res: resource pointer | |
492 | + * | |
493 | + * Returns alignment on success, 0 (invalid alignment) on failure. | |
494 | + */ | |
495 | +resource_size_t resource_alignment(struct resource *res) | |
496 | +{ | |
497 | + switch (res->flags & (IORESOURCE_SIZEALIGN | IORESOURCE_STARTALIGN)) { | |
498 | + case IORESOURCE_SIZEALIGN: | |
499 | + return res->end - res->start + 1; | |
500 | + case IORESOURCE_STARTALIGN: | |
501 | + return res->start; | |
502 | + default: | |
503 | + return 0; | |
504 | + } | |
505 | +} | |
506 | + | |
489 | 507 | /* |
490 | 508 | * This is compatibility stuff for IO resources. |
491 | 509 | * |