Skip to contentSkip to conversation

riscv: errata: Add ERRATA_THEAD_WRITE_ONCE fixup

PATCH Applied [email protected] 8 participants 16 messages Jul 13, 2025 – Jan 15

Subsystems (2)

v2 of 5 Applied 2/2 Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 cover riscv: errata: Add ERRATA_THEAD_WRITE_ONCE fixup

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C9xx cores has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

Changelog:
V2:
- Add new header file for errata_list_vendors.
- Rebase newest kernel version.

V1:
https://lore.kernel.org/all/[email protected]/

Guo Ren (Alibaba DAMO Academy) (2):
riscv: Move vendor errata definitions to new header
riscv: errata: Add ERRATA_THEAD_WRITE_ONCE fixup

 arch/riscv/Kconfig.errata                    | 17 ++++++++++
 arch/riscv/errata/thead/errata.c             | 20 ++++++++++++
 arch/riscv/include/asm/errata_list.h         | 19 +----------
 arch/riscv/include/asm/errata_list_vendors.h | 25 ++++++++++++++
 arch/riscv/include/asm/rwonce.h              | 34 ++++++++++++++++++++
 include/asm-generic/rwonce.h                 |  2 ++
 6 files changed, 99 insertions(+), 18 deletions(-)
 create mode 100644 arch/riscv/include/asm/errata_list_vendors.h
 create mode 100644 arch/riscv/include/asm/rwonce.h
Signature · 1 line
2.40.1
#1 lore raw

PATCH v2 1/2 riscv: Move vendor errata definitions to new header

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

Move vendor errata definitions into errata_list_vendors.h.

---
 arch/riscv/include/asm/errata_list.h         | 19 +---------------
 arch/riscv/include/asm/errata_list_vendors.h | 24 ++++++++++++++++++++
 2 files changed, 25 insertions(+), 18 deletions(-)
 create mode 100644 arch/riscv/include/asm/errata_list_vendors.h
arch/riscv/include/asm/errata_list.h +1 -18
index 6e426ed7919a..18c9f7ee9b7c 100644
@@ -10,24 +10,7 @@
 #include <asm/insn-def.h>
 #include <asm/hwcap.h>
 #include <asm/vendorid_list.h>
-
-#ifdef CONFIG_ERRATA_ANDES
-#define ERRATA_ANDES_NO_IOCP 0
-#define ERRATA_ANDES_NUMBER 1
-#endif
-
-#ifdef CONFIG_ERRATA_SIFIVE
-#define	ERRATA_SIFIVE_CIP_453 0
-#define	ERRATA_SIFIVE_CIP_1200 1
-#define	ERRATA_SIFIVE_NUMBER 2
-#endif
-
-#ifdef CONFIG_ERRATA_THEAD
-#define	ERRATA_THEAD_MAE 0
-#define	ERRATA_THEAD_PMU 1
-#define	ERRATA_THEAD_GHOSTWRITE 2
-#define	ERRATA_THEAD_NUMBER 3
-#endif
+#include <asm/errata_list_vendors.h>
 
 #ifdef __ASSEMBLY__
 
arch/riscv/include/asm/errata_list_vendors.h new file +24 -0
new file mode 100644
index 000000000000..a37d1558f39f
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef ASM_ERRATA_LIST_VENDORS_H
+#define ASM_ERRATA_LIST_VENDORS_H
+
+#ifdef CONFIG_ERRATA_ANDES
+#define ERRATA_ANDES_NO_IOCP 0
+#define ERRATA_ANDES_NUMBER 1
+#endif
+
+#ifdef CONFIG_ERRATA_SIFIVE
+#define	ERRATA_SIFIVE_CIP_453 0
+#define	ERRATA_SIFIVE_CIP_1200 1
+#define	ERRATA_SIFIVE_NUMBER 2
+#endif
+
+#ifdef CONFIG_ERRATA_THEAD
+#define	ERRATA_THEAD_MAE 0
+#define	ERRATA_THEAD_PMU 1
+#define	ERRATA_THEAD_GHOSTWRITE 2
+#define	ERRATA_THEAD_NUMBER 3
+#endif
+
+#endif
Signature · 1 line
2.40.1
Tested-by on v2 1/2
#2 lore raw

Re: [PATCH V2 1/2] riscv: Move vendor errata definitions to new header

Quoted 73 lines · On Sun, Jul 13, 2025 at 11:53 PM <[email protected]> wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

Move vendor errata definitions into errata_list_vendors.h.

---
 arch/riscv/include/asm/errata_list.h         | 19 +---------------
 arch/riscv/include/asm/errata_list_vendors.h | 24 ++++++++++++++++++++
 2 files changed, 25 insertions(+), 18 deletions(-)
 create mode 100644 arch/riscv/include/asm/errata_list_vendors.h
arch/riscv/include/asm/errata_list.h +1 -18
index 6e426ed7919a..18c9f7ee9b7c 100644
@@ -10,24 +10,7 @@
 #include <asm/insn-def.h>
 #include <asm/hwcap.h>
 #include <asm/vendorid_list.h>
