| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 1 | /* | 
 | 2 |  *  PowerPC version | 
 | 3 |  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | 
 | 4 |  * | 
 | 5 |  *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) | 
 | 6 |  *  and Cort Dougan (PReP) (cort@cs.nmt.edu) | 
 | 7 |  *    Copyright (C) 1996 Paul Mackerras | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 8 |  *  PPC44x/36-bit changes by Matt Porter (mporter@mvista.com) | 
 | 9 |  * | 
 | 10 |  *  Derived from "arch/i386/mm/init.c" | 
 | 11 |  *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds | 
 | 12 |  * | 
 | 13 |  *  This program is free software; you can redistribute it and/or | 
 | 14 |  *  modify it under the terms of the GNU General Public License | 
 | 15 |  *  as published by the Free Software Foundation; either version | 
 | 16 |  *  2 of the License, or (at your option) any later version. | 
 | 17 |  * | 
 | 18 |  */ | 
 | 19 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 20 | #include <linux/module.h> | 
 | 21 | #include <linux/sched.h> | 
 | 22 | #include <linux/kernel.h> | 
 | 23 | #include <linux/errno.h> | 
 | 24 | #include <linux/string.h> | 
 | 25 | #include <linux/types.h> | 
 | 26 | #include <linux/mm.h> | 
 | 27 | #include <linux/stddef.h> | 
 | 28 | #include <linux/init.h> | 
 | 29 | #include <linux/bootmem.h> | 
 | 30 | #include <linux/highmem.h> | 
 | 31 | #include <linux/initrd.h> | 
 | 32 | #include <linux/pagemap.h> | 
| Yinghai Lu | 95f72d1 | 2010-07-12 14:36:09 +1000 | [diff] [blame] | 33 | #include <linux/memblock.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 34 | #include <linux/gfp.h> | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 35 |  | 
 | 36 | #include <asm/pgalloc.h> | 
 | 37 | #include <asm/prom.h> | 
 | 38 | #include <asm/io.h> | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 39 | #include <asm/pgtable.h> | 
 | 40 | #include <asm/mmu.h> | 
 | 41 | #include <asm/smp.h> | 
 | 42 | #include <asm/machdep.h> | 
 | 43 | #include <asm/btext.h> | 
 | 44 | #include <asm/tlb.h> | 
| Paul Mackerras | 7c8c6b9 | 2005-10-06 12:23:33 +1000 | [diff] [blame] | 45 | #include <asm/sections.h> | 
| Michael Ellerman | 5f25f06 | 2008-05-08 14:27:07 +1000 | [diff] [blame] | 46 | #include <asm/system.h> | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 47 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 48 | #include "mmu_decl.h" | 
 | 49 |  | 
 | 50 | #if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL) | 
| Uwe Kleine-König | 9ddc5b6 | 2010-01-20 17:02:24 +0100 | [diff] [blame] | 51 | /* The amount of lowmem must be within 0xF0000000 - KERNELBASE. */ | 
| Dale Farnsworth | ccdcef7 | 2008-12-17 10:09:13 +0000 | [diff] [blame] | 52 | #if (CONFIG_LOWMEM_SIZE > (0xF0000000 - PAGE_OFFSET)) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 53 | #error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL" | 
 | 54 | #endif | 
 | 55 | #endif | 
 | 56 | #define MAX_LOW_MEM	CONFIG_LOWMEM_SIZE | 
 | 57 |  | 
| Stefan Roese | 2bf3016 | 2008-07-10 01:09:23 +1000 | [diff] [blame] | 58 | phys_addr_t total_memory; | 
 | 59 | phys_addr_t total_lowmem; | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 60 |  | 
| Kumar Gala | 37dd2ba | 2008-04-22 04:22:34 +1000 | [diff] [blame] | 61 | phys_addr_t memstart_addr = (phys_addr_t)~0ull; | 
 | 62 | EXPORT_SYMBOL(memstart_addr); | 
 | 63 | phys_addr_t kernstart_addr; | 
 | 64 | EXPORT_SYMBOL(kernstart_addr); | 
| Kumar Gala | 99c62dd | 2008-04-16 05:52:21 +1000 | [diff] [blame] | 65 | phys_addr_t lowmem_end_addr; | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 66 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 67 | int boot_mapsize; | 
 | 68 | #ifdef CONFIG_PPC_PMAC | 
 | 69 | unsigned long agp_special_page; | 
| Paul Mackerras | 5c8c56e | 2005-10-22 14:42:51 +1000 | [diff] [blame] | 70 | EXPORT_SYMBOL(agp_special_page); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 71 | #endif | 
 | 72 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 73 | void MMU_init(void); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 74 |  | 
 | 75 | /* XXX should be in current.h  -- paulus */ | 
 | 76 | extern struct task_struct *current_set[NR_CPUS]; | 
 | 77 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 78 | /* | 
 | 79 |  * this tells the system to map all of ram with the segregs | 
 | 80 |  * (i.e. page tables) instead of the bats. | 
 | 81 |  * -- Cort | 
 | 82 |  */ | 
 | 83 | int __map_without_bats; | 
 | 84 | int __map_without_ltlbs; | 
 | 85 |  | 
