aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2010-10-26 17:41:33 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-10-26 18:33:31 -0400
commite7f8567db9a7f6b3151b0b275e245c1cef0d9c70 (patch)
treef04a01581e86ec2b8c175b9f27648679c70d592c /kernel
parenta1862e31079149a52b6223776228c3aee493d4a7 (diff)
resources: support allocating space within a region from the top down
Allocate space from the top of a region first, then work downward, if an architecture desires this. When we allocate space from a resource, we look for gaps between children of the resource. Previously, we always looked at gaps from the bottom up. For example, given this: [mem 0xbff00000-0xf7ffffff] PCI Bus 0000:00 [mem 0xbff00000-0xbfffffff] gap -- available [mem 0xc0000000-0xdfffffff] PCI Bus 0000:02 [mem 0xe0000000-0xf7ffffff] gap -- available we attempted to allocate from the [mem 0xbff00000-0xbfffffff] gap first, then the [mem 0xe0000000-0xf7ffffff] gap. With this patch an architecture can choose to allocate from the top gap [mem 0xe0000000-0xf7ffffff] first. We can't do this across the board because iomem_resource.end is initialized to 0xffffffff_ffffffff on 64-bit architectures, and most machines can't address the entire 64-bit physical address space. Therefore, we only allocate top-down if the arch requests it by clearing "resource_alloc_from_bottom". Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/resource.c98
1 files changed, 94 insertions, 4 deletions
diff --git a/kernel/resource.c b/kernel/resource.c
index e15b922d4ba4..716b6804077e 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -40,6 +40,23 @@ EXPORT_SYMBOL(iomem_resource);
40 40
41static DEFINE_RWLOCK(resource_lock); 41static DEFINE_RWLOCK(resource_lock);
42 42
43/*
44 * By default, we allocate free space bottom-up. The architecture can request
45 * top-down by clearing this flag. The user can override the architecture's
46 * choice with the "resource_alloc_from_bottom" kernel boot option, but that
47 * should only be a debugging tool.
48 */
49int resource_alloc_from_bottom = 1;
50
51static __init int setup_alloc_from_bottom(char *s)
52{
53 printk(KERN_INFO
54 "resource: allocating from bottom-up; please report a bug\n");
55 resource_alloc_from_bottom = 1;
56 return 0;
57}
58early_param("resource_alloc_from_bottom", setup_alloc_from_bottom);
59
43static void *r_next(struct seq_file *m, void *v, loff_t *pos) 60static void *r_next(struct seq_file *m, void *v, loff_t *pos)
44{ 61{
45 struct resource *p = v; 62 struct resource *p = v;
@@ -380,7 +397,74 @@ static bool resource_contains(struct resource *res1, struct resource *res2)
380} 397}
381 398
382/* 399/*
400 * Find the resource before "child" in the sibling list of "root" children.
401 */
402static struct resource *find_sibling_prev(struct resource *root, struct resource *child)
403{
404 struct resource *this;
405
406 for (this = root->child; this; this = this->sibling)
407 if (this->sibling == child)
408 return this;
409
410 return NULL;
411}
412
413/*
414 * Find empty slot in the resource tree given range and alignment.
415 * This version allocates from the end of the root resource first.
416 */
417static int find_resource_from_top(struct resource *root, struct resource *new,
418 resource_size_t size, resource_size_t min,
419 resource_size_t max, resource_size_t align,
420 resource_size_t (*alignf)(void *,
421 const struct resource *,
422 resource_size_t,
423 resource_size_t),
424 void *alignf_data)
425{
426 struct resource *this;
427 struct resource tmp, avail, alloc;
428
429 tmp.start = root->end;
430 tmp.end = root->end;
431
432 this = find_sibling_prev(root, NULL);
433 for (;;) {
434 if (this) {
435 if (this->end < root->end)
436 tmp.start = this->end + 1;
437 } else
438 tmp.start = root->start;
439
440 resource_clip(&tmp, min, max);
441
442 /* Check for overflow after ALIGN() */
443 avail = *new;
444 avail.start = ALIGN(tmp.start, align);
445 avail.end = tmp.end;
446 if (avail.start >= tmp.start) {
447 alloc.start = alignf(alignf_data, &avail, size, align);
448 alloc.end = alloc.start + size - 1;
449 if (resource_contains(&avail, &alloc)) {
450 new->start = alloc.start;
451 new->end = alloc.end;
452 return 0;
453 }
454 }
455
456 if (!this || this->start == root->start)
457 break;
458
459 tmp.end = this->start - 1;
460 this = find_sibling_prev(root, this);
461 }
462 return -EBUSY;
463}
464
465/*
383 * Find empty slot in the resource tree given range and alignment. 466 * Find empty slot in the resource tree given range and alignment.
467 * This version allocates from the beginning of the root resource first.
384 */ 468 */
385static int find_resource(struct resource *root, struct resource *new, 469static int find_resource(struct resource *root, struct resource *new,
386 resource_size_t size, resource_size_t min, 470 resource_size_t size, resource_size_t min,
@@ -396,14 +480,15 @@ static int find_resource(struct resource *root, struct resource *new,
396 480
397 tmp.start = root->start; 481 tmp.start = root->start;
398 /* 482 /*
399 * Skip past an allocated resource that starts at 0, since the assignment 483 * Skip past an allocated resource that starts at 0, since the
400 * of this->start - 1 to tmp->end below would cause an underflow. 484 * assignment of this->start - 1 to tmp->end below would cause an
485 * underflow.
401 */ 486 */
402 if (this && this->start == 0) { 487 if (this && this->start == 0) {
403 tmp.start = this->end + 1; 488 tmp.start = this->end + 1;
404 this = this->sibling; 489 this = this->sibling;
405 } 490 }
406 for(;;) { 491 for (;;) {
407 if (this) 492 if (this)
408 tmp.end = this->start - 1; 493 tmp.end = this->start - 1;
409 else 494 else
@@ -424,8 +509,10 @@ static int find_resource(struct resource *root, struct resource *new,
424 return 0; 509 return 0;
425 } 510 }
426 } 511 }
512
427 if (!this) 513 if (!this)
428 break; 514 break;
515
429 tmp.start = this->end + 1; 516 tmp.start = this->end + 1;
430 this = this->sibling; 517 this = this->sibling;
431 } 518 }
@@ -458,7 +545,10 @@ int allocate_resource(struct resource *root, struct resource *new,
458 alignf = simple_align_resource; 545 alignf = simple_align_resource;
459 546
460 write_lock(&resource_lock); 547 write_lock(&resource_lock);
461 err = find_resource(root, new, size, min, max, align, alignf, alignf_data); 548 if (resource_alloc_from_bottom)
549 err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
550 else
551 err = find_resource_from_top(root, new, size, min, max, align, alignf, alignf_data);
462 if (err >= 0 && __request_resource(root, new)) 552 if (err >= 0 && __request_resource(root, new))
463 err = -EBUSY; 553 err = -EBUSY;
464 write_unlock(&resource_lock); 554 write_unlock(&resource_lock);