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 8 * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). 9 * PPC44x/36-bit changes by Matt Porter (mporter@mvista.com) 10 * 11 * Derived from "arch/i386/mm/init.c" 12 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 17 * 2 of the License, or (at your option) any later version. 18 * 19 */ 20 21 #include <linux/config.h> 22 #include <linux/module.h> 23 #include <linux/sched.h> 24 #include <linux/kernel.h> 25 #include <linux/errno.h> 26 #include <linux/string.h> 27 #include <linux/types.h> 28 #include <linux/mm.h> 29 #include <linux/stddef.h> 30 #include <linux/init.h> 31 #include <linux/bootmem.h> 32 #include <linux/highmem.h> 33 #include <linux/initrd.h> 34 #include <linux/pagemap.h> 35 36 #include <asm/pgalloc.h> 37 #include <asm/prom.h> 38 #include <asm/io.h> 39 #include <asm/mmu_context.h> 40 #include <asm/pgtable.h> 41 #include <asm/mmu.h> 42 #include <asm/smp.h> 43 #include <asm/machdep.h> 44 #include <asm/btext.h> 45 #include <asm/tlb.h> 46 #include <asm/prom.h> 47 #include <asm/lmb.h> 48 #include <asm/sections.h> 49 50 #include "mmu_decl.h" 51 52 #if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL) 53 /* The ammount of lowmem must be within 0xF0000000 - KERNELBASE. */ 54 #if (CONFIG_LOWMEM_SIZE > (0xF0000000 - KERNELBASE)) 55 #error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL" 56 #endif 57 #endif 58 #define MAX_LOW_MEM CONFIG_LOWMEM_SIZE 59 60 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); 61 62 unsigned long total_memory; 63 unsigned long total_lowmem; 64 65 unsigned long ppc_memstart; 66 unsigned long ppc_memoffset = PAGE_OFFSET; 67 68 int boot_mapsize; 69 #ifdef CONFIG_PPC_PMAC 70 unsigned long agp_special_page; 71 EXPORT_SYMBOL(agp_special_page); 72 #endif 73 74 #ifdef CONFIG_HIGHMEM 75 pte_t *kmap_pte; 76 pgprot_t kmap_prot; 77 78 EXPORT_SYMBOL(kmap_prot); 79 EXPORT_SYMBOL(kmap_pte); 80 #endif 81 82 void MMU_init(void); 83 84 /* XXX should be in current.h -- paulus */ 85 extern struct task_struct *current_set[NR_CPUS]; 86 87 char *klimit = _end; 88 struct device_node *memory_node; 89 90 extern int init_bootmem_done; 91 92 /* 93 * this tells the system to map all of ram with the segregs 94 * (i.e. page tables) instead of the bats. 95 * -- Cort 96 */ 97 int __map_without_bats; 98 int __map_without_ltlbs; 99 100 /* max amount of low RAM to map in */ 101 unsigned long __max_low_memory = MAX_LOW_MEM; 102 103 /* 104 * limit of what is accessible with initial MMU setup - 105 * 256MB usually, but only 16MB on 601. 106 */ 107 unsigned long __initial_memory_limit = 0x10000000; 108 109 /* 110 * Check for command-line options that affect what MMU_init will do. 111 */ 112 void MMU_setup(void) 113 { 114 /* Check for nobats option (used in mapin_ram). */ 115 if (strstr(cmd_line, "nobats")) { 116 __map_without_bats = 1; 117 } 118 119 if (strstr(cmd_line, "noltlbs")) { 120 __map_without_ltlbs = 1; 121 } 122 } 123 124 /* 125 * MMU_init sets up the basic memory mappings for the kernel, 126 * including both RAM and possibly some I/O regions, 127 * and sets up the page tables and the MMU hardware ready to go. 128 */ 129 void __init MMU_init(void) 130 { 131 if (ppc_md.progress) 132 ppc_md.progress("MMU:enter", 0x111); 133 134 /* 601 can only access 16MB at the moment */ 135 if (PVR_VER(mfspr(SPRN_PVR)) == 1) 136 __initial_memory_limit = 0x01000000; 137 138 /* parse args from command line */ 139 MMU_setup(); 140 141 if (lmb.memory.cnt > 1) { 142 lmb.memory.cnt = 1; 143 lmb_analyze(); 144 printk(KERN_WARNING "Only using first contiguous memory region"); 145 } 146 147 total_memory = lmb_end_of_DRAM(); 148 total_lowmem = total_memory; 149 150 #ifdef CONFIG_FSL_BOOKE 151 /* Freescale Book-E parts expect lowmem to be mapped by fixed TLB 152 * entries, so we need to adjust lowmem to match the amount we can map 153 * in the fixed entries */ 154 adjust_total_lowmem(); 155 #endif /* CONFIG_FSL_BOOKE */ 156 157 if (total_lowmem > __max_low_memory) { 158 total_lowmem = __max_low_memory; 159 #ifndef CONFIG_HIGHMEM 160 total_memory = total_lowmem; 161 lmb_enforce_memory_limit(total_lowmem); 162 lmb_analyze(); 163 #endif /* CONFIG_HIGHMEM */ 164 } 165 166 /* Initialize the MMU hardware */ 167 if (ppc_md.progress) 168 ppc_md.progress("MMU:hw init", 0x300); 169 MMU_init_hw(); 170 171 /* Map in all of RAM starting at KERNELBASE */ 172 if (ppc_md.progress) 173 ppc_md.progress("MMU:mapin", 0x301); 174 mapin_ram(); 175 176 #ifdef CONFIG_HIGHMEM 177 ioremap_base = PKMAP_BASE; 178 #else 179 ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 */ 180 #endif /* CONFIG_HIGHMEM */ 181 ioremap_bot = ioremap_base; 182 183 /* Map in I/O resources */ 184 if (ppc_md.progress) 185 ppc_md.progress("MMU:setio", 0x302); 186 if (ppc_md.setup_io_mappings) 187 ppc_md.setup_io_mappings(); 188 189 /* Initialize the context management stuff */ 190 mmu_context_init(); 191 192 if (ppc_md.progress) 193 ppc_md.progress("MMU:exit", 0x211); 194 } 195 196 /* This is only called until mem_init is done. */ 197 void __init *early_get_page(void) 198 { 199 void *p; 200 201 if (init_bootmem_done) { 202 p = alloc_bootmem_pages(PAGE_SIZE); 203 } else { 204 p = __va(lmb_alloc_base(PAGE_SIZE, PAGE_SIZE, 205 __initial_memory_limit)); 206 } 207 return p; 208 } 209 210 /* Free up now-unused memory */ 211 static void free_sec(unsigned long start, unsigned long end, const char *name) 212 { 213 unsigned long cnt = 0; 214 215 while (start < end) { 216 ClearPageReserved(virt_to_page(start)); 217 set_page_count(virt_to_page(start), 1); 218 free_page(start); 219 cnt++; 220 start += PAGE_SIZE; 221 } 222 if (cnt) { 223 printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name); 224 totalram_pages += cnt; 225 } 226 } 227 228 void free_initmem(void) 229 { 230 #define FREESEC(TYPE) \ 231 free_sec((unsigned long)(&__ ## TYPE ## _begin), \ 232 (unsigned long)(&__ ## TYPE ## _end), \ 233 #TYPE); 234 235 printk ("Freeing unused kernel memory:"); 236 FREESEC(init); 237 printk("\n"); 238 ppc_md.progress = NULL; 239 #undef FREESEC 240 } 241 242 #ifdef CONFIG_BLK_DEV_INITRD 243 void free_initrd_mem(unsigned long start, unsigned long end) 244 { 245 if (start < end) 246 printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); 247 for (; start < end; start += PAGE_SIZE) { 248 ClearPageReserved(virt_to_page(start)); 249 set_page_count(virt_to_page(start), 1); 250 free_page(start); 251 totalram_pages++; 252 } 253 } 254 #endif 255