-
-#ifdef CONFIG_ERRATA_ANDES
-#define ERRATA_ANDES_NO_IOCP 0
-#define ERRATA_ANDES_NUMBER 1
-#endif
-
-#ifdef CONFIG_ERRATA_SIFIVE
-#define        ERRATA_SIFIVE_CIP_453 0
-#define        ERRATA_SIFIVE_CIP_1200 1
-#define        ERRATA_SIFIVE_NUMBER 2
-#endif
-
-#ifdef CONFIG_ERRATA_THEAD
-#define        ERRATA_THEAD_MAE 0
-#define        ERRATA_THEAD_PMU 1
-#define        ERRATA_THEAD_GHOSTWRITE 2
-#define        ERRATA_THEAD_NUMBER 3
-#endif
+#include <asm/errata_list_vendors.h>
 
 #ifdef __ASSEMBLY__
 
arch/riscv/include/asm/errata_list_vendors.h new file +24 -1
new file mode 100644
index 000000000000..a37d1558f39f
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef ASM_ERRATA_LIST_VENDORS_H
+#define ASM_ERRATA_LIST_VENDORS_H
+
+#ifdef CONFIG_ERRATA_ANDES
+#define ERRATA_ANDES_NO_IOCP 0
+#define ERRATA_ANDES_NUMBER 1
+#endif
+
+#ifdef CONFIG_ERRATA_SIFIVE
+#define        ERRATA_SIFIVE_CIP_453 0
+#define        ERRATA_SIFIVE_CIP_1200 1
+#define        ERRATA_SIFIVE_NUMBER 2
+#endif
+
+#ifdef CONFIG_ERRATA_THEAD
+#define        ERRATA_THEAD_MAE 0
+#define        ERRATA_THEAD_PMU 1
+#define        ERRATA_THEAD_GHOSTWRITE 2
+#define        ERRATA_THEAD_NUMBER 3
+#endif
+
+#endif
--
Quoted 2 lines

2.40.1

reviewer Reviewed-by on v2 1/2
#3 lore raw

Re: [PATCH V2 1/2] riscv: Move vendor errata definitions to new header

In reply to [email protected]

Hi Guo,

Quoted 61 lines · On 7/13/25 17:53, [email protected] wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

Move vendor errata definitions into errata_list_vendors.h.

---
  arch/riscv/include/asm/errata_list.h         | 19 +---------------
  arch/riscv/include/asm/errata_list_vendors.h | 24 ++++++++++++++++++++
  2 files changed, 25 insertions(+), 18 deletions(-)

create mode 100644 arch/riscv/include/asm/errata_list_vendors.h

arch/riscv/include/asm/errata_list.h +1 -18
index 6e426ed7919a..18c9f7ee9b7c 100644
@@ -10,24 +10,7 @@
  #include <asm/insn-def.h>
  #include <asm/hwcap.h>
  #include <asm/vendorid_list.h>
-
-#ifdef CONFIG_ERRATA_ANDES
-#define ERRATA_ANDES_NO_IOCP 0
-#define ERRATA_ANDES_NUMBER 1
-#endif
-
-#ifdef CONFIG_ERRATA_SIFIVE
-#define	ERRATA_SIFIVE_CIP_453 0
-#define	ERRATA_SIFIVE_CIP_1200 1
-#define	ERRATA_SIFIVE_NUMBER 2
-#endif
-
-#ifdef CONFIG_ERRATA_THEAD
-#define	ERRATA_THEAD_MAE 0
-#define	ERRATA_THEAD_PMU 1
-#define	ERRATA_THEAD_GHOSTWRITE 2
-#define	ERRATA_THEAD_NUMBER 3
-#endif
+#include <asm/errata_list_vendors.h>
 
  #ifdef __ASSEMBLY__
 
arch/riscv/include/asm/errata_list_vendors.h new file +14 -0
new file mode 100644
index 000000000000..a37d1558f39f
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef ASM_ERRATA_LIST_VENDORS_H
+#define ASM_ERRATA_LIST_VENDORS_H
+
+#ifdef CONFIG_ERRATA_ANDES
+#define ERRATA_ANDES_NO_IOCP 0
+#define ERRATA_ANDES_NUMBER 1
+#endif
+
+#ifdef CONFIG_ERRATA_SIFIVE
+#define	ERRATA_SIFIVE_CIP_453 0
+#define	ERRATA_SIFIVE_CIP_1200 1
+#define	ERRATA_SIFIVE_NUMBER 2

arch/riscv/include/asm/errata_list_vendors.h line 24

Quoted 10 lines
arch/riscv/include/asm/errata_list_vendors.h new file +10 -0
+#endif
+
+#ifdef CONFIG_ERRATA_THEAD
+#define	ERRATA_THEAD_MAE 0
+#define	ERRATA_THEAD_PMU 1
+#define	ERRATA_THEAD_GHOSTWRITE 2
+#define	ERRATA_THEAD_NUMBER 3
+#endif
+
+#endif

Thanks,

Alex

#4 lore raw

PATCH v2 2/2 riscv: errata: Add ERRATA_THEAD_WRITE_ONCE fixup

In reply to [email protected]

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C910 core has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE().

This problem is only observed on the sg2042 hardware platform by running the lock_torture test program for half an hour. The problem was not found in the user space application, because interrupt can break the livelock.

---
 arch/riscv/Kconfig.errata                    | 17 ++++++++++
 arch/riscv/errata/thead/errata.c             | 20 ++++++++++++
 arch/riscv/include/asm/errata_list_vendors.h |  3 +-
 arch/riscv/include/asm/rwonce.h              | 34 ++++++++++++++++++++
 include/asm-generic/rwonce.h                 |  2 ++
 5 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/include/asm/rwonce.h
