[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250605-tlb-fix-v1-1-4af496f17b2f@flygoat.com>
Date: Thu, 05 Jun 2025 11:02:30 +0100
From: Jiaxun Yang <jiaxun.yang@...goat.com>
To: Thomas Bogendoerfer <tsbogend@...ha.franken.de>
Cc: linux-mips@...r.kernel.org, linux-kernel@...r.kernel.org,
stable@...nel.org, Jiaxun Yang <jiaxun.yang@...goat.com>
Subject: [PATCH] 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 overwrites
any conflicting entries with safe values before initializing the kernel's
UNIQUE_ENTRYHI pattern.
Cc: stable@...nel.org
Signed-off-by: Jiaxun Yang <jiaxun.yang@...goat.com>
---
arch/mips/mm/tlb-r4k.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 77 insertions(+), 1 deletion(-)
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 76f3b9c0a9f0ce60c42e4a9ea8025e1283678bd1..6467d74d2949e98bcc35ab7c368b3c2ea342a6d3 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -508,6 +508,82 @@ static int __init set_ntlb(char *str)
__setup("ntlb=", set_ntlb);
+/*
+ * This is used to set an absolutely safe entryhi value that will not
+ * collide with any existing TLB entries as well as other UNIQUE_ENTRYHI
+ * values.
+ */
+static unsigned long r4k_safe_entryhi(void)
+{
+ int entry = current_cpu_data.tlbsize;
+ int old_index;
+
+ old_index = read_c0_index();
+ while (entry >= 0) {
+ int idx;
+ unsigned long entryhi = UNIQUE_ENTRYHI(entry);
+
+ write_c0_entryhi(entryhi);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+ tlb_probe_hazard();
+ idx = read_c0_index();
+ if (idx < 0) {
+ /* Unused value found */
+ write_c0_index(old_index);
+ mtc0_tlbw_hazard();
+ return entryhi;
+ }
+ entry++;
+ }
+
+ panic("No safe TLB EntryHi value found");
+ return 0;
+}
+
+/*
+ * Initialize all TLB entries with unique values.
+ */
+static void r4k_tlb_uniquify(void)
+{
+ int entry;
+
+ entry = num_wired_entries();
+
+ htw_stop();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+ while (entry < current_cpu_data.tlbsize) {
+ unsigned long entryhi;
+ int collision_idx;
+
+ entryhi = UNIQUE_ENTRYHI(entry);
+ write_c0_entryhi(entryhi);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+ tlb_probe_hazard();
+
+ /* Check for possible collision */
+ collision_idx = read_c0_index();
+ if (collision_idx >= 0 && collision_idx != entry) {
+ /* Override collision entry with a safe value */
+ r4k_safe_entryhi();
+ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+ tlbw_use_hazard();
+ /* Recover correputed entryhi */
+ write_c0_entryhi(entryhi);
+ }
+
+ write_c0_index(entry);
+ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+ entry++;
+ }
+ tlbw_use_hazard();
+ htw_start();
+}
+
/*
* Configure TLB (for init or after a CPU has been powered off).
*/
@@ -547,7 +623,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? */
}
---
base-commit: 911483b25612c8bc32a706ba940738cc43299496
change-id: 20250605-tlb-fix-578bac7be546
Best regards,
--
Jiaxun Yang <jiaxun.yang@...goat.com>
Powered by blists - more mailing lists