diff options
Diffstat (limited to 'arch/mips/mm/tlbex.c')
-rw-r--r-- | arch/mips/mm/tlbex.c | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 678e63398461..d9a18b2b7f82 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -6,7 +6,7 @@ | |||
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 | * | 11 | * |
12 | * ... and the days got worse and worse and now you see | 12 | * ... and the days got worse and worse and now you see |
@@ -19,6 +19,7 @@ | |||
19 | * (Condolences to Napoleon XIV) | 19 | * (Condolences to Napoleon XIV) |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/bug.h> | ||
22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
23 | #include <linux/types.h> | 24 | #include <linux/types.h> |
24 | #include <linux/string.h> | 25 | #include <linux/string.h> |
@@ -732,36 +733,60 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
732 | uasm_copy_handler(relocs, labels, tlb_handler, p, f); | 733 | uasm_copy_handler(relocs, labels, tlb_handler, p, f); |
733 | final_len = p - tlb_handler; | 734 | final_len = p - tlb_handler; |
734 | } else { | 735 | } else { |
735 | /* | 736 | #ifdef MODULE_START |
736 | * Split two instructions before the end. One for the | 737 | const enum label_id ls = label_module_alloc; |
737 | * branch and one for the instruction in the delay | 738 | #else |
738 | * slot. | 739 | const enum label_id ls = label_vmalloc; |
739 | */ | 740 | #endif |
740 | u32 *split = tlb_handler + MIPS64_REFILL_INSNS - 2; | 741 | u32 *split; |
742 | int ov = 0; | ||
743 | int i; | ||
744 | |||
745 | for (i = 0; i < ARRAY_SIZE(labels) && labels[i].lab != ls; i++) | ||
746 | ; | ||
747 | BUG_ON(i == ARRAY_SIZE(labels)); | ||
748 | split = labels[i].addr; | ||
741 | 749 | ||
742 | /* | 750 | /* |
743 | * Find the split point. If the branch would fall in | 751 | * See if we have overflown one way or the other. |
744 | * a delay slot, we must back up an additional | ||
745 | * instruction so that it is no longer in a delay | ||
746 | * slot. | ||
747 | */ | 752 | */ |
748 | if (uasm_insn_has_bdelay(relocs, split - 1)) | 753 | if (split > tlb_handler + MIPS64_REFILL_INSNS || |
749 | split--; | 754 | split < p - MIPS64_REFILL_INSNS) |
750 | 755 | ov = 1; | |
756 | |||
757 | if (ov) { | ||
758 | /* | ||
759 | * Split two instructions before the end. One | ||
760 | * for the branch and one for the instruction | ||
761 | * in the delay slot. | ||
762 | */ | ||
763 | split = tlb_handler + MIPS64_REFILL_INSNS - 2; | ||
764 | |||
765 | /* | ||
766 | * If the branch would fall in a delay slot, | ||
767 | * we must back up an additional instruction | ||
768 | * so that it is no longer in a delay slot. | ||
769 | */ | ||
770 | if (uasm_insn_has_bdelay(relocs, split - 1)) | ||
771 | split--; | ||
772 | } | ||
751 | /* Copy first part of the handler. */ | 773 | /* Copy first part of the handler. */ |
752 | uasm_copy_handler(relocs, labels, tlb_handler, split, f); | 774 | uasm_copy_handler(relocs, labels, tlb_handler, split, f); |
753 | f += split - tlb_handler; | 775 | f += split - tlb_handler; |
754 | 776 | ||
755 | /* Insert branch. */ | 777 | if (ov) { |
756 | uasm_l_split(&l, final_handler); | 778 | /* Insert branch. */ |
757 | uasm_il_b(&f, &r, label_split); | 779 | uasm_l_split(&l, final_handler); |
758 | if (uasm_insn_has_bdelay(relocs, split)) | 780 | uasm_il_b(&f, &r, label_split); |
759 | uasm_i_nop(&f); | 781 | if (uasm_insn_has_bdelay(relocs, split)) |
760 | else { | 782 | uasm_i_nop(&f); |
761 | uasm_copy_handler(relocs, labels, split, split + 1, f); | 783 | else { |
762 | uasm_move_labels(labels, f, f + 1, -1); | 784 | uasm_copy_handler(relocs, labels, |
763 | f++; | 785 | split, split + 1, f); |
764 | split++; | 786 | uasm_move_labels(labels, f, f + 1, -1); |
787 | f++; | ||
788 | split++; | ||
789 | } | ||
765 | } | 790 | } |
766 | 791 | ||
767 | /* Copy the rest of the handler. */ | 792 | /* Copy the rest of the handler. */ |