FROMLIST: riscv: errata: Add ERRATA_THEAD_WRITE_ONCE fixup

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.

Reviewed-by: Leonardo Bras <leobras@redhat.com>
Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
Link: https://lore.kernel.org/r/20250713155321.2064856-3-guoren@kernel.org
Signed-off-by: Han Gao <rabenda.cn@gmail.com>
This commit is contained in:
Guo Ren (Alibaba DAMO Academy)
2025-07-13 11:53:21 -04:00
committed by Han Gao
parent 4584bdc055
commit 0d94e08ccd
5 changed files with 75 additions and 1 deletions

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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 /* ASM_ERRATA_LIST_VENDORS_H */

View File

@@ -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 */

View File

@@ -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 { \