Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jiaxun Yang and committed by
Thomas Bogendoerfer
35ad7e18 b9ace064

+55 -1
+55 -1
arch/mips/mm/tlb-r4k.c
··· 508 508 509 509 __setup("ntlb=", set_ntlb); 510 510 511 + /* Initialise all TLB entries with unique values */ 512 + static void r4k_tlb_uniquify(void) 513 + { 514 + int entry = num_wired_entries(); 515 + 516 + htw_stop(); 517 + write_c0_entrylo0(0); 518 + write_c0_entrylo1(0); 519 + 520 + while (entry < current_cpu_data.tlbsize) { 521 + unsigned long asid_mask = cpu_asid_mask(&current_cpu_data); 522 + unsigned long asid = 0; 523 + int idx; 524 + 525 + /* Skip wired MMID to make ginvt_mmid work */ 526 + if (cpu_has_mmid) 527 + asid = MMID_KERNEL_WIRED + 1; 528 + 529 + /* Check for match before using UNIQUE_ENTRYHI */ 530 + do { 531 + if (cpu_has_mmid) { 532 + write_c0_memorymapid(asid); 533 + write_c0_entryhi(UNIQUE_ENTRYHI(entry)); 534 + } else { 535 + write_c0_entryhi(UNIQUE_ENTRYHI(entry) | asid); 536 + } 537 + mtc0_tlbw_hazard(); 538 + tlb_probe(); 539 + tlb_probe_hazard(); 540 + idx = read_c0_index(); 541 + /* No match or match is on current entry */ 542 + if (idx < 0 || idx == entry) 543 + break; 544 + /* 545 + * If we hit a match, we need to try again with 546 + * a different ASID. 547 + */ 548 + asid++; 549 + } while (asid < asid_mask); 550 + 551 + if (idx >= 0 && idx != entry) 552 + panic("Unable to uniquify TLB entry %d", idx); 553 + 554 + write_c0_index(entry); 555 + mtc0_tlbw_hazard(); 556 + tlb_write_indexed(); 557 + entry++; 558 + } 559 + 560 + tlbw_use_hazard(); 561 + htw_start(); 562 + flush_micro_tlb(); 563 + } 564 + 511 565 /* 512 566 * Configure TLB (for init or after a CPU has been powered off). 513 567 */ ··· 601 547 temp_tlb_entry = current_cpu_data.tlbsize - 1; 602 548 603 549 /* From this point on the ARC firmware is dead. */ 604 - local_flush_tlb_all(); 550 + r4k_tlb_uniquify(); 605 551 606 552 /* Did I tell you that ARC SUCKS? */ 607 553 }