| Albert Herranz | c5df7f7 | 2009-12-12 06:31:54 +0000 | [diff] [blame] | 86 | /* | 
 | 87 |  * This tells the system to allow ioremapping memory marked as reserved. | 
 | 88 |  */ | 
 | 89 | int __allow_ioremap_reserved; | 
 | 90 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 91 | /* max amount of low RAM to map in */ | 
 | 92 | unsigned long __max_low_memory = MAX_LOW_MEM; | 
 | 93 |  | 
 | 94 | /* | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 95 |  * Check for command-line options that affect what MMU_init will do. | 
 | 96 |  */ | 
 | 97 | void MMU_setup(void) | 
 | 98 | { | 
 | 99 | 	/* Check for nobats option (used in mapin_ram). */ | 
 | 100 | 	if (strstr(cmd_line, "nobats")) { | 
 | 101 | 		__map_without_bats = 1; | 
 | 102 | 	} | 
 | 103 |  | 
 | 104 | 	if (strstr(cmd_line, "noltlbs")) { | 
 | 105 | 		__map_without_ltlbs = 1; | 
 | 106 | 	} | 
| Benjamin Herrenschmidt | 88df6e9 | 2007-04-12 15:30:22 +1000 | [diff] [blame] | 107 | #ifdef CONFIG_DEBUG_PAGEALLOC | 
 | 108 | 	__map_without_bats = 1; | 
 | 109 | 	__map_without_ltlbs = 1; | 
 | 110 | #endif | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 111 | } | 
 | 112 |  | 
 | 113 | /* | 
 | 114 |  * MMU_init sets up the basic memory mappings for the kernel, | 
 | 115 |  * including both RAM and possibly some I/O regions, | 
 | 116 |  * and sets up the page tables and the MMU hardware ready to go. | 
 | 117 |  */ | 
 | 118 | void __init MMU_init(void) | 
 | 119 | { | 
 | 120 | 	if (ppc_md.progress) | 
 | 121 | 		ppc_md.progress("MMU:enter", 0x111); | 
 | 122 |  | 
 | 123 | 	/* parse args from command line */ | 
 | 124 | 	MMU_setup(); | 
 | 125 |  | 
| Yinghai Lu | 95f72d1 | 2010-07-12 14:36:09 +1000 | [diff] [blame] | 126 | 	if (memblock.memory.cnt > 1) { | 
| Albert Herranz | de32400 | 2009-12-12 06:31:53 +0000 | [diff] [blame] | 127 | #ifndef CONFIG_WII | 
| Yinghai Lu | 95f72d1 | 2010-07-12 14:36:09 +1000 | [diff] [blame] | 128 | 		memblock.memory.cnt = 1; | 
 | 129 | 		memblock_analyze(); | 
| Paul Mackerras | 7c8c6b9 | 2005-10-06 12:23:33 +1000 | [diff] [blame] | 130 | 		printk(KERN_WARNING "Only using first contiguous memory region"); | 
| Albert Herranz | de32400 | 2009-12-12 06:31:53 +0000 | [diff] [blame] | 131 | #else | 
 | 132 | 		wii_memory_fixups(); | 
 | 133 | #endif | 
| Paul Mackerras | 7c8c6b9 | 2005-10-06 12:23:33 +1000 | [diff] [blame] | 134 | 	} | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 135 |  | 
| Yinghai Lu | 95f72d1 | 2010-07-12 14:36:09 +1000 | [diff] [blame] | 136 | 	total_lowmem = total_memory = memblock_end_of_DRAM() - memstart_addr; | 
| Kumar Gala | d7917ba | 2008-04-16 05:52:22 +1000 | [diff] [blame] | 137 | 	lowmem_end_addr = memstart_addr + total_lowmem; | 
| Paul Mackerras | 7c8c6b9 | 2005-10-06 12:23:33 +1000 | [diff] [blame] | 138 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 139 | #ifdef CONFIG_FSL_BOOKE | 
 | 140 | 	/* Freescale Book-E parts expect lowmem to be mapped by fixed TLB | 
 | 141 | 	 * entries, so we need to adjust lowmem to match the amount we can map | 
 | 142 | 	 * in the fixed entries */ | 
 | 143 | 	adjust_total_lowmem(); | 
 | 144 | #endif /* CONFIG_FSL_BOOKE */ | 
| Paul Mackerras | fa39dc4 | 2005-10-26 21:54:21 +1000 | [diff] [blame] | 145 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 146 | 	if (total_lowmem > __max_low_memory) { | 
 | 147 | 		total_lowmem = __max_low_memory; | 
| Kumar Gala | d7917ba | 2008-04-16 05:52:22 +1000 | [diff] [blame] | 148 | 		lowmem_end_addr = memstart_addr + total_lowmem; | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 149 | #ifndef CONFIG_HIGHMEM | 
 | 150 | 		total_memory = total_lowmem; | 
| Scott Wood | 6dd2270 | 2011-01-27 10:30:44 +0000 | [diff] [blame] | 151 | 		memblock_enforce_memory_limit(total_lowmem); | 
| Yinghai Lu | 95f72d1 | 2010-07-12 14:36:09 +1000 | [diff] [blame] | 152 | 		memblock_analyze(); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 153 | #endif /* CONFIG_HIGHMEM */ | 
 | 154 | 	} | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 155 |  | 
 | 156 | 	/* Initialize the MMU hardware */ | 
 | 157 | 	if (ppc_md.progress) | 
 | 158 | 		ppc_md.progress("MMU:hw init", 0x300); | 
 | 159 | 	MMU_init_hw(); | 
 | 160 |  | 
 | 161 | 	/* Map in all of RAM starting at KERNELBASE */ | 
 | 162 | 	if (ppc_md.progress) | 
 | 163 | 		ppc_md.progress("MMU:mapin", 0x301); | 
 | 164 | 	mapin_ram(); | 
 | 165 |  | 
| Benjamin Herrenschmidt | f637a49 | 2009-05-27 13:44:50 +1000 | [diff] [blame] | 166 | 	/* Initialize early top-down ioremap allocator */ | 
 | 167 | 	ioremap_bot = IOREMAP_TOP; | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 168 |  | 
 | 169 | 	/* Map in I/O resources */ | 
 | 170 | 	if (ppc_md.progress) | 
 | 171 | 		ppc_md.progress("MMU:setio", 0x302); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 172 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 173 | 	if (ppc_md.progress) | 
 | 174 | 		ppc_md.progress("MMU:exit", 0x211); | 
| Benjamin Herrenschmidt | 51d3082 | 2005-11-23 17:57:25 +1100 | [diff] [blame] | 175 |  | 
 | 176 | 	/* From now on, btext is no longer BAT mapped if it was at all */ | 
 | 177 | #ifdef CONFIG_BOOTX_TEXT | 
 | 178 | 	btext_unmap(); | 
 | 179 | #endif | 
| Benjamin Herrenschmidt | e63075a | 2010-07-06 15:39:01 -0700 | [diff] [blame] | 180 |  | 
 | 181 | 	/* Shortly after that, the entire linear mapping will be available */ | 
 | 182 | 	memblock_set_current_limit(lowmem_end_addr); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 183 | } | 
 | 184 |  | 
 | 185 | /* This is only called until mem_init is done. */ | 
 | 186 | void __init *early_get_page(void) | 
 | 187 | { | 
| Benjamin Herrenschmidt | e63075a | 2010-07-06 15:39:01 -0700 | [diff] [blame] | 188 | 	if (init_bootmem_done) | 
 | 189 | 		return alloc_bootmem_pages(PAGE_SIZE); | 
 | 190 | 	else | 
 | 191 | 		return __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE)); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 192 | } | 
 | 193 |  | 
 | 194 | /* Free up now-unused memory */ | 
 | 195 | static void free_sec(unsigned long start, unsigned long end, const char *name) | 
 | 196 | { | 
 | 197 | 	unsigned long cnt = 0; | 
 | 198 |  | 
 | 199 | 	while (start < end) { | 
 | 200 | 		ClearPageReserved(virt_to_page(start)); | 
| Nick Piggin | 7835e98 | 2006-03-22 00:08:40 -0800 | [diff] [blame] | 201 | 		init_page_count(virt_to_page(start)); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 202 | 		free_page(start); | 
 | 203 | 		cnt++; | 
 | 204 | 		start += PAGE_SIZE; | 
 | 205 |  	} | 
 | 206 | 	if (cnt) { | 
 | 207 | 		printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name); | 
 | 208 | 		totalram_pages += cnt; | 
 | 209 | 	} | 
 | 210 | } | 
 | 211 |  | 
 | 212 | void free_initmem(void) | 
 | 213 | { | 
 | 214 | #define FREESEC(TYPE) \ | 
 | 215 | 	free_sec((unsigned long)(&__ ## TYPE ## _begin), \ | 
 | 216 | 		 (unsigned long)(&__ ## TYPE ## _end), \ | 
 | 217 | 		 #TYPE); | 
 | 218 |  | 
 | 219 | 	printk ("Freeing unused kernel memory:"); | 
 | 220 | 	FREESEC(init); | 
 | 221 |  	printk("\n"); | 
 | 222 | 	ppc_md.progress = NULL; | 
 | 223 | #undef FREESEC | 
 | 224 | } | 
 | 225 |  | 
| Benjamin Herrenschmidt | cd3db0c | 2010-07-06 15:39:02 -0700 | [diff] [blame] | 226 | #ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */ | 
 | 227 | void setup_initial_memory_limit(phys_addr_t first_memblock_base, | 
 | 228 | 				phys_addr_t first_memblock_size) | 
 | 229 | { | 
 | 230 | 	/* We don't currently support the first MEMBLOCK not mapping 0 | 
 | 231 | 	 * physical on those processors | 
 | 232 | 	 */ | 
 | 233 | 	BUG_ON(first_memblock_base != 0); | 
 | 234 |  | 
 | 235 | 	/* 8xx can only access 8MB at the moment */ | 
 | 236 | 	memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000)); | 
 | 237 | } | 
 | 238 | #endif /* CONFIG_8xx */ |