]> Git Repo - J-u-boot.git/blob - lib/lmb.c
Merge branch 'staging' of https://source.denx.de/u-boot/custodians/u-boot-tegra
[J-u-boot.git] / lib / lmb.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Procedures for maintaining information about logical memory blocks.
4  *
5  * Peter Bergner, IBM Corp.     June 2001.
6  * Copyright (C) 2001 Peter Bergner.
7  */
8
9 #include <alist.h>
10 #include <efi_loader.h>
11 #include <image.h>
12 #include <mapmem.h>
13 #include <lmb.h>
14 #include <log.h>
15 #include <malloc.h>
16 #include <spl.h>
17
18 #include <asm/global_data.h>
19 #include <asm/sections.h>
20 #include <linux/kernel.h>
21 #include <linux/sizes.h>
22
23 DECLARE_GLOBAL_DATA_PTR;
24
25 #define LMB_ALLOC_ANYWHERE      0
26 #define LMB_ALIST_INITIAL_SIZE  4
27
28 static struct lmb lmb;
29
30 static void lmb_print_region_flags(enum lmb_flags flags)
31 {
32         u64 bitpos;
33         const char *flag_str[] = { "none", "no-map", "no-overwrite" };
34
35         do {
36                 bitpos = flags ? fls(flags) - 1 : 0;
37                 printf("%s", flag_str[bitpos]);
38                 flags &= ~(1ull << bitpos);
39                 puts(flags ? ", " : "\n");
40         } while (flags);
41 }
42
43 static void lmb_dump_region(struct alist *lmb_rgn_lst, char *name)
44 {
45         struct lmb_region *rgn = lmb_rgn_lst->data;
46         unsigned long long base, size, end;
47         enum lmb_flags flags;
48         int i;
49
50         printf(" %s.count = 0x%x\n", name, lmb_rgn_lst->count);
51
52         for (i = 0; i < lmb_rgn_lst->count; i++) {
53                 base = rgn[i].base;
54                 size = rgn[i].size;
55                 end = base + size - 1;
56                 flags = rgn[i].flags;
57
58                 printf(" %s[%d]\t[0x%llx-0x%llx], 0x%08llx bytes flags: ",
59                        name, i, base, end, size);
60                 lmb_print_region_flags(flags);
61         }
62 }
63
64 void lmb_dump_all_force(void)
65 {
66         printf("lmb_dump_all:\n");
67         lmb_dump_region(&lmb.free_mem, "memory");
68         lmb_dump_region(&lmb.used_mem, "reserved");
69 }
70
71 void lmb_dump_all(void)
72 {
73 #ifdef DEBUG
74         lmb_dump_all_force();
75 #endif
76 }
77
78 static long lmb_addrs_overlap(phys_addr_t base1, phys_size_t size1,
79                               phys_addr_t base2, phys_size_t size2)
80 {
81         const phys_addr_t base1_end = base1 + size1 - 1;
82         const phys_addr_t base2_end = base2 + size2 - 1;
83
84         return ((base1 <= base2_end) && (base2 <= base1_end));
85 }
86
87 static long lmb_addrs_adjacent(phys_addr_t base1, phys_size_t size1,
88                                phys_addr_t base2, phys_size_t size2)
89 {
90         if (base2 == base1 + size1)
91                 return 1;
92         else if (base1 == base2 + size2)
93                 return -1;
94
95         return 0;
96 }
97
98 static long lmb_regions_overlap(struct alist *lmb_rgn_lst, unsigned long r1,
99                                 unsigned long r2)
100 {
101         struct lmb_region *rgn = lmb_rgn_lst->data;
102
103         phys_addr_t base1 = rgn[r1].base;
104         phys_size_t size1 = rgn[r1].size;
105         phys_addr_t base2 = rgn[r2].base;
106         phys_size_t size2 = rgn[r2].size;
107
108         return lmb_addrs_overlap(base1, size1, base2, size2);
109 }
110
111 static long lmb_regions_adjacent(struct alist *lmb_rgn_lst, unsigned long r1,
112                                  unsigned long r2)
113 {
114         struct lmb_region *rgn = lmb_rgn_lst->data;
115
116         phys_addr_t base1 = rgn[r1].base;
117         phys_size_t size1 = rgn[r1].size;
118         phys_addr_t base2 = rgn[r2].base;
119         phys_size_t size2 = rgn[r2].size;
120         return lmb_addrs_adjacent(base1, size1, base2, size2);
121 }
122
123 static void lmb_remove_region(struct alist *lmb_rgn_lst, unsigned long r)
124 {
125         unsigned long i;
126         struct lmb_region *rgn = lmb_rgn_lst->data;
127
128         for (i = r; i < lmb_rgn_lst->count - 1; i++) {
129                 rgn[i].base = rgn[i + 1].base;
130                 rgn[i].size = rgn[i + 1].size;
131                 rgn[i].flags = rgn[i + 1].flags;
132         }
133         lmb_rgn_lst->count--;
134 }
135
136 /* Assumption: base addr of region 1 < base addr of region 2 */
137 static void lmb_coalesce_regions(struct alist *lmb_rgn_lst, unsigned long r1,
138                                  unsigned long r2)
139 {
140         struct lmb_region *rgn = lmb_rgn_lst->data;
141
142         rgn[r1].size += rgn[r2].size;
143         lmb_remove_region(lmb_rgn_lst, r2);
144 }
145
146 /*Assumption : base addr of region 1 < base addr of region 2*/
147 static void lmb_fix_over_lap_regions(struct alist *lmb_rgn_lst,
148                                      unsigned long r1, unsigned long r2)
149 {
150         struct lmb_region *rgn = lmb_rgn_lst->data;
151
152         phys_addr_t base1 = rgn[r1].base;
153         phys_size_t size1 = rgn[r1].size;
154         phys_addr_t base2 = rgn[r2].base;
155         phys_size_t size2 = rgn[r2].size;
156
157         if (base1 + size1 > base2 + size2) {
158                 printf("This will not be a case any time\n");
159                 return;
160         }
161         rgn[r1].size = base2 + size2 - base1;
162         lmb_remove_region(lmb_rgn_lst, r2);
163 }
164
165 /**
166  * efi_lmb_reserve() - add reservations for EFI memory
167  *
168  * Add reservations for all EFI memory areas that are not
169  * EFI_CONVENTIONAL_MEMORY.
170  *
171  * Return:      0 on success, 1 on failure
172  */
173 static __maybe_unused int efi_lmb_reserve(void)
174 {
175         struct efi_mem_desc *memmap = NULL, *map;
176         efi_uintn_t i, map_size = 0;
177         efi_status_t ret;
178
179         ret = efi_get_memory_map_alloc(&map_size, &memmap);
180         if (ret != EFI_SUCCESS)
181                 return 1;
182
183         for (i = 0, map = memmap; i < map_size / sizeof(*map); ++map, ++i) {
184                 if (map->type != EFI_CONVENTIONAL_MEMORY) {
185                         lmb_reserve_flags(map_to_sysmem((void *)(uintptr_t)
186                                                         map->physical_start),
187                                           map->num_pages * EFI_PAGE_SIZE,
188                                           map->type == EFI_RESERVED_MEMORY_TYPE
189                                               ? LMB_NOMAP : LMB_NONE);
190                 }
191         }
192         efi_free_pool(memmap);
193
194         return 0;
195 }
196
197 static void lmb_reserve_uboot_region(void)
198 {
199         int bank;
200         ulong end, bank_end;
201         phys_addr_t rsv_start;
202
203         rsv_start = gd->start_addr_sp - CONFIG_STACK_SIZE;
204         end = gd->ram_top;
205
206         /*
207          * Reserve memory from aligned address below the bottom of U-Boot stack
208          * until end of RAM area to prevent LMB from overwriting that memory.
209          */
210         debug("## Current stack ends at 0x%08lx ", (ulong)rsv_start);
211
212         /* adjust sp by 16K to be safe */
213         rsv_start -= SZ_16K;
214         for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
215                 if (!gd->bd->bi_dram[bank].size ||
216                     rsv_start < gd->bd->bi_dram[bank].start)
217                         continue;
218                 /* Watch out for RAM at end of address space! */
219                 bank_end = gd->bd->bi_dram[bank].start +
220                         gd->bd->bi_dram[bank].size - 1;
221                 if (rsv_start > bank_end)
222                         continue;
223                 if (bank_end > end)
224                         bank_end = end - 1;
225
226                 lmb_reserve_flags(rsv_start, bank_end - rsv_start + 1,
227                                   LMB_NOOVERWRITE);
228
229                 if (gd->flags & GD_FLG_SKIP_RELOC)
230                         lmb_reserve_flags((phys_addr_t)(uintptr_t)_start,
231                                           gd->mon_len, LMB_NOOVERWRITE);
232
233                 break;
234         }
235 }
236
237 static void lmb_reserve_common(void *fdt_blob)
238 {
239         lmb_reserve_uboot_region();
240
241         if (CONFIG_IS_ENABLED(OF_LIBFDT) && fdt_blob)
242                 boot_fdt_add_mem_rsv_regions(fdt_blob);
243
244         if (CONFIG_IS_ENABLED(EFI_LOADER))
245                 efi_lmb_reserve();
246 }
247
248 static __maybe_unused void lmb_reserve_common_spl(void)
249 {
250         phys_addr_t rsv_start;
251         phys_size_t rsv_size;
252
253         /*
254          * Assume a SPL stack of 16KB. This must be
255          * more than enough for the SPL stage.
256          */
257         if (IS_ENABLED(CONFIG_SPL_STACK_R_ADDR)) {
258                 rsv_start = gd->start_addr_sp - 16384;
259                 rsv_size = 16384;
260                 lmb_reserve_flags(rsv_start, rsv_size, LMB_NOOVERWRITE);
261         }
262
263         if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) {
264                 /* Reserve the bss region */
265                 rsv_start = (phys_addr_t)(uintptr_t)__bss_start;
266                 rsv_size = (phys_addr_t)(uintptr_t)__bss_end -
267                         (phys_addr_t)(uintptr_t)__bss_start;
268                 lmb_reserve_flags(rsv_start, rsv_size, LMB_NOOVERWRITE);
269         }
270 }
271
272 /**
273  * lmb_add_memory() - Add memory range for LMB allocations
274  *
275  * Add the entire available memory range to the pool of memory that
276  * can be used by the LMB module for allocations.
277  *
278  * Return: None
279  */
280 void lmb_add_memory(void)
281 {
282         int i;
283         phys_size_t size;
284         phys_addr_t rgn_top;
285         u64 ram_top = gd->ram_top;
286         struct bd_info *bd = gd->bd;
287
288         /* Assume a 4GB ram_top if not defined */
289         if (!ram_top)
290                 ram_top = 0x100000000ULL;
291
292         for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
293                 size = bd->bi_dram[i].size;
294                 if (size) {
295                         if (bd->bi_dram[i].start > ram_top)
296                                 continue;
297
298                         rgn_top = bd->bi_dram[i].start +
299                                 bd->bi_dram[i].size;
300
301                         if (rgn_top > ram_top)
302                                 size -= rgn_top - ram_top;
303
304                         lmb_add(bd->bi_dram[i].start, size);
305                 }
306         }
307 }
308
309 static long lmb_resize_regions(struct alist *lmb_rgn_lst,
310                                unsigned long idx_start,
311                                phys_addr_t base, phys_size_t size)
312 {
313         phys_size_t rgnsize;
314         unsigned long rgn_cnt, idx, idx_end;
315         phys_addr_t rgnbase, rgnend;
316         phys_addr_t mergebase, mergeend;
317         struct lmb_region *rgn = lmb_rgn_lst->data;
318
319         rgn_cnt = 0;
320         idx = idx_start;
321         idx_end = idx_start;
322
323         /*
324          * First thing to do is to identify how many regions
325          * the requested region overlaps.
326          * If the flags match, combine all these overlapping
327          * regions into a single region, and remove the merged
328          * regions.
329          */
330         while (idx <= lmb_rgn_lst->count - 1) {
331                 rgnbase = rgn[idx].base;
332                 rgnsize = rgn[idx].size;
333
334                 if (lmb_addrs_overlap(base, size, rgnbase,
335                                       rgnsize)) {
336                         if (rgn[idx].flags != LMB_NONE)
337                                 return -1;
338                         rgn_cnt++;
339                         idx_end = idx;
340                 }
341                 idx++;
342         }
343
344         /* The merged region's base and size */
345         rgnbase = rgn[idx_start].base;
346         mergebase = min(base, rgnbase);
347         rgnend = rgn[idx_end].base + rgn[idx_end].size;
348         mergeend = max(rgnend, (base + size));
349
350         rgn[idx_start].base = mergebase;
351         rgn[idx_start].size = mergeend - mergebase;
352
353         /* Now remove the merged regions */
354         while (--rgn_cnt)
355                 lmb_remove_region(lmb_rgn_lst, idx_start + 1);
356
357         return 0;
358 }
359
360 /**
361  * lmb_add_region_flags() - Add an lmb region to the given list
362  * @lmb_rgn_lst: LMB list to which region is to be added(free/used)
363  * @base: Start address of the region
364  * @size: Size of the region to be added
365  * @flags: Attributes of the LMB region
366  *
367  * Add a region of memory to the list. If the region does not exist, add
368  * it to the list. Depending on the attributes of the region to be added,
369  * the function might resize an already existing region or coalesce two
370  * adjacent regions.
371  *
372  *
373  * Returns: 0 if the region addition successful, -1 on failure
374  */
375 static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base,
376                                  phys_size_t size, enum lmb_flags flags)
377 {
378         unsigned long coalesced = 0;
379         long ret, i;
380         struct lmb_region *rgn = lmb_rgn_lst->data;
381
382         if (alist_err(lmb_rgn_lst))
383                 return -1;
384
385         /* First try and coalesce this LMB with another. */
386         for (i = 0; i < lmb_rgn_lst->count; i++) {
387                 phys_addr_t rgnbase = rgn[i].base;
388                 phys_size_t rgnsize = rgn[i].size;
389                 phys_size_t rgnflags = rgn[i].flags;
390                 phys_addr_t end = base + size - 1;
391                 phys_addr_t rgnend = rgnbase + rgnsize - 1;
392                 if (rgnbase <= base && end <= rgnend) {
393                         if (flags == rgnflags)
394                                 /* Already have this region, so we're done */
395                                 return 0;
396                         else
397                                 return -1; /* regions with new flags */
398                 }
399
400                 ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
401                 if (ret > 0) {
402                         if (flags != rgnflags)
403                                 break;
404                         rgn[i].base -= size;
405                         rgn[i].size += size;
406                         coalesced++;
407                         break;
408                 } else if (ret < 0) {
409                         if (flags != rgnflags)
410                                 break;
411                         rgn[i].size += size;
412                         coalesced++;
413                         break;
414                 } else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {
415                         if (flags == LMB_NONE) {
416                                 ret = lmb_resize_regions(lmb_rgn_lst, i, base,
417                                                          size);
418                                 if (ret < 0)
419                                         return -1;
420
421                                 coalesced++;
422                                 break;
423                         } else {
424                                 return -1;
425                         }
426                 }
427         }
428
429         if (lmb_rgn_lst->count && i < lmb_rgn_lst->count - 1) {
430                 rgn = lmb_rgn_lst->data;
431                 if (rgn[i].flags == rgn[i + 1].flags) {
432                         if (lmb_regions_adjacent(lmb_rgn_lst, i, i + 1)) {
433                                 lmb_coalesce_regions(lmb_rgn_lst, i, i + 1);
434                                 coalesced++;
435                         } else if (lmb_regions_overlap(lmb_rgn_lst, i, i + 1)) {
436                                 /* fix overlapping area */
437                                 lmb_fix_over_lap_regions(lmb_rgn_lst, i, i + 1);
438                                 coalesced++;
439                         }
440                 }
441         }
442
443         if (coalesced)
444                 return coalesced;
445
446         if (alist_full(lmb_rgn_lst) &&
447             !alist_expand_by(lmb_rgn_lst, lmb_rgn_lst->alloc))
448                 return -1;
449         rgn = lmb_rgn_lst->data;
450
451         /* Couldn't coalesce the LMB, so add it to the sorted table. */
452         for (i = lmb_rgn_lst->count; i >= 0; i--) {
453                 if (i && base < rgn[i - 1].base) {
454                         rgn[i] = rgn[i - 1];
455                 } else {
456                         rgn[i].base = base;
457                         rgn[i].size = size;
458                         rgn[i].flags = flags;
459                         break;
460                 }
461         }
462
463         lmb_rgn_lst->count++;
464
465         return 0;
466 }
467
468 static long lmb_add_region(struct alist *lmb_rgn_lst, phys_addr_t base,
469                            phys_size_t size)
470 {
471         return lmb_add_region_flags(lmb_rgn_lst, base, size, LMB_NONE);
472 }
473
474 /* This routine may be called with relocation disabled. */
475 long lmb_add(phys_addr_t base, phys_size_t size)
476 {
477         struct alist *lmb_rgn_lst = &lmb.free_mem;
478
479         return lmb_add_region(lmb_rgn_lst, base, size);
480 }
481
482 long lmb_free(phys_addr_t base, phys_size_t size)
483 {
484         struct lmb_region *rgn;
485         struct alist *lmb_rgn_lst = &lmb.used_mem;
486         phys_addr_t rgnbegin, rgnend;
487         phys_addr_t end = base + size - 1;
488         int i;
489
490         rgnbegin = rgnend = 0; /* supress gcc warnings */
491         rgn = lmb_rgn_lst->data;
492         /* Find the region where (base, size) belongs to */
493         for (i = 0; i < lmb_rgn_lst->count; i++) {
494                 rgnbegin = rgn[i].base;
495                 rgnend = rgnbegin + rgn[i].size - 1;
496
497                 if ((rgnbegin <= base) && (end <= rgnend))
498                         break;
499         }
500
501         /* Didn't find the region */
502         if (i == lmb_rgn_lst->count)
503                 return -1;
504
505         /* Check to see if we are removing entire region */
506         if ((rgnbegin == base) && (rgnend == end)) {
507                 lmb_remove_region(lmb_rgn_lst, i);
508                 return 0;
509         }
510
511         /* Check to see if region is matching at the front */
512         if (rgnbegin == base) {
513                 rgn[i].base = end + 1;
514                 rgn[i].size -= size;
515                 return 0;
516         }
517
518         /* Check to see if the region is matching at the end */
519         if (rgnend == end) {
520                 rgn[i].size -= size;
521                 return 0;
522         }
523
524         /*
525          * We need to split the entry -  adjust the current one to the
526          * beginging of the hole and add the region after hole.
527          */
528         rgn[i].size = base - rgn[i].base;
529         return lmb_add_region_flags(lmb_rgn_lst, end + 1, rgnend - end,
530                                     rgn[i].flags);
531 }
532
533 long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags)
534 {
535         struct alist *lmb_rgn_lst = &lmb.used_mem;
536
537         return lmb_add_region_flags(lmb_rgn_lst, base, size, flags);
538 }
539
540 long lmb_reserve(phys_addr_t base, phys_size_t size)
541 {
542         return lmb_reserve_flags(base, size, LMB_NONE);
543 }
544
545 static long lmb_overlaps_region(struct alist *lmb_rgn_lst, phys_addr_t base,
546                                 phys_size_t size)
547 {
548         unsigned long i;
549         struct lmb_region *rgn = lmb_rgn_lst->data;
550
551         for (i = 0; i < lmb_rgn_lst->count; i++) {
552                 phys_addr_t rgnbase = rgn[i].base;
553                 phys_size_t rgnsize = rgn[i].size;
554                 if (lmb_addrs_overlap(base, size, rgnbase, rgnsize))
555                         break;
556         }
557
558         return (i < lmb_rgn_lst->count) ? i : -1;
559 }
560
561 static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size)
562 {
563         return addr & ~(size - 1);
564 }
565
566 static phys_addr_t __lmb_alloc_base(phys_size_t size, ulong align,
567                                     phys_addr_t max_addr, enum lmb_flags flags)
568 {
569         long i, rgn;
570         phys_addr_t base = 0;
571         phys_addr_t res_base;
572         struct lmb_region *lmb_used = lmb.used_mem.data;
573         struct lmb_region *lmb_memory = lmb.free_mem.data;
574
575         for (i = lmb.free_mem.count - 1; i >= 0; i--) {
576                 phys_addr_t lmbbase = lmb_memory[i].base;
577                 phys_size_t lmbsize = lmb_memory[i].size;
578
579                 if (lmbsize < size)
580                         continue;
581                 if (max_addr == LMB_ALLOC_ANYWHERE)
582                         base = lmb_align_down(lmbbase + lmbsize - size, align);
583                 else if (lmbbase < max_addr) {
584                         base = lmbbase + lmbsize;
585                         if (base < lmbbase)
586                                 base = -1;
587                         base = min(base, max_addr);
588                         base = lmb_align_down(base - size, align);
589                 } else
590                         continue;
591
592                 while (base && lmbbase <= base) {
593                         rgn = lmb_overlaps_region(&lmb.used_mem, base, size);
594                         if (rgn < 0) {
595                                 /* This area isn't reserved, take it */
596                                 if (lmb_add_region_flags(&lmb.used_mem, base,
597                                                          size, flags) < 0)
598                                         return 0;
599                                 return base;
600                         }
601
602                         res_base = lmb_used[rgn].base;
603                         if (res_base < size)
604                                 break;
605                         base = lmb_align_down(res_base - size, align);
606                 }
607         }
608         return 0;
609 }
610
611 phys_addr_t lmb_alloc(phys_size_t size, ulong align)
612 {
613         return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE);
614 }
615
616 phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr)
617 {
618         phys_addr_t alloc;
619
620         alloc = __lmb_alloc_base(size, align, max_addr, LMB_NONE);
621
622         if (alloc == 0)
623                 printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n",
624                        (ulong)size, (ulong)max_addr);
625
626         return alloc;
627 }
628
629 static phys_addr_t __lmb_alloc_addr(phys_addr_t base, phys_size_t size,
630                                     enum lmb_flags flags)
631 {
632         long rgn;
633         struct lmb_region *lmb_memory = lmb.free_mem.data;
634
635         /* Check if the requested address is in one of the memory regions */
636         rgn = lmb_overlaps_region(&lmb.free_mem, base, size);
637         if (rgn >= 0) {
638                 /*
639                  * Check if the requested end address is in the same memory
640                  * region we found.
641                  */
642                 if (lmb_addrs_overlap(lmb_memory[rgn].base,
643                                       lmb_memory[rgn].size,
644                                       base + size - 1, 1)) {
645                         /* ok, reserve the memory */
646                         if (lmb_reserve_flags(base, size, flags) >= 0)
647                                 return base;
648                 }
649         }
650
651         return 0;
652 }
653
654 /*
655  * Try to allocate a specific address range: must be in defined memory but not
656  * reserved
657  */
658 phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size)
659 {
660         return __lmb_alloc_addr(base, size, LMB_NONE);
661 }
662
663 /* Return number of bytes from a given address that are free */
664 phys_size_t lmb_get_free_size(phys_addr_t addr)
665 {
666         int i;
667         long rgn;
668         struct lmb_region *lmb_used = lmb.used_mem.data;
669         struct lmb_region *lmb_memory = lmb.free_mem.data;
670
671         /* check if the requested address is in the memory regions */
672         rgn = lmb_overlaps_region(&lmb.free_mem, addr, 1);
673         if (rgn >= 0) {
674                 for (i = 0; i < lmb.used_mem.count; i++) {
675                         if (addr < lmb_used[i].base) {
676                                 /* first reserved range > requested address */
677                                 return lmb_used[i].base - addr;
678                         }
679                         if (lmb_used[i].base +
680                             lmb_used[i].size > addr) {
681                                 /* requested addr is in this reserved range */
682                                 return 0;
683                         }
684                 }
685                 /* if we come here: no reserved ranges above requested addr */
686                 return lmb_memory[lmb.free_mem.count - 1].base +
687                        lmb_memory[lmb.free_mem.count - 1].size - addr;
688         }
689         return 0;
690 }
691
692 int lmb_is_reserved_flags(phys_addr_t addr, int flags)
693 {
694         int i;
695         struct lmb_region *lmb_used = lmb.used_mem.data;
696
697         for (i = 0; i < lmb.used_mem.count; i++) {
698                 phys_addr_t upper = lmb_used[i].base +
699                         lmb_used[i].size - 1;
700                 if (addr >= lmb_used[i].base && addr <= upper)
701                         return (lmb_used[i].flags & flags) == flags;
702         }
703         return 0;
704 }
705
706 static int lmb_setup(void)
707 {
708         bool ret;
709
710         ret = alist_init(&lmb.free_mem, sizeof(struct lmb_region),
711                          (uint)LMB_ALIST_INITIAL_SIZE);
712         if (!ret) {
713                 log_debug("Unable to initialise the list for LMB free memory\n");
714                 return -ENOMEM;
715         }
716
717         ret = alist_init(&lmb.used_mem, sizeof(struct lmb_region),
718                          (uint)LMB_ALIST_INITIAL_SIZE);
719         if (!ret) {
720                 log_debug("Unable to initialise the list for LMB used memory\n");
721                 return -ENOMEM;
722         }
723
724         return 0;
725 }
726
727 /**
728  * lmb_init() - Initialise the LMB module
729  *
730  * Initialise the LMB lists needed for keeping the memory map. There
731  * are two lists, in form of alloced list data structure. One for the
732  * available memory, and one for the used memory. Initialise the two
733  * lists as part of board init. Add memory to the available memory
734  * list and reserve common areas by adding them to the used memory
735  * list.
736  *
737  * Return: 0 on success, -ve on error
738  */
739 int lmb_init(void)
740 {
741         int ret;
742
743         ret = lmb_setup();
744         if (ret) {
745                 log_info("Unable to init LMB\n");
746                 return ret;
747         }
748
749         lmb_add_memory();
750
751         /* Reserve the U-Boot image region once U-Boot has relocated */
752         if (xpl_phase() == PHASE_SPL)
753                 lmb_reserve_common_spl();
754         else if (xpl_phase() == PHASE_BOARD_R)
755                 lmb_reserve_common((void *)gd->fdt_blob);
756
757         return 0;
758 }
759
760 #if CONFIG_IS_ENABLED(UNIT_TEST)
761 struct lmb *lmb_get(void)
762 {
763         return &lmb;
764 }
765
766 int lmb_push(struct lmb *store)
767 {
768         int ret;
769
770         *store = lmb;
771         ret = lmb_setup();
772         if (ret)
773                 return ret;
774
775         return 0;
776 }
777
778 void lmb_pop(struct lmb *store)
779 {
780         alist_uninit(&lmb.free_mem);
781         alist_uninit(&lmb.used_mem);
782         lmb = *store;
783 }
784 #endif /* UNIT_TEST */
This page took 0.071311 seconds and 4 git commands to generate.