From nobody Tue Nov 11 11:33:56 2025 Received: from angie.orcam.me.uk (angie.orcam.me.uk [78.133.224.34]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 997E02D23B6; Tue, 11 Nov 2025 06:21:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.133.224.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762842111; cv=none; b=G6KxomcGnaU4NfKktPjTM2WItC4wTrCsGe6vM8aY0DL5mR73ncSARM5S4Bjc7mypqy3I3x9L8vO2LmCGqKfI5FPcN+LH4J+NgzMvzrv6je8A6EUrx1JopvdGcTMlp7bIVglVXFX+AFKpp+e3JpOlaYj5rWLALPPflCzS4iuKkoo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762842111; c=relaxed/simple; bh=c1aJqt6FfpbxVOTByKKHFtOH9kKk/8N2iMfGH0+oDzg=; h=Date:From:To:cc:Subject:Message-ID:MIME-Version:Content-Type; b=HXyQNTa583qqBJEM5VOFx3mNAdJ5HsXz4WPxfb3ECE5Q9bg8HvkoWcLR+aGtD2cQGxM0W9cspiNxH8T37xruZUo7kJ7SWgDu5xIh6AnWbIcqpda2x/tAp0QRhDIuK9qK8W0jFFY+G5+i+g7cnJqcvKuJ32KXEakqLlrQvW61wdE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk; spf=none smtp.mailfrom=orcam.me.uk; arc=none smtp.client-ip=78.133.224.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=orcam.me.uk Received: by angie.orcam.me.uk (Postfix, from userid 500) id 5CBF992009C; Tue, 11 Nov 2025 07:21:46 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by angie.orcam.me.uk (Postfix) with ESMTP id 5567992009B; Tue, 11 Nov 2025 06:21:46 +0000 (GMT) Date: Tue, 11 Nov 2025 06:21:46 +0000 (GMT) From: "Maciej W. Rozycki" To: Nick Bowler , Thomas Bogendoerfer , Jiaxun Yang cc: linux-mips@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] MIPS: mm: Prevent a TLB shutdown on initial uniquification Message-ID: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Depending on the particular CPU implementation a TLB shutdown may occur=20 if multiple matching entries are detected upon the execution of a TLBP=20 or the TLBWI/TLBWR instructions. Given that we don't know what entries=20 we have been handed we need to be very careful with the initial TLB=20 setup and avoid all these instructions. Therefore read all the TLB entries one by one with the TLBR instruction,=20 bypassing the content addressing logic, and preinitialize the TLB using=20 addresses outside our usual unique range and avoiding clashes with any=20 incoming contents before making the usual call to local_flush_tlb_all(). This fixes (at least) R4x00 cores if TLBP hits multiple matching TLB=20 entries (SGI IP22 PROM for examples sets up all TLBs to the same virtual=20 address). Signed-off-by: Maciej W. Rozycki Fixes: 35ad7e181541 ("MIPS: mm: tlb-r4k: Uniquify TLB entries on init") Cc: stable@vger.kernel.org # v6.17+ --- Hi, I have verified this lightly, also with some diagnostics added so as to=20 make sure things get set up correctly, with my Malta/74Kf system for a=20 32-bit configuration and with my SWARM/BCM1250 system for a 64-bit one. =20 Sadly the latter box does not finish booting either way, but it's to be=20 bisected separately. Can you please give it a try with your systems? Maciej --- arch/mips/mm/tlb-r4k.c | 92 +++++++++++++++++++++++++++++---------------= ----- 1 file changed, 55 insertions(+), 37 deletions(-) linux-mips-tlb-r4k-uniquify-fix.diff Index: linux-macro/arch/mips/mm/tlb-r4k.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- linux-macro.orig/arch/mips/mm/tlb-r4k.c +++ linux-macro/arch/mips/mm/tlb-r4k.c @@ -15,6 +15,7 @@ #include #include #include +#include =20 #include #include @@ -508,54 +509,70 @@ static int __init set_ntlb(char *str) =20 __setup("ntlb=3D", set_ntlb); =20 -/* Initialise all TLB entries with unique values */ + +/* Comparison function for EntryHi VPN fields. */ +static int r4k_vpn_cmp(const void *a, const void *b) +{ + return ((*(unsigned long *)a - *(unsigned long *)b) >> + (sizeof(unsigned long) - sizeof(int)) * 8); +} + +/* + * Initialise all TLB entries with unique values that do not clash with + * what we have been handed over and what we'll be using ourselves. + */ static void r4k_tlb_uniquify(void) { - int entry =3D num_wired_entries(); + unsigned long tlb_vpns[1 << MIPS_CONF1_TLBS_SIZE]; + int tlbsize =3D current_cpu_data.tlbsize; + int start =3D num_wired_entries(); + unsigned long vpn_mask; + int cnt, ent, idx, i; + + vpn_mask =3D GENMASK(cpu_vmbits - 1, 13); + vpn_mask |=3D IS_ENABLED(CONFIG_64BIT) ? 3ULL << 62 : 1 << 31; =20 htw_stop(); + + for (i =3D start, cnt =3D 0; i < tlbsize; i++, cnt++) { + unsigned long vpn; + + write_c0_index(i); + mtc0_tlbr_hazard(); + tlb_read(); + tlb_read_hazard(); + vpn =3D read_c0_entryhi(); + vpn &=3D vpn_mask & PAGE_MASK; + tlb_vpns[cnt] =3D vpn; + } + + sort(tlb_vpns, cnt, sizeof(tlb_vpns[0]), r4k_vpn_cmp, NULL); + write_c0_entrylo0(0); write_c0_entrylo1(0); =20 - while (entry < current_cpu_data.tlbsize) { - unsigned long asid_mask =3D cpu_asid_mask(¤t_cpu_data); - unsigned long asid =3D 0; - int idx; + idx =3D 0; + ent =3D cnt; + for (i =3D start; i < tlbsize; i++) + while (1) { + unsigned long entryhi, vpn; =20 - /* Skip wired MMID to make ginvt_mmid work */ - if (cpu_has_mmid) - asid =3D MMID_KERNEL_WIRED + 1; + entryhi =3D UNIQUE_ENTRYHI(ent); + vpn =3D entryhi & vpn_mask & PAGE_MASK; =20 - /* Check for match before using UNIQUE_ENTRYHI */ - do { - if (cpu_has_mmid) { - write_c0_memorymapid(asid); - write_c0_entryhi(UNIQUE_ENTRYHI(entry)); + if (idx >=3D cnt || vpn < tlb_vpns[idx]) { + write_c0_entryhi(entryhi); + write_c0_index(i); + mtc0_tlbw_hazard(); + tlb_write_indexed(); + ent++; + break; + } else if (vpn =3D=3D tlb_vpns[idx]) { + ent++; } else { - write_c0_entryhi(UNIQUE_ENTRYHI(entry) | asid); + idx++; } - mtc0_tlbw_hazard(); - tlb_probe(); - tlb_probe_hazard(); - idx =3D read_c0_index(); - /* No match or match is on current entry */ - if (idx < 0 || idx =3D=3D entry) - break; - /* - * If we hit a match, we need to try again with - * a different ASID. - */ - asid++; - } while (asid < asid_mask); - - if (idx >=3D 0 && idx !=3D entry) - panic("Unable to uniquify TLB entry %d", idx); - - write_c0_index(entry); - mtc0_tlbw_hazard(); - tlb_write_indexed(); - entry++; - } + } =20 tlbw_use_hazard(); htw_start(); @@ -602,6 +619,7 @@ static void r4k_tlb_configure(void) =20 /* From this point on the ARC firmware is dead. */ r4k_tlb_uniquify(); + local_flush_tlb_all(); =20 /* Did I tell you that ARC SUCKS? */ }