Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8df5beac authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Ralf Baechle
Browse files

[MIPS] Workaround for 4Kc machine check exception

parent 48d480b0
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -57,6 +57,21 @@ static __init int __maybe_unused r10000_llsc_war(void)
	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
 * 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_25KF:
	case CPU_LOONGSON2:
		if (m4kc_tlbp_war())
			i_nop(p);
		tlbw(p);
		break;

@@ -1705,6 +1722,7 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
	l_smp_pgtable_change(l, *p);
# endif
	iPTE_LW(p, l, pte, ptr); /* get even pte */
	if (!m4kc_tlbp_war())
		build_tlb_probe_entry(p);
}

@@ -1747,6 +1765,8 @@ static void __init build_r4000_tlb_load_handler(void)

	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
	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_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_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_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_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. */
	build_make_write(&p, &r, K0, K1);
	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);