Optimize TLB refill handler folding and cleanup.
cover Optimize TLB refill handler folding and cleanup.
The first patch in the set is unchanged from that last time I sent it, but since it is a prerequisite for the second, I am sending it again. In it we add some documentation on the TLB refill handler folding and replace some magic numbers with symbolic constants.
The second patch is the latest iteration on eliminating unnecessary branches from the refill handler. We now use macro's patch rebased onto the first patch.
I will reply with the two patches.
David Daney (2):
MIPS: Replace some magic numbers with symbolic values in tlbex.c (v2)
MIPS: Fold the TLB refill at the vmalloc path if possible.
arch/mips/mm/tlbex.c | 87 +++++++++++++++++++++++++++++++++++++------------ 1 files changed, 65 insertions(+), 22 deletions(-)
PATCH 1/2 MIPS: Replace some magic numbers with symbolic values in tlbex.c (v2)
The logic used to split the r4000 refill handler is liberally sprinkled with magic numbers. We attempt to explain what they are and normalize them against a new symbolic value (MIPS64_REFILL_INSNS).
Changes from v1: Corrected spelling in comment.
--- arch/mips/mm/tlbex.c | 34 ++++++++++++++++++++++++++-------- 1 files changed, 26 insertions(+), 8 deletions(-)
arch/mips/mm/tlbex.c +26 -8
@@ -649,6 +649,14 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,#endif } +/* +* For a 64-bit kernel, we are using the 64-bit XTLB refill exception +* because EXL == 0. If we wrap, we can also use the 32 instruction +* slots before the XTLB refill exception handler which belong to the +* unused TLB refill exception. +*/ +#define MIPS64_REFILL_INSNS 32 +static void __cpuinit build_r4000_tlb_refill_handler (void ) {u32 *p = tlb_handler;
@@ -702,9 +710,10 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)if ((p - tlb_handler) >64 )panic ("TLB refill handler space exceeded" );#else -if (((p - tlb_handler) >63 ) - || (((p - tlb_handler) >61 ) - &&uasm_insn_has_bdelay (relocs, tlb_handler +29 ))) +if (((p - tlb_handler) > (MIPS64_REFILL_INSNS *2 ) -1 ) + || (((p - tlb_handler) > (MIPS64_REFILL_INSNS *2 ) -3 ) + &&uasm_insn_has_bdelay (relocs, + tlb_handler +MIPS64_REFILL_INSNS -3 )))panic ("TLB refill handler space exceeded" );#endif
@@ -717,16 +726,24 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)uasm_copy_handler (relocs, labels, tlb_handler, p, f); final_len = p - tlb_handler;#else /* CONFIG_64BIT */ - f = final_handler +32 ; -if ((p - tlb_handler) <=32 ) { + f = final_handler +MIPS64_REFILL_INSNS ; +if ((p - tlb_handler) <=MIPS64_REFILL_INSNS ) {/* Just copy the handler. */ uasm_copy_handler (relocs, labels, tlb_handler, p, f); final_len = p - tlb_handler; }else { -u32 *split = tlb_handler +30 ; +/* +* Split two instructions before the end. One for the +* branch and one for the instruction in the delay +* slot. +*/ +u32 *split = tlb_handler +MIPS64_REFILL_INSNS -2 ;/* -* Find the split point. +* Find the split point. If the branch would fall in +* a delay slot, we must back up an additional +* instruction so that it is no longer in a delay +* slot. */ if (uasm_insn_has_bdelay (relocs, split -1 )) split--;
@@ -749,7 +766,8 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)/* Copy the rest of the handler. */ uasm_copy_handler (relocs, labels, split, p, final_handler); - final_len = (f - (final_handler + 32)) + (p - split); + final_len = (f - (final_handler +MIPS64_REFILL_INSNS )) + + (p - split); }#endif /* CONFIG_64BIT */
Signature · 1 line
1.6.0.6
PATCH 2/2 MIPS: Fold the TLB refill at the vmalloc path if possible.
In reply to David DaneyTry to fold the 64-bit TLB refill handler opportunistically at the beginning of the vmalloc path so as to avoid splitting execution flow in half and wasting cycles for a branch required at that point then. Resort to doing the split if either of the newly created parts would not fit into its designated slot.
--- arch/mips/mm/tlbex.c | 73 +++++++++++++++++++++++++++++++++---------------- 1 files changed, 49 insertions(+), 24 deletions(-)
arch/mips/mm/tlbex.c +49 -24
@@ -6,7 +6,7 @@* Synthesize TLB refill handlers at runtime. * * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer -* Copyright (C) 2005, 2007 Maciej W. Rozycki +* Copyright (C) 2005, 2007, 2008, 2009 Maciej W. Rozycki * Copyright (C) 2006 Ralf Baechle ([email protected]) * * ... and the days got worse and worse and now you see
@@ -19,6 +19,7 @@* (Condolences to Napoleon XIV) */ +#include <linux/bug.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/string.h>
@@ -732,36 +733,60 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)uasm_copy_handler (relocs, labels, tlb_handler, p, f); final_len = p - tlb_handler; }else { -/* -* Split two instructions before the end. One for the -* branch and one for the instruction in the delay -* slot. -*/ -u32 *split = tlb_handler +MIPS64_REFILL_INSNS -2 ; +#ifdef MODULE_START +const enum label_id ls = label_module_alloc; +#else +const enum label_id ls = label_vmalloc; +#endif +u32 *split; +int ov =0 ; +int i; + +for (i =0 ; i <ARRAY_SIZE (labels) && labels[i].lab != ls; i++) + ; +BUG_ON (i ==ARRAY_SIZE (labels)); + split = labels[i].addr;/* -* Find the split point. If the branch would fall in -* a delay slot, we must back up an additional -* instruction so that it is no longer in a delay -* slot. +* See if we have overflown one way or the other. */ -if (uasm_insn_has_bdelay (relocs, split -1 )) - split--; - +if (split > tlb_handler +MIPS64_REFILL_INSNS || + split < p -MIPS64_REFILL_INSNS ) + ov =1 ; + +if (ov) { +/* +* Split two instructions before the end. One +* for the branch and one for the instruction +* in the delay slot. +*/ + split = tlb_handler +MIPS64_REFILL_INSNS -2 ; + +/* +* If the branch would fall in a delay slot, +* we must back up an additional instruction +* so that it is no longer in a delay slot. +*/ +if (uasm_insn_has_bdelay (relocs, split -1 )) + split--; + }/* Copy first part of the handler. */ uasm_copy_handler (relocs, labels, tlb_handler, split, f); f += split - tlb_handler; -/* Insert branch. */ -uasm_l_split (&l, final_handler); -uasm_il_b (&f, &r, label_split); -if (uasm_insn_has_bdelay (relocs, split)) -uasm_i_nop (&f); -else { -uasm_copy_handler (relocs, labels, split, split +1 , f); -uasm_move_labels (labels, f, f +1 ,-1 ); - f++; - split++; +if (ov) { +/* Insert branch. */ +uasm_l_split (&l, final_handler); +uasm_il_b (&f, &r, label_split); +if (uasm_insn_has_bdelay (relocs, split)) +uasm_i_nop (&f); +else { +uasm_copy_handler (relocs, labels, + split, split +1 , f); +uasm_move_labels (labels, f, f +1 ,-1 ); + f++; + split++; + } }/* Copy the rest of the handler. */
Signature · 1 line
1.6.0.6
Quoted 8 lines · David Daney
The first patch in the set is unchanged from that last time I sent it, but since it is a prerequisite for the second, I am sending it again. In it we add some documentation on the TLB refill handler folding and replace some magic numbers with symbolic constants.
The second patch is the latest iteration on eliminating unnecessary branches from the refill handler. We now use macro's patch rebased onto the first patch.
Thanks, I droped the whole series into -queue and my tree for -next.
Ralf