176d2a049SPalmer Dabbelt /* 276d2a049SPalmer Dabbelt * Copyright (C) 2012 Regents of the University of California 376d2a049SPalmer Dabbelt * 476d2a049SPalmer Dabbelt * This program is free software; you can redistribute it and/or 576d2a049SPalmer Dabbelt * modify it under the terms of the GNU General Public License 676d2a049SPalmer Dabbelt * as published by the Free Software Foundation, version 2. 776d2a049SPalmer Dabbelt * 876d2a049SPalmer Dabbelt * This program is distributed in the hope that it will be useful, 976d2a049SPalmer Dabbelt * but WITHOUT ANY WARRANTY; without even the implied warranty of 1076d2a049SPalmer Dabbelt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1176d2a049SPalmer Dabbelt * GNU General Public License for more details. 1276d2a049SPalmer Dabbelt */ 1376d2a049SPalmer Dabbelt 1476d2a049SPalmer Dabbelt #include <linux/init.h> 1576d2a049SPalmer Dabbelt #include <linux/mm.h> 1676d2a049SPalmer Dabbelt #include <linux/memblock.h> 1757c8a661SMike Rapoport #include <linux/initrd.h> 1876d2a049SPalmer Dabbelt #include <linux/swap.h> 195ec9c4ffSChristoph Hellwig #include <linux/sizes.h> 200651c263SAnup Patel #include <linux/of_fdt.h> 2176d2a049SPalmer Dabbelt 2276d2a049SPalmer Dabbelt #include <asm/tlbflush.h> 2376d2a049SPalmer Dabbelt #include <asm/sections.h> 2476d2a049SPalmer Dabbelt #include <asm/pgtable.h> 2576d2a049SPalmer Dabbelt #include <asm/io.h> 2676d2a049SPalmer Dabbelt 2776d2a049SPalmer Dabbelt static void __init zone_sizes_init(void) 2876d2a049SPalmer Dabbelt { 295ec9c4ffSChristoph Hellwig unsigned long max_zone_pfns[MAX_NR_ZONES] = { 0, }; 3076d2a049SPalmer Dabbelt 31d5fad48cSZong Li #ifdef CONFIG_ZONE_DMA32 3228198c46SGuo Ren max_zone_pfns[ZONE_DMA32] = PFN_DOWN(min(4UL * SZ_1G, 3328198c46SGuo Ren (unsigned long) PFN_PHYS(max_low_pfn))); 34d5fad48cSZong Li #endif 355ec9c4ffSChristoph Hellwig max_zone_pfns[ZONE_NORMAL] = max_low_pfn; 365ec9c4ffSChristoph Hellwig 375ec9c4ffSChristoph Hellwig free_area_init_nodes(max_zone_pfns); 3876d2a049SPalmer Dabbelt } 3976d2a049SPalmer Dabbelt 4076d2a049SPalmer Dabbelt void setup_zero_page(void) 4176d2a049SPalmer Dabbelt { 4276d2a049SPalmer Dabbelt memset((void *)empty_zero_page, 0, PAGE_SIZE); 4376d2a049SPalmer Dabbelt } 4476d2a049SPalmer Dabbelt 4576d2a049SPalmer Dabbelt void __init paging_init(void) 4676d2a049SPalmer Dabbelt { 4776d2a049SPalmer Dabbelt setup_zero_page(); 4876d2a049SPalmer Dabbelt local_flush_tlb_all(); 4976d2a049SPalmer Dabbelt zone_sizes_init(); 5076d2a049SPalmer Dabbelt } 5176d2a049SPalmer Dabbelt 5276d2a049SPalmer Dabbelt void __init mem_init(void) 5376d2a049SPalmer Dabbelt { 5476d2a049SPalmer Dabbelt #ifdef CONFIG_FLATMEM 5576d2a049SPalmer Dabbelt BUG_ON(!mem_map); 5676d2a049SPalmer Dabbelt #endif /* CONFIG_FLATMEM */ 5776d2a049SPalmer Dabbelt 5876d2a049SPalmer Dabbelt high_memory = (void *)(__va(PFN_PHYS(max_low_pfn))); 59c6ffc5caSMike Rapoport memblock_free_all(); 6076d2a049SPalmer Dabbelt 6176d2a049SPalmer Dabbelt mem_init_print_info(NULL); 6276d2a049SPalmer Dabbelt } 6376d2a049SPalmer Dabbelt 6476d2a049SPalmer Dabbelt void free_initmem(void) 6576d2a049SPalmer Dabbelt { 6676d2a049SPalmer Dabbelt free_initmem_default(0); 6776d2a049SPalmer Dabbelt } 6876d2a049SPalmer Dabbelt 6976d2a049SPalmer Dabbelt #ifdef CONFIG_BLK_DEV_INITRD 700651c263SAnup Patel static void __init setup_initrd(void) 710651c263SAnup Patel { 720651c263SAnup Patel unsigned long size; 730651c263SAnup Patel 740651c263SAnup Patel if (initrd_start >= initrd_end) { 750651c263SAnup Patel pr_info("initrd not found or empty"); 760651c263SAnup Patel goto disable; 770651c263SAnup Patel } 780651c263SAnup Patel if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) { 790651c263SAnup Patel pr_err("initrd extends beyond end of memory"); 800651c263SAnup Patel goto disable; 810651c263SAnup Patel } 820651c263SAnup Patel 830651c263SAnup Patel size = initrd_end - initrd_start; 840651c263SAnup Patel memblock_reserve(__pa(initrd_start), size); 850651c263SAnup Patel initrd_below_start_ok = 1; 860651c263SAnup Patel 870651c263SAnup Patel pr_info("Initial ramdisk at: 0x%p (%lu bytes)\n", 880651c263SAnup Patel (void *)(initrd_start), size); 890651c263SAnup Patel return; 900651c263SAnup Patel disable: 910651c263SAnup Patel pr_cont(" - disabling initrd\n"); 920651c263SAnup Patel initrd_start = 0; 930651c263SAnup Patel initrd_end = 0; 940651c263SAnup Patel } 950651c263SAnup Patel 9676d2a049SPalmer Dabbelt void free_initrd_mem(unsigned long start, unsigned long end) 9776d2a049SPalmer Dabbelt { 9876d2a049SPalmer Dabbelt } 9976d2a049SPalmer Dabbelt #endif /* CONFIG_BLK_DEV_INITRD */ 1000651c263SAnup Patel 1010651c263SAnup Patel void __init setup_bootmem(void) 1020651c263SAnup Patel { 1030651c263SAnup Patel struct memblock_region *reg; 1040651c263SAnup Patel phys_addr_t mem_size = 0; 1050651c263SAnup Patel 1060651c263SAnup Patel /* Find the memory region containing the kernel */ 1070651c263SAnup Patel for_each_memblock(memory, reg) { 1080651c263SAnup Patel phys_addr_t vmlinux_end = __pa(_end); 1090651c263SAnup Patel phys_addr_t end = reg->base + reg->size; 1100651c263SAnup Patel 1110651c263SAnup Patel if (reg->base <= vmlinux_end && vmlinux_end <= end) { 1120651c263SAnup Patel /* 1130651c263SAnup Patel * Reserve from the start of the region to the end of 1140651c263SAnup Patel * the kernel 1150651c263SAnup Patel */ 1160651c263SAnup Patel memblock_reserve(reg->base, vmlinux_end - reg->base); 1170651c263SAnup Patel mem_size = min(reg->size, (phys_addr_t)-PAGE_OFFSET); 1180651c263SAnup Patel } 1190651c263SAnup Patel } 1200651c263SAnup Patel BUG_ON(mem_size == 0); 1210651c263SAnup Patel 1220651c263SAnup Patel set_max_mapnr(PFN_DOWN(mem_size)); 1230651c263SAnup Patel max_low_pfn = PFN_DOWN(memblock_end_of_DRAM()); 1240651c263SAnup Patel 1250651c263SAnup Patel #ifdef CONFIG_BLK_DEV_INITRD 1260651c263SAnup Patel setup_initrd(); 1270651c263SAnup Patel #endif /* CONFIG_BLK_DEV_INITRD */ 1280651c263SAnup Patel 1290651c263SAnup Patel early_init_fdt_reserve_self(); 1300651c263SAnup Patel early_init_fdt_scan_reserved_mem(); 1310651c263SAnup Patel memblock_allow_resize(); 1320651c263SAnup Patel memblock_dump_all(); 1330651c263SAnup Patel 1340651c263SAnup Patel for_each_memblock(memory, reg) { 1350651c263SAnup Patel unsigned long start_pfn = memblock_region_memory_base_pfn(reg); 1360651c263SAnup Patel unsigned long end_pfn = memblock_region_memory_end_pfn(reg); 1370651c263SAnup Patel 1380651c263SAnup Patel memblock_set_node(PFN_PHYS(start_pfn), 1390651c263SAnup Patel PFN_PHYS(end_pfn - start_pfn), 1400651c263SAnup Patel &memblock.memory, 0); 1410651c263SAnup Patel } 1420651c263SAnup Patel } 143