arch/riscv/Kconfig.errata +17 -0
index e318119d570d..d2c982ba5373 100644
@@ -130,4 +130,21 @@ config ERRATA_THEAD_GHOSTWRITE
 
 	  If you don't know what to do here, say "Y".
 
+config ERRATA_THEAD_WRITE_ONCE
+	bool "Apply T-Head WRITE_ONCE errata"
+	depends on ERRATA_THEAD
+	default y
+	help
+	  The early version of T-Head C9xx cores of sg2042 & th1520 have a store
+	  merge buffer delay problem. The store merge buffer could improve the
+	  store queue performance by merging multi-store requests, but when there
+	  are no continued store requests, the prior single store request would be
+	  waiting in the store queue for a long time. That would cause signifi-
+	  cant problems for communication between multi-cores. Appending a
+	  fence w.o could immediately flush the store merge buffer and let other
+	  cores see the write result.
+
+	  This will apply the WRITE_ONCE errata to handle the non-standard beh-
+	  avior via appending a fence w.o instruction for WRITE_ONCE().
+
 endmenu # "CPU errata selection"
arch/riscv/errata/thead/errata.c +20 -0
index 0b942183f708..fbe46f2fa8fb 100644
@@ -168,6 +168,23 @@ static bool errata_probe_ghostwrite(unsigned int stage,
 	return true;
 }
 
+static bool errata_probe_write_once(unsigned int stage,
+				    unsigned long arch_id, unsigned long impid)
+{
+	if (!IS_ENABLED(CONFIG_ERRATA_THEAD_WRITE_ONCE))
+		return false;
+
+	/* target-c9xx cores report arch_id and impid as 0 */
+	if (arch_id != 0 || impid != 0)
+		return false;
+
+	if (stage == RISCV_ALTERNATIVES_BOOT ||
+	    stage == RISCV_ALTERNATIVES_MODULE)
+		return true;
+
+	return false;
+}
+
 static u32 thead_errata_probe(unsigned int stage,
 			      unsigned long archid, unsigned long impid)
 {
@@ -183,6 +200,9 @@ static u32 thead_errata_probe(unsigned int stage,
 
 	errata_probe_ghostwrite(stage, archid, impid);
 
+	if (errata_probe_write_once(stage, archid, impid))
+		cpu_req_errata |= BIT(ERRATA_THEAD_WRITE_ONCE);
+
 	return cpu_req_errata;
 }
 
arch/riscv/include/asm/errata_list_vendors.h +2 -1
index a37d1558f39f..a7473cb8874d 100644
@@ -18,7 +18,8 @@
 #define	ERRATA_THEAD_MAE 0
 #define	ERRATA_THEAD_PMU 1
 #define	ERRATA_THEAD_GHOSTWRITE 2
-#define	ERRATA_THEAD_NUMBER 3
+#define	ERRATA_THEAD_WRITE_ONCE 3
+#define	ERRATA_THEAD_NUMBER 4
 #endif
 
 #endif
arch/riscv/include/asm/rwonce.h new file +34 -0
new file mode 100644
index 000000000000..081793d4d772
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_RWONCE_H
+#define __ASM_RWONCE_H
+
+#include <linux/compiler_types.h>
+#include <asm/alternative-macros.h>
+#include <asm/vendorid_list.h>
+#include <asm/errata_list_vendors.h>
+
+#if defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE)
+
+#define write_once_fence()				\
+do {							\
+	asm volatile(ALTERNATIVE(			\
+		"nop",					\
+		"fence w, o",				\
+		THEAD_VENDOR_ID,			\
+		ERRATA_THEAD_WRITE_ONCE,		\
+		CONFIG_ERRATA_THEAD_WRITE_ONCE)		\
+		: : : "memory");			\
+} while (0)
+
+#define __WRITE_ONCE(x, val)				\
+do {							\
+	*(volatile typeof(x) *)&(x) = (val);		\
+	write_once_fence();				\
+} while (0)
+
+#endif /* defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE) */
+
+#include <asm-generic/rwonce.h>
+
+#endif	/* __ASM_RWONCE_H */
include/asm-generic/rwonce.h +2 -0
index 52b969c7cef9..4e2d941f15a1 100644
@@ -50,10 +50,12 @@
 	__READ_ONCE(x);							\
 })
 
+#ifndef __WRITE_ONCE
 #define __WRITE_ONCE(x, val)						\
 do {									\
 	*(volatile typeof(x) *)&(x) = (val);				\
 } while (0)
