13d0407baSopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 23d0407baSopenharmony_ci#ifndef _LINUX_MEMBLOCK_H 33d0407baSopenharmony_ci#define _LINUX_MEMBLOCK_H 43d0407baSopenharmony_ci#ifdef __KERNEL__ 53d0407baSopenharmony_ci 63d0407baSopenharmony_ci/* 73d0407baSopenharmony_ci * Logical memory blocks. 83d0407baSopenharmony_ci * 93d0407baSopenharmony_ci * Copyright (C) 2001 Peter Bergner, IBM Corp. 103d0407baSopenharmony_ci */ 113d0407baSopenharmony_ci 123d0407baSopenharmony_ci#include <linux/init.h> 133d0407baSopenharmony_ci#include <linux/mm.h> 143d0407baSopenharmony_ci#include <asm/dma.h> 153d0407baSopenharmony_ci 163d0407baSopenharmony_ciextern unsigned long max_low_pfn; 173d0407baSopenharmony_ciextern unsigned long min_low_pfn; 183d0407baSopenharmony_ci 193d0407baSopenharmony_ci/* 203d0407baSopenharmony_ci * highest page 213d0407baSopenharmony_ci */ 223d0407baSopenharmony_ciextern unsigned long max_pfn; 233d0407baSopenharmony_ci/* 243d0407baSopenharmony_ci * highest possible page 253d0407baSopenharmony_ci */ 263d0407baSopenharmony_ciextern unsigned long long max_possible_pfn; 273d0407baSopenharmony_ci 283d0407baSopenharmony_ci#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT 293d0407baSopenharmony_ciextern int defer_free_memblock(void *unused); 303d0407baSopenharmony_ci#endif 313d0407baSopenharmony_ci 323d0407baSopenharmony_ci/** 333d0407baSopenharmony_ci * enum memblock_flags - definition of memory region attributes 343d0407baSopenharmony_ci * @MEMBLOCK_NONE: no special request 353d0407baSopenharmony_ci * @MEMBLOCK_HOTPLUG: hotpluggable region 363d0407baSopenharmony_ci * @MEMBLOCK_MIRROR: mirrored region 373d0407baSopenharmony_ci * @MEMBLOCK_NOMAP: don't add to kernel direct mapping 383d0407baSopenharmony_ci */ 393d0407baSopenharmony_cienum memblock_flags { 403d0407baSopenharmony_ci MEMBLOCK_NONE = 0x0, /* No special request */ 413d0407baSopenharmony_ci MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */ 423d0407baSopenharmony_ci MEMBLOCK_MIRROR = 0x2, /* mirrored region */ 433d0407baSopenharmony_ci MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */ 443d0407baSopenharmony_ci}; 453d0407baSopenharmony_ci 463d0407baSopenharmony_ci/** 473d0407baSopenharmony_ci * struct memblock_region - represents a memory region 483d0407baSopenharmony_ci * @base: base address of the region 493d0407baSopenharmony_ci * @size: size of the region 503d0407baSopenharmony_ci * @flags: memory region attributes 513d0407baSopenharmony_ci * @nid: NUMA node id 523d0407baSopenharmony_ci */ 533d0407baSopenharmony_cistruct memblock_region { 543d0407baSopenharmony_ci phys_addr_t base; 553d0407baSopenharmony_ci phys_addr_t size; 563d0407baSopenharmony_ci enum memblock_flags flags; 573d0407baSopenharmony_ci#ifdef CONFIG_NEED_MULTIPLE_NODES 583d0407baSopenharmony_ci int nid; 593d0407baSopenharmony_ci#endif 603d0407baSopenharmony_ci}; 613d0407baSopenharmony_ci 623d0407baSopenharmony_ci/** 633d0407baSopenharmony_ci * struct memblock_type - collection of memory regions of certain type 643d0407baSopenharmony_ci * @cnt: number of regions 653d0407baSopenharmony_ci * @max: size of the allocated array 663d0407baSopenharmony_ci * @total_size: size of all regions 673d0407baSopenharmony_ci * @regions: array of regions 683d0407baSopenharmony_ci * @name: the memory type symbolic name 693d0407baSopenharmony_ci */ 703d0407baSopenharmony_cistruct memblock_type { 713d0407baSopenharmony_ci unsigned long cnt; 723d0407baSopenharmony_ci unsigned long max; 733d0407baSopenharmony_ci phys_addr_t total_size; 743d0407baSopenharmony_ci struct memblock_region *regions; 753d0407baSopenharmony_ci char *name; 763d0407baSopenharmony_ci}; 773d0407baSopenharmony_ci 783d0407baSopenharmony_ci/** 793d0407baSopenharmony_ci * struct memblock - memblock allocator metadata 803d0407baSopenharmony_ci * @bottom_up: is bottom up direction? 813d0407baSopenharmony_ci * @current_limit: physical address of the current allocation limit 823d0407baSopenharmony_ci * @memory: usable memory regions 833d0407baSopenharmony_ci * @reserved: reserved memory regions 843d0407baSopenharmony_ci */ 853d0407baSopenharmony_cistruct memblock { 863d0407baSopenharmony_ci bool bottom_up; /* is bottom up direction? */ 873d0407baSopenharmony_ci phys_addr_t current_limit; 883d0407baSopenharmony_ci struct memblock_type memory; 893d0407baSopenharmony_ci struct memblock_type reserved; 903d0407baSopenharmony_ci}; 913d0407baSopenharmony_ci 923d0407baSopenharmony_ciextern struct memblock memblock; 933d0407baSopenharmony_ci 943d0407baSopenharmony_ci#ifndef CONFIG_ARCH_KEEP_MEMBLOCK 953d0407baSopenharmony_ci#define __init_memblock __meminit 963d0407baSopenharmony_ci#define __initdata_memblock __meminitdata 973d0407baSopenharmony_civoid memblock_discard(void); 983d0407baSopenharmony_ci#else 993d0407baSopenharmony_ci#define __init_memblock 1003d0407baSopenharmony_ci#define __initdata_memblock 1013d0407baSopenharmony_cistatic inline void memblock_discard(void) 1023d0407baSopenharmony_ci{ 1033d0407baSopenharmony_ci} 1043d0407baSopenharmony_ci#endif 1053d0407baSopenharmony_ci 1063d0407baSopenharmony_ciphys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align); 1073d0407baSopenharmony_civoid memblock_allow_resize(void); 1083d0407baSopenharmony_ciint memblock_add_node(phys_addr_t base, phys_addr_t size, int nid); 1093d0407baSopenharmony_ciint memblock_add(phys_addr_t base, phys_addr_t size); 1103d0407baSopenharmony_ciint memblock_remove(phys_addr_t base, phys_addr_t size); 1113d0407baSopenharmony_ciint memblock_free(phys_addr_t base, phys_addr_t size); 1123d0407baSopenharmony_ciint memblock_reserve(phys_addr_t base, phys_addr_t size); 1133d0407baSopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 1143d0407baSopenharmony_ciint memblock_physmem_add(phys_addr_t base, phys_addr_t size); 1153d0407baSopenharmony_ci#endif 1163d0407baSopenharmony_civoid memblock_trim_memory(phys_addr_t align); 1173d0407baSopenharmony_cibool memblock_overlaps_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size); 1183d0407baSopenharmony_ciint memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); 1193d0407baSopenharmony_ciint memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); 1203d0407baSopenharmony_ciint memblock_mark_mirror(phys_addr_t base, phys_addr_t size); 1213d0407baSopenharmony_ciint memblock_mark_nomap(phys_addr_t base, phys_addr_t size); 1223d0407baSopenharmony_ciint memblock_clear_nomap(phys_addr_t base, phys_addr_t size); 1233d0407baSopenharmony_ci 1243d0407baSopenharmony_ciunsigned long memblock_free_all(void); 1253d0407baSopenharmony_civoid reset_node_managed_pages(pg_data_t *pgdat); 1263d0407baSopenharmony_civoid reset_all_zones_managed_pages(void); 1273d0407baSopenharmony_ci 1283d0407baSopenharmony_ci/* Low level functions */ 1293d0407baSopenharmony_civoid __next_mem_range(u64 *idx, int nid, enum memblock_flags flags, struct memblock_type *type_a, 1303d0407baSopenharmony_ci struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid); 1313d0407baSopenharmony_ci 1323d0407baSopenharmony_civoid __next_mem_range_rev(u64 *idx, int nid, enum memblock_flags flags, struct memblock_type *type_a, 1333d0407baSopenharmony_ci struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid); 1343d0407baSopenharmony_ci 1353d0407baSopenharmony_civoid __memblock_free_late(phys_addr_t base, phys_addr_t size); 1363d0407baSopenharmony_ci 1373d0407baSopenharmony_ci#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP 1383d0407baSopenharmony_cistatic inline void _next_physmem_range(u64 *idx, struct memblock_type *type, phys_addr_t *out_start, 1393d0407baSopenharmony_ci phys_addr_t *out_end) 1403d0407baSopenharmony_ci{ 1413d0407baSopenharmony_ci extern struct memblock_type physmem; 1423d0407baSopenharmony_ci 1433d0407baSopenharmony_ci __next_mem_range(idx, NUMA_NO_NODE, MEMBLOCK_NONE, &physmem, type, out_start, out_end, NULL); 1443d0407baSopenharmony_ci} 1453d0407baSopenharmony_ci 1463d0407baSopenharmony_ci/** 1473d0407baSopenharmony_ci * for_each_physmem_range - iterate through physmem areas not included in type. 1483d0407baSopenharmony_ci * @i: u64 used as loop variable 1493d0407baSopenharmony_ci * @type: ptr to memblock_type which excludes from the iteration, can be %NULL 1503d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 1513d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 1523d0407baSopenharmony_ci */ 1533d0407baSopenharmony_ci#define for_each_physmem_range(i, type, p_start, p_end) \ 1543d0407baSopenharmony_ci for (i = 0, _next_physmem_range(&i, type, p_start, p_end); i != (u64)ULLONG_MAX; \ 1553d0407baSopenharmony_ci _next_physmem_range(&i, type, p_start, p_end)) 1563d0407baSopenharmony_ci#endif /* CONFIG_HAVE_MEMBLOCK_PHYS_MAP */ 1573d0407baSopenharmony_ci 1583d0407baSopenharmony_ci/** 1593d0407baSopenharmony_ci * _for_each_mem_range - iterate through memblock areas from type_a and not 1603d0407baSopenharmony_ci * included in type_b. Or just type_a if type_b is NULL. 1613d0407baSopenharmony_ci * @i: u64 used as loop variable 1623d0407baSopenharmony_ci * @type_a: ptr to memblock_type to iterate 1633d0407baSopenharmony_ci * @type_b: ptr to memblock_type which excludes from the iteration 1643d0407baSopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 1653d0407baSopenharmony_ci * @flags: pick from blocks based on memory attributes 1663d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 1673d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 1683d0407baSopenharmony_ci * @p_nid: ptr to int for nid of the range, can be %NULL 1693d0407baSopenharmony_ci */ 1703d0407baSopenharmony_ci#define _for_each_mem_range(i, type_a, type_b, nid, flags, p_start, p_end, p_nid) \ 1713d0407baSopenharmony_ci for (i = 0, __next_mem_range(&i, nid, flags, type_a, type_b, p_start, p_end, p_nid); i != (u64)ULLONG_MAX; \ 1723d0407baSopenharmony_ci __next_mem_range(&i, nid, flags, type_a, type_b, p_start, p_end, p_nid)) 1733d0407baSopenharmony_ci 1743d0407baSopenharmony_ci/** 1753d0407baSopenharmony_ci * _for_each_mem_range_rev - reverse iterate through memblock areas from 1763d0407baSopenharmony_ci * type_a and not included in type_b. Or just type_a if type_b is NULL. 1773d0407baSopenharmony_ci * @i: u64 used as loop variable 1783d0407baSopenharmony_ci * @type_a: ptr to memblock_type to iterate 1793d0407baSopenharmony_ci * @type_b: ptr to memblock_type which excludes from the iteration 1803d0407baSopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 1813d0407baSopenharmony_ci * @flags: pick from blocks based on memory attributes 1823d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 1833d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 1843d0407baSopenharmony_ci * @p_nid: ptr to int for nid of the range, can be %NULL 1853d0407baSopenharmony_ci */ 1863d0407baSopenharmony_ci#define _for_each_mem_range_rev(i, type_a, type_b, nid, flags, p_start, p_end, p_nid) \ 1873d0407baSopenharmony_ci for (i = (u64)ULLONG_MAX, __next_mem_range_rev(&i, nid, flags, type_a, type_b, p_start, p_end, p_nid); \ 1883d0407baSopenharmony_ci i != (u64)ULLONG_MAX; __next_mem_range_rev(&i, nid, flags, type_a, type_b, p_start, p_end, p_nid)) 1893d0407baSopenharmony_ci 1903d0407baSopenharmony_ci/** 1913d0407baSopenharmony_ci * for_each_mem_range - iterate through memory areas. 1923d0407baSopenharmony_ci * @i: u64 used as loop variable 1933d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 1943d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 1953d0407baSopenharmony_ci */ 1963d0407baSopenharmony_ci#define for_each_mem_range(i, p_start, p_end) \ 1973d0407baSopenharmony_ci _for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE, MEMBLOCK_HOTPLUG, p_start, p_end, NULL) 1983d0407baSopenharmony_ci 1993d0407baSopenharmony_ci/** 2003d0407baSopenharmony_ci * for_each_mem_range_rev - reverse iterate through memblock areas from 2013d0407baSopenharmony_ci * type_a and not included in type_b. Or just type_a if type_b is NULL. 2023d0407baSopenharmony_ci * @i: u64 used as loop variable 2033d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 2043d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 2053d0407baSopenharmony_ci */ 2063d0407baSopenharmony_ci#define for_each_mem_range_rev(i, p_start, p_end) \ 2073d0407baSopenharmony_ci _for_each_mem_range_rev(i, &memblock.memory, NULL, NUMA_NO_NODE, MEMBLOCK_HOTPLUG, p_start, p_end, NULL) 2083d0407baSopenharmony_ci 2093d0407baSopenharmony_ci/** 2103d0407baSopenharmony_ci * for_each_reserved_mem_range - iterate over all reserved memblock areas 2113d0407baSopenharmony_ci * @i: u64 used as loop variable 2123d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 2133d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 2143d0407baSopenharmony_ci * 2153d0407baSopenharmony_ci * Walks over reserved areas of memblock. Available as soon as memblock 2163d0407baSopenharmony_ci * is initialized. 2173d0407baSopenharmony_ci */ 2183d0407baSopenharmony_ci#define for_each_reserved_mem_range(i, p_start, p_end) \ 2193d0407baSopenharmony_ci _for_each_mem_range(i, &memblock.reserved, NULL, NUMA_NO_NODE, MEMBLOCK_NONE, p_start, p_end, NULL) 2203d0407baSopenharmony_ci 2213d0407baSopenharmony_cistatic inline bool memblock_is_hotpluggable(struct memblock_region *m) 2223d0407baSopenharmony_ci{ 2233d0407baSopenharmony_ci return m->flags & MEMBLOCK_HOTPLUG; 2243d0407baSopenharmony_ci} 2253d0407baSopenharmony_ci 2263d0407baSopenharmony_cistatic inline bool memblock_is_mirror(struct memblock_region *m) 2273d0407baSopenharmony_ci{ 2283d0407baSopenharmony_ci return m->flags & MEMBLOCK_MIRROR; 2293d0407baSopenharmony_ci} 2303d0407baSopenharmony_ci 2313d0407baSopenharmony_cistatic inline bool memblock_is_nomap(struct memblock_region *m) 2323d0407baSopenharmony_ci{ 2333d0407baSopenharmony_ci return m->flags & MEMBLOCK_NOMAP; 2343d0407baSopenharmony_ci} 2353d0407baSopenharmony_ci 2363d0407baSopenharmony_ciint memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn, unsigned long *end_pfn); 2373d0407baSopenharmony_civoid __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, unsigned long *out_end_pfn, int *out_nid); 2383d0407baSopenharmony_ci 2393d0407baSopenharmony_ci/** 2403d0407baSopenharmony_ci * for_each_mem_pfn_range - early memory pfn range iterator 2413d0407baSopenharmony_ci * @i: an integer used as loop variable 2423d0407baSopenharmony_ci * @nid: node selector, %MAX_NUMNODES for all nodes 2433d0407baSopenharmony_ci * @p_start: ptr to ulong for start pfn of the range, can be %NULL 2443d0407baSopenharmony_ci * @p_end: ptr to ulong for end pfn of the range, can be %NULL 2453d0407baSopenharmony_ci * @p_nid: ptr to int for nid of the range, can be %NULL 2463d0407baSopenharmony_ci * 2473d0407baSopenharmony_ci * Walks over configured memory ranges. 2483d0407baSopenharmony_ci */ 2493d0407baSopenharmony_ci#define for_each_mem_pfn_range(i, nid, p_start, p_end, p_nid) \ 2503d0407baSopenharmony_ci for (i = -1, __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid); i >= 0; \ 2513d0407baSopenharmony_ci __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid)) 2523d0407baSopenharmony_ci 2533d0407baSopenharmony_ci#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT 2543d0407baSopenharmony_civoid __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, unsigned long *out_spfn, unsigned long *out_epfn); 2553d0407baSopenharmony_ci/** 2563d0407baSopenharmony_ci * for_each_free_mem_range_in_zone - iterate through zone specific free 2573d0407baSopenharmony_ci * memblock areas 2583d0407baSopenharmony_ci * @i: u64 used as loop variable 2593d0407baSopenharmony_ci * @zone: zone in which all of the memory blocks reside 2603d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 2613d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 2623d0407baSopenharmony_ci * 2633d0407baSopenharmony_ci * Walks over free (memory && !reserved) areas of memblock in a specific 2643d0407baSopenharmony_ci * zone. Available once memblock and an empty zone is initialized. The main 2653d0407baSopenharmony_ci * assumption is that the zone start, end, and pgdat have been associated. 2663d0407baSopenharmony_ci * This way we can use the zone to determine NUMA node, and if a given part 2673d0407baSopenharmony_ci * of the memblock is valid for the zone. 2683d0407baSopenharmony_ci */ 2693d0407baSopenharmony_ci#define for_each_free_mem_pfn_range_in_zone(i, zone, p_start, p_end) \ 2703d0407baSopenharmony_ci for (i = 0, __next_mem_pfn_range_in_zone(&i, zone, p_start, p_end); i != U64_MAX; \ 2713d0407baSopenharmony_ci __next_mem_pfn_range_in_zone(&i, zone, p_start, p_end)) 2723d0407baSopenharmony_ci 2733d0407baSopenharmony_ci/** 2743d0407baSopenharmony_ci * for_each_free_mem_range_in_zone_from - iterate through zone specific 2753d0407baSopenharmony_ci * free memblock areas from a given point 2763d0407baSopenharmony_ci * @i: u64 used as loop variable 2773d0407baSopenharmony_ci * @zone: zone in which all of the memory blocks reside 2783d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 2793d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 2803d0407baSopenharmony_ci * 2813d0407baSopenharmony_ci * Walks over free (memory && !reserved) areas of memblock in a specific 2823d0407baSopenharmony_ci * zone, continuing from current position. Available as soon as memblock is 2833d0407baSopenharmony_ci * initialized. 2843d0407baSopenharmony_ci */ 2853d0407baSopenharmony_ci#define for_each_free_mem_pfn_range_in_zone_from(i, zone, p_start, p_end) \ 2863d0407baSopenharmony_ci for (; i != U64_MAX; __next_mem_pfn_range_in_zone(&i, zone, p_start, p_end)) 2873d0407baSopenharmony_ci 2883d0407baSopenharmony_ciint __init deferred_page_init_max_threads(const struct cpumask *node_cpumask); 2893d0407baSopenharmony_ci 2903d0407baSopenharmony_ci#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ 2913d0407baSopenharmony_ci 2923d0407baSopenharmony_ci/** 2933d0407baSopenharmony_ci * for_each_free_mem_range - iterate through free memblock areas 2943d0407baSopenharmony_ci * @i: u64 used as loop variable 2953d0407baSopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 2963d0407baSopenharmony_ci * @flags: pick from blocks based on memory attributes 2973d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 2983d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 2993d0407baSopenharmony_ci * @p_nid: ptr to int for nid of the range, can be %NULL 3003d0407baSopenharmony_ci * 3013d0407baSopenharmony_ci * Walks over free (memory && !reserved) areas of memblock. Available as 3023d0407baSopenharmony_ci * soon as memblock is initialized. 3033d0407baSopenharmony_ci */ 3043d0407baSopenharmony_ci#define for_each_free_mem_range(i, nid, flags, p_start, p_end, p_nid) \ 3053d0407baSopenharmony_ci _for_each_mem_range(i, &memblock.memory, &memblock.reserved, nid, flags, p_start, p_end, p_nid) 3063d0407baSopenharmony_ci 3073d0407baSopenharmony_ci/** 3083d0407baSopenharmony_ci * for_each_free_mem_range_reverse - rev-iterate through free memblock areas 3093d0407baSopenharmony_ci * @i: u64 used as loop variable 3103d0407baSopenharmony_ci * @nid: node selector, %NUMA_NO_NODE for all nodes 3113d0407baSopenharmony_ci * @flags: pick from blocks based on memory attributes 3123d0407baSopenharmony_ci * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL 3133d0407baSopenharmony_ci * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL 3143d0407baSopenharmony_ci * @p_nid: ptr to int for nid of the range, can be %NULL 3153d0407baSopenharmony_ci * 3163d0407baSopenharmony_ci * Walks over free (memory && !reserved) areas of memblock in reverse 3173d0407baSopenharmony_ci * order. Available as soon as memblock is initialized. 3183d0407baSopenharmony_ci */ 3193d0407baSopenharmony_ci#define for_each_free_mem_range_reverse(i, nid, flags, p_start, p_end, p_nid) \ 3203d0407baSopenharmony_ci _for_each_mem_range_rev(i, &memblock.memory, &memblock.reserved, nid, flags, p_start, p_end, p_nid) 3213d0407baSopenharmony_ci 3223d0407baSopenharmony_ciint memblock_set_node(phys_addr_t base, phys_addr_t size, struct memblock_type *type, int nid); 3233d0407baSopenharmony_ci 3243d0407baSopenharmony_ci#ifdef CONFIG_NEED_MULTIPLE_NODES 3253d0407baSopenharmony_cistatic inline void memblock_set_region_node(struct memblock_region *r, int nid) 3263d0407baSopenharmony_ci{ 3273d0407baSopenharmony_ci r->nid = nid; 3283d0407baSopenharmony_ci} 3293d0407baSopenharmony_ci 3303d0407baSopenharmony_cistatic inline int memblock_get_region_node(const struct memblock_region *r) 3313d0407baSopenharmony_ci{ 3323d0407baSopenharmony_ci return r->nid; 3333d0407baSopenharmony_ci} 3343d0407baSopenharmony_ci#else 3353d0407baSopenharmony_cistatic inline void memblock_set_region_node(struct memblock_region *r, int nid) 3363d0407baSopenharmony_ci{ 3373d0407baSopenharmony_ci} 3383d0407baSopenharmony_ci 3393d0407baSopenharmony_cistatic inline int memblock_get_region_node(const struct memblock_region *r) 3403d0407baSopenharmony_ci{ 3413d0407baSopenharmony_ci return 0; 3423d0407baSopenharmony_ci} 3433d0407baSopenharmony_ci#endif /* CONFIG_NEED_MULTIPLE_NODES */ 3443d0407baSopenharmony_ci 3453d0407baSopenharmony_ci/* Flags for memblock allocation APIs */ 3463d0407baSopenharmony_ci#define MEMBLOCK_ALLOC_ANYWHERE (~(phys_addr_t)0) 3473d0407baSopenharmony_ci#define MEMBLOCK_ALLOC_ACCESSIBLE 0 3483d0407baSopenharmony_ci#define MEMBLOCK_ALLOC_KASAN 1 3493d0407baSopenharmony_ci 3503d0407baSopenharmony_ci/* We are using top down, so it is safe to use 0 here */ 3513d0407baSopenharmony_ci#define MEMBLOCK_LOW_LIMIT 0 3523d0407baSopenharmony_ci 3533d0407baSopenharmony_ci#ifndef ARCH_LOW_ADDRESS_LIMIT 3543d0407baSopenharmony_ci#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL 3553d0407baSopenharmony_ci#endif 3563d0407baSopenharmony_ci 3573d0407baSopenharmony_ciphys_addr_t memblock_phys_alloc_range(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end); 3583d0407baSopenharmony_ciphys_addr_t memblock_alloc_range_nid(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, int nid, 3593d0407baSopenharmony_ci bool exact_nid); 3603d0407baSopenharmony_ciphys_addr_t memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid); 3613d0407baSopenharmony_ci 3623d0407baSopenharmony_cistatic __always_inline phys_addr_t memblock_phys_alloc(phys_addr_t size, phys_addr_t align) 3633d0407baSopenharmony_ci{ 3643d0407baSopenharmony_ci return memblock_phys_alloc_range(size, align, 0, MEMBLOCK_ALLOC_ACCESSIBLE); 3653d0407baSopenharmony_ci} 3663d0407baSopenharmony_ci 3673d0407baSopenharmony_civoid *memblock_alloc_exact_nid_raw(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, 3683d0407baSopenharmony_ci int nid); 3693d0407baSopenharmony_civoid *memblock_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, 3703d0407baSopenharmony_ci int nid); 3713d0407baSopenharmony_civoid *memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, int nid); 3723d0407baSopenharmony_ci 3733d0407baSopenharmony_cistatic __always_inline void *memblock_alloc(phys_addr_t size, phys_addr_t align) 3743d0407baSopenharmony_ci{ 3753d0407baSopenharmony_ci return memblock_alloc_try_nid(size, align, MEMBLOCK_LOW_LIMIT, MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); 3763d0407baSopenharmony_ci} 3773d0407baSopenharmony_ci 3783d0407baSopenharmony_cistatic inline void *memblock_alloc_raw(phys_addr_t size, phys_addr_t align) 3793d0407baSopenharmony_ci{ 3803d0407baSopenharmony_ci return memblock_alloc_try_nid_raw(size, align, MEMBLOCK_LOW_LIMIT, MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); 3813d0407baSopenharmony_ci} 3823d0407baSopenharmony_ci 3833d0407baSopenharmony_cistatic inline void *memblock_alloc_from(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr) 3843d0407baSopenharmony_ci{ 3853d0407baSopenharmony_ci return memblock_alloc_try_nid(size, align, min_addr, MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); 3863d0407baSopenharmony_ci} 3873d0407baSopenharmony_ci 3883d0407baSopenharmony_cistatic inline void *memblock_alloc_low(phys_addr_t size, phys_addr_t align) 3893d0407baSopenharmony_ci{ 3903d0407baSopenharmony_ci return memblock_alloc_try_nid(size, align, MEMBLOCK_LOW_LIMIT, ARCH_LOW_ADDRESS_LIMIT, NUMA_NO_NODE); 3913d0407baSopenharmony_ci} 3923d0407baSopenharmony_ci 3933d0407baSopenharmony_cistatic inline void *memblock_alloc_node(phys_addr_t size, phys_addr_t align, int nid) 3943d0407baSopenharmony_ci{ 3953d0407baSopenharmony_ci return memblock_alloc_try_nid(size, align, MEMBLOCK_LOW_LIMIT, MEMBLOCK_ALLOC_ACCESSIBLE, nid); 3963d0407baSopenharmony_ci} 3973d0407baSopenharmony_ci 3983d0407baSopenharmony_cistatic inline void memblock_free_early(phys_addr_t base, phys_addr_t size) 3993d0407baSopenharmony_ci{ 4003d0407baSopenharmony_ci memblock_free(base, size); 4013d0407baSopenharmony_ci} 4023d0407baSopenharmony_ci 4033d0407baSopenharmony_cistatic inline void memblock_free_early_nid(phys_addr_t base, phys_addr_t size, int nid) 4043d0407baSopenharmony_ci{ 4053d0407baSopenharmony_ci memblock_free(base, size); 4063d0407baSopenharmony_ci} 4073d0407baSopenharmony_ci 4083d0407baSopenharmony_cistatic inline void memblock_free_late(phys_addr_t base, phys_addr_t size) 4093d0407baSopenharmony_ci{ 4103d0407baSopenharmony_ci __memblock_free_late(base, size); 4113d0407baSopenharmony_ci} 4123d0407baSopenharmony_ci 4133d0407baSopenharmony_ci/* 4143d0407baSopenharmony_ci * Set the allocation direction to bottom-up or top-down. 4153d0407baSopenharmony_ci */ 4163d0407baSopenharmony_cistatic inline __init void memblock_set_bottom_up(bool enable) 4173d0407baSopenharmony_ci{ 4183d0407baSopenharmony_ci memblock.bottom_up = enable; 4193d0407baSopenharmony_ci} 4203d0407baSopenharmony_ci 4213d0407baSopenharmony_ci/* 4223d0407baSopenharmony_ci * Check if the allocation direction is bottom-up or not. 4233d0407baSopenharmony_ci * if this is true, that said, memblock will allocate memory 4243d0407baSopenharmony_ci * in bottom-up direction. 4253d0407baSopenharmony_ci */ 4263d0407baSopenharmony_cistatic inline __init bool memblock_bottom_up(void) 4273d0407baSopenharmony_ci{ 4283d0407baSopenharmony_ci return memblock.bottom_up; 4293d0407baSopenharmony_ci} 4303d0407baSopenharmony_ci 4313d0407baSopenharmony_ciphys_addr_t memblock_phys_mem_size(void); 4323d0407baSopenharmony_ciphys_addr_t memblock_reserved_size(void); 4333d0407baSopenharmony_ciphys_addr_t memblock_start_of_DRAM(void); 4343d0407baSopenharmony_ciphys_addr_t memblock_end_of_DRAM(void); 4353d0407baSopenharmony_civoid memblock_enforce_memory_limit(phys_addr_t memory_limit); 4363d0407baSopenharmony_civoid memblock_cap_memory_range(phys_addr_t base, phys_addr_t size); 4373d0407baSopenharmony_civoid memblock_mem_limit_remove_map(phys_addr_t limit); 4383d0407baSopenharmony_cibool memblock_is_memory(phys_addr_t addr); 4393d0407baSopenharmony_cibool memblock_is_map_memory(phys_addr_t addr); 4403d0407baSopenharmony_cibool memblock_is_region_memory(phys_addr_t base, phys_addr_t size); 4413d0407baSopenharmony_cibool memblock_is_reserved(phys_addr_t addr); 4423d0407baSopenharmony_cibool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size); 4433d0407baSopenharmony_ci 4443d0407baSopenharmony_civoid memblock_dump_all(void); 4453d0407baSopenharmony_ci 4463d0407baSopenharmony_ci/** 4473d0407baSopenharmony_ci * memblock_set_current_limit - Set the current allocation limit to allow 4483d0407baSopenharmony_ci * limiting allocations to what is currently 4493d0407baSopenharmony_ci * accessible during boot 4503d0407baSopenharmony_ci * @limit: New limit value (physical address) 4513d0407baSopenharmony_ci */ 4523d0407baSopenharmony_civoid memblock_set_current_limit(phys_addr_t limit); 4533d0407baSopenharmony_ci 4543d0407baSopenharmony_ciphys_addr_t memblock_get_current_limit(void); 4553d0407baSopenharmony_ci 4563d0407baSopenharmony_ci/* 4573d0407baSopenharmony_ci * pfn conversion functions 4583d0407baSopenharmony_ci * 4593d0407baSopenharmony_ci * While the memory MEMBLOCKs should always be page aligned, the reserved 4603d0407baSopenharmony_ci * MEMBLOCKs may not be. This accessor attempt to provide a very clear 4613d0407baSopenharmony_ci * idea of what they return for such non aligned MEMBLOCKs. 4623d0407baSopenharmony_ci */ 4633d0407baSopenharmony_ci 4643d0407baSopenharmony_ci/** 4653d0407baSopenharmony_ci * memblock_region_memory_base_pfn - get the lowest pfn of the memory region 4663d0407baSopenharmony_ci * @reg: memblock_region structure 4673d0407baSopenharmony_ci * 4683d0407baSopenharmony_ci * Return: the lowest pfn intersecting with the memory region 4693d0407baSopenharmony_ci */ 4703d0407baSopenharmony_cistatic inline unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg) 4713d0407baSopenharmony_ci{ 4723d0407baSopenharmony_ci return PFN_UP(reg->base); 4733d0407baSopenharmony_ci} 4743d0407baSopenharmony_ci 4753d0407baSopenharmony_ci/** 4763d0407baSopenharmony_ci * memblock_region_memory_end_pfn - get the end pfn of the memory region 4773d0407baSopenharmony_ci * @reg: memblock_region structure 4783d0407baSopenharmony_ci * 4793d0407baSopenharmony_ci * Return: the end_pfn of the reserved region 4803d0407baSopenharmony_ci */ 4813d0407baSopenharmony_cistatic inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg) 4823d0407baSopenharmony_ci{ 4833d0407baSopenharmony_ci return PFN_DOWN(reg->base + reg->size); 4843d0407baSopenharmony_ci} 4853d0407baSopenharmony_ci 4863d0407baSopenharmony_ci/** 4873d0407baSopenharmony_ci * memblock_region_reserved_base_pfn - get the lowest pfn of the reserved region 4883d0407baSopenharmony_ci * @reg: memblock_region structure 4893d0407baSopenharmony_ci * 4903d0407baSopenharmony_ci * Return: the lowest pfn intersecting with the reserved region 4913d0407baSopenharmony_ci */ 4923d0407baSopenharmony_cistatic inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg) 4933d0407baSopenharmony_ci{ 4943d0407baSopenharmony_ci return PFN_DOWN(reg->base); 4953d0407baSopenharmony_ci} 4963d0407baSopenharmony_ci 4973d0407baSopenharmony_ci/** 4983d0407baSopenharmony_ci * memblock_region_reserved_end_pfn - get the end pfn of the reserved region 4993d0407baSopenharmony_ci * @reg: memblock_region structure 5003d0407baSopenharmony_ci * 5013d0407baSopenharmony_ci * Return: the end_pfn of the reserved region 5023d0407baSopenharmony_ci */ 5033d0407baSopenharmony_cistatic inline unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg) 5043d0407baSopenharmony_ci{ 5053d0407baSopenharmony_ci return PFN_UP(reg->base + reg->size); 5063d0407baSopenharmony_ci} 5073d0407baSopenharmony_ci 5083d0407baSopenharmony_ci/** 5093d0407baSopenharmony_ci * for_each_mem_region - itereate over memory regions 5103d0407baSopenharmony_ci * @region: loop variable 5113d0407baSopenharmony_ci */ 5123d0407baSopenharmony_ci#define for_each_mem_region(region) \ 5133d0407baSopenharmony_ci for (region = memblock.memory.regions; region < (memblock.memory.regions + memblock.memory.cnt); region++) 5143d0407baSopenharmony_ci 5153d0407baSopenharmony_ci/** 5163d0407baSopenharmony_ci * for_each_reserved_mem_region - itereate over reserved memory regions 5173d0407baSopenharmony_ci * @region: loop variable 5183d0407baSopenharmony_ci */ 5193d0407baSopenharmony_ci#define for_each_reserved_mem_region(region) \ 5203d0407baSopenharmony_ci for (region = memblock.reserved.regions; region < (memblock.reserved.regions + memblock.reserved.cnt); region++) 5213d0407baSopenharmony_ci 5223d0407baSopenharmony_ciextern void *alloc_large_system_hash(const char *tablename, unsigned long bucketsize, unsigned long numentries, 5233d0407baSopenharmony_ci int scale, int flags, unsigned int *_hash_shift, unsigned int *_hash_mask, 5243d0407baSopenharmony_ci unsigned long low_limit, unsigned long high_limit); 5253d0407baSopenharmony_ci 5263d0407baSopenharmony_ci#define HASH_EARLY 0x00000001 /* Allocating during early boot? */ 5273d0407baSopenharmony_ci#define HASH_SMALL \ 5283d0407baSopenharmony_ci 0x00000002 /* sub-page allocation allowed, min \ 5293d0407baSopenharmony_ci * shift passed via *_hash_shift */ 5303d0407baSopenharmony_ci#define HASH_ZERO 0x00000004 /* Zero allocated hash table */ 5313d0407baSopenharmony_ci 5323d0407baSopenharmony_ci/* Only NUMA needs hash distribution. 64bit NUMA architectures have 5333d0407baSopenharmony_ci * sufficient vmalloc space. 5343d0407baSopenharmony_ci */ 5353d0407baSopenharmony_ci#ifdef CONFIG_NUMA 5363d0407baSopenharmony_ci#define HASHDIST_DEFAULT IS_ENABLED(CONFIG_64BIT) 5373d0407baSopenharmony_ciextern int hashdist; /* Distribute hashes across NUMA nodes? */ 5383d0407baSopenharmony_ci#else 5393d0407baSopenharmony_ci#define hashdist (0) 5403d0407baSopenharmony_ci#endif 5413d0407baSopenharmony_ci 5423d0407baSopenharmony_ci#ifdef CONFIG_MEMTEST 5433d0407baSopenharmony_ciextern void early_memtest(phys_addr_t start, phys_addr_t end); 5443d0407baSopenharmony_ci#else 5453d0407baSopenharmony_cistatic inline void early_memtest(phys_addr_t start, phys_addr_t end) 5463d0407baSopenharmony_ci{ 5473d0407baSopenharmony_ci} 5483d0407baSopenharmony_ci#endif 5493d0407baSopenharmony_ci 5503d0407baSopenharmony_ci#endif /* __KERNEL__ */ 5513d0407baSopenharmony_ci 5523d0407baSopenharmony_ci#endif /* _LINUX_MEMBLOCK_H */ 553