162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Procedures for maintaining information about logical memory blocks. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Peter Bergner, IBM Corp. June 2001. 662306a36Sopenharmony_ci * Copyright (C) 2001 Peter Bergner. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/bitops.h> 1362306a36Sopenharmony_ci#include <linux/poison.h> 1462306a36Sopenharmony_ci#include <linux/pfn.h> 1562306a36Sopenharmony_ci#include <linux/debugfs.h> 1662306a36Sopenharmony_ci#include <linux/kmemleak.h> 1762306a36Sopenharmony_ci#include <linux/seq_file.h> 1862306a36Sopenharmony_ci#include <linux/memblock.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <asm/sections.h> 2162306a36Sopenharmony_ci#include <linux/io.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "internal.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define INIT_MEMBLOCK_REGIONS 128 2662306a36Sopenharmony_ci#define INIT_PHYSMEM_REGIONS 4 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#ifndef INIT_MEMBLOCK_RESERVED_REGIONS 2962306a36Sopenharmony_ci# define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS 3062306a36Sopenharmony_ci#endif 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#ifndef INIT_MEMBLOCK_MEMORY_REGIONS 3362306a36Sopenharmony_ci#define INIT_MEMBLOCK_MEMORY_REGIONS INIT_MEMBLOCK_REGIONS 3462306a36Sopenharmony_ci#endif 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/** 3762306a36Sopenharmony_ci * DOC: memblock overview 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * Memblock is a method of managing memory regions during the early 4062306a36Sopenharmony_ci * boot period when the usual kernel memory allocators are not up and 4162306a36Sopenharmony_ci * running. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * Memblock views the system memory as collections of contiguous 4462306a36Sopenharmony_ci * regions. There are several types of these collections: 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * * ``memory`` - describes the physical memory available to the 4762306a36Sopenharmony_ci * kernel; this may differ from the actual physical memory installed 4862306a36Sopenharmony_ci * in the system, for instance when the memory is restricted with 4962306a36Sopenharmony_ci * ``mem=`` command line parameter 5062306a36Sopenharmony_ci * * ``reserved`` - describes the regions that were allocated 5162306a36Sopenharmony_ci * * ``physmem`` - describes the actual physical memory available during 5262306a36Sopenharmony_ci * boot regardless of the possible restrictions and memory hot(un)plug; 5362306a36Sopenharmony_ci * the ``physmem`` type is only available on some architectures. 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * Each region is represented by struct memblock_region that 5662306a36Sopenharmony_ci * defines the region extents, its attributes and NUMA node id on NUMA 5762306a36Sopenharmony_ci * systems. Every memory type is described by the struct memblock_type 5862306a36Sopenharmony_ci * which contains an array of memory regions along with 5962306a36Sopenharmony_ci * the allocator metadata. The "memory" and "reserved" types are nicely 6062306a36Sopenharmony_ci * wrapped with struct memblock. This structure is statically 6162306a36Sopenharmony_ci * initialized at build time. The region arrays are initially sized to 6262306a36Sopenharmony_ci * %INIT_MEMBLOCK_MEMORY_REGIONS for "memory" and 6362306a36Sopenharmony_ci * %INIT_MEMBLOCK_RESERVED_REGIONS for "reserved". The region array 6462306a36Sopenharmony_ci * for "physmem" is initially sized to %INIT_PHYSMEM_REGIONS. 6562306a36Sopenharmony_ci * The memblock_allow_resize() enables automatic resizing of the region 6662306a36Sopenharmony_ci * arrays during addition of new regions. This feature should be used 6762306a36Sopenharmony_ci * with care so that memory allocated for the region array will not 6862306a36Sopenharmony_ci * overlap with areas that should be reserved, for example initrd. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * The early architecture setup should tell memblock what the physical 7162306a36Sopenharmony_ci * memory layout is by using memblock_add() or memblock_add_node() 7262306a36Sopenharmony_ci * functions. The first function does not assign the region to a NUMA 7362306a36Sopenharmony_ci * node and it is appropriate for UMA systems. Yet, it is possible to 7462306a36Sopenharmony_ci * use it on NUMA systems as well and assign the region to a NUMA node 7562306a36Sopenharmony_ci * later in the setup process using memblock_set_node(). The 7662306a36Sopenharmony_ci * memblock_add_node() performs such an assignment directly. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Once memblock is setup the memory can be allocated using one of the 7962306a36Sopenharmony_ci * API variants: 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * * memblock_phys_alloc*() - these functions return the **physical** 8262306a36Sopenharmony_ci * address of the allocated memory 8362306a36Sopenharmony_ci * * memblock_alloc*() - these functions return the **virtual** address 8462306a36Sopenharmony_ci * of the allocated memory. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Note, that both API variants use implicit assumptions about allowed 8762306a36Sopenharmony_ci * memory ranges and the fallback methods. Consult the documentation 8862306a36Sopenharmony_ci * of memblock_alloc_internal() and memblock_alloc_range_nid() 8962306a36Sopenharmony_ci * functions for more elaborate description. 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * As the system boot progresses, the architecture specific mem_init() 9262306a36Sopenharmony_ci * function frees all the memory to the buddy page allocator. 9362306a36Sopenharmony_ci * 9462306a36Sopenharmony_ci * Unless an architecture enables %CONFIG_ARCH_KEEP_MEMBLOCK, the 9562306a36Sopenharmony_ci * memblock data structures (except "physmem") will be discarded after the 9662306a36Sopenharmony_ci * system initialization completes. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#ifndef CONFIG_NUMA 10062306a36Sopenharmony_cistruct pglist_data __refdata contig_page_data; 10162306a36Sopenharmony_ciEXPORT_SYMBOL(contig_page_data); 10262306a36Sopenharmony_ci#endif 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciunsigned long max_low_pfn; 10562306a36Sopenharmony_ciunsigned long min_low_pfn; 10662306a36Sopenharmony_ciunsigned long max_pfn; 10762306a36Sopenharmony_ciunsigned long long max_possible_pfn; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_MEMORY_REGIONS] __initdata_memblock; 11062306a36Sopenharmony_cistatic struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_RESERVED_REGIONS] __initdata_memblock; 11162306a36Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 11262306a36Sopenharmony_cistatic struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS]; 11362306a36Sopenharmony_ci#endif 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistruct memblock memblock __initdata_memblock = { 11662306a36Sopenharmony_ci .memory.regions = memblock_memory_init_regions, 11762306a36Sopenharmony_ci .memory.cnt = 1, /* empty dummy entry */ 11862306a36Sopenharmony_ci .memory.max = INIT_MEMBLOCK_MEMORY_REGIONS, 11962306a36Sopenharmony_ci .memory.name = "memory", 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci .reserved.regions = memblock_reserved_init_regions, 12262306a36Sopenharmony_ci .reserved.cnt = 1, /* empty dummy entry */ 12362306a36Sopenharmony_ci .reserved.max = INIT_MEMBLOCK_RESERVED_REGIONS, 12462306a36Sopenharmony_ci .reserved.name = "reserved", 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci .bottom_up = false, 12762306a36Sopenharmony_ci .current_limit = MEMBLOCK_ALLOC_ANYWHERE, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 13162306a36Sopenharmony_cistruct memblock_type physmem = { 13262306a36Sopenharmony_ci .regions = memblock_physmem_init_regions, 13362306a36Sopenharmony_ci .cnt = 1, /* empty dummy entry */ 13462306a36Sopenharmony_ci .max = INIT_PHYSMEM_REGIONS, 13562306a36Sopenharmony_ci .name = "physmem", 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci#endif 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * keep a pointer to &memblock.memory in the text section to use it in 14162306a36Sopenharmony_ci * __next_mem_range() and its helpers. 14262306a36Sopenharmony_ci * For architectures that do not keep memblock data after init, this 14362306a36Sopenharmony_ci * pointer will be reset to NULL at memblock_discard() 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic __refdata struct memblock_type *memblock_memory = &memblock.memory; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define for_each_memblock_type(i, memblock_type, rgn) \ 14862306a36Sopenharmony_ci for (i = 0, rgn = &memblock_type->regions[0]; \ 14962306a36Sopenharmony_ci i < memblock_type->cnt; \ 15062306a36Sopenharmony_ci i++, rgn = &memblock_type->regions[i]) 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#define memblock_dbg(fmt, ...) \ 15362306a36Sopenharmony_ci do { \ 15462306a36Sopenharmony_ci if (memblock_debug) \ 15562306a36Sopenharmony_ci pr_info(fmt, ##__VA_ARGS__); \ 15662306a36Sopenharmony_ci } while (0) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int memblock_debug __initdata_memblock; 15962306a36Sopenharmony_cistatic bool system_has_some_mirror __initdata_memblock; 16062306a36Sopenharmony_cistatic int memblock_can_resize __initdata_memblock; 16162306a36Sopenharmony_cistatic int memblock_memory_in_slab __initdata_memblock; 16262306a36Sopenharmony_cistatic int memblock_reserved_in_slab __initdata_memblock; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cibool __init_memblock memblock_has_mirror(void) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci return system_has_some_mirror; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic enum memblock_flags __init_memblock choose_memblock_flags(void) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci return system_has_some_mirror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* adjust *@size so that (@base + *@size) doesn't overflow, return new size */ 17562306a36Sopenharmony_cistatic inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return *size = min(*size, PHYS_ADDR_MAX - base); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * Address comparison utilities 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ciunsigned long __init_memblock 18462306a36Sopenharmony_cimemblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1, phys_addr_t base2, 18562306a36Sopenharmony_ci phys_addr_t size2) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cibool __init_memblock memblock_overlaps_region(struct memblock_type *type, 19162306a36Sopenharmony_ci phys_addr_t base, phys_addr_t size) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci unsigned long i; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci memblock_cap_size(base, &size); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci for (i = 0; i < type->cnt; i++) 19862306a36Sopenharmony_ci if (memblock_addrs_overlap(base, size, type->regions[i].base, 19962306a36Sopenharmony_ci type->regions[i].size)) 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci return i < type->cnt; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/** 20562306a36Sopenharmony_ci * __memblock_find_range_bottom_up - find free area utility in bottom-up 20662306a36Sopenharmony_ci * @start: start of candidate range 20762306a36Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 20862306a36Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 20962306a36Sopenharmony_ci * @size: size of free area to find 21062306a36Sopenharmony_ci * @align: alignment of free area to find 21162306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 21262306a36Sopenharmony_ci * @flags: pick from blocks based on memory attributes 21362306a36Sopenharmony_ci * 21462306a36Sopenharmony_ci * Utility called from memblock_find_in_range_node(), find free area bottom-up. 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Return: 21762306a36Sopenharmony_ci * Found address on success, 0 on failure. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistatic phys_addr_t __init_memblock 22062306a36Sopenharmony_ci__memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, 22162306a36Sopenharmony_ci phys_addr_t size, phys_addr_t align, int nid, 22262306a36Sopenharmony_ci enum memblock_flags flags) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci phys_addr_t this_start, this_end, cand; 22562306a36Sopenharmony_ci u64 i; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci for_each_free_mem_range(i, nid, flags, &this_start, &this_end, NULL) { 22862306a36Sopenharmony_ci this_start = clamp(this_start, start, end); 22962306a36Sopenharmony_ci this_end = clamp(this_end, start, end); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci cand = round_up(this_start, align); 23262306a36Sopenharmony_ci if (cand < this_end && this_end - cand >= size) 23362306a36Sopenharmony_ci return cand; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/** 24062306a36Sopenharmony_ci * __memblock_find_range_top_down - find free area utility, in top-down 24162306a36Sopenharmony_ci * @start: start of candidate range 24262306a36Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 24362306a36Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 24462306a36Sopenharmony_ci * @size: size of free area to find 24562306a36Sopenharmony_ci * @align: alignment of free area to find 24662306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 24762306a36Sopenharmony_ci * @flags: pick from blocks based on memory attributes 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * Utility called from memblock_find_in_range_node(), find free area top-down. 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * Return: 25262306a36Sopenharmony_ci * Found address on success, 0 on failure. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_cistatic phys_addr_t __init_memblock 25562306a36Sopenharmony_ci__memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, 25662306a36Sopenharmony_ci phys_addr_t size, phys_addr_t align, int nid, 25762306a36Sopenharmony_ci enum memblock_flags flags) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci phys_addr_t this_start, this_end, cand; 26062306a36Sopenharmony_ci u64 i; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci for_each_free_mem_range_reverse(i, nid, flags, &this_start, &this_end, 26362306a36Sopenharmony_ci NULL) { 26462306a36Sopenharmony_ci this_start = clamp(this_start, start, end); 26562306a36Sopenharmony_ci this_end = clamp(this_end, start, end); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (this_end < size) 26862306a36Sopenharmony_ci continue; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci cand = round_down(this_end - size, align); 27162306a36Sopenharmony_ci if (cand >= this_start) 27262306a36Sopenharmony_ci return cand; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/** 27962306a36Sopenharmony_ci * memblock_find_in_range_node - find free area in given range and node 28062306a36Sopenharmony_ci * @size: size of free area to find 28162306a36Sopenharmony_ci * @align: alignment of free area to find 28262306a36Sopenharmony_ci * @start: start of candidate range 28362306a36Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 28462306a36Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 28562306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 28662306a36Sopenharmony_ci * @flags: pick from blocks based on memory attributes 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * Find @size free area aligned to @align in the specified range and node. 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * Return: 29162306a36Sopenharmony_ci * Found address on success, 0 on failure. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_cistatic phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, 29462306a36Sopenharmony_ci phys_addr_t align, phys_addr_t start, 29562306a36Sopenharmony_ci phys_addr_t end, int nid, 29662306a36Sopenharmony_ci enum memblock_flags flags) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci /* pump up @end */ 29962306a36Sopenharmony_ci if (end == MEMBLOCK_ALLOC_ACCESSIBLE || 30062306a36Sopenharmony_ci end == MEMBLOCK_ALLOC_NOLEAKTRACE) 30162306a36Sopenharmony_ci end = memblock.current_limit; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* avoid allocating the first page */ 30462306a36Sopenharmony_ci start = max_t(phys_addr_t, start, PAGE_SIZE); 30562306a36Sopenharmony_ci end = max(start, end); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (memblock_bottom_up()) 30862306a36Sopenharmony_ci return __memblock_find_range_bottom_up(start, end, size, align, 30962306a36Sopenharmony_ci nid, flags); 31062306a36Sopenharmony_ci else 31162306a36Sopenharmony_ci return __memblock_find_range_top_down(start, end, size, align, 31262306a36Sopenharmony_ci nid, flags); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/** 31662306a36Sopenharmony_ci * memblock_find_in_range - find free area in given range 31762306a36Sopenharmony_ci * @start: start of candidate range 31862306a36Sopenharmony_ci * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or 31962306a36Sopenharmony_ci * %MEMBLOCK_ALLOC_ACCESSIBLE 32062306a36Sopenharmony_ci * @size: size of free area to find 32162306a36Sopenharmony_ci * @align: alignment of free area to find 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * Find @size free area aligned to @align in the specified range. 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * Return: 32662306a36Sopenharmony_ci * Found address on success, 0 on failure. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_cistatic phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, 32962306a36Sopenharmony_ci phys_addr_t end, phys_addr_t size, 33062306a36Sopenharmony_ci phys_addr_t align) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci phys_addr_t ret; 33362306a36Sopenharmony_ci enum memblock_flags flags = choose_memblock_flags(); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciagain: 33662306a36Sopenharmony_ci ret = memblock_find_in_range_node(size, align, start, end, 33762306a36Sopenharmony_ci NUMA_NO_NODE, flags); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!ret && (flags & MEMBLOCK_MIRROR)) { 34062306a36Sopenharmony_ci pr_warn_ratelimited("Could not allocate %pap bytes of mirrored memory\n", 34162306a36Sopenharmony_ci &size); 34262306a36Sopenharmony_ci flags &= ~MEMBLOCK_MIRROR; 34362306a36Sopenharmony_ci goto again; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci type->total_size -= type->regions[r].size; 35262306a36Sopenharmony_ci memmove(&type->regions[r], &type->regions[r + 1], 35362306a36Sopenharmony_ci (type->cnt - (r + 1)) * sizeof(type->regions[r])); 35462306a36Sopenharmony_ci type->cnt--; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Special case for empty arrays */ 35762306a36Sopenharmony_ci if (type->cnt == 0) { 35862306a36Sopenharmony_ci WARN_ON(type->total_size != 0); 35962306a36Sopenharmony_ci type->cnt = 1; 36062306a36Sopenharmony_ci type->regions[0].base = 0; 36162306a36Sopenharmony_ci type->regions[0].size = 0; 36262306a36Sopenharmony_ci type->regions[0].flags = 0; 36362306a36Sopenharmony_ci memblock_set_region_node(&type->regions[0], MAX_NUMNODES); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci#ifndef CONFIG_ARCH_KEEP_MEMBLOCK 36862306a36Sopenharmony_ci/** 36962306a36Sopenharmony_ci * memblock_discard - discard memory and reserved arrays if they were allocated 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_civoid __init memblock_discard(void) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci phys_addr_t addr, size; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (memblock.reserved.regions != memblock_reserved_init_regions) { 37662306a36Sopenharmony_ci addr = __pa(memblock.reserved.regions); 37762306a36Sopenharmony_ci size = PAGE_ALIGN(sizeof(struct memblock_region) * 37862306a36Sopenharmony_ci memblock.reserved.max); 37962306a36Sopenharmony_ci if (memblock_reserved_in_slab) 38062306a36Sopenharmony_ci kfree(memblock.reserved.regions); 38162306a36Sopenharmony_ci else 38262306a36Sopenharmony_ci memblock_free_late(addr, size); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (memblock.memory.regions != memblock_memory_init_regions) { 38662306a36Sopenharmony_ci addr = __pa(memblock.memory.regions); 38762306a36Sopenharmony_ci size = PAGE_ALIGN(sizeof(struct memblock_region) * 38862306a36Sopenharmony_ci memblock.memory.max); 38962306a36Sopenharmony_ci if (memblock_memory_in_slab) 39062306a36Sopenharmony_ci kfree(memblock.memory.regions); 39162306a36Sopenharmony_ci else 39262306a36Sopenharmony_ci memblock_free_late(addr, size); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci memblock_memory = NULL; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci#endif 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/** 40062306a36Sopenharmony_ci * memblock_double_array - double the size of the memblock regions array 40162306a36Sopenharmony_ci * @type: memblock type of the regions array being doubled 40262306a36Sopenharmony_ci * @new_area_start: starting address of memory range to avoid overlap with 40362306a36Sopenharmony_ci * @new_area_size: size of memory range to avoid overlap with 40462306a36Sopenharmony_ci * 40562306a36Sopenharmony_ci * Double the size of the @type regions array. If memblock is being used to 40662306a36Sopenharmony_ci * allocate memory for a new reserved regions array and there is a previously 40762306a36Sopenharmony_ci * allocated memory range [@new_area_start, @new_area_start + @new_area_size] 40862306a36Sopenharmony_ci * waiting to be reserved, ensure the memory used by the new array does 40962306a36Sopenharmony_ci * not overlap. 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * Return: 41262306a36Sopenharmony_ci * 0 on success, -1 on failure. 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_cistatic int __init_memblock memblock_double_array(struct memblock_type *type, 41562306a36Sopenharmony_ci phys_addr_t new_area_start, 41662306a36Sopenharmony_ci phys_addr_t new_area_size) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct memblock_region *new_array, *old_array; 41962306a36Sopenharmony_ci phys_addr_t old_alloc_size, new_alloc_size; 42062306a36Sopenharmony_ci phys_addr_t old_size, new_size, addr, new_end; 42162306a36Sopenharmony_ci int use_slab = slab_is_available(); 42262306a36Sopenharmony_ci int *in_slab; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* We don't allow resizing until we know about the reserved regions 42562306a36Sopenharmony_ci * of memory that aren't suitable for allocation 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (!memblock_can_resize) 42862306a36Sopenharmony_ci return -1; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Calculate new doubled size */ 43162306a36Sopenharmony_ci old_size = type->max * sizeof(struct memblock_region); 43262306a36Sopenharmony_ci new_size = old_size << 1; 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * We need to allocated new one align to PAGE_SIZE, 43562306a36Sopenharmony_ci * so we can free them completely later. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci old_alloc_size = PAGE_ALIGN(old_size); 43862306a36Sopenharmony_ci new_alloc_size = PAGE_ALIGN(new_size); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Retrieve the slab flag */ 44162306a36Sopenharmony_ci if (type == &memblock.memory) 44262306a36Sopenharmony_ci in_slab = &memblock_memory_in_slab; 44362306a36Sopenharmony_ci else 44462306a36Sopenharmony_ci in_slab = &memblock_reserved_in_slab; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* Try to find some space for it */ 44762306a36Sopenharmony_ci if (use_slab) { 44862306a36Sopenharmony_ci new_array = kmalloc(new_size, GFP_KERNEL); 44962306a36Sopenharmony_ci addr = new_array ? __pa(new_array) : 0; 45062306a36Sopenharmony_ci } else { 45162306a36Sopenharmony_ci /* only exclude range when trying to double reserved.regions */ 45262306a36Sopenharmony_ci if (type != &memblock.reserved) 45362306a36Sopenharmony_ci new_area_start = new_area_size = 0; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci addr = memblock_find_in_range(new_area_start + new_area_size, 45662306a36Sopenharmony_ci memblock.current_limit, 45762306a36Sopenharmony_ci new_alloc_size, PAGE_SIZE); 45862306a36Sopenharmony_ci if (!addr && new_area_size) 45962306a36Sopenharmony_ci addr = memblock_find_in_range(0, 46062306a36Sopenharmony_ci min(new_area_start, memblock.current_limit), 46162306a36Sopenharmony_ci new_alloc_size, PAGE_SIZE); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci new_array = addr ? __va(addr) : NULL; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci if (!addr) { 46662306a36Sopenharmony_ci pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", 46762306a36Sopenharmony_ci type->name, type->max, type->max * 2); 46862306a36Sopenharmony_ci return -1; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci new_end = addr + new_size - 1; 47262306a36Sopenharmony_ci memblock_dbg("memblock: %s is doubled to %ld at [%pa-%pa]", 47362306a36Sopenharmony_ci type->name, type->max * 2, &addr, &new_end); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* 47662306a36Sopenharmony_ci * Found space, we now need to move the array over before we add the 47762306a36Sopenharmony_ci * reserved region since it may be our reserved array itself that is 47862306a36Sopenharmony_ci * full. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci memcpy(new_array, type->regions, old_size); 48162306a36Sopenharmony_ci memset(new_array + type->max, 0, old_size); 48262306a36Sopenharmony_ci old_array = type->regions; 48362306a36Sopenharmony_ci type->regions = new_array; 48462306a36Sopenharmony_ci type->max <<= 1; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Free old array. We needn't free it if the array is the static one */ 48762306a36Sopenharmony_ci if (*in_slab) 48862306a36Sopenharmony_ci kfree(old_array); 48962306a36Sopenharmony_ci else if (old_array != memblock_memory_init_regions && 49062306a36Sopenharmony_ci old_array != memblock_reserved_init_regions) 49162306a36Sopenharmony_ci memblock_free(old_array, old_alloc_size); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* 49462306a36Sopenharmony_ci * Reserve the new array if that comes from the memblock. Otherwise, we 49562306a36Sopenharmony_ci * needn't do it 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci if (!use_slab) 49862306a36Sopenharmony_ci BUG_ON(memblock_reserve(addr, new_alloc_size)); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* Update slab flag */ 50162306a36Sopenharmony_ci *in_slab = use_slab; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/** 50762306a36Sopenharmony_ci * memblock_merge_regions - merge neighboring compatible regions 50862306a36Sopenharmony_ci * @type: memblock type to scan 50962306a36Sopenharmony_ci * @start_rgn: start scanning from (@start_rgn - 1) 51062306a36Sopenharmony_ci * @end_rgn: end scanning at (@end_rgn - 1) 51162306a36Sopenharmony_ci * Scan @type and merge neighboring compatible regions in [@start_rgn - 1, @end_rgn) 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_cistatic void __init_memblock memblock_merge_regions(struct memblock_type *type, 51462306a36Sopenharmony_ci unsigned long start_rgn, 51562306a36Sopenharmony_ci unsigned long end_rgn) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci int i = 0; 51862306a36Sopenharmony_ci if (start_rgn) 51962306a36Sopenharmony_ci i = start_rgn - 1; 52062306a36Sopenharmony_ci end_rgn = min(end_rgn, type->cnt - 1); 52162306a36Sopenharmony_ci while (i < end_rgn) { 52262306a36Sopenharmony_ci struct memblock_region *this = &type->regions[i]; 52362306a36Sopenharmony_ci struct memblock_region *next = &type->regions[i + 1]; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (this->base + this->size != next->base || 52662306a36Sopenharmony_ci memblock_get_region_node(this) != 52762306a36Sopenharmony_ci memblock_get_region_node(next) || 52862306a36Sopenharmony_ci this->flags != next->flags) { 52962306a36Sopenharmony_ci BUG_ON(this->base + this->size > next->base); 53062306a36Sopenharmony_ci i++; 53162306a36Sopenharmony_ci continue; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci this->size += next->size; 53562306a36Sopenharmony_ci /* move forward from next + 1, index of which is i + 2 */ 53662306a36Sopenharmony_ci memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next)); 53762306a36Sopenharmony_ci type->cnt--; 53862306a36Sopenharmony_ci end_rgn--; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/** 54362306a36Sopenharmony_ci * memblock_insert_region - insert new memblock region 54462306a36Sopenharmony_ci * @type: memblock type to insert into 54562306a36Sopenharmony_ci * @idx: index for the insertion point 54662306a36Sopenharmony_ci * @base: base address of the new region 54762306a36Sopenharmony_ci * @size: size of the new region 54862306a36Sopenharmony_ci * @nid: node id of the new region 54962306a36Sopenharmony_ci * @flags: flags of the new region 55062306a36Sopenharmony_ci * 55162306a36Sopenharmony_ci * Insert new memblock region [@base, @base + @size) into @type at @idx. 55262306a36Sopenharmony_ci * @type must already have extra room to accommodate the new region. 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_cistatic void __init_memblock memblock_insert_region(struct memblock_type *type, 55562306a36Sopenharmony_ci int idx, phys_addr_t base, 55662306a36Sopenharmony_ci phys_addr_t size, 55762306a36Sopenharmony_ci int nid, 55862306a36Sopenharmony_ci enum memblock_flags flags) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct memblock_region *rgn = &type->regions[idx]; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci BUG_ON(type->cnt >= type->max); 56362306a36Sopenharmony_ci memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn)); 56462306a36Sopenharmony_ci rgn->base = base; 56562306a36Sopenharmony_ci rgn->size = size; 56662306a36Sopenharmony_ci rgn->flags = flags; 56762306a36Sopenharmony_ci memblock_set_region_node(rgn, nid); 56862306a36Sopenharmony_ci type->cnt++; 56962306a36Sopenharmony_ci type->total_size += size; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/** 57362306a36Sopenharmony_ci * memblock_add_range - add new memblock region 57462306a36Sopenharmony_ci * @type: memblock type to add new region into 57562306a36Sopenharmony_ci * @base: base address of the new region 57662306a36Sopenharmony_ci * @size: size of the new region 57762306a36Sopenharmony_ci * @nid: nid of the new region 57862306a36Sopenharmony_ci * @flags: flags of the new region 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * Add new memblock region [@base, @base + @size) into @type. The new region 58162306a36Sopenharmony_ci * is allowed to overlap with existing ones - overlaps don't affect already 58262306a36Sopenharmony_ci * existing regions. @type is guaranteed to be minimal (all neighbouring 58362306a36Sopenharmony_ci * compatible regions are merged) after the addition. 58462306a36Sopenharmony_ci * 58562306a36Sopenharmony_ci * Return: 58662306a36Sopenharmony_ci * 0 on success, -errno on failure. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_cistatic int __init_memblock memblock_add_range(struct memblock_type *type, 58962306a36Sopenharmony_ci phys_addr_t base, phys_addr_t size, 59062306a36Sopenharmony_ci int nid, enum memblock_flags flags) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci bool insert = false; 59362306a36Sopenharmony_ci phys_addr_t obase = base; 59462306a36Sopenharmony_ci phys_addr_t end = base + memblock_cap_size(base, &size); 59562306a36Sopenharmony_ci int idx, nr_new, start_rgn = -1, end_rgn; 59662306a36Sopenharmony_ci struct memblock_region *rgn; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (!size) 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* special case for empty array */ 60262306a36Sopenharmony_ci if (type->regions[0].size == 0) { 60362306a36Sopenharmony_ci WARN_ON(type->cnt != 1 || type->total_size); 60462306a36Sopenharmony_ci type->regions[0].base = base; 60562306a36Sopenharmony_ci type->regions[0].size = size; 60662306a36Sopenharmony_ci type->regions[0].flags = flags; 60762306a36Sopenharmony_ci memblock_set_region_node(&type->regions[0], nid); 60862306a36Sopenharmony_ci type->total_size = size; 60962306a36Sopenharmony_ci return 0; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* 61362306a36Sopenharmony_ci * The worst case is when new range overlaps all existing regions, 61462306a36Sopenharmony_ci * then we'll need type->cnt + 1 empty regions in @type. So if 61562306a36Sopenharmony_ci * type->cnt * 2 + 1 is less than or equal to type->max, we know 61662306a36Sopenharmony_ci * that there is enough empty regions in @type, and we can insert 61762306a36Sopenharmony_ci * regions directly. 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_ci if (type->cnt * 2 + 1 <= type->max) 62062306a36Sopenharmony_ci insert = true; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cirepeat: 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * The following is executed twice. Once with %false @insert and 62562306a36Sopenharmony_ci * then with %true. The first counts the number of regions needed 62662306a36Sopenharmony_ci * to accommodate the new area. The second actually inserts them. 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_ci base = obase; 62962306a36Sopenharmony_ci nr_new = 0; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci for_each_memblock_type(idx, type, rgn) { 63262306a36Sopenharmony_ci phys_addr_t rbase = rgn->base; 63362306a36Sopenharmony_ci phys_addr_t rend = rbase + rgn->size; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (rbase >= end) 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci if (rend <= base) 63862306a36Sopenharmony_ci continue; 63962306a36Sopenharmony_ci /* 64062306a36Sopenharmony_ci * @rgn overlaps. If it separates the lower part of new 64162306a36Sopenharmony_ci * area, insert that portion. 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ci if (rbase > base) { 64462306a36Sopenharmony_ci#ifdef CONFIG_NUMA 64562306a36Sopenharmony_ci WARN_ON(nid != memblock_get_region_node(rgn)); 64662306a36Sopenharmony_ci#endif 64762306a36Sopenharmony_ci WARN_ON(flags != rgn->flags); 64862306a36Sopenharmony_ci nr_new++; 64962306a36Sopenharmony_ci if (insert) { 65062306a36Sopenharmony_ci if (start_rgn == -1) 65162306a36Sopenharmony_ci start_rgn = idx; 65262306a36Sopenharmony_ci end_rgn = idx + 1; 65362306a36Sopenharmony_ci memblock_insert_region(type, idx++, base, 65462306a36Sopenharmony_ci rbase - base, nid, 65562306a36Sopenharmony_ci flags); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci /* area below @rend is dealt with, forget about it */ 65962306a36Sopenharmony_ci base = min(rend, end); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* insert the remaining portion */ 66362306a36Sopenharmony_ci if (base < end) { 66462306a36Sopenharmony_ci nr_new++; 66562306a36Sopenharmony_ci if (insert) { 66662306a36Sopenharmony_ci if (start_rgn == -1) 66762306a36Sopenharmony_ci start_rgn = idx; 66862306a36Sopenharmony_ci end_rgn = idx + 1; 66962306a36Sopenharmony_ci memblock_insert_region(type, idx, base, end - base, 67062306a36Sopenharmony_ci nid, flags); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (!nr_new) 67562306a36Sopenharmony_ci return 0; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* 67862306a36Sopenharmony_ci * If this was the first round, resize array and repeat for actual 67962306a36Sopenharmony_ci * insertions; otherwise, merge and return. 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_ci if (!insert) { 68262306a36Sopenharmony_ci while (type->cnt + nr_new > type->max) 68362306a36Sopenharmony_ci if (memblock_double_array(type, obase, size) < 0) 68462306a36Sopenharmony_ci return -ENOMEM; 68562306a36Sopenharmony_ci insert = true; 68662306a36Sopenharmony_ci goto repeat; 68762306a36Sopenharmony_ci } else { 68862306a36Sopenharmony_ci memblock_merge_regions(type, start_rgn, end_rgn); 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/** 69462306a36Sopenharmony_ci * memblock_add_node - add new memblock region within a NUMA node 69562306a36Sopenharmony_ci * @base: base address of the new region 69662306a36Sopenharmony_ci * @size: size of the new region 69762306a36Sopenharmony_ci * @nid: nid of the new region 69862306a36Sopenharmony_ci * @flags: flags of the new region 69962306a36Sopenharmony_ci * 70062306a36Sopenharmony_ci * Add new memblock region [@base, @base + @size) to the "memory" 70162306a36Sopenharmony_ci * type. See memblock_add_range() description for mode details 70262306a36Sopenharmony_ci * 70362306a36Sopenharmony_ci * Return: 70462306a36Sopenharmony_ci * 0 on success, -errno on failure. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ciint __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size, 70762306a36Sopenharmony_ci int nid, enum memblock_flags flags) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci phys_addr_t end = base + size - 1; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] nid=%d flags=%x %pS\n", __func__, 71262306a36Sopenharmony_ci &base, &end, nid, flags, (void *)_RET_IP_); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return memblock_add_range(&memblock.memory, base, size, nid, flags); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/** 71862306a36Sopenharmony_ci * memblock_add - add new memblock region 71962306a36Sopenharmony_ci * @base: base address of the new region 72062306a36Sopenharmony_ci * @size: size of the new region 72162306a36Sopenharmony_ci * 72262306a36Sopenharmony_ci * Add new memblock region [@base, @base + @size) to the "memory" 72362306a36Sopenharmony_ci * type. See memblock_add_range() description for mode details 72462306a36Sopenharmony_ci * 72562306a36Sopenharmony_ci * Return: 72662306a36Sopenharmony_ci * 0 on success, -errno on failure. 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_ciint __init_memblock memblock_add(phys_addr_t base, phys_addr_t size) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci phys_addr_t end = base + size - 1; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 73362306a36Sopenharmony_ci &base, &end, (void *)_RET_IP_); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return memblock_add_range(&memblock.memory, base, size, MAX_NUMNODES, 0); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/** 73962306a36Sopenharmony_ci * memblock_isolate_range - isolate given range into disjoint memblocks 74062306a36Sopenharmony_ci * @type: memblock type to isolate range for 74162306a36Sopenharmony_ci * @base: base of range to isolate 74262306a36Sopenharmony_ci * @size: size of range to isolate 74362306a36Sopenharmony_ci * @start_rgn: out parameter for the start of isolated region 74462306a36Sopenharmony_ci * @end_rgn: out parameter for the end of isolated region 74562306a36Sopenharmony_ci * 74662306a36Sopenharmony_ci * Walk @type and ensure that regions don't cross the boundaries defined by 74762306a36Sopenharmony_ci * [@base, @base + @size). Crossing regions are split at the boundaries, 74862306a36Sopenharmony_ci * which may create at most two more regions. The index of the first 74962306a36Sopenharmony_ci * region inside the range is returned in *@start_rgn and end in *@end_rgn. 75062306a36Sopenharmony_ci * 75162306a36Sopenharmony_ci * Return: 75262306a36Sopenharmony_ci * 0 on success, -errno on failure. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_cistatic int __init_memblock memblock_isolate_range(struct memblock_type *type, 75562306a36Sopenharmony_ci phys_addr_t base, phys_addr_t size, 75662306a36Sopenharmony_ci int *start_rgn, int *end_rgn) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci phys_addr_t end = base + memblock_cap_size(base, &size); 75962306a36Sopenharmony_ci int idx; 76062306a36Sopenharmony_ci struct memblock_region *rgn; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci *start_rgn = *end_rgn = 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (!size) 76562306a36Sopenharmony_ci return 0; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci /* we'll create at most two more regions */ 76862306a36Sopenharmony_ci while (type->cnt + 2 > type->max) 76962306a36Sopenharmony_ci if (memblock_double_array(type, base, size) < 0) 77062306a36Sopenharmony_ci return -ENOMEM; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci for_each_memblock_type(idx, type, rgn) { 77362306a36Sopenharmony_ci phys_addr_t rbase = rgn->base; 77462306a36Sopenharmony_ci phys_addr_t rend = rbase + rgn->size; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (rbase >= end) 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci if (rend <= base) 77962306a36Sopenharmony_ci continue; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (rbase < base) { 78262306a36Sopenharmony_ci /* 78362306a36Sopenharmony_ci * @rgn intersects from below. Split and continue 78462306a36Sopenharmony_ci * to process the next region - the new top half. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci rgn->base = base; 78762306a36Sopenharmony_ci rgn->size -= base - rbase; 78862306a36Sopenharmony_ci type->total_size -= base - rbase; 78962306a36Sopenharmony_ci memblock_insert_region(type, idx, rbase, base - rbase, 79062306a36Sopenharmony_ci memblock_get_region_node(rgn), 79162306a36Sopenharmony_ci rgn->flags); 79262306a36Sopenharmony_ci } else if (rend > end) { 79362306a36Sopenharmony_ci /* 79462306a36Sopenharmony_ci * @rgn intersects from above. Split and redo the 79562306a36Sopenharmony_ci * current region - the new bottom half. 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_ci rgn->base = end; 79862306a36Sopenharmony_ci rgn->size -= end - rbase; 79962306a36Sopenharmony_ci type->total_size -= end - rbase; 80062306a36Sopenharmony_ci memblock_insert_region(type, idx--, rbase, end - rbase, 80162306a36Sopenharmony_ci memblock_get_region_node(rgn), 80262306a36Sopenharmony_ci rgn->flags); 80362306a36Sopenharmony_ci } else { 80462306a36Sopenharmony_ci /* @rgn is fully contained, record it */ 80562306a36Sopenharmony_ci if (!*end_rgn) 80662306a36Sopenharmony_ci *start_rgn = idx; 80762306a36Sopenharmony_ci *end_rgn = idx + 1; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int __init_memblock memblock_remove_range(struct memblock_type *type, 81562306a36Sopenharmony_ci phys_addr_t base, phys_addr_t size) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci int start_rgn, end_rgn; 81862306a36Sopenharmony_ci int i, ret; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); 82162306a36Sopenharmony_ci if (ret) 82262306a36Sopenharmony_ci return ret; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci for (i = end_rgn - 1; i >= start_rgn; i--) 82562306a36Sopenharmony_ci memblock_remove_region(type, i); 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ciint __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci phys_addr_t end = base + size - 1; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 83462306a36Sopenharmony_ci &base, &end, (void *)_RET_IP_); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci return memblock_remove_range(&memblock.memory, base, size); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci/** 84062306a36Sopenharmony_ci * memblock_free - free boot memory allocation 84162306a36Sopenharmony_ci * @ptr: starting address of the boot memory allocation 84262306a36Sopenharmony_ci * @size: size of the boot memory block in bytes 84362306a36Sopenharmony_ci * 84462306a36Sopenharmony_ci * Free boot memory block previously allocated by memblock_alloc_xx() API. 84562306a36Sopenharmony_ci * The freeing memory will not be released to the buddy allocator. 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_civoid __init_memblock memblock_free(void *ptr, size_t size) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci if (ptr) 85062306a36Sopenharmony_ci memblock_phys_free(__pa(ptr), size); 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci/** 85462306a36Sopenharmony_ci * memblock_phys_free - free boot memory block 85562306a36Sopenharmony_ci * @base: phys starting address of the boot memory block 85662306a36Sopenharmony_ci * @size: size of the boot memory block in bytes 85762306a36Sopenharmony_ci * 85862306a36Sopenharmony_ci * Free boot memory block previously allocated by memblock_phys_alloc_xx() API. 85962306a36Sopenharmony_ci * The freeing memory will not be released to the buddy allocator. 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ciint __init_memblock memblock_phys_free(phys_addr_t base, phys_addr_t size) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci phys_addr_t end = base + size - 1; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 86662306a36Sopenharmony_ci &base, &end, (void *)_RET_IP_); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci kmemleak_free_part_phys(base, size); 86962306a36Sopenharmony_ci return memblock_remove_range(&memblock.reserved, base, size); 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ciint __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci phys_addr_t end = base + size - 1; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 87762306a36Sopenharmony_ci &base, &end, (void *)_RET_IP_); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return memblock_add_range(&memblock.reserved, base, size, MAX_NUMNODES, 0); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 88362306a36Sopenharmony_ciint __init_memblock memblock_physmem_add(phys_addr_t base, phys_addr_t size) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci phys_addr_t end = base + size - 1; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", __func__, 88862306a36Sopenharmony_ci &base, &end, (void *)_RET_IP_); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci return memblock_add_range(&physmem, base, size, MAX_NUMNODES, 0); 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci#endif 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci/** 89562306a36Sopenharmony_ci * memblock_setclr_flag - set or clear flag for a memory region 89662306a36Sopenharmony_ci * @base: base address of the region 89762306a36Sopenharmony_ci * @size: size of the region 89862306a36Sopenharmony_ci * @set: set or clear the flag 89962306a36Sopenharmony_ci * @flag: the flag to update 90062306a36Sopenharmony_ci * 90162306a36Sopenharmony_ci * This function isolates region [@base, @base + @size), and sets/clears flag 90262306a36Sopenharmony_ci * 90362306a36Sopenharmony_ci * Return: 0 on success, -errno on failure. 90462306a36Sopenharmony_ci */ 90562306a36Sopenharmony_cistatic int __init_memblock memblock_setclr_flag(phys_addr_t base, 90662306a36Sopenharmony_ci phys_addr_t size, int set, int flag) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci struct memblock_type *type = &memblock.memory; 90962306a36Sopenharmony_ci int i, ret, start_rgn, end_rgn; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); 91262306a36Sopenharmony_ci if (ret) 91362306a36Sopenharmony_ci return ret; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci for (i = start_rgn; i < end_rgn; i++) { 91662306a36Sopenharmony_ci struct memblock_region *r = &type->regions[i]; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (set) 91962306a36Sopenharmony_ci r->flags |= flag; 92062306a36Sopenharmony_ci else 92162306a36Sopenharmony_ci r->flags &= ~flag; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci memblock_merge_regions(type, start_rgn, end_rgn); 92562306a36Sopenharmony_ci return 0; 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci/** 92962306a36Sopenharmony_ci * memblock_mark_hotplug - Mark hotpluggable memory with flag MEMBLOCK_HOTPLUG. 93062306a36Sopenharmony_ci * @base: the base phys addr of the region 93162306a36Sopenharmony_ci * @size: the size of the region 93262306a36Sopenharmony_ci * 93362306a36Sopenharmony_ci * Return: 0 on success, -errno on failure. 93462306a36Sopenharmony_ci */ 93562306a36Sopenharmony_ciint __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci return memblock_setclr_flag(base, size, 1, MEMBLOCK_HOTPLUG); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci/** 94162306a36Sopenharmony_ci * memblock_clear_hotplug - Clear flag MEMBLOCK_HOTPLUG for a specified region. 94262306a36Sopenharmony_ci * @base: the base phys addr of the region 94362306a36Sopenharmony_ci * @size: the size of the region 94462306a36Sopenharmony_ci * 94562306a36Sopenharmony_ci * Return: 0 on success, -errno on failure. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_ciint __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci return memblock_setclr_flag(base, size, 0, MEMBLOCK_HOTPLUG); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci/** 95362306a36Sopenharmony_ci * memblock_mark_mirror - Mark mirrored memory with flag MEMBLOCK_MIRROR. 95462306a36Sopenharmony_ci * @base: the base phys addr of the region 95562306a36Sopenharmony_ci * @size: the size of the region 95662306a36Sopenharmony_ci * 95762306a36Sopenharmony_ci * Return: 0 on success, -errno on failure. 95862306a36Sopenharmony_ci */ 95962306a36Sopenharmony_ciint __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci if (!mirrored_kernelcore) 96262306a36Sopenharmony_ci return 0; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci system_has_some_mirror = true; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR); 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci/** 97062306a36Sopenharmony_ci * memblock_mark_nomap - Mark a memory region with flag MEMBLOCK_NOMAP. 97162306a36Sopenharmony_ci * @base: the base phys addr of the region 97262306a36Sopenharmony_ci * @size: the size of the region 97362306a36Sopenharmony_ci * 97462306a36Sopenharmony_ci * The memory regions marked with %MEMBLOCK_NOMAP will not be added to the 97562306a36Sopenharmony_ci * direct mapping of the physical memory. These regions will still be 97662306a36Sopenharmony_ci * covered by the memory map. The struct page representing NOMAP memory 97762306a36Sopenharmony_ci * frames in the memory map will be PageReserved() 97862306a36Sopenharmony_ci * 97962306a36Sopenharmony_ci * Note: if the memory being marked %MEMBLOCK_NOMAP was allocated from 98062306a36Sopenharmony_ci * memblock, the caller must inform kmemleak to ignore that memory 98162306a36Sopenharmony_ci * 98262306a36Sopenharmony_ci * Return: 0 on success, -errno on failure. 98362306a36Sopenharmony_ci */ 98462306a36Sopenharmony_ciint __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci return memblock_setclr_flag(base, size, 1, MEMBLOCK_NOMAP); 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci/** 99062306a36Sopenharmony_ci * memblock_clear_nomap - Clear flag MEMBLOCK_NOMAP for a specified region. 99162306a36Sopenharmony_ci * @base: the base phys addr of the region 99262306a36Sopenharmony_ci * @size: the size of the region 99362306a36Sopenharmony_ci * 99462306a36Sopenharmony_ci * Return: 0 on success, -errno on failure. 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_ciint __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci return memblock_setclr_flag(base, size, 0, MEMBLOCK_NOMAP); 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic bool should_skip_region(struct memblock_type *type, 100262306a36Sopenharmony_ci struct memblock_region *m, 100362306a36Sopenharmony_ci int nid, int flags) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci int m_nid = memblock_get_region_node(m); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci /* we never skip regions when iterating memblock.reserved or physmem */ 100862306a36Sopenharmony_ci if (type != memblock_memory) 100962306a36Sopenharmony_ci return false; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* only memory regions are associated with nodes, check it */ 101262306a36Sopenharmony_ci if (nid != NUMA_NO_NODE && nid != m_nid) 101362306a36Sopenharmony_ci return true; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci /* skip hotpluggable memory regions if needed */ 101662306a36Sopenharmony_ci if (movable_node_is_enabled() && memblock_is_hotpluggable(m) && 101762306a36Sopenharmony_ci !(flags & MEMBLOCK_HOTPLUG)) 101862306a36Sopenharmony_ci return true; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* if we want mirror memory skip non-mirror memory regions */ 102162306a36Sopenharmony_ci if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m)) 102262306a36Sopenharmony_ci return true; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* skip nomap memory unless we were asked for it explicitly */ 102562306a36Sopenharmony_ci if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m)) 102662306a36Sopenharmony_ci return true; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* skip driver-managed memory unless we were asked for it explicitly */ 102962306a36Sopenharmony_ci if (!(flags & MEMBLOCK_DRIVER_MANAGED) && memblock_is_driver_managed(m)) 103062306a36Sopenharmony_ci return true; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci return false; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci/** 103662306a36Sopenharmony_ci * __next_mem_range - next function for for_each_free_mem_range() etc. 103762306a36Sopenharmony_ci * @idx: pointer to u64 loop variable 103862306a36Sopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 103962306a36Sopenharmony_ci * @flags: pick from blocks based on memory attributes 104062306a36Sopenharmony_ci * @type_a: pointer to memblock_type from where the range is taken 104162306a36Sopenharmony_ci * @type_b: pointer to memblock_type which excludes memory from being taken 104262306a36Sopenharmony_ci * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL 104362306a36Sopenharmony_ci * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL 104462306a36Sopenharmony_ci * @out_nid: ptr to int for nid of the range, can be %NULL 104562306a36Sopenharmony_ci * 104662306a36Sopenharmony_ci * Find the first area from *@idx which matches @nid, fill the out 104762306a36Sopenharmony_ci * parameters, and update *@idx for the next iteration. The lower 32bit of 104862306a36Sopenharmony_ci * *@idx contains index into type_a and the upper 32bit indexes the 104962306a36Sopenharmony_ci * areas before each region in type_b. For example, if type_b regions 105062306a36Sopenharmony_ci * look like the following, 105162306a36Sopenharmony_ci * 105262306a36Sopenharmony_ci * 0:[0-16), 1:[32-48), 2:[128-130) 105362306a36Sopenharmony_ci * 105462306a36Sopenharmony_ci * The upper 32bit indexes the following regions. 105562306a36Sopenharmony_ci * 105662306a36Sopenharmony_ci * 0:[0-0), 1:[16-32), 2:[48-128), 3:[130-MAX) 105762306a36Sopenharmony_ci * 105862306a36Sopenharmony_ci * As both region arrays are sorted, the function advances the two indices 105962306a36Sopenharmony_ci * in lockstep and returns each intersection. 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_civoid __next_mem_range(u64 *idx, int nid, enum memblock_flags flags, 106262306a36Sopenharmony_ci struct memblock_type *type_a, 106362306a36Sopenharmony_ci struct memblock_type *type_b, phys_addr_t *out_start, 106462306a36Sopenharmony_ci phys_addr_t *out_end, int *out_nid) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci int idx_a = *idx & 0xffffffff; 106762306a36Sopenharmony_ci int idx_b = *idx >> 32; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (WARN_ONCE(nid == MAX_NUMNODES, 107062306a36Sopenharmony_ci "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) 107162306a36Sopenharmony_ci nid = NUMA_NO_NODE; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci for (; idx_a < type_a->cnt; idx_a++) { 107462306a36Sopenharmony_ci struct memblock_region *m = &type_a->regions[idx_a]; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci phys_addr_t m_start = m->base; 107762306a36Sopenharmony_ci phys_addr_t m_end = m->base + m->size; 107862306a36Sopenharmony_ci int m_nid = memblock_get_region_node(m); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (should_skip_region(type_a, m, nid, flags)) 108162306a36Sopenharmony_ci continue; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (!type_b) { 108462306a36Sopenharmony_ci if (out_start) 108562306a36Sopenharmony_ci *out_start = m_start; 108662306a36Sopenharmony_ci if (out_end) 108762306a36Sopenharmony_ci *out_end = m_end; 108862306a36Sopenharmony_ci if (out_nid) 108962306a36Sopenharmony_ci *out_nid = m_nid; 109062306a36Sopenharmony_ci idx_a++; 109162306a36Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 109262306a36Sopenharmony_ci return; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* scan areas before each reservation */ 109662306a36Sopenharmony_ci for (; idx_b < type_b->cnt + 1; idx_b++) { 109762306a36Sopenharmony_ci struct memblock_region *r; 109862306a36Sopenharmony_ci phys_addr_t r_start; 109962306a36Sopenharmony_ci phys_addr_t r_end; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci r = &type_b->regions[idx_b]; 110262306a36Sopenharmony_ci r_start = idx_b ? r[-1].base + r[-1].size : 0; 110362306a36Sopenharmony_ci r_end = idx_b < type_b->cnt ? 110462306a36Sopenharmony_ci r->base : PHYS_ADDR_MAX; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* 110762306a36Sopenharmony_ci * if idx_b advanced past idx_a, 110862306a36Sopenharmony_ci * break out to advance idx_a 110962306a36Sopenharmony_ci */ 111062306a36Sopenharmony_ci if (r_start >= m_end) 111162306a36Sopenharmony_ci break; 111262306a36Sopenharmony_ci /* if the two regions intersect, we're done */ 111362306a36Sopenharmony_ci if (m_start < r_end) { 111462306a36Sopenharmony_ci if (out_start) 111562306a36Sopenharmony_ci *out_start = 111662306a36Sopenharmony_ci max(m_start, r_start); 111762306a36Sopenharmony_ci if (out_end) 111862306a36Sopenharmony_ci *out_end = min(m_end, r_end); 111962306a36Sopenharmony_ci if (out_nid) 112062306a36Sopenharmony_ci *out_nid = m_nid; 112162306a36Sopenharmony_ci /* 112262306a36Sopenharmony_ci * The region which ends first is 112362306a36Sopenharmony_ci * advanced for the next iteration. 112462306a36Sopenharmony_ci */ 112562306a36Sopenharmony_ci if (m_end <= r_end) 112662306a36Sopenharmony_ci idx_a++; 112762306a36Sopenharmony_ci else 112862306a36Sopenharmony_ci idx_b++; 112962306a36Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 113062306a36Sopenharmony_ci return; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* signal end of iteration */ 113662306a36Sopenharmony_ci *idx = ULLONG_MAX; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci/** 114062306a36Sopenharmony_ci * __next_mem_range_rev - generic next function for for_each_*_range_rev() 114162306a36Sopenharmony_ci * 114262306a36Sopenharmony_ci * @idx: pointer to u64 loop variable 114362306a36Sopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 114462306a36Sopenharmony_ci * @flags: pick from blocks based on memory attributes 114562306a36Sopenharmony_ci * @type_a: pointer to memblock_type from where the range is taken 114662306a36Sopenharmony_ci * @type_b: pointer to memblock_type which excludes memory from being taken 114762306a36Sopenharmony_ci * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL 114862306a36Sopenharmony_ci * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL 114962306a36Sopenharmony_ci * @out_nid: ptr to int for nid of the range, can be %NULL 115062306a36Sopenharmony_ci * 115162306a36Sopenharmony_ci * Finds the next range from type_a which is not marked as unsuitable 115262306a36Sopenharmony_ci * in type_b. 115362306a36Sopenharmony_ci * 115462306a36Sopenharmony_ci * Reverse of __next_mem_range(). 115562306a36Sopenharmony_ci */ 115662306a36Sopenharmony_civoid __init_memblock __next_mem_range_rev(u64 *idx, int nid, 115762306a36Sopenharmony_ci enum memblock_flags flags, 115862306a36Sopenharmony_ci struct memblock_type *type_a, 115962306a36Sopenharmony_ci struct memblock_type *type_b, 116062306a36Sopenharmony_ci phys_addr_t *out_start, 116162306a36Sopenharmony_ci phys_addr_t *out_end, int *out_nid) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci int idx_a = *idx & 0xffffffff; 116462306a36Sopenharmony_ci int idx_b = *idx >> 32; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) 116762306a36Sopenharmony_ci nid = NUMA_NO_NODE; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci if (*idx == (u64)ULLONG_MAX) { 117062306a36Sopenharmony_ci idx_a = type_a->cnt - 1; 117162306a36Sopenharmony_ci if (type_b != NULL) 117262306a36Sopenharmony_ci idx_b = type_b->cnt; 117362306a36Sopenharmony_ci else 117462306a36Sopenharmony_ci idx_b = 0; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci for (; idx_a >= 0; idx_a--) { 117862306a36Sopenharmony_ci struct memblock_region *m = &type_a->regions[idx_a]; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci phys_addr_t m_start = m->base; 118162306a36Sopenharmony_ci phys_addr_t m_end = m->base + m->size; 118262306a36Sopenharmony_ci int m_nid = memblock_get_region_node(m); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (should_skip_region(type_a, m, nid, flags)) 118562306a36Sopenharmony_ci continue; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (!type_b) { 118862306a36Sopenharmony_ci if (out_start) 118962306a36Sopenharmony_ci *out_start = m_start; 119062306a36Sopenharmony_ci if (out_end) 119162306a36Sopenharmony_ci *out_end = m_end; 119262306a36Sopenharmony_ci if (out_nid) 119362306a36Sopenharmony_ci *out_nid = m_nid; 119462306a36Sopenharmony_ci idx_a--; 119562306a36Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 119662306a36Sopenharmony_ci return; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* scan areas before each reservation */ 120062306a36Sopenharmony_ci for (; idx_b >= 0; idx_b--) { 120162306a36Sopenharmony_ci struct memblock_region *r; 120262306a36Sopenharmony_ci phys_addr_t r_start; 120362306a36Sopenharmony_ci phys_addr_t r_end; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci r = &type_b->regions[idx_b]; 120662306a36Sopenharmony_ci r_start = idx_b ? r[-1].base + r[-1].size : 0; 120762306a36Sopenharmony_ci r_end = idx_b < type_b->cnt ? 120862306a36Sopenharmony_ci r->base : PHYS_ADDR_MAX; 120962306a36Sopenharmony_ci /* 121062306a36Sopenharmony_ci * if idx_b advanced past idx_a, 121162306a36Sopenharmony_ci * break out to advance idx_a 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (r_end <= m_start) 121562306a36Sopenharmony_ci break; 121662306a36Sopenharmony_ci /* if the two regions intersect, we're done */ 121762306a36Sopenharmony_ci if (m_end > r_start) { 121862306a36Sopenharmony_ci if (out_start) 121962306a36Sopenharmony_ci *out_start = max(m_start, r_start); 122062306a36Sopenharmony_ci if (out_end) 122162306a36Sopenharmony_ci *out_end = min(m_end, r_end); 122262306a36Sopenharmony_ci if (out_nid) 122362306a36Sopenharmony_ci *out_nid = m_nid; 122462306a36Sopenharmony_ci if (m_start >= r_start) 122562306a36Sopenharmony_ci idx_a--; 122662306a36Sopenharmony_ci else 122762306a36Sopenharmony_ci idx_b--; 122862306a36Sopenharmony_ci *idx = (u32)idx_a | (u64)idx_b << 32; 122962306a36Sopenharmony_ci return; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci /* signal end of iteration */ 123462306a36Sopenharmony_ci *idx = ULLONG_MAX; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci/* 123862306a36Sopenharmony_ci * Common iterator interface used to define for_each_mem_pfn_range(). 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_civoid __init_memblock __next_mem_pfn_range(int *idx, int nid, 124162306a36Sopenharmony_ci unsigned long *out_start_pfn, 124262306a36Sopenharmony_ci unsigned long *out_end_pfn, int *out_nid) 124362306a36Sopenharmony_ci{ 124462306a36Sopenharmony_ci struct memblock_type *type = &memblock.memory; 124562306a36Sopenharmony_ci struct memblock_region *r; 124662306a36Sopenharmony_ci int r_nid; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci while (++*idx < type->cnt) { 124962306a36Sopenharmony_ci r = &type->regions[*idx]; 125062306a36Sopenharmony_ci r_nid = memblock_get_region_node(r); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (PFN_UP(r->base) >= PFN_DOWN(r->base + r->size)) 125362306a36Sopenharmony_ci continue; 125462306a36Sopenharmony_ci if (nid == MAX_NUMNODES || nid == r_nid) 125562306a36Sopenharmony_ci break; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci if (*idx >= type->cnt) { 125862306a36Sopenharmony_ci *idx = -1; 125962306a36Sopenharmony_ci return; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (out_start_pfn) 126362306a36Sopenharmony_ci *out_start_pfn = PFN_UP(r->base); 126462306a36Sopenharmony_ci if (out_end_pfn) 126562306a36Sopenharmony_ci *out_end_pfn = PFN_DOWN(r->base + r->size); 126662306a36Sopenharmony_ci if (out_nid) 126762306a36Sopenharmony_ci *out_nid = r_nid; 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci/** 127162306a36Sopenharmony_ci * memblock_set_node - set node ID on memblock regions 127262306a36Sopenharmony_ci * @base: base of area to set node ID for 127362306a36Sopenharmony_ci * @size: size of area to set node ID for 127462306a36Sopenharmony_ci * @type: memblock type to set node ID for 127562306a36Sopenharmony_ci * @nid: node ID to set 127662306a36Sopenharmony_ci * 127762306a36Sopenharmony_ci * Set the nid of memblock @type regions in [@base, @base + @size) to @nid. 127862306a36Sopenharmony_ci * Regions which cross the area boundaries are split as necessary. 127962306a36Sopenharmony_ci * 128062306a36Sopenharmony_ci * Return: 128162306a36Sopenharmony_ci * 0 on success, -errno on failure. 128262306a36Sopenharmony_ci */ 128362306a36Sopenharmony_ciint __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, 128462306a36Sopenharmony_ci struct memblock_type *type, int nid) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci#ifdef CONFIG_NUMA 128762306a36Sopenharmony_ci int start_rgn, end_rgn; 128862306a36Sopenharmony_ci int i, ret; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); 129162306a36Sopenharmony_ci if (ret) 129262306a36Sopenharmony_ci return ret; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci for (i = start_rgn; i < end_rgn; i++) 129562306a36Sopenharmony_ci memblock_set_region_node(&type->regions[i], nid); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci memblock_merge_regions(type, start_rgn, end_rgn); 129862306a36Sopenharmony_ci#endif 129962306a36Sopenharmony_ci return 0; 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT 130362306a36Sopenharmony_ci/** 130462306a36Sopenharmony_ci * __next_mem_pfn_range_in_zone - iterator for for_each_*_range_in_zone() 130562306a36Sopenharmony_ci * 130662306a36Sopenharmony_ci * @idx: pointer to u64 loop variable 130762306a36Sopenharmony_ci * @zone: zone in which all of the memory blocks reside 130862306a36Sopenharmony_ci * @out_spfn: ptr to ulong for start pfn of the range, can be %NULL 130962306a36Sopenharmony_ci * @out_epfn: ptr to ulong for end pfn of the range, can be %NULL 131062306a36Sopenharmony_ci * 131162306a36Sopenharmony_ci * This function is meant to be a zone/pfn specific wrapper for the 131262306a36Sopenharmony_ci * for_each_mem_range type iterators. Specifically they are used in the 131362306a36Sopenharmony_ci * deferred memory init routines and as such we were duplicating much of 131462306a36Sopenharmony_ci * this logic throughout the code. So instead of having it in multiple 131562306a36Sopenharmony_ci * locations it seemed like it would make more sense to centralize this to 131662306a36Sopenharmony_ci * one new iterator that does everything they need. 131762306a36Sopenharmony_ci */ 131862306a36Sopenharmony_civoid __init_memblock 131962306a36Sopenharmony_ci__next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, 132062306a36Sopenharmony_ci unsigned long *out_spfn, unsigned long *out_epfn) 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci int zone_nid = zone_to_nid(zone); 132362306a36Sopenharmony_ci phys_addr_t spa, epa; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci __next_mem_range(idx, zone_nid, MEMBLOCK_NONE, 132662306a36Sopenharmony_ci &memblock.memory, &memblock.reserved, 132762306a36Sopenharmony_ci &spa, &epa, NULL); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci while (*idx != U64_MAX) { 133062306a36Sopenharmony_ci unsigned long epfn = PFN_DOWN(epa); 133162306a36Sopenharmony_ci unsigned long spfn = PFN_UP(spa); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci /* 133462306a36Sopenharmony_ci * Verify the end is at least past the start of the zone and 133562306a36Sopenharmony_ci * that we have at least one PFN to initialize. 133662306a36Sopenharmony_ci */ 133762306a36Sopenharmony_ci if (zone->zone_start_pfn < epfn && spfn < epfn) { 133862306a36Sopenharmony_ci /* if we went too far just stop searching */ 133962306a36Sopenharmony_ci if (zone_end_pfn(zone) <= spfn) { 134062306a36Sopenharmony_ci *idx = U64_MAX; 134162306a36Sopenharmony_ci break; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if (out_spfn) 134562306a36Sopenharmony_ci *out_spfn = max(zone->zone_start_pfn, spfn); 134662306a36Sopenharmony_ci if (out_epfn) 134762306a36Sopenharmony_ci *out_epfn = min(zone_end_pfn(zone), epfn); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci return; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci __next_mem_range(idx, zone_nid, MEMBLOCK_NONE, 135362306a36Sopenharmony_ci &memblock.memory, &memblock.reserved, 135462306a36Sopenharmony_ci &spa, &epa, NULL); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* signal end of iteration */ 135862306a36Sopenharmony_ci if (out_spfn) 135962306a36Sopenharmony_ci *out_spfn = ULONG_MAX; 136062306a36Sopenharmony_ci if (out_epfn) 136162306a36Sopenharmony_ci *out_epfn = 0; 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci/** 136762306a36Sopenharmony_ci * memblock_alloc_range_nid - allocate boot memory block 136862306a36Sopenharmony_ci * @size: size of memory block to be allocated in bytes 136962306a36Sopenharmony_ci * @align: alignment of the region and block's size 137062306a36Sopenharmony_ci * @start: the lower bound of the memory region to allocate (phys address) 137162306a36Sopenharmony_ci * @end: the upper bound of the memory region to allocate (phys address) 137262306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 137362306a36Sopenharmony_ci * @exact_nid: control the allocation fall back to other nodes 137462306a36Sopenharmony_ci * 137562306a36Sopenharmony_ci * The allocation is performed from memory region limited by 137662306a36Sopenharmony_ci * memblock.current_limit if @end == %MEMBLOCK_ALLOC_ACCESSIBLE. 137762306a36Sopenharmony_ci * 137862306a36Sopenharmony_ci * If the specified node can not hold the requested memory and @exact_nid 137962306a36Sopenharmony_ci * is false, the allocation falls back to any node in the system. 138062306a36Sopenharmony_ci * 138162306a36Sopenharmony_ci * For systems with memory mirroring, the allocation is attempted first 138262306a36Sopenharmony_ci * from the regions with mirroring enabled and then retried from any 138362306a36Sopenharmony_ci * memory region. 138462306a36Sopenharmony_ci * 138562306a36Sopenharmony_ci * In addition, function using kmemleak_alloc_phys for allocated boot 138662306a36Sopenharmony_ci * memory block, it is never reported as leaks. 138762306a36Sopenharmony_ci * 138862306a36Sopenharmony_ci * Return: 138962306a36Sopenharmony_ci * Physical address of allocated memory block on success, %0 on failure. 139062306a36Sopenharmony_ci */ 139162306a36Sopenharmony_ciphys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, 139262306a36Sopenharmony_ci phys_addr_t align, phys_addr_t start, 139362306a36Sopenharmony_ci phys_addr_t end, int nid, 139462306a36Sopenharmony_ci bool exact_nid) 139562306a36Sopenharmony_ci{ 139662306a36Sopenharmony_ci enum memblock_flags flags = choose_memblock_flags(); 139762306a36Sopenharmony_ci phys_addr_t found; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) 140062306a36Sopenharmony_ci nid = NUMA_NO_NODE; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci if (!align) { 140362306a36Sopenharmony_ci /* Can't use WARNs this early in boot on powerpc */ 140462306a36Sopenharmony_ci dump_stack(); 140562306a36Sopenharmony_ci align = SMP_CACHE_BYTES; 140662306a36Sopenharmony_ci } 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ciagain: 140962306a36Sopenharmony_ci found = memblock_find_in_range_node(size, align, start, end, nid, 141062306a36Sopenharmony_ci flags); 141162306a36Sopenharmony_ci if (found && !memblock_reserve(found, size)) 141262306a36Sopenharmony_ci goto done; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (nid != NUMA_NO_NODE && !exact_nid) { 141562306a36Sopenharmony_ci found = memblock_find_in_range_node(size, align, start, 141662306a36Sopenharmony_ci end, NUMA_NO_NODE, 141762306a36Sopenharmony_ci flags); 141862306a36Sopenharmony_ci if (found && !memblock_reserve(found, size)) 141962306a36Sopenharmony_ci goto done; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (flags & MEMBLOCK_MIRROR) { 142362306a36Sopenharmony_ci flags &= ~MEMBLOCK_MIRROR; 142462306a36Sopenharmony_ci pr_warn_ratelimited("Could not allocate %pap bytes of mirrored memory\n", 142562306a36Sopenharmony_ci &size); 142662306a36Sopenharmony_ci goto again; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci return 0; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_cidone: 143262306a36Sopenharmony_ci /* 143362306a36Sopenharmony_ci * Skip kmemleak for those places like kasan_init() and 143462306a36Sopenharmony_ci * early_pgtable_alloc() due to high volume. 143562306a36Sopenharmony_ci */ 143662306a36Sopenharmony_ci if (end != MEMBLOCK_ALLOC_NOLEAKTRACE) 143762306a36Sopenharmony_ci /* 143862306a36Sopenharmony_ci * Memblock allocated blocks are never reported as 143962306a36Sopenharmony_ci * leaks. This is because many of these blocks are 144062306a36Sopenharmony_ci * only referred via the physical address which is 144162306a36Sopenharmony_ci * not looked up by kmemleak. 144262306a36Sopenharmony_ci */ 144362306a36Sopenharmony_ci kmemleak_alloc_phys(found, size, 0); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci /* 144662306a36Sopenharmony_ci * Some Virtual Machine platforms, such as Intel TDX or AMD SEV-SNP, 144762306a36Sopenharmony_ci * require memory to be accepted before it can be used by the 144862306a36Sopenharmony_ci * guest. 144962306a36Sopenharmony_ci * 145062306a36Sopenharmony_ci * Accept the memory of the allocated buffer. 145162306a36Sopenharmony_ci */ 145262306a36Sopenharmony_ci accept_memory(found, found + size); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci return found; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci/** 145862306a36Sopenharmony_ci * memblock_phys_alloc_range - allocate a memory block inside specified range 145962306a36Sopenharmony_ci * @size: size of memory block to be allocated in bytes 146062306a36Sopenharmony_ci * @align: alignment of the region and block's size 146162306a36Sopenharmony_ci * @start: the lower bound of the memory region to allocate (physical address) 146262306a36Sopenharmony_ci * @end: the upper bound of the memory region to allocate (physical address) 146362306a36Sopenharmony_ci * 146462306a36Sopenharmony_ci * Allocate @size bytes in the between @start and @end. 146562306a36Sopenharmony_ci * 146662306a36Sopenharmony_ci * Return: physical address of the allocated memory block on success, 146762306a36Sopenharmony_ci * %0 on failure. 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_ciphys_addr_t __init memblock_phys_alloc_range(phys_addr_t size, 147062306a36Sopenharmony_ci phys_addr_t align, 147162306a36Sopenharmony_ci phys_addr_t start, 147262306a36Sopenharmony_ci phys_addr_t end) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci memblock_dbg("%s: %llu bytes align=0x%llx from=%pa max_addr=%pa %pS\n", 147562306a36Sopenharmony_ci __func__, (u64)size, (u64)align, &start, &end, 147662306a36Sopenharmony_ci (void *)_RET_IP_); 147762306a36Sopenharmony_ci return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE, 147862306a36Sopenharmony_ci false); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci/** 148262306a36Sopenharmony_ci * memblock_phys_alloc_try_nid - allocate a memory block from specified NUMA node 148362306a36Sopenharmony_ci * @size: size of memory block to be allocated in bytes 148462306a36Sopenharmony_ci * @align: alignment of the region and block's size 148562306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 148662306a36Sopenharmony_ci * 148762306a36Sopenharmony_ci * Allocates memory block from the specified NUMA node. If the node 148862306a36Sopenharmony_ci * has no available memory, attempts to allocated from any node in the 148962306a36Sopenharmony_ci * system. 149062306a36Sopenharmony_ci * 149162306a36Sopenharmony_ci * Return: physical address of the allocated memory block on success, 149262306a36Sopenharmony_ci * %0 on failure. 149362306a36Sopenharmony_ci */ 149462306a36Sopenharmony_ciphys_addr_t __init memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid) 149562306a36Sopenharmony_ci{ 149662306a36Sopenharmony_ci return memblock_alloc_range_nid(size, align, 0, 149762306a36Sopenharmony_ci MEMBLOCK_ALLOC_ACCESSIBLE, nid, false); 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci/** 150162306a36Sopenharmony_ci * memblock_alloc_internal - allocate boot memory block 150262306a36Sopenharmony_ci * @size: size of memory block to be allocated in bytes 150362306a36Sopenharmony_ci * @align: alignment of the region and block's size 150462306a36Sopenharmony_ci * @min_addr: the lower bound of the memory region to allocate (phys address) 150562306a36Sopenharmony_ci * @max_addr: the upper bound of the memory region to allocate (phys address) 150662306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 150762306a36Sopenharmony_ci * @exact_nid: control the allocation fall back to other nodes 150862306a36Sopenharmony_ci * 150962306a36Sopenharmony_ci * Allocates memory block using memblock_alloc_range_nid() and 151062306a36Sopenharmony_ci * converts the returned physical address to virtual. 151162306a36Sopenharmony_ci * 151262306a36Sopenharmony_ci * The @min_addr limit is dropped if it can not be satisfied and the allocation 151362306a36Sopenharmony_ci * will fall back to memory below @min_addr. Other constraints, such 151462306a36Sopenharmony_ci * as node and mirrored memory will be handled again in 151562306a36Sopenharmony_ci * memblock_alloc_range_nid(). 151662306a36Sopenharmony_ci * 151762306a36Sopenharmony_ci * Return: 151862306a36Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_cistatic void * __init memblock_alloc_internal( 152162306a36Sopenharmony_ci phys_addr_t size, phys_addr_t align, 152262306a36Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 152362306a36Sopenharmony_ci int nid, bool exact_nid) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci phys_addr_t alloc; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci /* 152862306a36Sopenharmony_ci * Detect any accidental use of these APIs after slab is ready, as at 152962306a36Sopenharmony_ci * this moment memblock may be deinitialized already and its 153062306a36Sopenharmony_ci * internal data may be destroyed (after execution of memblock_free_all) 153162306a36Sopenharmony_ci */ 153262306a36Sopenharmony_ci if (WARN_ON_ONCE(slab_is_available())) 153362306a36Sopenharmony_ci return kzalloc_node(size, GFP_NOWAIT, nid); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci if (max_addr > memblock.current_limit) 153662306a36Sopenharmony_ci max_addr = memblock.current_limit; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid, 153962306a36Sopenharmony_ci exact_nid); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci /* retry allocation without lower limit */ 154262306a36Sopenharmony_ci if (!alloc && min_addr) 154362306a36Sopenharmony_ci alloc = memblock_alloc_range_nid(size, align, 0, max_addr, nid, 154462306a36Sopenharmony_ci exact_nid); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (!alloc) 154762306a36Sopenharmony_ci return NULL; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci return phys_to_virt(alloc); 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci/** 155362306a36Sopenharmony_ci * memblock_alloc_exact_nid_raw - allocate boot memory block on the exact node 155462306a36Sopenharmony_ci * without zeroing memory 155562306a36Sopenharmony_ci * @size: size of memory block to be allocated in bytes 155662306a36Sopenharmony_ci * @align: alignment of the region and block's size 155762306a36Sopenharmony_ci * @min_addr: the lower bound of the memory region from where the allocation 155862306a36Sopenharmony_ci * is preferred (phys address) 155962306a36Sopenharmony_ci * @max_addr: the upper bound of the memory region from where the allocation 156062306a36Sopenharmony_ci * is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to 156162306a36Sopenharmony_ci * allocate only from memory limited by memblock.current_limit value 156262306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 156362306a36Sopenharmony_ci * 156462306a36Sopenharmony_ci * Public function, provides additional debug information (including caller 156562306a36Sopenharmony_ci * info), if enabled. Does not zero allocated memory. 156662306a36Sopenharmony_ci * 156762306a36Sopenharmony_ci * Return: 156862306a36Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 156962306a36Sopenharmony_ci */ 157062306a36Sopenharmony_civoid * __init memblock_alloc_exact_nid_raw( 157162306a36Sopenharmony_ci phys_addr_t size, phys_addr_t align, 157262306a36Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 157362306a36Sopenharmony_ci int nid) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n", 157662306a36Sopenharmony_ci __func__, (u64)size, (u64)align, nid, &min_addr, 157762306a36Sopenharmony_ci &max_addr, (void *)_RET_IP_); 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci return memblock_alloc_internal(size, align, min_addr, max_addr, nid, 158062306a36Sopenharmony_ci true); 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci/** 158462306a36Sopenharmony_ci * memblock_alloc_try_nid_raw - allocate boot memory block without zeroing 158562306a36Sopenharmony_ci * memory and without panicking 158662306a36Sopenharmony_ci * @size: size of memory block to be allocated in bytes 158762306a36Sopenharmony_ci * @align: alignment of the region and block's size 158862306a36Sopenharmony_ci * @min_addr: the lower bound of the memory region from where the allocation 158962306a36Sopenharmony_ci * is preferred (phys address) 159062306a36Sopenharmony_ci * @max_addr: the upper bound of the memory region from where the allocation 159162306a36Sopenharmony_ci * is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to 159262306a36Sopenharmony_ci * allocate only from memory limited by memblock.current_limit value 159362306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 159462306a36Sopenharmony_ci * 159562306a36Sopenharmony_ci * Public function, provides additional debug information (including caller 159662306a36Sopenharmony_ci * info), if enabled. Does not zero allocated memory, does not panic if request 159762306a36Sopenharmony_ci * cannot be satisfied. 159862306a36Sopenharmony_ci * 159962306a36Sopenharmony_ci * Return: 160062306a36Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 160162306a36Sopenharmony_ci */ 160262306a36Sopenharmony_civoid * __init memblock_alloc_try_nid_raw( 160362306a36Sopenharmony_ci phys_addr_t size, phys_addr_t align, 160462306a36Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 160562306a36Sopenharmony_ci int nid) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n", 160862306a36Sopenharmony_ci __func__, (u64)size, (u64)align, nid, &min_addr, 160962306a36Sopenharmony_ci &max_addr, (void *)_RET_IP_); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci return memblock_alloc_internal(size, align, min_addr, max_addr, nid, 161262306a36Sopenharmony_ci false); 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci/** 161662306a36Sopenharmony_ci * memblock_alloc_try_nid - allocate boot memory block 161762306a36Sopenharmony_ci * @size: size of memory block to be allocated in bytes 161862306a36Sopenharmony_ci * @align: alignment of the region and block's size 161962306a36Sopenharmony_ci * @min_addr: the lower bound of the memory region from where the allocation 162062306a36Sopenharmony_ci * is preferred (phys address) 162162306a36Sopenharmony_ci * @max_addr: the upper bound of the memory region from where the allocation 162262306a36Sopenharmony_ci * is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to 162362306a36Sopenharmony_ci * allocate only from memory limited by memblock.current_limit value 162462306a36Sopenharmony_ci * @nid: nid of the free area to find, %NUMA_NO_NODE for any node 162562306a36Sopenharmony_ci * 162662306a36Sopenharmony_ci * Public function, provides additional debug information (including caller 162762306a36Sopenharmony_ci * info), if enabled. This function zeroes the allocated memory. 162862306a36Sopenharmony_ci * 162962306a36Sopenharmony_ci * Return: 163062306a36Sopenharmony_ci * Virtual address of allocated memory block on success, NULL on failure. 163162306a36Sopenharmony_ci */ 163262306a36Sopenharmony_civoid * __init memblock_alloc_try_nid( 163362306a36Sopenharmony_ci phys_addr_t size, phys_addr_t align, 163462306a36Sopenharmony_ci phys_addr_t min_addr, phys_addr_t max_addr, 163562306a36Sopenharmony_ci int nid) 163662306a36Sopenharmony_ci{ 163762306a36Sopenharmony_ci void *ptr; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n", 164062306a36Sopenharmony_ci __func__, (u64)size, (u64)align, nid, &min_addr, 164162306a36Sopenharmony_ci &max_addr, (void *)_RET_IP_); 164262306a36Sopenharmony_ci ptr = memblock_alloc_internal(size, align, 164362306a36Sopenharmony_ci min_addr, max_addr, nid, false); 164462306a36Sopenharmony_ci if (ptr) 164562306a36Sopenharmony_ci memset(ptr, 0, size); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci return ptr; 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci/** 165162306a36Sopenharmony_ci * memblock_free_late - free pages directly to buddy allocator 165262306a36Sopenharmony_ci * @base: phys starting address of the boot memory block 165362306a36Sopenharmony_ci * @size: size of the boot memory block in bytes 165462306a36Sopenharmony_ci * 165562306a36Sopenharmony_ci * This is only useful when the memblock allocator has already been torn 165662306a36Sopenharmony_ci * down, but we are still initializing the system. Pages are released directly 165762306a36Sopenharmony_ci * to the buddy allocator. 165862306a36Sopenharmony_ci */ 165962306a36Sopenharmony_civoid __init memblock_free_late(phys_addr_t base, phys_addr_t size) 166062306a36Sopenharmony_ci{ 166162306a36Sopenharmony_ci phys_addr_t cursor, end; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci end = base + size - 1; 166462306a36Sopenharmony_ci memblock_dbg("%s: [%pa-%pa] %pS\n", 166562306a36Sopenharmony_ci __func__, &base, &end, (void *)_RET_IP_); 166662306a36Sopenharmony_ci kmemleak_free_part_phys(base, size); 166762306a36Sopenharmony_ci cursor = PFN_UP(base); 166862306a36Sopenharmony_ci end = PFN_DOWN(base + size); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci for (; cursor < end; cursor++) { 167162306a36Sopenharmony_ci memblock_free_pages(pfn_to_page(cursor), cursor, 0); 167262306a36Sopenharmony_ci totalram_pages_inc(); 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci/* 167762306a36Sopenharmony_ci * Remaining API functions 167862306a36Sopenharmony_ci */ 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ciphys_addr_t __init_memblock memblock_phys_mem_size(void) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci return memblock.memory.total_size; 168362306a36Sopenharmony_ci} 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ciphys_addr_t __init_memblock memblock_reserved_size(void) 168662306a36Sopenharmony_ci{ 168762306a36Sopenharmony_ci return memblock.reserved.total_size; 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci/* lowest address */ 169162306a36Sopenharmony_ciphys_addr_t __init_memblock memblock_start_of_DRAM(void) 169262306a36Sopenharmony_ci{ 169362306a36Sopenharmony_ci return memblock.memory.regions[0].base; 169462306a36Sopenharmony_ci} 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ciphys_addr_t __init_memblock memblock_end_of_DRAM(void) 169762306a36Sopenharmony_ci{ 169862306a36Sopenharmony_ci int idx = memblock.memory.cnt - 1; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size); 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cistatic phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci phys_addr_t max_addr = PHYS_ADDR_MAX; 170662306a36Sopenharmony_ci struct memblock_region *r; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci /* 170962306a36Sopenharmony_ci * translate the memory @limit size into the max address within one of 171062306a36Sopenharmony_ci * the memory memblock regions, if the @limit exceeds the total size 171162306a36Sopenharmony_ci * of those regions, max_addr will keep original value PHYS_ADDR_MAX 171262306a36Sopenharmony_ci */ 171362306a36Sopenharmony_ci for_each_mem_region(r) { 171462306a36Sopenharmony_ci if (limit <= r->size) { 171562306a36Sopenharmony_ci max_addr = r->base + limit; 171662306a36Sopenharmony_ci break; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci limit -= r->size; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci return max_addr; 172262306a36Sopenharmony_ci} 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_civoid __init memblock_enforce_memory_limit(phys_addr_t limit) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci phys_addr_t max_addr; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci if (!limit) 172962306a36Sopenharmony_ci return; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci max_addr = __find_max_addr(limit); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci /* @limit exceeds the total size of the memory, do nothing */ 173462306a36Sopenharmony_ci if (max_addr == PHYS_ADDR_MAX) 173562306a36Sopenharmony_ci return; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci /* truncate both memory and reserved regions */ 173862306a36Sopenharmony_ci memblock_remove_range(&memblock.memory, max_addr, 173962306a36Sopenharmony_ci PHYS_ADDR_MAX); 174062306a36Sopenharmony_ci memblock_remove_range(&memblock.reserved, max_addr, 174162306a36Sopenharmony_ci PHYS_ADDR_MAX); 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_civoid __init memblock_cap_memory_range(phys_addr_t base, phys_addr_t size) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci int start_rgn, end_rgn; 174762306a36Sopenharmony_ci int i, ret; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci if (!size) 175062306a36Sopenharmony_ci return; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (!memblock_memory->total_size) { 175362306a36Sopenharmony_ci pr_warn("%s: No memory registered yet\n", __func__); 175462306a36Sopenharmony_ci return; 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci ret = memblock_isolate_range(&memblock.memory, base, size, 175862306a36Sopenharmony_ci &start_rgn, &end_rgn); 175962306a36Sopenharmony_ci if (ret) 176062306a36Sopenharmony_ci return; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* remove all the MAP regions */ 176362306a36Sopenharmony_ci for (i = memblock.memory.cnt - 1; i >= end_rgn; i--) 176462306a36Sopenharmony_ci if (!memblock_is_nomap(&memblock.memory.regions[i])) 176562306a36Sopenharmony_ci memblock_remove_region(&memblock.memory, i); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci for (i = start_rgn - 1; i >= 0; i--) 176862306a36Sopenharmony_ci if (!memblock_is_nomap(&memblock.memory.regions[i])) 176962306a36Sopenharmony_ci memblock_remove_region(&memblock.memory, i); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* truncate the reserved regions */ 177262306a36Sopenharmony_ci memblock_remove_range(&memblock.reserved, 0, base); 177362306a36Sopenharmony_ci memblock_remove_range(&memblock.reserved, 177462306a36Sopenharmony_ci base + size, PHYS_ADDR_MAX); 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_civoid __init memblock_mem_limit_remove_map(phys_addr_t limit) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci phys_addr_t max_addr; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci if (!limit) 178262306a36Sopenharmony_ci return; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci max_addr = __find_max_addr(limit); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* @limit exceeds the total size of the memory, do nothing */ 178762306a36Sopenharmony_ci if (max_addr == PHYS_ADDR_MAX) 178862306a36Sopenharmony_ci return; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci memblock_cap_memory_range(0, max_addr); 179162306a36Sopenharmony_ci} 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_cistatic int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) 179462306a36Sopenharmony_ci{ 179562306a36Sopenharmony_ci unsigned int left = 0, right = type->cnt; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci do { 179862306a36Sopenharmony_ci unsigned int mid = (right + left) / 2; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci if (addr < type->regions[mid].base) 180162306a36Sopenharmony_ci right = mid; 180262306a36Sopenharmony_ci else if (addr >= (type->regions[mid].base + 180362306a36Sopenharmony_ci type->regions[mid].size)) 180462306a36Sopenharmony_ci left = mid + 1; 180562306a36Sopenharmony_ci else 180662306a36Sopenharmony_ci return mid; 180762306a36Sopenharmony_ci } while (left < right); 180862306a36Sopenharmony_ci return -1; 180962306a36Sopenharmony_ci} 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_cibool __init_memblock memblock_is_reserved(phys_addr_t addr) 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci return memblock_search(&memblock.reserved, addr) != -1; 181462306a36Sopenharmony_ci} 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_cibool __init_memblock memblock_is_memory(phys_addr_t addr) 181762306a36Sopenharmony_ci{ 181862306a36Sopenharmony_ci return memblock_search(&memblock.memory, addr) != -1; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cibool __init_memblock memblock_is_map_memory(phys_addr_t addr) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci int i = memblock_search(&memblock.memory, addr); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (i == -1) 182662306a36Sopenharmony_ci return false; 182762306a36Sopenharmony_ci return !memblock_is_nomap(&memblock.memory.regions[i]); 182862306a36Sopenharmony_ci} 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ciint __init_memblock memblock_search_pfn_nid(unsigned long pfn, 183162306a36Sopenharmony_ci unsigned long *start_pfn, unsigned long *end_pfn) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci struct memblock_type *type = &memblock.memory; 183462306a36Sopenharmony_ci int mid = memblock_search(type, PFN_PHYS(pfn)); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci if (mid == -1) 183762306a36Sopenharmony_ci return -1; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci *start_pfn = PFN_DOWN(type->regions[mid].base); 184062306a36Sopenharmony_ci *end_pfn = PFN_DOWN(type->regions[mid].base + type->regions[mid].size); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci return memblock_get_region_node(&type->regions[mid]); 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci/** 184662306a36Sopenharmony_ci * memblock_is_region_memory - check if a region is a subset of memory 184762306a36Sopenharmony_ci * @base: base of region to check 184862306a36Sopenharmony_ci * @size: size of region to check 184962306a36Sopenharmony_ci * 185062306a36Sopenharmony_ci * Check if the region [@base, @base + @size) is a subset of a memory block. 185162306a36Sopenharmony_ci * 185262306a36Sopenharmony_ci * Return: 185362306a36Sopenharmony_ci * 0 if false, non-zero if true 185462306a36Sopenharmony_ci */ 185562306a36Sopenharmony_cibool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) 185662306a36Sopenharmony_ci{ 185762306a36Sopenharmony_ci int idx = memblock_search(&memblock.memory, base); 185862306a36Sopenharmony_ci phys_addr_t end = base + memblock_cap_size(base, &size); 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (idx == -1) 186162306a36Sopenharmony_ci return false; 186262306a36Sopenharmony_ci return (memblock.memory.regions[idx].base + 186362306a36Sopenharmony_ci memblock.memory.regions[idx].size) >= end; 186462306a36Sopenharmony_ci} 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci/** 186762306a36Sopenharmony_ci * memblock_is_region_reserved - check if a region intersects reserved memory 186862306a36Sopenharmony_ci * @base: base of region to check 186962306a36Sopenharmony_ci * @size: size of region to check 187062306a36Sopenharmony_ci * 187162306a36Sopenharmony_ci * Check if the region [@base, @base + @size) intersects a reserved 187262306a36Sopenharmony_ci * memory block. 187362306a36Sopenharmony_ci * 187462306a36Sopenharmony_ci * Return: 187562306a36Sopenharmony_ci * True if they intersect, false if not. 187662306a36Sopenharmony_ci */ 187762306a36Sopenharmony_cibool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci return memblock_overlaps_region(&memblock.reserved, base, size); 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_civoid __init_memblock memblock_trim_memory(phys_addr_t align) 188362306a36Sopenharmony_ci{ 188462306a36Sopenharmony_ci phys_addr_t start, end, orig_start, orig_end; 188562306a36Sopenharmony_ci struct memblock_region *r; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci for_each_mem_region(r) { 188862306a36Sopenharmony_ci orig_start = r->base; 188962306a36Sopenharmony_ci orig_end = r->base + r->size; 189062306a36Sopenharmony_ci start = round_up(orig_start, align); 189162306a36Sopenharmony_ci end = round_down(orig_end, align); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (start == orig_start && end == orig_end) 189462306a36Sopenharmony_ci continue; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci if (start < end) { 189762306a36Sopenharmony_ci r->base = start; 189862306a36Sopenharmony_ci r->size = end - start; 189962306a36Sopenharmony_ci } else { 190062306a36Sopenharmony_ci memblock_remove_region(&memblock.memory, 190162306a36Sopenharmony_ci r - memblock.memory.regions); 190262306a36Sopenharmony_ci r--; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci} 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_civoid __init_memblock memblock_set_current_limit(phys_addr_t limit) 190862306a36Sopenharmony_ci{ 190962306a36Sopenharmony_ci memblock.current_limit = limit; 191062306a36Sopenharmony_ci} 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ciphys_addr_t __init_memblock memblock_get_current_limit(void) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci return memblock.current_limit; 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_cistatic void __init_memblock memblock_dump(struct memblock_type *type) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci phys_addr_t base, end, size; 192062306a36Sopenharmony_ci enum memblock_flags flags; 192162306a36Sopenharmony_ci int idx; 192262306a36Sopenharmony_ci struct memblock_region *rgn; 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci pr_info(" %s.cnt = 0x%lx\n", type->name, type->cnt); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci for_each_memblock_type(idx, type, rgn) { 192762306a36Sopenharmony_ci char nid_buf[32] = ""; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci base = rgn->base; 193062306a36Sopenharmony_ci size = rgn->size; 193162306a36Sopenharmony_ci end = base + size - 1; 193262306a36Sopenharmony_ci flags = rgn->flags; 193362306a36Sopenharmony_ci#ifdef CONFIG_NUMA 193462306a36Sopenharmony_ci if (memblock_get_region_node(rgn) != MAX_NUMNODES) 193562306a36Sopenharmony_ci snprintf(nid_buf, sizeof(nid_buf), " on node %d", 193662306a36Sopenharmony_ci memblock_get_region_node(rgn)); 193762306a36Sopenharmony_ci#endif 193862306a36Sopenharmony_ci pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#x\n", 193962306a36Sopenharmony_ci type->name, idx, &base, &end, &size, nid_buf, flags); 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci} 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_cistatic void __init_memblock __memblock_dump_all(void) 194462306a36Sopenharmony_ci{ 194562306a36Sopenharmony_ci pr_info("MEMBLOCK configuration:\n"); 194662306a36Sopenharmony_ci pr_info(" memory size = %pa reserved size = %pa\n", 194762306a36Sopenharmony_ci &memblock.memory.total_size, 194862306a36Sopenharmony_ci &memblock.reserved.total_size); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci memblock_dump(&memblock.memory); 195162306a36Sopenharmony_ci memblock_dump(&memblock.reserved); 195262306a36Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 195362306a36Sopenharmony_ci memblock_dump(&physmem); 195462306a36Sopenharmony_ci#endif 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_civoid __init_memblock memblock_dump_all(void) 195862306a36Sopenharmony_ci{ 195962306a36Sopenharmony_ci if (memblock_debug) 196062306a36Sopenharmony_ci __memblock_dump_all(); 196162306a36Sopenharmony_ci} 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_civoid __init memblock_allow_resize(void) 196462306a36Sopenharmony_ci{ 196562306a36Sopenharmony_ci memblock_can_resize = 1; 196662306a36Sopenharmony_ci} 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_cistatic int __init early_memblock(char *p) 196962306a36Sopenharmony_ci{ 197062306a36Sopenharmony_ci if (p && strstr(p, "debug")) 197162306a36Sopenharmony_ci memblock_debug = 1; 197262306a36Sopenharmony_ci return 0; 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ciearly_param("memblock", early_memblock); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_cistatic void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci struct page *start_pg, *end_pg; 197962306a36Sopenharmony_ci phys_addr_t pg, pgend; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci /* 198262306a36Sopenharmony_ci * Convert start_pfn/end_pfn to a struct page pointer. 198362306a36Sopenharmony_ci */ 198462306a36Sopenharmony_ci start_pg = pfn_to_page(start_pfn - 1) + 1; 198562306a36Sopenharmony_ci end_pg = pfn_to_page(end_pfn - 1) + 1; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci /* 198862306a36Sopenharmony_ci * Convert to physical addresses, and round start upwards and end 198962306a36Sopenharmony_ci * downwards. 199062306a36Sopenharmony_ci */ 199162306a36Sopenharmony_ci pg = PAGE_ALIGN(__pa(start_pg)); 199262306a36Sopenharmony_ci pgend = __pa(end_pg) & PAGE_MASK; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci /* 199562306a36Sopenharmony_ci * If there are free pages between these, free the section of the 199662306a36Sopenharmony_ci * memmap array. 199762306a36Sopenharmony_ci */ 199862306a36Sopenharmony_ci if (pg < pgend) 199962306a36Sopenharmony_ci memblock_phys_free(pg, pgend - pg); 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci/* 200362306a36Sopenharmony_ci * The mem_map array can get very big. Free the unused area of the memory map. 200462306a36Sopenharmony_ci */ 200562306a36Sopenharmony_cistatic void __init free_unused_memmap(void) 200662306a36Sopenharmony_ci{ 200762306a36Sopenharmony_ci unsigned long start, end, prev_end = 0; 200862306a36Sopenharmony_ci int i; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_HAVE_ARCH_PFN_VALID) || 201162306a36Sopenharmony_ci IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP)) 201262306a36Sopenharmony_ci return; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci /* 201562306a36Sopenharmony_ci * This relies on each bank being in address order. 201662306a36Sopenharmony_ci * The banks are sorted previously in bootmem_init(). 201762306a36Sopenharmony_ci */ 201862306a36Sopenharmony_ci for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) { 201962306a36Sopenharmony_ci#ifdef CONFIG_SPARSEMEM 202062306a36Sopenharmony_ci /* 202162306a36Sopenharmony_ci * Take care not to free memmap entries that don't exist 202262306a36Sopenharmony_ci * due to SPARSEMEM sections which aren't present. 202362306a36Sopenharmony_ci */ 202462306a36Sopenharmony_ci start = min(start, ALIGN(prev_end, PAGES_PER_SECTION)); 202562306a36Sopenharmony_ci#endif 202662306a36Sopenharmony_ci /* 202762306a36Sopenharmony_ci * Align down here since many operations in VM subsystem 202862306a36Sopenharmony_ci * presume that there are no holes in the memory map inside 202962306a36Sopenharmony_ci * a pageblock 203062306a36Sopenharmony_ci */ 203162306a36Sopenharmony_ci start = pageblock_start_pfn(start); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci /* 203462306a36Sopenharmony_ci * If we had a previous bank, and there is a space 203562306a36Sopenharmony_ci * between the current bank and the previous, free it. 203662306a36Sopenharmony_ci */ 203762306a36Sopenharmony_ci if (prev_end && prev_end < start) 203862306a36Sopenharmony_ci free_memmap(prev_end, start); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci /* 204162306a36Sopenharmony_ci * Align up here since many operations in VM subsystem 204262306a36Sopenharmony_ci * presume that there are no holes in the memory map inside 204362306a36Sopenharmony_ci * a pageblock 204462306a36Sopenharmony_ci */ 204562306a36Sopenharmony_ci prev_end = pageblock_align(end); 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci#ifdef CONFIG_SPARSEMEM 204962306a36Sopenharmony_ci if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION)) { 205062306a36Sopenharmony_ci prev_end = pageblock_align(end); 205162306a36Sopenharmony_ci free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION)); 205262306a36Sopenharmony_ci } 205362306a36Sopenharmony_ci#endif 205462306a36Sopenharmony_ci} 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_cistatic void __init __free_pages_memory(unsigned long start, unsigned long end) 205762306a36Sopenharmony_ci{ 205862306a36Sopenharmony_ci int order; 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci while (start < end) { 206162306a36Sopenharmony_ci /* 206262306a36Sopenharmony_ci * Free the pages in the largest chunks alignment allows. 206362306a36Sopenharmony_ci * 206462306a36Sopenharmony_ci * __ffs() behaviour is undefined for 0. start == 0 is 206562306a36Sopenharmony_ci * MAX_ORDER-aligned, set order to MAX_ORDER for the case. 206662306a36Sopenharmony_ci */ 206762306a36Sopenharmony_ci if (start) 206862306a36Sopenharmony_ci order = min_t(int, MAX_ORDER, __ffs(start)); 206962306a36Sopenharmony_ci else 207062306a36Sopenharmony_ci order = MAX_ORDER; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci while (start + (1UL << order) > end) 207362306a36Sopenharmony_ci order--; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci memblock_free_pages(pfn_to_page(start), start, order); 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci start += (1UL << order); 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci} 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_cistatic unsigned long __init __free_memory_core(phys_addr_t start, 208262306a36Sopenharmony_ci phys_addr_t end) 208362306a36Sopenharmony_ci{ 208462306a36Sopenharmony_ci unsigned long start_pfn = PFN_UP(start); 208562306a36Sopenharmony_ci unsigned long end_pfn = min_t(unsigned long, 208662306a36Sopenharmony_ci PFN_DOWN(end), max_low_pfn); 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci if (start_pfn >= end_pfn) 208962306a36Sopenharmony_ci return 0; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci __free_pages_memory(start_pfn, end_pfn); 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci return end_pfn - start_pfn; 209462306a36Sopenharmony_ci} 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_cistatic void __init memmap_init_reserved_pages(void) 209762306a36Sopenharmony_ci{ 209862306a36Sopenharmony_ci struct memblock_region *region; 209962306a36Sopenharmony_ci phys_addr_t start, end; 210062306a36Sopenharmony_ci int nid; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* 210362306a36Sopenharmony_ci * set nid on all reserved pages and also treat struct 210462306a36Sopenharmony_ci * pages for the NOMAP regions as PageReserved 210562306a36Sopenharmony_ci */ 210662306a36Sopenharmony_ci for_each_mem_region(region) { 210762306a36Sopenharmony_ci nid = memblock_get_region_node(region); 210862306a36Sopenharmony_ci start = region->base; 210962306a36Sopenharmony_ci end = start + region->size; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci if (memblock_is_nomap(region)) 211262306a36Sopenharmony_ci reserve_bootmem_region(start, end, nid); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci memblock_set_node(start, end, &memblock.reserved, nid); 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci /* initialize struct pages for the reserved regions */ 211862306a36Sopenharmony_ci for_each_reserved_mem_region(region) { 211962306a36Sopenharmony_ci nid = memblock_get_region_node(region); 212062306a36Sopenharmony_ci start = region->base; 212162306a36Sopenharmony_ci end = start + region->size; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci if (nid == NUMA_NO_NODE || nid >= MAX_NUMNODES) 212462306a36Sopenharmony_ci nid = early_pfn_to_nid(PFN_DOWN(start)); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci reserve_bootmem_region(start, end, nid); 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_cistatic unsigned long __init free_low_memory_core_early(void) 213162306a36Sopenharmony_ci{ 213262306a36Sopenharmony_ci unsigned long count = 0; 213362306a36Sopenharmony_ci phys_addr_t start, end; 213462306a36Sopenharmony_ci u64 i; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci memblock_clear_hotplug(0, -1); 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci memmap_init_reserved_pages(); 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci /* 214162306a36Sopenharmony_ci * We need to use NUMA_NO_NODE instead of NODE_DATA(0)->node_id 214262306a36Sopenharmony_ci * because in some case like Node0 doesn't have RAM installed 214362306a36Sopenharmony_ci * low ram will be on Node1 214462306a36Sopenharmony_ci */ 214562306a36Sopenharmony_ci for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, 214662306a36Sopenharmony_ci NULL) 214762306a36Sopenharmony_ci count += __free_memory_core(start, end); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci return count; 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cistatic int reset_managed_pages_done __initdata; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_cistatic void __init reset_node_managed_pages(pg_data_t *pgdat) 215562306a36Sopenharmony_ci{ 215662306a36Sopenharmony_ci struct zone *z; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) 215962306a36Sopenharmony_ci atomic_long_set(&z->managed_pages, 0); 216062306a36Sopenharmony_ci} 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_civoid __init reset_all_zones_managed_pages(void) 216362306a36Sopenharmony_ci{ 216462306a36Sopenharmony_ci struct pglist_data *pgdat; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci if (reset_managed_pages_done) 216762306a36Sopenharmony_ci return; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci for_each_online_pgdat(pgdat) 217062306a36Sopenharmony_ci reset_node_managed_pages(pgdat); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci reset_managed_pages_done = 1; 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci/** 217662306a36Sopenharmony_ci * memblock_free_all - release free pages to the buddy allocator 217762306a36Sopenharmony_ci */ 217862306a36Sopenharmony_civoid __init memblock_free_all(void) 217962306a36Sopenharmony_ci{ 218062306a36Sopenharmony_ci unsigned long pages; 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci free_unused_memmap(); 218362306a36Sopenharmony_ci reset_all_zones_managed_pages(); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci pages = free_low_memory_core_early(); 218662306a36Sopenharmony_ci totalram_pages_add(pages); 218762306a36Sopenharmony_ci} 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK) 219062306a36Sopenharmony_cistatic const char * const flagname[] = { 219162306a36Sopenharmony_ci [ilog2(MEMBLOCK_HOTPLUG)] = "HOTPLUG", 219262306a36Sopenharmony_ci [ilog2(MEMBLOCK_MIRROR)] = "MIRROR", 219362306a36Sopenharmony_ci [ilog2(MEMBLOCK_NOMAP)] = "NOMAP", 219462306a36Sopenharmony_ci [ilog2(MEMBLOCK_DRIVER_MANAGED)] = "DRV_MNG", 219562306a36Sopenharmony_ci}; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_cistatic int memblock_debug_show(struct seq_file *m, void *private) 219862306a36Sopenharmony_ci{ 219962306a36Sopenharmony_ci struct memblock_type *type = m->private; 220062306a36Sopenharmony_ci struct memblock_region *reg; 220162306a36Sopenharmony_ci int i, j, nid; 220262306a36Sopenharmony_ci unsigned int count = ARRAY_SIZE(flagname); 220362306a36Sopenharmony_ci phys_addr_t end; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci for (i = 0; i < type->cnt; i++) { 220662306a36Sopenharmony_ci reg = &type->regions[i]; 220762306a36Sopenharmony_ci end = reg->base + reg->size - 1; 220862306a36Sopenharmony_ci nid = memblock_get_region_node(reg); 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci seq_printf(m, "%4d: ", i); 221162306a36Sopenharmony_ci seq_printf(m, "%pa..%pa ", ®->base, &end); 221262306a36Sopenharmony_ci if (nid != MAX_NUMNODES) 221362306a36Sopenharmony_ci seq_printf(m, "%4d ", nid); 221462306a36Sopenharmony_ci else 221562306a36Sopenharmony_ci seq_printf(m, "%4c ", 'x'); 221662306a36Sopenharmony_ci if (reg->flags) { 221762306a36Sopenharmony_ci for (j = 0; j < count; j++) { 221862306a36Sopenharmony_ci if (reg->flags & (1U << j)) { 221962306a36Sopenharmony_ci seq_printf(m, "%s\n", flagname[j]); 222062306a36Sopenharmony_ci break; 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci if (j == count) 222462306a36Sopenharmony_ci seq_printf(m, "%s\n", "UNKNOWN"); 222562306a36Sopenharmony_ci } else { 222662306a36Sopenharmony_ci seq_printf(m, "%s\n", "NONE"); 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci } 222962306a36Sopenharmony_ci return 0; 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(memblock_debug); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_cistatic int __init memblock_init_debugfs(void) 223462306a36Sopenharmony_ci{ 223562306a36Sopenharmony_ci struct dentry *root = debugfs_create_dir("memblock", NULL); 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci debugfs_create_file("memory", 0444, root, 223862306a36Sopenharmony_ci &memblock.memory, &memblock_debug_fops); 223962306a36Sopenharmony_ci debugfs_create_file("reserved", 0444, root, 224062306a36Sopenharmony_ci &memblock.reserved, &memblock_debug_fops); 224162306a36Sopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 224262306a36Sopenharmony_ci debugfs_create_file("physmem", 0444, root, &physmem, 224362306a36Sopenharmony_ci &memblock_debug_fops); 224462306a36Sopenharmony_ci#endif 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci return 0; 224762306a36Sopenharmony_ci} 224862306a36Sopenharmony_ci__initcall(memblock_init_debugfs); 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 2251