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

Commit 020f1053 authored by Jiaxun Yang's avatar Jiaxun Yang Committed by Greg Kroah-Hartman
Browse files

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: stable@kernel.org
Signed-off-by: default avatarJiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: default avatarThomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1db292bc
Loading
Loading
Loading
Loading
+55 −1
Original line number Diff line number Diff line
@@ -497,6 +497,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(&current_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).
 */
@@ -536,7 +590,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?  */
}