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