Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ivan Kokshaysky and committed by
Greg Kroah-Hartman
88452565 d75b3052

+51 -22
+3 -2
drivers/pci/probe.c
··· 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 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 }
+3
drivers/pci/setup-bus.c
··· 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; ··· 328 327 /* Alignment of the IO window is always 4K */ 329 328 b_res->start = 4096; 330 329 b_res->end = b_res->start + size - 1; 330 + b_res->flags |= IORESOURCE_STARTALIGN; 331 331 } 332 332 333 333 /* Calculate the size of the bus and minimal alignment which ··· 403 401 } 404 402 b_res->start = min_align; 405 403 b_res->end = size + min_align - 1; 404 + b_res->flags |= IORESOURCE_STARTALIGN; 406 405 return 1; 407 406 } 408 407
+23 -19
drivers/pci/setup-res.c
··· 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; 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 + } 144 150 145 151 /* First, try exact prefetching match.. */ 146 152 ret = pci_bus_alloc_resource(bus, res, size, align, min, ··· 170 164 res->flags & IORESOURCE_IO ? "I/O" : "mem", 171 165 resno, (unsigned long long)size, 172 166 (unsigned long long)res->start, pci_name(dev)); 173 - } else if (resno < PCI_BRIDGE_RESOURCES) { 174 - pci_update_resource(dev, res, resno); 167 + } else { 168 + res->flags &= ~IORESOURCE_STARTALIGN; 169 + if (resno < PCI_BRIDGE_RESOURCES) 170 + pci_update_resource(dev, res, resno); 175 171 } 176 172 177 173 return ret; ··· 234 226 if (r->flags & IORESOURCE_PCI_FIXED) 235 227 continue; 236 228 237 - r_align = r->end - r->start; 238 - 239 229 if (!(r->flags) || r->parent) 240 230 continue; 231 + 232 + r_align = resource_alignment(r); 241 233 if (!r_align) { 242 - printk(KERN_WARNING "PCI: Ignore bogus resource %d " 243 - "[%llx:%llx] of %s\n", 234 + printk(KERN_WARNING "PCI: bogus alignment of resource " 235 + "%d [%llx:%llx] (flags %lx) of %s\n", 244 236 i, (unsigned long long)r->start, 245 - (unsigned long long)r->end, pci_name(dev)); 237 + (unsigned long long)r->end, r->flags, 238 + pci_name(dev)); 246 239 continue; 247 240 } 248 - r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start; 249 241 for (list = head; ; list = list->next) { 250 242 resource_size_t align = 0; 251 243 struct resource_list *ln = list->next; 252 - int idx; 253 244 254 - if (ln) { 255 - idx = ln->res - &ln->dev->resource[0]; 256 - align = (idx < PCI_BRIDGE_RESOURCES) ? 257 - ln->res->end - ln->res->start + 1 : 258 - ln->res->start; 259 - } 245 + if (ln) 246 + align = resource_alignment(ln->res); 247 + 260 248 if (r_align > align) { 261 249 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 262 250 if (!tmp)
+4 -1
include/linux/ioport.h
··· 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 47 + 48 + #define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */ 49 + #define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ 48 50 49 51 #define IORESOURCE_DISABLED 0x10000000 50 52 #define IORESOURCE_UNSET 0x20000000 ··· 112 110 void *alignf_data); 113 111 int adjust_resource(struct resource *res, resource_size_t start, 114 112 resource_size_t size); 113 + resource_size_t resource_alignment(struct resource *res); 115 114 116 115 /* Convenience shorthand with allocation */ 117 116 #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
+18
kernel/resource.c
··· 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 *