+#endif
 
 #define WRITE_ONCE(x, val)						\
 do {									\
Signature · 1 line
2.40.1
#5 lore raw
Quoted 14 lines · On Sun, Jul 13, 2025 at 11:53:21AM -0400, [email protected] wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C910 core has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result.

Quoted 7 lines

This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE().

This problem is only observed on the sg2042 hardware platform by running the lock_torture test program for half an hour. The problem was not found in the user space application, because interrupt can break the livelock.

The first paragraph states the problem was found on both the SG2042 and TH1520, but this paragraph states it is only observed on the SG2042. Is worth me trying to run lock_torture on the TH1520 for many hours?

Thanks,
Drew

author
#6 lore raw
Quoted 19 lines · Drew Fustini
Quoted 17 lines · On Sun, Jul 13, 2025 at 11:53:21AM -0400, [email protected] wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C910 core has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE().

Quoted 8 lines
Quoted 4 lines

This problem is only observed on the sg2042 hardware platform by running the lock_torture test program for half an hour. The problem was not found in the user space application, because interrupt can break the livelock.

The first paragraph states the problem was found on both the SG2042 and TH1520, but this paragraph states it is only observed on the SG2042. Is worth me trying to run lock_torture on the TH1520 for many hours?

We didn't observe that problem on the 1520 due to its small number of cores. But, we still recommend the th1520 involve this patch for potential write delay.

Quoted 3 lines

Thanks,
Drew

Signature · 2 lines
Best Regards
 Guo Ren
Tested-by on v2 2/2
#7 lore raw
In reply to [email protected]
Quoted 170 lines · On Sun, Jul 13, 2025 at 11:53 PM <[email protected]> wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C910 core has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE().

This problem is only observed on the sg2042 hardware platform by running the lock_torture test program for half an hour. The problem was not found in the user space application, because interrupt can break the livelock.

---
 arch/riscv/Kconfig.errata                    | 17 ++++++++++
 arch/riscv/errata/thead/errata.c             | 20 ++++++++++++
 arch/riscv/include/asm/errata_list_vendors.h |  3 +-
 arch/riscv/include/asm/rwonce.h              | 34 ++++++++++++++++++++
 include/asm-generic/rwonce.h                 |  2 ++
 5 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/include/asm/rwonce.h
arch/riscv/Kconfig.errata +17 -0
index e318119d570d..d2c982ba5373 100644
@@ -130,4 +130,21 @@ config ERRATA_THEAD_GHOSTWRITE
 
          If you don't know what to do here, say "Y".
 
+config ERRATA_THEAD_WRITE_ONCE
+       bool "Apply T-Head WRITE_ONCE errata"
+       depends on ERRATA_THEAD
+       default y
+       help
+         The early version of T-Head C9xx cores of sg2042 & th1520 have a store
+         merge buffer delay problem. The store merge buffer could improve the
+         store queue performance by merging multi-store requests, but when there
+         are no continued store requests, the prior single store request would be
+         waiting in the store queue for a long time. That would cause signifi-
+         cant problems for communication between multi-cores. Appending a
+         fence w.o could immediately flush the store merge buffer and let other
+         cores see the write result.
+
+         This will apply the WRITE_ONCE errata to handle the non-standard beh-
+         avior via appending a fence w.o instruction for WRITE_ONCE().
+
 endmenu # "CPU errata selection"
arch/riscv/errata/thead/errata.c +20 -0
index 0b942183f708..fbe46f2fa8fb 100644
@@ -168,6 +168,23 @@ static bool errata_probe_ghostwrite(unsigned int stage,
        return true;
 }
 
+static bool errata_probe_write_once(unsigned int stage,
+                                   unsigned long arch_id, unsigned long impid)
+{
+       if (!IS_ENABLED(CONFIG_ERRATA_THEAD_WRITE_ONCE))
+               return false;
+
+       /* target-c9xx cores report arch_id and impid as 0 */
+       if (arch_id != 0 || impid != 0)
+               return false;
+
+       if (stage == RISCV_ALTERNATIVES_BOOT ||
+           stage == RISCV_ALTERNATIVES_MODULE)
+               return true;
+
+       return false;
+}
+
 static u32 thead_errata_probe(unsigned int stage,
                              unsigned long archid, unsigned long impid)
 {
@@ -183,6 +200,9 @@ static u32 thead_errata_probe(unsigned int stage,
 
        errata_probe_ghostwrite(stage, archid, impid);
 
+       if (errata_probe_write_once(stage, archid, impid))
+               cpu_req_errata |= BIT(ERRATA_THEAD_WRITE_ONCE);
+
        return cpu_req_errata;
 }
 
arch/riscv/include/asm/errata_list_vendors.h +2 -1
index a37d1558f39f..a7473cb8874d 100644
@@ -18,7 +18,8 @@
 #define        ERRATA_THEAD_MAE 0
 #define        ERRATA_THEAD_PMU 1
 #define        ERRATA_THEAD_GHOSTWRITE 2
-#define        ERRATA_THEAD_NUMBER 3
+#define        ERRATA_THEAD_WRITE_ONCE 3
+#define        ERRATA_THEAD_NUMBER 4
 #endif
 
 #endif
arch/riscv/include/asm/rwonce.h new file +34 -0
new file mode 100644
index 000000000000..081793d4d772
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_RWONCE_H
+#define __ASM_RWONCE_H
+
+#include <linux/compiler_types.h>
+#include <asm/alternative-macros.h>
+#include <asm/vendorid_list.h>
+#include <asm/errata_list_vendors.h>
+
+#if defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE)
+
+#define write_once_fence()                             \
+do {                                                   \
+       asm volatile(ALTERNATIVE(                       \
+               "nop",                                  \
+               "fence w, o",                           \
+               THEAD_VENDOR_ID,                        \
+               ERRATA_THEAD_WRITE_ONCE,                \
+               CONFIG_ERRATA_THEAD_WRITE_ONCE)         \
+               : : : "memory");                        \
+} while (0)
+
+#define __WRITE_ONCE(x, val)                           \
+do {                                                   \
+       *(volatile typeof(x) *)&(x) = (val);            \
+       write_once_fence();                             \
+} while (0)
+
+#endif /* defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE) */
+
+#include <asm-generic/rwonce.h>
+
+#endif /* __ASM_RWONCE_H */
include/asm-generic/rwonce.h +2 -1
index 52b969c7cef9..4e2d941f15a1 100644
@@ -50,10 +50,12 @@
        __READ_ONCE(x);                                                 \
 })
 
