Add lmb_free
authorAndy Fleming <afleming@freescale.com>
Mon, 16 Jun 2008 18:58:54 +0000 (13:58 -0500)
committerWolfgang Denk <wd@denx.de>
Sat, 28 Jun 2008 20:21:38 +0000 (22:21 +0200)
lmb_free allows us to unreserve some memory so we can use lmb_alloc_base or
lmb_reserve to temporarily reserve some memory.

Signed-off-by: Andy Fleming <afleming@freescale.com>
lib_generic/lmb.c

index afe33197dec7e7b75521c8af475f63218b9839bf..3240f66bf98906c890f42b37e071352c9a98f935 100644 (file)
@@ -181,6 +181,55 @@ long lmb_add(struct lmb *lmb, phys_addr_t base, phys_size_t size)
        return lmb_add_region(_rgn, base, size);
 }
 
+long lmb_free(struct lmb *lmb, u64 base, u64 size)
+{
+       struct lmb_region *rgn = &(lmb->reserved);
+       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 lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size)
 {
        struct lmb_region *_rgn = &(lmb->reserved);