diff options
author | Kumar Gala <galak@kernel.crashing.org> | 2009-10-15 13:49:01 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2009-11-20 17:45:33 -0500 |
commit | 8b27f0b61db57f5555fc2d3fc95c3ea9fd1a9d6c (patch) | |
tree | a1b1181a62555b2d76b1d63b31a873c42f26d4d6 /arch/powerpc/mm | |
parent | 5753c082f66eca5be81f6bda85c1718c5eea6ada (diff) |
powerpc/fsl-booke: Rework TLB CAM code
Re-write the code so its more standalone and fixed some issues:
* Bump'd # of CAM entries to 64 to support e500mc
* Make the code handle MAS7 properly
* Use pr_cont instead of creating a string as we go
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/fsl_booke_mmu.c | 132 | ||||
-rw-r--r-- | arch/powerpc/mm/mmu_decl.h | 11 |
2 files changed, 74 insertions, 69 deletions
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index dc93e95b256e..fcfcb6e976c7 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c | |||
@@ -54,26 +54,35 @@ | |||
54 | 54 | ||
55 | #include "mmu_decl.h" | 55 | #include "mmu_decl.h" |
56 | 56 | ||
57 | extern void loadcam_entry(unsigned int index); | ||
58 | unsigned int tlbcam_index; | 57 | unsigned int tlbcam_index; |
59 | static unsigned long cam[CONFIG_LOWMEM_CAM_NUM]; | ||
60 | 58 | ||
61 | #define NUM_TLBCAMS (16) | 59 | #define NUM_TLBCAMS (64) |
62 | 60 | ||
63 | #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) | 61 | #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) |
64 | #error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS" | 62 | #error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS" |
65 | #endif | 63 | #endif |
66 | 64 | ||
67 | struct tlbcam TLBCAM[NUM_TLBCAMS]; | 65 | struct tlbcam { |
66 | u32 MAS0; | ||
67 | u32 MAS1; | ||
68 | unsigned long MAS2; | ||
69 | u32 MAS3; | ||
70 | u32 MAS7; | ||
71 | } TLBCAM[NUM_TLBCAMS]; | ||
68 | 72 | ||
69 | struct tlbcamrange { | 73 | struct tlbcamrange { |
70 | unsigned long start; | 74 | unsigned long start; |
71 | unsigned long limit; | 75 | unsigned long limit; |
72 | phys_addr_t phys; | 76 | phys_addr_t phys; |
73 | } tlbcam_addrs[NUM_TLBCAMS]; | 77 | } tlbcam_addrs[NUM_TLBCAMS]; |
74 | 78 | ||
75 | extern unsigned int tlbcam_index; | 79 | extern unsigned int tlbcam_index; |
76 | 80 | ||
81 | unsigned long tlbcam_sz(int idx) | ||
82 | { | ||
83 | return tlbcam_addrs[idx].limit - tlbcam_addrs[idx].start + 1; | ||
84 | } | ||
85 | |||
77 | /* | 86 | /* |
78 | * Return PA for this VA if it is mapped by a CAM, or 0 | 87 | * Return PA for this VA if it is mapped by a CAM, or 0 |
79 | */ | 88 | */ |
@@ -94,23 +103,36 @@ unsigned long p_mapped_by_tlbcam(phys_addr_t pa) | |||
94 | int b; | 103 | int b; |
95 | for (b = 0; b < tlbcam_index; ++b) | 104 | for (b = 0; b < tlbcam_index; ++b) |
96 | if (pa >= tlbcam_addrs[b].phys | 105 | if (pa >= tlbcam_addrs[b].phys |
97 | && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) | 106 | && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) |
98 | +tlbcam_addrs[b].phys) | 107 | +tlbcam_addrs[b].phys) |
99 | return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); | 108 | return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); |
100 | return 0; | 109 | return 0; |
101 | } | 110 | } |
102 | 111 | ||
112 | void loadcam_entry(int idx) | ||
113 | { | ||
114 | mtspr(SPRN_MAS0, TLBCAM[idx].MAS0); | ||
115 | mtspr(SPRN_MAS1, TLBCAM[idx].MAS1); | ||
116 | mtspr(SPRN_MAS2, TLBCAM[idx].MAS2); | ||
117 | mtspr(SPRN_MAS3, TLBCAM[idx].MAS3); | ||
118 | |||
119 | if (cur_cpu_spec->cpu_features & MMU_FTR_BIG_PHYS) | ||
120 | mtspr(SPRN_MAS7, TLBCAM[idx].MAS7); | ||
121 | |||
122 | asm volatile("isync;tlbwe;isync" : : : "memory"); | ||
123 | } | ||
124 | |||
103 | /* | 125 | /* |
104 | * Set up one of the I/D BAT (block address translation) register pairs. | 126 | * 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 | 127 | * The parameters are not checked; in particular size must be a power |
106 | * of 4 between 4k and 256M. | 128 | * of 4 between 4k and 256M. |
107 | */ | 129 | */ |
108 | void settlbcam(int index, unsigned long virt, phys_addr_t phys, | 130 | static void settlbcam(int index, unsigned long virt, phys_addr_t phys, |
109 | unsigned int size, int flags, unsigned int pid) | 131 | unsigned long size, unsigned long flags, unsigned int pid) |
110 | { | 132 | { |
111 | unsigned int tsize, lz; | 133 | unsigned int tsize, lz; |
112 | 134 | ||
113 | asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size)); | 135 | asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (size)); |
114 | tsize = 21 - lz; | 136 | tsize = 21 - lz; |
115 | 137 | ||
116 | #ifdef CONFIG_SMP | 138 | #ifdef CONFIG_SMP |
@@ -128,8 +150,10 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys, | |||
128 | TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; | 150 | TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; |
129 | TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; | 151 | TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; |
130 | 152 | ||
131 | TLBCAM[index].MAS3 = (phys & PAGE_MASK) | MAS3_SX | MAS3_SR; | 153 | TLBCAM[index].MAS3 = (phys & MAS3_RPN) | MAS3_SX | MAS3_SR; |
132 | TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); | 154 | TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); |
155 | if (cur_cpu_spec->cpu_features & MMU_FTR_BIG_PHYS) | ||
156 | TLBCAM[index].MAS7 = (u64)phys >> 32; | ||
133 | 157 | ||
134 | #ifndef CONFIG_KGDB /* want user access for breakpoints */ | 158 | #ifndef CONFIG_KGDB /* want user access for breakpoints */ |
135 | if (flags & _PAGE_USER) { | 159 | if (flags & _PAGE_USER) { |
@@ -148,27 +172,44 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys, | |||
148 | loadcam_entry(index); | 172 | loadcam_entry(index); |
149 | } | 173 | } |
150 | 174 | ||
151 | void invalidate_tlbcam_entry(int index) | 175 | unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) |
152 | { | ||
153 | TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index); | ||
154 | TLBCAM[index].MAS1 = ~MAS1_VALID; | ||
155 | |||
156 | loadcam_entry(index); | ||
157 | } | ||
158 | |||
159 | unsigned long __init mmu_mapin_ram(void) | ||
160 | { | 176 | { |
177 | int i; | ||
161 | unsigned long virt = PAGE_OFFSET; | 178 | unsigned long virt = PAGE_OFFSET; |
162 | phys_addr_t phys = memstart_addr; | 179 | phys_addr_t phys = memstart_addr; |
180 | unsigned long amount_mapped = 0; | ||
181 | unsigned long max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf; | ||
182 | |||
183 | /* Convert (4^max) kB to (2^max) bytes */ | ||
184 | max_cam = max_cam * 2 + 10; | ||
163 | 185 | ||
164 | while (tlbcam_index < ARRAY_SIZE(cam) && cam[tlbcam_index]) { | 186 | /* Calculate CAM values */ |
165 | settlbcam(tlbcam_index, virt, phys, cam[tlbcam_index], PAGE_KERNEL_X, 0); | 187 | for (i = 0; ram && i < max_cam_idx; i++) { |
166 | virt += cam[tlbcam_index]; | 188 | unsigned int camsize = __ilog2(ram) & ~1U; |
167 | phys += cam[tlbcam_index]; | 189 | unsigned int align = __ffs(virt | phys) & ~1U; |
168 | tlbcam_index++; | 190 | unsigned long cam_sz; |
191 | |||
192 | if (camsize > align) | ||
193 | camsize = align; | ||
194 | if (camsize > max_cam) | ||
195 | camsize = max_cam; | ||
196 | |||
197 | cam_sz = 1UL << camsize; | ||
198 | settlbcam(i, virt, phys, cam_sz, PAGE_KERNEL_X, 0); | ||
199 | |||
200 | ram -= cam_sz; | ||
201 | amount_mapped += cam_sz; | ||
202 | virt += cam_sz; | ||
203 | phys += cam_sz; | ||
169 | } | 204 | } |
205 | tlbcam_index = i; | ||
206 | |||
207 | return amount_mapped; | ||
208 | } | ||
170 | 209 | ||
171 | return virt - PAGE_OFFSET; | 210 | unsigned long __init mmu_mapin_ram(void) |
211 | { | ||
212 | return tlbcam_addrs[tlbcam_index - 1].limit - PAGE_OFFSET + 1; | ||
172 | } | 213 | } |
173 | 214 | ||
174 | /* | 215 | /* |
@@ -179,46 +220,21 @@ void __init MMU_init_hw(void) | |||
179 | flush_instruction_cache(); | 220 | flush_instruction_cache(); |
180 | } | 221 | } |
181 | 222 | ||
182 | void __init | 223 | void __init adjust_total_lowmem(void) |
183 | adjust_total_lowmem(void) | ||
184 | { | 224 | { |
185 | phys_addr_t ram; | 225 | unsigned long ram; |
186 | unsigned int max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xff; | ||
187 | char buf[ARRAY_SIZE(cam) * 5 + 1], *p = buf; | ||
188 | int i; | 226 | 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 | 227 | ||
195 | /* adjust lowmem size to __max_low_memory */ | 228 | /* adjust lowmem size to __max_low_memory */ |
196 | ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); | 229 | ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); |
197 | 230 | ||
198 | /* Calculate CAM values */ | 231 | __max_low_memory = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM); |
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 | 232 | ||
204 | if (camsize > align) | 233 | pr_info("Memory CAM mapping: "); |
205 | camsize = align; | 234 | for (i = 0; i < tlbcam_index - 1; i++) |
206 | if (camsize > max_cam) | 235 | pr_cont("%lu/", tlbcam_sz(i) >> 20); |
207 | camsize = max_cam; | 236 | pr_cont("%lu Mb, residual: %dMb\n", tlbcam_sz(tlbcam_index - 1) >> 20, |
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)); | 237 | (unsigned int)((total_lowmem - __max_low_memory) >> 20)); |
238 | |||
223 | __initial_memory_limit_addr = memstart_addr + __max_low_memory; | 239 | __initial_memory_limit_addr = memstart_addr + __max_low_memory; |
224 | } | 240 | } |
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index d2e5321d5ea6..e27a990af42d 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h | |||
@@ -98,21 +98,10 @@ extern void _tlbia(void); | |||
98 | 98 | ||
99 | #ifdef CONFIG_PPC32 | 99 | #ifdef CONFIG_PPC32 |
100 | 100 | ||
101 | struct tlbcam { | ||
102 | u32 MAS0; | ||
103 | u32 MAS1; | ||
104 | u32 MAS2; | ||
105 | u32 MAS3; | ||
106 | u32 MAS7; | ||
107 | }; | ||
108 | |||
109 | extern void mapin_ram(void); | 101 | extern void mapin_ram(void); |
110 | extern int map_page(unsigned long va, phys_addr_t pa, int flags); | 102 | extern int map_page(unsigned long va, phys_addr_t pa, int flags); |
111 | extern void setbat(int index, unsigned long virt, phys_addr_t phys, | 103 | extern void setbat(int index, unsigned long virt, phys_addr_t phys, |
112 | unsigned int size, int flags); | 104 | unsigned int size, int flags); |
113 | extern void settlbcam(int index, unsigned long virt, phys_addr_t phys, | ||
114 | unsigned int size, int flags, unsigned int pid); | ||
115 | extern void invalidate_tlbcam_entry(int index); | ||
116 | 105 | ||
117 | extern int __map_without_bats; | 106 | extern int __map_without_bats; |
118 | extern unsigned long ioremap_base; | 107 | extern unsigned long ioremap_base; |