+#ifndef __WRITE_ONCE
 #define __WRITE_ONCE(x, val)                                           \
 do {                                                                   \
        *(volatile typeof(x) *)&(x) = (val);                            \
 } while (0)
+#endif
 
 #define WRITE_ONCE(x, val)                                             \
 do {                                                                   \
--
Quoted 2 lines

2.40.1

reviewer Reviewed-by on v2 2/2
#8 lore raw
In reply to [email protected]
Quoted 158 lines · On 7/13/25 17:53, [email protected] wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C910 core has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE().

This problem is only observed on the sg2042 hardware platform by running the lock_torture test program for half an hour. The problem was not found in the user space application, because interrupt can break the livelock.

---
  arch/riscv/Kconfig.errata                    | 17 ++++++++++
  arch/riscv/errata/thead/errata.c             | 20 ++++++++++++
  arch/riscv/include/asm/errata_list_vendors.h |  3 +-
  arch/riscv/include/asm/rwonce.h              | 34 ++++++++++++++++++++
  include/asm-generic/rwonce.h                 |  2 ++
  5 files changed, 75 insertions(+), 1 deletion(-)

create mode 100644 arch/riscv/include/asm/rwonce.h

arch/riscv/Kconfig.errata +17 -0
index e318119d570d..d2c982ba5373 100644
@@ -130,4 +130,21 @@ config ERRATA_THEAD_GHOSTWRITE
 
  	  If you don't know what to do here, say "Y".
 
+config ERRATA_THEAD_WRITE_ONCE
+	bool "Apply T-Head WRITE_ONCE errata"
+	depends on ERRATA_THEAD
+	default y
+	help
+	  The early version of T-Head C9xx cores of sg2042 & th1520 have a store
+	  merge buffer delay problem. The store merge buffer could improve the
+	  store queue performance by merging multi-store requests, but when there
+	  are no continued store requests, the prior single store request would be
+	  waiting in the store queue for a long time. That would cause signifi-
+	  cant problems for communication between multi-cores. Appending a
+	  fence w.o could immediately flush the store merge buffer and let other
+	  cores see the write result.
+
+	  This will apply the WRITE_ONCE errata to handle the non-standard beh-
+	  avior via appending a fence w.o instruction for WRITE_ONCE().
+
  endmenu # "CPU errata selection"
arch/riscv/errata/thead/errata.c +20 -0
index 0b942183f708..fbe46f2fa8fb 100644
@@ -168,6 +168,23 @@ static bool errata_probe_ghostwrite(unsigned int stage,
  	return true;
  }
 
+static bool errata_probe_write_once(unsigned int stage,
+				    unsigned long arch_id, unsigned long impid)
+{
+	if (!IS_ENABLED(CONFIG_ERRATA_THEAD_WRITE_ONCE))
+		return false;
+
+	/* target-c9xx cores report arch_id and impid as 0 */
+	if (arch_id != 0 || impid != 0)
+		return false;
+
+	if (stage == RISCV_ALTERNATIVES_BOOT ||
+	    stage == RISCV_ALTERNATIVES_MODULE)
+		return true;
+
+	return false;
+}
+
  static u32 thead_errata_probe(unsigned int stage,
  			      unsigned long archid, unsigned long impid)
  {
@@ -183,6 +200,9 @@ static u32 thead_errata_probe(unsigned int stage,
 
  	errata_probe_ghostwrite(stage, archid, impid);
 
+	if (errata_probe_write_once(stage, archid, impid))
+		cpu_req_errata |= BIT(ERRATA_THEAD_WRITE_ONCE);
+
  	return cpu_req_errata;
  }
 
arch/riscv/include/asm/errata_list_vendors.h +2 -1
index a37d1558f39f..a7473cb8874d 100644
@@ -18,7 +18,8 @@
  #define	ERRATA_THEAD_MAE 0
  #define	ERRATA_THEAD_PMU 1
  #define	ERRATA_THEAD_GHOSTWRITE 2
-#define	ERRATA_THEAD_NUMBER 3
+#define	ERRATA_THEAD_WRITE_ONCE 3
+#define	ERRATA_THEAD_NUMBER 4
  #endif
 
  #endif
arch/riscv/include/asm/rwonce.h new file +34 -0
new file mode 100644
index 000000000000..081793d4d772
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_RWONCE_H
+#define __ASM_RWONCE_H
+
+#include <linux/compiler_types.h>
+#include <asm/alternative-macros.h>
+#include <asm/vendorid_list.h>
+#include <asm/errata_list_vendors.h>
+
+#if defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE)
+
+#define write_once_fence()				\
+do {							\
+	asm volatile(ALTERNATIVE(			\
+		"nop",					\
+		"fence w, o",				\
+		THEAD_VENDOR_ID,			\
+		ERRATA_THEAD_WRITE_ONCE,		\
+		CONFIG_ERRATA_THEAD_WRITE_ONCE)		\
+		: : : "memory");			\
+} while (0)
+
+#define __WRITE_ONCE(x, val)				\
+do {							\
+	*(volatile typeof(x) *)&(x) = (val);		\
+	write_once_fence();				\
+} while (0)
+
+#endif /* defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE) */
+
+#include <asm-generic/rwonce.h>
+
+#endif	/* __ASM_RWONCE_H */
include/asm-generic/rwonce.h +0 -0
index 52b969c7cef9..4e2d941f15a1 100644
@@ -50,10 +50,12 @@
  	__READ_ONCE(x);							\
  })

