diff options
author | Ivan Kokshaysky <ink@jurassic.park.msu.ru> | 2008-03-30 11:50:14 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-04-21 00:47:08 -0400 |
commit | 884525655d07fdee9245716b998ecdc45cdd8007 (patch) | |
tree | 975cbf2b5079430240d3496323df1a266be95d27 | |
parent | d75b305295c38ba9610ff3b2200f7d1989dc55fd (diff) |
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>
-rw-r--r-- | drivers/pci/probe.c | 5 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 3 | ||||
-rw-r--r-- | drivers/pci/setup-res.c | 42 | ||||
-rw-r--r-- | include/linux/ioport.h | 5 | ||||
-rw-r--r-- | kernel/resource.c | 18 |
5 files changed, 51 insertions, 22 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c2e99fd87faf..33d9b8bea6e0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -235,7 +235,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
235 | res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; | 235 | res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; |
236 | } | 236 | } |
237 | res->end = res->start + (unsigned long) sz; | 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 | if (is_64bit_memory(l)) { | 239 | if (is_64bit_memory(l)) { |
240 | u32 szhi, lhi; | 240 | u32 szhi, lhi; |
241 | 241 | ||
@@ -288,7 +288,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
288 | if (sz) { | 288 | if (sz) { |
289 | res->flags = (l & IORESOURCE_ROM_ENABLE) | | 289 | res->flags = (l & IORESOURCE_ROM_ENABLE) | |
290 | IORESOURCE_MEM | IORESOURCE_PREFETCH | | 290 | IORESOURCE_MEM | IORESOURCE_PREFETCH | |
291 | IORESOURCE_READONLY | IORESOURCE_CACHEABLE; | 291 | IORESOURCE_READONLY | IORESOURCE_CACHEABLE | |
292 | IORESOURCE_SIZEALIGN; | ||
292 | res->start = l & PCI_ROM_ADDRESS_MASK; | 293 | res->start = l & PCI_ROM_ADDRESS_MASK; |
293 | res->end = res->start + (unsigned long) sz; | 294 | res->end = res->start + (unsigned long) sz; |
294 | } | 295 | } |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index f7cb8e0758b4..5cf84568c9e4 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -65,6 +65,7 @@ static void pbus_assign_resources_sorted(struct pci_bus *bus) | |||
65 | res = list->res; | 65 | res = list->res; |
66 | idx = res - &list->dev->resource[0]; | 66 | idx = res - &list->dev->resource[0]; |
67 | if (pci_assign_resource(list->dev, idx)) { | 67 | if (pci_assign_resource(list->dev, idx)) { |
68 | /* FIXME: get rid of this */ | ||
68 | res->start = 0; | 69 | res->start = 0; |
69 | res->end = 0; | 70 | res->end = 0; |
70 | res->flags = 0; | 71 | res->flags = 0; |
@@ -327,6 +328,7 @@ static void pbus_size_io(struct pci_bus *bus) | |||
327 | /* Alignment of the IO window is always 4K */ | 328 | /* Alignment of the IO window is always 4K */ |
328 | b_res->start = 4096; | 329 | b_res->start = 4096; |
329 | b_res->end = b_res->start + size - 1; | 330 | b_res->end = b_res->start + size - 1; |
331 | b_res->flags |= IORESOURCE_STARTALIGN; | ||
330 | } | 332 | } |
331 | 333 | ||
332 | /* Calculate the size of the bus and minimal alignment which | 334 | /* Calculate the size of the bus and minimal alignment which |
@@ -401,6 +403,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
401 | } | 403 | } |
402 | b_res->start = min_align; | 404 | b_res->start = min_align; |
403 | b_res->end = size + min_align - 1; | 405 | b_res->end = size + min_align - 1; |
406 | b_res->flags |= IORESOURCE_STARTALIGN; | ||
404 | return 1; | 407 | return 1; |
405 | } | 408 | } |
406 | 409 | ||
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index bad509e40fbc..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,8 +170,10 @@ 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; |
@@ -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) |
diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 605d237364d2..d5d40a9f7929 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h | |||
@@ -44,7 +44,9 @@ struct resource_list { | |||
44 | #define IORESOURCE_CACHEABLE 0x00004000 | 44 | #define IORESOURCE_CACHEABLE 0x00004000 |
45 | #define IORESOURCE_RANGELENGTH 0x00008000 | 45 | #define IORESOURCE_RANGELENGTH 0x00008000 |
46 | #define IORESOURCE_SHADOWABLE 0x00010000 | 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 | #define IORESOURCE_DISABLED 0x10000000 | 51 | #define IORESOURCE_DISABLED 0x10000000 |
50 | #define IORESOURCE_UNSET 0x20000000 | 52 | #define IORESOURCE_UNSET 0x20000000 |
@@ -110,6 +112,7 @@ extern int allocate_resource(struct resource *root, struct resource *new, | |||
110 | void *alignf_data); | 112 | void *alignf_data); |
111 | int adjust_resource(struct resource *res, resource_size_t start, | 113 | int adjust_resource(struct resource *res, resource_size_t start, |
112 | resource_size_t size); | 114 | resource_size_t size); |
115 | resource_size_t resource_alignment(struct resource *res); | ||
113 | 116 | ||
114 | /* Convenience shorthand with allocation */ | 117 | /* Convenience shorthand with allocation */ |
115 | #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) | 118 | #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) |
diff --git a/kernel/resource.c b/kernel/resource.c index 82aea814d409..cee12cc47cab 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -486,6 +486,24 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t | |||
486 | 486 | ||
487 | EXPORT_SYMBOL(adjust_resource); | 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 | * This is compatibility stuff for IO resources. | 508 | * This is compatibility stuff for IO resources. |
491 | * | 509 | * |