Commit 884525655d07fdee9245716b998ecdc45cdd8007

Authored by Ivan Kokshaysky
Committed by Greg Kroah-Hartman
1 parent d75b305295

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

... ... @@ -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))
... ... @@ -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 *