diff options
Diffstat (limited to 'arch/mips/mm/tlbex.c')
-rw-r--r-- | arch/mips/mm/tlbex.c | 283 |
1 files changed, 245 insertions, 38 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 0615b62efd6d..9a17bf8395df 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -6,8 +6,9 @@ | |||
6 | * Synthesize TLB refill handlers at runtime. | 6 | * Synthesize TLB refill handlers at runtime. |
7 | * | 7 | * |
8 | * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer | 8 | * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer |
9 | * Copyright (C) 2005, 2007 Maciej W. Rozycki | 9 | * Copyright (C) 2005, 2007, 2008, 2009 Maciej W. Rozycki |
10 | * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) | 10 | * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) |
11 | * Copyright (C) 2008, 2009 Cavium Networks, Inc. | ||
11 | * | 12 | * |
12 | * ... and the days got worse and worse and now you see | 13 | * ... and the days got worse and worse and now you see |
13 | * I've gone completly out of my mind. | 14 | * I've gone completly out of my mind. |
@@ -19,8 +20,10 @@ | |||
19 | * (Condolences to Napoleon XIV) | 20 | * (Condolences to Napoleon XIV) |
20 | */ | 21 | */ |
21 | 22 | ||
23 | #include <linux/bug.h> | ||
22 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
23 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <linux/smp.h> | ||
24 | #include <linux/string.h> | 27 | #include <linux/string.h> |
25 | #include <linux/init.h> | 28 | #include <linux/init.h> |
26 | 29 | ||
@@ -82,6 +85,9 @@ enum label_id { | |||
82 | label_nopage_tlbm, | 85 | label_nopage_tlbm, |
83 | label_smp_pgtable_change, | 86 | label_smp_pgtable_change, |
84 | label_r3000_write_probe_fail, | 87 | label_r3000_write_probe_fail, |
88 | #ifdef CONFIG_HUGETLB_PAGE | ||
89 | label_tlb_huge_update, | ||
90 | #endif | ||
85 | }; | 91 | }; |
86 | 92 | ||
87 | UASM_L_LA(_second_part) | 93 | UASM_L_LA(_second_part) |
@@ -98,6 +104,9 @@ UASM_L_LA(_nopage_tlbs) | |||
98 | UASM_L_LA(_nopage_tlbm) | 104 | UASM_L_LA(_nopage_tlbm) |
99 | UASM_L_LA(_smp_pgtable_change) | 105 | UASM_L_LA(_smp_pgtable_change) |
100 | UASM_L_LA(_r3000_write_probe_fail) | 106 | UASM_L_LA(_r3000_write_probe_fail) |
107 | #ifdef CONFIG_HUGETLB_PAGE | ||
108 | UASM_L_LA(_tlb_huge_update) | ||
109 | #endif | ||
101 | 110 | ||
102 | /* | 111 | /* |
103 | * For debug purposes. | 112 | * For debug purposes. |
@@ -125,6 +134,7 @@ static inline void dump_handler(const u32 *handler, int count) | |||
125 | #define C0_TCBIND 2, 2 | 134 | #define C0_TCBIND 2, 2 |
126 | #define C0_ENTRYLO1 3, 0 | 135 | #define C0_ENTRYLO1 3, 0 |
127 | #define C0_CONTEXT 4, 0 | 136 | #define C0_CONTEXT 4, 0 |
137 | #define C0_PAGEMASK 5, 0 | ||
128 | #define C0_BADVADDR 8, 0 | 138 | #define C0_BADVADDR 8, 0 |
129 | #define C0_ENTRYHI 10, 0 | 139 | #define C0_ENTRYHI 10, 0 |
130 | #define C0_EPC 14, 0 | 140 | #define C0_EPC 14, 0 |
@@ -258,7 +268,8 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, | |||
258 | } | 268 | } |
259 | 269 | ||
260 | if (cpu_has_mips_r2) { | 270 | if (cpu_has_mips_r2) { |
261 | uasm_i_ehb(p); | 271 | if (cpu_has_mips_r2_exec_hazard) |
272 | uasm_i_ehb(p); | ||
262 | tlbw(p); | 273 | tlbw(p); |
263 | return; | 274 | return; |
264 | } | 275 | } |
@@ -310,7 +321,6 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, | |||
310 | case CPU_BCM3302: | 321 | case CPU_BCM3302: |
311 | case CPU_BCM4710: | 322 | case CPU_BCM4710: |
312 | case CPU_LOONGSON2: | 323 | case CPU_LOONGSON2: |
313 | case CPU_CAVIUM_OCTEON: | ||
314 | case CPU_R5500: | 324 | case CPU_R5500: |
315 | if (m4kc_tlbp_war()) | 325 | if (m4kc_tlbp_war()) |
316 | uasm_i_nop(p); | 326 | uasm_i_nop(p); |
@@ -382,6 +392,98 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, | |||
382 | } | 392 | } |
383 | } | 393 | } |
384 | 394 | ||
395 | #ifdef CONFIG_HUGETLB_PAGE | ||
396 | static __cpuinit void build_huge_tlb_write_entry(u32 **p, | ||
397 | struct uasm_label **l, | ||
398 | struct uasm_reloc **r, | ||
399 | unsigned int tmp, | ||
400 | enum tlb_write_entry wmode) | ||
401 | { | ||
402 | /* Set huge page tlb entry size */ | ||
403 | uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16); | ||
404 | uasm_i_ori(p, tmp, tmp, PM_HUGE_MASK & 0xffff); | ||
405 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | ||
406 | |||
407 | build_tlb_write_entry(p, l, r, wmode); | ||
408 | |||
409 | /* Reset default page size */ | ||
410 | if (PM_DEFAULT_MASK >> 16) { | ||
411 | uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); | ||
412 | uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); | ||
413 | uasm_il_b(p, r, label_leave); | ||
414 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | ||
415 | } else if (PM_DEFAULT_MASK) { | ||
416 | uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); | ||
417 | uasm_il_b(p, r, label_leave); | ||
418 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | ||
419 | } else { | ||
420 | uasm_il_b(p, r, label_leave); | ||
421 | uasm_i_mtc0(p, 0, C0_PAGEMASK); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Check if Huge PTE is present, if so then jump to LABEL. | ||
427 | */ | ||
428 | static void __cpuinit | ||
429 | build_is_huge_pte(u32 **p, struct uasm_reloc **r, unsigned int tmp, | ||
430 | unsigned int pmd, int lid) | ||
431 | { | ||
432 | UASM_i_LW(p, tmp, 0, pmd); | ||
433 | uasm_i_andi(p, tmp, tmp, _PAGE_HUGE); | ||
434 | uasm_il_bnez(p, r, tmp, lid); | ||
435 | } | ||
436 | |||
437 | static __cpuinit void build_huge_update_entries(u32 **p, | ||
438 | unsigned int pte, | ||
439 | unsigned int tmp) | ||
440 | { | ||
441 | int small_sequence; | ||
442 | |||
443 | /* | ||
444 | * A huge PTE describes an area the size of the | ||
445 | * configured huge page size. This is twice the | ||
446 | * of the large TLB entry size we intend to use. | ||
447 | * A TLB entry half the size of the configured | ||
448 | * huge page size is configured into entrylo0 | ||
449 | * and entrylo1 to cover the contiguous huge PTE | ||
450 | * address space. | ||
451 | */ | ||
452 | small_sequence = (HPAGE_SIZE >> 7) < 0x10000; | ||
453 | |||
454 | /* We can clobber tmp. It isn't used after this.*/ | ||
455 | if (!small_sequence) | ||
456 | uasm_i_lui(p, tmp, HPAGE_SIZE >> (7 + 16)); | ||
457 | |||
458 | UASM_i_SRL(p, pte, pte, 6); /* convert to entrylo */ | ||
459 | uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* load it */ | ||
460 | /* convert to entrylo1 */ | ||
461 | if (small_sequence) | ||
462 | UASM_i_ADDIU(p, pte, pte, HPAGE_SIZE >> 7); | ||
463 | else | ||
464 | UASM_i_ADDU(p, pte, pte, tmp); | ||
465 | |||
466 | uasm_i_mtc0(p, pte, C0_ENTRYLO1); /* load it */ | ||
467 | } | ||
468 | |||
469 | static __cpuinit void build_huge_handler_tail(u32 **p, | ||
470 | struct uasm_reloc **r, | ||
471 | struct uasm_label **l, | ||
472 | unsigned int pte, | ||
473 | unsigned int ptr) | ||
474 | { | ||
475 | #ifdef CONFIG_SMP | ||
476 | UASM_i_SC(p, pte, 0, ptr); | ||
477 | uasm_il_beqz(p, r, pte, label_tlb_huge_update); | ||
478 | UASM_i_LW(p, pte, 0, ptr); /* Needed because SC killed our PTE */ | ||
479 | #else | ||
480 | UASM_i_SW(p, pte, 0, ptr); | ||
481 | #endif | ||
482 | build_huge_update_entries(p, pte, ptr); | ||
483 | build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed); | ||
484 | } | ||
485 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
486 | |||
385 | #ifdef CONFIG_64BIT | 487 | #ifdef CONFIG_64BIT |
386 | /* | 488 | /* |
387 | * TMP and PTR are scratch. | 489 | * TMP and PTR are scratch. |
@@ -649,6 +751,14 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, | |||
649 | #endif | 751 | #endif |
650 | } | 752 | } |
651 | 753 | ||
754 | /* | ||
755 | * For a 64-bit kernel, we are using the 64-bit XTLB refill exception | ||
756 | * because EXL == 0. If we wrap, we can also use the 32 instruction | ||
757 | * slots before the XTLB refill exception handler which belong to the | ||
758 | * unused TLB refill exception. | ||
759 | */ | ||
760 | #define MIPS64_REFILL_INSNS 32 | ||
761 | |||
652 | static void __cpuinit build_r4000_tlb_refill_handler(void) | 762 | static void __cpuinit build_r4000_tlb_refill_handler(void) |
653 | { | 763 | { |
654 | u32 *p = tlb_handler; | 764 | u32 *p = tlb_handler; |
@@ -680,12 +790,23 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
680 | build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ | 790 | build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ |
681 | #endif | 791 | #endif |
682 | 792 | ||
793 | #ifdef CONFIG_HUGETLB_PAGE | ||
794 | build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update); | ||
795 | #endif | ||
796 | |||
683 | build_get_ptep(&p, K0, K1); | 797 | build_get_ptep(&p, K0, K1); |
684 | build_update_entries(&p, K0, K1); | 798 | build_update_entries(&p, K0, K1); |
685 | build_tlb_write_entry(&p, &l, &r, tlb_random); | 799 | build_tlb_write_entry(&p, &l, &r, tlb_random); |
686 | uasm_l_leave(&l, p); | 800 | uasm_l_leave(&l, p); |
687 | uasm_i_eret(&p); /* return from trap */ | 801 | uasm_i_eret(&p); /* return from trap */ |
688 | 802 | ||
803 | #ifdef CONFIG_HUGETLB_PAGE | ||
804 | uasm_l_tlb_huge_update(&l, p); | ||
805 | UASM_i_LW(&p, K0, 0, K1); | ||
806 | build_huge_update_entries(&p, K0, K1); | ||
807 | build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random); | ||
808 | #endif | ||
809 | |||
689 | #ifdef CONFIG_64BIT | 810 | #ifdef CONFIG_64BIT |
690 | build_get_pgd_vmalloc64(&p, &l, &r, K0, K1); | 811 | build_get_pgd_vmalloc64(&p, &l, &r, K0, K1); |
691 | #endif | 812 | #endif |
@@ -702,9 +823,10 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
702 | if ((p - tlb_handler) > 64) | 823 | if ((p - tlb_handler) > 64) |
703 | panic("TLB refill handler space exceeded"); | 824 | panic("TLB refill handler space exceeded"); |
704 | #else | 825 | #else |
705 | if (((p - tlb_handler) > 63) | 826 | if (((p - tlb_handler) > (MIPS64_REFILL_INSNS * 2) - 1) |
706 | || (((p - tlb_handler) > 61) | 827 | || (((p - tlb_handler) > (MIPS64_REFILL_INSNS * 2) - 3) |
707 | && uasm_insn_has_bdelay(relocs, tlb_handler + 29))) | 828 | && uasm_insn_has_bdelay(relocs, |
829 | tlb_handler + MIPS64_REFILL_INSNS - 3))) | ||
708 | panic("TLB refill handler space exceeded"); | 830 | panic("TLB refill handler space exceeded"); |
709 | #endif | 831 | #endif |
710 | 832 | ||
@@ -717,39 +839,74 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
717 | uasm_copy_handler(relocs, labels, tlb_handler, p, f); | 839 | uasm_copy_handler(relocs, labels, tlb_handler, p, f); |
718 | final_len = p - tlb_handler; | 840 | final_len = p - tlb_handler; |
719 | #else /* CONFIG_64BIT */ | 841 | #else /* CONFIG_64BIT */ |
720 | f = final_handler + 32; | 842 | f = final_handler + MIPS64_REFILL_INSNS; |
721 | if ((p - tlb_handler) <= 32) { | 843 | if ((p - tlb_handler) <= MIPS64_REFILL_INSNS) { |
722 | /* Just copy the handler. */ | 844 | /* Just copy the handler. */ |
723 | uasm_copy_handler(relocs, labels, tlb_handler, p, f); | 845 | uasm_copy_handler(relocs, labels, tlb_handler, p, f); |
724 | final_len = p - tlb_handler; | 846 | final_len = p - tlb_handler; |
725 | } else { | 847 | } else { |
726 | u32 *split = tlb_handler + 30; | 848 | #if defined(CONFIG_HUGETLB_PAGE) |
849 | const enum label_id ls = label_tlb_huge_update; | ||
850 | #elif defined(MODULE_START) | ||
851 | const enum label_id ls = label_module_alloc; | ||
852 | #else | ||
853 | const enum label_id ls = label_vmalloc; | ||
854 | #endif | ||
855 | u32 *split; | ||
856 | int ov = 0; | ||
857 | int i; | ||
858 | |||
859 | for (i = 0; i < ARRAY_SIZE(labels) && labels[i].lab != ls; i++) | ||
860 | ; | ||
861 | BUG_ON(i == ARRAY_SIZE(labels)); | ||
862 | split = labels[i].addr; | ||
727 | 863 | ||
728 | /* | 864 | /* |
729 | * Find the split point. | 865 | * See if we have overflown one way or the other. |
730 | */ | 866 | */ |
731 | if (uasm_insn_has_bdelay(relocs, split - 1)) | 867 | if (split > tlb_handler + MIPS64_REFILL_INSNS || |
732 | split--; | 868 | split < p - MIPS64_REFILL_INSNS) |
733 | 869 | ov = 1; | |
870 | |||
871 | if (ov) { | ||
872 | /* | ||
873 | * Split two instructions before the end. One | ||
874 | * for the branch and one for the instruction | ||
875 | * in the delay slot. | ||
876 | */ | ||
877 | split = tlb_handler + MIPS64_REFILL_INSNS - 2; | ||
878 | |||
879 | /* | ||
880 | * If the branch would fall in a delay slot, | ||
881 | * we must back up an additional instruction | ||
882 | * so that it is no longer in a delay slot. | ||
883 | */ | ||
884 | if (uasm_insn_has_bdelay(relocs, split - 1)) | ||
885 | split--; | ||
886 | } | ||
734 | /* Copy first part of the handler. */ | 887 | /* Copy first part of the handler. */ |
735 | uasm_copy_handler(relocs, labels, tlb_handler, split, f); | 888 | uasm_copy_handler(relocs, labels, tlb_handler, split, f); |
736 | f += split - tlb_handler; | 889 | f += split - tlb_handler; |
737 | 890 | ||
738 | /* Insert branch. */ | 891 | if (ov) { |
739 | uasm_l_split(&l, final_handler); | 892 | /* Insert branch. */ |
740 | uasm_il_b(&f, &r, label_split); | 893 | uasm_l_split(&l, final_handler); |
741 | if (uasm_insn_has_bdelay(relocs, split)) | 894 | uasm_il_b(&f, &r, label_split); |
742 | uasm_i_nop(&f); | 895 | if (uasm_insn_has_bdelay(relocs, split)) |
743 | else { | 896 | uasm_i_nop(&f); |
744 | uasm_copy_handler(relocs, labels, split, split + 1, f); | 897 | else { |
745 | uasm_move_labels(labels, f, f + 1, -1); | 898 | uasm_copy_handler(relocs, labels, |
746 | f++; | 899 | split, split + 1, f); |
747 | split++; | 900 | uasm_move_labels(labels, f, f + 1, -1); |
901 | f++; | ||
902 | split++; | ||
903 | } | ||
748 | } | 904 | } |
749 | 905 | ||
750 | /* Copy the rest of the handler. */ | 906 | /* Copy the rest of the handler. */ |
751 | uasm_copy_handler(relocs, labels, split, p, final_handler); | 907 | uasm_copy_handler(relocs, labels, split, p, final_handler); |
752 | final_len = (f - (final_handler + 32)) + (p - split); | 908 | final_len = (f - (final_handler + MIPS64_REFILL_INSNS)) + |
909 | (p - split); | ||
753 | } | 910 | } |
754 | #endif /* CONFIG_64BIT */ | 911 | #endif /* CONFIG_64BIT */ |
755 | 912 | ||
@@ -782,7 +939,7 @@ u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; | |||
782 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; | 939 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; |
783 | 940 | ||
784 | static void __cpuinit | 941 | static void __cpuinit |
785 | iPTE_LW(u32 **p, struct uasm_label **l, unsigned int pte, unsigned int ptr) | 942 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) |
786 | { | 943 | { |
787 | #ifdef CONFIG_SMP | 944 | #ifdef CONFIG_SMP |
788 | # ifdef CONFIG_64BIT_PHYS_ADDR | 945 | # ifdef CONFIG_64BIT_PHYS_ADDR |
@@ -862,13 +1019,13 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, | |||
862 | * with it's original value. | 1019 | * with it's original value. |
863 | */ | 1020 | */ |
864 | static void __cpuinit | 1021 | static void __cpuinit |
865 | build_pte_present(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | 1022 | build_pte_present(u32 **p, struct uasm_reloc **r, |
866 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1023 | unsigned int pte, unsigned int ptr, enum label_id lid) |
867 | { | 1024 | { |
868 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1025 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
869 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1026 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
870 | uasm_il_bnez(p, r, pte, lid); | 1027 | uasm_il_bnez(p, r, pte, lid); |
871 | iPTE_LW(p, l, pte, ptr); | 1028 | iPTE_LW(p, pte, ptr); |
872 | } | 1029 | } |
873 | 1030 | ||
874 | /* Make PTE valid, store result in PTR. */ | 1031 | /* Make PTE valid, store result in PTR. */ |
@@ -886,13 +1043,13 @@ build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte, | |||
886 | * restore PTE with value from PTR when done. | 1043 | * restore PTE with value from PTR when done. |
887 | */ | 1044 | */ |
888 | static void __cpuinit | 1045 | static void __cpuinit |
889 | build_pte_writable(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | 1046 | build_pte_writable(u32 **p, struct uasm_reloc **r, |
890 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1047 | unsigned int pte, unsigned int ptr, enum label_id lid) |
891 | { | 1048 | { |
892 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1049 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); |
893 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1050 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); |
894 | uasm_il_bnez(p, r, pte, lid); | 1051 | uasm_il_bnez(p, r, pte, lid); |
895 | iPTE_LW(p, l, pte, ptr); | 1052 | iPTE_LW(p, pte, ptr); |
896 | } | 1053 | } |
897 | 1054 | ||
898 | /* Make PTE writable, update software status bits as well, then store | 1055 | /* Make PTE writable, update software status bits as well, then store |
@@ -913,12 +1070,12 @@ build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte, | |||
913 | * restore PTE with value from PTR when done. | 1070 | * restore PTE with value from PTR when done. |
914 | */ | 1071 | */ |
915 | static void __cpuinit | 1072 | static void __cpuinit |
916 | build_pte_modifiable(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | 1073 | build_pte_modifiable(u32 **p, struct uasm_reloc **r, |
917 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1074 | unsigned int pte, unsigned int ptr, enum label_id lid) |
918 | { | 1075 | { |
919 | uasm_i_andi(p, pte, pte, _PAGE_WRITE); | 1076 | uasm_i_andi(p, pte, pte, _PAGE_WRITE); |
920 | uasm_il_beqz(p, r, pte, lid); | 1077 | uasm_il_beqz(p, r, pte, lid); |
921 | iPTE_LW(p, l, pte, ptr); | 1078 | iPTE_LW(p, pte, ptr); |
922 | } | 1079 | } |
923 | 1080 | ||
924 | /* | 1081 | /* |
@@ -994,7 +1151,7 @@ static void __cpuinit build_r3000_tlb_load_handler(void) | |||
994 | memset(relocs, 0, sizeof(relocs)); | 1151 | memset(relocs, 0, sizeof(relocs)); |
995 | 1152 | ||
996 | build_r3000_tlbchange_handler_head(&p, K0, K1); | 1153 | build_r3000_tlbchange_handler_head(&p, K0, K1); |
997 | build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl); | 1154 | build_pte_present(&p, &r, K0, K1, label_nopage_tlbl); |
998 | uasm_i_nop(&p); /* load delay */ | 1155 | uasm_i_nop(&p); /* load delay */ |
999 | build_make_valid(&p, &r, K0, K1); | 1156 | build_make_valid(&p, &r, K0, K1); |
1000 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); | 1157 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); |
@@ -1024,7 +1181,7 @@ static void __cpuinit build_r3000_tlb_store_handler(void) | |||
1024 | memset(relocs, 0, sizeof(relocs)); | 1181 | memset(relocs, 0, sizeof(relocs)); |
1025 | 1182 | ||
1026 | build_r3000_tlbchange_handler_head(&p, K0, K1); | 1183 | build_r3000_tlbchange_handler_head(&p, K0, K1); |
1027 | build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs); | 1184 | build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs); |
1028 | uasm_i_nop(&p); /* load delay */ | 1185 | uasm_i_nop(&p); /* load delay */ |
1029 | build_make_write(&p, &r, K0, K1); | 1186 | build_make_write(&p, &r, K0, K1); |
1030 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); | 1187 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); |
@@ -1054,7 +1211,7 @@ static void __cpuinit build_r3000_tlb_modify_handler(void) | |||
1054 | memset(relocs, 0, sizeof(relocs)); | 1211 | memset(relocs, 0, sizeof(relocs)); |
1055 | 1212 | ||
1056 | build_r3000_tlbchange_handler_head(&p, K0, K1); | 1213 | build_r3000_tlbchange_handler_head(&p, K0, K1); |
1057 | build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm); | 1214 | build_pte_modifiable(&p, &r, K0, K1, label_nopage_tlbm); |
1058 | uasm_i_nop(&p); /* load delay */ | 1215 | uasm_i_nop(&p); /* load delay */ |
1059 | build_make_write(&p, &r, K0, K1); | 1216 | build_make_write(&p, &r, K0, K1); |
1060 | build_r3000_pte_reload_tlbwi(&p, K0, K1); | 1217 | build_r3000_pte_reload_tlbwi(&p, K0, K1); |
@@ -1087,6 +1244,15 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l, | |||
1087 | build_get_pgde32(p, pte, ptr); /* get pgd in ptr */ | 1244 | build_get_pgde32(p, pte, ptr); /* get pgd in ptr */ |
1088 | #endif | 1245 | #endif |
1089 | 1246 | ||
1247 | #ifdef CONFIG_HUGETLB_PAGE | ||
1248 | /* | ||
1249 | * For huge tlb entries, pmd doesn't contain an address but | ||
1250 | * instead contains the tlb pte. Check the PAGE_HUGE bit and | ||
1251 | * see if we need to jump to huge tlb processing. | ||
1252 | */ | ||
1253 | build_is_huge_pte(p, r, pte, ptr, label_tlb_huge_update); | ||
1254 | #endif | ||
1255 | |||
1090 | UASM_i_MFC0(p, pte, C0_BADVADDR); | 1256 | UASM_i_MFC0(p, pte, C0_BADVADDR); |
1091 | UASM_i_LW(p, ptr, 0, ptr); | 1257 | UASM_i_LW(p, ptr, 0, ptr); |
1092 | UASM_i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2); | 1258 | UASM_i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2); |
@@ -1096,7 +1262,7 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l, | |||
1096 | #ifdef CONFIG_SMP | 1262 | #ifdef CONFIG_SMP |
1097 | uasm_l_smp_pgtable_change(l, *p); | 1263 | uasm_l_smp_pgtable_change(l, *p); |
1098 | #endif | 1264 | #endif |
1099 | iPTE_LW(p, l, pte, ptr); /* get even pte */ | 1265 | iPTE_LW(p, pte, ptr); /* get even pte */ |
1100 | if (!m4kc_tlbp_war()) | 1266 | if (!m4kc_tlbp_war()) |
1101 | build_tlb_probe_entry(p); | 1267 | build_tlb_probe_entry(p); |
1102 | } | 1268 | } |
@@ -1138,12 +1304,25 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
1138 | } | 1304 | } |
1139 | 1305 | ||
1140 | build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1); | 1306 | build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1); |
1141 | build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl); | 1307 | build_pte_present(&p, &r, K0, K1, label_nopage_tlbl); |
1142 | if (m4kc_tlbp_war()) | 1308 | if (m4kc_tlbp_war()) |
1143 | build_tlb_probe_entry(&p); | 1309 | build_tlb_probe_entry(&p); |
1144 | build_make_valid(&p, &r, K0, K1); | 1310 | build_make_valid(&p, &r, K0, K1); |
1145 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); | 1311 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); |
1146 | 1312 | ||
1313 | #ifdef CONFIG_HUGETLB_PAGE | ||
1314 | /* | ||
1315 | * This is the entry point when build_r4000_tlbchange_handler_head | ||
1316 | * spots a huge page. | ||
1317 | */ | ||
1318 | uasm_l_tlb_huge_update(&l, p); | ||
1319 | iPTE_LW(&p, K0, K1); | ||
1320 | build_pte_present(&p, &r, K0, K1, label_nopage_tlbl); | ||
1321 | build_tlb_probe_entry(&p); | ||
1322 | uasm_i_ori(&p, K0, K0, (_PAGE_ACCESSED | _PAGE_VALID)); | ||
1323 | build_huge_handler_tail(&p, &r, &l, K0, K1); | ||
1324 | #endif | ||
1325 | |||
1147 | uasm_l_nopage_tlbl(&l, p); | 1326 | uasm_l_nopage_tlbl(&l, p); |
1148 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); | 1327 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); |
1149 | uasm_i_nop(&p); | 1328 | uasm_i_nop(&p); |
@@ -1169,12 +1348,26 @@ static void __cpuinit build_r4000_tlb_store_handler(void) | |||
1169 | memset(relocs, 0, sizeof(relocs)); | 1348 | memset(relocs, 0, sizeof(relocs)); |
1170 | 1349 | ||
1171 | build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1); | 1350 | build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1); |
1172 | build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs); | 1351 | build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs); |
1173 | if (m4kc_tlbp_war()) | 1352 | if (m4kc_tlbp_war()) |
1174 | build_tlb_probe_entry(&p); | 1353 | build_tlb_probe_entry(&p); |
1175 | build_make_write(&p, &r, K0, K1); | 1354 | build_make_write(&p, &r, K0, K1); |
1176 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); | 1355 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); |
1177 | 1356 | ||
1357 | #ifdef CONFIG_HUGETLB_PAGE | ||
1358 | /* | ||
1359 | * This is the entry point when | ||
1360 | * build_r4000_tlbchange_handler_head spots a huge page. | ||
1361 | */ | ||
1362 | uasm_l_tlb_huge_update(&l, p); | ||
1363 | iPTE_LW(&p, K0, K1); | ||
1364 | build_pte_writable(&p, &r, K0, K1, label_nopage_tlbs); | ||
1365 | build_tlb_probe_entry(&p); | ||
1366 | uasm_i_ori(&p, K0, K0, | ||
1367 | _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY); | ||
1368 | build_huge_handler_tail(&p, &r, &l, K0, K1); | ||
1369 | #endif | ||
1370 | |||
1178 | uasm_l_nopage_tlbs(&l, p); | 1371 | uasm_l_nopage_tlbs(&l, p); |
1179 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 1372 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |
1180 | uasm_i_nop(&p); | 1373 | uasm_i_nop(&p); |
@@ -1200,13 +1393,27 @@ static void __cpuinit build_r4000_tlb_modify_handler(void) | |||
1200 | memset(relocs, 0, sizeof(relocs)); | 1393 | memset(relocs, 0, sizeof(relocs)); |
1201 | 1394 | ||
1202 | build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1); | 1395 | build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1); |
1203 | build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm); | 1396 | build_pte_modifiable(&p, &r, K0, K1, label_nopage_tlbm); |
1204 | if (m4kc_tlbp_war()) | 1397 | if (m4kc_tlbp_war()) |
1205 | build_tlb_probe_entry(&p); | 1398 | build_tlb_probe_entry(&p); |
1206 | /* Present and writable bits set, set accessed and dirty bits. */ | 1399 | /* Present and writable bits set, set accessed and dirty bits. */ |
1207 | build_make_write(&p, &r, K0, K1); | 1400 | build_make_write(&p, &r, K0, K1); |
1208 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); | 1401 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); |
1209 | 1402 | ||
1403 | #ifdef CONFIG_HUGETLB_PAGE | ||
1404 | /* | ||
1405 | * This is the entry point when | ||
1406 | * build_r4000_tlbchange_handler_head spots a huge page. | ||
1407 | */ | ||
1408 | uasm_l_tlb_huge_update(&l, p); | ||
1409 | iPTE_LW(&p, K0, K1); | ||
1410 | build_pte_modifiable(&p, &r, K0, K1, label_nopage_tlbm); | ||
1411 | build_tlb_probe_entry(&p); | ||
1412 | uasm_i_ori(&p, K0, K0, | ||
1413 | _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY); | ||
1414 | build_huge_handler_tail(&p, &r, &l, K0, K1); | ||
1415 | #endif | ||
1416 | |||
1210 | uasm_l_nopage_tlbm(&l, p); | 1417 | uasm_l_nopage_tlbm(&l, p); |
1211 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 1418 | uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |
1212 | uasm_i_nop(&p); | 1419 | uasm_i_nop(&p); |