diff options
Diffstat (limited to 'arch/mips/mm/tlbex.c')
| -rw-r--r-- | arch/mips/mm/tlbex.c | 87 |
1 files changed, 65 insertions, 22 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 599b3c297186..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 | ||
| 90 | enum opcode { | 103 | enum 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 | ||
| 258 | static __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); | |||
| 358 | I_u1s2(_bltz); | 380 | I_u1s2(_bltz); |
| 359 | I_u1s2(_bltzl); | 381 | I_u1s2(_bltzl); |
| 360 | I_u1u2s3(_bne); | 382 | I_u1u2s3(_bne); |
| 361 | I_u1u2(_dmfc0); | 383 | I_u1u2u3(_dmfc0); |
| 362 | I_u1u2(_dmtc0); | 384 | I_u1u2u3(_dmtc0); |
| 363 | I_u2u1s3(_daddiu); | 385 | I_u2u1s3(_daddiu); |
| 364 | I_u3u1u2(_daddu); | 386 | I_u3u1u2(_daddu); |
| 365 | I_u2u1u3(_dsll); | 387 | I_u2u1u3(_dsll); |
| @@ -376,8 +398,8 @@ I_u2s3u1(_ll); | |||
| 376 | I_u2s3u1(_lld); | 398 | I_u2s3u1(_lld); |
| 377 | I_u1s2(_lui); | 399 | I_u1s2(_lui); |
| 378 | I_u2s3u1(_lw); | 400 | I_u2s3u1(_lw); |
| 379 | I_u1u2(_mfc0); | 401 | I_u1u2u3(_mfc0); |
| 380 | I_u1u2(_mtc0); | 402 | I_u1u2u3(_mtc0); |
| 381 | I_u2u1u3(_ori); | 403 | I_u2u1u3(_ori); |
| 382 | I_0(_rfe); | 404 | I_0(_rfe); |
| 383 | I_u2s3u1(_sc); | 405 | I_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) |
| @@ -742,7 +765,7 @@ static void __init build_r3000_tlb_refill_handler(void) | |||
| 742 | } | 765 | } |
| 743 | #endif | 766 | #endif |
| 744 | 767 | ||
| 745 | memcpy((void *)CAC_BASE, tlb_handler, 0x80); | 768 | memcpy((void *)ebase, tlb_handler, 0x80); |
| 746 | } | 769 | } |
| 747 | 770 | ||
| 748 | /* | 771 | /* |
| @@ -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); |
| @@ -1247,7 +1290,7 @@ static void __init build_r4000_tlb_refill_handler(void) | |||
| 1247 | } | 1290 | } |
| 1248 | #endif | 1291 | #endif |
| 1249 | 1292 | ||
| 1250 | memcpy((void *)CAC_BASE, final_handler, 0x100); | 1293 | memcpy((void *)ebase, final_handler, 0x100); |
| 1251 | } | 1294 | } |
| 1252 | 1295 | ||
| 1253 | /* | 1296 | /* |
