When unaligned access triggered, do_ade() will access user address with EXL=1, and that may trigger tlb refill. Huacai On Wed, Jan 27, 2016 at 5:15 AM, David Daney <ddaney.cavm@xxxxxxxxx> wrote: > On 01/26/2016 05:26 AM, Huacai Chen wrote: >> >> If a tlb miss triggered when EXL=1, > > > How is that possible? The exception handlers are not in mapped memory, and > we clear EXL very early in the exception handlers. > > In valid code, how are you getting TLB related exceptions when EXL=1? > > >> tlb refill exception is treated as >> tlb invalid exception, so tlbp may fails. In this situation, CP0_Index >> register doesn't contain a valid value. This may not be a problem for >> VTLB since it is fully-associative. However, FTLB is set-associative so >> not every tlb entry is valid for a specific address. Thus, we should >> use tlbwr instead of tlbwi when tlbp fails. >> >> There is a similar case for huge page, so build_huge_tlb_write_entry() >> is also modified. If wmode != tlb_random, that means the caller is tlb >> invalid handler, we should select tlbr/tlbi depend on the tlbp result. >> >> Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx> >> --- >> arch/mips/mm/tlbex.c | 31 ++++++++++++++++++++++++++++++- >> 1 file changed, 30 insertions(+), 1 deletion(-) >> >> diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c >> index d0975cd..da68ffb 100644 >> --- a/arch/mips/mm/tlbex.c >> +++ b/arch/mips/mm/tlbex.c >> @@ -173,7 +173,10 @@ enum label_id { >> label_large_segbits_fault, >> #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT >> label_tlb_huge_update, >> + label_tail_huge_miss, >> + label_tail_huge_done, >> #endif >> + label_tail_miss, >> }; >> >> UASM_L_LA(_second_part) >> @@ -192,7 +195,10 @@ UASM_L_LA(_r3000_write_probe_fail) >> UASM_L_LA(_large_segbits_fault) >> #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT >> UASM_L_LA(_tlb_huge_update) >> +UASM_L_LA(_tail_huge_miss) >> +UASM_L_LA(_tail_huge_done) >> #endif >> +UASM_L_LA(_tail_miss) >> >> static int hazard_instance; >> >> @@ -706,8 +712,24 @@ static void build_huge_tlb_write_entry(u32 **p, >> struct uasm_label **l, >> uasm_i_ori(p, tmp, tmp, PM_HUGE_MASK & 0xffff); >> uasm_i_mtc0(p, tmp, C0_PAGEMASK); >> >> - build_tlb_write_entry(p, l, r, wmode); >> + if (wmode == tlb_random) { /* Caller is TLB Refill Handler */ >> + build_tlb_write_entry(p, l, r, wmode); >> + build_restore_pagemask(p, r, tmp, label_leave, >> restore_scratch); >> + return; >> + } >> + >> + /* Caller is TLB Load/Store/Modify Handler */ >> + uasm_i_mfc0(p, tmp, C0_INDEX); >> + uasm_il_bltz(p, r, tmp, label_tail_huge_miss); >> + uasm_i_nop(p); >> + build_tlb_write_entry(p, l, r, tlb_indexed); >> + uasm_il_b(p, r, label_tail_huge_done); >> + uasm_i_nop(p); >> + >> + uasm_l_tail_huge_miss(l, *p); >> + build_tlb_write_entry(p, l, r, tlb_random); >> >> + uasm_l_tail_huge_done(l, *p); >> build_restore_pagemask(p, r, tmp, label_leave, restore_scratch); >> } >> >> @@ -2026,7 +2048,14 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct >> uasm_label **l, >> uasm_i_ori(p, ptr, ptr, sizeof(pte_t)); >> uasm_i_xori(p, ptr, ptr, sizeof(pte_t)); >> build_update_entries(p, tmp, ptr); >> + uasm_i_mfc0(p, ptr, C0_INDEX); >> + uasm_il_bltz(p, r, ptr, label_tail_miss); >> + uasm_i_nop(p); >> build_tlb_write_entry(p, l, r, tlb_indexed); >> + uasm_il_b(p, r, label_leave); >> + uasm_i_nop(p); >> + uasm_l_tail_miss(l, *p); >> + build_tlb_write_entry(p, l, r, tlb_random); >> uasm_l_leave(l, *p); >> build_restore_work_registers(p); >> uasm_i_eret(p); /* return from trap */ >> > >