fsl_booke_mmu.c revision 96a8bac5895a41b0fb05a6aa7c3fa1ea631a91fe
1/* 2 * Modifications by Kumar Gala (galak@kernel.crashing.org) to support 3 * E500 Book E processors. 4 * 5 * Copyright 2004 Freescale Semiconductor, Inc 6 * 7 * This file contains the routines for initializing the MMU 8 * on the 4xx series of chips. 9 * -- paulus 10 * 11 * Derived from arch/ppc/mm/init.c: 12 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 13 * 14 * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) 15 * and Cort Dougan (PReP) (cort@cs.nmt.edu) 16 * Copyright (C) 1996 Paul Mackerras 17 * 18 * Derived from "arch/i386/mm/init.c" 19 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 20 * 21 * This program is free software; you can redistribute it and/or 22 * modify it under the terms of the GNU General Public License 23 * as published by the Free Software Foundation; either version 24 * 2 of the License, or (at your option) any later version. 25 * 26 */ 27 28#include <linux/signal.h> 29#include <linux/sched.h> 30#include <linux/kernel.h> 31#include <linux/errno.h> 32#include <linux/string.h> 33#include <linux/types.h> 34#include <linux/ptrace.h> 35#include <linux/mman.h> 36#include <linux/mm.h> 37#include <linux/swap.h> 38#include <linux/stddef.h> 39#include <linux/vmalloc.h> 40#include <linux/init.h> 41#include <linux/delay.h> 42#include <linux/highmem.h> 43 44#include <asm/pgalloc.h> 45#include <asm/prom.h> 46#include <asm/io.h> 47#include <asm/mmu_context.h> 48#include <asm/pgtable.h> 49#include <asm/mmu.h> 50#include <asm/uaccess.h> 51#include <asm/smp.h> 52#include <asm/machdep.h> 53#include <asm/setup.h> 54 55#include "mmu_decl.h" 56 57extern void loadcam_entry(unsigned int index); 58unsigned int tlbcam_index; 59static unsigned long cam[CONFIG_LOWMEM_CAM_NUM]; 60 61#define NUM_TLBCAMS (16) 62 63#if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) 64#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS" 65#endif 66 67struct tlbcam TLBCAM[NUM_TLBCAMS]; 68 69struct tlbcamrange { 70 unsigned long start; 71 unsigned long limit; 72 phys_addr_t phys; 73} tlbcam_addrs[NUM_TLBCAMS]; 74 75extern unsigned int tlbcam_index; 76 77/* 78 * Return PA for this VA if it is mapped by a CAM, or 0 79 */ 80phys_addr_t v_mapped_by_tlbcam(unsigned long va) 81{ 82 int b; 83 for (b = 0; b < tlbcam_index; ++b) 84 if (va >= tlbcam_addrs[b].start && va < tlbcam_addrs[b].limit) 85 return tlbcam_addrs[b].phys + (va - tlbcam_addrs[b].start); 86 return 0; 87} 88 89/* 90 * Return VA for a given PA or 0 if not mapped 91 */ 92unsigned long p_mapped_by_tlbcam(phys_addr_t pa) 93{ 94 int b; 95 for (b = 0; b < tlbcam_index; ++b) 96 if (pa >= tlbcam_addrs[b].phys 97 && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) 98 +tlbcam_addrs[b].phys) 99 return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); 100 return 0; 101} 102 103/* 104 * Set up one of the I/D BAT (block address translation) register pairs. 105 * The parameters are not checked; in particular size must be a power 106 * of 4 between 4k and 256M. 107 */ 108void settlbcam(int index, unsigned long virt, phys_addr_t phys, 109 unsigned int size, int flags, unsigned int pid) 110{ 111 unsigned int tsize, lz; 112 113 asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size)); 114 tsize = 21 - lz; 115 116#ifdef CONFIG_SMP 117 if ((flags & _PAGE_NO_CACHE) == 0) 118 flags |= _PAGE_COHERENT; 119#endif 120 121 TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index) | MAS0_NV(index+1); 122 TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | MAS1_TID(pid); 123 TLBCAM[index].MAS2 = virt & PAGE_MASK; 124 125 TLBCAM[index].MAS2 |= (flags & _PAGE_WRITETHRU) ? MAS2_W : 0; 126 TLBCAM[index].MAS2 |= (flags & _PAGE_NO_CACHE) ? MAS2_I : 0; 127 TLBCAM[index].MAS2 |= (flags & _PAGE_COHERENT) ? MAS2_M : 0; 128 TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; 129 TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; 130 131 TLBCAM[index].MAS3 = (phys & PAGE_MASK) | MAS3_SX | MAS3_SR; 132 TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); 133 134#ifndef CONFIG_KGDB /* want user access for breakpoints */ 135 if (flags & _PAGE_USER) { 136 TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR; 137 TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0); 138 } 139#else 140 TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR; 141 TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0); 142#endif 143 144 tlbcam_addrs[index].start = virt; 145 tlbcam_addrs[index].limit = virt + size - 1; 146 tlbcam_addrs[index].phys = phys; 147 148 loadcam_entry(index); 149} 150 151void invalidate_tlbcam_entry(int index) 152{ 153 TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index); 154 TLBCAM[index].MAS1 = ~MAS1_VALID; 155 156 loadcam_entry(index); 157} 158 159unsigned long __init mmu_mapin_ram(void) 160{ 161 unsigned long virt = PAGE_OFFSET; 162 phys_addr_t phys = memstart_addr; 163 164 while (cam[tlbcam_index] && tlbcam_index < ARRAY_SIZE(cam)) { 165 settlbcam(tlbcam_index, virt, phys, cam[tlbcam_index], _PAGE_KERNEL, 0); 166 virt += cam[tlbcam_index]; 167 phys += cam[tlbcam_index]; 168 tlbcam_index++; 169 } 170 171 return virt - PAGE_OFFSET; 172} 173 174/* 175 * MMU_init_hw does the chip-specific initialization of the MMU hardware. 176 */ 177void __init MMU_init_hw(void) 178{ 179 flush_instruction_cache(); 180} 181 182void __init 183adjust_total_lowmem(void) 184{ 185 phys_addr_t ram; 186 unsigned int max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xff; 187 char buf[ARRAY_SIZE(cam) * 5 + 1], *p = buf; 188 int i; 189 unsigned long virt = PAGE_OFFSET & 0xffffffffUL; 190 unsigned long phys = memstart_addr & 0xffffffffUL; 191 192 /* Convert (4^max) kB to (2^max) bytes */ 193 max_cam = max_cam * 2 + 10; 194 195 /* adjust lowmem size to __max_low_memory */ 196 ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); 197 198 /* Calculate CAM values */ 199 __max_low_memory = 0; 200 for (i = 0; ram && i < ARRAY_SIZE(cam); i++) { 201 unsigned int camsize = __ilog2(ram) & ~1U; 202 unsigned int align = __ffs(virt | phys) & ~1U; 203 204 if (camsize > align) 205 camsize = align; 206 if (camsize > max_cam) 207 camsize = max_cam; 208 209 cam[i] = 1UL << camsize; 210 ram -= cam[i]; 211 __max_low_memory += cam[i]; 212 virt += cam[i]; 213 phys += cam[i]; 214 215 p += sprintf(p, "%lu/", cam[i] >> 20); 216 } 217 for (; i < ARRAY_SIZE(cam); i++) 218 p += sprintf(p, "0/"); 219 p[-1] = '\0'; 220 221 pr_info("Memory CAM mapping: %s Mb, residual: %dMb\n", buf, 222 (unsigned int)((total_lowmem - __max_low_memory) >> 20)); 223 __initial_memory_limit_addr = memstart_addr + __max_low_memory; 224} 225