arch/loongarch/kernel/cpu-probe.c | 32 ++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
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@xry111.site>
---
arch/loongarch/kernel/cpu-probe.c | 32 ++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
index 657bbae6c1c7..943e5826c71b 100644
--- a/arch/loongarch/kernel/cpu-probe.c
+++ b/arch/loongarch/kernel/cpu-probe.c
@@ -132,6 +132,36 @@ 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 (
+ "1:ll.d\t$r0, %[mem]\n\t"
+ "move\t%[tmp], $r0\n\t"
+ "sc.q\t%[tmp], %[one], %[mem]\n\t"
+ "beqz\t%[tmp], 1b"
+ : [mem] "=ZB" (mem), [tmp] "=&r" (tmp)
+ : [one] "r" (1));
+
+ 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 +207,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;
}
--
2.53.0
Hi Xi,
kernel test robot noticed the following build errors:
[auto build test ERROR on soc/for-next]
[also build test ERROR on linus/master v7.0-rc7 next-20260406]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Xi-Ruoyao/LoongArch-detect-and-disable-sc-q-if-erratic/20260407-193425
base: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git for-next
patch link: https://lore.kernel.org/r/20260402044732.164294-2-xry111%40xry111.site
patch subject: [PATCH] LoongArch: detect and disable sc.q if erratic
config: loongarch-allnoconfig (https://download.01.org/0day-ci/archive/20260407/202604072314.9J2SQEFo-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project c80443cd37b2e2788cba67ffa180a6331e5f0791)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260407/202604072314.9J2SQEFo-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604072314.9J2SQEFo-lkp@intel.com/
All errors (new ones prefixed by >>):
>> arch/loongarch/kernel/cpu-probe.c:151:23: error: invalid operand for instruction
151 | "move\t%[tmp], $r0\n\t"
| ^
<inline asm>:3:22: note: instantiated into assembly here
3 | sc.q $a2, $a0, $a1, 0
| ^
1 error generated.
vim +151 arch/loongarch/kernel/cpu-probe.c
134
135 /*
136 * Some LoongArch has broken sc.q which incorrectly handles the upper word
137 * when the lower word is zero. Newer firmware versions (such as the 202602
138 * release from Loongson) seem to contain a workaround for this issue.
139 *
140 * Disable sc.q if erratic to ensure reliability and compatibility.
141 */
142 static bool sc_q_is_sane(void)
143 {
144 struct {
145 long word[2];
146 } __aligned(16) mem;
147 register long tmp;
148
149 asm (
150 "1:ll.d\t$r0, %[mem]\n\t"
> 151 "move\t%[tmp], $r0\n\t"
152 "sc.q\t%[tmp], %[one], %[mem]\n\t"
153 "beqz\t%[tmp], 1b"
154 : [mem] "=ZB" (mem), [tmp] "=&r" (tmp)
155 : [one] "r" (1));
156
157 if (mem.word[1] != 1) {
158 pr_warn_once("Warning: sc.q is erratic on this platform, disabling for both kernel and HWCAP. Please try a firmware update.");
159 return false;
160 }
161
162 return true;
163 }
164
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On 2026-04-02 12:47:30+0800, Xi Ruoyao wrote:
(...)
> +/*
> + * 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 (
> + "1:ll.d\t$r0, %[mem]\n\t"
> + "move\t%[tmp], $r0\n\t"
> + "sc.q\t%[tmp], %[one], %[mem]\n\t"
This probably needs to be gated behind CONFIG_AS_HAS_SCQ_EXTENSION to
avoid errors on older toolchains.
> + "beqz\t%[tmp], 1b"
> + : [mem] "=ZB" (mem), [tmp] "=&r" (tmp)
> + : [one] "r" (1));
> +
> + 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;
> +}
On Thu, 2026-04-02 at 08:39 +0200, Thomas Weißschuh wrote:
> On 2026-04-02 12:47:30+0800, Xi Ruoyao wrote:
>
> (...)
>
> > +/*
> > + * 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 (
> > + "1:ll.d\t$r0, %[mem]\n\t"
> > + "move\t%[tmp], $r0\n\t"
> > + "sc.q\t%[tmp], %[one], %[mem]\n\t"
>
> This probably needs to be gated behind CONFIG_AS_HAS_SCQ_EXTENSION to
> avoid errors on older toolchains.
I guess I'd code the insn with .word instead...
This also affects HWCAP, and I don't want the userspace to see neither a
false positive nor a false negative simply because the kernel was built
with an old toolchain.
--
Xi Ruoyao <xry111@xry111.site>
Hi Ruoyao,
在 2026/4/2 12:47, Xi Ruoyao 写道:
> 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@xry111.site>
> ---
> arch/loongarch/kernel/cpu-probe.c | 32 ++++++++++++++++++++++++++++++-
> 1 file changed, 31 insertions(+), 1 deletion(-)
This patch was tested on a Loongson XB6MXC0_V1.0 motherboard (Loongson
3B6000M) and an OrangePi Nova V1.1 (Loongson 2K3000), each against
firmware versions stable202511 (without workaround) and stable202602
(with workaround). Both devices had sc.q disabled correctly with
stable202511, and enabled with the latter, no instability or
functionality issue was observed.
With that:
Tested-by: Mingcong Bai <jeffbai@aosc.io>
> diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
> index 657bbae6c1c7..943e5826c71b 100644
> --- a/arch/loongarch/kernel/cpu-probe.c
> +++ b/arch/loongarch/kernel/cpu-probe.c
> @@ -132,6 +132,36 @@ 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 (
> + "1:ll.d\t$r0, %[mem]\n\t"
> + "move\t%[tmp], $r0\n\t"
> + "sc.q\t%[tmp], %[one], %[mem]\n\t"
> + "beqz\t%[tmp], 1b"
> + : [mem] "=ZB" (mem), [tmp] "=&r" (tmp)
> + : [one] "r" (1));
> +
> + 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 +207,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;
> }
© 2016 - 2026 Red Hat, Inc.