Skip to content

Commit 7a1201a

Browse files
FlyGoatopsiff
authored andcommitted
MIPS: mm: tlb-r4k: Uniquify TLB entries on init
commit 35ad7e181541aa5757f9f316768d3e64403ec843 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: [email protected] Signed-off-by: Jiaxun Yang <[email protected]> Signed-off-by: Thomas Bogendoerfer <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> (cherry picked from commit d98b34c40dc73b3743784bc51995b813483e2081)
1 parent 2eec176 commit 7a1201a

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

arch/mips/mm/tlb-r4k.c

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

507507
__setup("ntlb=", set_ntlb);
508508

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

547601
/* From this point on the ARC firmware is dead. */
548-
local_flush_tlb_all();
602+
r4k_tlb_uniquify();
549603

550604
/* Did I tell you that ARC SUCKS? */
551605
}

0 commit comments

Comments
 (0)