]> Git Repo - linux.git/blob - arch/powerpc/mm/8xx_mmu.c
doc:process: add links where missing
[linux.git] / arch / powerpc / mm / 8xx_mmu.c
1 /*
2  * This file contains the routines for initializing the MMU
3  * on the 8xx series of chips.
4  *  -- christophe
5  *
6  *  Derived from arch/powerpc/mm/40x_mmu.c:
7  *
8  *  This program is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU General Public License
10  *  as published by the Free Software Foundation; either version
11  *  2 of the License, or (at your option) any later version.
12  *
13  */
14
15 #include <linux/memblock.h>
16 #include <linux/mmu_context.h>
17 #include <asm/fixmap.h>
18 #include <asm/code-patching.h>
19
20 #include "mmu_decl.h"
21
22 #define IMMR_SIZE (FIX_IMMR_SIZE << PAGE_SHIFT)
23
24 extern int __map_without_ltlbs;
25
26 static unsigned long block_mapped_ram;
27
28 /*
29  * Return PA for this VA if it is in an area mapped with LTLBs.
30  * Otherwise, returns 0
31  */
32 phys_addr_t v_block_mapped(unsigned long va)
33 {
34         unsigned long p = PHYS_IMMR_BASE;
35
36         if (__map_without_ltlbs)
37                 return 0;
38         if (va >= VIRT_IMMR_BASE && va < VIRT_IMMR_BASE + IMMR_SIZE)
39                 return p + va - VIRT_IMMR_BASE;
40         if (va >= PAGE_OFFSET && va < PAGE_OFFSET + block_mapped_ram)
41                 return __pa(va);
42         return 0;
43 }
44
45 /*
46  * Return VA for a given PA mapped with LTLBs or 0 if not mapped
47  */
48 unsigned long p_block_mapped(phys_addr_t pa)
49 {
50         unsigned long p = PHYS_IMMR_BASE;
51
52         if (__map_without_ltlbs)
53                 return 0;
54         if (pa >= p && pa < p + IMMR_SIZE)
55                 return VIRT_IMMR_BASE + pa - p;
56         if (pa < block_mapped_ram)
57                 return (unsigned long)__va(pa);
58         return 0;
59 }
60
61 #define LARGE_PAGE_SIZE_8M      (1<<23)
62
63 /*
64  * MMU_init_hw does the chip-specific initialization of the MMU hardware.
65  */
66 void __init MMU_init_hw(void)
67 {
68         /* PIN up to the 3 first 8Mb after IMMR in DTLB table */
69 #ifdef CONFIG_PIN_TLB_DATA
70         unsigned long ctr = mfspr(SPRN_MD_CTR) & 0xfe000000;
71         unsigned long flags = 0xf0 | MD_SPS16K | _PAGE_SH | _PAGE_DIRTY;
72 #ifdef CONFIG_PIN_TLB_IMMR
73         int i = 29;
74 #else
75         int i = 28;
76 #endif
77         unsigned long addr = 0;
78         unsigned long mem = total_lowmem;
79
80         for (; i < 32 && mem >= LARGE_PAGE_SIZE_8M; i++) {
81                 mtspr(SPRN_MD_CTR, ctr | (i << 8));
82                 mtspr(SPRN_MD_EPN, (unsigned long)__va(addr) | MD_EVALID);
83                 mtspr(SPRN_MD_TWC, MD_PS8MEG | MD_SVALID);
84                 mtspr(SPRN_MD_RPN, addr | flags | _PAGE_PRESENT);
85                 addr += LARGE_PAGE_SIZE_8M;
86                 mem -= LARGE_PAGE_SIZE_8M;
87         }
88 #endif
89 }
90
91 static void __init mmu_mapin_immr(void)
92 {
93         unsigned long p = PHYS_IMMR_BASE;
94         unsigned long v = VIRT_IMMR_BASE;
95         int offset;
96
97         for (offset = 0; offset < IMMR_SIZE; offset += PAGE_SIZE)
98                 map_kernel_page(v + offset, p + offset, PAGE_KERNEL_NCG);
99 }
100
101 static void __init mmu_patch_cmp_limit(s32 *site, unsigned long mapped)
102 {
103         unsigned int instr = *(unsigned int *)patch_site_addr(site);
104
105         instr &= 0xffff0000;
106         instr |= (unsigned long)__va(mapped) >> 16;
107         patch_instruction_site(site, instr);
108 }
109
110 unsigned long __init mmu_mapin_ram(unsigned long top)
111 {
112         unsigned long mapped;
113
114         if (__map_without_ltlbs) {
115                 mapped = 0;
116                 mmu_mapin_immr();
117 #ifndef CONFIG_PIN_TLB_IMMR
118                 patch_instruction_site(&patch__dtlbmiss_immr_jmp, PPC_INST_NOP);
119 #endif
120 #ifndef CONFIG_PIN_TLB_TEXT
121                 mmu_patch_cmp_limit(&patch__itlbmiss_linmem_top, 0);
122 #endif
123         } else {
124                 mapped = top & ~(LARGE_PAGE_SIZE_8M - 1);
125         }
126
127         mmu_patch_cmp_limit(&patch__dtlbmiss_linmem_top, mapped);
128         mmu_patch_cmp_limit(&patch__fixupdar_linmem_top, mapped);
129
130         /* If the size of RAM is not an exact power of two, we may not
131          * have covered RAM in its entirety with 8 MiB
132          * pages. Consequently, restrict the top end of RAM currently
133          * allocable so that calls to the MEMBLOCK to allocate PTEs for "tail"
134          * coverage with normal-sized pages (or other reasons) do not
135          * attempt to allocate outside the allowed range.
136          */
137         if (mapped)
138                 memblock_set_current_limit(mapped);
139
140         block_mapped_ram = mapped;
141
142         return mapped;
143 }
144
145 void __init setup_initial_memory_limit(phys_addr_t first_memblock_base,
146                                        phys_addr_t first_memblock_size)
147 {
148         /* We don't currently support the first MEMBLOCK not mapping 0
149          * physical on those processors
150          */
151         BUG_ON(first_memblock_base != 0);
152
153         /* 8xx can only access 24MB at the moment */
154         memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01800000));
155 }
156
157 /*
158  * Set up to use a given MMU context.
159  * id is context number, pgd is PGD pointer.
160  *
161  * We place the physical address of the new task page directory loaded
162  * into the MMU base register, and set the ASID compare register with
163  * the new "context."
164  */
165 void set_context(unsigned long id, pgd_t *pgd)
166 {
167         s16 offset = (s16)(__pa(swapper_pg_dir));
168
169 #ifdef CONFIG_BDI_SWITCH
170         pgd_t   **ptr = *(pgd_t ***)(KERNELBASE + 0xf0);
171
172         /* Context switch the PTE pointer for the Abatron BDI2000.
173          * The PGDIR is passed as second argument.
174          */
175         *(ptr + 1) = pgd;
176 #endif
177
178         /* Register M_TW will contain base address of level 1 table minus the
179          * lower part of the kernel PGDIR base address, so that all accesses to
180          * level 1 table are done relative to lower part of kernel PGDIR base
181          * address.
182          */
183         mtspr(SPRN_M_TW, __pa(pgd) - offset);
184
185         /* Update context */
186         mtspr(SPRN_M_CASID, id - 1);
187         /* sync */
188         mb();
189 }
190
191 void flush_instruction_cache(void)
192 {
193         isync();
194         mtspr(SPRN_IC_CST, IDC_INVALL);
195         isync();
196 }
This page took 0.042305 seconds and 4 git commands to generate.