summaryrefslogtreecommitdiff
path: root/lib/lmb.c
diff options
context:
space:
mode:
authorYe Li <ye.li@nxp.com>2019-06-04 23:33:38 -0700
committerYe Li <ye.li@nxp.com>2020-04-26 23:26:40 -0700
commit2876d2923afe42ccdfb65a8bb286271fce78b626 (patch)
treee0e95acf30ef50c0235efe2159a482b7d8a27433 /lib/lmb.c
parent108a69331a52b752ca418ad71734c9fa1d2410bd (diff)
MLK-21885 lmb: Handle the overlap case for lmb reserve
lmb reserve is used to reserve some memory so that when loading images (like kernel, dtb, initrd), images won't be loaded into the reserved memory. The problem in current lmb is it does not handle the overlap case. When adding a new reserved memory, if the memory region is overlap with regions already been added in lmb, it will fail. One example is reserved memory in DTB may overlap with u-boot relocate address. lmb reserves the u-boot relocate address firstly, so when adding reserved memory from DTB, we will meet failure. Actually if we handle the overlap case, we can resolve the overlap by using a max common region for the overlap regions. So that this case won't fail. Signed-off-by: Ye Li <ye.li@nxp.com> Reviewed-by: Peng Fan <peng.fan@nxp.com> (cherry picked from commit 37d86c68816dffde3dc8dcda5b9d67a195b2f9c2)
Diffstat (limited to 'lib/lmb.c')
-rw-r--r--lib/lmb.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/lib/lmb.c b/lib/lmb.c
index 07b9308adf2..9ead0039298 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -173,7 +173,7 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t
break;
} else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {
/* regions overlap */
- return -1;
+ return -2;
}
}
@@ -266,13 +266,6 @@ long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size)
return lmb_add_region(rgn, end + 1, rgnend - end);
}
-long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size)
-{
- struct lmb_region *_rgn = &(lmb->reserved);
-
- return lmb_add_region(_rgn, base, size);
-}
-
static long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base,
phys_size_t size)
{
@@ -288,6 +281,41 @@ static long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base,
return (i < rgn->cnt) ? i : -1;
}
+long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+{
+ struct lmb_region *_rgn = &(lmb->reserved);
+ long ret = lmb_add_region(_rgn, base, size);
+ long overlap_rgn;
+ phys_addr_t res_base;
+ phys_size_t res_size;
+
+ /* Handle the overlap */
+ if (ret == -2) {
+ overlap_rgn = lmb_overlaps_region(_rgn, base, size);
+ res_base = lmb->reserved.region[overlap_rgn].base;
+ res_size = lmb->reserved.region[overlap_rgn].size;
+
+ if ((base >= res_base) && ((base + size) <= (res_base + res_size))) {
+ /* new region is inside reserved region, so it is already reserved */
+ return 0;
+ } else {
+ if (base < res_base) {
+ ret = lmb_reserve(lmb, base, res_base - base);
+ if (ret < 0)
+ return ret;
+ }
+
+ if ((base + size) > (res_base + res_size)) {
+ ret = lmb_reserve(lmb, res_base + res_size, (base + size) - (res_base + res_size));
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
phys_addr_t lmb_alloc(struct lmb *lmb, phys_size_t size, ulong align)
{
return lmb_alloc_base(lmb, size, align, LMB_ALLOC_ANYWHERE);