Skip to content

Commit 648d3ab

Browse files
guoren83RevySR
authored andcommitted
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 <[email protected]> Signed-off-by: Guo Ren (Alibaba DAMO Academy) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Han Gao <[email protected]>
1 parent 427565e commit 648d3ab

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-1
lines changed

arch/riscv/Kconfig.errata

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,21 @@ config ERRATA_THEAD_GHOSTWRITE
130130

131131
If you don't know what to do here, say "Y".
132132

133+
config ERRATA_THEAD_WRITE_ONCE
134+
bool "Apply T-Head WRITE_ONCE errata"
135+
depends on ERRATA_THEAD
136+
default y
137+
help
138+
The early version of T-Head C9xx cores of sg2042 & th1520 have a store
139+
merge buffer delay problem. The store merge buffer could improve the
140+
store queue performance by merging multi-store requests, but when there
141+
are no continued store requests, the prior single store request would be
142+
waiting in the store queue for a long time. That would cause signifi-
143+
cant problems for communication between multi-cores. Appending a
144+
fence w.o could immediately flush the store merge buffer and let other
145+
cores see the write result.
146+
147+
This will apply the WRITE_ONCE errata to handle the non-standard beh-
148+
avior via appending a fence w.o instruction for WRITE_ONCE().
149+
133150
endmenu # "CPU errata selection"

arch/riscv/errata/thead/errata.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,23 @@ static bool errata_probe_ghostwrite(unsigned int stage,
168168
return true;
169169
}
170170

171+
static bool errata_probe_write_once(unsigned int stage,
172+
unsigned long arch_id, unsigned long impid)
173+
{
174+
if (!IS_ENABLED(CONFIG_ERRATA_THEAD_WRITE_ONCE))
175+
return false;
176+
177+
/* target-c9xx cores report arch_id and impid as 0 */
178+
if (arch_id != 0 || impid != 0)
179+
return false;
180+
181+
if (stage == RISCV_ALTERNATIVES_BOOT ||
182+
stage == RISCV_ALTERNATIVES_MODULE)
183+
return true;
184+
185+
return false;
186+
}
187+
171188
static u32 thead_errata_probe(unsigned int stage,
172189
unsigned long archid, unsigned long impid)
173190
{
@@ -183,6 +200,9 @@ static u32 thead_errata_probe(unsigned int stage,
183200

184201
errata_probe_ghostwrite(stage, archid, impid);
185202

203+
if (errata_probe_write_once(stage, archid, impid))
204+
cpu_req_errata |= BIT(ERRATA_THEAD_WRITE_ONCE);
205+
186206
return cpu_req_errata;
187207
}
188208

arch/riscv/include/asm/errata_list_vendors.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
#define ERRATA_THEAD_MAE 0
1919
#define ERRATA_THEAD_PMU 1
2020
#define ERRATA_THEAD_GHOSTWRITE 2
21-
#define ERRATA_THEAD_NUMBER 3
21+
#define ERRATA_THEAD_WRITE_ONCE 3
22+
#define ERRATA_THEAD_NUMBER 4
2223
#endif
2324

2425
#endif

arch/riscv/include/asm/rwonce.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef __ASM_RWONCE_H
4+
#define __ASM_RWONCE_H
5+
6+
#include <linux/compiler_types.h>
7+
#include <asm/alternative-macros.h>
8+
#include <asm/vendorid_list.h>
9+
#include <asm/errata_list_vendors.h>
10+
11+
#if defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE)
12+
13+
#define write_once_fence() \
14+
do { \
15+
asm volatile(ALTERNATIVE( \
16+
"nop", \
17+
"fence w, o", \
18+
THEAD_VENDOR_ID, \
19+
ERRATA_THEAD_WRITE_ONCE, \
20+
CONFIG_ERRATA_THEAD_WRITE_ONCE) \
21+
: : : "memory"); \
22+
} while (0)
23+
24+
#define __WRITE_ONCE(x, val) \
25+
do { \
26+
*(volatile typeof(x) *)&(x) = (val); \
27+
write_once_fence(); \
28+
} while (0)
29+
30+
#endif /* defined(CONFIG_ERRATA_THEAD_WRITE_ONCE) && !defined(NO_ALTERNATIVE) */
31+
32+
#include <asm-generic/rwonce.h>
33+
34+
#endif /* __ASM_RWONCE_H */

include/asm-generic/rwonce.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@
5050
__READ_ONCE(x); \
5151
})
5252

53+
#ifndef __WRITE_ONCE
5354
#define __WRITE_ONCE(x, val) \
5455
do { \
5556
*(volatile typeof(x) *)&(x) = (val); \
5657
} while (0)
58+
#endif
5759

5860
#define WRITE_ONCE(x, val) \
5961
do { \

0 commit comments

Comments
 (0)