195f72d1eSYinghai Lu /* 295f72d1eSYinghai Lu * Procedures for maintaining information about logical memory blocks. 395f72d1eSYinghai Lu * 495f72d1eSYinghai Lu * Peter Bergner, IBM Corp. June 2001. 595f72d1eSYinghai Lu * Copyright (C) 2001 Peter Bergner. 695f72d1eSYinghai Lu * 795f72d1eSYinghai Lu * This program is free software; you can redistribute it and/or 895f72d1eSYinghai Lu * modify it under the terms of the GNU General Public License 995f72d1eSYinghai Lu * as published by the Free Software Foundation; either version 1095f72d1eSYinghai Lu * 2 of the License, or (at your option) any later version. 1195f72d1eSYinghai Lu */ 1295f72d1eSYinghai Lu 1395f72d1eSYinghai Lu #include <linux/kernel.h> 14142b45a7SBenjamin Herrenschmidt #include <linux/slab.h> 1595f72d1eSYinghai Lu #include <linux/init.h> 1695f72d1eSYinghai Lu #include <linux/bitops.h> 17449e8df3SBenjamin Herrenschmidt #include <linux/poison.h> 18c196f76fSBenjamin Herrenschmidt #include <linux/pfn.h> 196d03b885SBenjamin Herrenschmidt #include <linux/debugfs.h> 206d03b885SBenjamin Herrenschmidt #include <linux/seq_file.h> 2195f72d1eSYinghai Lu #include <linux/memblock.h> 2295f72d1eSYinghai Lu 2310d06439SYinghai Lu struct memblock memblock __initdata_memblock; 2495f72d1eSYinghai Lu 2510d06439SYinghai Lu int memblock_debug __initdata_memblock; 2610d06439SYinghai Lu int memblock_can_resize __initdata_memblock; 2710d06439SYinghai Lu static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS + 1] __initdata_memblock; 2810d06439SYinghai Lu static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS + 1] __initdata_memblock; 2995f72d1eSYinghai Lu 30142b45a7SBenjamin Herrenschmidt /* inline so we don't get a warning when pr_debug is compiled out */ 31142b45a7SBenjamin Herrenschmidt static inline const char *memblock_type_name(struct memblock_type *type) 32142b45a7SBenjamin Herrenschmidt { 33142b45a7SBenjamin Herrenschmidt if (type == &memblock.memory) 34142b45a7SBenjamin Herrenschmidt return "memory"; 35142b45a7SBenjamin Herrenschmidt else if (type == &memblock.reserved) 36142b45a7SBenjamin Herrenschmidt return "reserved"; 37142b45a7SBenjamin Herrenschmidt else 38142b45a7SBenjamin Herrenschmidt return "unknown"; 39142b45a7SBenjamin Herrenschmidt } 40142b45a7SBenjamin Herrenschmidt 416ed311b2SBenjamin Herrenschmidt /* 426ed311b2SBenjamin Herrenschmidt * Address comparison utilities 436ed311b2SBenjamin Herrenschmidt */ 446ed311b2SBenjamin Herrenschmidt 4510d06439SYinghai Lu static phys_addr_t __init_memblock memblock_align_down(phys_addr_t addr, phys_addr_t size) 4695f72d1eSYinghai Lu { 476ed311b2SBenjamin Herrenschmidt return addr & ~(size - 1); 4895f72d1eSYinghai Lu } 4995f72d1eSYinghai Lu 5010d06439SYinghai Lu static phys_addr_t __init_memblock memblock_align_up(phys_addr_t addr, phys_addr_t size) 5195f72d1eSYinghai Lu { 526ed311b2SBenjamin Herrenschmidt return (addr + (size - 1)) & ~(size - 1); 5395f72d1eSYinghai Lu } 5495f72d1eSYinghai Lu 5510d06439SYinghai Lu static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1, 562898cc4cSBenjamin Herrenschmidt phys_addr_t base2, phys_addr_t size2) 5795f72d1eSYinghai Lu { 5895f72d1eSYinghai Lu return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 5995f72d1eSYinghai Lu } 6095f72d1eSYinghai Lu 6110d06439SYinghai Lu long __init_memblock memblock_overlaps_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size) 626ed311b2SBenjamin Herrenschmidt { 636ed311b2SBenjamin Herrenschmidt unsigned long i; 646ed311b2SBenjamin Herrenschmidt 656ed311b2SBenjamin Herrenschmidt for (i = 0; i < type->cnt; i++) { 666ed311b2SBenjamin Herrenschmidt phys_addr_t rgnbase = type->regions[i].base; 676ed311b2SBenjamin Herrenschmidt phys_addr_t rgnsize = type->regions[i].size; 686ed311b2SBenjamin Herrenschmidt if (memblock_addrs_overlap(base, size, rgnbase, rgnsize)) 696ed311b2SBenjamin Herrenschmidt break; 706ed311b2SBenjamin Herrenschmidt } 716ed311b2SBenjamin Herrenschmidt 726ed311b2SBenjamin Herrenschmidt return (i < type->cnt) ? i : -1; 736ed311b2SBenjamin Herrenschmidt } 746ed311b2SBenjamin Herrenschmidt 756ed311b2SBenjamin Herrenschmidt /* 766ed311b2SBenjamin Herrenschmidt * Find, allocate, deallocate or reserve unreserved regions. All allocations 776ed311b2SBenjamin Herrenschmidt * are top-down. 786ed311b2SBenjamin Herrenschmidt */ 796ed311b2SBenjamin Herrenschmidt 80cd79481dSYinghai Lu static phys_addr_t __init_memblock memblock_find_region(phys_addr_t start, phys_addr_t end, 816ed311b2SBenjamin Herrenschmidt phys_addr_t size, phys_addr_t align) 826ed311b2SBenjamin Herrenschmidt { 836ed311b2SBenjamin Herrenschmidt phys_addr_t base, res_base; 846ed311b2SBenjamin Herrenschmidt long j; 856ed311b2SBenjamin Herrenschmidt 86f1af98c7SYinghai Lu /* In case, huge size is requested */ 87f1af98c7SYinghai Lu if (end < size) 88f1af98c7SYinghai Lu return MEMBLOCK_ERROR; 89f1af98c7SYinghai Lu 90f1af98c7SYinghai Lu base = memblock_align_down((end - size), align); 91f1af98c7SYinghai Lu 9225818f0fSBenjamin Herrenschmidt /* Prevent allocations returning 0 as it's also used to 9325818f0fSBenjamin Herrenschmidt * indicate an allocation failure 9425818f0fSBenjamin Herrenschmidt */ 9525818f0fSBenjamin Herrenschmidt if (start == 0) 9625818f0fSBenjamin Herrenschmidt start = PAGE_SIZE; 9725818f0fSBenjamin Herrenschmidt 986ed311b2SBenjamin Herrenschmidt while (start <= base) { 996ed311b2SBenjamin Herrenschmidt j = memblock_overlaps_region(&memblock.reserved, base, size); 1006ed311b2SBenjamin Herrenschmidt if (j < 0) 1016ed311b2SBenjamin Herrenschmidt return base; 1026ed311b2SBenjamin Herrenschmidt res_base = memblock.reserved.regions[j].base; 1036ed311b2SBenjamin Herrenschmidt if (res_base < size) 1046ed311b2SBenjamin Herrenschmidt break; 1056ed311b2SBenjamin Herrenschmidt base = memblock_align_down(res_base - size, align); 1066ed311b2SBenjamin Herrenschmidt } 1076ed311b2SBenjamin Herrenschmidt 1086ed311b2SBenjamin Herrenschmidt return MEMBLOCK_ERROR; 1096ed311b2SBenjamin Herrenschmidt } 1106ed311b2SBenjamin Herrenschmidt 1113661ca66SYinghai Lu static phys_addr_t __init_memblock memblock_find_base(phys_addr_t size, 1123661ca66SYinghai Lu phys_addr_t align, phys_addr_t start, phys_addr_t end) 1136ed311b2SBenjamin Herrenschmidt { 1146ed311b2SBenjamin Herrenschmidt long i; 1156ed311b2SBenjamin Herrenschmidt 1166ed311b2SBenjamin Herrenschmidt BUG_ON(0 == size); 1176ed311b2SBenjamin Herrenschmidt 1186ed311b2SBenjamin Herrenschmidt /* Pump up max_addr */ 119fef501d4SBenjamin Herrenschmidt if (end == MEMBLOCK_ALLOC_ACCESSIBLE) 120fef501d4SBenjamin Herrenschmidt end = memblock.current_limit; 1216ed311b2SBenjamin Herrenschmidt 1226ed311b2SBenjamin Herrenschmidt /* We do a top-down search, this tends to limit memory 1236ed311b2SBenjamin Herrenschmidt * fragmentation by keeping early boot allocs near the 1246ed311b2SBenjamin Herrenschmidt * top of memory 1256ed311b2SBenjamin Herrenschmidt */ 1266ed311b2SBenjamin Herrenschmidt for (i = memblock.memory.cnt - 1; i >= 0; i--) { 1276ed311b2SBenjamin Herrenschmidt phys_addr_t memblockbase = memblock.memory.regions[i].base; 1286ed311b2SBenjamin Herrenschmidt phys_addr_t memblocksize = memblock.memory.regions[i].size; 129fef501d4SBenjamin Herrenschmidt phys_addr_t bottom, top, found; 1306ed311b2SBenjamin Herrenschmidt 1316ed311b2SBenjamin Herrenschmidt if (memblocksize < size) 1326ed311b2SBenjamin Herrenschmidt continue; 133fef501d4SBenjamin Herrenschmidt if ((memblockbase + memblocksize) <= start) 134fef501d4SBenjamin Herrenschmidt break; 135fef501d4SBenjamin Herrenschmidt bottom = max(memblockbase, start); 136fef501d4SBenjamin Herrenschmidt top = min(memblockbase + memblocksize, end); 137fef501d4SBenjamin Herrenschmidt if (bottom >= top) 138fef501d4SBenjamin Herrenschmidt continue; 139fef501d4SBenjamin Herrenschmidt found = memblock_find_region(bottom, top, size, align); 140fef501d4SBenjamin Herrenschmidt if (found != MEMBLOCK_ERROR) 141fef501d4SBenjamin Herrenschmidt return found; 1426ed311b2SBenjamin Herrenschmidt } 1436ed311b2SBenjamin Herrenschmidt return MEMBLOCK_ERROR; 1446ed311b2SBenjamin Herrenschmidt } 1456ed311b2SBenjamin Herrenschmidt 1465303b68fSYinghai Lu /* 1475303b68fSYinghai Lu * Find a free area with specified alignment in a specific range. 1485303b68fSYinghai Lu */ 1495303b68fSYinghai Lu u64 __init_memblock memblock_find_in_range(u64 start, u64 end, u64 size, u64 align) 1505303b68fSYinghai Lu { 1515303b68fSYinghai Lu return memblock_find_base(size, align, start, end); 1525303b68fSYinghai Lu } 1535303b68fSYinghai Lu 1547950c407SYinghai Lu /* 1557950c407SYinghai Lu * Free memblock.reserved.regions 1567950c407SYinghai Lu */ 1577950c407SYinghai Lu int __init_memblock memblock_free_reserved_regions(void) 1587950c407SYinghai Lu { 1597950c407SYinghai Lu if (memblock.reserved.regions == memblock_reserved_init_regions) 1607950c407SYinghai Lu return 0; 1617950c407SYinghai Lu 1627950c407SYinghai Lu return memblock_free(__pa(memblock.reserved.regions), 1637950c407SYinghai Lu sizeof(struct memblock_region) * memblock.reserved.max); 1647950c407SYinghai Lu } 1657950c407SYinghai Lu 1667950c407SYinghai Lu /* 1677950c407SYinghai Lu * Reserve memblock.reserved.regions 1687950c407SYinghai Lu */ 1697950c407SYinghai Lu int __init_memblock memblock_reserve_reserved_regions(void) 1707950c407SYinghai Lu { 1717950c407SYinghai Lu if (memblock.reserved.regions == memblock_reserved_init_regions) 1727950c407SYinghai Lu return 0; 1737950c407SYinghai Lu 1747950c407SYinghai Lu return memblock_reserve(__pa(memblock.reserved.regions), 1757950c407SYinghai Lu sizeof(struct memblock_region) * memblock.reserved.max); 1767950c407SYinghai Lu } 1777950c407SYinghai Lu 17810d06439SYinghai Lu static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) 17995f72d1eSYinghai Lu { 18095f72d1eSYinghai Lu unsigned long i; 18195f72d1eSYinghai Lu 182e3239ff9SBenjamin Herrenschmidt for (i = r; i < type->cnt - 1; i++) { 183e3239ff9SBenjamin Herrenschmidt type->regions[i].base = type->regions[i + 1].base; 184e3239ff9SBenjamin Herrenschmidt type->regions[i].size = type->regions[i + 1].size; 18595f72d1eSYinghai Lu } 186e3239ff9SBenjamin Herrenschmidt type->cnt--; 18795f72d1eSYinghai Lu 1888f7a6605SBenjamin Herrenschmidt /* Special case for empty arrays */ 1898f7a6605SBenjamin Herrenschmidt if (type->cnt == 0) { 1908f7a6605SBenjamin Herrenschmidt type->cnt = 1; 1918f7a6605SBenjamin Herrenschmidt type->regions[0].base = 0; 1928f7a6605SBenjamin Herrenschmidt type->regions[0].size = 0; 1938f7a6605SBenjamin Herrenschmidt } 19495f72d1eSYinghai Lu } 19595f72d1eSYinghai Lu 196142b45a7SBenjamin Herrenschmidt /* Defined below but needed now */ 197142b45a7SBenjamin Herrenschmidt static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size); 198142b45a7SBenjamin Herrenschmidt 19910d06439SYinghai Lu static int __init_memblock memblock_double_array(struct memblock_type *type) 200142b45a7SBenjamin Herrenschmidt { 201142b45a7SBenjamin Herrenschmidt struct memblock_region *new_array, *old_array; 202142b45a7SBenjamin Herrenschmidt phys_addr_t old_size, new_size, addr; 203142b45a7SBenjamin Herrenschmidt int use_slab = slab_is_available(); 204142b45a7SBenjamin Herrenschmidt 205142b45a7SBenjamin Herrenschmidt /* We don't allow resizing until we know about the reserved regions 206142b45a7SBenjamin Herrenschmidt * of memory that aren't suitable for allocation 207142b45a7SBenjamin Herrenschmidt */ 208142b45a7SBenjamin Herrenschmidt if (!memblock_can_resize) 209142b45a7SBenjamin Herrenschmidt return -1; 210142b45a7SBenjamin Herrenschmidt 211142b45a7SBenjamin Herrenschmidt /* Calculate new doubled size */ 212142b45a7SBenjamin Herrenschmidt old_size = type->max * sizeof(struct memblock_region); 213142b45a7SBenjamin Herrenschmidt new_size = old_size << 1; 214142b45a7SBenjamin Herrenschmidt 215142b45a7SBenjamin Herrenschmidt /* Try to find some space for it. 216142b45a7SBenjamin Herrenschmidt * 217142b45a7SBenjamin Herrenschmidt * WARNING: We assume that either slab_is_available() and we use it or 218142b45a7SBenjamin Herrenschmidt * we use MEMBLOCK for allocations. That means that this is unsafe to use 219142b45a7SBenjamin Herrenschmidt * when bootmem is currently active (unless bootmem itself is implemented 220142b45a7SBenjamin Herrenschmidt * on top of MEMBLOCK which isn't the case yet) 221142b45a7SBenjamin Herrenschmidt * 222142b45a7SBenjamin Herrenschmidt * This should however not be an issue for now, as we currently only 223142b45a7SBenjamin Herrenschmidt * call into MEMBLOCK while it's still active, or much later when slab is 224142b45a7SBenjamin Herrenschmidt * active for memory hotplug operations 225142b45a7SBenjamin Herrenschmidt */ 226142b45a7SBenjamin Herrenschmidt if (use_slab) { 227142b45a7SBenjamin Herrenschmidt new_array = kmalloc(new_size, GFP_KERNEL); 228142b45a7SBenjamin Herrenschmidt addr = new_array == NULL ? MEMBLOCK_ERROR : __pa(new_array); 229142b45a7SBenjamin Herrenschmidt } else 230fef501d4SBenjamin Herrenschmidt addr = memblock_find_base(new_size, sizeof(phys_addr_t), 0, MEMBLOCK_ALLOC_ACCESSIBLE); 231142b45a7SBenjamin Herrenschmidt if (addr == MEMBLOCK_ERROR) { 232142b45a7SBenjamin Herrenschmidt pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", 233142b45a7SBenjamin Herrenschmidt memblock_type_name(type), type->max, type->max * 2); 234142b45a7SBenjamin Herrenschmidt return -1; 235142b45a7SBenjamin Herrenschmidt } 236142b45a7SBenjamin Herrenschmidt new_array = __va(addr); 237142b45a7SBenjamin Herrenschmidt 238ea9e4376SYinghai Lu memblock_dbg("memblock: %s array is doubled to %ld at [%#010llx-%#010llx]", 239ea9e4376SYinghai Lu memblock_type_name(type), type->max * 2, (u64)addr, (u64)addr + new_size - 1); 240ea9e4376SYinghai Lu 241142b45a7SBenjamin Herrenschmidt /* Found space, we now need to move the array over before 242142b45a7SBenjamin Herrenschmidt * we add the reserved region since it may be our reserved 243142b45a7SBenjamin Herrenschmidt * array itself that is full. 244142b45a7SBenjamin Herrenschmidt */ 245142b45a7SBenjamin Herrenschmidt memcpy(new_array, type->regions, old_size); 246142b45a7SBenjamin Herrenschmidt memset(new_array + type->max, 0, old_size); 247142b45a7SBenjamin Herrenschmidt old_array = type->regions; 248142b45a7SBenjamin Herrenschmidt type->regions = new_array; 249142b45a7SBenjamin Herrenschmidt type->max <<= 1; 250142b45a7SBenjamin Herrenschmidt 251142b45a7SBenjamin Herrenschmidt /* If we use SLAB that's it, we are done */ 252142b45a7SBenjamin Herrenschmidt if (use_slab) 253142b45a7SBenjamin Herrenschmidt return 0; 254142b45a7SBenjamin Herrenschmidt 255142b45a7SBenjamin Herrenschmidt /* Add the new reserved region now. Should not fail ! */ 2568f7a6605SBenjamin Herrenschmidt BUG_ON(memblock_add_region(&memblock.reserved, addr, new_size)); 257142b45a7SBenjamin Herrenschmidt 258142b45a7SBenjamin Herrenschmidt /* If the array wasn't our static init one, then free it. We only do 259142b45a7SBenjamin Herrenschmidt * that before SLAB is available as later on, we don't know whether 260142b45a7SBenjamin Herrenschmidt * to use kfree or free_bootmem_pages(). Shouldn't be a big deal 261142b45a7SBenjamin Herrenschmidt * anyways 262142b45a7SBenjamin Herrenschmidt */ 263142b45a7SBenjamin Herrenschmidt if (old_array != memblock_memory_init_regions && 264142b45a7SBenjamin Herrenschmidt old_array != memblock_reserved_init_regions) 265142b45a7SBenjamin Herrenschmidt memblock_free(__pa(old_array), old_size); 266142b45a7SBenjamin Herrenschmidt 267142b45a7SBenjamin Herrenschmidt return 0; 268142b45a7SBenjamin Herrenschmidt } 269142b45a7SBenjamin Herrenschmidt 27010d06439SYinghai Lu extern int __init_memblock __weak memblock_memory_can_coalesce(phys_addr_t addr1, phys_addr_t size1, 271d2cd563bSBenjamin Herrenschmidt phys_addr_t addr2, phys_addr_t size2) 272d2cd563bSBenjamin Herrenschmidt { 273d2cd563bSBenjamin Herrenschmidt return 1; 274d2cd563bSBenjamin Herrenschmidt } 275d2cd563bSBenjamin Herrenschmidt 2768f7a6605SBenjamin Herrenschmidt static long __init_memblock memblock_add_region(struct memblock_type *type, 2778f7a6605SBenjamin Herrenschmidt phys_addr_t base, phys_addr_t size) 27895f72d1eSYinghai Lu { 2798f7a6605SBenjamin Herrenschmidt phys_addr_t end = base + size; 2808f7a6605SBenjamin Herrenschmidt int i, slot = -1; 28195f72d1eSYinghai Lu 2828f7a6605SBenjamin Herrenschmidt /* First try and coalesce this MEMBLOCK with others */ 2838f7a6605SBenjamin Herrenschmidt for (i = 0; i < type->cnt; i++) { 2848f7a6605SBenjamin Herrenschmidt struct memblock_region *rgn = &type->regions[i]; 2858f7a6605SBenjamin Herrenschmidt phys_addr_t rend = rgn->base + rgn->size; 2868f7a6605SBenjamin Herrenschmidt 2878f7a6605SBenjamin Herrenschmidt /* Exit if there's no possible hits */ 2888f7a6605SBenjamin Herrenschmidt if (rgn->base > end || rgn->size == 0) 2898f7a6605SBenjamin Herrenschmidt break; 2908f7a6605SBenjamin Herrenschmidt 2918f7a6605SBenjamin Herrenschmidt /* Check if we are fully enclosed within an existing 2928f7a6605SBenjamin Herrenschmidt * block 2938f7a6605SBenjamin Herrenschmidt */ 2948f7a6605SBenjamin Herrenschmidt if (rgn->base <= base && rend >= end) 2958f7a6605SBenjamin Herrenschmidt return 0; 2968f7a6605SBenjamin Herrenschmidt 2978f7a6605SBenjamin Herrenschmidt /* Check if we overlap or are adjacent with the bottom 2988f7a6605SBenjamin Herrenschmidt * of a block. 2998f7a6605SBenjamin Herrenschmidt */ 3008f7a6605SBenjamin Herrenschmidt if (base < rgn->base && end >= rgn->base) { 3018f7a6605SBenjamin Herrenschmidt /* If we can't coalesce, create a new block */ 3028f7a6605SBenjamin Herrenschmidt if (!memblock_memory_can_coalesce(base, size, 3038f7a6605SBenjamin Herrenschmidt rgn->base, 3048f7a6605SBenjamin Herrenschmidt rgn->size)) { 3058f7a6605SBenjamin Herrenschmidt /* Overlap & can't coalesce are mutually 3068f7a6605SBenjamin Herrenschmidt * exclusive, if you do that, be prepared 3078f7a6605SBenjamin Herrenschmidt * for trouble 3088f7a6605SBenjamin Herrenschmidt */ 3098f7a6605SBenjamin Herrenschmidt WARN_ON(end != rgn->base); 3108f7a6605SBenjamin Herrenschmidt goto new_block; 3118f7a6605SBenjamin Herrenschmidt } 3128f7a6605SBenjamin Herrenschmidt /* We extend the bottom of the block down to our 3138f7a6605SBenjamin Herrenschmidt * base 3148f7a6605SBenjamin Herrenschmidt */ 3158f7a6605SBenjamin Herrenschmidt rgn->base = base; 3168f7a6605SBenjamin Herrenschmidt rgn->size = rend - base; 3178f7a6605SBenjamin Herrenschmidt 3188f7a6605SBenjamin Herrenschmidt /* Return if we have nothing else to allocate 3198f7a6605SBenjamin Herrenschmidt * (fully coalesced) 3208f7a6605SBenjamin Herrenschmidt */ 3218f7a6605SBenjamin Herrenschmidt if (rend >= end) 3228f7a6605SBenjamin Herrenschmidt return 0; 3238f7a6605SBenjamin Herrenschmidt 3248f7a6605SBenjamin Herrenschmidt /* We continue processing from the end of the 3258f7a6605SBenjamin Herrenschmidt * coalesced block. 3268f7a6605SBenjamin Herrenschmidt */ 3278f7a6605SBenjamin Herrenschmidt base = rend; 3288f7a6605SBenjamin Herrenschmidt size = end - base; 3298f7a6605SBenjamin Herrenschmidt } 3308f7a6605SBenjamin Herrenschmidt 3318f7a6605SBenjamin Herrenschmidt /* Now check if we overlap or are adjacent with the 3328f7a6605SBenjamin Herrenschmidt * top of a block 3338f7a6605SBenjamin Herrenschmidt */ 3348f7a6605SBenjamin Herrenschmidt if (base <= rend && end >= rend) { 3358f7a6605SBenjamin Herrenschmidt /* If we can't coalesce, create a new block */ 3368f7a6605SBenjamin Herrenschmidt if (!memblock_memory_can_coalesce(rgn->base, 3378f7a6605SBenjamin Herrenschmidt rgn->size, 3388f7a6605SBenjamin Herrenschmidt base, size)) { 3398f7a6605SBenjamin Herrenschmidt /* Overlap & can't coalesce are mutually 3408f7a6605SBenjamin Herrenschmidt * exclusive, if you do that, be prepared 3418f7a6605SBenjamin Herrenschmidt * for trouble 3428f7a6605SBenjamin Herrenschmidt */ 3438f7a6605SBenjamin Herrenschmidt WARN_ON(rend != base); 3448f7a6605SBenjamin Herrenschmidt goto new_block; 3458f7a6605SBenjamin Herrenschmidt } 3468f7a6605SBenjamin Herrenschmidt /* We adjust our base down to enclose the 3478f7a6605SBenjamin Herrenschmidt * original block and destroy it. It will be 3488f7a6605SBenjamin Herrenschmidt * part of our new allocation. Since we've 3498f7a6605SBenjamin Herrenschmidt * freed an entry, we know we won't fail 3508f7a6605SBenjamin Herrenschmidt * to allocate one later, so we won't risk 3518f7a6605SBenjamin Herrenschmidt * losing the original block allocation. 3528f7a6605SBenjamin Herrenschmidt */ 3538f7a6605SBenjamin Herrenschmidt size += (base - rgn->base); 3548f7a6605SBenjamin Herrenschmidt base = rgn->base; 3558f7a6605SBenjamin Herrenschmidt memblock_remove_region(type, i--); 3568f7a6605SBenjamin Herrenschmidt } 3578f7a6605SBenjamin Herrenschmidt } 3588f7a6605SBenjamin Herrenschmidt 3598f7a6605SBenjamin Herrenschmidt /* If the array is empty, special case, replace the fake 3608f7a6605SBenjamin Herrenschmidt * filler region and return 3618f7a6605SBenjamin Herrenschmidt */ 362e3239ff9SBenjamin Herrenschmidt if ((type->cnt == 1) && (type->regions[0].size == 0)) { 363e3239ff9SBenjamin Herrenschmidt type->regions[0].base = base; 364e3239ff9SBenjamin Herrenschmidt type->regions[0].size = size; 36595f72d1eSYinghai Lu return 0; 36695f72d1eSYinghai Lu } 36795f72d1eSYinghai Lu 3688f7a6605SBenjamin Herrenschmidt new_block: 369142b45a7SBenjamin Herrenschmidt /* If we are out of space, we fail. It's too late to resize the array 370142b45a7SBenjamin Herrenschmidt * but then this shouldn't have happened in the first place. 371142b45a7SBenjamin Herrenschmidt */ 372142b45a7SBenjamin Herrenschmidt if (WARN_ON(type->cnt >= type->max)) 37395f72d1eSYinghai Lu return -1; 37495f72d1eSYinghai Lu 37595f72d1eSYinghai Lu /* Couldn't coalesce the MEMBLOCK, so add it to the sorted table. */ 376e3239ff9SBenjamin Herrenschmidt for (i = type->cnt - 1; i >= 0; i--) { 377e3239ff9SBenjamin Herrenschmidt if (base < type->regions[i].base) { 378e3239ff9SBenjamin Herrenschmidt type->regions[i+1].base = type->regions[i].base; 379e3239ff9SBenjamin Herrenschmidt type->regions[i+1].size = type->regions[i].size; 38095f72d1eSYinghai Lu } else { 381e3239ff9SBenjamin Herrenschmidt type->regions[i+1].base = base; 382e3239ff9SBenjamin Herrenschmidt type->regions[i+1].size = size; 3838f7a6605SBenjamin Herrenschmidt slot = i + 1; 38495f72d1eSYinghai Lu break; 38595f72d1eSYinghai Lu } 38695f72d1eSYinghai Lu } 387e3239ff9SBenjamin Herrenschmidt if (base < type->regions[0].base) { 388e3239ff9SBenjamin Herrenschmidt type->regions[0].base = base; 389e3239ff9SBenjamin Herrenschmidt type->regions[0].size = size; 3908f7a6605SBenjamin Herrenschmidt slot = 0; 39195f72d1eSYinghai Lu } 392e3239ff9SBenjamin Herrenschmidt type->cnt++; 39395f72d1eSYinghai Lu 394142b45a7SBenjamin Herrenschmidt /* The array is full ? Try to resize it. If that fails, we undo 395142b45a7SBenjamin Herrenschmidt * our allocation and return an error 396142b45a7SBenjamin Herrenschmidt */ 397142b45a7SBenjamin Herrenschmidt if (type->cnt == type->max && memblock_double_array(type)) { 3988f7a6605SBenjamin Herrenschmidt BUG_ON(slot < 0); 3998f7a6605SBenjamin Herrenschmidt memblock_remove_region(type, slot); 400142b45a7SBenjamin Herrenschmidt return -1; 401142b45a7SBenjamin Herrenschmidt } 402142b45a7SBenjamin Herrenschmidt 40395f72d1eSYinghai Lu return 0; 40495f72d1eSYinghai Lu } 40595f72d1eSYinghai Lu 40610d06439SYinghai Lu long __init_memblock memblock_add(phys_addr_t base, phys_addr_t size) 40795f72d1eSYinghai Lu { 408e3239ff9SBenjamin Herrenschmidt return memblock_add_region(&memblock.memory, base, size); 40995f72d1eSYinghai Lu 41095f72d1eSYinghai Lu } 41195f72d1eSYinghai Lu 4128f7a6605SBenjamin Herrenschmidt static long __init_memblock __memblock_remove(struct memblock_type *type, 4138f7a6605SBenjamin Herrenschmidt phys_addr_t base, phys_addr_t size) 41495f72d1eSYinghai Lu { 4152898cc4cSBenjamin Herrenschmidt phys_addr_t end = base + size; 41695f72d1eSYinghai Lu int i; 41795f72d1eSYinghai Lu 4188f7a6605SBenjamin Herrenschmidt /* Walk through the array for collisions */ 419e3239ff9SBenjamin Herrenschmidt for (i = 0; i < type->cnt; i++) { 4208f7a6605SBenjamin Herrenschmidt struct memblock_region *rgn = &type->regions[i]; 4218f7a6605SBenjamin Herrenschmidt phys_addr_t rend = rgn->base + rgn->size; 42295f72d1eSYinghai Lu 4238f7a6605SBenjamin Herrenschmidt /* Nothing more to do, exit */ 4248f7a6605SBenjamin Herrenschmidt if (rgn->base > end || rgn->size == 0) 4258f7a6605SBenjamin Herrenschmidt break; 4268f7a6605SBenjamin Herrenschmidt 4278f7a6605SBenjamin Herrenschmidt /* If we fully enclose the block, drop it */ 4288f7a6605SBenjamin Herrenschmidt if (base <= rgn->base && end >= rend) { 4298f7a6605SBenjamin Herrenschmidt memblock_remove_region(type, i--); 4308f7a6605SBenjamin Herrenschmidt continue; 4318f7a6605SBenjamin Herrenschmidt } 4328f7a6605SBenjamin Herrenschmidt 4338f7a6605SBenjamin Herrenschmidt /* If we are fully enclosed within a block 4348f7a6605SBenjamin Herrenschmidt * then we need to split it and we are done 4358f7a6605SBenjamin Herrenschmidt */ 4368f7a6605SBenjamin Herrenschmidt if (base > rgn->base && end < rend) { 4378f7a6605SBenjamin Herrenschmidt rgn->size = base - rgn->base; 4388f7a6605SBenjamin Herrenschmidt if (!memblock_add_region(type, end, rend - end)) 4398f7a6605SBenjamin Herrenschmidt return 0; 4408f7a6605SBenjamin Herrenschmidt /* Failure to split is bad, we at least 4418f7a6605SBenjamin Herrenschmidt * restore the block before erroring 4428f7a6605SBenjamin Herrenschmidt */ 4438f7a6605SBenjamin Herrenschmidt rgn->size = rend - rgn->base; 4448f7a6605SBenjamin Herrenschmidt WARN_ON(1); 4458f7a6605SBenjamin Herrenschmidt return -1; 4468f7a6605SBenjamin Herrenschmidt } 4478f7a6605SBenjamin Herrenschmidt 4488f7a6605SBenjamin Herrenschmidt /* Check if we need to trim the bottom of a block */ 4498f7a6605SBenjamin Herrenschmidt if (rgn->base < end && rend > end) { 4508f7a6605SBenjamin Herrenschmidt rgn->size -= end - rgn->base; 4518f7a6605SBenjamin Herrenschmidt rgn->base = end; 45295f72d1eSYinghai Lu break; 45395f72d1eSYinghai Lu } 45495f72d1eSYinghai Lu 4558f7a6605SBenjamin Herrenschmidt /* And check if we need to trim the top of a block */ 4568f7a6605SBenjamin Herrenschmidt if (base < rend) 4578f7a6605SBenjamin Herrenschmidt rgn->size -= rend - base; 45895f72d1eSYinghai Lu 45995f72d1eSYinghai Lu } 46095f72d1eSYinghai Lu return 0; 46195f72d1eSYinghai Lu } 46295f72d1eSYinghai Lu 46310d06439SYinghai Lu long __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size) 46495f72d1eSYinghai Lu { 46595f72d1eSYinghai Lu return __memblock_remove(&memblock.memory, base, size); 46695f72d1eSYinghai Lu } 46795f72d1eSYinghai Lu 4683661ca66SYinghai Lu long __init_memblock memblock_free(phys_addr_t base, phys_addr_t size) 46995f72d1eSYinghai Lu { 47095f72d1eSYinghai Lu return __memblock_remove(&memblock.reserved, base, size); 47195f72d1eSYinghai Lu } 47295f72d1eSYinghai Lu 4733661ca66SYinghai Lu long __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) 47495f72d1eSYinghai Lu { 475e3239ff9SBenjamin Herrenschmidt struct memblock_type *_rgn = &memblock.reserved; 47695f72d1eSYinghai Lu 47795f72d1eSYinghai Lu BUG_ON(0 == size); 47895f72d1eSYinghai Lu 47995f72d1eSYinghai Lu return memblock_add_region(_rgn, base, size); 48095f72d1eSYinghai Lu } 48195f72d1eSYinghai Lu 4826ed311b2SBenjamin Herrenschmidt phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr) 48395f72d1eSYinghai Lu { 4846ed311b2SBenjamin Herrenschmidt phys_addr_t found; 48595f72d1eSYinghai Lu 4866ed311b2SBenjamin Herrenschmidt /* We align the size to limit fragmentation. Without this, a lot of 4876ed311b2SBenjamin Herrenschmidt * small allocs quickly eat up the whole reserve array on sparc 4886ed311b2SBenjamin Herrenschmidt */ 4896ed311b2SBenjamin Herrenschmidt size = memblock_align_up(size, align); 4906ed311b2SBenjamin Herrenschmidt 491fef501d4SBenjamin Herrenschmidt found = memblock_find_base(size, align, 0, max_addr); 4926ed311b2SBenjamin Herrenschmidt if (found != MEMBLOCK_ERROR && 4938f7a6605SBenjamin Herrenschmidt !memblock_add_region(&memblock.reserved, found, size)) 4946ed311b2SBenjamin Herrenschmidt return found; 4956ed311b2SBenjamin Herrenschmidt 4966ed311b2SBenjamin Herrenschmidt return 0; 49795f72d1eSYinghai Lu } 49895f72d1eSYinghai Lu 4996ed311b2SBenjamin Herrenschmidt phys_addr_t __init memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr) 50095f72d1eSYinghai Lu { 5016ed311b2SBenjamin Herrenschmidt phys_addr_t alloc; 5026ed311b2SBenjamin Herrenschmidt 5036ed311b2SBenjamin Herrenschmidt alloc = __memblock_alloc_base(size, align, max_addr); 5046ed311b2SBenjamin Herrenschmidt 5056ed311b2SBenjamin Herrenschmidt if (alloc == 0) 5066ed311b2SBenjamin Herrenschmidt panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n", 5076ed311b2SBenjamin Herrenschmidt (unsigned long long) size, (unsigned long long) max_addr); 5086ed311b2SBenjamin Herrenschmidt 5096ed311b2SBenjamin Herrenschmidt return alloc; 51095f72d1eSYinghai Lu } 51195f72d1eSYinghai Lu 5126ed311b2SBenjamin Herrenschmidt phys_addr_t __init memblock_alloc(phys_addr_t size, phys_addr_t align) 51395f72d1eSYinghai Lu { 5146ed311b2SBenjamin Herrenschmidt return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE); 51595f72d1eSYinghai Lu } 51695f72d1eSYinghai Lu 51795f72d1eSYinghai Lu 5186ed311b2SBenjamin Herrenschmidt /* 5196ed311b2SBenjamin Herrenschmidt * Additional node-local allocators. Search for node memory is bottom up 5206ed311b2SBenjamin Herrenschmidt * and walks memblock regions within that node bottom-up as well, but allocation 521c196f76fSBenjamin Herrenschmidt * within an memblock region is top-down. XXX I plan to fix that at some stage 522c196f76fSBenjamin Herrenschmidt * 523c196f76fSBenjamin Herrenschmidt * WARNING: Only available after early_node_map[] has been populated, 524c196f76fSBenjamin Herrenschmidt * on some architectures, that is after all the calls to add_active_range() 525c196f76fSBenjamin Herrenschmidt * have been done to populate it. 5266ed311b2SBenjamin Herrenschmidt */ 52795f72d1eSYinghai Lu 5282898cc4cSBenjamin Herrenschmidt phys_addr_t __weak __init memblock_nid_range(phys_addr_t start, phys_addr_t end, int *nid) 529c3f72b57SBenjamin Herrenschmidt { 530c196f76fSBenjamin Herrenschmidt #ifdef CONFIG_ARCH_POPULATES_NODE_MAP 531c196f76fSBenjamin Herrenschmidt /* 532c196f76fSBenjamin Herrenschmidt * This code originates from sparc which really wants use to walk by addresses 533c196f76fSBenjamin Herrenschmidt * and returns the nid. This is not very convenient for early_pfn_map[] users 534c196f76fSBenjamin Herrenschmidt * as the map isn't sorted yet, and it really wants to be walked by nid. 535c196f76fSBenjamin Herrenschmidt * 536c196f76fSBenjamin Herrenschmidt * For now, I implement the inefficient method below which walks the early 537c196f76fSBenjamin Herrenschmidt * map multiple times. Eventually we may want to use an ARCH config option 538c196f76fSBenjamin Herrenschmidt * to implement a completely different method for both case. 539c196f76fSBenjamin Herrenschmidt */ 540c196f76fSBenjamin Herrenschmidt unsigned long start_pfn, end_pfn; 541c196f76fSBenjamin Herrenschmidt int i; 542c196f76fSBenjamin Herrenschmidt 543c196f76fSBenjamin Herrenschmidt for (i = 0; i < MAX_NUMNODES; i++) { 544c196f76fSBenjamin Herrenschmidt get_pfn_range_for_nid(i, &start_pfn, &end_pfn); 545c196f76fSBenjamin Herrenschmidt if (start < PFN_PHYS(start_pfn) || start >= PFN_PHYS(end_pfn)) 546c196f76fSBenjamin Herrenschmidt continue; 547c196f76fSBenjamin Herrenschmidt *nid = i; 548c196f76fSBenjamin Herrenschmidt return min(end, PFN_PHYS(end_pfn)); 549c196f76fSBenjamin Herrenschmidt } 550c196f76fSBenjamin Herrenschmidt #endif 551c3f72b57SBenjamin Herrenschmidt *nid = 0; 552c3f72b57SBenjamin Herrenschmidt 553c3f72b57SBenjamin Herrenschmidt return end; 554c3f72b57SBenjamin Herrenschmidt } 555c3f72b57SBenjamin Herrenschmidt 5562898cc4cSBenjamin Herrenschmidt static phys_addr_t __init memblock_alloc_nid_region(struct memblock_region *mp, 5572898cc4cSBenjamin Herrenschmidt phys_addr_t size, 5582898cc4cSBenjamin Herrenschmidt phys_addr_t align, int nid) 55995f72d1eSYinghai Lu { 5602898cc4cSBenjamin Herrenschmidt phys_addr_t start, end; 56195f72d1eSYinghai Lu 56295f72d1eSYinghai Lu start = mp->base; 56395f72d1eSYinghai Lu end = start + mp->size; 56495f72d1eSYinghai Lu 56595f72d1eSYinghai Lu start = memblock_align_up(start, align); 56695f72d1eSYinghai Lu while (start < end) { 5672898cc4cSBenjamin Herrenschmidt phys_addr_t this_end; 56895f72d1eSYinghai Lu int this_nid; 56995f72d1eSYinghai Lu 57035a1f0bdSBenjamin Herrenschmidt this_end = memblock_nid_range(start, end, &this_nid); 57195f72d1eSYinghai Lu if (this_nid == nid) { 5723a9c2c81SBenjamin Herrenschmidt phys_addr_t ret = memblock_find_region(start, this_end, size, align); 5734d629f9aSBenjamin Herrenschmidt if (ret != MEMBLOCK_ERROR && 5748f7a6605SBenjamin Herrenschmidt !memblock_add_region(&memblock.reserved, ret, size)) 57595f72d1eSYinghai Lu return ret; 57695f72d1eSYinghai Lu } 57795f72d1eSYinghai Lu start = this_end; 57895f72d1eSYinghai Lu } 57995f72d1eSYinghai Lu 5804d629f9aSBenjamin Herrenschmidt return MEMBLOCK_ERROR; 58195f72d1eSYinghai Lu } 58295f72d1eSYinghai Lu 5832898cc4cSBenjamin Herrenschmidt phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid) 58495f72d1eSYinghai Lu { 585e3239ff9SBenjamin Herrenschmidt struct memblock_type *mem = &memblock.memory; 58695f72d1eSYinghai Lu int i; 58795f72d1eSYinghai Lu 58895f72d1eSYinghai Lu BUG_ON(0 == size); 58995f72d1eSYinghai Lu 5907f219c73SBenjamin Herrenschmidt /* We align the size to limit fragmentation. Without this, a lot of 5917f219c73SBenjamin Herrenschmidt * small allocs quickly eat up the whole reserve array on sparc 5927f219c73SBenjamin Herrenschmidt */ 5937f219c73SBenjamin Herrenschmidt size = memblock_align_up(size, align); 5947f219c73SBenjamin Herrenschmidt 595c3f72b57SBenjamin Herrenschmidt /* We do a bottom-up search for a region with the right 596c3f72b57SBenjamin Herrenschmidt * nid since that's easier considering how memblock_nid_range() 597c3f72b57SBenjamin Herrenschmidt * works 598c3f72b57SBenjamin Herrenschmidt */ 59995f72d1eSYinghai Lu for (i = 0; i < mem->cnt; i++) { 6002898cc4cSBenjamin Herrenschmidt phys_addr_t ret = memblock_alloc_nid_region(&mem->regions[i], 60195f72d1eSYinghai Lu size, align, nid); 6024d629f9aSBenjamin Herrenschmidt if (ret != MEMBLOCK_ERROR) 60395f72d1eSYinghai Lu return ret; 60495f72d1eSYinghai Lu } 60595f72d1eSYinghai Lu 6069d1e2492SBenjamin Herrenschmidt return 0; 6079d1e2492SBenjamin Herrenschmidt } 6089d1e2492SBenjamin Herrenschmidt 6099d1e2492SBenjamin Herrenschmidt phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid) 6109d1e2492SBenjamin Herrenschmidt { 6119d1e2492SBenjamin Herrenschmidt phys_addr_t res = memblock_alloc_nid(size, align, nid); 6129d1e2492SBenjamin Herrenschmidt 6139d1e2492SBenjamin Herrenschmidt if (res) 6149d1e2492SBenjamin Herrenschmidt return res; 615918fe8d6SBenjamin Herrenschmidt return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ANYWHERE); 61695f72d1eSYinghai Lu } 61795f72d1eSYinghai Lu 6189d1e2492SBenjamin Herrenschmidt 6199d1e2492SBenjamin Herrenschmidt /* 6209d1e2492SBenjamin Herrenschmidt * Remaining API functions 6219d1e2492SBenjamin Herrenschmidt */ 6229d1e2492SBenjamin Herrenschmidt 62395f72d1eSYinghai Lu /* You must call memblock_analyze() before this. */ 6242898cc4cSBenjamin Herrenschmidt phys_addr_t __init memblock_phys_mem_size(void) 62595f72d1eSYinghai Lu { 6264734b594SBenjamin Herrenschmidt return memblock.memory_size; 62795f72d1eSYinghai Lu } 62895f72d1eSYinghai Lu 629*0a93ebefSSam Ravnborg /* lowest address */ 630*0a93ebefSSam Ravnborg phys_addr_t __init_memblock memblock_start_of_DRAM(void) 631*0a93ebefSSam Ravnborg { 632*0a93ebefSSam Ravnborg return memblock.memory.regions[0].base; 633*0a93ebefSSam Ravnborg } 634*0a93ebefSSam Ravnborg 63510d06439SYinghai Lu phys_addr_t __init_memblock memblock_end_of_DRAM(void) 63695f72d1eSYinghai Lu { 63795f72d1eSYinghai Lu int idx = memblock.memory.cnt - 1; 63895f72d1eSYinghai Lu 639e3239ff9SBenjamin Herrenschmidt return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size); 64095f72d1eSYinghai Lu } 64195f72d1eSYinghai Lu 64295f72d1eSYinghai Lu /* You must call memblock_analyze() after this. */ 6432898cc4cSBenjamin Herrenschmidt void __init memblock_enforce_memory_limit(phys_addr_t memory_limit) 64495f72d1eSYinghai Lu { 64595f72d1eSYinghai Lu unsigned long i; 6462898cc4cSBenjamin Herrenschmidt phys_addr_t limit; 647e3239ff9SBenjamin Herrenschmidt struct memblock_region *p; 64895f72d1eSYinghai Lu 64995f72d1eSYinghai Lu if (!memory_limit) 65095f72d1eSYinghai Lu return; 65195f72d1eSYinghai Lu 65295f72d1eSYinghai Lu /* Truncate the memblock regions to satisfy the memory limit. */ 65395f72d1eSYinghai Lu limit = memory_limit; 65495f72d1eSYinghai Lu for (i = 0; i < memblock.memory.cnt; i++) { 655e3239ff9SBenjamin Herrenschmidt if (limit > memblock.memory.regions[i].size) { 656e3239ff9SBenjamin Herrenschmidt limit -= memblock.memory.regions[i].size; 65795f72d1eSYinghai Lu continue; 65895f72d1eSYinghai Lu } 65995f72d1eSYinghai Lu 660e3239ff9SBenjamin Herrenschmidt memblock.memory.regions[i].size = limit; 66195f72d1eSYinghai Lu memblock.memory.cnt = i + 1; 66295f72d1eSYinghai Lu break; 66395f72d1eSYinghai Lu } 66495f72d1eSYinghai Lu 66595f72d1eSYinghai Lu memory_limit = memblock_end_of_DRAM(); 66695f72d1eSYinghai Lu 66795f72d1eSYinghai Lu /* And truncate any reserves above the limit also. */ 66895f72d1eSYinghai Lu for (i = 0; i < memblock.reserved.cnt; i++) { 669e3239ff9SBenjamin Herrenschmidt p = &memblock.reserved.regions[i]; 67095f72d1eSYinghai Lu 67195f72d1eSYinghai Lu if (p->base > memory_limit) 67295f72d1eSYinghai Lu p->size = 0; 67395f72d1eSYinghai Lu else if ((p->base + p->size) > memory_limit) 67495f72d1eSYinghai Lu p->size = memory_limit - p->base; 67595f72d1eSYinghai Lu 67695f72d1eSYinghai Lu if (p->size == 0) { 67795f72d1eSYinghai Lu memblock_remove_region(&memblock.reserved, i); 67895f72d1eSYinghai Lu i--; 67995f72d1eSYinghai Lu } 68095f72d1eSYinghai Lu } 68195f72d1eSYinghai Lu } 68295f72d1eSYinghai Lu 683cd79481dSYinghai Lu static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) 68472d4b0b4SBenjamin Herrenschmidt { 68572d4b0b4SBenjamin Herrenschmidt unsigned int left = 0, right = type->cnt; 68672d4b0b4SBenjamin Herrenschmidt 68772d4b0b4SBenjamin Herrenschmidt do { 68872d4b0b4SBenjamin Herrenschmidt unsigned int mid = (right + left) / 2; 68972d4b0b4SBenjamin Herrenschmidt 69072d4b0b4SBenjamin Herrenschmidt if (addr < type->regions[mid].base) 69172d4b0b4SBenjamin Herrenschmidt right = mid; 69272d4b0b4SBenjamin Herrenschmidt else if (addr >= (type->regions[mid].base + 69372d4b0b4SBenjamin Herrenschmidt type->regions[mid].size)) 69472d4b0b4SBenjamin Herrenschmidt left = mid + 1; 69572d4b0b4SBenjamin Herrenschmidt else 69672d4b0b4SBenjamin Herrenschmidt return mid; 69772d4b0b4SBenjamin Herrenschmidt } while (left < right); 69872d4b0b4SBenjamin Herrenschmidt return -1; 69972d4b0b4SBenjamin Herrenschmidt } 70072d4b0b4SBenjamin Herrenschmidt 7012898cc4cSBenjamin Herrenschmidt int __init memblock_is_reserved(phys_addr_t addr) 70295f72d1eSYinghai Lu { 70372d4b0b4SBenjamin Herrenschmidt return memblock_search(&memblock.reserved, addr) != -1; 70495f72d1eSYinghai Lu } 70572d4b0b4SBenjamin Herrenschmidt 7063661ca66SYinghai Lu int __init_memblock memblock_is_memory(phys_addr_t addr) 70772d4b0b4SBenjamin Herrenschmidt { 70872d4b0b4SBenjamin Herrenschmidt return memblock_search(&memblock.memory, addr) != -1; 70972d4b0b4SBenjamin Herrenschmidt } 71072d4b0b4SBenjamin Herrenschmidt 7113661ca66SYinghai Lu int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) 71272d4b0b4SBenjamin Herrenschmidt { 713abb65272STomi Valkeinen int idx = memblock_search(&memblock.memory, base); 71472d4b0b4SBenjamin Herrenschmidt 71572d4b0b4SBenjamin Herrenschmidt if (idx == -1) 71695f72d1eSYinghai Lu return 0; 717abb65272STomi Valkeinen return memblock.memory.regions[idx].base <= base && 718abb65272STomi Valkeinen (memblock.memory.regions[idx].base + 719abb65272STomi Valkeinen memblock.memory.regions[idx].size) >= (base + size); 72095f72d1eSYinghai Lu } 72195f72d1eSYinghai Lu 72210d06439SYinghai Lu int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) 72395f72d1eSYinghai Lu { 724f1c2c19cSBenjamin Herrenschmidt return memblock_overlaps_region(&memblock.reserved, base, size) >= 0; 72595f72d1eSYinghai Lu } 72695f72d1eSYinghai Lu 727e63075a3SBenjamin Herrenschmidt 7283661ca66SYinghai Lu void __init_memblock memblock_set_current_limit(phys_addr_t limit) 729e63075a3SBenjamin Herrenschmidt { 730e63075a3SBenjamin Herrenschmidt memblock.current_limit = limit; 731e63075a3SBenjamin Herrenschmidt } 732e63075a3SBenjamin Herrenschmidt 73310d06439SYinghai Lu static void __init_memblock memblock_dump(struct memblock_type *region, char *name) 7346ed311b2SBenjamin Herrenschmidt { 7356ed311b2SBenjamin Herrenschmidt unsigned long long base, size; 7366ed311b2SBenjamin Herrenschmidt int i; 7376ed311b2SBenjamin Herrenschmidt 7386ed311b2SBenjamin Herrenschmidt pr_info(" %s.cnt = 0x%lx\n", name, region->cnt); 7396ed311b2SBenjamin Herrenschmidt 7406ed311b2SBenjamin Herrenschmidt for (i = 0; i < region->cnt; i++) { 7416ed311b2SBenjamin Herrenschmidt base = region->regions[i].base; 7426ed311b2SBenjamin Herrenschmidt size = region->regions[i].size; 7436ed311b2SBenjamin Herrenschmidt 744ea9e4376SYinghai Lu pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes\n", 7456ed311b2SBenjamin Herrenschmidt name, i, base, base + size - 1, size); 7466ed311b2SBenjamin Herrenschmidt } 7476ed311b2SBenjamin Herrenschmidt } 7486ed311b2SBenjamin Herrenschmidt 74910d06439SYinghai Lu void __init_memblock memblock_dump_all(void) 7506ed311b2SBenjamin Herrenschmidt { 7516ed311b2SBenjamin Herrenschmidt if (!memblock_debug) 7526ed311b2SBenjamin Herrenschmidt return; 7536ed311b2SBenjamin Herrenschmidt 7546ed311b2SBenjamin Herrenschmidt pr_info("MEMBLOCK configuration:\n"); 7556ed311b2SBenjamin Herrenschmidt pr_info(" memory size = 0x%llx\n", (unsigned long long)memblock.memory_size); 7566ed311b2SBenjamin Herrenschmidt 7576ed311b2SBenjamin Herrenschmidt memblock_dump(&memblock.memory, "memory"); 7586ed311b2SBenjamin Herrenschmidt memblock_dump(&memblock.reserved, "reserved"); 7596ed311b2SBenjamin Herrenschmidt } 7606ed311b2SBenjamin Herrenschmidt 7616ed311b2SBenjamin Herrenschmidt void __init memblock_analyze(void) 7626ed311b2SBenjamin Herrenschmidt { 7636ed311b2SBenjamin Herrenschmidt int i; 7646ed311b2SBenjamin Herrenschmidt 7656ed311b2SBenjamin Herrenschmidt /* Check marker in the unused last array entry */ 7666ed311b2SBenjamin Herrenschmidt WARN_ON(memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS].base 767c9d8c3d0SAndrew Morton != MEMBLOCK_INACTIVE); 7686ed311b2SBenjamin Herrenschmidt WARN_ON(memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS].base 769c9d8c3d0SAndrew Morton != MEMBLOCK_INACTIVE); 7706ed311b2SBenjamin Herrenschmidt 7716ed311b2SBenjamin Herrenschmidt memblock.memory_size = 0; 7726ed311b2SBenjamin Herrenschmidt 7736ed311b2SBenjamin Herrenschmidt for (i = 0; i < memblock.memory.cnt; i++) 7746ed311b2SBenjamin Herrenschmidt memblock.memory_size += memblock.memory.regions[i].size; 775142b45a7SBenjamin Herrenschmidt 776142b45a7SBenjamin Herrenschmidt /* We allow resizing from there */ 777142b45a7SBenjamin Herrenschmidt memblock_can_resize = 1; 7786ed311b2SBenjamin Herrenschmidt } 7796ed311b2SBenjamin Herrenschmidt 7807590abe8SBenjamin Herrenschmidt void __init memblock_init(void) 7817590abe8SBenjamin Herrenschmidt { 782236260b9SJeremy Fitzhardinge static int init_done __initdata = 0; 783236260b9SJeremy Fitzhardinge 784236260b9SJeremy Fitzhardinge if (init_done) 785236260b9SJeremy Fitzhardinge return; 786236260b9SJeremy Fitzhardinge init_done = 1; 787236260b9SJeremy Fitzhardinge 7887590abe8SBenjamin Herrenschmidt /* Hookup the initial arrays */ 7897590abe8SBenjamin Herrenschmidt memblock.memory.regions = memblock_memory_init_regions; 7907590abe8SBenjamin Herrenschmidt memblock.memory.max = INIT_MEMBLOCK_REGIONS; 7917590abe8SBenjamin Herrenschmidt memblock.reserved.regions = memblock_reserved_init_regions; 7927590abe8SBenjamin Herrenschmidt memblock.reserved.max = INIT_MEMBLOCK_REGIONS; 7937590abe8SBenjamin Herrenschmidt 7947590abe8SBenjamin Herrenschmidt /* Write a marker in the unused last array entry */ 795c9d8c3d0SAndrew Morton memblock.memory.regions[INIT_MEMBLOCK_REGIONS].base = MEMBLOCK_INACTIVE; 796c9d8c3d0SAndrew Morton memblock.reserved.regions[INIT_MEMBLOCK_REGIONS].base = MEMBLOCK_INACTIVE; 7977590abe8SBenjamin Herrenschmidt 7987590abe8SBenjamin Herrenschmidt /* Create a dummy zero size MEMBLOCK which will get coalesced away later. 7997590abe8SBenjamin Herrenschmidt * This simplifies the memblock_add() code below... 8007590abe8SBenjamin Herrenschmidt */ 8017590abe8SBenjamin Herrenschmidt memblock.memory.regions[0].base = 0; 8027590abe8SBenjamin Herrenschmidt memblock.memory.regions[0].size = 0; 8037590abe8SBenjamin Herrenschmidt memblock.memory.cnt = 1; 8047590abe8SBenjamin Herrenschmidt 8057590abe8SBenjamin Herrenschmidt /* Ditto. */ 8067590abe8SBenjamin Herrenschmidt memblock.reserved.regions[0].base = 0; 8077590abe8SBenjamin Herrenschmidt memblock.reserved.regions[0].size = 0; 8087590abe8SBenjamin Herrenschmidt memblock.reserved.cnt = 1; 8097590abe8SBenjamin Herrenschmidt 8107590abe8SBenjamin Herrenschmidt memblock.current_limit = MEMBLOCK_ALLOC_ANYWHERE; 8117590abe8SBenjamin Herrenschmidt } 8127590abe8SBenjamin Herrenschmidt 8136ed311b2SBenjamin Herrenschmidt static int __init early_memblock(char *p) 8146ed311b2SBenjamin Herrenschmidt { 8156ed311b2SBenjamin Herrenschmidt if (p && strstr(p, "debug")) 8166ed311b2SBenjamin Herrenschmidt memblock_debug = 1; 8176ed311b2SBenjamin Herrenschmidt return 0; 8186ed311b2SBenjamin Herrenschmidt } 8196ed311b2SBenjamin Herrenschmidt early_param("memblock", early_memblock); 8206ed311b2SBenjamin Herrenschmidt 82110d06439SYinghai Lu #if defined(CONFIG_DEBUG_FS) && !defined(ARCH_DISCARD_MEMBLOCK) 8226d03b885SBenjamin Herrenschmidt 8236d03b885SBenjamin Herrenschmidt static int memblock_debug_show(struct seq_file *m, void *private) 8246d03b885SBenjamin Herrenschmidt { 8256d03b885SBenjamin Herrenschmidt struct memblock_type *type = m->private; 8266d03b885SBenjamin Herrenschmidt struct memblock_region *reg; 8276d03b885SBenjamin Herrenschmidt int i; 8286d03b885SBenjamin Herrenschmidt 8296d03b885SBenjamin Herrenschmidt for (i = 0; i < type->cnt; i++) { 8306d03b885SBenjamin Herrenschmidt reg = &type->regions[i]; 8316d03b885SBenjamin Herrenschmidt seq_printf(m, "%4d: ", i); 8326d03b885SBenjamin Herrenschmidt if (sizeof(phys_addr_t) == 4) 8336d03b885SBenjamin Herrenschmidt seq_printf(m, "0x%08lx..0x%08lx\n", 8346d03b885SBenjamin Herrenschmidt (unsigned long)reg->base, 8356d03b885SBenjamin Herrenschmidt (unsigned long)(reg->base + reg->size - 1)); 8366d03b885SBenjamin Herrenschmidt else 8376d03b885SBenjamin Herrenschmidt seq_printf(m, "0x%016llx..0x%016llx\n", 8386d03b885SBenjamin Herrenschmidt (unsigned long long)reg->base, 8396d03b885SBenjamin Herrenschmidt (unsigned long long)(reg->base + reg->size - 1)); 8406d03b885SBenjamin Herrenschmidt 8416d03b885SBenjamin Herrenschmidt } 8426d03b885SBenjamin Herrenschmidt return 0; 8436d03b885SBenjamin Herrenschmidt } 8446d03b885SBenjamin Herrenschmidt 8456d03b885SBenjamin Herrenschmidt static int memblock_debug_open(struct inode *inode, struct file *file) 8466d03b885SBenjamin Herrenschmidt { 8476d03b885SBenjamin Herrenschmidt return single_open(file, memblock_debug_show, inode->i_private); 8486d03b885SBenjamin Herrenschmidt } 8496d03b885SBenjamin Herrenschmidt 8506d03b885SBenjamin Herrenschmidt static const struct file_operations memblock_debug_fops = { 8516d03b885SBenjamin Herrenschmidt .open = memblock_debug_open, 8526d03b885SBenjamin Herrenschmidt .read = seq_read, 8536d03b885SBenjamin Herrenschmidt .llseek = seq_lseek, 8546d03b885SBenjamin Herrenschmidt .release = single_release, 8556d03b885SBenjamin Herrenschmidt }; 8566d03b885SBenjamin Herrenschmidt 8576d03b885SBenjamin Herrenschmidt static int __init memblock_init_debugfs(void) 8586d03b885SBenjamin Herrenschmidt { 8596d03b885SBenjamin Herrenschmidt struct dentry *root = debugfs_create_dir("memblock", NULL); 8606d03b885SBenjamin Herrenschmidt if (!root) 8616d03b885SBenjamin Herrenschmidt return -ENXIO; 8626d03b885SBenjamin Herrenschmidt debugfs_create_file("memory", S_IRUGO, root, &memblock.memory, &memblock_debug_fops); 8636d03b885SBenjamin Herrenschmidt debugfs_create_file("reserved", S_IRUGO, root, &memblock.reserved, &memblock_debug_fops); 8646d03b885SBenjamin Herrenschmidt 8656d03b885SBenjamin Herrenschmidt return 0; 8666d03b885SBenjamin Herrenschmidt } 8676d03b885SBenjamin Herrenschmidt __initcall(memblock_init_debugfs); 8686d03b885SBenjamin Herrenschmidt 8696d03b885SBenjamin Herrenschmidt #endif /* CONFIG_DEBUG_FS */ 870