aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mm/tlbex.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/mm/tlbex.c')
-rw-r--r--arch/mips/mm/tlbex.c100
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;
305static int check_for_high_segbits __cpuinitdata; 306static int check_for_high_segbits __cpuinitdata;
306#endif 307#endif
307 308
309static 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) \
341do { \
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 */
350static 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
308static int check_for_high_segbits __cpuinitdata; 381static int check_for_high_segbits __cpuinitdata;
309 382
310static unsigned int kscratch_used_mask __cpuinitdata; 383static 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