Merge branch 'omap-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind...
[cascardo/linux.git] / lib / lmb.c
index 896e283..83287d3 100644 (file)
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -46,14 +46,13 @@ void lmb_dump_all(void)
 #endif /* DEBUG */
 }
 
-static unsigned long __init lmb_addrs_overlap(u64 base1, u64 size1,
-               u64 base2, u64 size2)
+static unsigned long lmb_addrs_overlap(u64 base1, u64 size1, u64 base2,
+                                       u64 size2)
 {
        return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
 }
 
-static long __init lmb_addrs_adjacent(u64 base1, u64 size1,
-               u64 base2, u64 size2)
+static long lmb_addrs_adjacent(u64 base1, u64 size1, u64 base2, u64 size2)
 {
        if (base2 == base1 + size1)
                return 1;
@@ -63,7 +62,7 @@ static long __init lmb_addrs_adjacent(u64 base1, u64 size1,
        return 0;
 }
 
-static long __init lmb_regions_adjacent(struct lmb_region *rgn,
+static long lmb_regions_adjacent(struct lmb_region *rgn,
                unsigned long r1, unsigned long r2)
 {
        u64 base1 = rgn->region[r1].base;
@@ -74,7 +73,7 @@ static long __init lmb_regions_adjacent(struct lmb_region *rgn,
        return lmb_addrs_adjacent(base1, size1, base2, size2);
 }
 
-static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r)
+static void lmb_remove_region(struct lmb_region *rgn, unsigned long r)
 {
        unsigned long i;
 
@@ -86,7 +85,7 @@ static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r)
 }
 
 /* Assumption: base addr of region 1 < base addr of region 2 */
-static void __init lmb_coalesce_regions(struct lmb_region *rgn,
+static void lmb_coalesce_regions(struct lmb_region *rgn,
                unsigned long r1, unsigned long r2)
 {
        rgn->region[r1].size += rgn->region[r2].size;
@@ -118,7 +117,7 @@ void __init lmb_analyze(void)
                lmb.memory.size += lmb.memory.region[i].size;
 }
 
-static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
+static long lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
 {
        unsigned long coalesced = 0;
        long adjacent, i;
@@ -182,7 +181,7 @@ static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
        return 0;
 }
 
-long __init lmb_add(u64 base, u64 size)
+long lmb_add(u64 base, u64 size)
 {
        struct lmb_region *_rgn = &lmb.memory;
 
@@ -194,6 +193,55 @@ long __init lmb_add(u64 base, u64 size)
 
 }
 
+long lmb_remove(u64 base, u64 size)
+{
+       struct lmb_region *rgn = &(lmb.memory);
+       u64 rgnbegin, rgnend;
+       u64 end = base + size;
+       int i;
+
+       rgnbegin = rgnend = 0; /* supress gcc warnings */
+
+       /* Find the region where (base, size) belongs to */
+       for (i=0; i < rgn->cnt; i++) {
+               rgnbegin = rgn->region[i].base;
+               rgnend = rgnbegin + rgn->region[i].size;
+
+               if ((rgnbegin <= base) && (end <= rgnend))
+                       break;
+       }
+
+       /* Didn't find the region */
+       if (i == rgn->cnt)
+               return -1;
+
+       /* Check to see if we are removing entire region */
+       if ((rgnbegin == base) && (rgnend == end)) {
+               lmb_remove_region(rgn, i);
+               return 0;
+       }
+
+       /* Check to see if region is matching at the front */
+       if (rgnbegin == base) {
+               rgn->region[i].base = end;
+               rgn->region[i].size -= size;
+               return 0;
+       }
+
+       /* Check to see if the region is matching at the end */
+       if (rgnend == end) {
+               rgn->region[i].size -= size;
+               return 0;
+       }
+
+       /*
+        * We need to split the entry -  adjust the current one to the
+        * beginging of the hole and add the region after hole.
+        */
+       rgn->region[i].size = base - rgn->region[i].base;
+       return lmb_add_region(rgn, end, rgnend - end);
+}
+
 long __init lmb_reserve(u64 base, u64 size)
 {
        struct lmb_region *_rgn = &lmb.reserved;
@@ -346,7 +394,7 @@ u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr)
                        if (j < 0) {
                                /* this area isn't reserved, take it */
                                if (lmb_add_region(&lmb.reserved, base,
-                                                  size) < 0)
+                                                  lmb_align_up(size, align)) < 0)
                                        return 0;
                                return base;
                        }
@@ -426,3 +474,36 @@ int __init lmb_is_reserved(u64 addr)
        }
        return 0;
 }
+
+/*
+ * Given a <base, len>, find which memory regions belong to this range.
+ * Adjust the request and return a contiguous chunk.
+ */
+int lmb_find(struct lmb_property *res)
+{
+       int i;
+       u64 rstart, rend;
+
+       rstart = res->base;
+       rend = rstart + res->size - 1;
+
+       for (i = 0; i < lmb.memory.cnt; i++) {
+               u64 start = lmb.memory.region[i].base;
+               u64 end = start + lmb.memory.region[i].size - 1;
+
+               if (start > rend)
+                       return -1;
+
+               if ((end >= rstart) && (start < rend)) {
+                       /* adjust the request */
+                       if (rstart < start)
+                               rstart = start;
+                       if (rend > end)
+                               rend = end;
+                       res->base = rstart;
+                       res->size = rend - rstart + 1;
+                       return 0;
+               }
+       }
+       return -1;
+}