diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-29 15:19:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-29 15:19:15 -0400 |
commit | e9d52234e35b27ea4ea5f2ab64ca47b1a0c740ab (patch) | |
tree | 318d37a7d55c79e6f7d86163fb28e0eccbb0fe83 /arch/mips/mm/tlbex.c | |
parent | 955c5038823748e529a49f0e33ab635d92843500 (diff) | |
parent | 09af7b443c257460d45cb6c1896d29f173fef35b (diff) |
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
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 | } | ||