aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/mm/tlbex.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 0615b62efd6d..678e63398461 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -649,6 +649,14 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
649#endif 649#endif
650} 650}
651 651
652/*
653 * For a 64-bit kernel, we are using the 64-bit XTLB refill exception
654 * because EXL == 0. If we wrap, we can also use the 32 instruction
655 * slots before the XTLB refill exception handler which belong to the
656 * unused TLB refill exception.
657 */
658#define MIPS64_REFILL_INSNS 32
659
652static void __cpuinit build_r4000_tlb_refill_handler(void) 660static void __cpuinit build_r4000_tlb_refill_handler(void)
653{ 661{
654 u32 *p = tlb_handler; 662 u32 *p = tlb_handler;
@@ -702,9 +710,10 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
702 if ((p - tlb_handler) > 64) 710 if ((p - tlb_handler) > 64)
703 panic("TLB refill handler space exceeded"); 711 panic("TLB refill handler space exceeded");
704#else 712#else
705 if (((p - tlb_handler) > 63) 713 if (((p - tlb_handler) > (MIPS64_REFILL_INSNS * 2) - 1)
706 || (((p - tlb_handler) > 61) 714 || (((p - tlb_handler) > (MIPS64_REFILL_INSNS * 2) - 3)
707 && uasm_insn_has_bdelay(relocs, tlb_handler + 29))) 715 && uasm_insn_has_bdelay(relocs,
716 tlb_handler + MIPS64_REFILL_INSNS - 3)))
708 panic("TLB refill handler space exceeded"); 717 panic("TLB refill handler space exceeded");
709#endif 718#endif
710 719
@@ -717,16 +726,24 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
717 uasm_copy_handler(relocs, labels, tlb_handler, p, f); 726 uasm_copy_handler(relocs, labels, tlb_handler, p, f);
718 final_len = p - tlb_handler; 727 final_len = p - tlb_handler;
719#else /* CONFIG_64BIT */ 728#else /* CONFIG_64BIT */
720 f = final_handler + 32; 729 f = final_handler + MIPS64_REFILL_INSNS;
721 if ((p - tlb_handler) <= 32) { 730 if ((p - tlb_handler) <= MIPS64_REFILL_INSNS) {
722 /* Just copy the handler. */ 731 /* Just copy the handler. */
723 uasm_copy_handler(relocs, labels, tlb_handler, p, f); 732 uasm_copy_handler(relocs, labels, tlb_handler, p, f);
724 final_len = p - tlb_handler; 733 final_len = p - tlb_handler;
725 } else { 734 } else {
726 u32 *split = tlb_handler + 30; 735 /*
736 * Split two instructions before the end. One for the
737 * branch and one for the instruction in the delay
738 * slot.
739 */
740 u32 *split = tlb_handler + MIPS64_REFILL_INSNS - 2;
727 741
728 /* 742 /*
729 * Find the split point. 743 * Find the split point. If the branch would fall in
744 * a delay slot, we must back up an additional
745 * instruction so that it is no longer in a delay
746 * slot.
730 */ 747 */
731 if (uasm_insn_has_bdelay(relocs, split - 1)) 748 if (uasm_insn_has_bdelay(relocs, split - 1))
732 split--; 749 split--;
@@ -749,7 +766,8 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
749 766
750 /* Copy the rest of the handler. */ 767 /* Copy the rest of the handler. */
751 uasm_copy_handler(relocs, labels, split, p, final_handler); 768 uasm_copy_handler(relocs, labels, split, p, final_handler);
752 final_len = (f - (final_handler + 32)) + (p - split); 769 final_len = (f - (final_handler + MIPS64_REFILL_INSNS)) +
770 (p - split);
753 } 771 }
754#endif /* CONFIG_64BIT */ 772#endif /* CONFIG_64BIT */
755 773