mirror of
https://github.com/torvalds/linux.git
synced 2025-11-30 23:16:01 +07:00
MIPS: mm: tlb-r4k: Uniquify TLB entries on init
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>
This commit is contained in:
committed by
Thomas Bogendoerfer
parent
b9ace0647f
commit
35ad7e1815
@@ -508,6 +508,60 @@ static int __init set_ntlb(char *str)
|
||||
|
||||
__setup("ntlb=", set_ntlb);
|
||||
|
||||
/* Initialise all TLB entries with unique values */
|
||||
static void r4k_tlb_uniquify(void)
|
||||
{
|
||||
int entry = num_wired_entries();
|
||||
|
||||
htw_stop();
|
||||
write_c0_entrylo0(0);
|
||||
write_c0_entrylo1(0);
|
||||
|
||||
while (entry < current_cpu_data.tlbsize) {
|
||||
unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data);
|
||||
unsigned long asid = 0;
|
||||
int idx;
|
||||
|
||||
/* Skip wired MMID to make ginvt_mmid work */
|
||||
if (cpu_has_mmid)
|
||||
asid = MMID_KERNEL_WIRED + 1;
|
||||
|
||||
/* Check for match before using UNIQUE_ENTRYHI */
|
||||
do {
|
||||
if (cpu_has_mmid) {
|
||||
write_c0_memorymapid(asid);
|
||||
write_c0_entryhi(UNIQUE_ENTRYHI(entry));
|
||||
} else {
|
||||
write_c0_entryhi(UNIQUE_ENTRYHI(entry) | asid);
|
||||
}
|
||||
mtc0_tlbw_hazard();
|
||||
tlb_probe();
|
||||
tlb_probe_hazard();
|
||||
idx = read_c0_index();
|
||||
/* No match or match is on current entry */
|
||||
if (idx < 0 || idx == entry)
|
||||
break;
|
||||
/*
|
||||
* If we hit a match, we need to try again with
|
||||
* a different ASID.
|
||||
*/
|
||||
asid++;
|
||||
} while (asid < asid_mask);
|
||||
|
||||
if (idx >= 0 && idx != entry)
|
||||
panic("Unable to uniquify TLB entry %d", idx);
|
||||
|
||||
write_c0_index(entry);
|
||||
mtc0_tlbw_hazard();
|
||||
tlb_write_indexed();
|
||||
entry++;
|
||||
}
|
||||
|
||||
tlbw_use_hazard();
|
||||
htw_start();
|
||||
flush_micro_tlb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure TLB (for init or after a CPU has been powered off).
|
||||
*/
|
||||
@@ -547,7 +601,7 @@ static void r4k_tlb_configure(void)
|
||||
temp_tlb_entry = current_cpu_data.tlbsize - 1;
|
||||
|
||||
/* From this point on the ARC firmware is dead. */
|
||||
local_flush_tlb_all();
|
||||
r4k_tlb_uniquify();
|
||||
|
||||
/* Did I tell you that ARC SUCKS? */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user