18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Procedures for maintaining information about logical memory blocks. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Peter Bergner, IBM Corp. June 2001. 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 Peter Bergner. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/bitops.h> 138c2ecf20Sopenharmony_ci#include <linux/poison.h> 148c2ecf20Sopenharmony_ci#include <linux/pfn.h> 158c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 168c2ecf20Sopenharmony_ci#include <linux/kmemleak.h> 178c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 188c2ecf20Sopenharmony_ci#include <linux/memblock.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/sections.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "internal.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define INIT_MEMBLOCK_REGIONS 128 268c2ecf20Sopenharmony_ci#define INIT_PHYSMEM_REGIONS 4 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#ifndef INIT_MEMBLOCK_RESERVED_REGIONS 298c2ecf20Sopenharmony_ci# define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS 308c2ecf20Sopenharmony_ci#endif 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/** 338c2ecf20Sopenharmony_ci * DOC: memblock overview 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Memblock is a method of managing memory regions during the early 368c2ecf20Sopenharmony_ci * boot period when the usual kernel memory allocators are not up and 378c2ecf20Sopenharmony_ci * running. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * Memblock views the system memory as collections of contiguous 408c2ecf20Sopenharmony_ci * regions. There are several types of these collections: 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * * ``memory`` - describes the physical memory available to the 438c2ecf20Sopenharmony_ci * kernel; this may differ from the actual physical memory installed 448c2ecf20Sopenharmony_ci * in the system, for instance when the memory is restricted with 458c2ecf20Sopenharmony_ci * ``mem=`` command line parameter 468c2ecf20Sopenharmony_ci * * ``reserved`` - describes the regions that were allocated 478c2ecf20Sopenharmony_ci * * ``physmem`` - describes the actual physical memory available during 488c2ecf20Sopenharmony_ci * boot regardless of the possible restrictions and memory hot(un)plug; 498c2ecf20Sopenharmony_ci * the ``physmem`` type is only available on some architectures. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * Each region is represented by struct memblock_region that 528c2ecf20Sopenharmony_ci * defines the region extents, its attributes and NUMA node id on NUMA 538c2ecf20Sopenharmony_ci * systems. Every memory type is described by the struct memblock_type 548c2ecf20Sopenharmony_ci * which contains an array of memory regions along with 558c2ecf20Sopenharmony_ci * the allocator metadata. The "memory" and "reserved" types are nicely 568c2ecf20Sopenharmony_ci * wrapped with struct memblock. This structure is statically 578c2ecf20Sopenharmony_ci * initialized at build time. The region arrays are initially sized to 588c2ecf20Sopenharmony_ci * %INIT_MEMBLOCK_REGIONS for "memory" and %INIT_MEMBLOCK_RESERVED_REGIONS 598c2ecf20Sopenharmony_ci * for "reserved". The region array for "physmem" is initially sized to 608c2ecf20Sopenharmony_ci * %INIT_PHYSMEM_REGIONS. 618c2ecf20Sopenharmony_ci * The memblock_allow_resize() enables automatic resizing of the region 628c2ecf20Sopenharmony_ci * arrays during addition of new regions. This feature should be used 638c2ecf20Sopenharmony_ci * with care so that memory allocated for the region array will not 648c2ecf20Sopenharmony_ci * overlap with areas that should be reserved, for example initrd. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * The early architecture setup should tell memblock what the physical 678c2ecf20Sopenharmony_ci * memory layout is by using memblock_add() or memblock_add_node() 688c2ecf20Sopenharmony_ci * functions. The first function does not assign the region to a NUMA 698c2ecf20Sopenharmony_ci * node and it is appropriate for UMA systems. Yet, it is possible to 708c2ecf20Sopenharmony_ci * use it on NUMA systems as well and assign the region to a NUMA node 718c2ecf20Sopenharmony_ci * later in the setup process using memblock_set_node(). The 728c2ecf20Sopenharmony_ci * memblock_add_node() performs such an assignment directly. 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * Once memblock is setup the memory can be allocated using one of the 758c2ecf20Sopenharmony_ci * API variants: 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * * memblock_phys_alloc*() - these functions return the **physical** 788c2ecf20Sopenharmony_ci * address of the allocated memory 798c2ecf20Sopenharmony_ci * * memblock_alloc*() - these functions return the **virtual** address 808c2ecf20Sopenharmony_ci * of the allocated memory. 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * Note, that both API variants use implicit assumptions about allowed 838c2ecf20Sopenharmony_ci * memory ranges and the fallback methods. Consult the documentation 848c2ecf20Sopenharmony_ci * of memblock_alloc_internal() and memblock_alloc_range_nid() 858c2ecf20Sopenharmony_ci * functions for more elaborate description. 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * As the system boot progresses, the architecture specific mem_init() 888c2ecf20Sopenharmony_ci * function frees all the memory to the buddy page allocator. 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * Unless an architecture enables %CONFIG_ARCH_KEEP_MEMBLOCK, the 918c2ecf20Sopenharmony_ci * memblock data structures (except "physmem") will be discarded after the 928c2ecf20Sopenharmony_ci * system initialization completes. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#ifndef CONFIG_NEED_MULTIPLE_NODES 968c2ecf20Sopenharmony_cistruct pglist_data __refdata contig_page_data; 978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(contig_page_data); 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ciunsigned long max_low_pfn; 1018c2ecf20Sopenharmony_ciunsigned long min_low_pfn; 1028c2ecf20Sopenharmony_ciunsigned long max_pfn; 1038c2ecf20Sopenharmony_ciunsigned long long max_possible_pfn; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; 1068c2ecf20Sopenharmony_cistatic struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_RESERVED_REGIONS] __initdata_memblock; 1078c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 1088c2ecf20Sopenharmony_cistatic struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS]; 1098c2ecf20Sopenharmony_ci#endif 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistruct memblock memblock __initdata_memblock = { 1128c2ecf20Sopenharmony_ci .memory.regions = memblock_memory_init_regions, 1138c2ecf20Sopenharmony_ci .memory.cnt = 1, /* empty dummy entry */ 1148c2ecf20Sopenharmony_ci .memory.max = INIT_MEMBLOCK_REGIONS, 1158c2ecf20Sopenharmony_ci .memory.name = "memory", 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci .reserved.regions = memblock_reserved_init_regions, 1188c2ecf20Sopenharmony_ci .reserved.cnt = 1, /* empty dummy entry */ 1198c2ecf20Sopenharmony_ci .reserved.max = INIT_MEMBLOCK_RESERVED_REGIONS, 1208c2ecf20Sopenharmony_ci .reserved.name = "reserved", 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci .bottom_up = false, 1238c2ecf20Sopenharmony_ci .current_limit = MEMBLOCK_ALLOC_ANYWHERE, 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 1278c2ecf20Sopenharmony_cistruct memblock_type physmem = { 1288c2ecf20Sopenharmony_ci .regions = memblock_physmem_init_regions, 1298c2ecf20Sopenharmony_ci .cnt = 1, /* empty dummy entry */ 1308c2ecf20Sopenharmony_ci .max = INIT_PHYSMEM_REGIONS, 1318c2ecf20Sopenharmony_ci .name = "physmem", 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci#endif 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * keep a pointer to &memblock.memory in the text section to use it in 1378c2ecf20Sopenharmony_ci * __next_mem_range() and its helpers. 1388c2ecf20Sopenharmony_ci * For architectures that do not keep memblock data after init, this 1398c2ecf20Sopenharmony_ci * pointer will be reset to NULL at memblock_discard() 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic __refdata struct memblock_type *memblock_memory = &memblock.memory; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define for_each_memblock_type(i, memblock_type, rgn) \ 1448c2ecf20Sopenharmony_ci for (i = 0, rgn = &memblock_type->regions[0]; \ 1458c2ecf20Sopenharmony_ci i < memblock_type->cnt; \ 1468c2ecf20Sopenharmony_ci i++, rgn = &memblock_type->regions[i]) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define memblock_dbg(fmt, ...) \ 1498c2ecf20Sopenharmony_ci do { \ 1508c2ecf20Sopenharmony_ci if (memblock_debug) \ 1518c2ecf20Sopenharmony_ci pr_info(fmt, ##__VA_ARGS__); \ 1528c2ecf20Sopenharmony_ci } while (0) 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic int memblock_debug __initdata_memblock; 1558c2ecf20Sopenharmony_cistatic bool system_has_some_mirror __initdata_memblock = false; 1568c2ecf20Sopenharmony_cistatic int memblock_can_resize __initdata_memblock; 1578c2ecf20Sopenharmony_cistatic int memblock_memory_in_slab __initdata_memblock = 0; 1588c2ecf20Sopenharmony_cistatic int memblock_reserved_in_slab __initdata_memblock = 0; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic enum memblock_flags __init_memblock choose_memblock_flags(void) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return system_has_some_mirror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* adjust *@size so that (@base + *@size) doesn't overflow, return new size */ 1668c2ecf20Sopenharmony_cistatic inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci return *size = min(*size, PHYS_ADDR_MAX - base); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* 1728c2ecf20Sopenharmony_ci * Address comparison utilities 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_cistatic unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1, 1758c2ecf20Sopenharmony_ci phys_addr_t base2, phys_addr_t size2) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cibool __init_memblock memblock_overlaps_region(struct memblock_type *type, 1818c2ecf20Sopenharmony_ci phys_addr_t base, phys_addr_t size) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci unsigned long i; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci memblock_cap_size(base, &size); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci for (i = 0; i < type->cnt; i++) 1888c2ecf20Sopenharmony_ci if (memblock_addrs_overlap(base, size, type->regions[i].base, 1898c2ecf20Sopenharmony_ci type->regions[i].size)) 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci return i < type->cnt; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/** 1958c2ecf20Sopenharmony_ci * __memblock_find_range_bottom_up - find free area utility in bottom-up 1968c2ecf20Sopenharmony_ci * @start: start of candidate range 1978c2ecf20Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 1988c2ecf20Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 1998c2ecf20Sopenharmony_ci * @size: size of free area to find 2008c2ecf20Sopenharmony_ci * @align: alignment of free area to find 2018c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 2028c2ecf20Sopenharmony_ci * @flags: pick from blocks based on memory attributes 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * Utility called from memblock_find_in_range_node(), find free area bottom-up. 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * Return: 2078c2ecf20Sopenharmony_ci * Found address on success, 0 on failure. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic phys_addr_t __init_memblock 2108c2ecf20Sopenharmony_ci__memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, 2118c2ecf20Sopenharmony_ci phys_addr_t size, phys_addr_t align, int nid, 2128c2ecf20Sopenharmony_ci enum memblock_flags flags) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci phys_addr_t this_start, this_end, cand; 2158c2ecf20Sopenharmony_ci u64 i; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci for_each_free_mem_range(i, nid, flags, &this_start, &this_end, NULL) { 2188c2ecf20Sopenharmony_ci this_start = clamp(this_start, start, end); 2198c2ecf20Sopenharmony_ci this_end = clamp(this_end, start, end); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci cand = round_up(this_start, align); 2228c2ecf20Sopenharmony_ci if (cand < this_end && this_end - cand >= size) 2238c2ecf20Sopenharmony_ci return cand; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/** 2308c2ecf20Sopenharmony_ci * __memblock_find_range_top_down - find free area utility, in top-down 2318c2ecf20Sopenharmony_ci * @start: start of candidate range 2328c2ecf20Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 2338c2ecf20Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 2348c2ecf20Sopenharmony_ci * @size: size of free area to find 2358c2ecf20Sopenharmony_ci * @align: alignment of free area to find 2368c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 2378c2ecf20Sopenharmony_ci * @flags: pick from blocks based on memory attributes 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * Utility called from memblock_find_in_range_node(), find free area top-down. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Return: 2428c2ecf20Sopenharmony_ci * Found address on success, 0 on failure. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic phys_addr_t __init_memblock 2458c2ecf20Sopenharmony_ci__memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, 2468c2ecf20Sopenharmony_ci phys_addr_t size, phys_addr_t align, int nid, 2478c2ecf20Sopenharmony_ci enum memblock_flags flags) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci phys_addr_t this_start, this_end, cand; 2508c2ecf20Sopenharmony_ci u64 i; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci for_each_free_mem_range_reverse(i, nid, flags, &this_start, &this_end, 2538c2ecf20Sopenharmony_ci NULL) { 2548c2ecf20Sopenharmony_ci this_start = clamp(this_start, start, end); 2558c2ecf20Sopenharmony_ci this_end = clamp(this_end, start, end); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (this_end < size) 2588c2ecf20Sopenharmony_ci continue; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci cand = round_down(this_end - size, align); 2618c2ecf20Sopenharmony_ci if (cand >= this_start) 2628c2ecf20Sopenharmony_ci return cand; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/** 2698c2ecf20Sopenharmony_ci * memblock_find_in_range_node - find free area in given range and node 2708c2ecf20Sopenharmony_ci * @size: size of free area to find 2718c2ecf20Sopenharmony_ci * @align: alignment of free area to find 2728c2ecf20Sopenharmony_ci * @start: start of candidate range 2738c2ecf20Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 2748c2ecf20Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 2758c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 2768c2ecf20Sopenharmony_ci * @flags: pick from blocks based on memory attributes 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * Find @size free area aligned to @align in the specified range and node. 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * Return: 2818c2ecf20Sopenharmony_ci * Found address on success, 0 on failure. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_cistatic phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, 2848c2ecf20Sopenharmony_ci phys_addr_t align, phys_addr_t start, 2858c2ecf20Sopenharmony_ci phys_addr_t end, int nid, 2868c2ecf20Sopenharmony_ci enum memblock_flags flags) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci /* pump up @end */ 2898c2ecf20Sopenharmony_ci if (end == MEMBLOCK_ALLOC_ACCESSIBLE || 2908c2ecf20Sopenharmony_ci end == MEMBLOCK_ALLOC_KASAN) 2918c2ecf20Sopenharmony_ci end = memblock.current_limit; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* avoid allocating the first page */ 2948c2ecf20Sopenharmony_ci start = max_t(phys_addr_t, start, PAGE_SIZE); 2958c2ecf20Sopenharmony_ci end = max(start, end); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (memblock_bottom_up()) 2988c2ecf20Sopenharmony_ci return __memblock_find_range_bottom_up(start, end, size, align, 2998c2ecf20Sopenharmony_ci nid, flags); 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci return __memblock_find_range_top_down(start, end, size, align, 3028c2ecf20Sopenharmony_ci nid, flags); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * memblock_find_in_range - find free area in given range 3078c2ecf20Sopenharmony_ci * @start: start of candidate range 3088c2ecf20Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 3098c2ecf20Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 3108c2ecf20Sopenharmony_ci * @size: size of free area to find 3118c2ecf20Sopenharmony_ci * @align: alignment of free area to find 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Find @size free area aligned to @align in the specified range. 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * Return: 3168c2ecf20Sopenharmony_ci * Found address on success, 0 on failure. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ciphys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, 3198c2ecf20Sopenharmony_ci phys_addr_t end, phys_addr_t size, 3208c2ecf20Sopenharmony_ci phys_addr_t align) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci phys_addr_t ret; 3238c2ecf20Sopenharmony_ci enum memblock_flags flags = choose_memblock_flags(); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ciagain: 3268c2ecf20Sopenharmony_ci ret = memblock_find_in_range_node(size, align, start, end, 3278c2ecf20Sopenharmony_ci NUMA_NO_NODE, flags); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (!ret && (flags & MEMBLOCK_MIRROR)) { 3308c2ecf20Sopenharmony_ci pr_warn("Could not allocate %pap bytes of mirrored memory\n", 3318c2ecf20Sopenharmony_ci &size); 3328c2ecf20Sopenharmony_ci flags &= ~MEMBLOCK_MIRROR; 3338c2ecf20Sopenharmony_ci goto again; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return ret; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci type->total_size -= type->regions[r].size; 3428c2ecf20Sopenharmony_ci memmove(&type->regions[r], &type->regions[r + 1], 3438c2ecf20Sopenharmony_ci (type->cnt - (r + 1)) * sizeof(type->regions[r])); 3448c2ecf20Sopenharmony_ci type->cnt--; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Special case for empty arrays */ 3478c2ecf20Sopenharmony_ci if (type->cnt == 0) { 3488c2ecf20Sopenharmony_ci WARN_ON(type->total_size != 0); 3498c2ecf20Sopenharmony_ci type->cnt = 1; 3508c2ecf20Sopenharmony_ci type->regions[0].base = 0; 3518c2ecf20Sopenharmony_ci type->regions[0].size = 0; 3528c2ecf20Sopenharmony_ci type->regions[0].flags = 0; 3538c2ecf20Sopenharmony_ci memblock_set_region_node(&type->regions[0], MAX_NUMNODES); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci#ifndef CONFIG_ARCH_KEEP_MEMBLOCK 3588c2ecf20Sopenharmony_ci/** 3598c2ecf20Sopenharmony_ci * memblock_discard - discard memory and reserved arrays if they were allocated 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_civoid __init memblock_discard(void) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci phys_addr_t addr, size; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (memblock.reserved.regions != memblock_reserved_init_regions) { 3668c2ecf20Sopenharmony_ci addr = __pa(memblock.reserved.regions); 3678c2ecf20Sopenharmony_ci size = PAGE_ALIGN(sizeof(struct memblock_region) * 3688c2ecf20Sopenharmony_ci memblock.reserved.max); 3698c2ecf20Sopenharmony_ci if (memblock_reserved_in_slab) 3708c2ecf20Sopenharmony_ci kfree(memblock.reserved.regions); 3718c2ecf20Sopenharmony_ci else 3728c2ecf20Sopenharmony_ci __memblock_free_late(addr, size); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (memblock.memory.regions != memblock_memory_init_regions) { 3768c2ecf20Sopenharmony_ci addr = __pa(memblock.memory.regions); 3778c2ecf20Sopenharmony_ci size = PAGE_ALIGN(sizeof(struct memblock_region) * 3788c2ecf20Sopenharmony_ci memblock.memory.max); 3798c2ecf20Sopenharmony_ci if (memblock_memory_in_slab) 3808c2ecf20Sopenharmony_ci kfree(memblock.memory.regions); 3818c2ecf20Sopenharmony_ci else 3828c2ecf20Sopenharmony_ci __memblock_free_late(addr, size); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci memblock_memory = NULL; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci#endif 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/** 3908c2ecf20Sopenharmony_ci * memblock_double_array - double the size of the memblock regions array 3918c2ecf20Sopenharmony_ci * @type: memblock type of the regions array being doubled 3928c2ecf20Sopenharmony_ci * @new_area_start: starting address of memory range to avoid overlap with 3938c2ecf20Sopenharmony_ci * @new_area_size: size of memory range to avoid overlap with 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * Double the size of the @type regions array. If memblock is being used to 3968c2ecf20Sopenharmony_ci * allocate memory for a new reserved regions array and there is a previously 3978c2ecf20Sopenharmony_ci * allocated memory range [@new_area_start, @new_area_start + @new_area_size] 3988c2ecf20Sopenharmony_ci * waiting to be reserved, ensure the memory used by the new array does 3998c2ecf20Sopenharmony_ci * not overlap. 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * Return: 4028c2ecf20Sopenharmony_ci * 0 on success, -1 on failure. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_cistatic int __init_memblock memblock_double_array(struct memblock_type *type, 4058c2ecf20Sopenharmony_ci phys_addr_t new_area_start, 4068c2ecf20Sopenharmony_ci phys_addr_t new_area_size) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct memblock_region *new_array, *old_array; 4098c2ecf20Sopenharmony_ci phys_addr_t old_alloc_size, new_alloc_size; 4108c2ecf20Sopenharmony_ci phys_addr_t old_size, new_size, addr, new_end; 4118c2ecf20Sopenharmony_ci int use_slab = slab_is_available(); 4128c2ecf20Sopenharmony_ci int *in_slab; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* We don't allow resizing until we know about the reserved regions 4158c2ecf20Sopenharmony_ci * of memory that aren't suitable for allocation 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci if (!memblock_can_resize) 4188c2ecf20Sopenharmony_ci return -1; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* Calculate new doubled size */ 4218c2ecf20Sopenharmony_ci old_size = type->max * sizeof(struct memblock_region); 4228c2ecf20Sopenharmony_ci new_size = old_size << 1; 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * We need to allocated new one align to PAGE_SIZE, 4258c2ecf20Sopenharmony_ci * so we can free them completely later. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci old_alloc_size = PAGE_ALIGN(old_size); 4288c2ecf20Sopenharmony_ci new_alloc_size = PAGE_ALIGN(new_size); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* Retrieve the slab flag */ 4318c2ecf20Sopenharmony_ci if (type == &memblock.memory) 4328c2ecf20Sopenharmony_ci in_slab = &memblock_memory_in_slab; 4338c2ecf20Sopenharmony_ci else 4348c2ecf20Sopenharmony_ci in_slab = &memblock_reserved_in_slab; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Try to find some space for it */ 4378c2ecf20Sopenharmony_ci if (use_slab) { 4388c2ecf20Sopenharmony_ci new_array = kmalloc(new_size, GFP_KERNEL); 4398c2ecf20Sopenharmony_ci addr = new_array ? __pa(new_array) : 0; 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci /* only exclude range when trying to double reserved.regions */ 4428c2ecf20Sopenharmony_ci if (type != &memblock.reserved) 4438c2ecf20Sopenharmony_ci new_area_start = new_area_size = 0; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci addr = memblock_find_in_range(new_area_start + new_area_size, 4468c2ecf20Sopenharmony_ci memblock.current_limit, 4478c2ecf20Sopenharmony_ci new_alloc_size, PAGE_SIZE); 4488c2ecf20Sopenharmony_ci if (!addr && new_area_size) 4498c2ecf20Sopenharmony_ci addr = memblock_find_in_range(0, 4508c2ecf20Sopenharmony_ci min(new_area_start, memblock.current_limit), 4518c2ecf20Sopenharmony_ci new_alloc_size, PAGE_SIZE); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci new_array = addr ? __va(addr) : NULL; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci if (!addr) { 4568c2ecf20Sopenharmony_ci pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", 4578c2ecf20Sopenharmony_ci type->name, type->max, type->max * 2); 4588c2ecf20Sopenharmony_ci return -1; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci new_end = addr + new_size - 1; 4628c2ecf20Sopenharmony_ci memblock_dbg("memblock: %s is doubled to %ld at [%pa-%pa]", 4638c2ecf20Sopenharmony_ci type->name, type->max * 2, &addr, &new_end); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* 4668c2ecf20Sopenharmony_ci * Found space, we now need to move the array over before we add the 4678c2ecf20Sopenharmony_ci * reserved region since it may be our reserved array itself that is 4688c2ecf20Sopenharmony_ci * full. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci memcpy(new_array, type->regions, old_size); 4718c2ecf20Sopenharmony_ci memset(new_array + type->max, 0, old_size); 4728c2ecf20Sopenharmony_ci old_array = type->regions; 4738c2ecf20Sopenharmony_ci type->regions = new_array; 4748c2ecf20Sopenharmony_ci type->max <<= 1; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Free old array. We needn't free it if the array is the static one */ 4778c2ecf20Sopenharmony_ci if (*in_slab) 4788c2ecf20Sopenharmony_ci kfree(old_array); 4798c2ecf20Sopenharmony_ci else if (old_array != memblock_memory_init_regions && 4808c2ecf20Sopenharmony_ci old_array != memblock_reserved_init_regions) 4818c2ecf20Sopenharmony_ci memblock_free(__pa(old_array), old_alloc_size); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* 4848c2ecf20Sopenharmony_ci * Reserve the new array if that comes from the memblock. Otherwise, we 4858c2ecf20Sopenharmony_ci * needn't do it 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci if (!use_slab) 4888c2ecf20Sopenharmony_ci BUG_ON(memblock_reserve(addr, new_alloc_size)); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* Update slab flag */ 4918c2ecf20Sopenharmony_ci *in_slab = use_slab; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return 0; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci/** 4978c2ecf20Sopenharmony_ci * memblock_merge_regions - merge neighboring compatible regions 4988c2ecf20Sopenharmony_ci * @type: memblock type to scan 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci * Scan @type and merge neighboring compatible regions. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistatic void __init_memblock memblock_merge_regions(struct memblock_type *type) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int i = 0; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* cnt never goes below 1 */ 5078c2ecf20Sopenharmony_ci while (i < type->cnt - 1) { 5088c2ecf20Sopenharmony_ci struct memblock_region *this = &type->regions[i]; 5098c2ecf20Sopenharmony_ci struct memblock_region *next = &type->regions[i + 1]; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (this->base + this->size != next->base || 5128c2ecf20Sopenharmony_ci memblock_get_region_node(this) != 5138c2ecf20Sopenharmony_ci memblock_get_region_node(next) || 5148c2ecf20Sopenharmony_ci this->flags != next->flags) { 5158c2ecf20Sopenharmony_ci BUG_ON(this->base + this->size > next->base); 5168c2ecf20Sopenharmony_ci i++; 5178c2ecf20Sopenharmony_ci continue; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci this->size += next->size; 5218c2ecf20Sopenharmony_ci /* move forward from next + 1, index of which is i + 2 */ 5228c2ecf20Sopenharmony_ci memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next)); 5238c2ecf20Sopenharmony_ci type->cnt--; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/** 5288c2ecf20Sopenharmony_ci * memblock_insert_region - insert new memblock region 5298c2ecf20Sopenharmony_ci * @type: memblock type to insert into 5308c2ecf20Sopenharmony_ci * @idx: index for the insertion point 5318c2ecf20Sopenharmony_ci * @base: base address of the new region 5328c2ecf20Sopenharmony_ci * @size: size of the new region 5338c2ecf20Sopenharmony_ci * @nid: node id of the new region 5348c2ecf20Sopenharmony_ci * @flags: flags of the new region 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * Insert new memblock region [@base, @base + @size) into @type at @idx. 5378c2ecf20Sopenharmony_ci * @type must already have extra room to accommodate the new region. 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_cistatic void __init_memblock memblock_insert_region(struct memblock_type *type, 5408c2ecf20Sopenharmony_ci int idx, phys_addr_t base, 5418c2ecf20Sopenharmony_ci phys_addr_t size, 5428c2ecf20Sopenharmony_ci int nid, 5438c2ecf20Sopenharmony_ci enum memblock_flags flags) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct memblock_region *rgn = &type->regions[idx]; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci BUG_ON(type->cnt >= type->max); 5488c2ecf20Sopenharmony_ci memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn)); 5498c2ecf20Sopenharmony_ci rgn->base = base; 5508c2ecf20Sopenharmony_ci rgn->size = size; 5518c2ecf20Sopenharmony_ci rgn->flags = flags; 5528c2ecf20Sopenharmony_ci memblock_set_region_node(rgn, nid); 5538c2ecf20Sopenharmony_ci type->cnt++; 5548c2ecf20Sopenharmony_ci type->total_size += size; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * memblock_add_range - add new memblock region 5598c2ecf20Sopenharmony_ci * @type: memblock type to add new region into 5608c2ecf20Sopenharmony_ci * @base: base address of the new region 5618c2ecf20Sopenharmony_ci * @size: size of the new region 5628c2ecf20Sopenharmony_ci * @nid: nid of the new region 5638c2ecf20Sopenharmony_ci * @flags: flags of the new region 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * Add new memblock region [@base, @base + @size) into @type. The new region 5668c2ecf20Sopenharmony_ci * is allowed to overlap with existing ones - overlaps don't affect already 5678c2ecf20Sopenharmony_ci * existing regions. @type is guaranteed to be minimal (all neighbouring 5688c2ecf20Sopenharmony_ci * compatible regions are merged) after the addition. 5698c2ecf20Sopenharmony_ci * 5708c2ecf20Sopenharmony_ci * Return: 5718c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_cistatic int __init_memblock memblock_add_range(struct memblock_type *type, 5748c2ecf20Sopenharmony_ci phys_addr_t base, phys_addr_t size, 5758c2ecf20Sopenharmony_ci int nid, enum memblock_flags flags) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci bool insert = false; 5788c2ecf20Sopenharmony_ci phys_addr_t obase = base; 5798c2ecf20Sopenharmony_ci phys_addr_t end = base + memblock_cap_size(base, &size); 5808c2ecf20Sopenharmony_ci int idx, nr_new; 5818c2ecf20Sopenharmony_ci struct memblock_region *rgn; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (!size) 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* special case for empty array */ 5878c2ecf20Sopenharmony_ci if (type->regions[0].size == 0) { 5888c2ecf20Sopenharmony_ci WARN_ON(type->cnt != 1 || type->total_size); 5898c2ecf20Sopenharmony_ci type->regions[0].base = base; 5908c2ecf20Sopenharmony_ci type->regions[0].size = size; 5918c2ecf20Sopenharmony_ci type->regions[0].flags = flags; 5928c2ecf20Sopenharmony_ci memblock_set_region_node(&type->regions[0], nid); 5938c2ecf20Sopenharmony_ci type->total_size = size; 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_cirepeat: 5978c2ecf20Sopenharmony_ci /* 5988c2ecf20Sopenharmony_ci * The following is executed twice. Once with %false @insert and 5998c2ecf20Sopenharmony_ci * then with %true. The first counts the number of regions needed 6008c2ecf20Sopenharmony_ci * to accommodate the new area. The second actually inserts them. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci base = obase; 6038c2ecf20Sopenharmony_ci nr_new = 0; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci for_each_memblock_type(idx, type, rgn) { 6068c2ecf20Sopenharmony_ci phys_addr_t rbase = rgn->base; 6078c2ecf20Sopenharmony_ci phys_addr_t rend = rbase + rgn->size; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (rbase >= end) 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci if (rend <= base) 6128c2ecf20Sopenharmony_ci continue; 6138c2ecf20Sopenharmony_ci /* 6148c2ecf20Sopenharmony_ci * @rgn overlaps. If it separates the lower part of new 6158c2ecf20Sopenharmony_ci * area, insert that portion. 6168c2ecf20Sopenharmony_ci */ 6178c2ecf20Sopenharmony_ci if (rbase > base) { 6188c2ecf20Sopenharmony_ci#ifdef CONFIG_NEED_MULTIPLE_NODES 6198c2ecf20Sopenharmony_ci WARN_ON(nid != memblock_get_region_node(rgn)); 6208c2ecf20Sopenharmony_ci#endif 6218c2ecf20Sopenharmony_ci WARN_ON(flags != rgn->flags); 6228c2ecf20Sopenharmony_ci nr_new++; 6238c2ecf20Sopenharmony_ci if (insert) 6248c2ecf20Sopenharmony_ci memblock_insert_region(type, idx++, base, 6258c2ecf20Sopenharmony_ci rbase - base, nid, 6268c2ecf20Sopenharmony_ci flags); 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci /* area below @rend is dealt with, forget about it */ 6298c2ecf20Sopenharmony_ci base = min(rend, end); 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* insert the remaining portion */ 6338c2ecf20Sopenharmony_ci if (base < end) { 6348c2ecf20Sopenharmony_ci nr_new++; 6358c2ecf20Sopenharmony_ci if (insert) 6368c2ecf20Sopenharmony_ci memblock_insert_region(type, idx, base, end - base, 6378c2ecf20Sopenharmony_ci nid, flags); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (!nr_new) 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * If this was the first round, resize array and repeat for actual 6458c2ecf20Sopenharmony_ci * insertions; otherwise, merge and return. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_ci if (!insert) { 6488c2ecf20Sopenharmony_ci while (type->cnt + nr_new > type->max) 6498c2ecf20Sopenharmony_ci if (memblock_double_array(type, obase, size) < 0) 6508c2ecf20Sopenharmony_ci return -ENOMEM; 6518c2ecf20Sopenharmony_ci insert = true; 6528c2ecf20Sopenharmony_ci goto repeat; 6538c2ecf20Sopenharmony_ci } else { 6548c2ecf20Sopenharmony_ci memblock_merge_regions(type); 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci/** 6608c2ecf20Sopenharmony_ci * memblock_add_node - add new memblock region within a NUMA node 6618c2ecf20Sopenharmony_ci * @base: base address of the new region 6628c2ecf20Sopenharmony_ci * @size: size of the new region 6638c2ecf20Sopenharmony_ci * @nid: nid of the new region 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * Add new memblock region [@base, @base + @size) to the "memory" 6668c2ecf20Sopenharmony_ci * type. See memblock_add_range() description for mode details 6678c2ecf20Sopenharmony_ci * 6688c2ecf20Sopenharmony_ci * Return: 6698c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_ciint __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size, 6728c2ecf20Sopenharmony_ci int nid) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci return memblock_add_range(&memblock.memory, base, size, nid, 0); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci/** 6788c2ecf20Sopenharmony_ci * memblock_add - add new memblock region 6798c2ecf20Sopenharmony_ci * @base: base address of the new region 6808c2ecf20Sopenharmony_ci * @size: size of the new region 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * Add new memblock region [@base, @base + @size) to the "memory" 6838c2ecf20Sopenharmony_ci * type. See memblock_add_range() description for mode details 6848c2ecf20Sopenharmony_ci * 6858c2ecf20Sopenharmony_ci * Return: 6868c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ciint __init_memblock memblock_add(phys_addr_t base, phys_addr_t size) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci phys_addr_t end = base + size - 1; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 6938c2ecf20Sopenharmony_ci &base, &end, (void *)_RET_IP_); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return memblock_add_range(&memblock.memory, base, size, MAX_NUMNODES, 0); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/** 6998c2ecf20Sopenharmony_ci * memblock_isolate_range - isolate given range into disjoint memblocks 7008c2ecf20Sopenharmony_ci * @type: memblock type to isolate range for 7018c2ecf20Sopenharmony_ci * @base: base of range to isolate 7028c2ecf20Sopenharmony_ci * @size: size of range to isolate 7038c2ecf20Sopenharmony_ci * @start_rgn: out parameter for the start of isolated region 7048c2ecf20Sopenharmony_ci * @end_rgn: out parameter for the end of isolated region 7058c2ecf20Sopenharmony_ci * 7068c2ecf20Sopenharmony_ci * Walk @type and ensure that regions don't cross the boundaries defined by 7078c2ecf20Sopenharmony_ci * [@base, @base + @size). Crossing regions are split at the boundaries, 7088c2ecf20Sopenharmony_ci * which may create at most two more regions. The index of the first 7098c2ecf20Sopenharmony_ci * region inside the range is returned in *@start_rgn and end in *@end_rgn. 7108c2ecf20Sopenharmony_ci * 7118c2ecf20Sopenharmony_ci * Return: 7128c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_cistatic int __init_memblock memblock_isolate_range(struct memblock_type *type, 7158c2ecf20Sopenharmony_ci phys_addr_t base, phys_addr_t size, 7168c2ecf20Sopenharmony_ci int *start_rgn, int *end_rgn) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci phys_addr_t end = base + memblock_cap_size(base, &size); 7198c2ecf20Sopenharmony_ci int idx; 7208c2ecf20Sopenharmony_ci struct memblock_region *rgn; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci *start_rgn = *end_rgn = 0; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (!size) 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* we'll create at most two more regions */ 7288c2ecf20Sopenharmony_ci while (type->cnt + 2 > type->max) 7298c2ecf20Sopenharmony_ci if (memblock_double_array(type, base, size) < 0) 7308c2ecf20Sopenharmony_ci return -ENOMEM; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci for_each_memblock_type(idx, type, rgn) { 7338c2ecf20Sopenharmony_ci phys_addr_t rbase = rgn->base; 7348c2ecf20Sopenharmony_ci phys_addr_t rend = rbase + rgn->size; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (rbase >= end) 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci if (rend <= base) 7398c2ecf20Sopenharmony_ci continue; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (rbase < base) { 7428c2ecf20Sopenharmony_ci /* 7438c2ecf20Sopenharmony_ci * @rgn intersects from below. Split and continue 7448c2ecf20Sopenharmony_ci * to process the next region - the new top half. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ci rgn->base = base; 7478c2ecf20Sopenharmony_ci rgn->size -= base - rbase; 7488c2ecf20Sopenharmony_ci type->total_size -= base - rbase; 7498c2ecf20Sopenharmony_ci memblock_insert_region(type, idx, rbase, base - rbase, 7508c2ecf20Sopenharmony_ci memblock_get_region_node(rgn), 7518c2ecf20Sopenharmony_ci rgn->flags); 7528c2ecf20Sopenharmony_ci } else if (rend > end) { 7538c2ecf20Sopenharmony_ci /* 7548c2ecf20Sopenharmony_ci * @rgn intersects from above. Split and redo the 7558c2ecf20Sopenharmony_ci * current region - the new bottom half. 7568c2ecf20Sopenharmony_ci */ 7578c2ecf20Sopenharmony_ci rgn->base = end; 7588c2ecf20Sopenharmony_ci rgn->size -= end - rbase; 7598c2ecf20Sopenharmony_ci type->total_size -= end - rbase; 7608c2ecf20Sopenharmony_ci memblock_insert_region(type, idx--, rbase, end - rbase, 7618c2ecf20Sopenharmony_ci memblock_get_region_node(rgn), 7628c2ecf20Sopenharmony_ci rgn->flags); 7638c2ecf20Sopenharmony_ci } else { 7648c2ecf20Sopenharmony_ci /* @rgn is fully contained, record it */ 7658c2ecf20Sopenharmony_ci if (!*end_rgn) 7668c2ecf20Sopenharmony_ci *start_rgn = idx; 7678c2ecf20Sopenharmony_ci *end_rgn = idx + 1; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int __init_memblock memblock_remove_range(struct memblock_type *type, 7758c2ecf20Sopenharmony_ci phys_addr_t base, phys_addr_t size) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci int start_rgn, end_rgn; 7788c2ecf20Sopenharmony_ci int i, ret; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); 7818c2ecf20Sopenharmony_ci if (ret) 7828c2ecf20Sopenharmony_ci return ret; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci for (i = end_rgn - 1; i >= start_rgn; i--) 7858c2ecf20Sopenharmony_ci memblock_remove_region(type, i); 7868c2ecf20Sopenharmony_ci return 0; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ciint __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci phys_addr_t end = base + size - 1; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 7948c2ecf20Sopenharmony_ci &base, &end, (void *)_RET_IP_); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return memblock_remove_range(&memblock.memory, base, size); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci/** 8008c2ecf20Sopenharmony_ci * memblock_free - free boot memory block 8018c2ecf20Sopenharmony_ci * @base: phys starting address of the boot memory block 8028c2ecf20Sopenharmony_ci * @size: size of the boot memory block in bytes 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * Free boot memory block previously allocated by memblock_alloc_xx() API. 8058c2ecf20Sopenharmony_ci * The freeing memory will not be released to the buddy allocator. 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ciint __init_memblock memblock_free(phys_addr_t base, phys_addr_t size) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci phys_addr_t end = base + size - 1; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 8128c2ecf20Sopenharmony_ci &base, &end, (void *)_RET_IP_); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci kmemleak_free_part_phys(base, size); 8158c2ecf20Sopenharmony_ci return memblock_remove_range(&memblock.reserved, base, size); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ciint __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci phys_addr_t end = base + size - 1; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 8238c2ecf20Sopenharmony_ci &base, &end, (void *)_RET_IP_); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return memblock_add_range(&memblock.reserved, base, size, MAX_NUMNODES, 0); 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 8298c2ecf20Sopenharmony_ciint __init_memblock memblock_physmem_add(phys_addr_t base, phys_addr_t size) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci phys_addr_t end = base + size - 1; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 8348c2ecf20Sopenharmony_ci &base, &end, (void *)_RET_IP_); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return memblock_add_range(&physmem, base, size, MAX_NUMNODES, 0); 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci#endif 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/** 8418c2ecf20Sopenharmony_ci * memblock_setclr_flag - set or clear flag for a memory region 8428c2ecf20Sopenharmony_ci * @base: base address of the region 8438c2ecf20Sopenharmony_ci * @size: size of the region 8448c2ecf20Sopenharmony_ci * @set: set or clear the flag 8458c2ecf20Sopenharmony_ci * @flag: the flag to udpate 8468c2ecf20Sopenharmony_ci * 8478c2ecf20Sopenharmony_ci * This function isolates region [@base, @base + @size), and sets/clears flag 8488c2ecf20Sopenharmony_ci * 8498c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure. 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_cistatic int __init_memblock memblock_setclr_flag(phys_addr_t base, 8528c2ecf20Sopenharmony_ci phys_addr_t size, int set, int flag) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct memblock_type *type = &memblock.memory; 8558c2ecf20Sopenharmony_ci int i, ret, start_rgn, end_rgn; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); 8588c2ecf20Sopenharmony_ci if (ret) 8598c2ecf20Sopenharmony_ci return ret; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci for (i = start_rgn; i < end_rgn; i++) { 8628c2ecf20Sopenharmony_ci struct memblock_region *r = &type->regions[i]; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (set) 8658c2ecf20Sopenharmony_ci r->flags |= flag; 8668c2ecf20Sopenharmony_ci else 8678c2ecf20Sopenharmony_ci r->flags &= ~flag; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci memblock_merge_regions(type); 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/** 8758c2ecf20Sopenharmony_ci * memblock_mark_hotplug - Mark hotpluggable memory with flag MEMBLOCK_HOTPLUG. 8768c2ecf20Sopenharmony_ci * @base: the base phys addr of the region 8778c2ecf20Sopenharmony_ci * @size: the size of the region 8788c2ecf20Sopenharmony_ci * 8798c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure. 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_ciint __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci return memblock_setclr_flag(base, size, 1, MEMBLOCK_HOTPLUG); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci/** 8878c2ecf20Sopenharmony_ci * memblock_clear_hotplug - Clear flag MEMBLOCK_HOTPLUG for a specified region. 8888c2ecf20Sopenharmony_ci * @base: the base phys addr of the region 8898c2ecf20Sopenharmony_ci * @size: the size of the region 8908c2ecf20Sopenharmony_ci * 8918c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure. 8928c2ecf20Sopenharmony_ci */ 8938c2ecf20Sopenharmony_ciint __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci return memblock_setclr_flag(base, size, 0, MEMBLOCK_HOTPLUG); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/** 8998c2ecf20Sopenharmony_ci * memblock_mark_mirror - Mark mirrored memory with flag MEMBLOCK_MIRROR. 9008c2ecf20Sopenharmony_ci * @base: the base phys addr of the region 9018c2ecf20Sopenharmony_ci * @size: the size of the region 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure. 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_ciint __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci system_has_some_mirror = true; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci/** 9138c2ecf20Sopenharmony_ci * memblock_mark_nomap - Mark a memory region with flag MEMBLOCK_NOMAP. 9148c2ecf20Sopenharmony_ci * @base: the base phys addr of the region 9158c2ecf20Sopenharmony_ci * @size: the size of the region 9168c2ecf20Sopenharmony_ci * 9178c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_ciint __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci return memblock_setclr_flag(base, size, 1, MEMBLOCK_NOMAP); 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci/** 9258c2ecf20Sopenharmony_ci * memblock_clear_nomap - Clear flag MEMBLOCK_NOMAP for a specified region. 9268c2ecf20Sopenharmony_ci * @base: the base phys addr of the region 9278c2ecf20Sopenharmony_ci * @size: the size of the region 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure. 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_ciint __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci return memblock_setclr_flag(base, size, 0, MEMBLOCK_NOMAP); 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic bool should_skip_region(struct memblock_type *type, 9378c2ecf20Sopenharmony_ci struct memblock_region *m, 9388c2ecf20Sopenharmony_ci int nid, int flags) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci int m_nid = memblock_get_region_node(m); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* we never skip regions when iterating memblock.reserved or physmem */ 9438c2ecf20Sopenharmony_ci if (type != memblock_memory) 9448c2ecf20Sopenharmony_ci return false; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* only memory regions are associated with nodes, check it */ 9478c2ecf20Sopenharmony_ci if (nid != NUMA_NO_NODE && nid != m_nid) 9488c2ecf20Sopenharmony_ci return true; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* skip hotpluggable memory regions if needed */ 9518c2ecf20Sopenharmony_ci if (movable_node_is_enabled() && memblock_is_hotpluggable(m) && 9528c2ecf20Sopenharmony_ci !(flags & MEMBLOCK_HOTPLUG)) 9538c2ecf20Sopenharmony_ci return true; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci /* if we want mirror memory skip non-mirror memory regions */ 9568c2ecf20Sopenharmony_ci if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m)) 9578c2ecf20Sopenharmony_ci return true; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* skip nomap memory unless we were asked for it explicitly */ 9608c2ecf20Sopenharmony_ci if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m)) 9618c2ecf20Sopenharmony_ci return true; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci return false; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci/** 9678c2ecf20Sopenharmony_ci * __next_mem_range - next function for for_each_free_mem_range() etc. 9688c2ecf20Sopenharmony_ci * @idx: pointer to u64 loop variable 9698c2ecf20Sopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 9708c2ecf20Sopenharmony_ci * @flags: pick from blocks based on memory attributes 9718c2ecf20Sopenharmony_ci * @type_a: pointer to memblock_type from where the range is taken 9728c2ecf20Sopenharmony_ci * @type_b: pointer to memblock_type which excludes memory from being taken 9738c2ecf20Sopenharmony_ci * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL 9748c2ecf20Sopenharmony_ci * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL 9758c2ecf20Sopenharmony_ci * @out_nid: ptr to int for nid of the range, can be %NULL 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci * Find the first area from *@idx which matches @nid, fill the out 9788c2ecf20Sopenharmony_ci * parameters, and update *@idx for the next iteration. The lower 32bit of 9798c2ecf20Sopenharmony_ci * *@idx contains index into type_a and the upper 32bit indexes the 9808c2ecf20Sopenharmony_ci * areas before each region in type_b. For example, if type_b regions 9818c2ecf20Sopenharmony_ci * look like the following, 9828c2ecf20Sopenharmony_ci * 9838c2ecf20Sopenharmony_ci * 0:[0-16), 1:[32-48), 2:[128-130) 9848c2ecf20Sopenharmony_ci * 9858c2ecf20Sopenharmony_ci * The upper 32bit indexes the following regions. 9868c2ecf20Sopenharmony_ci * 9878c2ecf20Sopenharmony_ci * 0:[0-0), 1:[16-32), 2:[48-128), 3:[130-MAX) 9888c2ecf20Sopenharmony_ci * 9898c2ecf20Sopenharmony_ci * As both region arrays are sorted, the function advances the two indices 9908c2ecf20Sopenharmony_ci * in lockstep and returns each intersection. 9918c2ecf20Sopenharmony_ci */ 9928c2ecf20Sopenharmony_civoid __next_mem_range(u64 *idx, int nid, enum memblock_flags flags, 9938c2ecf20Sopenharmony_ci struct memblock_type *type_a, 9948c2ecf20Sopenharmony_ci struct memblock_type *type_b, phys_addr_t *out_start, 9958c2ecf20Sopenharmony_ci phys_addr_t *out_end, int *out_nid) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci int idx_a = *idx & 0xffffffff; 9988c2ecf20Sopenharmony_ci int idx_b = *idx >> 32; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (WARN_ONCE(nid == MAX_NUMNODES, 10018c2ecf20Sopenharmony_ci "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) 10028c2ecf20Sopenharmony_ci nid = NUMA_NO_NODE; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci for (; idx_a < type_a->cnt; idx_a++) { 10058c2ecf20Sopenharmony_ci struct memblock_region *m = &type_a->regions[idx_a]; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci phys_addr_t m_start = m->base; 10088c2ecf20Sopenharmony_ci phys_addr_t m_end = m->base + m->size; 10098c2ecf20Sopenharmony_ci int m_nid = memblock_get_region_node(m); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (should_skip_region(type_a, m, nid, flags)) 10128c2ecf20Sopenharmony_ci continue; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (!type_b) { 10158c2ecf20Sopenharmony_ci if (out_start) 10168c2ecf20Sopenharmony_ci *out_start = m_start; 10178c2ecf20Sopenharmony_ci if (out_end) 10188c2ecf20Sopenharmony_ci *out_end = m_end; 10198c2ecf20Sopenharmony_ci if (out_nid) 10208c2ecf20Sopenharmony_ci *out_nid = m_nid; 10218c2ecf20Sopenharmony_ci idx_a++; 10228c2ecf20Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 10238c2ecf20Sopenharmony_ci return; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* scan areas before each reservation */ 10278c2ecf20Sopenharmony_ci for (; idx_b < type_b->cnt + 1; idx_b++) { 10288c2ecf20Sopenharmony_ci struct memblock_region *r; 10298c2ecf20Sopenharmony_ci phys_addr_t r_start; 10308c2ecf20Sopenharmony_ci phys_addr_t r_end; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci r = &type_b->regions[idx_b]; 10338c2ecf20Sopenharmony_ci r_start = idx_b ? r[-1].base + r[-1].size : 0; 10348c2ecf20Sopenharmony_ci r_end = idx_b < type_b->cnt ? 10358c2ecf20Sopenharmony_ci r->base : PHYS_ADDR_MAX; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* 10388c2ecf20Sopenharmony_ci * if idx_b advanced past idx_a, 10398c2ecf20Sopenharmony_ci * break out to advance idx_a 10408c2ecf20Sopenharmony_ci */ 10418c2ecf20Sopenharmony_ci if (r_start >= m_end) 10428c2ecf20Sopenharmony_ci break; 10438c2ecf20Sopenharmony_ci /* if the two regions intersect, we're done */ 10448c2ecf20Sopenharmony_ci if (m_start < r_end) { 10458c2ecf20Sopenharmony_ci if (out_start) 10468c2ecf20Sopenharmony_ci *out_start = 10478c2ecf20Sopenharmony_ci max(m_start, r_start); 10488c2ecf20Sopenharmony_ci if (out_end) 10498c2ecf20Sopenharmony_ci *out_end = min(m_end, r_end); 10508c2ecf20Sopenharmony_ci if (out_nid) 10518c2ecf20Sopenharmony_ci *out_nid = m_nid; 10528c2ecf20Sopenharmony_ci /* 10538c2ecf20Sopenharmony_ci * The region which ends first is 10548c2ecf20Sopenharmony_ci * advanced for the next iteration. 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci if (m_end <= r_end) 10578c2ecf20Sopenharmony_ci idx_a++; 10588c2ecf20Sopenharmony_ci else 10598c2ecf20Sopenharmony_ci idx_b++; 10608c2ecf20Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 10618c2ecf20Sopenharmony_ci return; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* signal end of iteration */ 10678c2ecf20Sopenharmony_ci *idx = ULLONG_MAX; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci/** 10718c2ecf20Sopenharmony_ci * __next_mem_range_rev - generic next function for for_each_*_range_rev() 10728c2ecf20Sopenharmony_ci * 10738c2ecf20Sopenharmony_ci * @idx: pointer to u64 loop variable 10748c2ecf20Sopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 10758c2ecf20Sopenharmony_ci * @flags: pick from blocks based on memory attributes 10768c2ecf20Sopenharmony_ci * @type_a: pointer to memblock_type from where the range is taken 10778c2ecf20Sopenharmony_ci * @type_b: pointer to memblock_type which excludes memory from being taken 10788c2ecf20Sopenharmony_ci * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL 10798c2ecf20Sopenharmony_ci * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL 10808c2ecf20Sopenharmony_ci * @out_nid: ptr to int for nid of the range, can be %NULL 10818c2ecf20Sopenharmony_ci * 10828c2ecf20Sopenharmony_ci * Finds the next range from type_a which is not marked as unsuitable 10838c2ecf20Sopenharmony_ci * in type_b. 10848c2ecf20Sopenharmony_ci * 10858c2ecf20Sopenharmony_ci * Reverse of __next_mem_range(). 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_civoid __init_memblock __next_mem_range_rev(u64 *idx, int nid, 10888c2ecf20Sopenharmony_ci enum memblock_flags flags, 10898c2ecf20Sopenharmony_ci struct memblock_type *type_a, 10908c2ecf20Sopenharmony_ci struct memblock_type *type_b, 10918c2ecf20Sopenharmony_ci phys_addr_t *out_start, 10928c2ecf20Sopenharmony_ci phys_addr_t *out_end, int *out_nid) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci int idx_a = *idx & 0xffffffff; 10958c2ecf20Sopenharmony_ci int idx_b = *idx >> 32; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) 10988c2ecf20Sopenharmony_ci nid = NUMA_NO_NODE; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (*idx == (u64)ULLONG_MAX) { 11018c2ecf20Sopenharmony_ci idx_a = type_a->cnt - 1; 11028c2ecf20Sopenharmony_ci if (type_b != NULL) 11038c2ecf20Sopenharmony_ci idx_b = type_b->cnt; 11048c2ecf20Sopenharmony_ci else 11058c2ecf20Sopenharmony_ci idx_b = 0; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci for (; idx_a >= 0; idx_a--) { 11098c2ecf20Sopenharmony_ci struct memblock_region *m = &type_a->regions[idx_a]; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci phys_addr_t m_start = m->base; 11128c2ecf20Sopenharmony_ci phys_addr_t m_end = m->base + m->size; 11138c2ecf20Sopenharmony_ci int m_nid = memblock_get_region_node(m); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (should_skip_region(type_a, m, nid, flags)) 11168c2ecf20Sopenharmony_ci continue; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (!type_b) { 11198c2ecf20Sopenharmony_ci if (out_start) 11208c2ecf20Sopenharmony_ci *out_start = m_start; 11218c2ecf20Sopenharmony_ci if (out_end) 11228c2ecf20Sopenharmony_ci *out_end = m_end; 11238c2ecf20Sopenharmony_ci if (out_nid) 11248c2ecf20Sopenharmony_ci *out_nid = m_nid; 11258c2ecf20Sopenharmony_ci idx_a--; 11268c2ecf20Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 11278c2ecf20Sopenharmony_ci return; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* scan areas before each reservation */ 11318c2ecf20Sopenharmony_ci for (; idx_b >= 0; idx_b--) { 11328c2ecf20Sopenharmony_ci struct memblock_region *r; 11338c2ecf20Sopenharmony_ci phys_addr_t r_start; 11348c2ecf20Sopenharmony_ci phys_addr_t r_end; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci r = &type_b->regions[idx_b]; 11378c2ecf20Sopenharmony_ci r_start = idx_b ? r[-1].base + r[-1].size : 0; 11388c2ecf20Sopenharmony_ci r_end = idx_b < type_b->cnt ? 11398c2ecf20Sopenharmony_ci r->base : PHYS_ADDR_MAX; 11408c2ecf20Sopenharmony_ci /* 11418c2ecf20Sopenharmony_ci * if idx_b advanced past idx_a, 11428c2ecf20Sopenharmony_ci * break out to advance idx_a 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (r_end <= m_start) 11468c2ecf20Sopenharmony_ci break; 11478c2ecf20Sopenharmony_ci /* if the two regions intersect, we're done */ 11488c2ecf20Sopenharmony_ci if (m_end > r_start) { 11498c2ecf20Sopenharmony_ci if (out_start) 11508c2ecf20Sopenharmony_ci *out_start = max(m_start, r_start); 11518c2ecf20Sopenharmony_ci if (out_end) 11528c2ecf20Sopenharmony_ci *out_end = min(m_end, r_end); 11538c2ecf20Sopenharmony_ci if (out_nid) 11548c2ecf20Sopenharmony_ci *out_nid = m_nid; 11558c2ecf20Sopenharmony_ci if (m_start >= r_start) 11568c2ecf20Sopenharmony_ci idx_a--; 11578c2ecf20Sopenharmony_ci else 11588c2ecf20Sopenharmony_ci idx_b--; 11598c2ecf20Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 11608c2ecf20Sopenharmony_ci return; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci /* signal end of iteration */ 11658c2ecf20Sopenharmony_ci *idx = ULLONG_MAX; 11668c2ecf20Sopenharmony_ci} 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci/* 11698c2ecf20Sopenharmony_ci * Common iterator interface used to define for_each_mem_pfn_range(). 11708c2ecf20Sopenharmony_ci */ 11718c2ecf20Sopenharmony_civoid __init_memblock __next_mem_pfn_range(int *idx, int nid, 11728c2ecf20Sopenharmony_ci unsigned long *out_start_pfn, 11738c2ecf20Sopenharmony_ci unsigned long *out_end_pfn, int *out_nid) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci struct memblock_type *type = &memblock.memory; 11768c2ecf20Sopenharmony_ci struct memblock_region *r; 11778c2ecf20Sopenharmony_ci int r_nid; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci while (++*idx < type->cnt) { 11808c2ecf20Sopenharmony_ci r = &type->regions[*idx]; 11818c2ecf20Sopenharmony_ci r_nid = memblock_get_region_node(r); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (PFN_UP(r->base) >= PFN_DOWN(r->base + r->size)) 11848c2ecf20Sopenharmony_ci continue; 11858c2ecf20Sopenharmony_ci if (nid == MAX_NUMNODES || nid == r_nid) 11868c2ecf20Sopenharmony_ci break; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci if (*idx >= type->cnt) { 11898c2ecf20Sopenharmony_ci *idx = -1; 11908c2ecf20Sopenharmony_ci return; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (out_start_pfn) 11948c2ecf20Sopenharmony_ci *out_start_pfn = PFN_UP(r->base); 11958c2ecf20Sopenharmony_ci if (out_end_pfn) 11968c2ecf20Sopenharmony_ci *out_end_pfn = PFN_DOWN(r->base + r->size); 11978c2ecf20Sopenharmony_ci if (out_nid) 11988c2ecf20Sopenharmony_ci *out_nid = r_nid; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci/** 12028c2ecf20Sopenharmony_ci * memblock_set_node - set node ID on memblock regions 12038c2ecf20Sopenharmony_ci * @base: base of area to set node ID for 12048c2ecf20Sopenharmony_ci * @size: size of area to set node ID for 12058c2ecf20Sopenharmony_ci * @type: memblock type to set node ID for 12068c2ecf20Sopenharmony_ci * @nid: node ID to set 12078c2ecf20Sopenharmony_ci * 12088c2ecf20Sopenharmony_ci * Set the nid of memblock @type regions in [@base, @base + @size) to @nid. 12098c2ecf20Sopenharmony_ci * Regions which cross the area boundaries are split as necessary. 12108c2ecf20Sopenharmony_ci * 12118c2ecf20Sopenharmony_ci * Return: 12128c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 12138c2ecf20Sopenharmony_ci */ 12148c2ecf20Sopenharmony_ciint __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, 12158c2ecf20Sopenharmony_ci struct memblock_type *type, int nid) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci#ifdef CONFIG_NEED_MULTIPLE_NODES 12188c2ecf20Sopenharmony_ci int start_rgn, end_rgn; 12198c2ecf20Sopenharmony_ci int i, ret; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); 12228c2ecf20Sopenharmony_ci if (ret) 12238c2ecf20Sopenharmony_ci return ret; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci for (i = start_rgn; i < end_rgn; i++) 12268c2ecf20Sopenharmony_ci memblock_set_region_node(&type->regions[i], nid); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci memblock_merge_regions(type); 12298c2ecf20Sopenharmony_ci#endif 12308c2ecf20Sopenharmony_ci return 0; 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT 12348c2ecf20Sopenharmony_ci/** 12358c2ecf20Sopenharmony_ci * __next_mem_pfn_range_in_zone - iterator for for_each_*_range_in_zone() 12368c2ecf20Sopenharmony_ci * 12378c2ecf20Sopenharmony_ci * @idx: pointer to u64 loop variable 12388c2ecf20Sopenharmony_ci * @zone: zone in which all of the memory blocks reside 12398c2ecf20Sopenharmony_ci * @out_spfn: ptr to ulong for start pfn of the range, can be %NULL 12408c2ecf20Sopenharmony_ci * @out_epfn: ptr to ulong for end pfn of the range, can be %NULL 12418c2ecf20Sopenharmony_ci * 12428c2ecf20Sopenharmony_ci * This function is meant to be a zone/pfn specific wrapper for the 12438c2ecf20Sopenharmony_ci * for_each_mem_range type iterators. Specifically they are used in the 12448c2ecf20Sopenharmony_ci * deferred memory init routines and as such we were duplicating much of 12458c2ecf20Sopenharmony_ci * this logic throughout the code. So instead of having it in multiple 12468c2ecf20Sopenharmony_ci * locations it seemed like it would make more sense to centralize this to 12478c2ecf20Sopenharmony_ci * one new iterator that does everything they need. 12488c2ecf20Sopenharmony_ci */ 12498c2ecf20Sopenharmony_civoid __init_memblock 12508c2ecf20Sopenharmony_ci__next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, 12518c2ecf20Sopenharmony_ci unsigned long *out_spfn, unsigned long *out_epfn) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci int zone_nid = zone_to_nid(zone); 12548c2ecf20Sopenharmony_ci phys_addr_t spa, epa; 12558c2ecf20Sopenharmony_ci int nid; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci __next_mem_range(idx, zone_nid, MEMBLOCK_NONE, 12588c2ecf20Sopenharmony_ci &memblock.memory, &memblock.reserved, 12598c2ecf20Sopenharmony_ci &spa, &epa, &nid); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci while (*idx != U64_MAX) { 12628c2ecf20Sopenharmony_ci unsigned long epfn = PFN_DOWN(epa); 12638c2ecf20Sopenharmony_ci unsigned long spfn = PFN_UP(spa); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* 12668c2ecf20Sopenharmony_ci * Verify the end is at least past the start of the zone and 12678c2ecf20Sopenharmony_ci * that we have at least one PFN to initialize. 12688c2ecf20Sopenharmony_ci */ 12698c2ecf20Sopenharmony_ci if (zone->zone_start_pfn < epfn && spfn < epfn) { 12708c2ecf20Sopenharmony_ci /* if we went too far just stop searching */ 12718c2ecf20Sopenharmony_ci if (zone_end_pfn(zone) <= spfn) { 12728c2ecf20Sopenharmony_ci *idx = U64_MAX; 12738c2ecf20Sopenharmony_ci break; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if (out_spfn) 12778c2ecf20Sopenharmony_ci *out_spfn = max(zone->zone_start_pfn, spfn); 12788c2ecf20Sopenharmony_ci if (out_epfn) 12798c2ecf20Sopenharmony_ci *out_epfn = min(zone_end_pfn(zone), epfn); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci __next_mem_range(idx, zone_nid, MEMBLOCK_NONE, 12858c2ecf20Sopenharmony_ci &memblock.memory, &memblock.reserved, 12868c2ecf20Sopenharmony_ci &spa, &epa, &nid); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* signal end of iteration */ 12908c2ecf20Sopenharmony_ci if (out_spfn) 12918c2ecf20Sopenharmony_ci *out_spfn = ULONG_MAX; 12928c2ecf20Sopenharmony_ci if (out_epfn) 12938c2ecf20Sopenharmony_ci *out_epfn = 0; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci/** 12998c2ecf20Sopenharmony_ci * memblock_alloc_range_nid - allocate boot memory block 13008c2ecf20Sopenharmony_ci * @size: size of memory block to be allocated in bytes 13018c2ecf20Sopenharmony_ci * @align: alignment of the region and block's size 13028c2ecf20Sopenharmony_ci * @start: the lower bound of the memory region to allocate (phys address) 13038c2ecf20Sopenharmony_ci * @end: the upper bound of the memory region to allocate (phys address) 13048c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 13058c2ecf20Sopenharmony_ci * @exact_nid: control the allocation fall back to other nodes 13068c2ecf20Sopenharmony_ci * 13078c2ecf20Sopenharmony_ci * The allocation is performed from memory region limited by 13088c2ecf20Sopenharmony_ci * memblock.current_limit if @end == %MEMBLOCK_ALLOC_ACCESSIBLE. 13098c2ecf20Sopenharmony_ci * 13108c2ecf20Sopenharmony_ci * If the specified node can not hold the requested memory and @exact_nid 13118c2ecf20Sopenharmony_ci * is false, the allocation falls back to any node in the system. 13128c2ecf20Sopenharmony_ci * 13138c2ecf20Sopenharmony_ci * For systems with memory mirroring, the allocation is attempted first 13148c2ecf20Sopenharmony_ci * from the regions with mirroring enabled and then retried from any 13158c2ecf20Sopenharmony_ci * memory region. 13168c2ecf20Sopenharmony_ci * 13178c2ecf20Sopenharmony_ci * In addition, function sets the min_count to 0 using kmemleak_alloc_phys for 13188c2ecf20Sopenharmony_ci * allocated boot memory block, so that it is never reported as leaks. 13198c2ecf20Sopenharmony_ci * 13208c2ecf20Sopenharmony_ci * Return: 13218c2ecf20Sopenharmony_ci * Physical address of allocated memory block on success, %0 on failure. 13228c2ecf20Sopenharmony_ci */ 13238c2ecf20Sopenharmony_ciphys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, 13248c2ecf20Sopenharmony_ci phys_addr_t align, phys_addr_t start, 13258c2ecf20Sopenharmony_ci phys_addr_t end, int nid, 13268c2ecf20Sopenharmony_ci bool exact_nid) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci enum memblock_flags flags = choose_memblock_flags(); 13298c2ecf20Sopenharmony_ci phys_addr_t found; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) 13328c2ecf20Sopenharmony_ci nid = NUMA_NO_NODE; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (!align) { 13358c2ecf20Sopenharmony_ci /* Can't use WARNs this early in boot on powerpc */ 13368c2ecf20Sopenharmony_ci dump_stack(); 13378c2ecf20Sopenharmony_ci align = SMP_CACHE_BYTES; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ciagain: 13418c2ecf20Sopenharmony_ci found = memblock_find_in_range_node(size, align, start, end, nid, 13428c2ecf20Sopenharmony_ci flags); 13438c2ecf20Sopenharmony_ci if (found && !memblock_reserve(found, size)) 13448c2ecf20Sopenharmony_ci goto done; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (nid != NUMA_NO_NODE && !exact_nid) { 13478c2ecf20Sopenharmony_ci found = memblock_find_in_range_node(size, align, start, 13488c2ecf20Sopenharmony_ci end, NUMA_NO_NODE, 13498c2ecf20Sopenharmony_ci flags); 13508c2ecf20Sopenharmony_ci if (found && !memblock_reserve(found, size)) 13518c2ecf20Sopenharmony_ci goto done; 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (flags & MEMBLOCK_MIRROR) { 13558c2ecf20Sopenharmony_ci flags &= ~MEMBLOCK_MIRROR; 13568c2ecf20Sopenharmony_ci pr_warn("Could not allocate %pap bytes of mirrored memory\n", 13578c2ecf20Sopenharmony_ci &size); 13588c2ecf20Sopenharmony_ci goto again; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci return 0; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cidone: 13648c2ecf20Sopenharmony_ci /* Skip kmemleak for kasan_init() due to high volume. */ 13658c2ecf20Sopenharmony_ci if (end != MEMBLOCK_ALLOC_KASAN) 13668c2ecf20Sopenharmony_ci /* 13678c2ecf20Sopenharmony_ci * The min_count is set to 0 so that memblock allocated 13688c2ecf20Sopenharmony_ci * blocks are never reported as leaks. This is because many 13698c2ecf20Sopenharmony_ci * of these blocks are only referred via the physical 13708c2ecf20Sopenharmony_ci * address which is not looked up by kmemleak. 13718c2ecf20Sopenharmony_ci */ 13728c2ecf20Sopenharmony_ci kmemleak_alloc_phys(found, size, 0, 0); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci return found; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci/** 13788c2ecf20Sopenharmony_ci * memblock_phys_alloc_range - allocate a memory block inside specified range 13798c2ecf20Sopenharmony_ci * @size: size of memory block to be allocated in bytes 13808c2ecf20Sopenharmony_ci * @align: alignment of the region and block's size 13818c2ecf20Sopenharmony_ci * @start: the lower bound of the memory region to allocate (physical address) 13828c2ecf20Sopenharmony_ci * @end: the upper bound of the memory region to allocate (physical address) 13838c2ecf20Sopenharmony_ci * 13848c2ecf20Sopenharmony_ci * Allocate @size bytes in the between @start and @end. 13858c2ecf20Sopenharmony_ci * 13868c2ecf20Sopenharmony_ci * Return: physical address of the allocated memory block on success, 13878c2ecf20Sopenharmony_ci * %0 on failure. 13888c2ecf20Sopenharmony_ci */ 13898c2ecf20Sopenharmony_ciphys_addr_t __init memblock_phys_alloc_range(phys_addr_t size, 13908c2ecf20Sopenharmony_ci phys_addr_t align, 13918c2ecf20Sopenharmony_ci phys_addr_t start, 13928c2ecf20Sopenharmony_ci phys_addr_t end) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE, 13958c2ecf20Sopenharmony_ci false); 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci/** 13998c2ecf20Sopenharmony_ci * memblock_phys_alloc_try_nid - allocate a memory block from specified MUMA node 14008c2ecf20Sopenharmony_ci * @size: size of memory block to be allocated in bytes 14018c2ecf20Sopenharmony_ci * @align: alignment of the region and block's size 14028c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 14038c2ecf20Sopenharmony_ci * 14048c2ecf20Sopenharmony_ci * Allocates memory block from the specified NUMA node. If the node 14058c2ecf20Sopenharmony_ci * has no available memory, attempts to allocated from any node in the 14068c2ecf20Sopenharmony_ci * system. 14078c2ecf20Sopenharmony_ci * 14088c2ecf20Sopenharmony_ci * Return: physical address of the allocated memory block on success, 14098c2ecf20Sopenharmony_ci * %0 on failure. 14108c2ecf20Sopenharmony_ci */ 14118c2ecf20Sopenharmony_ciphys_addr_t __init memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci return memblock_alloc_range_nid(size, align, 0, 14148c2ecf20Sopenharmony_ci MEMBLOCK_ALLOC_ACCESSIBLE, nid, false); 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci/** 14188c2ecf20Sopenharmony_ci * memblock_alloc_internal - allocate boot memory block 14198c2ecf20Sopenharmony_ci * @size: size of memory block to be allocated in bytes 14208c2ecf20Sopenharmony_ci * @align: alignment of the region and block's size 14218c2ecf20Sopenharmony_ci * @min_addr: the lower bound of the memory region to allocate (phys address) 14228c2ecf20Sopenharmony_ci * @max_addr: the upper bound of the memory region to allocate (phys address) 14238c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 14248c2ecf20Sopenharmony_ci * @exact_nid: control the allocation fall back to other nodes 14258c2ecf20Sopenharmony_ci * 14268c2ecf20Sopenharmony_ci * Allocates memory block using memblock_alloc_range_nid() and 14278c2ecf20Sopenharmony_ci * converts the returned physical address to virtual. 14288c2ecf20Sopenharmony_ci * 14298c2ecf20Sopenharmony_ci * The @min_addr limit is dropped if it can not be satisfied and the allocation 14308c2ecf20Sopenharmony_ci * will fall back to memory below @min_addr. Other constraints, such 14318c2ecf20Sopenharmony_ci * as node and mirrored memory will be handled again in 14328c2ecf20Sopenharmony_ci * memblock_alloc_range_nid(). 14338c2ecf20Sopenharmony_ci * 14348c2ecf20Sopenharmony_ci * Return: 14358c2ecf20Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 14368c2ecf20Sopenharmony_ci */ 14378c2ecf20Sopenharmony_cistatic void * __init memblock_alloc_internal( 14388c2ecf20Sopenharmony_ci phys_addr_t size, phys_addr_t align, 14398c2ecf20Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 14408c2ecf20Sopenharmony_ci int nid, bool exact_nid) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci phys_addr_t alloc; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci /* 14458c2ecf20Sopenharmony_ci * Detect any accidental use of these APIs after slab is ready, as at 14468c2ecf20Sopenharmony_ci * this moment memblock may be deinitialized already and its 14478c2ecf20Sopenharmony_ci * internal data may be destroyed (after execution of memblock_free_all) 14488c2ecf20Sopenharmony_ci */ 14498c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(slab_is_available())) 14508c2ecf20Sopenharmony_ci return kzalloc_node(size, GFP_NOWAIT, nid); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (max_addr > memblock.current_limit) 14538c2ecf20Sopenharmony_ci max_addr = memblock.current_limit; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid, 14568c2ecf20Sopenharmony_ci exact_nid); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* retry allocation without lower limit */ 14598c2ecf20Sopenharmony_ci if (!alloc && min_addr) 14608c2ecf20Sopenharmony_ci alloc = memblock_alloc_range_nid(size, align, 0, max_addr, nid, 14618c2ecf20Sopenharmony_ci exact_nid); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (!alloc) 14648c2ecf20Sopenharmony_ci return NULL; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci return phys_to_virt(alloc); 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci/** 14708c2ecf20Sopenharmony_ci * memblock_alloc_exact_nid_raw - allocate boot memory block on the exact node 14718c2ecf20Sopenharmony_ci * without zeroing memory 14728c2ecf20Sopenharmony_ci * @size: size of memory block to be allocated in bytes 14738c2ecf20Sopenharmony_ci * @align: alignment of the region and block's size 14748c2ecf20Sopenharmony_ci * @min_addr: the lower bound of the memory region from where the allocation 14758c2ecf20Sopenharmony_ci * is preferred (phys address) 14768c2ecf20Sopenharmony_ci * @max_addr: the upper bound of the memory region from where the allocation 14778c2ecf20Sopenharmony_ci * is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to 14788c2ecf20Sopenharmony_ci * allocate only from memory limited by memblock.current_limit value 14798c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 14808c2ecf20Sopenharmony_ci * 14818c2ecf20Sopenharmony_ci * Public function, provides additional debug information (including caller 14828c2ecf20Sopenharmony_ci * info), if enabled. Does not zero allocated memory. 14838c2ecf20Sopenharmony_ci * 14848c2ecf20Sopenharmony_ci * Return: 14858c2ecf20Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 14868c2ecf20Sopenharmony_ci */ 14878c2ecf20Sopenharmony_civoid * __init memblock_alloc_exact_nid_raw( 14888c2ecf20Sopenharmony_ci phys_addr_t size, phys_addr_t align, 14898c2ecf20Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 14908c2ecf20Sopenharmony_ci int nid) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci void *ptr; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n", 14958c2ecf20Sopenharmony_ci __func__, (u64)size, (u64)align, nid, &min_addr, 14968c2ecf20Sopenharmony_ci &max_addr, (void *)_RET_IP_); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci ptr = memblock_alloc_internal(size, align, 14998c2ecf20Sopenharmony_ci min_addr, max_addr, nid, true); 15008c2ecf20Sopenharmony_ci if (ptr && size > 0) 15018c2ecf20Sopenharmony_ci page_init_poison(ptr, size); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci return ptr; 15048c2ecf20Sopenharmony_ci} 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci/** 15078c2ecf20Sopenharmony_ci * memblock_alloc_try_nid_raw - allocate boot memory block without zeroing 15088c2ecf20Sopenharmony_ci * memory and without panicking 15098c2ecf20Sopenharmony_ci * @size: size of memory block to be allocated in bytes 15108c2ecf20Sopenharmony_ci * @align: alignment of the region and block's size 15118c2ecf20Sopenharmony_ci * @min_addr: the lower bound of the memory region from where the allocation 15128c2ecf20Sopenharmony_ci * is preferred (phys address) 15138c2ecf20Sopenharmony_ci * @max_addr: the upper bound of the memory region from where the allocation 15148c2ecf20Sopenharmony_ci * is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to 15158c2ecf20Sopenharmony_ci * allocate only from memory limited by memblock.current_limit value 15168c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 15178c2ecf20Sopenharmony_ci * 15188c2ecf20Sopenharmony_ci * Public function, provides additional debug information (including caller 15198c2ecf20Sopenharmony_ci * info), if enabled. Does not zero allocated memory, does not panic if request 15208c2ecf20Sopenharmony_ci * cannot be satisfied. 15218c2ecf20Sopenharmony_ci * 15228c2ecf20Sopenharmony_ci * Return: 15238c2ecf20Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 15248c2ecf20Sopenharmony_ci */ 15258c2ecf20Sopenharmony_civoid * __init memblock_alloc_try_nid_raw( 15268c2ecf20Sopenharmony_ci phys_addr_t size, phys_addr_t align, 15278c2ecf20Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 15288c2ecf20Sopenharmony_ci int nid) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci void *ptr; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n", 15338c2ecf20Sopenharmony_ci __func__, (u64)size, (u64)align, nid, &min_addr, 15348c2ecf20Sopenharmony_ci &max_addr, (void *)_RET_IP_); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci ptr = memblock_alloc_internal(size, align, 15378c2ecf20Sopenharmony_ci min_addr, max_addr, nid, false); 15388c2ecf20Sopenharmony_ci if (ptr && size > 0) 15398c2ecf20Sopenharmony_ci page_init_poison(ptr, size); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci return ptr; 15428c2ecf20Sopenharmony_ci} 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci/** 15458c2ecf20Sopenharmony_ci * memblock_alloc_try_nid - allocate boot memory block 15468c2ecf20Sopenharmony_ci * @size: size of memory block to be allocated in bytes 15478c2ecf20Sopenharmony_ci * @align: alignment of the region and block's size 15488c2ecf20Sopenharmony_ci * @min_addr: the lower bound of the memory region from where the allocation 15498c2ecf20Sopenharmony_ci * is preferred (phys address) 15508c2ecf20Sopenharmony_ci * @max_addr: the upper bound of the memory region from where the allocation 15518c2ecf20Sopenharmony_ci * is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to 15528c2ecf20Sopenharmony_ci * allocate only from memory limited by memblock.current_limit value 15538c2ecf20Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 15548c2ecf20Sopenharmony_ci * 15558c2ecf20Sopenharmony_ci * Public function, provides additional debug information (including caller 15568c2ecf20Sopenharmony_ci * info), if enabled. This function zeroes the allocated memory. 15578c2ecf20Sopenharmony_ci * 15588c2ecf20Sopenharmony_ci * Return: 15598c2ecf20Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 15608c2ecf20Sopenharmony_ci */ 15618c2ecf20Sopenharmony_civoid * __init memblock_alloc_try_nid( 15628c2ecf20Sopenharmony_ci phys_addr_t size, phys_addr_t align, 15638c2ecf20Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 15648c2ecf20Sopenharmony_ci int nid) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci void *ptr; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n", 15698c2ecf20Sopenharmony_ci __func__, (u64)size, (u64)align, nid, &min_addr, 15708c2ecf20Sopenharmony_ci &max_addr, (void *)_RET_IP_); 15718c2ecf20Sopenharmony_ci ptr = memblock_alloc_internal(size, align, 15728c2ecf20Sopenharmony_ci min_addr, max_addr, nid, false); 15738c2ecf20Sopenharmony_ci if (ptr) 15748c2ecf20Sopenharmony_ci memset(ptr, 0, size); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci return ptr; 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci/** 15808c2ecf20Sopenharmony_ci * __memblock_free_late - free pages directly to buddy allocator 15818c2ecf20Sopenharmony_ci * @base: phys starting address of the boot memory block 15828c2ecf20Sopenharmony_ci * @size: size of the boot memory block in bytes 15838c2ecf20Sopenharmony_ci * 15848c2ecf20Sopenharmony_ci * This is only useful when the memblock allocator has already been torn 15858c2ecf20Sopenharmony_ci * down, but we are still initializing the system. Pages are released directly 15868c2ecf20Sopenharmony_ci * to the buddy allocator. 15878c2ecf20Sopenharmony_ci */ 15888c2ecf20Sopenharmony_civoid __init __memblock_free_late(phys_addr_t base, phys_addr_t size) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci phys_addr_t cursor, end; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci end = base + size - 1; 15938c2ecf20Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", 15948c2ecf20Sopenharmony_ci __func__, &base, &end, (void *)_RET_IP_); 15958c2ecf20Sopenharmony_ci kmemleak_free_part_phys(base, size); 15968c2ecf20Sopenharmony_ci cursor = PFN_UP(base); 15978c2ecf20Sopenharmony_ci end = PFN_DOWN(base + size); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci for (; cursor < end; cursor++) { 16008c2ecf20Sopenharmony_ci memblock_free_pages(pfn_to_page(cursor), cursor, 0); 16018c2ecf20Sopenharmony_ci totalram_pages_inc(); 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci/* 16068c2ecf20Sopenharmony_ci * Remaining API functions 16078c2ecf20Sopenharmony_ci */ 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ciphys_addr_t __init_memblock memblock_phys_mem_size(void) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci return memblock.memory.total_size; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ciphys_addr_t __init_memblock memblock_reserved_size(void) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci return memblock.reserved.total_size; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci/* lowest address */ 16208c2ecf20Sopenharmony_ciphys_addr_t __init_memblock memblock_start_of_DRAM(void) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci return memblock.memory.regions[0].base; 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ciphys_addr_t __init_memblock memblock_end_of_DRAM(void) 16268c2ecf20Sopenharmony_ci{ 16278c2ecf20Sopenharmony_ci int idx = memblock.memory.cnt - 1; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size); 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci phys_addr_t max_addr = PHYS_ADDR_MAX; 16358c2ecf20Sopenharmony_ci struct memblock_region *r; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci /* 16388c2ecf20Sopenharmony_ci * translate the memory @limit size into the max address within one of 16398c2ecf20Sopenharmony_ci * the memory memblock regions, if the @limit exceeds the total size 16408c2ecf20Sopenharmony_ci * of those regions, max_addr will keep original value PHYS_ADDR_MAX 16418c2ecf20Sopenharmony_ci */ 16428c2ecf20Sopenharmony_ci for_each_mem_region(r) { 16438c2ecf20Sopenharmony_ci if (limit <= r->size) { 16448c2ecf20Sopenharmony_ci max_addr = r->base + limit; 16458c2ecf20Sopenharmony_ci break; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci limit -= r->size; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci return max_addr; 16518c2ecf20Sopenharmony_ci} 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_civoid __init memblock_enforce_memory_limit(phys_addr_t limit) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci phys_addr_t max_addr; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (!limit) 16588c2ecf20Sopenharmony_ci return; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci max_addr = __find_max_addr(limit); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci /* @limit exceeds the total size of the memory, do nothing */ 16638c2ecf20Sopenharmony_ci if (max_addr == PHYS_ADDR_MAX) 16648c2ecf20Sopenharmony_ci return; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci /* truncate both memory and reserved regions */ 16678c2ecf20Sopenharmony_ci memblock_remove_range(&memblock.memory, max_addr, 16688c2ecf20Sopenharmony_ci PHYS_ADDR_MAX); 16698c2ecf20Sopenharmony_ci memblock_remove_range(&memblock.reserved, max_addr, 16708c2ecf20Sopenharmony_ci PHYS_ADDR_MAX); 16718c2ecf20Sopenharmony_ci} 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_civoid __init memblock_cap_memory_range(phys_addr_t base, phys_addr_t size) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci int start_rgn, end_rgn; 16768c2ecf20Sopenharmony_ci int i, ret; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (!size) 16798c2ecf20Sopenharmony_ci return; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci ret = memblock_isolate_range(&memblock.memory, base, size, 16828c2ecf20Sopenharmony_ci &start_rgn, &end_rgn); 16838c2ecf20Sopenharmony_ci if (ret) 16848c2ecf20Sopenharmony_ci return; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* remove all the MAP regions */ 16878c2ecf20Sopenharmony_ci for (i = memblock.memory.cnt - 1; i >= end_rgn; i--) 16888c2ecf20Sopenharmony_ci if (!memblock_is_nomap(&memblock.memory.regions[i])) 16898c2ecf20Sopenharmony_ci memblock_remove_region(&memblock.memory, i); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci for (i = start_rgn - 1; i >= 0; i--) 16928c2ecf20Sopenharmony_ci if (!memblock_is_nomap(&memblock.memory.regions[i])) 16938c2ecf20Sopenharmony_ci memblock_remove_region(&memblock.memory, i); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci /* truncate the reserved regions */ 16968c2ecf20Sopenharmony_ci memblock_remove_range(&memblock.reserved, 0, base); 16978c2ecf20Sopenharmony_ci memblock_remove_range(&memblock.reserved, 16988c2ecf20Sopenharmony_ci base + size, PHYS_ADDR_MAX); 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_civoid __init memblock_mem_limit_remove_map(phys_addr_t limit) 17028c2ecf20Sopenharmony_ci{ 17038c2ecf20Sopenharmony_ci phys_addr_t max_addr; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (!limit) 17068c2ecf20Sopenharmony_ci return; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci max_addr = __find_max_addr(limit); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci /* @limit exceeds the total size of the memory, do nothing */ 17118c2ecf20Sopenharmony_ci if (max_addr == PHYS_ADDR_MAX) 17128c2ecf20Sopenharmony_ci return; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci memblock_cap_memory_range(0, max_addr); 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_cistatic int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) 17188c2ecf20Sopenharmony_ci{ 17198c2ecf20Sopenharmony_ci unsigned int left = 0, right = type->cnt; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci do { 17228c2ecf20Sopenharmony_ci unsigned int mid = (right + left) / 2; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (addr < type->regions[mid].base) 17258c2ecf20Sopenharmony_ci right = mid; 17268c2ecf20Sopenharmony_ci else if (addr >= (type->regions[mid].base + 17278c2ecf20Sopenharmony_ci type->regions[mid].size)) 17288c2ecf20Sopenharmony_ci left = mid + 1; 17298c2ecf20Sopenharmony_ci else 17308c2ecf20Sopenharmony_ci return mid; 17318c2ecf20Sopenharmony_ci } while (left < right); 17328c2ecf20Sopenharmony_ci return -1; 17338c2ecf20Sopenharmony_ci} 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_cibool __init_memblock memblock_is_reserved(phys_addr_t addr) 17368c2ecf20Sopenharmony_ci{ 17378c2ecf20Sopenharmony_ci return memblock_search(&memblock.reserved, addr) != -1; 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cibool __init_memblock memblock_is_memory(phys_addr_t addr) 17418c2ecf20Sopenharmony_ci{ 17428c2ecf20Sopenharmony_ci return memblock_search(&memblock.memory, addr) != -1; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_cibool __init_memblock memblock_is_map_memory(phys_addr_t addr) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci int i = memblock_search(&memblock.memory, addr); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (i == -1) 17508c2ecf20Sopenharmony_ci return false; 17518c2ecf20Sopenharmony_ci return !memblock_is_nomap(&memblock.memory.regions[i]); 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ciint __init_memblock memblock_search_pfn_nid(unsigned long pfn, 17558c2ecf20Sopenharmony_ci unsigned long *start_pfn, unsigned long *end_pfn) 17568c2ecf20Sopenharmony_ci{ 17578c2ecf20Sopenharmony_ci struct memblock_type *type = &memblock.memory; 17588c2ecf20Sopenharmony_ci int mid = memblock_search(type, PFN_PHYS(pfn)); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci if (mid == -1) 17618c2ecf20Sopenharmony_ci return -1; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci *start_pfn = PFN_DOWN(type->regions[mid].base); 17648c2ecf20Sopenharmony_ci *end_pfn = PFN_DOWN(type->regions[mid].base + type->regions[mid].size); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci return memblock_get_region_node(&type->regions[mid]); 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci/** 17708c2ecf20Sopenharmony_ci * memblock_is_region_memory - check if a region is a subset of memory 17718c2ecf20Sopenharmony_ci * @base: base of region to check 17728c2ecf20Sopenharmony_ci * @size: size of region to check 17738c2ecf20Sopenharmony_ci * 17748c2ecf20Sopenharmony_ci * Check if the region [@base, @base + @size) is a subset of a memory block. 17758c2ecf20Sopenharmony_ci * 17768c2ecf20Sopenharmony_ci * Return: 17778c2ecf20Sopenharmony_ci * 0 if false, non-zero if true 17788c2ecf20Sopenharmony_ci */ 17798c2ecf20Sopenharmony_cibool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) 17808c2ecf20Sopenharmony_ci{ 17818c2ecf20Sopenharmony_ci int idx = memblock_search(&memblock.memory, base); 17828c2ecf20Sopenharmony_ci phys_addr_t end = base + memblock_cap_size(base, &size); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (idx == -1) 17858c2ecf20Sopenharmony_ci return false; 17868c2ecf20Sopenharmony_ci return (memblock.memory.regions[idx].base + 17878c2ecf20Sopenharmony_ci memblock.memory.regions[idx].size) >= end; 17888c2ecf20Sopenharmony_ci} 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci/** 17918c2ecf20Sopenharmony_ci * memblock_is_region_reserved - check if a region intersects reserved memory 17928c2ecf20Sopenharmony_ci * @base: base of region to check 17938c2ecf20Sopenharmony_ci * @size: size of region to check 17948c2ecf20Sopenharmony_ci * 17958c2ecf20Sopenharmony_ci * Check if the region [@base, @base + @size) intersects a reserved 17968c2ecf20Sopenharmony_ci * memory block. 17978c2ecf20Sopenharmony_ci * 17988c2ecf20Sopenharmony_ci * Return: 17998c2ecf20Sopenharmony_ci * True if they intersect, false if not. 18008c2ecf20Sopenharmony_ci */ 18018c2ecf20Sopenharmony_cibool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci return memblock_overlaps_region(&memblock.reserved, base, size); 18048c2ecf20Sopenharmony_ci} 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_civoid __init_memblock memblock_trim_memory(phys_addr_t align) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci phys_addr_t start, end, orig_start, orig_end; 18098c2ecf20Sopenharmony_ci struct memblock_region *r; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci for_each_mem_region(r) { 18128c2ecf20Sopenharmony_ci orig_start = r->base; 18138c2ecf20Sopenharmony_ci orig_end = r->base + r->size; 18148c2ecf20Sopenharmony_ci start = round_up(orig_start, align); 18158c2ecf20Sopenharmony_ci end = round_down(orig_end, align); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci if (start == orig_start && end == orig_end) 18188c2ecf20Sopenharmony_ci continue; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci if (start < end) { 18218c2ecf20Sopenharmony_ci r->base = start; 18228c2ecf20Sopenharmony_ci r->size = end - start; 18238c2ecf20Sopenharmony_ci } else { 18248c2ecf20Sopenharmony_ci memblock_remove_region(&memblock.memory, 18258c2ecf20Sopenharmony_ci r - memblock.memory.regions); 18268c2ecf20Sopenharmony_ci r--; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_civoid __init_memblock memblock_set_current_limit(phys_addr_t limit) 18328c2ecf20Sopenharmony_ci{ 18338c2ecf20Sopenharmony_ci memblock.current_limit = limit; 18348c2ecf20Sopenharmony_ci} 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ciphys_addr_t __init_memblock memblock_get_current_limit(void) 18378c2ecf20Sopenharmony_ci{ 18388c2ecf20Sopenharmony_ci return memblock.current_limit; 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic void __init_memblock memblock_dump(struct memblock_type *type) 18428c2ecf20Sopenharmony_ci{ 18438c2ecf20Sopenharmony_ci phys_addr_t base, end, size; 18448c2ecf20Sopenharmony_ci enum memblock_flags flags; 18458c2ecf20Sopenharmony_ci int idx; 18468c2ecf20Sopenharmony_ci struct memblock_region *rgn; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci pr_info(" %s.cnt = 0x%lx\n", type->name, type->cnt); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci for_each_memblock_type(idx, type, rgn) { 18518c2ecf20Sopenharmony_ci char nid_buf[32] = ""; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci base = rgn->base; 18548c2ecf20Sopenharmony_ci size = rgn->size; 18558c2ecf20Sopenharmony_ci end = base + size - 1; 18568c2ecf20Sopenharmony_ci flags = rgn->flags; 18578c2ecf20Sopenharmony_ci#ifdef CONFIG_NEED_MULTIPLE_NODES 18588c2ecf20Sopenharmony_ci if (memblock_get_region_node(rgn) != MAX_NUMNODES) 18598c2ecf20Sopenharmony_ci snprintf(nid_buf, sizeof(nid_buf), " on node %d", 18608c2ecf20Sopenharmony_ci memblock_get_region_node(rgn)); 18618c2ecf20Sopenharmony_ci#endif 18628c2ecf20Sopenharmony_ci pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#x\n", 18638c2ecf20Sopenharmony_ci type->name, idx, &base, &end, &size, nid_buf, flags); 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic void __init_memblock __memblock_dump_all(void) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci pr_info("MEMBLOCK configuration:\n"); 18708c2ecf20Sopenharmony_ci pr_info(" memory size = %pa reserved size = %pa\n", 18718c2ecf20Sopenharmony_ci &memblock.memory.total_size, 18728c2ecf20Sopenharmony_ci &memblock.reserved.total_size); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci memblock_dump(&memblock.memory); 18758c2ecf20Sopenharmony_ci memblock_dump(&memblock.reserved); 18768c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 18778c2ecf20Sopenharmony_ci memblock_dump(&physmem); 18788c2ecf20Sopenharmony_ci#endif 18798c2ecf20Sopenharmony_ci} 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_civoid __init_memblock memblock_dump_all(void) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci if (memblock_debug) 18848c2ecf20Sopenharmony_ci __memblock_dump_all(); 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_civoid __init memblock_allow_resize(void) 18888c2ecf20Sopenharmony_ci{ 18898c2ecf20Sopenharmony_ci memblock_can_resize = 1; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_cistatic int __init early_memblock(char *p) 18938c2ecf20Sopenharmony_ci{ 18948c2ecf20Sopenharmony_ci if (p && strstr(p, "debug")) 18958c2ecf20Sopenharmony_ci memblock_debug = 1; 18968c2ecf20Sopenharmony_ci return 0; 18978c2ecf20Sopenharmony_ci} 18988c2ecf20Sopenharmony_ciearly_param("memblock", early_memblock); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_cistatic void __init __free_pages_memory(unsigned long start, unsigned long end) 19018c2ecf20Sopenharmony_ci{ 19028c2ecf20Sopenharmony_ci int order; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci while (start < end) { 19058c2ecf20Sopenharmony_ci order = min(MAX_ORDER - 1UL, __ffs(start)); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci while (start + (1UL << order) > end) 19088c2ecf20Sopenharmony_ci order--; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci memblock_free_pages(pfn_to_page(start), start, order); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci start += (1UL << order); 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci} 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_cistatic unsigned long __init __free_memory_core(phys_addr_t start, 19178c2ecf20Sopenharmony_ci phys_addr_t end) 19188c2ecf20Sopenharmony_ci{ 19198c2ecf20Sopenharmony_ci unsigned long start_pfn = PFN_UP(start); 19208c2ecf20Sopenharmony_ci unsigned long end_pfn = min_t(unsigned long, 19218c2ecf20Sopenharmony_ci PFN_DOWN(end), max_low_pfn); 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (start_pfn >= end_pfn) 19248c2ecf20Sopenharmony_ci return 0; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci __free_pages_memory(start_pfn, end_pfn); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci return end_pfn - start_pfn; 19298c2ecf20Sopenharmony_ci} 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_cistatic unsigned long __init free_low_memory_core_early(void) 19328c2ecf20Sopenharmony_ci{ 19338c2ecf20Sopenharmony_ci unsigned long count = 0; 19348c2ecf20Sopenharmony_ci phys_addr_t start, end; 19358c2ecf20Sopenharmony_ci u64 i; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci memblock_clear_hotplug(0, -1); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci for_each_reserved_mem_range(i, &start, &end) 19408c2ecf20Sopenharmony_ci reserve_bootmem_region(start, end); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* 19438c2ecf20Sopenharmony_ci * We need to use NUMA_NO_NODE instead of NODE_DATA(0)->node_id 19448c2ecf20Sopenharmony_ci * because in some case like Node0 doesn't have RAM installed 19458c2ecf20Sopenharmony_ci * low ram will be on Node1 19468c2ecf20Sopenharmony_ci */ 19478c2ecf20Sopenharmony_ci for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, 19488c2ecf20Sopenharmony_ci NULL) 19498c2ecf20Sopenharmony_ci count += __free_memory_core(start, end); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci return count; 19528c2ecf20Sopenharmony_ci} 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_cistatic int reset_managed_pages_done __initdata; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_civoid reset_node_managed_pages(pg_data_t *pgdat) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci struct zone *z; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) 19618c2ecf20Sopenharmony_ci atomic_long_set(&z->managed_pages, 0); 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_civoid __init reset_all_zones_managed_pages(void) 19658c2ecf20Sopenharmony_ci{ 19668c2ecf20Sopenharmony_ci struct pglist_data *pgdat; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci if (reset_managed_pages_done) 19698c2ecf20Sopenharmony_ci return; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci for_each_online_pgdat(pgdat) 19728c2ecf20Sopenharmony_ci reset_node_managed_pages(pgdat); 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci reset_managed_pages_done = 1; 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci/** 19788c2ecf20Sopenharmony_ci * memblock_free_all - release free pages to the buddy allocator 19798c2ecf20Sopenharmony_ci * 19808c2ecf20Sopenharmony_ci * Return: the number of pages actually released. 19818c2ecf20Sopenharmony_ci */ 19828c2ecf20Sopenharmony_ciunsigned long __init memblock_free_all(void) 19838c2ecf20Sopenharmony_ci{ 19848c2ecf20Sopenharmony_ci unsigned long pages; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci reset_all_zones_managed_pages(); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci pages = free_low_memory_core_early(); 19898c2ecf20Sopenharmony_ci totalram_pages_add(pages); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci return pages; 19928c2ecf20Sopenharmony_ci} 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK) 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_cistatic int memblock_debug_show(struct seq_file *m, void *private) 19978c2ecf20Sopenharmony_ci{ 19988c2ecf20Sopenharmony_ci struct memblock_type *type = m->private; 19998c2ecf20Sopenharmony_ci struct memblock_region *reg; 20008c2ecf20Sopenharmony_ci int i; 20018c2ecf20Sopenharmony_ci phys_addr_t end; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci for (i = 0; i < type->cnt; i++) { 20048c2ecf20Sopenharmony_ci reg = &type->regions[i]; 20058c2ecf20Sopenharmony_ci end = reg->base + reg->size - 1; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci seq_printf(m, "%4d: ", i); 20088c2ecf20Sopenharmony_ci seq_printf(m, "%pa..%pa\n", ®->base, &end); 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci return 0; 20118c2ecf20Sopenharmony_ci} 20128c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(memblock_debug); 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_cistatic int __init memblock_init_debugfs(void) 20158c2ecf20Sopenharmony_ci{ 20168c2ecf20Sopenharmony_ci struct dentry *root = debugfs_create_dir("memblock", NULL); 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci debugfs_create_file("memory", 0444, root, 20198c2ecf20Sopenharmony_ci &memblock.memory, &memblock_debug_fops); 20208c2ecf20Sopenharmony_ci debugfs_create_file("reserved", 0444, root, 20218c2ecf20Sopenharmony_ci &memblock.reserved, &memblock_debug_fops); 20228c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 20238c2ecf20Sopenharmony_ci debugfs_create_file("physmem", 0444, root, &physmem, 20248c2ecf20Sopenharmony_ci &memblock_debug_fops); 20258c2ecf20Sopenharmony_ci#endif 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci return 0; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci__initcall(memblock_init_debugfs); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 2032