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