include/asm-generic/rwonce.h line 61

Quoted 10 lines
include/asm-generic/rwonce.h +2 -0
 
+#ifndef __WRITE_ONCE
  #define __WRITE_ONCE(x, val)						\
  do {									\
  	*(volatile typeof(x) *)&(x) = (val);				\
  } while (0)
+#endif
 
  #define WRITE_ONCE(x, val)						\
  do {									\

I'll send this patchset in my next PR for 6.17:

Thanks,

Alex

#9 lore raw

Hi Alex
This patch is included in the 6.17 merge window but not in the
6.18 merge window.
Is it possible that the patch was missed?

Quoted 179 lines · Alexandre Ghiti
Quoted 158 lines · On 7/13/25 17:53, [email protected] wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C910 core has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE().

This problem is only observed on the sg2042 hardware platform by running the lock_torture test program for half an hour. The problem was not found in the user space application, because interrupt can break the livelock.

---
  arch/riscv/Kconfig.errata                    | 17 ++++++++++
  arch/riscv/errata/thead/errata.c             | 20 ++++++++++++
  arch/riscv/include/asm/errata_list_vendors.h |  3 +-
  arch/riscv/include/asm/rwonce.h              | 34 ++++++++++++++++++++
  include/asm-generic/rwonce.h                 |  2 ++
  5 files changed, 75 insertions(+), 1 deletion(-)

create mode 100644 arch/riscv/include/asm/rwonce.h

arch/riscv/Kconfig.errata +17 -0
index e318119d570d..d2c982ba5373 100644
@@ -130,4 +130,21 @@ config ERRATA_THEAD_GHOSTWRITE
 
        If you don't know what to do here, say "Y".
 
+config ERRATA_THEAD_WRITE_ONCE
+     bool "Apply T-Head WRITE_ONCE errata"
+     depends on ERRATA_THEAD
+     default y
+     help
+       The early version of T-Head C9xx cores of sg2042 & th1520 have a store
+       merge buffer delay problem. The store merge buffer could improve the
+       store queue performance by merging multi-store requests, but when there
+       are no continued store requests, the prior single store request would be
+       waiting in the store queue for a long time. That would cause signifi-
+       cant problems for communication between multi-cores. Appending a
+       fence w.o could immediately flush the store merge buffer and let other
+       cores see the write result.
+
+       This will apply the WRITE_ONCE errata to handle the non-standard beh-
+       avior via appending a fence w.o instruction for WRITE_ONCE().
+
  endmenu # "CPU errata selection"
arch/riscv/errata/thead/errata.c +20 -0
index 0b942183f708..fbe46f2fa8fb 100644
@@ -168,6 +168,23 @@ static bool errata_probe_ghostwrite(unsigned int stage,
      return true;
  }
 
+static bool errata_probe_write_once(unsigned int stage,
+                                 unsigned long arch_id, unsigned long impid)
+{
+     if (!IS_ENABLED(CONFIG_ERRATA_THEAD_WRITE_ONCE))
+             return false;
+
+     /* target-c9xx cores report arch_id and impid as 0 */
+     if (arch_id != 0 || impid != 0)
+             return false;
+
+     if (stage == RISCV_ALTERNATIVES_BOOT ||
+         stage == RISCV_ALTERNATIVES_MODULE)
+             return true;
+
+     return false;
+}
+
  static u32 thead_errata_probe(unsigned int stage,
                            unsigned long archid, unsigned long impid)
  {
@@ -183,6 +200,9 @@ static u32 thead_errata_probe(unsigned int stage,
 
      errata_probe_ghostwrite(stage, archid, impid);
 
+     if (errata_probe_write_once(stage, archid, impid))
+             cpu_req_errata |= BIT(ERRATA_THEAD_WRITE_ONCE);
+
      return cpu_req_errata;
  }
 
arch/riscv/include/asm/errata_list_vendors.h +2 -1
index a37d1558f39f..a7473cb8874d 100644
@@ -18,7 +18,8 @@
  #define     ERRATA_THEAD_MAE 0
  #define     ERRATA_THEAD_PMU 1
  #define     ERRATA_THEAD_GHOSTWRITE 2
-#define      ERRATA_THEAD_NUMBER 3
+#define      ERRATA_THEAD_WRITE_ONCE 3
+#define      ERRATA_THEAD_NUMBER 4
  #endif
 
  #endif
arch/riscv/include/asm/rwonce.h new file +34 -0
new file mode 100644
index 000000000000..081793d4d772
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_RWONCE_H
+#define __ASM_RWONCE_H
+
+#include <linux/compiler_types.h>
+#include <asm/alternative-macros.h>
+#include <asm/vendorid_list.h>
+#include <asm/errata_list_vendors.h>
+
+#if defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE)
+
+#define write_once_fence()                           \
+do {                                                 \
+     asm volatile(ALTERNATIVE(                       \
+             "nop",                                  \
+             "fence w, o",                           \
+             THEAD_VENDOR_ID,                        \
+             ERRATA_THEAD_WRITE_ONCE,                \
+             CONFIG_ERRATA_THEAD_WRITE_ONCE)         \
+             : : : "memory");                        \
+} while (0)
+
+#define __WRITE_ONCE(x, val)                         \
+do {                                                 \
+     *(volatile typeof(x) *)&(x) = (val);            \
+     write_once_fence();                             \
+} while (0)
+
+#endif /* defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE) */
+
+#include <asm-generic/rwonce.h>
+
+#endif       /* __ASM_RWONCE_H */
include/asm-generic/rwonce.h +0 -0
index 52b969c7cef9..4e2d941f15a1 100644
@@ -50,10 +50,12 @@
      __READ_ONCE(x);                                                 \
  })

