summaryrefslogtreecommitdiff
path: root/lib_generic/lmb.c
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2008-07-06 01:15:17 +0200
committerWolfgang Denk <wd@denx.de>2008-07-06 01:15:17 +0200
commitd86a0a6f7fe433787edf06aecba9fd6abfecab48 (patch)
tree005ba8a000e7bdcab42c1df6339bf7e51dcda2ca /lib_generic/lmb.c
parenta524e112b424c6843800ea2f19d3a8cf01d0aa94 (diff)
parentf492dd636fbbae529e17533995bc6e5813c007f6 (diff)
downloadu-boot-imx-d86a0a6f7fe433787edf06aecba9fd6abfecab48.zip
u-boot-imx-d86a0a6f7fe433787edf06aecba9fd6abfecab48.tar.gz
u-boot-imx-d86a0a6f7fe433787edf06aecba9fd6abfecab48.tar.bz2
Merge branch 'master' of ssh+git://mercury.denx.de/home/wd/git/u-boot/master
Conflicts: board/amirix/ap1000/serial.c board/exbitgen/exbitgen.c board/exbitgen/flash.c board/ml2/serial.c board/xilinx/ml300/serial.c Signed-off-by: Wolfgang Denk <wd@denx.de>
Diffstat (limited to 'lib_generic/lmb.c')
-rw-r--r--lib_generic/lmb.c83
1 files changed, 68 insertions, 15 deletions
diff --git a/lib_generic/lmb.c b/lib_generic/lmb.c
index afe3319..93264c1 100644
--- a/lib_generic/lmb.c
+++ b/lib_generic/lmb.c
@@ -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);
@@ -236,11 +285,14 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy
{
long i, j;
phys_addr_t base = 0;
+ phys_addr_t res_base;
for (i = lmb->memory.cnt-1; i >= 0; i--) {
phys_addr_t lmbbase = lmb->memory.region[i].base;
phys_size_t 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) {
@@ -249,22 +301,23 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy
} else
continue;
- while ((lmbbase <= base) &&
- ((j = lmb_overlaps_region(&(lmb->reserved), base, size)) >= 0) )
- base = lmb_align_down(lmb->reserved.region[j].base - size,
- align);
-
- if ((base != 0) && (lmbbase <= base))
- break;
+ while (base && lmbbase <= 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)
+ return 0;
+ return base;
+ }
+ res_base = lmb->reserved.region[j].base;
+ if (res_base < size)
+ break;
+ base = lmb_align_down(res_base - size, align);
+ }
}
-
- if (i < 0)
- return 0;
-
- if (lmb_add_region(&(lmb->reserved), base, lmb_align_up(size, align)) < 0)
- return 0;
-
- return base;
+ return 0;
}
int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr)