Skip to content

Commit 794b679

Browse files
FlyGoatgregkh
authored andcommitted
MIPS: mm: tlb-r4k: Uniquify TLB entries on init
commit 35ad7e1 upstream. Hardware or bootloader will initialize TLB entries to any value, which may collide with kernel's UNIQUE_ENTRYHI value. On MIPS microAptiv/M5150 family of cores this will trigger machine check exception and cause boot failure. On M5150 simulation this could happen 7 times out of 1000 boots. Replace local_flush_tlb_all() with r4k_tlb_uniquify() which probes each TLB ENTRIHI unique value for collisions before it's written, and in case of collision try a different ASID. Cc: stable@kernel.org Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent f5d093b commit 794b679

1 file changed

Lines changed: 55 additions & 1 deletion

File tree

arch/mips/mm/tlb-r4k.c

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,60 @@ static int __init set_ntlb(char *str)
498498

499499
__setup("ntlb=", set_ntlb);
500500

501+
/* Initialise all TLB entries with unique values */
502+
static void r4k_tlb_uniquify(void)
503+
{
504+
int entry = num_wired_entries();
505+
506+
htw_stop();
507+
write_c0_entrylo0(0);
508+
write_c0_entrylo1(0);
509+
510+
while (entry < current_cpu_data.tlbsize) {
511+
unsigned long asid_mask = cpu_asid_mask(&current_cpu_data);
512+
unsigned long asid = 0;
513+
int idx;
514+
515+
/* Skip wired MMID to make ginvt_mmid work */
516+
if (cpu_has_mmid)
517+
asid = MMID_KERNEL_WIRED + 1;
518+
519+
/* Check for match before using UNIQUE_ENTRYHI */
520+
do {
521+
if (cpu_has_mmid) {
522+
write_c0_memorymapid(asid);
523+
write_c0_entryhi(UNIQUE_ENTRYHI(entry));
524+
} else {
525+
write_c0_entryhi(UNIQUE_ENTRYHI(entry) | asid);
526+
}
527+
mtc0_tlbw_hazard();
528+
tlb_probe();
529+
tlb_probe_hazard();
530+
idx = read_c0_index();
531+
/* No match or match is on current entry */
532+
if (idx < 0 || idx == entry)
533+
break;
534+
/*
535+
* If we hit a match, we need to try again with
536+
* a different ASID.
537+
*/
538+
asid++;
539+
} while (asid < asid_mask);
540+
541+
if (idx >= 0 && idx != entry)
542+
panic("Unable to uniquify TLB entry %d", idx);
543+
544+
write_c0_index(entry);
545+
mtc0_tlbw_hazard();
546+
tlb_write_indexed();
547+
entry++;
548+
}
549+
550+
tlbw_use_hazard();
551+
htw_start();
552+
flush_micro_tlb();
553+
}
554+
501555
/*
502556
* Configure TLB (for init or after a CPU has been powered off).
503557
*/
@@ -537,7 +591,7 @@ static void r4k_tlb_configure(void)
537591
temp_tlb_entry = current_cpu_data.tlbsize - 1;
538592

539593
/* From this point on the ARC firmware is dead. */
540-
local_flush_tlb_all();
594+
r4k_tlb_uniquify();
541595

542596
/* Did I tell you that ARC SUCKS? */
543597
}

0 commit comments

Comments
 (0)