include/asm-generic/rwonce.h line 61

Quoted 10 lines
include/asm-generic/rwonce.h +2 -0
 
+#ifndef __WRITE_ONCE
  #define __WRITE_ONCE(x, val)                                                \
  do {                                                                        \
      *(volatile typeof(x) *)&(x) = (val);                            \
  } while (0)
+#endif
 
  #define WRITE_ONCE(x, val)                                          \
  do {                                                                        \

I'll send this patchset in my next PR for 6.17:

Thanks,

Alex

#10 lore raw

Hi Han,

Quoted 5 lines · Han Gao

Hi Alex
This patch is included in the 6.17 merge window but not in the
6.18 merge window.
Is it possible that the patch was missed?

Unfortunately, I can't say, you should ask the maintainers.

Thanks,

Alex

Quoted 181 lines · Alexandre Ghiti
Quoted 179 lines · On 7/13/25 17:53, [email protected] wrote:
Quoted 158 lines

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C910 core has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE().

This problem is only observed on the sg2042 hardware platform by running the lock_torture test program for half an hour. The problem was not found in the user space application, because interrupt can break the livelock.

---
  arch/riscv/Kconfig.errata                    | 17 ++++++++++
  arch/riscv/errata/thead/errata.c             | 20 ++++++++++++
  arch/riscv/include/asm/errata_list_vendors.h |  3 +-
  arch/riscv/include/asm/rwonce.h              | 34 ++++++++++++++++++++
  include/asm-generic/rwonce.h                 |  2 ++
  5 files changed, 75 insertions(+), 1 deletion(-)

create mode 100644 arch/riscv/include/asm/rwonce.h

arch/riscv/Kconfig.errata +17 -0
index e318119d570d..d2c982ba5373 100644
@@ -130,4 +130,21 @@ config ERRATA_THEAD_GHOSTWRITE
 
        If you don't know what to do here, say "Y".
 
+config ERRATA_THEAD_WRITE_ONCE
+     bool "Apply T-Head WRITE_ONCE errata"
+     depends on ERRATA_THEAD
+     default y
+     help
+       The early version of T-Head C9xx cores of sg2042 & th1520 have a store
+       merge buffer delay problem. The store merge buffer could improve the
+       store queue performance by merging multi-store requests, but when there
+       are no continued store requests, the prior single store request would be
+       waiting in the store queue for a long time. That would cause signifi-
+       cant problems for communication between multi-cores. Appending a
+       fence w.o could immediately flush the store merge buffer and let other
+       cores see the write result.
+
+       This will apply the WRITE_ONCE errata to handle the non-standard beh-
+       avior via appending a fence w.o instruction for WRITE_ONCE().
+
  endmenu # "CPU errata selection"
arch/riscv/errata/thead/errata.c +20 -0
index 0b942183f708..fbe46f2fa8fb 100644
@@ -168,6 +168,23 @@ static bool errata_probe_ghostwrite(unsigned int stage,
      return true;
  }
 
+static bool errata_probe_write_once(unsigned int stage,
+                                 unsigned long arch_id, unsigned long impid)
+{
+     if (!IS_ENABLED(CONFIG_ERRATA_THEAD_WRITE_ONCE))
+             return false;
+
+     /* target-c9xx cores report arch_id and impid as 0 */
+     if (arch_id != 0 || impid != 0)
+             return false;
+
+     if (stage == RISCV_ALTERNATIVES_BOOT ||
+         stage == RISCV_ALTERNATIVES_MODULE)
+             return true;
+
+     return false;
+}
+
  static u32 thead_errata_probe(unsigned int stage,
                            unsigned long archid, unsigned long impid)
  {
@@ -183,6 +200,9 @@ static u32 thead_errata_probe(unsigned int stage,
 
      errata_probe_ghostwrite(stage, archid, impid);
 
+     if (errata_probe_write_once(stage, archid, impid))
+             cpu_req_errata |= BIT(ERRATA_THEAD_WRITE_ONCE);
+
      return cpu_req_errata;
  }
 
arch/riscv/include/asm/errata_list_vendors.h +2 -1
index a37d1558f39f..a7473cb8874d 100644
@@ -18,7 +18,8 @@
  #define     ERRATA_THEAD_MAE 0
  #define     ERRATA_THEAD_PMU 1
  #define     ERRATA_THEAD_GHOSTWRITE 2
-#define      ERRATA_THEAD_NUMBER 3
+#define      ERRATA_THEAD_WRITE_ONCE 3
+#define      ERRATA_THEAD_NUMBER 4
  #endif
 
  #endif
arch/riscv/include/asm/rwonce.h new file +34 -0
new file mode 100644
index 000000000000..081793d4d772
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_RWONCE_H
+#define __ASM_RWONCE_H
+
+#include <linux/compiler_types.h>
+#include <asm/alternative-macros.h>
+#include <asm/vendorid_list.h>
+#include <asm/errata_list_vendors.h>
+
+#if defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE)
+
+#define write_once_fence()                           \
+do {                                                 \
+     asm volatile(ALTERNATIVE(                       \
+             "nop",                                  \
+             "fence w, o",                           \
+             THEAD_VENDOR_ID,                        \
+             ERRATA_THEAD_WRITE_ONCE,                \
+             CONFIG_ERRATA_THEAD_WRITE_ONCE)         \
+             : : : "memory");                        \
+} while (0)
+
+#define __WRITE_ONCE(x, val)                         \
+do {                                                 \
+     *(volatile typeof(x) *)&(x) = (val);            \
+     write_once_fence();                             \
+} while (0)
+
+#endif /* defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE) */
+
+#include <asm-generic/rwonce.h>
+
+#endif       /* __ASM_RWONCE_H */
include/asm-generic/rwonce.h +0 -0
index 52b969c7cef9..4e2d941f15a1 100644
@@ -50,10 +50,12 @@
      __READ_ONCE(x);                                                 \
  })

