aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/lmb.c56
1 files changed, 30 insertions, 26 deletions
diff --git a/lib/lmb.c b/lib/lmb.c
index e4bbc617f46..896e2832099 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -230,20 +230,23 @@ static u64 lmb_align_up(u64 addr, u64 size)
static u64 __init lmb_alloc_nid_unreserved(u64 start, u64 end,
u64 size, u64 align)
{
- u64 base;
+ u64 base, res_base;
long j;
base = lmb_align_down((end - size), align);
- while (start <= base &&
- ((j = lmb_overlaps_region(&lmb.reserved, base, size)) >= 0))
- base = lmb_align_down(lmb.reserved.region[j].base - size,
- align);
-
- if (base != 0 && start <= base) {
- if (lmb_add_region(&lmb.reserved, base,
- lmb_align_up(size, align)) < 0)
- base = ~(u64)0;
- return base;
+ while (start <= base) {
+ j = lmb_overlaps_region(&lmb.reserved, base, size);
+ if (j < 0) {
+ /* this area isn't reserved, take it */
+ if (lmb_add_region(&lmb.reserved, base,
+ lmb_align_up(size, align)) < 0)
+ base = ~(u64)0;
+ return base;
+ }
+ res_base = lmb.reserved.region[j].base;
+ if (res_base < size)
+ break;
+ base = lmb_align_down(res_base - size, align);
}
return ~(u64)0;
@@ -315,10 +318,12 @@ u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr)
{
long i, j;
u64 base = 0;
+ u64 res_base;
BUG_ON(0 == size);
/* On some platforms, make sure we allocate lowmem */
+ /* Note that LMB_REAL_LIMIT may be LMB_ALLOC_ANYWHERE */
if (max_addr == LMB_ALLOC_ANYWHERE)
max_addr = LMB_REAL_LIMIT;
@@ -326,6 +331,8 @@ u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr)
u64 lmbbase = lmb.memory.region[i].base;
u64 lmbsize = lmb.memory.region[i].size;
+ if (lmbsize < size)
+ continue;
if (max_addr == LMB_ALLOC_ANYWHERE)
base = lmb_align_down(lmbbase + lmbsize - size, align);
else if (lmbbase < max_addr) {
@@ -334,25 +341,22 @@ u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr)
} else
continue;
- while (lmbbase <= base) {
+ while (base && lmbbase <= base) {
j = lmb_overlaps_region(&lmb.reserved, base, size);
- if (j < 0)
+ if (j < 0) {
+ /* this area isn't reserved, take it */
+ if (lmb_add_region(&lmb.reserved, base,
+ size) < 0)
+ return 0;
+ return base;
+ }
+ res_base = lmb.reserved.region[j].base;
+ if (res_base < size)
break;
- base = lmb_align_down(lmb.reserved.region[j].base - size,
- align);
+ base = lmb_align_down(res_base - size, align);
}
-
- if ((base != 0) && (lmbbase <= base))
- break;
}
-
- if (i < 0)
- return 0;
-
- if (lmb_add_region(&lmb.reserved, base, lmb_align_up(size, align)) < 0)
- return 0;
-
- return base;
+ return 0;
}
/* You must call lmb_analyze() before this. */