diff options
Diffstat (limited to 'arch/mips/mm/tlbex.c')
-rw-r--r-- | arch/mips/mm/tlbex.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 3b3822afb059..4d46d3787576 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/cache.h> | 30 | #include <linux/cache.h> |
31 | 31 | ||
32 | #include <asm/mmu_context.h> | ||
32 | #include <asm/cacheflush.h> | 33 | #include <asm/cacheflush.h> |
33 | #include <asm/pgtable.h> | 34 | #include <asm/pgtable.h> |
34 | #include <asm/war.h> | 35 | #include <asm/war.h> |
@@ -305,6 +306,78 @@ static struct uasm_reloc relocs[128] __cpuinitdata; | |||
305 | static int check_for_high_segbits __cpuinitdata; | 306 | static int check_for_high_segbits __cpuinitdata; |
306 | #endif | 307 | #endif |
307 | 308 | ||
309 | static void __cpuinit insn_fixup(unsigned int **start, unsigned int **stop, | ||
310 | unsigned int i_const) | ||
311 | { | ||
312 | unsigned int **p; | ||
313 | |||
314 | for (p = start; p < stop; p++) { | ||
315 | #ifndef CONFIG_CPU_MICROMIPS | ||
316 | unsigned int *ip; | ||
317 | |||
318 | ip = *p; | ||
319 | *ip = (*ip & 0xffff0000) | i_const; | ||
320 | #else | ||
321 | unsigned short *ip; | ||
322 | |||
323 | ip = ((unsigned short *)((unsigned int)*p - 1)); | ||
324 | if ((*ip & 0xf000) == 0x4000) { | ||
325 | *ip &= 0xfff1; | ||
326 | *ip |= (i_const << 1); | ||
327 | } else if ((*ip & 0xf000) == 0x6000) { | ||
328 | *ip &= 0xfff1; | ||
329 | *ip |= ((i_const >> 2) << 1); | ||
330 | } else { | ||
331 | ip++; | ||
332 | *ip = i_const; | ||
333 | } | ||
334 | #endif | ||
335 | local_flush_icache_range((unsigned long)ip, | ||
336 | (unsigned long)ip + sizeof(*ip)); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | #define asid_insn_fixup(section, const) \ | ||
341 | do { \ | ||
342 | extern unsigned int *__start_ ## section; \ | ||
343 | extern unsigned int *__stop_ ## section; \ | ||
344 | insn_fixup(&__start_ ## section, &__stop_ ## section, const); \ | ||
345 | } while(0) | ||
346 | |||
347 | /* | ||
348 | * Caller is assumed to flush the caches before the first context switch. | ||
349 | */ | ||
350 | static void __cpuinit setup_asid(unsigned int inc, unsigned int mask, | ||
351 | unsigned int version_mask, | ||
352 | unsigned int first_version) | ||
353 | { | ||
354 | extern asmlinkage void handle_ri_rdhwr_vivt(void); | ||
355 | unsigned long *vivt_exc; | ||
356 | |||
357 | #ifdef CONFIG_CPU_MICROMIPS | ||
358 | /* | ||
359 | * Worst case optimised microMIPS addiu instructions support | ||
360 | * only a 3-bit immediate value. | ||
361 | */ | ||
362 | if(inc > 7) | ||
363 | panic("Invalid ASID increment value!"); | ||
364 | #endif | ||
365 | asid_insn_fixup(__asid_inc, inc); | ||
366 | asid_insn_fixup(__asid_mask, mask); | ||
367 | asid_insn_fixup(__asid_version_mask, version_mask); | ||
368 | asid_insn_fixup(__asid_first_version, first_version); | ||
369 | |||
370 | /* Patch up the 'handle_ri_rdhwr_vivt' handler. */ | ||
371 | vivt_exc = (unsigned long *) &handle_ri_rdhwr_vivt; | ||
372 | #ifdef CONFIG_CPU_MICROMIPS | ||
373 | vivt_exc = (unsigned long *)((unsigned long) vivt_exc - 1); | ||
374 | #endif | ||
375 | vivt_exc++; | ||
376 | *vivt_exc = (*vivt_exc & ~mask) | mask; | ||
377 | |||
378 | current_cpu_data.asid_cache = first_version; | ||
379 | } | ||
380 | |||
308 | static int check_for_high_segbits __cpuinitdata; | 381 | static int check_for_high_segbits __cpuinitdata; |
309 | 382 | ||
310 | static unsigned int kscratch_used_mask __cpuinitdata; | 383 | static unsigned int kscratch_used_mask __cpuinitdata; |
@@ -2030,6 +2103,13 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
2030 | 2103 | ||
2031 | uasm_l_nopage_tlbl(&l, p); | 2104 | uasm_l_nopage_tlbl(&l, p); |
2032 | build_restore_work_registers(&p); | 2105 | build_restore_work_registers(&p); |
2106 | #ifdef CONFIG_CPU_MICROMIPS | ||
2107 | if ((unsigned long)tlb_do_page_fault_0 & 1) { | ||
2108 | uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_0)); | ||
2109 | uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_0)); | ||
2110 | uasm_i_jr(&p, K0); | ||
2111 | } else | ||
2112 | #endif | ||
2033 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); | 2113 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); |
2034 | uasm_i_nop(&p); | 2114 | uasm_i_nop(&p); |
2035 | 2115 | ||
@@ -2077,6 +2157,13 @@ static void __cpuinit build_r4000_tlb_store_handler(void) | |||
2077 | 2157 | ||
2078 | uasm_l_nopage_tlbs(&l, p); | 2158 | uasm_l_nopage_tlbs(&l, p); |
2079 | build_restore_work_registers(&p); | 2159 | build_restore_work_registers(&p); |
2160 | #ifdef CONFIG_CPU_MICROMIPS | ||
2161 | if ((unsigned long)tlb_do_page_fault_1 & 1) { | ||
2162 | uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1)); | ||
2163 | uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1)); | ||
2164 | uasm_i_jr(&p, K0); | ||
2165 | } else | ||
2166 | #endif | ||
2080 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 2167 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |
2081 | uasm_i_nop(&p); | 2168 | uasm_i_nop(&p); |
2082 | 2169 | ||
@@ -2125,6 +2212,13 @@ static void __cpuinit build_r4000_tlb_modify_handler(void) | |||
2125 | 2212 | ||
2126 | uasm_l_nopage_tlbm(&l, p); | 2213 | uasm_l_nopage_tlbm(&l, p); |
2127 | build_restore_work_registers(&p); | 2214 | build_restore_work_registers(&p); |
2215 | #ifdef CONFIG_CPU_MICROMIPS | ||
2216 | if ((unsigned long)tlb_do_page_fault_1 & 1) { | ||
2217 | uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1)); | ||
2218 | uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1)); | ||
2219 | uasm_i_jr(&p, K0); | ||
2220 | } else | ||
2221 | #endif | ||
2128 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 2222 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |
2129 | uasm_i_nop(&p); | 2223 | uasm_i_nop(&p); |
2130 | 2224 | ||
@@ -2162,6 +2256,7 @@ void __cpuinit build_tlb_refill_handler(void) | |||
2162 | case CPU_TX3922: | 2256 | case CPU_TX3922: |
2163 | case CPU_TX3927: | 2257 | case CPU_TX3927: |
2164 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT | 2258 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT |
2259 | setup_asid(0x40, 0xfc0, 0xf000, ASID_FIRST_VERSION_R3000); | ||
2165 | if (cpu_has_local_ebase) | 2260 | if (cpu_has_local_ebase) |
2166 | build_r3000_tlb_refill_handler(); | 2261 | build_r3000_tlb_refill_handler(); |
2167 | if (!run_once) { | 2262 | if (!run_once) { |
@@ -2187,6 +2282,11 @@ void __cpuinit build_tlb_refill_handler(void) | |||
2187 | break; | 2282 | break; |
2188 | 2283 | ||
2189 | default: | 2284 | default: |
2285 | #ifndef CONFIG_MIPS_MT_SMTC | ||
2286 | setup_asid(0x1, 0xff, 0xff00, ASID_FIRST_VERSION_R4000); | ||
2287 | #else | ||
2288 | setup_asid(0x1, smtc_asid_mask, 0xff00, ASID_FIRST_VERSION_R4000); | ||
2289 | #endif | ||
2190 | if (!run_once) { | 2290 | if (!run_once) { |
2191 | scratch_reg = allocate_kscratch(); | 2291 | scratch_reg = allocate_kscratch(); |
2192 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | 2292 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT |