[MIPS] Workaround for 4Kc machine check exception
Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
48d480b0bd
commit
8df5beac2a
1 changed files with 25 additions and 1 deletions
|
@ -57,6 +57,21 @@ static __init int __maybe_unused r10000_llsc_war(void)
|
||||||
return R10000_LLSC_WAR;
|
return R10000_LLSC_WAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Found by experiment: At least some revisions of the 4kc throw under
|
||||||
|
* some circumstances a machine check exception, triggered by invalid
|
||||||
|
* values in the index register. Delaying the tlbp instruction until
|
||||||
|
* after the next branch, plus adding an additional nop in front of
|
||||||
|
* tlbwi/tlbwr avoids the invalid index register values. Nobody knows
|
||||||
|
* why; it's not an issue caused by the core RTL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static __init int __attribute__((unused)) m4kc_tlbp_war(void)
|
||||||
|
{
|
||||||
|
return (current_cpu_data.processor_id & 0xffff00) ==
|
||||||
|
(PRID_COMP_MIPS | PRID_IMP_4KC);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A little micro-assembler, intended for TLB refill handler
|
* A little micro-assembler, intended for TLB refill handler
|
||||||
* synthesizing. It is intentionally kept simple, does only support
|
* synthesizing. It is intentionally kept simple, does only support
|
||||||
|
@ -894,6 +909,8 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
|
||||||
case CPU_20KC:
|
case CPU_20KC:
|
||||||
case CPU_25KF:
|
case CPU_25KF:
|
||||||
case CPU_LOONGSON2:
|
case CPU_LOONGSON2:
|
||||||
|
if (m4kc_tlbp_war())
|
||||||
|
i_nop(p);
|
||||||
tlbw(p);
|
tlbw(p);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1705,7 +1722,8 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
|
||||||
l_smp_pgtable_change(l, *p);
|
l_smp_pgtable_change(l, *p);
|
||||||
# endif
|
# endif
|
||||||
iPTE_LW(p, l, pte, ptr); /* get even pte */
|
iPTE_LW(p, l, pte, ptr); /* get even pte */
|
||||||
build_tlb_probe_entry(p);
|
if (!m4kc_tlbp_war())
|
||||||
|
build_tlb_probe_entry(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
|
@ -1747,6 +1765,8 @@ static void __init build_r4000_tlb_load_handler(void)
|
||||||
|
|
||||||
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
|
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
|
||||||
build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
|
build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
|
||||||
|
if (m4kc_tlbp_war())
|
||||||
|
build_tlb_probe_entry(&p);
|
||||||
build_make_valid(&p, &r, K0, K1);
|
build_make_valid(&p, &r, K0, K1);
|
||||||
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
|
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
|
||||||
|
|
||||||
|
@ -1781,6 +1801,8 @@ static void __init build_r4000_tlb_store_handler(void)
|
||||||
|
|
||||||
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
|
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
|
||||||
build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
|
build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
|
||||||
|
if (m4kc_tlbp_war())
|
||||||
|
build_tlb_probe_entry(&p);
|
||||||
build_make_write(&p, &r, K0, K1);
|
build_make_write(&p, &r, K0, K1);
|
||||||
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
|
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
|
||||||
|
|
||||||
|
@ -1815,6 +1837,8 @@ static void __init build_r4000_tlb_modify_handler(void)
|
||||||
|
|
||||||
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
|
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
|
||||||
build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
|
build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
|
||||||
|
if (m4kc_tlbp_war())
|
||||||
|
build_tlb_probe_entry(&p);
|
||||||
/* Present and writable bits set, set accessed and dirty bits. */
|
/* Present and writable bits set, set accessed and dirty bits. */
|
||||||
build_make_write(&p, &r, K0, K1);
|
build_make_write(&p, &r, K0, K1);
|
||||||
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
|
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
|
||||||
|
|
Loading…
Reference in a new issue