Merge branch '2019-01-16-master-imports'
[oweals/u-boot.git] / lib / lmb.c
index 6d3dcf4e09bce5cd2623f64d6972871b2531df80..3407705fa7030029baf97d03cf5beec1eb9187c5 100644 (file)
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -98,6 +98,19 @@ void lmb_init(struct lmb *lmb)
        lmb->reserved.size = 0;
 }
 
+/* Initialize the struct, add memory and call arch/board reserve functions */
+void lmb_init_and_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size,
+                         void *fdt_blob)
+{
+       lmb_init(lmb);
+       lmb_add(lmb, base, size);
+       arch_lmb_reserve(lmb);
+       board_lmb_reserve(lmb);
+
+       if (IMAGE_ENABLE_OF_LIBFDT && fdt_blob)
+               boot_fdt_add_mem_rsv_regions(lmb, fdt_blob);
+}
+
 /* This routine called with relocation disabled. */
 static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t size)
 {
@@ -131,6 +144,9 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t
                        rgn->region[i].size += size;
                        coalesced++;
                        break;
+               } else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {
+                       /* regions overlap */
+                       return -1;
                }
        }
 
@@ -269,11 +285,6 @@ static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size)
        return addr & ~(size - 1);
 }
 
-static phys_addr_t lmb_align_up(phys_addr_t addr, ulong size)
-{
-       return (addr + (size - 1)) & ~(size - 1);
-}
-
 phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phys_addr_t max_addr)
 {
        long i, j;
@@ -302,8 +313,7 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy
                        if (j < 0) {
                                /* This area isn't reserved, take it */
                                if (lmb_add_region(&lmb->reserved, base,
-                                                       lmb_align_up(size,
-                                                               align)) < 0)
+                                                  size) < 0)
                                        return 0;
                                return base;
                        }
@@ -316,6 +326,59 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy
        return 0;
 }
 
+/*
+ * Try to allocate a specific address range: must be in defined memory but not
+ * reserved
+ */
+phys_addr_t lmb_alloc_addr(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+{
+       long j;
+
+       /* Check if the requested address is in one of the memory regions */
+       j = lmb_overlaps_region(&lmb->memory, base, size);
+       if (j >= 0) {
+               /*
+                * Check if the requested end address is in the same memory
+                * region we found.
+                */
+               if (lmb_addrs_overlap(lmb->memory.region[j].base,
+                                     lmb->memory.region[j].size, base + size -
+                                     1, 1)) {
+                       /* ok, reserve the memory */
+                       if (lmb_reserve(lmb, base, size) >= 0)
+                               return base;
+               }
+       }
+       return 0;
+}
+
+/* Return number of bytes from a given address that are free */
+phys_size_t lmb_get_unreserved_size(struct lmb *lmb, phys_addr_t addr)
+{
+       int i;
+       long j;
+
+       /* check if the requested address is in the memory regions */
+       j = lmb_overlaps_region(&lmb->memory, addr, 1);
+       if (j >= 0) {
+               for (i = 0; i < lmb->reserved.cnt; i++) {
+                       if (addr < lmb->reserved.region[i].base) {
+                               /* first reserved range > requested address */
+                               return lmb->reserved.region[i].base - addr;
+                       }
+                       if (lmb->reserved.region[i].base +
+                           lmb->reserved.region[i].size > addr) {
+                               /* requested addr is in this reserved range */
+                               return 0;
+                       }
+               }
+               /* if we come here: no reserved ranges above requested addr */
+               return lmb->memory.region[lmb->memory.cnt - 1].base +
+                      lmb->memory.region[lmb->memory.cnt - 1].size - addr;
+       }
+       return 0;
+}
+
 int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr)
 {
        int i;