Re: Ping: [PATCH v2] LoongArch: detect and disable sc.q if erratic

From: Huacai Chen

Date: Mon Apr 27 2026 - 04:47:35 EST


Hi, Ruoyao,

On Mon, Apr 27, 2026 at 10:17 AM Xi Ruoyao <xry111@xxxxxxxxxxx> wrote:
>
> Ping.
Can we keep this as an out-of-tree patch? It's a bit ugly and I think
the corrct way is update firmware.

Huacai

>
> On Thu, 2026-04-09 at 20:19 +0800, Xi Ruoyao wrote:
> > We've observed that, on some Loongson 2K3000/3B6000M systems with earlier
> > firmware revisions, the sc.q instruction may write incorrect data into
> > the upper half of the written 128-bit datum.
> >
> > It seems upgrading the firmware (for example, the 202602 release from
> > Loongson [1]) will resolve the issue. But since not all systems may be
> > running the most up-to-date firmware, based on firmware update avail-
> > ability and the environment in which they are running in.
> >
> > To help with system compatibility and ensure correct behavior, check if
> > sc.q behaves erratically and disable if so.
> >
> > Link: https://github.com/loongson/Firmware/pull/156 [1]
> > Signed-off-by: Xi Ruoyao <xry111@xxxxxxxxxxx>
> > ---
> > arch/loongarch/kernel/cpu-probe.c | 39 ++++++++++++++++++++++++++++++-
> > 1 file changed, 38 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
> > index 657bbae6c1c7..5fcf2672172f 100644
> > --- a/arch/loongarch/kernel/cpu-probe.c
> > +++ b/arch/loongarch/kernel/cpu-probe.c
> > @@ -132,6 +132,43 @@ static void set_isa(struct cpuinfo_loongarch *c, unsigned int isa)
> > }
> > }
> >
> > +/*
> > + * Some LoongArch has broken sc.q which incorrectly handles the upper word
> > + * when the lower word is zero. Newer firmware versions (such as the 202602
> > + * release from Loongson) seem to contain a workaround for this issue.
> > + *
> > + * Disable sc.q if erratic to ensure reliability and compatibility.
> > + */
> > +static bool sc_q_is_sane(void)
> > +{
> > + struct {
> > + long word[2];
> > + } __aligned(16) mem;
> > + register long tmp asm("t0");
> > + register long one asm("t1") = 1;
> > + register long *ptr asm("t2") = &mem.word[0];
> > +
> > + /*
> > + * The sc.q instruction is hard coded with .word so the HWCAP bit
> > + * exported to the userspace won't depend on the assembler version
> > + * used to build the kernel.
> > + */
> > + asm (
> > + "1:ll.d\t$r0, %[ptr], 0\n\t"
> > + "move\t%[tmp], $r0\n\t"
> > + ".word\t0x385735cc\n\t" /* sc.q %[tmp], %[one], %[ptr]*/
> > + "beqz\t%[tmp], 1b"
> > + : [tmp] "=&r" (tmp), "=m" (mem)
> > + : [ptr] "r" (ptr), [one] "r" (one));
> > +
> > + if (mem.word[1] != 1) {
> > + pr_warn_once("Warning: sc.q is erratic on this platform, disabling for both kernel and HWCAP. Please try a firmware update.");
> > + return false;
> > + }
> > +
> > + return true;
> > +}
> > +
> > static void cpu_probe_common(struct cpuinfo_loongarch *c)
> > {
> > unsigned int config;
> > @@ -177,7 +214,7 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
> > c->options |= LOONGARCH_CPU_LAM;
> > elf_hwcap |= HWCAP_LOONGARCH_LAM;
> > }
> > - if (config & CPUCFG2_SCQ) {
> > + if ((config & CPUCFG2_SCQ) && sc_q_is_sane()) {
> > c->options |= LOONGARCH_CPU_SCQ;
> > elf_hwcap |= HWCAP_LOONGARCH_SCQ;
> > }
>
> --
> Xi Ruoyao <xry111@xxxxxxxxxxx>