diff options
Diffstat (limited to 'arch/mips/mm/tlbex.c')
| -rw-r--r-- | arch/mips/mm/tlbex.c | 245 |
1 files changed, 123 insertions, 122 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 6569be3983c7..0f9485806bac 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * Synthesize TLB refill handlers at runtime. | 6 | * Synthesize TLB refill handlers at runtime. |
| 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 | */ | 10 | */ |
| 10 | 11 | ||
| 11 | #include <stdarg.h> | 12 | #include <stdarg.h> |
| @@ -91,7 +92,7 @@ enum opcode { | |||
| 91 | insn_addu, insn_addiu, insn_and, insn_andi, insn_beq, | 92 | insn_addu, insn_addiu, insn_and, insn_andi, insn_beq, |
| 92 | insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, | 93 | insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, |
| 93 | insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0, | 94 | insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0, |
| 94 | insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, | 95 | insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, |
| 95 | insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld, | 96 | insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld, |
| 96 | insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0, | 97 | insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0, |
| 97 | insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, | 98 | insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, |
| @@ -134,7 +135,6 @@ static __initdata struct insn insn_table[] = { | |||
| 134 | { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE }, | 135 | { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE }, |
| 135 | { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE }, | 136 | { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE }, |
| 136 | { insn_dsrl, M(spec_op,0,0,0,0,dsrl_op), RT | RD | RE }, | 137 | { insn_dsrl, M(spec_op,0,0,0,0,dsrl_op), RT | RD | RE }, |
| 137 | { insn_dsrl32, M(spec_op,0,0,0,0,dsrl32_op), RT | RD | RE }, | ||
| 138 | { insn_dsubu, M(spec_op,0,0,0,0,dsubu_op), RS | RT | RD }, | 138 | { insn_dsubu, M(spec_op,0,0,0,0,dsubu_op), RS | RT | RD }, |
| 139 | { insn_eret, M(cop0_op,cop_op,0,0,0,eret_op), 0 }, | 139 | { insn_eret, M(cop0_op,cop_op,0,0,0,eret_op), 0 }, |
| 140 | { insn_j, M(j_op,0,0,0,0,0), JIMM }, | 140 | { insn_j, M(j_op,0,0,0,0,0), JIMM }, |
| @@ -366,7 +366,6 @@ I_u2u1u3(_dsll); | |||
| 366 | I_u2u1u3(_dsll32); | 366 | I_u2u1u3(_dsll32); |
| 367 | I_u2u1u3(_dsra); | 367 | I_u2u1u3(_dsra); |
| 368 | I_u2u1u3(_dsrl); | 368 | I_u2u1u3(_dsrl); |
| 369 | I_u2u1u3(_dsrl32); | ||
| 370 | I_u3u1u2(_dsubu); | 369 | I_u3u1u2(_dsubu); |
| 371 | I_0(_eret); | 370 | I_0(_eret); |
| 372 | I_u1(_j); | 371 | I_u1(_j); |
| @@ -412,7 +411,6 @@ enum label_id { | |||
| 412 | label_nopage_tlbm, | 411 | label_nopage_tlbm, |
| 413 | label_smp_pgtable_change, | 412 | label_smp_pgtable_change, |
| 414 | label_r3000_write_probe_fail, | 413 | label_r3000_write_probe_fail, |
| 415 | label_r3000_write_probe_ok | ||
| 416 | }; | 414 | }; |
| 417 | 415 | ||
| 418 | struct label { | 416 | struct label { |
| @@ -445,7 +443,6 @@ L_LA(_nopage_tlbs) | |||
| 445 | L_LA(_nopage_tlbm) | 443 | L_LA(_nopage_tlbm) |
| 446 | L_LA(_smp_pgtable_change) | 444 | L_LA(_smp_pgtable_change) |
| 447 | L_LA(_r3000_write_probe_fail) | 445 | L_LA(_r3000_write_probe_fail) |
| 448 | L_LA(_r3000_write_probe_ok) | ||
| 449 | 446 | ||
| 450 | /* convenience macros for instructions */ | 447 | /* convenience macros for instructions */ |
| 451 | #ifdef CONFIG_64BIT | 448 | #ifdef CONFIG_64BIT |
| @@ -490,7 +487,7 @@ L_LA(_r3000_write_probe_ok) | |||
| 490 | static __init int __attribute__((unused)) in_compat_space_p(long addr) | 487 | static __init int __attribute__((unused)) in_compat_space_p(long addr) |
| 491 | { | 488 | { |
| 492 | /* Is this address in 32bit compat space? */ | 489 | /* Is this address in 32bit compat space? */ |
| 493 | return (((addr) & 0xffffffff00000000) == 0xffffffff00000000); | 490 | return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L); |
| 494 | } | 491 | } |
| 495 | 492 | ||
| 496 | static __init int __attribute__((unused)) rel_highest(long val) | 493 | static __init int __attribute__((unused)) rel_highest(long val) |
| @@ -734,7 +731,7 @@ static void __init build_r3000_tlb_refill_handler(void) | |||
| 734 | if (p > tlb_handler + 32) | 731 | if (p > tlb_handler + 32) |
| 735 | panic("TLB refill handler space exceeded"); | 732 | panic("TLB refill handler space exceeded"); |
| 736 | 733 | ||
| 737 | printk("Synthesized TLB handler (%u instructions).\n", | 734 | printk("Synthesized TLB refill handler (%u instructions).\n", |
| 738 | (unsigned int)(p - tlb_handler)); | 735 | (unsigned int)(p - tlb_handler)); |
| 739 | #ifdef DEBUG_TLB | 736 | #ifdef DEBUG_TLB |
| 740 | { | 737 | { |
| @@ -746,7 +743,6 @@ static void __init build_r3000_tlb_refill_handler(void) | |||
| 746 | #endif | 743 | #endif |
| 747 | 744 | ||
| 748 | memcpy((void *)CAC_BASE, tlb_handler, 0x80); | 745 | memcpy((void *)CAC_BASE, tlb_handler, 0x80); |
| 749 | flush_icache_range(CAC_BASE, CAC_BASE + 0x80); | ||
| 750 | } | 746 | } |
| 751 | 747 | ||
| 752 | /* | 748 | /* |
| @@ -783,6 +779,8 @@ static __initdata u32 final_handler[64]; | |||
| 783 | static __init void __attribute__((unused)) build_tlb_probe_entry(u32 **p) | 779 | static __init void __attribute__((unused)) build_tlb_probe_entry(u32 **p) |
| 784 | { | 780 | { |
| 785 | switch (current_cpu_data.cputype) { | 781 | switch (current_cpu_data.cputype) { |
| 782 | /* Found by experiment: R4600 v2.0 needs this, too. */ | ||
| 783 | case CPU_R4600: | ||
| 786 | case CPU_R5000: | 784 | case CPU_R5000: |
| 787 | case CPU_R5000A: | 785 | case CPU_R5000A: |
| 788 | case CPU_NEVADA: | 786 | case CPU_NEVADA: |
| @@ -834,12 +832,20 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, | |||
| 834 | case CPU_R4700: | 832 | case CPU_R4700: |
| 835 | case CPU_R5000: | 833 | case CPU_R5000: |
| 836 | case CPU_R5000A: | 834 | case CPU_R5000A: |
| 835 | i_nop(p); | ||
| 836 | tlbw(p); | ||
| 837 | i_nop(p); | ||
| 838 | break; | ||
| 839 | |||
| 840 | case CPU_R4300: | ||
| 837 | case CPU_5KC: | 841 | case CPU_5KC: |
| 838 | case CPU_TX49XX: | 842 | case CPU_TX49XX: |
| 839 | case CPU_AU1000: | 843 | case CPU_AU1000: |
| 840 | case CPU_AU1100: | 844 | case CPU_AU1100: |
| 841 | case CPU_AU1500: | 845 | case CPU_AU1500: |
| 842 | case CPU_AU1550: | 846 | case CPU_AU1550: |
| 847 | case CPU_AU1200: | ||
| 848 | case CPU_PR4450: | ||
| 843 | i_nop(p); | 849 | i_nop(p); |
| 844 | tlbw(p); | 850 | tlbw(p); |
| 845 | break; | 851 | break; |
| @@ -848,6 +854,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, | |||
| 848 | case CPU_R12000: | 854 | case CPU_R12000: |
| 849 | case CPU_4KC: | 855 | case CPU_4KC: |
| 850 | case CPU_SB1: | 856 | case CPU_SB1: |
| 857 | case CPU_SB1A: | ||
| 851 | case CPU_4KSC: | 858 | case CPU_4KSC: |
| 852 | case CPU_20KC: | 859 | case CPU_20KC: |
| 853 | case CPU_25KF: | 860 | case CPU_25KF: |
| @@ -875,6 +882,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, | |||
| 875 | 882 | ||
| 876 | case CPU_4KEC: | 883 | case CPU_4KEC: |
| 877 | case CPU_24K: | 884 | case CPU_24K: |
| 885 | case CPU_34K: | ||
| 878 | i_ehb(p); | 886 | i_ehb(p); |
| 879 | tlbw(p); | 887 | tlbw(p); |
| 880 | break; | 888 | break; |
| @@ -911,6 +919,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, | |||
| 911 | 919 | ||
| 912 | case CPU_VR4131: | 920 | case CPU_VR4131: |
| 913 | case CPU_VR4133: | 921 | case CPU_VR4133: |
| 922 | case CPU_R5432: | ||
| 914 | i_nop(p); | 923 | i_nop(p); |
| 915 | i_nop(p); | 924 | i_nop(p); |
| 916 | tlbw(p); | 925 | tlbw(p); |
| @@ -942,34 +951,29 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r, | |||
| 942 | /* No i_nop needed here, since the next insn doesn't touch TMP. */ | 951 | /* No i_nop needed here, since the next insn doesn't touch TMP. */ |
| 943 | 952 | ||
| 944 | #ifdef CONFIG_SMP | 953 | #ifdef CONFIG_SMP |
| 954 | # ifdef CONFIG_BUILD_ELF64 | ||
| 945 | /* | 955 | /* |
| 946 | * 64 bit SMP has the lower part of &pgd_current[smp_processor_id()] | 956 | * 64 bit SMP running in XKPHYS has smp_processor_id() << 3 |
| 947 | * stored in CONTEXT. | 957 | * stored in CONTEXT. |
| 948 | */ | 958 | */ |
| 949 | if (in_compat_space_p(pgdc)) { | 959 | i_dmfc0(p, ptr, C0_CONTEXT); |
| 950 | i_dmfc0(p, ptr, C0_CONTEXT); | 960 | i_dsrl(p, ptr, ptr, 23); |
| 951 | i_dsra(p, ptr, ptr, 23); | 961 | i_LA_mostly(p, tmp, pgdc); |
| 952 | i_ld(p, ptr, 0, ptr); | 962 | i_daddu(p, ptr, ptr, tmp); |
| 953 | } else { | 963 | i_dmfc0(p, tmp, C0_BADVADDR); |
| 954 | #ifdef CONFIG_BUILD_ELF64 | 964 | i_ld(p, ptr, rel_lo(pgdc), ptr); |
| 955 | i_dmfc0(p, ptr, C0_CONTEXT); | 965 | # else |
| 956 | i_dsrl(p, ptr, ptr, 23); | 966 | /* |
| 957 | i_dsll(p, ptr, ptr, 3); | 967 | * 64 bit SMP running in compat space has the lower part of |
| 958 | i_LA_mostly(p, tmp, pgdc); | 968 | * &pgd_current[smp_processor_id()] stored in CONTEXT. |
| 959 | i_daddu(p, ptr, ptr, tmp); | 969 | */ |
| 960 | i_dmfc0(p, tmp, C0_BADVADDR); | 970 | if (!in_compat_space_p(pgdc)) |
| 961 | i_ld(p, ptr, rel_lo(pgdc), ptr); | 971 | panic("Invalid page directory address!"); |
| 962 | #else | 972 | |
| 963 | i_dmfc0(p, ptr, C0_CONTEXT); | 973 | i_dmfc0(p, ptr, C0_CONTEXT); |
| 964 | i_lui(p, tmp, rel_highest(pgdc)); | 974 | i_dsra(p, ptr, ptr, 23); |
| 965 | i_dsll(p, ptr, ptr, 9); | 975 | i_ld(p, ptr, 0, ptr); |
| 966 | i_daddiu(p, tmp, tmp, rel_higher(pgdc)); | 976 | # endif |
| 967 | i_dsrl32(p, ptr, ptr, 0); | ||
| 968 | i_and(p, ptr, ptr, tmp); | ||
| 969 | i_dmfc0(p, tmp, C0_BADVADDR); | ||
| 970 | i_ld(p, ptr, 0, ptr); | ||
| 971 | #endif | ||
| 972 | } | ||
| 973 | #else | 977 | #else |
| 974 | i_LA_mostly(p, ptr, pgdc); | 978 | i_LA_mostly(p, ptr, pgdc); |
| 975 | i_ld(p, ptr, rel_lo(pgdc), ptr); | 979 | i_ld(p, ptr, rel_lo(pgdc), ptr); |
| @@ -1026,7 +1030,6 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr) | |||
| 1026 | i_mfc0(p, ptr, C0_CONTEXT); | 1030 | i_mfc0(p, ptr, C0_CONTEXT); |
| 1027 | i_LA_mostly(p, tmp, pgdc); | 1031 | i_LA_mostly(p, tmp, pgdc); |
| 1028 | i_srl(p, ptr, ptr, 23); | 1032 | i_srl(p, ptr, ptr, 23); |
| 1029 | i_sll(p, ptr, ptr, 2); | ||
| 1030 | i_addu(p, ptr, tmp, ptr); | 1033 | i_addu(p, ptr, tmp, ptr); |
| 1031 | #else | 1034 | #else |
| 1032 | i_LA_mostly(p, ptr, pgdc); | 1035 | i_LA_mostly(p, ptr, pgdc); |
| @@ -1245,13 +1248,19 @@ static void __init build_r4000_tlb_refill_handler(void) | |||
| 1245 | { | 1248 | { |
| 1246 | int i; | 1249 | int i; |
| 1247 | 1250 | ||
| 1248 | for (i = 0; i < 64; i++) | 1251 | f = final_handler; |
| 1249 | printk("%08x\n", final_handler[i]); | 1252 | #ifdef CONFIG_64BIT |
| 1253 | if (final_len > 32) | ||
| 1254 | final_len = 64; | ||
| 1255 | else | ||
| 1256 | f = final_handler + 32; | ||
| 1257 | #endif /* CONFIG_64BIT */ | ||
| 1258 | for (i = 0; i < final_len; i++) | ||
| 1259 | printk("%08x\n", f[i]); | ||
| 1250 | } | 1260 | } |
| 1251 | #endif | 1261 | #endif |
| 1252 | 1262 | ||
| 1253 | memcpy((void *)CAC_BASE, final_handler, 0x100); | 1263 | memcpy((void *)CAC_BASE, final_handler, 0x100); |
| 1254 | flush_icache_range(CAC_BASE, CAC_BASE + 0x100); | ||
| 1255 | } | 1264 | } |
| 1256 | 1265 | ||
| 1257 | /* | 1266 | /* |
| @@ -1277,37 +1286,41 @@ u32 __tlb_handler_align handle_tlbs[FASTPATH_SIZE]; | |||
| 1277 | u32 __tlb_handler_align handle_tlbm[FASTPATH_SIZE]; | 1286 | u32 __tlb_handler_align handle_tlbm[FASTPATH_SIZE]; |
| 1278 | 1287 | ||
| 1279 | static void __init | 1288 | static void __init |
| 1280 | iPTE_LW(u32 **p, struct label **l, unsigned int pte, int offset, | 1289 | iPTE_LW(u32 **p, struct label **l, unsigned int pte, unsigned int ptr) |
| 1281 | unsigned int ptr) | ||
| 1282 | { | 1290 | { |
| 1283 | #ifdef CONFIG_SMP | 1291 | #ifdef CONFIG_SMP |
| 1284 | # ifdef CONFIG_64BIT_PHYS_ADDR | 1292 | # ifdef CONFIG_64BIT_PHYS_ADDR |
| 1285 | if (cpu_has_64bits) | 1293 | if (cpu_has_64bits) |
| 1286 | i_lld(p, pte, offset, ptr); | 1294 | i_lld(p, pte, 0, ptr); |
| 1287 | else | 1295 | else |
| 1288 | # endif | 1296 | # endif |
| 1289 | i_LL(p, pte, offset, ptr); | 1297 | i_LL(p, pte, 0, ptr); |
| 1290 | #else | 1298 | #else |
| 1291 | # ifdef CONFIG_64BIT_PHYS_ADDR | 1299 | # ifdef CONFIG_64BIT_PHYS_ADDR |
| 1292 | if (cpu_has_64bits) | 1300 | if (cpu_has_64bits) |
| 1293 | i_ld(p, pte, offset, ptr); | 1301 | i_ld(p, pte, 0, ptr); |
| 1294 | else | 1302 | else |
| 1295 | # endif | 1303 | # endif |
| 1296 | i_LW(p, pte, offset, ptr); | 1304 | i_LW(p, pte, 0, ptr); |
| 1297 | #endif | 1305 | #endif |
| 1298 | } | 1306 | } |
| 1299 | 1307 | ||
| 1300 | static void __init | 1308 | static void __init |
| 1301 | iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, int offset, | 1309 | iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr, |
| 1302 | unsigned int ptr) | 1310 | unsigned int mode) |
| 1303 | { | 1311 | { |
| 1312 | #ifdef CONFIG_64BIT_PHYS_ADDR | ||
| 1313 | unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY); | ||
| 1314 | #endif | ||
| 1315 | |||
| 1316 | i_ori(p, pte, pte, mode); | ||
| 1304 | #ifdef CONFIG_SMP | 1317 | #ifdef CONFIG_SMP |
| 1305 | # ifdef CONFIG_64BIT_PHYS_ADDR | 1318 | # ifdef CONFIG_64BIT_PHYS_ADDR |
| 1306 | if (cpu_has_64bits) | 1319 | if (cpu_has_64bits) |
| 1307 | i_scd(p, pte, offset, ptr); | 1320 | i_scd(p, pte, 0, ptr); |
| 1308 | else | 1321 | else |
| 1309 | # endif | 1322 | # endif |
| 1310 | i_SC(p, pte, offset, ptr); | 1323 | i_SC(p, pte, 0, ptr); |
| 1311 | 1324 | ||
| 1312 | if (r10000_llsc_war()) | 1325 | if (r10000_llsc_war()) |
| 1313 | il_beqzl(p, r, pte, label_smp_pgtable_change); | 1326 | il_beqzl(p, r, pte, label_smp_pgtable_change); |
| @@ -1318,7 +1331,7 @@ iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, int offset, | |||
| 1318 | if (!cpu_has_64bits) { | 1331 | if (!cpu_has_64bits) { |
| 1319 | /* no i_nop needed */ | 1332 | /* no i_nop needed */ |
| 1320 | i_ll(p, pte, sizeof(pte_t) / 2, ptr); | 1333 | i_ll(p, pte, sizeof(pte_t) / 2, ptr); |
| 1321 | i_ori(p, pte, pte, _PAGE_VALID); | 1334 | i_ori(p, pte, pte, hwmode); |
| 1322 | i_sc(p, pte, sizeof(pte_t) / 2, ptr); | 1335 | i_sc(p, pte, sizeof(pte_t) / 2, ptr); |
| 1323 | il_beqz(p, r, pte, label_smp_pgtable_change); | 1336 | il_beqz(p, r, pte, label_smp_pgtable_change); |
| 1324 | /* no i_nop needed */ | 1337 | /* no i_nop needed */ |
| @@ -1331,15 +1344,15 @@ iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, int offset, | |||
| 1331 | #else | 1344 | #else |
| 1332 | # ifdef CONFIG_64BIT_PHYS_ADDR | 1345 | # ifdef CONFIG_64BIT_PHYS_ADDR |
| 1333 | if (cpu_has_64bits) | 1346 | if (cpu_has_64bits) |
| 1334 | i_sd(p, pte, offset, ptr); | 1347 | i_sd(p, pte, 0, ptr); |
| 1335 | else | 1348 | else |
| 1336 | # endif | 1349 | # endif |
| 1337 | i_SW(p, pte, offset, ptr); | 1350 | i_SW(p, pte, 0, ptr); |
| 1338 | 1351 | ||
| 1339 | # ifdef CONFIG_64BIT_PHYS_ADDR | 1352 | # ifdef CONFIG_64BIT_PHYS_ADDR |
| 1340 | if (!cpu_has_64bits) { | 1353 | if (!cpu_has_64bits) { |
| 1341 | i_lw(p, pte, sizeof(pte_t) / 2, ptr); | 1354 | i_lw(p, pte, sizeof(pte_t) / 2, ptr); |
| 1342 | i_ori(p, pte, pte, _PAGE_VALID); | 1355 | i_ori(p, pte, pte, hwmode); |
| 1343 | i_sw(p, pte, sizeof(pte_t) / 2, ptr); | 1356 | i_sw(p, pte, sizeof(pte_t) / 2, ptr); |
| 1344 | i_lw(p, pte, 0, ptr); | 1357 | i_lw(p, pte, 0, ptr); |
| 1345 | } | 1358 | } |
| @@ -1359,7 +1372,7 @@ build_pte_present(u32 **p, struct label **l, struct reloc **r, | |||
| 1359 | i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1372 | i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
| 1360 | i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1373 | i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
| 1361 | il_bnez(p, r, pte, lid); | 1374 | il_bnez(p, r, pte, lid); |
| 1362 | iPTE_LW(p, l, pte, 0, ptr); | 1375 | iPTE_LW(p, l, pte, ptr); |
| 1363 | } | 1376 | } |
| 1364 | 1377 | ||
| 1365 | /* Make PTE valid, store result in PTR. */ | 1378 | /* Make PTE valid, store result in PTR. */ |
| @@ -1367,8 +1380,9 @@ static void __init | |||
| 1367 | build_make_valid(u32 **p, struct reloc **r, unsigned int pte, | 1380 | build_make_valid(u32 **p, struct reloc **r, unsigned int pte, |
| 1368 | unsigned int ptr) | 1381 | unsigned int ptr) |
| 1369 | { | 1382 | { |
| 1370 | i_ori(p, pte, pte, _PAGE_VALID | _PAGE_ACCESSED); | 1383 | unsigned int mode = _PAGE_VALID | _PAGE_ACCESSED; |
| 1371 | iPTE_SW(p, r, pte, 0, ptr); | 1384 | |
| 1385 | iPTE_SW(p, r, pte, ptr, mode); | ||
| 1372 | } | 1386 | } |
| 1373 | 1387 | ||
| 1374 | /* | 1388 | /* |
| @@ -1382,7 +1396,7 @@ build_pte_writable(u32 **p, struct label **l, struct reloc **r, | |||
| 1382 | i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1396 | i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); |
| 1383 | i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1397 | i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); |
| 1384 | il_bnez(p, r, pte, lid); | 1398 | il_bnez(p, r, pte, lid); |
| 1385 | iPTE_LW(p, l, pte, 0, ptr); | 1399 | iPTE_LW(p, l, pte, ptr); |
| 1386 | } | 1400 | } |
| 1387 | 1401 | ||
| 1388 | /* Make PTE writable, update software status bits as well, then store | 1402 | /* Make PTE writable, update software status bits as well, then store |
| @@ -1392,9 +1406,10 @@ static void __init | |||
| 1392 | build_make_write(u32 **p, struct reloc **r, unsigned int pte, | 1406 | build_make_write(u32 **p, struct reloc **r, unsigned int pte, |
| 1393 | unsigned int ptr) | 1407 | unsigned int ptr) |
| 1394 | { | 1408 | { |
| 1395 | i_ori(p, pte, pte, | 1409 | unsigned int mode = (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID |
| 1396 | _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY); | 1410 | | _PAGE_DIRTY); |
| 1397 | iPTE_SW(p, r, pte, 0, ptr); | 1411 | |
| 1412 | iPTE_SW(p, r, pte, ptr, mode); | ||
| 1398 | } | 1413 | } |
| 1399 | 1414 | ||
| 1400 | /* | 1415 | /* |
| @@ -1407,41 +1422,48 @@ build_pte_modifiable(u32 **p, struct label **l, struct reloc **r, | |||
| 1407 | { | 1422 | { |
| 1408 | i_andi(p, pte, pte, _PAGE_WRITE); | 1423 | i_andi(p, pte, pte, _PAGE_WRITE); |
| 1409 | il_beqz(p, r, pte, lid); | 1424 | il_beqz(p, r, pte, lid); |
| 1410 | iPTE_LW(p, l, pte, 0, ptr); | 1425 | iPTE_LW(p, l, pte, ptr); |
| 1411 | } | 1426 | } |
| 1412 | 1427 | ||
| 1413 | /* | 1428 | /* |
| 1414 | * R3000 style TLB load/store/modify handlers. | 1429 | * R3000 style TLB load/store/modify handlers. |
| 1415 | */ | 1430 | */ |
| 1416 | 1431 | ||
| 1417 | /* This places the pte in the page table at PTR into ENTRYLO0. */ | 1432 | /* |
| 1433 | * This places the pte into ENTRYLO0 and writes it with tlbwi. | ||
| 1434 | * Then it returns. | ||
| 1435 | */ | ||
| 1418 | static void __init | 1436 | static void __init |
| 1419 | build_r3000_pte_reload(u32 **p, unsigned int ptr) | 1437 | build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp) |
| 1420 | { | 1438 | { |
| 1421 | i_lw(p, ptr, 0, ptr); | 1439 | i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */ |
| 1422 | i_nop(p); /* load delay */ | 1440 | i_mfc0(p, tmp, C0_EPC); /* cp0 delay */ |
| 1423 | i_mtc0(p, ptr, C0_ENTRYLO0); | 1441 | i_tlbwi(p); |
| 1424 | i_nop(p); /* cp0 delay */ | 1442 | i_jr(p, tmp); |
| 1443 | i_rfe(p); /* branch delay */ | ||
| 1425 | } | 1444 | } |
| 1426 | 1445 | ||
| 1427 | /* | 1446 | /* |
| 1428 | * The index register may have the probe fail bit set, | 1447 | * This places the pte into ENTRYLO0 and writes it with tlbwi |
| 1429 | * because we would trap on access kseg2, i.e. without refill. | 1448 | * or tlbwr as appropriate. This is because the index register |
| 1449 | * may have the probe fail bit set as a result of a trap on a | ||
| 1450 | * kseg2 access, i.e. without refill. Then it returns. | ||
| 1430 | */ | 1451 | */ |
| 1431 | static void __init | 1452 | static void __init |
| 1432 | build_r3000_tlb_write(u32 **p, struct label **l, struct reloc **r, | 1453 | build_r3000_tlb_reload_write(u32 **p, struct label **l, struct reloc **r, |
| 1433 | unsigned int tmp) | 1454 | unsigned int pte, unsigned int tmp) |
| 1434 | { | 1455 | { |
| 1435 | i_mfc0(p, tmp, C0_INDEX); | 1456 | i_mfc0(p, tmp, C0_INDEX); |
| 1436 | i_nop(p); /* cp0 delay */ | 1457 | i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */ |
| 1437 | il_bltz(p, r, tmp, label_r3000_write_probe_fail); | 1458 | il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */ |
| 1438 | i_nop(p); /* branch delay */ | 1459 | i_mfc0(p, tmp, C0_EPC); /* branch delay */ |
| 1439 | i_tlbwi(p); | 1460 | i_tlbwi(p); /* cp0 delay */ |
| 1440 | il_b(p, r, label_r3000_write_probe_ok); | 1461 | i_jr(p, tmp); |
| 1441 | i_nop(p); /* branch delay */ | 1462 | i_rfe(p); /* branch delay */ |
| 1442 | l_r3000_write_probe_fail(l, *p); | 1463 | l_r3000_write_probe_fail(l, *p); |
| 1443 | i_tlbwr(p); | 1464 | i_tlbwr(p); /* cp0 delay */ |
| 1444 | l_r3000_write_probe_ok(l, *p); | 1465 | i_jr(p, tmp); |
| 1466 | i_rfe(p); /* branch delay */ | ||
| 1445 | } | 1467 | } |
| 1446 | 1468 | ||
| 1447 | static void __init | 1469 | static void __init |
| @@ -1461,17 +1483,7 @@ build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte, | |||
| 1461 | i_andi(p, pte, pte, 0xffc); /* load delay */ | 1483 | i_andi(p, pte, pte, 0xffc); /* load delay */ |
| 1462 | i_addu(p, ptr, ptr, pte); | 1484 | i_addu(p, ptr, ptr, pte); |
| 1463 | i_lw(p, pte, 0, ptr); | 1485 | i_lw(p, pte, 0, ptr); |
| 1464 | i_nop(p); /* load delay */ | 1486 | i_tlbp(p); /* load delay */ |
| 1465 | i_tlbp(p); | ||
| 1466 | } | ||
| 1467 | |||
| 1468 | static void __init | ||
| 1469 | build_r3000_tlbchange_handler_tail(u32 **p, unsigned int tmp) | ||
| 1470 | { | ||
| 1471 | i_mfc0(p, tmp, C0_EPC); | ||
| 1472 | i_nop(p); /* cp0 delay */ | ||
| 1473 | i_jr(p, tmp); | ||
| 1474 | i_rfe(p); /* branch delay */ | ||
| 1475 | } | 1487 | } |
| 1476 | 1488 | ||
| 1477 | static void __init build_r3000_tlb_load_handler(void) | 1489 | static void __init build_r3000_tlb_load_handler(void) |
| @@ -1486,10 +1498,9 @@ static void __init build_r3000_tlb_load_handler(void) | |||
| 1486 | 1498 | ||
| 1487 | build_r3000_tlbchange_handler_head(&p, K0, K1); | 1499 | build_r3000_tlbchange_handler_head(&p, K0, K1); |
| 1488 | build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl); | 1500 | build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl); |
| 1501 | i_nop(&p); /* load delay */ | ||
| 1489 | build_make_valid(&p, &r, K0, K1); | 1502 | build_make_valid(&p, &r, K0, K1); |
| 1490 | build_r3000_pte_reload(&p, K1); | 1503 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); |
| 1491 | build_r3000_tlb_write(&p, &l, &r, K0); | ||
| 1492 | build_r3000_tlbchange_handler_tail(&p, K0); | ||
| 1493 | 1504 | ||
| 1494 | l_nopage_tlbl(&l, p); | 1505 | l_nopage_tlbl(&l, p); |
| 1495 | i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); | 1506 | i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); |
| @@ -1506,13 +1517,10 @@ static void __init build_r3000_tlb_load_handler(void) | |||
| 1506 | { | 1517 | { |
| 1507 | int i; | 1518 | int i; |
| 1508 | 1519 | ||
| 1509 | for (i = 0; i < FASTPATH_SIZE; i++) | 1520 | for (i = 0; i < (p - handle_tlbl); i++) |
| 1510 | printk("%08x\n", handle_tlbl[i]); | 1521 | printk("%08x\n", handle_tlbl[i]); |
| 1511 | } | 1522 | } |
| 1512 | #endif | 1523 | #endif |
| 1513 | |||
| 1514 | flush_icache_range((unsigned long)handle_tlbl, | ||
| 1515 | (unsigned long)handle_tlbl + FASTPATH_SIZE * sizeof(u32)); | ||
| 1516 | } | 1524 | } |
| 1517 | 1525 | ||
| 1518 | static void __init build_r3000_tlb_store_handler(void) | 1526 | static void __init build_r3000_tlb_store_handler(void) |
| @@ -1527,10 +1535,9 @@ static void __init build_r3000_tlb_store_handler(void) | |||
| 1527 | 1535 | ||
| 1528 | build_r3000_tlbchange_handler_head(&p, K0, K1); | 1536 | build_r3000_tlbchange_handler_head(&p, K0, K1); |
| 1529 | build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs); | 1537 | build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs); |
| 1538 | i_nop(&p); /* load delay */ | ||
| 1530 | build_make_write(&p, &r, K0, K1); | 1539 | build_make_write(&p, &r, K0, K1); |
| 1531 | build_r3000_pte_reload(&p, K1); | 1540 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); |
| 1532 | build_r3000_tlb_write(&p, &l, &r, K0); | ||
| 1533 | build_r3000_tlbchange_handler_tail(&p, K0); | ||
| 1534 | 1541 | ||
| 1535 | l_nopage_tlbs(&l, p); | 1542 | l_nopage_tlbs(&l, p); |
| 1536 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 1543 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |
| @@ -1547,13 +1554,10 @@ static void __init build_r3000_tlb_store_handler(void) | |||
| 1547 | { | 1554 | { |
| 1548 | int i; | 1555 | int i; |
| 1549 | 1556 | ||
| 1550 | for (i = 0; i < FASTPATH_SIZE; i++) | 1557 | for (i = 0; i < (p - handle_tlbs); i++) |
| 1551 | printk("%08x\n", handle_tlbs[i]); | 1558 | printk("%08x\n", handle_tlbs[i]); |
| 1552 | } | 1559 | } |
| 1553 | #endif | 1560 | #endif |
| 1554 | |||
| 1555 | flush_icache_range((unsigned long)handle_tlbs, | ||
| 1556 | (unsigned long)handle_tlbs + FASTPATH_SIZE * sizeof(u32)); | ||
| 1557 | } | 1561 | } |
| 1558 | 1562 | ||
| 1559 | static void __init build_r3000_tlb_modify_handler(void) | 1563 | static void __init build_r3000_tlb_modify_handler(void) |
| @@ -1568,10 +1572,9 @@ static void __init build_r3000_tlb_modify_handler(void) | |||
| 1568 | 1572 | ||
| 1569 | build_r3000_tlbchange_handler_head(&p, K0, K1); | 1573 | build_r3000_tlbchange_handler_head(&p, K0, K1); |
| 1570 | build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm); | 1574 | build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm); |
| 1575 | i_nop(&p); /* load delay */ | ||
| 1571 | build_make_write(&p, &r, K0, K1); | 1576 | build_make_write(&p, &r, K0, K1); |
| 1572 | build_r3000_pte_reload(&p, K1); | 1577 | build_r3000_pte_reload_tlbwi(&p, K0, K1); |
| 1573 | i_tlbwi(&p); | ||
| 1574 | build_r3000_tlbchange_handler_tail(&p, K0); | ||
| 1575 | 1578 | ||
| 1576 | l_nopage_tlbm(&l, p); | 1579 | l_nopage_tlbm(&l, p); |
| 1577 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 1580 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |
| @@ -1588,13 +1591,10 @@ static void __init build_r3000_tlb_modify_handler(void) | |||
| 1588 | { | 1591 | { |
| 1589 | int i; | 1592 | int i; |
| 1590 | 1593 | ||
| 1591 | for (i = 0; i < FASTPATH_SIZE; i++) | 1594 | for (i = 0; i < (p - handle_tlbm); i++) |
| 1592 | printk("%08x\n", handle_tlbm[i]); | 1595 | printk("%08x\n", handle_tlbm[i]); |
| 1593 | } | 1596 | } |
| 1594 | #endif | 1597 | #endif |
| 1595 | |||
| 1596 | flush_icache_range((unsigned long)handle_tlbm, | ||
| 1597 | (unsigned long)handle_tlbm + FASTPATH_SIZE * sizeof(u32)); | ||
| 1598 | } | 1598 | } |
| 1599 | 1599 | ||
| 1600 | /* | 1600 | /* |
| @@ -1620,7 +1620,7 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l, | |||
| 1620 | #ifdef CONFIG_SMP | 1620 | #ifdef CONFIG_SMP |
| 1621 | l_smp_pgtable_change(l, *p); | 1621 | l_smp_pgtable_change(l, *p); |
| 1622 | # endif | 1622 | # endif |
| 1623 | iPTE_LW(p, l, pte, 0, ptr); /* get even pte */ | 1623 | iPTE_LW(p, l, pte, ptr); /* get even pte */ |
| 1624 | build_tlb_probe_entry(p); | 1624 | build_tlb_probe_entry(p); |
| 1625 | } | 1625 | } |
| 1626 | 1626 | ||
| @@ -1680,13 +1680,10 @@ static void __init build_r4000_tlb_load_handler(void) | |||
| 1680 | { | 1680 | { |
| 1681 | int i; | 1681 | int i; |
| 1682 | 1682 | ||
| 1683 | for (i = 0; i < FASTPATH_SIZE; i++) | 1683 | for (i = 0; i < (p - handle_tlbl); i++) |
| 1684 | printk("%08x\n", handle_tlbl[i]); | 1684 | printk("%08x\n", handle_tlbl[i]); |
| 1685 | } | 1685 | } |
| 1686 | #endif | 1686 | #endif |
| 1687 | |||
| 1688 | flush_icache_range((unsigned long)handle_tlbl, | ||
| 1689 | (unsigned long)handle_tlbl + FASTPATH_SIZE * sizeof(u32)); | ||
| 1690 | } | 1687 | } |
| 1691 | 1688 | ||
| 1692 | static void __init build_r4000_tlb_store_handler(void) | 1689 | static void __init build_r4000_tlb_store_handler(void) |
| @@ -1719,13 +1716,10 @@ static void __init build_r4000_tlb_store_handler(void) | |||
| 1719 | { | 1716 | { |
| 1720 | int i; | 1717 | int i; |
| 1721 | 1718 | ||
| 1722 | for (i = 0; i < FASTPATH_SIZE; i++) | 1719 | for (i = 0; i < (p - handle_tlbs); i++) |
| 1723 | printk("%08x\n", handle_tlbs[i]); | 1720 | printk("%08x\n", handle_tlbs[i]); |
| 1724 | } | 1721 | } |
| 1725 | #endif | 1722 | #endif |
| 1726 | |||
| 1727 | flush_icache_range((unsigned long)handle_tlbs, | ||
| 1728 | (unsigned long)handle_tlbs + FASTPATH_SIZE * sizeof(u32)); | ||
| 1729 | } | 1723 | } |
| 1730 | 1724 | ||
| 1731 | static void __init build_r4000_tlb_modify_handler(void) | 1725 | static void __init build_r4000_tlb_modify_handler(void) |
| @@ -1759,13 +1753,10 @@ static void __init build_r4000_tlb_modify_handler(void) | |||
| 1759 | { | 1753 | { |
| 1760 | int i; | 1754 | int i; |
| 1761 | 1755 | ||
| 1762 | for (i = 0; i < FASTPATH_SIZE; i++) | 1756 | for (i = 0; i < (p - handle_tlbm); i++) |
| 1763 | printk("%08x\n", handle_tlbm[i]); | 1757 | printk("%08x\n", handle_tlbm[i]); |
| 1764 | } | 1758 | } |
| 1765 | #endif | 1759 | #endif |
| 1766 | |||
| 1767 | flush_icache_range((unsigned long)handle_tlbm, | ||
| 1768 | (unsigned long)handle_tlbm + FASTPATH_SIZE * sizeof(u32)); | ||
| 1769 | } | 1760 | } |
| 1770 | 1761 | ||
| 1771 | void __init build_tlb_refill_handler(void) | 1762 | void __init build_tlb_refill_handler(void) |
| @@ -1813,3 +1804,13 @@ void __init build_tlb_refill_handler(void) | |||
| 1813 | } | 1804 | } |
| 1814 | } | 1805 | } |
| 1815 | } | 1806 | } |
| 1807 | |||
| 1808 | void __init flush_tlb_handlers(void) | ||
| 1809 | { | ||
| 1810 | flush_icache_range((unsigned long)handle_tlbl, | ||
| 1811 | (unsigned long)handle_tlbl + sizeof(handle_tlbl)); | ||
| 1812 | flush_icache_range((unsigned long)handle_tlbs, | ||
| 1813 | (unsigned long)handle_tlbs + sizeof(handle_tlbs)); | ||
| 1814 | flush_icache_range((unsigned long)handle_tlbm, | ||
| 1815 | (unsigned long)handle_tlbm + sizeof(handle_tlbm)); | ||
| 1816 | } | ||
