diff options
Diffstat (limited to 'arch/mips/mm')
-rw-r--r-- | arch/mips/mm/tlbex.c | 34 |
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 | |||
652 | static void __cpuinit build_r4000_tlb_refill_handler(void) | 660 | static 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 | ||