include/asm-generic/rwonce.h line 61

Quoted 10 lines
include/asm-generic/rwonce.h +2 -0
 
+#ifndef __WRITE_ONCE
  #define __WRITE_ONCE(x, val)                                                \
  do {                                                                        \
      *(volatile typeof(x) *)&(x) = (val);                            \
  } while (0)
+#endif
 
  #define WRITE_ONCE(x, val)                                          \
  do {                                                                        \

I'll send this patchset in my next PR for 6.17:

Thanks,

Alex

maintainer
#11 lore raw

Hello Han Gao, Guo Ren,

Sorry for the delay in responding -

Quoted 3 lines · Han Gao

This patch is included in the 6.17 merge window but not in the
6.18 merge window.
Is it possible that the patch was missed?

This was almost sent upstream as part of the v6.18 merge window, but given that it adds the ability for architectures to override WRITE_ONCE, I think it needs one more attempt at gathering feedback before we do. I'll send that out this week.

thanks for your patience,

- Paul

author
#12 lore raw
Quoted 7 lines · Paul Walmsley

Hello Han Gao, Guo Ren,

Sorry for the delay in responding -

On Tue, Oct 7, 2025 at 11:36 PM Han Gao <[email protected]> wrote:

Quoted 8 lines
Quoted 3 lines

This patch is included in the 6.17 merge window but not in the
6.18 merge window.
Is it possible that the patch was missed?

This was almost sent upstream as part of the v6.18 merge window, but given that it adds the ability for architectures to override WRITE_ONCE, I think it needs one more attempt at gathering feedback before we do. I'll send that out this week.

Thanks, Paul, for the effort on this patch. Yes, overriding WRITE_ONCE needs more public feedback; it makes sense to us. This errata from the c910 early version causes issues for the community, but some SoCs, such as th1520 and sg2042, need it to prevent potential risks.

Quoted 4 lines

thanks for your patience,

- Paul

--
Best Regards
Guo Ren

#13 lore raw
In reply to Paul Walmsley

Hi, Paul

This patch is still not being considered for merging in 6.19. Is there some new issue?

Quoted 19 lines · Paul Walmsley

Hello Han Gao, Guo Ren,

Sorry for the delay in responding -

Quoted 3 lines · Han Gao

This patch is included in the 6.17 merge window but not in the
6.18 merge window.
Is it possible that the patch was missed?

This was almost sent upstream as part of the v6.18 merge window, but given that it adds the ability for architectures to override WRITE_ONCE, I think it needs one more attempt at gathering feedback before we do. I'll send that out this week.

thanks for your patience,

- Paul

#14 lore raw
In reply to Paul Walmsley
Quoted 10 lines · Paul Walmsley

Hello Han Gao, Guo Ren,

Sorry for the delay in responding -

Quoted 3 lines · Han Gao

This patch is included in the 6.17 merge window but not in the
6.18 merge window.
Is it possible that the patch was missed?

Quoted 6 lines

This was almost sent upstream as part of the v6.18 merge window, but given that it adds the ability for architectures to override WRITE_ONCE, I think it needs one more attempt at gathering feedback before we do. I'll send that out this week.

thanks for your patience,

Hi Paul,

Could this series be queued for 6.20? It has been more than two months, and seems no more feedback has come up. Thanks for your work!

Quoted 1 line

- Paul

Best regards,
Yao Zi

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv

#15 lore raw
In reply to [email protected]
This series was applied to riscv/linux.git (for-next) by Alexandre Ghiti <[email protected]>:

Hello:

This series was applied to riscv/linux.git (for-next) by Alexandre Ghiti <[email protected]>:

Quoted 11 lines · On Sun, 13 Jul 2025 11:53:19 -0400 you wrote:

From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>

The early version of XuanTie C9xx cores has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test.

Quoted 1 line

[...]

Here is the summary with links:
- [V2,1/2] riscv: Move vendor errata definitions to new header

    https://git.kernel.org/riscv/c/736d67e4f0d0
  - [V2,2/2] riscv: errata: Add ERRATA_THEAD_WRITE_ONCE fixup
    https://git.kernel.org/riscv/c/b7f09bd30ca8

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html