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.c83
1 files changed, 63 insertions, 20 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index c5eea6ae12ca..053dbacac56b 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -7,6 +7,16 @@
7 * 7 *
8 * Copyright (C) 2004,2005 by Thiemo Seufer 8 * Copyright (C) 2004,2005 by Thiemo Seufer
9 * Copyright (C) 2005 Maciej W. Rozycki 9 * Copyright (C) 2005 Maciej W. Rozycki
10 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
11 *
12 * ... and the days got worse and worse and now you see
13 * I've gone completly out of my mind.
14 *
15 * They're coming to take me a away haha
16 * they're coming to take me a away hoho hihi haha
17 * to the funny farm where code is beautiful all the time ...
18 *
19 * (Condolences to Napoleon XIV)
10 */ 20 */
11 21
12#include <stdarg.h> 22#include <stdarg.h>
@@ -68,6 +78,7 @@ enum fields
68 BIMM = 0x040, 78 BIMM = 0x040,
69 JIMM = 0x080, 79 JIMM = 0x080,
70 FUNC = 0x100, 80 FUNC = 0x100,
81 SET = 0x200
71}; 82};
72 83
73#define OP_MASK 0x2f 84#define OP_MASK 0x2f
@@ -86,6 +97,8 @@ enum fields
86#define JIMM_SH 0 97#define JIMM_SH 0
87#define FUNC_MASK 0x2f 98#define FUNC_MASK 0x2f
88#define FUNC_SH 0 99#define FUNC_SH 0
100#define SET_MASK 0x7
101#define SET_SH 0
89 102
90enum opcode { 103enum opcode {
91 insn_invalid, 104 insn_invalid,
@@ -129,8 +142,8 @@ static __initdata struct insn insn_table[] = {
129 { insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM }, 142 { insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM },
130 { insn_daddiu, M(daddiu_op,0,0,0,0,0), RS | RT | SIMM }, 143 { insn_daddiu, M(daddiu_op,0,0,0,0,0), RS | RT | SIMM },
131 { insn_daddu, M(spec_op,0,0,0,0,daddu_op), RS | RT | RD }, 144 { insn_daddu, M(spec_op,0,0,0,0,daddu_op), RS | RT | RD },
132 { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD }, 145 { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD | SET},
133 { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD }, 146 { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD | SET},
134 { insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE }, 147 { insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE },
135 { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE }, 148 { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE },
136 { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE }, 149 { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE },
@@ -145,8 +158,8 @@ static __initdata struct insn insn_table[] = {
145 { insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM }, 158 { insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM },
146 { insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM }, 159 { insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM },
147 { insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM }, 160 { insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM },
148 { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD }, 161 { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD | SET},
149 { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD }, 162 { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD | SET},
150 { insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM }, 163 { insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM },
151 { insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 }, 164 { insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 },
152 { insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM }, 165 { insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM },
@@ -242,6 +255,14 @@ static __init u32 build_func(u32 arg)
242 return arg & FUNC_MASK; 255 return arg & FUNC_MASK;
243} 256}
244 257
258static __init u32 build_set(u32 arg)
259{
260 if (arg & ~SET_MASK)
261 printk(KERN_WARNING "TLB synthesizer field overflow\n");
262
263 return arg & SET_MASK;
264}
265
245/* 266/*
246 * The order of opcode arguments is implicitly left to right, 267 * The order of opcode arguments is implicitly left to right,
247 * starting with RS and ending with FUNC or IMM. 268 * starting with RS and ending with FUNC or IMM.
@@ -273,6 +294,7 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...)
273 if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32)); 294 if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
274 if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32)); 295 if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
275 if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32)); 296 if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
297 if (ip->fields & SET) op |= build_set(va_arg(ap, u32));
276 va_end(ap); 298 va_end(ap);
277 299
278 **buf = op; 300 **buf = op;
@@ -358,8 +380,8 @@ I_u1s2(_bgezl);
358I_u1s2(_bltz); 380I_u1s2(_bltz);
359I_u1s2(_bltzl); 381I_u1s2(_bltzl);
360I_u1u2s3(_bne); 382I_u1u2s3(_bne);
361I_u1u2(_dmfc0); 383I_u1u2u3(_dmfc0);
362I_u1u2(_dmtc0); 384I_u1u2u3(_dmtc0);
363I_u2u1s3(_daddiu); 385I_u2u1s3(_daddiu);
364I_u3u1u2(_daddu); 386I_u3u1u2(_daddu);
365I_u2u1u3(_dsll); 387I_u2u1u3(_dsll);
@@ -376,8 +398,8 @@ I_u2s3u1(_ll);
376I_u2s3u1(_lld); 398I_u2s3u1(_lld);
377I_u1s2(_lui); 399I_u1s2(_lui);
378I_u2s3u1(_lw); 400I_u2s3u1(_lw);
379I_u1u2(_mfc0); 401I_u1u2u3(_mfc0);
380I_u1u2(_mtc0); 402I_u1u2u3(_mtc0);
381I_u2u1u3(_ori); 403I_u2u1u3(_ori);
382I_0(_rfe); 404I_0(_rfe);
383I_u2s3u1(_sc); 405I_u2s3u1(_sc);
@@ -451,8 +473,8 @@ L_LA(_r3000_write_probe_fail)
451# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh) 473# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
452# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh) 474# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
453# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh) 475# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
454# define i_MFC0(buf, rt, rd) i_dmfc0(buf, rt, rd) 476# define i_MFC0(buf, rt, rd...) i_dmfc0(buf, rt, rd)
455# define i_MTC0(buf, rt, rd) i_dmtc0(buf, rt, rd) 477# define i_MTC0(buf, rt, rd...) i_dmtc0(buf, rt, rd)
456# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val) 478# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
457# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd) 479# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
458# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd) 480# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
@@ -464,8 +486,8 @@ L_LA(_r3000_write_probe_fail)
464# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh) 486# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
465# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh) 487# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
466# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh) 488# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
467# define i_MFC0(buf, rt, rd) i_mfc0(buf, rt, rd) 489# define i_MFC0(buf, rt, rd...) i_mfc0(buf, rt, rd)
468# define i_MTC0(buf, rt, rd) i_mtc0(buf, rt, rd) 490# define i_MTC0(buf, rt, rd...) i_mtc0(buf, rt, rd)
469# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val) 491# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
470# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd) 492# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
471# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd) 493# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
@@ -670,14 +692,15 @@ static void __init il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
670#define K1 27 692#define K1 27
671 693
672/* Some CP0 registers */ 694/* Some CP0 registers */
673#define C0_INDEX 0 695#define C0_INDEX 0, 0
674#define C0_ENTRYLO0 2 696#define C0_ENTRYLO0 2, 0
675#define C0_ENTRYLO1 3 697#define C0_TCBIND 2, 2
676#define C0_CONTEXT 4 698#define C0_ENTRYLO1 3, 0
677#define C0_BADVADDR 8 699#define C0_CONTEXT 4, 0
678#define C0_ENTRYHI 10 700#define C0_BADVADDR 8, 0
679#define C0_EPC 14 701#define C0_ENTRYHI 10, 0
680#define C0_XCONTEXT 20 702#define C0_EPC 14, 0
703#define C0_XCONTEXT 20, 0
681 704
682#ifdef CONFIG_64BIT 705#ifdef CONFIG_64BIT
683# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT) 706# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
@@ -951,12 +974,20 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
951 /* No i_nop needed here, since the next insn doesn't touch TMP. */ 974 /* No i_nop needed here, since the next insn doesn't touch TMP. */
952 975
953#ifdef CONFIG_SMP 976#ifdef CONFIG_SMP
977# ifdef CONFIG_MIPS_MT_SMTC
978 /*
979 * SMTC uses TCBind value as "CPU" index
980 */
981 i_mfc0(p, ptr, C0_TCBIND);
982 i_dsrl(p, ptr, ptr, 19);
983# else
954 /* 984 /*
955 * 64 bit SMP running in XKPHYS has smp_processor_id() << 3 985 * 64 bit SMP running in XKPHYS has smp_processor_id() << 3
956 * stored in CONTEXT. 986 * stored in CONTEXT.
957 */ 987 */
958 i_dmfc0(p, ptr, C0_CONTEXT); 988 i_dmfc0(p, ptr, C0_CONTEXT);
959 i_dsrl(p, ptr, ptr, 23); 989 i_dsrl(p, ptr, ptr, 23);
990#endif
960 i_LA_mostly(p, tmp, pgdc); 991 i_LA_mostly(p, tmp, pgdc);
961 i_daddu(p, ptr, ptr, tmp); 992 i_daddu(p, ptr, ptr, tmp);
962 i_dmfc0(p, tmp, C0_BADVADDR); 993 i_dmfc0(p, tmp, C0_BADVADDR);
@@ -1014,9 +1045,21 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
1014 1045
1015 /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */ 1046 /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
1016#ifdef CONFIG_SMP 1047#ifdef CONFIG_SMP
1048#ifdef CONFIG_MIPS_MT_SMTC
1049 /*
1050 * SMTC uses TCBind value as "CPU" index
1051 */
1052 i_mfc0(p, ptr, C0_TCBIND);
1053 i_LA_mostly(p, tmp, pgdc);
1054 i_srl(p, ptr, ptr, 19);
1055#else
1056 /*
1057 * smp_processor_id() << 3 is stored in CONTEXT.
1058 */
1017 i_mfc0(p, ptr, C0_CONTEXT); 1059 i_mfc0(p, ptr, C0_CONTEXT);
1018 i_LA_mostly(p, tmp, pgdc); 1060 i_LA_mostly(p, tmp, pgdc);
1019 i_srl(p, ptr, ptr, 23); 1061 i_srl(p, ptr, ptr, 23);
1062#endif
1020 i_addu(p, ptr, tmp, ptr); 1063 i_addu(p, ptr, tmp, ptr);
1021#else 1064#else
1022 i_LA_mostly(p, ptr, pgdc); 1065 i_LA_mostly(p, ptr, pgdc);