* [PATCH v3 0/5] Add workarounds for Picoheart erratas
@ 2026-09-07 7:21 Yicong Yang
2026-09-07 7:21 ` [PATCH v3 1/5] riscv: Make get_insn public for instruction fault handling Yicong Yang
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Yicong Yang @ 2026-09-07 7:21 UTC (permalink / raw)
To: pjw, palmer, aou, linux-riscv
Cc: wangruikang, ganboing, alex, andrew.jones, cleger, geshijian,
niehaitao, cuiyunhui, yang.yicong
This series add basic errata framework for Picoheart SoCs for handling
upcoming Picoheart erratas. And add workarounds for the first two
erratas on our hardware. Also do some fixups and refactor in support
of the erratas.
Change since v2:
- rebase on 7.3-rc2
- merge the MXR fix and get_insn extraction into one patch
Link: https://lore.kernel.org/linux-riscv/20260728094627.94975-1-yang.yicong@picoheart.com/
Change since v1:
- factor out a common get_insn for reading userspace instructions
- fix the issue from reading instructions of a exec-only mapping
- cleanups and code style refinements per comments
Link: https://lore.kernel.org/linux-riscv/20260715084724.26578-1-yang.yicong@picoheart.com/
Yicong Yang (5):
riscv: Make get_insn public for instruction fault handling
riscv: insn: Support decoding of CBO instructions
riscv: errata: Add init framework for picoheart errata
riscv: errata: picoheart: Add workaround for cbo.clean errata
riscv: errata: picoheart: Add workaround for AMOCASQ errata
arch/riscv/Kconfig.errata | 34 +++
arch/riscv/errata/Makefile | 1 +
arch/riscv/errata/picoheart/Makefile | 5 +
arch/riscv/errata/picoheart/errata.c | 238 +++++++++++++++++++
arch/riscv/include/asm/alternative.h | 3 +
arch/riscv/include/asm/cmpxchg.h | 2 +-
arch/riscv/include/asm/cpufeature.h | 8 +
arch/riscv/include/asm/csr.h | 1 +
arch/riscv/include/asm/errata_list.h | 25 +-
arch/riscv/include/asm/errata_list_vendors.h | 4 +
arch/riscv/include/asm/insn.h | 63 ++++-
arch/riscv/include/asm/processor.h | 2 +-
arch/riscv/include/asm/vendorid_list.h | 1 +
arch/riscv/kernel/alternative.c | 5 +
arch/riscv/kernel/asm-offsets.c | 6 +-
arch/riscv/kernel/cpufeature.c | 16 +-
arch/riscv/kernel/entry.S | 14 +-
arch/riscv/kernel/traps.c | 4 +
arch/riscv/kernel/traps_misaligned.c | 52 ----
arch/riscv/kernel/vector.c | 6 +-
20 files changed, 419 insertions(+), 71 deletions(-)
create mode 100644 arch/riscv/errata/picoheart/Makefile
create mode 100644 arch/riscv/errata/picoheart/errata.c
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 1/5] riscv: Make get_insn public for instruction fault handling
2026-09-07 7:21 [PATCH v3 0/5] Add workarounds for Picoheart erratas Yicong Yang
@ 2026-09-07 7:21 ` Yicong Yang
2026-09-07 7:21 ` [PATCH v3 2/5] riscv: insn: Support decoding of CBO instructions Yicong Yang
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Yicong Yang @ 2026-09-07 7:21 UTC (permalink / raw)
To: pjw, palmer, aou, linux-riscv
Cc: wangruikang, ganboing, alex, andrew.jones, cleger, geshijian,
niehaitao, cuiyunhui, yang.yicong
Currently two places (vector and misaligned load/store) need
to get fault instructions for handling and they implement the
function separately. This is a common function so make
get_insn() public in asm/insn.h for doing this job to make it
less fragile and improve the maintainability.
Also fix a bug that Bo Gan noticed: get_user() is insufficient
in this case since it's possible for the instruction segment
mapped as execute-only and get_user() doesn't have permissions
to load it. The architecture provides sstatus.MXR for handling
this so set MXR when reading userspace instruction.
Cc: Bo Gan <ganboing@gmail.com>
Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
arch/riscv/include/asm/csr.h | 1 +
arch/riscv/include/asm/insn.h | 55 ++++++++++++++++++++++++++++
arch/riscv/include/asm/processor.h | 2 +-
arch/riscv/kernel/asm-offsets.c | 6 +--
arch/riscv/kernel/entry.S | 14 +++----
arch/riscv/kernel/traps_misaligned.c | 52 --------------------------
arch/riscv/kernel/vector.c | 6 +--
7 files changed, 70 insertions(+), 66 deletions(-)
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 6c823361be86..16e1c5ee955c 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -17,6 +17,7 @@
#define SR_SPP _AC(0x00000100, UL) /* Previously Supervisor */
#define SR_MPP _AC(0x00001800, UL) /* Previously Machine */
#define SR_SUM _AC(0x00040000, UL) /* Supervisor User Memory Access */
+#define SR_MXR _AC(0x00080000, UL) /* Make eXecutable Readable */
/* zicfilp landing pad status bit */
#define SR_SPELP _AC(0x00800000, UL)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index c3005573e8c9..c36d1dfa16c6 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -600,4 +600,59 @@ static inline void riscv_insn_insert_utype_itype_imm(u32 *utype_insn, u32 *itype
*utype_insn |= (imm & RV_U_IMM_31_12_MASK) + ((imm & BIT(11)) << 1);
*itype_insn |= ((imm & RV_I_IMM_11_0_MASK) << RV_I_IMM_11_0_OPOFF);
}
+
+#define __read_insn(regs, insn, insn_addr, type) \
+({ \
+ int __ret; \
+ \
+ if (user_mode(regs)) { \
+ csr_set(CSR_STATUS, SR_MXR); \
+ __ret = get_user(insn, (type __user *) insn_addr); \
+ csr_clear(CSR_STATUS, SR_MXR); \
+ } else { \
+ insn = *(type *)insn_addr; \
+ __ret = 0; \
+ } \
+ \
+ __ret; \
+})
+
+static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn)
+{
+ ulong insn = 0;
+
+ if (epc & 0x2) {
+ ulong tmp = 0;
+
+ if (__read_insn(regs, insn, epc, u16))
+ return -EFAULT;
+ /* __get_user() uses regular "lw" which sign extend the loaded
+ * value make sure to clear higher order bits in case we "or" it
+ * below with the upper 16 bits half.
+ */
+ insn &= GENMASK(15, 0);
+ if ((insn & __INSN_LENGTH_MASK) != __INSN_LENGTH_32) {
+ *r_insn = insn;
+ return 0;
+ }
+ epc += sizeof(u16);
+ if (__read_insn(regs, tmp, epc, u16))
+ return -EFAULT;
+ *r_insn = (tmp << 16) | insn;
+
+ return 0;
+ } else {
+ if (__read_insn(regs, insn, epc, u32))
+ return -EFAULT;
+ if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) {
+ *r_insn = insn;
+ return 0;
+ }
+ insn &= GENMASK(15, 0);
+ *r_insn = insn;
+
+ return 0;
+ }
+}
+
#endif /* _ASM_RISCV_INSN_H */
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 815715c67f94..29af76aa486e 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -119,7 +119,7 @@ struct thread_struct {
struct __riscv_d_ext_state fstate;
unsigned long bad_cause;
unsigned long envcfg;
- unsigned long sum;
+ unsigned long sum_mxr;
u32 riscv_v_flags;
u32 vstate_ctrl;
struct __riscv_v_ext_state vstate;
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index a75f0cfea1e9..b6de2179570b 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -35,7 +35,7 @@ void asm_offsets(void)
OFFSET(TASK_THREAD_S9, task_struct, thread.s[9]);
OFFSET(TASK_THREAD_S10, task_struct, thread.s[10]);
OFFSET(TASK_THREAD_S11, task_struct, thread.s[11]);
- OFFSET(TASK_THREAD_SUM, task_struct, thread.sum);
+ OFFSET(TASK_THREAD_SUM_MXR, task_struct, thread.sum_mxr);
OFFSET(TASK_TI_CPU, task_struct, thread_info.cpu);
OFFSET(TASK_TI_PREEMPT_COUNT, task_struct, thread_info.preempt_count);
@@ -352,8 +352,8 @@ void asm_offsets(void)
offsetof(struct task_struct, thread.s[11])
- offsetof(struct task_struct, thread.ra)
);
- DEFINE(TASK_THREAD_SUM_RA,
- offsetof(struct task_struct, thread.sum)
+ DEFINE(TASK_THREAD_SUM_MXR_RA,
+ offsetof(struct task_struct, thread.sum_mxr)
- offsetof(struct task_struct, thread.ra)
);
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index d799c4e56f80..9ccc74aafece 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -172,13 +172,13 @@ SYM_CODE_START(handle_exception)
save_from_x6_to_x31
/*
- * Disable user-mode memory access as it should only be set in the
- * actual user copy routines.
+ * Disable user-mode memory access and MXR as it should only be set in
+ * the actual user copy routines.
*
* Disable the FPU/Vector to detect illegal usage of floating point
* or vector in kernel space.
*/
- li t0, SR_SUM | SR_FS_VS
+ li t0, SR_SUM | SR_MXR | SR_FS_VS
#ifdef CONFIG_64BIT
li t1, SR_ELP
or t0, t0, t1
@@ -443,15 +443,15 @@ SYM_FUNC_START(__switch_to)
REG_S s10, TASK_THREAD_S10_RA(a3)
REG_S s11, TASK_THREAD_S11_RA(a3)
- /* save the user space access flag */
+ /* save the user space access and MXR flag */
csrr s0, CSR_STATUS
- REG_S s0, TASK_THREAD_SUM_RA(a3)
+ REG_S s0, TASK_THREAD_SUM_MXR_RA(a3)
/* Save the kernel shadow call stack pointer */
scs_save_current
/* Restore context from next->thread */
- REG_L s0, TASK_THREAD_SUM_RA(a4)
- li s1, SR_SUM
+ REG_L s0, TASK_THREAD_SUM_MXR_RA(a4)
+ li s1, SR_SUM | SR_MXR
and s0, s0, s1
csrs CSR_STATUS, s0
REG_L ra, TASK_THREAD_RA_RA(a4)
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 6e8ae6c66322..f10f14001480 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -129,58 +129,6 @@ static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset,
#define GET_F32_RS2C(insn, regs) (get_f32_rs(insn, 2, regs))
#define GET_F32_RS2S(insn, regs) (get_f32_rs(RVC_RS2S(insn), 0, regs))
-#define __read_insn(regs, insn, insn_addr, type) \
-({ \
- int __ret; \
- \
- if (user_mode(regs)) { \
- __ret = get_user(insn, (type __user *) insn_addr); \
- } else { \
- insn = *(type *)insn_addr; \
- __ret = 0; \
- } \
- \
- __ret; \
-})
-
-static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn)
-{
- ulong insn = 0;
-
- if (epc & 0x2) {
- ulong tmp = 0;
-
- if (__read_insn(regs, insn, epc, u16))
- return -EFAULT;
- /* __get_user() uses regular "lw" which sign extend the loaded
- * value make sure to clear higher order bits in case we "or" it
- * below with the upper 16 bits half.
- */
- insn &= GENMASK(15, 0);
- if ((insn & __INSN_LENGTH_MASK) != __INSN_LENGTH_32) {
- *r_insn = insn;
- return 0;
- }
- epc += sizeof(u16);
- if (__read_insn(regs, tmp, epc, u16))
- return -EFAULT;
- *r_insn = (tmp << 16) | insn;
-
- return 0;
- } else {
- if (__read_insn(regs, insn, epc, u32))
- return -EFAULT;
- if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) {
- *r_insn = insn;
- return 0;
- }
- insn &= GENMASK(15, 0);
- *r_insn = insn;
-
- return 0;
- }
-}
-
union reg_data {
u8 data_bytes[8];
ulong data_ulong;
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index b112166d51e9..1e37810035a9 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -184,8 +184,8 @@ EXPORT_SYMBOL_GPL(riscv_v_vstate_ctrl_user_allowed);
bool riscv_v_first_use_handler(struct pt_regs *regs)
{
- u32 __user *epc = (u32 __user *)regs->epc;
- u32 insn = (u32)regs->badaddr;
+ unsigned long epc = regs->epc;
+ unsigned long insn = regs->badaddr;
if (!(has_vector() || has_xtheadvector()))
return false;
@@ -200,7 +200,7 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
/* Get the instruction */
if (!insn) {
- if (__get_user(insn, epc))
+ if (get_insn(regs, epc, &insn))
return false;
}
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 2/5] riscv: insn: Support decoding of CBO instructions
2026-09-07 7:21 [PATCH v3 0/5] Add workarounds for Picoheart erratas Yicong Yang
2026-09-07 7:21 ` [PATCH v3 1/5] riscv: Make get_insn public for instruction fault handling Yicong Yang
@ 2026-09-07 7:21 ` Yicong Yang
2026-09-07 7:21 ` [PATCH v3 3/5] riscv: errata: Add init framework for picoheart errata Yicong Yang
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Yicong Yang @ 2026-09-07 7:21 UTC (permalink / raw)
To: pjw, palmer, aou, linux-riscv
Cc: wangruikang, ganboing, alex, andrew.jones, cleger, geshijian,
niehaitao, cuiyunhui, yang.yicong
Add definitions for decoding CBO instructions. Rename
RVG_OPCODE_FENCE to RVG_OPCODE_MISC_MEM as spec defines
it as MISC-MEM and it's also used by CBO instructions.
Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
arch/riscv/include/asm/insn.h | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index c36d1dfa16c6..f6b32d8d558d 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -12,6 +12,7 @@
#define RV_INSN_FUNCT3_OPOFF 12
#define RV_INSN_OPCODE_MASK GENMASK(6, 0)
#define RV_INSN_OPCODE_OPOFF 0
+#define RV_INSN_FUNCT12_MASK GENMASK(31, 20)
#define RV_INSN_FUNCT12_OPOFF 20
#define RV_ENCODE_FUNCT3(f_) (RVG_FUNCT3_##f_ << RV_INSN_FUNCT3_OPOFF)
@@ -135,7 +136,7 @@
#define RVC_C2_RS1_MASK GENMASK(4, 0)
/* parts of opcode for RVG*/
-#define RVG_OPCODE_FENCE 0x0f
+#define RVG_OPCODE_MISC_MEM 0x0f
#define RVG_OPCODE_AUIPC 0x17
#define RVG_OPCODE_BRANCH 0x63
#define RVG_OPCODE_JALR 0x67
@@ -171,6 +172,7 @@
#define RVG_FUNCT3_JALR 0x0
#define RVG_FUNCT3_BEQ 0x0
#define RVG_FUNCT3_BNE 0x1
+#define RVG_FUNCT3_CBO 0x2
#define RVG_FUNCT3_BLT 0x4
#define RVG_FUNCT3_BGE 0x5
#define RVG_FUNCT3_BLTU 0x6
@@ -186,12 +188,14 @@
#define RVC_FUNCT4_C_EBREAK 0x9
#define RVG_FUNCT12_EBREAK 0x1
+#define RVG_FUNCT12_CBO_CLEAN 0x1
+#define RVG_FUNCT12_CBO_FLUSH 0x2
#define RVG_FUNCT12_SRET 0x102
#define RVG_MATCH_AUIPC (RVG_OPCODE_AUIPC)
#define RVG_MATCH_JALR (RV_ENCODE_FUNCT3(JALR) | RVG_OPCODE_JALR)
#define RVG_MATCH_JAL (RVG_OPCODE_JAL)
-#define RVG_MATCH_FENCE (RVG_OPCODE_FENCE)
+#define RVG_MATCH_FENCE (RVG_OPCODE_MISC_MEM)
#define RVG_MATCH_BEQ (RV_ENCODE_FUNCT3(BEQ) | RVG_OPCODE_BRANCH)
#define RVG_MATCH_BNE (RV_ENCODE_FUNCT3(BNE) | RVG_OPCODE_BRANCH)
#define RVG_MATCH_BLT (RV_ENCODE_FUNCT3(BLT) | RVG_OPCODE_BRANCH)
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 3/5] riscv: errata: Add init framework for picoheart errata
2026-09-07 7:21 [PATCH v3 0/5] Add workarounds for Picoheart erratas Yicong Yang
2026-09-07 7:21 ` [PATCH v3 1/5] riscv: Make get_insn public for instruction fault handling Yicong Yang
2026-09-07 7:21 ` [PATCH v3 2/5] riscv: insn: Support decoding of CBO instructions Yicong Yang
@ 2026-09-07 7:21 ` Yicong Yang
2026-09-07 7:21 ` [PATCH v3 4/5] riscv: errata: picoheart: Add workaround for cbo.clean errata Yicong Yang
2026-09-07 7:21 ` [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata Yicong Yang
4 siblings, 0 replies; 10+ messages in thread
From: Yicong Yang @ 2026-09-07 7:21 UTC (permalink / raw)
To: pjw, palmer, aou, linux-riscv
Cc: wangruikang, ganboing, alex, andrew.jones, cleger, geshijian,
niehaitao, cuiyunhui, yang.yicong
Add init framework for handling upcoming picoheart erratas.
Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
arch/riscv/Kconfig.errata | 10 ++++
arch/riscv/errata/Makefile | 1 +
arch/riscv/errata/picoheart/Makefile | 5 ++
arch/riscv/errata/picoheart/errata.c | 57 ++++++++++++++++++++
arch/riscv/include/asm/alternative.h | 3 ++
arch/riscv/include/asm/errata_list_vendors.h | 4 ++
arch/riscv/include/asm/vendorid_list.h | 1 +
arch/riscv/kernel/alternative.c | 5 ++
8 files changed, 86 insertions(+)
create mode 100644 arch/riscv/errata/picoheart/Makefile
create mode 100644 arch/riscv/errata/picoheart/errata.c
diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
index 3c945d086c7d..374d7fcf7936 100644
--- a/arch/riscv/Kconfig.errata
+++ b/arch/riscv/Kconfig.errata
@@ -154,4 +154,14 @@ config ERRATA_THEAD_GHOSTWRITE
If you don't know what to do here, say "Y".
+config ERRATA_PICOHEART
+ bool "Picoheart errata"
+ depends on RISCV_ALTERNATIVE
+ help
+ All Picoheart errata Kconfig depend on this Kconfig. Disabling
+ this Kconfig will disable all Picoheart errata. Please say "Y"
+ here if your platform uses Picoheart CPU cores.
+
+ Otherwise, please say "N" here to avoid unnecessary overhead.
+
endmenu # "CPU errata selection"
diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile
index 02a7a3335b1d..a36c5ce1ce7b 100644
--- a/arch/riscv/errata/Makefile
+++ b/arch/riscv/errata/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_ERRATA_ANDES) += andes/
obj-$(CONFIG_ERRATA_MIPS) += mips/
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
obj-$(CONFIG_ERRATA_THEAD) += thead/
+obj-$(CONFIG_ERRATA_PICOHEART) += picoheart/
diff --git a/arch/riscv/errata/picoheart/Makefile b/arch/riscv/errata/picoheart/Makefile
new file mode 100644
index 000000000000..6278c389b801
--- /dev/null
+++ b/arch/riscv/errata/picoheart/Makefile
@@ -0,0 +1,5 @@
+ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
+CFLAGS_errata.o := -mcmodel=medany
+endif
+
+obj-y += errata.o
diff --git a/arch/riscv/errata/picoheart/errata.c b/arch/riscv/errata/picoheart/errata.c
new file mode 100644
index 000000000000..53b690878f78
--- /dev/null
+++ b/arch/riscv/errata/picoheart/errata.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026 Picoheart (SG) Pte. Ltd.
+ *
+ * Author: Yicong Yang <yang.yicong@picoheart.com>
+ */
+
+#include <linux/cacheflush.h>
+#include <linux/cleanup.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/string.h>
+#include <asm/alternative.h>
+#include <asm/errata_list.h>
+#include <asm/text-patching.h>
+#include <asm/vendor_extensions.h>
+#include <asm/vendorid_list.h>
+
+static u32 picoheart_errata_probe(unsigned int stage, unsigned long archid,
+ unsigned long impid)
+{
+ return 0;
+}
+
+void picoheart_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
+ unsigned long archid, unsigned long impid,
+ unsigned int stage)
+{
+ u32 cpu_req_errata = picoheart_errata_probe(stage, archid, impid);
+ struct alt_entry *alt;
+ void *oldptr, *altptr;
+ u32 tmp;
+
+ BUILD_BUG_ON(ERRATA_PICOHEART_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
+
+ for (alt = begin; alt < end; alt++) {
+ if (alt->vendor_id != PICOHEART_VENDOR_ID ||
+ alt->patch_id >= ERRATA_PICOHEART_NUMBER)
+ continue;
+
+ tmp = (1U << alt->patch_id);
+ if (cpu_req_errata & tmp) {
+ oldptr = ALT_OLD_PTR(alt);
+ altptr = ALT_ALT_PTR(alt);
+
+ if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) {
+ memcpy(oldptr, altptr, alt->alt_len);
+ } else {
+ guard(mutex)(&text_mutex);
+ patch_text_nosync(oldptr, altptr, alt->alt_len);
+ }
+ }
+ }
+
+ if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
+ local_flush_icache_all();
+}
diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
index 8407d1d535b8..57298f21bb70 100644
--- a/arch/riscv/include/asm/alternative.h
+++ b/arch/riscv/include/asm/alternative.h
@@ -57,6 +57,9 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid,
unsigned int stage);
+void picoheart_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
+ unsigned long archid, unsigned long impid,
+ unsigned int stage);
void riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned int stage);
diff --git a/arch/riscv/include/asm/errata_list_vendors.h b/arch/riscv/include/asm/errata_list_vendors.h
index ec7eba373437..958e4f4624f7 100644
--- a/arch/riscv/include/asm/errata_list_vendors.h
+++ b/arch/riscv/include/asm/errata_list_vendors.h
@@ -26,4 +26,8 @@
#define ERRATA_MIPS_NUMBER 1
#endif
+#ifdef CONFIG_ERRATA_PICOHEART
+#define ERRATA_PICOHEART_NUMBER 0
+#endif
+
#endif /* ASM_ERRATA_LIST_VENDORS_H */
diff --git a/arch/riscv/include/asm/vendorid_list.h b/arch/riscv/include/asm/vendorid_list.h
index 7f5030ee1fcf..1ea6d00eb61a 100644
--- a/arch/riscv/include/asm/vendorid_list.h
+++ b/arch/riscv/include/asm/vendorid_list.h
@@ -10,5 +10,6 @@
#define MIPS_VENDOR_ID 0x127
#define SIFIVE_VENDOR_ID 0x489
#define THEAD_VENDOR_ID 0x5b7
+#define PICOHEART_VENDOR_ID 0x77d
#endif
diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
index c0c9306022c5..44c62932fb27 100644
--- a/arch/riscv/kernel/alternative.c
+++ b/arch/riscv/kernel/alternative.c
@@ -61,6 +61,11 @@ static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info
case THEAD_VENDOR_ID:
cpu_mfr_info->patch_func = thead_errata_patch_func;
break;
+#endif
+#ifdef CONFIG_ERRATA_PICOHEART
+ case PICOHEART_VENDOR_ID:
+ cpu_mfr_info->patch_func = picoheart_errata_patch_func;
+ break;
#endif
default:
cpu_mfr_info->patch_func = NULL;
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 4/5] riscv: errata: picoheart: Add workaround for cbo.clean errata
2026-09-07 7:21 [PATCH v3 0/5] Add workarounds for Picoheart erratas Yicong Yang
` (2 preceding siblings ...)
2026-09-07 7:21 ` [PATCH v3 3/5] riscv: errata: Add init framework for picoheart errata Yicong Yang
@ 2026-09-07 7:21 ` Yicong Yang
2026-09-07 7:21 ` [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata Yicong Yang
4 siblings, 0 replies; 10+ messages in thread
From: Yicong Yang @ 2026-09-07 7:21 UTC (permalink / raw)
To: pjw, palmer, aou, linux-riscv
Cc: wangruikang, ganboing, alex, andrew.jones, cleger, geshijian,
niehaitao, cuiyunhui, yang.yicong
cbo.clean may fail to write back the cacheline in a few very corner
cases on the affected Picoheart SoCs. Since cbo.flush is not affected,
the problem could be solved by promoting cbo.clean to cbo.flush to
keep the data coherent. So Implement and register Picoheart specific
riscv_nonstd_cache_ops for all the kernel space cache maintenance
operations. Implement riscv_nonstd_cache_ops->wback with cbo.clean
while other callbacks with corresponding CBO operations.
This could solve the issue in the kernel space. For userspace, clear
the xenvcfg.CBCFE to trap the cbo.{clean, flush} and emulate
the cbo.clean with cbo.flush in the kernel space to avoid the issue.
Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
arch/riscv/Kconfig.errata | 12 ++
arch/riscv/errata/picoheart/errata.c | 159 +++++++++++++++++++++++++++
arch/riscv/include/asm/errata_list.h | 25 ++++-
arch/riscv/kernel/cpufeature.c | 3 +
arch/riscv/kernel/traps.c | 4 +
5 files changed, 202 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
index 374d7fcf7936..8ce5c0314321 100644
--- a/arch/riscv/Kconfig.errata
+++ b/arch/riscv/Kconfig.errata
@@ -164,4 +164,16 @@ config ERRATA_PICOHEART
Otherwise, please say "N" here to avoid unnecessary overhead.
+config ERRATA_PICOHEART_CBO_CLEAN
+ bool "Apply Picoheart cbo.clean errata"
+ depends on ERRATA_PICOHEART
+ select RISCV_NONSTANDARD_CACHE_OPS
+ default y
+ help
+ This will apply the cbo.clean errata workaround on the affected
+ Picoheart SoCs where cbo.clean instructions may fail to write back
+ the cacheline in few corner cases.
+
+ If you don't know what to do here, say "Y".
+
endmenu # "CPU errata selection"
diff --git a/arch/riscv/errata/picoheart/errata.c b/arch/riscv/errata/picoheart/errata.c
index 53b690878f78..21480d19c084 100644
--- a/arch/riscv/errata/picoheart/errata.c
+++ b/arch/riscv/errata/picoheart/errata.c
@@ -5,20 +5,179 @@
* Author: Yicong Yang <yang.yicong@picoheart.com>
*/
+#include <linux/align.h>
#include <linux/cacheflush.h>
#include <linux/cleanup.h>
+#include <linux/jump_label.h>
#include <linux/kernel.h>
#include <linux/memory.h>
+#include <linux/mm_types.h>
+#include <linux/mmap_lock.h>
+#include <linux/signal.h>
#include <linux/string.h>
+#include <asm/asm-extable.h>
#include <asm/alternative.h>
+#include <asm/cpufeature.h>
+#include <asm/dma-noncoherent.h>
#include <asm/errata_list.h>
+#include <asm/insn.h>
+#include <asm/insn-def.h>
#include <asm/text-patching.h>
+#include <asm/uaccess.h>
#include <asm/vendor_extensions.h>
#include <asm/vendorid_list.h>
+#ifdef CONFIG_ERRATA_PICOHEART_CBO_CLEAN
+
+static bool insn_is_cbo_clean_flush(u32 insn_buf)
+{
+ u32 rd, opcode, funct3, funct12;
+
+ /* CBO instructions don't have compressed variants */
+ if (GET_INSN_LENGTH(insn_buf) != 4)
+ return false;
+
+ rd = RV_EXTRACT_RD_REG(insn_buf);
+ opcode = insn_buf & __INSN_OPCODE_MASK;
+ funct3 = insn_buf & RV_INSN_FUNCT3_MASK;
+ funct12 = insn_buf & RV_INSN_FUNCT12_MASK;
+
+ if (rd != 0 || opcode != RVG_OPCODE_MISC_MEM ||
+ funct3 != RV_ENCODE_FUNCT3(CBO) ||
+ (funct12 != RV_ENCODE_FUNCT12(CBO_CLEAN) &&
+ funct12 != RV_ENCODE_FUNCT12(CBO_FLUSH)))
+ return false;
+
+ return true;
+}
+
+static int cbo_clean_fault_sicode(unsigned long addr)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+
+ guard(mmap_read_lock)(mm);
+ vma = vma_lookup(mm, addr);
+ if (!vma)
+ return SEGV_MAPERR;
+
+ return SEGV_ACCERR;
+}
+
+bool riscv_picoheart_illegal_insn_handler(struct pt_regs *regs)
+{
+ unsigned long insn = regs->badaddr;
+ unsigned long epc = regs->epc;
+ void __user *line_addr;
+ int ret = 0;
+ u64 addr;
+ u32 rs1;
+
+ if (!insn) {
+ if (get_insn(regs, epc, &insn))
+ return false;
+ }
+
+ if (!insn_is_cbo_clean_flush(insn))
+ return false;
+
+ rs1 = RV_EXTRACT_RS1_REG(insn);
+ addr = rs1 ? ((unsigned long *)regs)[rs1] : 0;
+ line_addr = (void __user *)ALIGN_DOWN(addr, riscv_cbom_block_size);
+
+ /*
+ * Check if the target address is within the valid userspace
+ * address range. Otherwise update the bad_cause to match the
+ * store page fault. See the comment below.
+ */
+ if (!access_ok(line_addr, riscv_cbom_block_size)) {
+ current->thread.bad_cause = EXC_STORE_PAGE_FAULT;
+ goto err_map;
+ }
+
+ __enable_user_access();
+ asm volatile("\n"
+ "1: \n"
+ CBO_FLUSH(%[addr])
+ "2: \n"
+ _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %[err])
+ : [err] "+r" (ret)
+ : [addr] "r" (untagged_addr(addr))
+ : "memory");
+ __disable_user_access();
+
+ if (ret)
+ goto err_map;
+
+ regs->epc += GET_INSN_LENGTH(insn);
+ return true;
+
+err_map:
+ /*
+ * We'll reach here if the target address is invalid.
+ * cbo.{flush ,clean} on invalid address will cause
+ * store page fault, update the cause and badaddr.
+ */
+ regs->badaddr = addr;
+ regs->cause = current->thread.bad_cause;
+
+ /*
+ * In emulation of the cbo.clean, a SIGSEGV rather than
+ * a SIGILL should be issued if the target address is
+ * invalid. Use do_trap() to handle the signal delivery
+ * and related stuffs to make it analogous to the page
+ * fault.
+ */
+ do_trap(regs, SIGSEGV, cbo_clean_fault_sicode(untagged_addr(addr)),
+ untagged_addr(addr));
+
+ return true;
+}
+
+#endif /* CONFIG_ERRATA_PICOHEART_CBO_CLEAN */
+
+static void picoheart_errata_cache_wback(phys_addr_t paddr, size_t size)
+{
+ void *vaddr = phys_to_virt(paddr);
+
+ ALT_CMO_OP(FLUSH, vaddr, size, riscv_cbom_block_size);
+}
+
+/*
+ * The errata only affects the cbo.clean (wback) so use standard operations
+ * for other semantic.
+ */
+struct riscv_nonstd_cache_ops picoheart_errata_cmo_ops = {
+ .wback = &picoheart_errata_cache_wback,
+};
+
+DEFINE_STATIC_KEY_FALSE(has_picoheart_cbo_clean_errata);
+
+static void picoheart_errata_probe_cbo_clean(unsigned int stage,
+ unsigned long archid,
+ unsigned long impid)
+{
+ if (!IS_ENABLED(CONFIG_ERRATA_PICOHEART_CBO_CLEAN))
+ return;
+
+ if (stage != RISCV_ALTERNATIVES_BOOT)
+ return;
+
+ if (!riscv_isa_extension_available(NULL, ZICBOM))
+ return;
+
+ if (archid != 0x804a555049544552 || impid != 0x100)
+ return;
+
+ riscv_noncoherent_supported();
+ riscv_noncoherent_register_cache_ops(&picoheart_errata_cmo_ops);
+ static_branch_enable(&has_picoheart_cbo_clean_errata);
+}
+
static u32 picoheart_errata_probe(unsigned int stage, unsigned long archid,
unsigned long impid)
{
+ picoheart_errata_probe_cbo_clean(stage, archid, impid);
return 0;
}
diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
index 6694b5ccdcf8..7e31acae4e0a 100644
--- a/arch/riscv/include/asm/errata_list.h
+++ b/arch/riscv/include/asm/errata_list.h
@@ -117,6 +117,29 @@ asm volatile(ALTERNATIVE( \
#define THEAD_C9XX_RV_IRQ_PMU 17
#define THEAD_C9XX_CSR_SCOUNTEROF 0x5c5
-#endif /* __ASSEMBLER__ */
+#ifdef CONFIG_ERRATA_PICOHEART_CBO_CLEAN
+
+#include <linux/jump_label.h>
+
+DECLARE_STATIC_KEY_FALSE(has_picoheart_cbo_clean_errata);
+
+static inline bool riscv_has_picoheart_zicbom_errata(void)
+{
+ return static_branch_unlikely(&has_picoheart_cbo_clean_errata);
+}
+
+bool riscv_picoheart_illegal_insn_handler(struct pt_regs *regs);
+
+#else /* !CONFIG_ERRATA_PICOHEART_CBO_CLEAN */
+
+static inline bool riscv_has_picoheart_zicbom_errata(void) { return false; }
+static inline bool riscv_picoheart_illegal_insn_handler(struct pt_regs *regs)
+{
+ return false;
+}
+
+#endif /* CONFIG_ERRATA_PICOHEART_CBO_CLEAN */
+
+#endif /* __ASSEMBLY__ */
#endif
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index d2ec96843456..b56d149cf4ed 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -1215,6 +1215,9 @@ void __init riscv_user_isa_enable(void)
if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICBOP) &&
any_cpu_has_zicbop)
pr_warn("Zicbop disabled as it is unavailable on some harts\n");
+
+ if (riscv_has_picoheart_zicbom_errata())
+ current->thread.envcfg &= ~ENVCFG_CBCFE;
}
#ifdef CONFIG_RISCV_ALTERNATIVE
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index f8292adda099..a103203622ff 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -176,6 +176,10 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
local_irq_enable();
handled = riscv_v_first_use_handler(regs);
+
+ if (!handled && riscv_has_picoheart_zicbom_errata())
+ handled = riscv_picoheart_illegal_insn_handler(regs);
+
if (!handled)
do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->epc,
"Oops - illegal instruction");
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata
2026-09-07 7:21 [PATCH v3 0/5] Add workarounds for Picoheart erratas Yicong Yang
` (3 preceding siblings ...)
2026-09-07 7:21 ` [PATCH v3 4/5] riscv: errata: picoheart: Add workaround for cbo.clean errata Yicong Yang
@ 2026-09-07 7:21 ` Yicong Yang
2026-09-07 15:44 ` Conor Dooley
4 siblings, 1 reply; 10+ messages in thread
From: Yicong Yang @ 2026-09-07 7:21 UTC (permalink / raw)
To: pjw, palmer, aou, linux-riscv
Cc: wangruikang, ganboing, alex, andrew.jones, cleger, geshijian,
niehaitao, cuiyunhui, yang.yicong
Some Picoheart CPUs implement Zacas extension but lack support
for AMOCASQ PMA attribute. Thus makes the CASQ instruction de
facto unavailable. Since currently no ways to retrieve the PMA
information and the riscv kernel will declare cmpxchg128 support
if platform declare support of Zacas, the use of cmpxchg128 will
lead to PMA violation and crash the kernel. Add the errata
workaround to disable the use of cmpxchg128 on the affected CPUs.
Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
arch/riscv/Kconfig.errata | 12 ++++++++++++
arch/riscv/errata/picoheart/errata.c | 22 ++++++++++++++++++++++
arch/riscv/include/asm/cmpxchg.h | 2 +-
arch/riscv/include/asm/cpufeature.h | 8 ++++++++
arch/riscv/kernel/cpufeature.c | 13 ++++++++++++-
5 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
index 8ce5c0314321..16e37391d596 100644
--- a/arch/riscv/Kconfig.errata
+++ b/arch/riscv/Kconfig.errata
@@ -176,4 +176,16 @@ config ERRATA_PICOHEART_CBO_CLEAN
If you don't know what to do here, say "Y".
+config ERRATA_PICOHEART_AMOCASQ
+ bool "Apply Picoheart AMOCASQ errata"
+ depends on ERRATA_PICOHEART && RISCV_ISA_ZACAS
+ default y
+ help
+ Some Picoheart CPUs implement the Zacas extension but lack support
+ for AMOCASQ PMA attribute. Thus makes the CASQ instruction de facto
+ unavailable. Enable this errata workaround to disable the use of
+ CASQ in the kernel (cmpxchg128).
+
+ If you don't know what to do here, say "Y".
+
endmenu # "CPU errata selection"
diff --git a/arch/riscv/errata/picoheart/errata.c b/arch/riscv/errata/picoheart/errata.c
index 21480d19c084..0fb4cb41ab03 100644
--- a/arch/riscv/errata/picoheart/errata.c
+++ b/arch/riscv/errata/picoheart/errata.c
@@ -174,10 +174,32 @@ static void picoheart_errata_probe_cbo_clean(unsigned int stage,
static_branch_enable(&has_picoheart_cbo_clean_errata);
}
+static void picoheart_errata_probe_amocasq(unsigned int stage,
+ unsigned long archid,
+ unsigned long impid)
+{
+ if (!IS_ENABLED(CONFIG_ERRATA_PICOHEART_AMOCASQ))
+ return;
+
+ if (stage != RISCV_ALTERNATIVES_BOOT)
+ return;
+
+ if (!IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) ||
+ !riscv_isa_extension_available(NULL, ZACAS))
+ return;
+
+ if (archid != 0x804a555049544552 || impid != 0x100)
+ return;
+
+ static_branch_disable(&cpus_support_cmpxchg128);
+}
+
static u32 picoheart_errata_probe(unsigned int stage, unsigned long archid,
unsigned long impid)
{
picoheart_errata_probe_cbo_clean(stage, archid, impid);
+ picoheart_errata_probe_amocasq(stage, archid, impid);
+
return 0;
}
diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
index 662e160b0522..e231e9619eee 100644
--- a/arch/riscv/include/asm/cmpxchg.h
+++ b/arch/riscv/include/asm/cmpxchg.h
@@ -329,7 +329,7 @@
#if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) && defined(CONFIG_TOOLCHAIN_HAS_ZACAS)
-#define system_has_cmpxchg128() riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)
+#define system_has_cmpxchg128 system_has_cmpxchg128
union __u128_halves {
u128 full;
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 739fcc84bf7b..f9d95cbf5abd 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -164,4 +164,12 @@ static inline bool cpu_supports_indirect_br_lp_instr(void)
riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFILP));
}
+DECLARE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
+
+static inline bool system_has_cmpxchg128(void)
+{
+ return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS) &&
+ static_branch_likely(&cpus_support_cmpxchg128);
+}
+
#endif
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index b56d149cf4ed..f73ce43df626 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -46,6 +46,9 @@ struct riscv_isainfo hart_isa[NR_CPUS];
u32 thead_vlenb_of;
+/* All the CPUs supports cmpxchg128 (CASQ*). */
+DEFINE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
+
/**
* riscv_isa_extension_base() - Get base extension word
*
@@ -317,6 +320,14 @@ static int riscv_cfiss_validate(const struct riscv_isa_ext_data *data,
return 0;
}
+static int riscv_ext_zacas_validate(const struct riscv_isa_ext_data *data,
+ const unsigned long *isa_bitmap)
+{
+ static_branch_enable(&cpus_support_cmpxchg128);
+
+ return 0;
+}
+
static const unsigned int riscv_a_exts[] = {
RISCV_ISA_EXT_ZAAMO,
RISCV_ISA_EXT_ZALRSC,
@@ -544,7 +555,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(za64rs, RISCV_ISA_EXT_ZA64RS),
__RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO),
__RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA),
- __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
+ __RISCV_ISA_EXT_DATA_VALIDATE(zacas, RISCV_ISA_EXT_ZACAS, riscv_ext_zacas_validate),
__RISCV_ISA_EXT_DATA(zalasr, RISCV_ISA_EXT_ZALASR),
__RISCV_ISA_EXT_DATA(zalrsc, RISCV_ISA_EXT_ZALRSC),
__RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata
2026-09-07 7:21 ` [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata Yicong Yang
@ 2026-09-07 15:44 ` Conor Dooley
2026-09-08 11:41 ` Yicong Yang
0 siblings, 1 reply; 10+ messages in thread
From: Conor Dooley @ 2026-09-07 15:44 UTC (permalink / raw)
To: Yicong Yang
Cc: pjw, palmer, aou, linux-riscv, wangruikang, ganboing, alex,
andrew.jones, cleger, geshijian, niehaitao, cuiyunhui
[-- Attachment #1.1: Type: text/plain, Size: 6651 bytes --]
On Mon, Sep 07, 2026 at 03:21:49PM +0800, Yicong Yang wrote:
> Some Picoheart CPUs implement Zacas extension but lack support
> for AMOCASQ PMA attribute. Thus makes the CASQ instruction de
> facto unavailable. Since currently no ways to retrieve the PMA
> information and the riscv kernel will declare cmpxchg128 support
> if platform declare support of Zacas, the use of cmpxchg128 will
> lead to PMA violation and crash the kernel. Add the errata
> workaround to disable the use of cmpxchg128 on the affected CPUs.
>
> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> ---
> arch/riscv/Kconfig.errata | 12 ++++++++++++
> arch/riscv/errata/picoheart/errata.c | 22 ++++++++++++++++++++++
> arch/riscv/include/asm/cmpxchg.h | 2 +-
> arch/riscv/include/asm/cpufeature.h | 8 ++++++++
> arch/riscv/kernel/cpufeature.c | 13 ++++++++++++-
> 5 files changed, 55 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
> index 8ce5c0314321..16e37391d596 100644
> --- a/arch/riscv/Kconfig.errata
> +++ b/arch/riscv/Kconfig.errata
> @@ -176,4 +176,16 @@ config ERRATA_PICOHEART_CBO_CLEAN
>
> If you don't know what to do here, say "Y".
>
> +config ERRATA_PICOHEART_AMOCASQ
> + bool "Apply Picoheart AMOCASQ errata"
> + depends on ERRATA_PICOHEART && RISCV_ISA_ZACAS
> + default y
> + help
> + Some Picoheart CPUs implement the Zacas extension but lack support
> + for AMOCASQ PMA attribute. Thus makes the CASQ instruction de facto
> + unavailable. Enable this errata workaround to disable the use of
> + CASQ in the kernel (cmpxchg128).
> +
> + If you don't know what to do here, say "Y".
> +
> endmenu # "CPU errata selection"
> diff --git a/arch/riscv/errata/picoheart/errata.c b/arch/riscv/errata/picoheart/errata.c
> index 21480d19c084..0fb4cb41ab03 100644
> --- a/arch/riscv/errata/picoheart/errata.c
> +++ b/arch/riscv/errata/picoheart/errata.c
> @@ -174,10 +174,32 @@ static void picoheart_errata_probe_cbo_clean(unsigned int stage,
> static_branch_enable(&has_picoheart_cbo_clean_errata);
> }
>
> +static void picoheart_errata_probe_amocasq(unsigned int stage,
> + unsigned long archid,
> + unsigned long impid)
> +{
> + if (!IS_ENABLED(CONFIG_ERRATA_PICOHEART_AMOCASQ))
> + return;
> +
> + if (stage != RISCV_ALTERNATIVES_BOOT)
> + return;
> +
> + if (!IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) ||
> + !riscv_isa_extension_available(NULL, ZACAS))
> + return;
> +
> + if (archid != 0x804a555049544552 || impid != 0x100)
> + return;
> +
> + static_branch_disable(&cpus_support_cmpxchg128);
> +}
> +
> static u32 picoheart_errata_probe(unsigned int stage, unsigned long archid,
> unsigned long impid)
> {
> picoheart_errata_probe_cbo_clean(stage, archid, impid);
> + picoheart_errata_probe_amocasq(stage, archid, impid);
> +
> return 0;
> }
>
> diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
> index 662e160b0522..e231e9619eee 100644
> --- a/arch/riscv/include/asm/cmpxchg.h
> +++ b/arch/riscv/include/asm/cmpxchg.h
> @@ -329,7 +329,7 @@
>
> #if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) && defined(CONFIG_TOOLCHAIN_HAS_ZACAS)
>
> -#define system_has_cmpxchg128() riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)
> +#define system_has_cmpxchg128 system_has_cmpxchg128
>
> union __u128_halves {
> u128 full;
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index 739fcc84bf7b..f9d95cbf5abd 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -164,4 +164,12 @@ static inline bool cpu_supports_indirect_br_lp_instr(void)
> riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFILP));
> }
>
> +DECLARE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
> +
> +static inline bool system_has_cmpxchg128(void)
> +{
> + return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS) &&
> + static_branch_likely(&cpus_support_cmpxchg128);
> +}
> +
> #endif
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index b56d149cf4ed..f73ce43df626 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -46,6 +46,9 @@ struct riscv_isainfo hart_isa[NR_CPUS];
>
> u32 thead_vlenb_of;
>
> +/* All the CPUs supports cmpxchg128 (CASQ*). */
> +DEFINE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
> +
> /**
> * riscv_isa_extension_base() - Get base extension word
> *
> @@ -317,6 +320,14 @@ static int riscv_cfiss_validate(const struct riscv_isa_ext_data *data,
> return 0;
> }
>
> +static int riscv_ext_zacas_validate(const struct riscv_isa_ext_data *data,
> + const unsigned long *isa_bitmap)
> +{
> + static_branch_enable(&cpus_support_cmpxchg128);
A validate callback is meant to determine whether or not the extension
can be used, it's not there for people to add arbitrary code, partially
because each validate callback runs multiple times and may change state
depending on what happens with other extensions. E.g. a validate
callback may pass on the first iteration but fail on the second because
a dependant extension later in the list fails. In practice, this might
not ever affect Zacas, and doesn't at the moment, but this sort of code
should not be added to validate callbacks.
To be honest, I'd rather just turn the extension off entirely on this
platform rather than make everyone suffer.
The errata probe functions run after extension detection but before
patching, so could we just clear the Zacas bit in the isa bitmap?
Cheers,
Conor.
> +
> + return 0;
> +}
> +
> static const unsigned int riscv_a_exts[] = {
> RISCV_ISA_EXT_ZAAMO,
> RISCV_ISA_EXT_ZALRSC,
> @@ -544,7 +555,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
> __RISCV_ISA_EXT_DATA(za64rs, RISCV_ISA_EXT_ZA64RS),
> __RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO),
> __RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA),
> - __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
> + __RISCV_ISA_EXT_DATA_VALIDATE(zacas, RISCV_ISA_EXT_ZACAS, riscv_ext_zacas_validate),
> __RISCV_ISA_EXT_DATA(zalasr, RISCV_ISA_EXT_ZALASR),
> __RISCV_ISA_EXT_DATA(zalrsc, RISCV_ISA_EXT_ZALRSC),
> __RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
> --
> 2.50.1 (Apple Git-155)
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 161 bytes --]
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata
2026-09-07 15:44 ` Conor Dooley
@ 2026-09-08 11:41 ` Yicong Yang
2026-09-08 13:27 ` Conor Dooley
0 siblings, 1 reply; 10+ messages in thread
From: Yicong Yang @ 2026-09-08 11:41 UTC (permalink / raw)
To: Conor Dooley
Cc: yang.yicong, pjw, palmer, aou, linux-riscv, wangruikang, ganboing,
alex, andrew.jones, cleger, geshijian, niehaitao, cuiyunhui
Hi Conor,
On 9/7/26 11:44 PM, Conor Dooley wrote:
> On Mon, Sep 07, 2026 at 03:21:49PM +0800, Yicong Yang wrote:
>> Some Picoheart CPUs implement Zacas extension but lack support
>> for AMOCASQ PMA attribute. Thus makes the CASQ instruction de
>> facto unavailable. Since currently no ways to retrieve the PMA
>> information and the riscv kernel will declare cmpxchg128 support
>> if platform declare support of Zacas, the use of cmpxchg128 will
>> lead to PMA violation and crash the kernel. Add the errata
>> workaround to disable the use of cmpxchg128 on the affected CPUs.
>>
>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>> ---
>> arch/riscv/Kconfig.errata | 12 ++++++++++++
>> arch/riscv/errata/picoheart/errata.c | 22 ++++++++++++++++++++++
>> arch/riscv/include/asm/cmpxchg.h | 2 +-
>> arch/riscv/include/asm/cpufeature.h | 8 ++++++++
>> arch/riscv/kernel/cpufeature.c | 13 ++++++++++++-
>> 5 files changed, 55 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
>> index 8ce5c0314321..16e37391d596 100644
>> --- a/arch/riscv/Kconfig.errata
>> +++ b/arch/riscv/Kconfig.errata
>> @@ -176,4 +176,16 @@ config ERRATA_PICOHEART_CBO_CLEAN
>>
>> If you don't know what to do here, say "Y".
>>
>> +config ERRATA_PICOHEART_AMOCASQ
>> + bool "Apply Picoheart AMOCASQ errata"
>> + depends on ERRATA_PICOHEART && RISCV_ISA_ZACAS
>> + default y
>> + help
>> + Some Picoheart CPUs implement the Zacas extension but lack support
>> + for AMOCASQ PMA attribute. Thus makes the CASQ instruction de facto
>> + unavailable. Enable this errata workaround to disable the use of
>> + CASQ in the kernel (cmpxchg128).
>> +
>> + If you don't know what to do here, say "Y".
>> +
>> endmenu # "CPU errata selection"
>> diff --git a/arch/riscv/errata/picoheart/errata.c b/arch/riscv/errata/picoheart/errata.c
>> index 21480d19c084..0fb4cb41ab03 100644
>> --- a/arch/riscv/errata/picoheart/errata.c
>> +++ b/arch/riscv/errata/picoheart/errata.c
>> @@ -174,10 +174,32 @@ static void picoheart_errata_probe_cbo_clean(unsigned int stage,
>> static_branch_enable(&has_picoheart_cbo_clean_errata);
>> }
>>
>> +static void picoheart_errata_probe_amocasq(unsigned int stage,
>> + unsigned long archid,
>> + unsigned long impid)
>> +{
>> + if (!IS_ENABLED(CONFIG_ERRATA_PICOHEART_AMOCASQ))
>> + return;
>> +
>> + if (stage != RISCV_ALTERNATIVES_BOOT)
>> + return;
>> +
>> + if (!IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) ||
>> + !riscv_isa_extension_available(NULL, ZACAS))
>> + return;
>> +
>> + if (archid != 0x804a555049544552 || impid != 0x100)
>> + return;
>> +
>> + static_branch_disable(&cpus_support_cmpxchg128);
>> +}
>> +
>> static u32 picoheart_errata_probe(unsigned int stage, unsigned long archid,
>> unsigned long impid)
>> {
>> picoheart_errata_probe_cbo_clean(stage, archid, impid);
>> + picoheart_errata_probe_amocasq(stage, archid, impid);
>> +
>> return 0;
>> }
>>
>> diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
>> index 662e160b0522..e231e9619eee 100644
>> --- a/arch/riscv/include/asm/cmpxchg.h
>> +++ b/arch/riscv/include/asm/cmpxchg.h
>> @@ -329,7 +329,7 @@
>>
>> #if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) && defined(CONFIG_TOOLCHAIN_HAS_ZACAS)
>>
>> -#define system_has_cmpxchg128() riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)
>> +#define system_has_cmpxchg128 system_has_cmpxchg128
>>
>> union __u128_halves {
>> u128 full;
>> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
>> index 739fcc84bf7b..f9d95cbf5abd 100644
>> --- a/arch/riscv/include/asm/cpufeature.h
>> +++ b/arch/riscv/include/asm/cpufeature.h
>> @@ -164,4 +164,12 @@ static inline bool cpu_supports_indirect_br_lp_instr(void)
>> riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFILP));
>> }
>>
>> +DECLARE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
>> +
>> +static inline bool system_has_cmpxchg128(void)
>> +{
>> + return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS) &&
>> + static_branch_likely(&cpus_support_cmpxchg128);
>> +}
>> +
>> #endif
>> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
>> index b56d149cf4ed..f73ce43df626 100644
>> --- a/arch/riscv/kernel/cpufeature.c
>> +++ b/arch/riscv/kernel/cpufeature.c
>> @@ -46,6 +46,9 @@ struct riscv_isainfo hart_isa[NR_CPUS];
>>
>> u32 thead_vlenb_of;
>>
>> +/* All the CPUs supports cmpxchg128 (CASQ*). */
>> +DEFINE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
>> +
>> /**
>> * riscv_isa_extension_base() - Get base extension word
>> *
>> @@ -317,6 +320,14 @@ static int riscv_cfiss_validate(const struct riscv_isa_ext_data *data,
>> return 0;
>> }
>>
>> +static int riscv_ext_zacas_validate(const struct riscv_isa_ext_data *data,
>> + const unsigned long *isa_bitmap)
>> +{
>> + static_branch_enable(&cpus_support_cmpxchg128);
>
> A validate callback is meant to determine whether or not the extension
> can be used, it's not there for people to add arbitrary code, partially
> because each validate callback runs multiple times and may change state
> depending on what happens with other extensions. E.g. a validate
> callback may pass on the first iteration but fail on the second because
> a dependant extension later in the list fails. In practice, this might
> not ever affect Zacas, and doesn't at the moment, but this sort of code
> should not be added to validate callbacks.
agree that this doesn't match the validate callback function perfectly.
the motivation here is to split a separate control for cmpxchg128
then the suffered platform can disable it in the errata code. though all
the AMOCAS.{W,D,Q} are included by Zacas, the PMA attribute is separated
as AMOCASW, AMOCASD, AMOCASQ. so I suppose the right validation here
is to check whether the AMOCASQ is supported, similar to how the Zicbom
is enabled according to a valid riscv_cbom_block_size. But unfortunately
there's no starndard way to retrieve the PMA attributes currently.
>
> To be honest, I'd rather just turn the extension off entirely on this
> platform rather than make everyone suffer.
it's too brutal to disable the entire Zacas. we'll lose the performance
benefit from the users of cmpxchg and if clear it in the isa bitmap, it'll
be unavailable to the userspace. considering the kernel already provides
the system_has_cmpxchg128() for checking, we can limit it to cmpxchg128 only.
> The errata probe functions run after extension detection but before
> patching, so could we just clear the Zacas bit in the isa bitmap?
>
maybe not, as from _apply_alternatives() the errata probe/patch is performed
after the patching. so it's too late to clear the isa bitmap as the patching
is already done...
what about something like below to add an errata alternative to disable
the cmpxchg128 only on the suffered platforms? this will limit the
change only to system_has_cmpxchg128() and won't bother others:
#define system_has_cmpxchg128 system_has_cmpxchg128
static __always_inline bool system_has_cmpxchg128(void)
{
if (!IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
return riscv_isa_extension_available(NULL, ZACAS);
/* The vendor erratum overrides the standard Zacas alternative. */
asm goto(ALTERNATIVE_2(
"nop",
"j %l[l_yes]",
STANDARD_EXT, RISCV_ISA_EXT_ZACAS, 1,
"nop",
PICOHEART_VENDOR_ID, ERRATA_PICOHEART_AMOCASQ,
CONFIG_ERRATA_PICOHEART_AMOCASQ)
: : : : l_yes);
return false;
l_yes:
return true;
}
Thanks.
> Cheers,
> Conor.
>
>> +
>> + return 0;
>> +}
>> +
>> static const unsigned int riscv_a_exts[] = {
>> RISCV_ISA_EXT_ZAAMO,
>> RISCV_ISA_EXT_ZALRSC,
>> @@ -544,7 +555,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
>> __RISCV_ISA_EXT_DATA(za64rs, RISCV_ISA_EXT_ZA64RS),
>> __RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO),
>> __RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA),
>> - __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
>> + __RISCV_ISA_EXT_DATA_VALIDATE(zacas, RISCV_ISA_EXT_ZACAS, riscv_ext_zacas_validate),
>> __RISCV_ISA_EXT_DATA(zalasr, RISCV_ISA_EXT_ZALASR),
>> __RISCV_ISA_EXT_DATA(zalrsc, RISCV_ISA_EXT_ZALRSC),
>> __RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
>> --
>> 2.50.1 (Apple Git-155)
>>
>> _______________________________________________
>> linux-riscv mailing list
>> linux-riscv@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-riscv
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata
2026-09-08 11:41 ` Yicong Yang
@ 2026-09-08 13:27 ` Conor Dooley
2026-09-08 14:28 ` Yicong Yang
0 siblings, 1 reply; 10+ messages in thread
From: Conor Dooley @ 2026-09-08 13:27 UTC (permalink / raw)
To: Yicong Yang
Cc: pjw, palmer, aou, linux-riscv, wangruikang, ganboing, alex,
andrew.jones, cleger, geshijian, niehaitao, cuiyunhui
[-- Attachment #1.1: Type: text/plain, Size: 9979 bytes --]
On Tue, Sep 08, 2026 at 07:41:24PM +0800, Yicong Yang wrote:
> Hi Conor,
>
> On 9/7/26 11:44 PM, Conor Dooley wrote:
> > On Mon, Sep 07, 2026 at 03:21:49PM +0800, Yicong Yang wrote:
> >> Some Picoheart CPUs implement Zacas extension but lack support
> >> for AMOCASQ PMA attribute. Thus makes the CASQ instruction de
> >> facto unavailable. Since currently no ways to retrieve the PMA
> >> information and the riscv kernel will declare cmpxchg128 support
> >> if platform declare support of Zacas, the use of cmpxchg128 will
> >> lead to PMA violation and crash the kernel. Add the errata
> >> workaround to disable the use of cmpxchg128 on the affected CPUs.
> >>
> >> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> >> ---
> >> arch/riscv/Kconfig.errata | 12 ++++++++++++
> >> arch/riscv/errata/picoheart/errata.c | 22 ++++++++++++++++++++++
> >> arch/riscv/include/asm/cmpxchg.h | 2 +-
> >> arch/riscv/include/asm/cpufeature.h | 8 ++++++++
> >> arch/riscv/kernel/cpufeature.c | 13 ++++++++++++-
> >> 5 files changed, 55 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
> >> index 8ce5c0314321..16e37391d596 100644
> >> --- a/arch/riscv/Kconfig.errata
> >> +++ b/arch/riscv/Kconfig.errata
> >> @@ -176,4 +176,16 @@ config ERRATA_PICOHEART_CBO_CLEAN
> >>
> >> If you don't know what to do here, say "Y".
> >>
> >> +config ERRATA_PICOHEART_AMOCASQ
> >> + bool "Apply Picoheart AMOCASQ errata"
> >> + depends on ERRATA_PICOHEART && RISCV_ISA_ZACAS
> >> + default y
> >> + help
> >> + Some Picoheart CPUs implement the Zacas extension but lack support
> >> + for AMOCASQ PMA attribute. Thus makes the CASQ instruction de facto
> >> + unavailable. Enable this errata workaround to disable the use of
> >> + CASQ in the kernel (cmpxchg128).
> >> +
> >> + If you don't know what to do here, say "Y".
> >> +
> >> endmenu # "CPU errata selection"
> >> diff --git a/arch/riscv/errata/picoheart/errata.c b/arch/riscv/errata/picoheart/errata.c
> >> index 21480d19c084..0fb4cb41ab03 100644
> >> --- a/arch/riscv/errata/picoheart/errata.c
> >> +++ b/arch/riscv/errata/picoheart/errata.c
> >> @@ -174,10 +174,32 @@ static void picoheart_errata_probe_cbo_clean(unsigned int stage,
> >> static_branch_enable(&has_picoheart_cbo_clean_errata);
> >> }
> >>
> >> +static void picoheart_errata_probe_amocasq(unsigned int stage,
> >> + unsigned long archid,
> >> + unsigned long impid)
> >> +{
> >> + if (!IS_ENABLED(CONFIG_ERRATA_PICOHEART_AMOCASQ))
> >> + return;
> >> +
> >> + if (stage != RISCV_ALTERNATIVES_BOOT)
> >> + return;
> >> +
> >> + if (!IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) ||
> >> + !riscv_isa_extension_available(NULL, ZACAS))
> >> + return;
> >> +
> >> + if (archid != 0x804a555049544552 || impid != 0x100)
> >> + return;
> >> +
> >> + static_branch_disable(&cpus_support_cmpxchg128);
> >> +}
> >> +
> >> static u32 picoheart_errata_probe(unsigned int stage, unsigned long archid,
> >> unsigned long impid)
> >> {
> >> picoheart_errata_probe_cbo_clean(stage, archid, impid);
> >> + picoheart_errata_probe_amocasq(stage, archid, impid);
> >> +
> >> return 0;
> >> }
> >>
> >> diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
> >> index 662e160b0522..e231e9619eee 100644
> >> --- a/arch/riscv/include/asm/cmpxchg.h
> >> +++ b/arch/riscv/include/asm/cmpxchg.h
> >> @@ -329,7 +329,7 @@
> >>
> >> #if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) && defined(CONFIG_TOOLCHAIN_HAS_ZACAS)
> >>
> >> -#define system_has_cmpxchg128() riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)
> >> +#define system_has_cmpxchg128 system_has_cmpxchg128
> >>
> >> union __u128_halves {
> >> u128 full;
> >> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> >> index 739fcc84bf7b..f9d95cbf5abd 100644
> >> --- a/arch/riscv/include/asm/cpufeature.h
> >> +++ b/arch/riscv/include/asm/cpufeature.h
> >> @@ -164,4 +164,12 @@ static inline bool cpu_supports_indirect_br_lp_instr(void)
> >> riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFILP));
> >> }
> >>
> >> +DECLARE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
> >> +
> >> +static inline bool system_has_cmpxchg128(void)
> >> +{
> >> + return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS) &&
> >> + static_branch_likely(&cpus_support_cmpxchg128);
> >> +}
> >> +
> >> #endif
> >> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> >> index b56d149cf4ed..f73ce43df626 100644
> >> --- a/arch/riscv/kernel/cpufeature.c
> >> +++ b/arch/riscv/kernel/cpufeature.c
> >> @@ -46,6 +46,9 @@ struct riscv_isainfo hart_isa[NR_CPUS];
> >>
> >> u32 thead_vlenb_of;
> >>
> >> +/* All the CPUs supports cmpxchg128 (CASQ*). */
> >> +DEFINE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
> >> +
> >> /**
> >> * riscv_isa_extension_base() - Get base extension word
> >> *
> >> @@ -317,6 +320,14 @@ static int riscv_cfiss_validate(const struct riscv_isa_ext_data *data,
> >> return 0;
> >> }
> >>
> >> +static int riscv_ext_zacas_validate(const struct riscv_isa_ext_data *data,
> >> + const unsigned long *isa_bitmap)
> >> +{
> >> + static_branch_enable(&cpus_support_cmpxchg128);
> >
> > A validate callback is meant to determine whether or not the extension
> > can be used, it's not there for people to add arbitrary code, partially
> > because each validate callback runs multiple times and may change state
> > depending on what happens with other extensions. E.g. a validate
> > callback may pass on the first iteration but fail on the second because
> > a dependant extension later in the list fails. In practice, this might
> > not ever affect Zacas, and doesn't at the moment, but this sort of code
> > should not be added to validate callbacks.
>
> agree that this doesn't match the validate callback function perfectly.
It doesn't match it at all, it's not a slight mismatch, it's doing
something that cannot be done in one.
> the motivation here is to split a separate control for cmpxchg128
> then the suffered platform can disable it in the errata code. though all
> the AMOCAS.{W,D,Q} are included by Zacas, the PMA attribute is separated
> as AMOCASW, AMOCASD, AMOCASQ. so I suppose the right validation here
> is to check whether the AMOCASQ is supported, similar to how the Zicbom
> is enabled according to a valid riscv_cbom_block_size. But unfortunately
> there's no starndard way to retrieve the PMA attributes currently.
>
> >
> > To be honest, I'd rather just turn the extension off entirely on this
> > platform rather than make everyone suffer.
>
> it's too brutal to disable the entire Zacas. we'll lose the performance
> benefit from the users of cmpxchg and if clear it in the isa bitmap, it'll
> be unavailable to the userspace. considering the kernel already provides
> the system_has_cmpxchg128() for checking, we can limit it to cmpxchg128 only.
I don't understand the details of this particular extension, but should we
be telling userspace that the extension is supported? Is the same problem
of not being able to use AMOCAS.Q present there?
>
> > The errata probe functions run after extension detection but before
> > patching, so could we just clear the Zacas bit in the isa bitmap?
> >
>
> maybe not, as from _apply_alternatives() the errata probe/patch is performed
> after the patching. so it's too late to clear the isa bitmap as the patching
> is already done...
Ah right, I did actually go and look at this but I forgot that
riscv_fill_cpu_mfr_info() only sets the manufacturer and patch function,
and doesn't actually run it.
>
> what about something like below to add an errata alternative to disable
> the cmpxchg128 only on the suffered platforms? this will limit the
> change only to system_has_cmpxchg128() and won't bother others:
>
> #define system_has_cmpxchg128 system_has_cmpxchg128
> static __always_inline bool system_has_cmpxchg128(void)
> {
> if (!IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> return riscv_isa_extension_available(NULL, ZACAS);
>
> /* The vendor erratum overrides the standard Zacas alternative. */
> asm goto(ALTERNATIVE_2(
> "nop",
> "j %l[l_yes]",
> STANDARD_EXT, RISCV_ISA_EXT_ZACAS, 1,
> "nop",
> PICOHEART_VENDOR_ID, ERRATA_PICOHEART_AMOCASQ,
> CONFIG_ERRATA_PICOHEART_AMOCASQ)
> : : : : l_yes);
I would prefer this because it doesn't abuse a validate callback.
Thanks,
Conor.
>
> return false;
> l_yes:
> return true;
> }
>
> Thanks.
>
>
> > Cheers,
> > Conor.
> >
> >> +
> >> + return 0;
> >> +}
> >> +
> >> static const unsigned int riscv_a_exts[] = {
> >> RISCV_ISA_EXT_ZAAMO,
> >> RISCV_ISA_EXT_ZALRSC,
> >> @@ -544,7 +555,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
> >> __RISCV_ISA_EXT_DATA(za64rs, RISCV_ISA_EXT_ZA64RS),
> >> __RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO),
> >> __RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA),
> >> - __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
> >> + __RISCV_ISA_EXT_DATA_VALIDATE(zacas, RISCV_ISA_EXT_ZACAS, riscv_ext_zacas_validate),
> >> __RISCV_ISA_EXT_DATA(zalasr, RISCV_ISA_EXT_ZALASR),
> >> __RISCV_ISA_EXT_DATA(zalrsc, RISCV_ISA_EXT_ZALRSC),
> >> __RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
> >> --
> >> 2.50.1 (Apple Git-155)
> >>
> >> _______________________________________________
> >> linux-riscv mailing list
> >> linux-riscv@lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 161 bytes --]
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata
2026-09-08 13:27 ` Conor Dooley
@ 2026-09-08 14:28 ` Yicong Yang
0 siblings, 0 replies; 10+ messages in thread
From: Yicong Yang @ 2026-09-08 14:28 UTC (permalink / raw)
To: Conor Dooley
Cc: yang.yicong, pjw, palmer, aou, linux-riscv, wangruikang, ganboing,
alex, andrew.jones, cleger, geshijian, niehaitao, cuiyunhui
On 9/8/26 9:27 PM, Conor Dooley wrote:
> On Tue, Sep 08, 2026 at 07:41:24PM +0800, Yicong Yang wrote:
>> Hi Conor,
>>
>> On 9/7/26 11:44 PM, Conor Dooley wrote:
>>> On Mon, Sep 07, 2026 at 03:21:49PM +0800, Yicong Yang wrote:
>>>> Some Picoheart CPUs implement Zacas extension but lack support
>>>> for AMOCASQ PMA attribute. Thus makes the CASQ instruction de
>>>> facto unavailable. Since currently no ways to retrieve the PMA
>>>> information and the riscv kernel will declare cmpxchg128 support
>>>> if platform declare support of Zacas, the use of cmpxchg128 will
>>>> lead to PMA violation and crash the kernel. Add the errata
>>>> workaround to disable the use of cmpxchg128 on the affected CPUs.
>>>>
>>>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>>>> ---
>>>> arch/riscv/Kconfig.errata | 12 ++++++++++++
>>>> arch/riscv/errata/picoheart/errata.c | 22 ++++++++++++++++++++++
>>>> arch/riscv/include/asm/cmpxchg.h | 2 +-
>>>> arch/riscv/include/asm/cpufeature.h | 8 ++++++++
>>>> arch/riscv/kernel/cpufeature.c | 13 ++++++++++++-
>>>> 5 files changed, 55 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
>>>> index 8ce5c0314321..16e37391d596 100644
>>>> --- a/arch/riscv/Kconfig.errata
>>>> +++ b/arch/riscv/Kconfig.errata
>>>> @@ -176,4 +176,16 @@ config ERRATA_PICOHEART_CBO_CLEAN
>>>>
>>>> If you don't know what to do here, say "Y".
>>>>
>>>> +config ERRATA_PICOHEART_AMOCASQ
>>>> + bool "Apply Picoheart AMOCASQ errata"
>>>> + depends on ERRATA_PICOHEART && RISCV_ISA_ZACAS
>>>> + default y
>>>> + help
>>>> + Some Picoheart CPUs implement the Zacas extension but lack support
>>>> + for AMOCASQ PMA attribute. Thus makes the CASQ instruction de facto
>>>> + unavailable. Enable this errata workaround to disable the use of
>>>> + CASQ in the kernel (cmpxchg128).
>>>> +
>>>> + If you don't know what to do here, say "Y".
>>>> +
>>>> endmenu # "CPU errata selection"
>>>> diff --git a/arch/riscv/errata/picoheart/errata.c b/arch/riscv/errata/picoheart/errata.c
>>>> index 21480d19c084..0fb4cb41ab03 100644
>>>> --- a/arch/riscv/errata/picoheart/errata.c
>>>> +++ b/arch/riscv/errata/picoheart/errata.c
>>>> @@ -174,10 +174,32 @@ static void picoheart_errata_probe_cbo_clean(unsigned int stage,
>>>> static_branch_enable(&has_picoheart_cbo_clean_errata);
>>>> }
>>>>
>>>> +static void picoheart_errata_probe_amocasq(unsigned int stage,
>>>> + unsigned long archid,
>>>> + unsigned long impid)
>>>> +{
>>>> + if (!IS_ENABLED(CONFIG_ERRATA_PICOHEART_AMOCASQ))
>>>> + return;
>>>> +
>>>> + if (stage != RISCV_ALTERNATIVES_BOOT)
>>>> + return;
>>>> +
>>>> + if (!IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) ||
>>>> + !riscv_isa_extension_available(NULL, ZACAS))
>>>> + return;
>>>> +
>>>> + if (archid != 0x804a555049544552 || impid != 0x100)
>>>> + return;
>>>> +
>>>> + static_branch_disable(&cpus_support_cmpxchg128);
>>>> +}
>>>> +
>>>> static u32 picoheart_errata_probe(unsigned int stage, unsigned long archid,
>>>> unsigned long impid)
>>>> {
>>>> picoheart_errata_probe_cbo_clean(stage, archid, impid);
>>>> + picoheart_errata_probe_amocasq(stage, archid, impid);
>>>> +
>>>> return 0;
>>>> }
>>>>
>>>> diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
>>>> index 662e160b0522..e231e9619eee 100644
>>>> --- a/arch/riscv/include/asm/cmpxchg.h
>>>> +++ b/arch/riscv/include/asm/cmpxchg.h
>>>> @@ -329,7 +329,7 @@
>>>>
>>>> #if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) && defined(CONFIG_TOOLCHAIN_HAS_ZACAS)
>>>>
>>>> -#define system_has_cmpxchg128() riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)
>>>> +#define system_has_cmpxchg128 system_has_cmpxchg128
>>>>
>>>> union __u128_halves {
>>>> u128 full;
>>>> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
>>>> index 739fcc84bf7b..f9d95cbf5abd 100644
>>>> --- a/arch/riscv/include/asm/cpufeature.h
>>>> +++ b/arch/riscv/include/asm/cpufeature.h
>>>> @@ -164,4 +164,12 @@ static inline bool cpu_supports_indirect_br_lp_instr(void)
>>>> riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFILP));
>>>> }
>>>>
>>>> +DECLARE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
>>>> +
>>>> +static inline bool system_has_cmpxchg128(void)
>>>> +{
>>>> + return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS) &&
>>>> + static_branch_likely(&cpus_support_cmpxchg128);
>>>> +}
>>>> +
>>>> #endif
>>>> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
>>>> index b56d149cf4ed..f73ce43df626 100644
>>>> --- a/arch/riscv/kernel/cpufeature.c
>>>> +++ b/arch/riscv/kernel/cpufeature.c
>>>> @@ -46,6 +46,9 @@ struct riscv_isainfo hart_isa[NR_CPUS];
>>>>
>>>> u32 thead_vlenb_of;
>>>>
>>>> +/* All the CPUs supports cmpxchg128 (CASQ*). */
>>>> +DEFINE_STATIC_KEY_FALSE(cpus_support_cmpxchg128);
>>>> +
>>>> /**
>>>> * riscv_isa_extension_base() - Get base extension word
>>>> *
>>>> @@ -317,6 +320,14 @@ static int riscv_cfiss_validate(const struct riscv_isa_ext_data *data,
>>>> return 0;
>>>> }
>>>>
>>>> +static int riscv_ext_zacas_validate(const struct riscv_isa_ext_data *data,
>>>> + const unsigned long *isa_bitmap)
>>>> +{
>>>> + static_branch_enable(&cpus_support_cmpxchg128);
>>>
>>> A validate callback is meant to determine whether or not the extension
>>> can be used, it's not there for people to add arbitrary code, partially
>>> because each validate callback runs multiple times and may change state
>>> depending on what happens with other extensions. E.g. a validate
>>> callback may pass on the first iteration but fail on the second because
>>> a dependant extension later in the list fails. In practice, this might
>>> not ever affect Zacas, and doesn't at the moment, but this sort of code
>>> should not be added to validate callbacks.
>>
>> agree that this doesn't match the validate callback function perfectly.
>
> It doesn't match it at all, it's not a slight mismatch, it's doing
> something that cannot be done in one.
>
>> the motivation here is to split a separate control for cmpxchg128
>> then the suffered platform can disable it in the errata code. though all
>> the AMOCAS.{W,D,Q} are included by Zacas, the PMA attribute is separated
>> as AMOCASW, AMOCASD, AMOCASQ. so I suppose the right validation here
>> is to check whether the AMOCASQ is supported, similar to how the Zicbom
>> is enabled according to a valid riscv_cbom_block_size. But unfortunately
>> there's no starndard way to retrieve the PMA attributes currently.
>>
>>>
>>> To be honest, I'd rather just turn the extension off entirely on this
>>> platform rather than make everyone suffer.
>>
>> it's too brutal to disable the entire Zacas. we'll lose the performance
>> benefit from the users of cmpxchg and if clear it in the isa bitmap, it'll
>> be unavailable to the userspace. considering the kernel already provides
>> the system_has_cmpxchg128() for checking, we can limit it to cmpxchg128 only.
>
> I don't understand the details of this particular extension, but should we
> be telling userspace that the extension is supported? Is the same problem
> of not being able to use AMOCAS.Q present there?
Zacas include support of three CAS instructions for word(W), doubleword(D) and
quadword(Q) respectively, the former 2 are more widely used and we want them
to be supported (same to the kernel). casq is not available due to the PMA but the
consequence is less fatal, unlike in the kernel that a PMA violation will cause
the crash.
>
>>
>>> The errata probe functions run after extension detection but before
>>> patching, so could we just clear the Zacas bit in the isa bitmap?
>>>
>>
>> maybe not, as from _apply_alternatives() the errata probe/patch is performed
>> after the patching. so it's too late to clear the isa bitmap as the patching
>> is already done...
>
> Ah right, I did actually go and look at this but I forgot that
> riscv_fill_cpu_mfr_info() only sets the manufacturer and patch function,
> and doesn't actually run it.
>
>>
>> what about something like below to add an errata alternative to disable
>> the cmpxchg128 only on the suffered platforms? this will limit the
>> change only to system_has_cmpxchg128() and won't bother others:
>>
>> #define system_has_cmpxchg128 system_has_cmpxchg128
>> static __always_inline bool system_has_cmpxchg128(void)
>> {
>> if (!IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
>> return riscv_isa_extension_available(NULL, ZACAS);
>>
>> /* The vendor erratum overrides the standard Zacas alternative. */
>> asm goto(ALTERNATIVE_2(
>> "nop",
>> "j %l[l_yes]",
>> STANDARD_EXT, RISCV_ISA_EXT_ZACAS, 1,
>> "nop",
>> PICOHEART_VENDOR_ID, ERRATA_PICOHEART_AMOCASQ,
>> CONFIG_ERRATA_PICOHEART_AMOCASQ)
>> : : : : l_yes);
>
> I would prefer this because it doesn't abuse a validate callback.
>
sure, will update in v4.
thanks.
> Thanks,
> Conor.
>
>>
>> return false;
>> l_yes:
>> return true;
>> }
>>
>> Thanks.
>>
>>
>>> Cheers,
>>> Conor.
>>>
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> static const unsigned int riscv_a_exts[] = {
>>>> RISCV_ISA_EXT_ZAAMO,
>>>> RISCV_ISA_EXT_ZALRSC,
>>>> @@ -544,7 +555,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
>>>> __RISCV_ISA_EXT_DATA(za64rs, RISCV_ISA_EXT_ZA64RS),
>>>> __RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO),
>>>> __RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA),
>>>> - __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
>>>> + __RISCV_ISA_EXT_DATA_VALIDATE(zacas, RISCV_ISA_EXT_ZACAS, riscv_ext_zacas_validate),
>>>> __RISCV_ISA_EXT_DATA(zalasr, RISCV_ISA_EXT_ZALASR),
>>>> __RISCV_ISA_EXT_DATA(zalrsc, RISCV_ISA_EXT_ZALRSC),
>>>> __RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
>>>> --
>>>> 2.50.1 (Apple Git-155)
>>>>
>>>> _______________________________________________
>>>> linux-riscv mailing list
>>>> linux-riscv@lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/linux-riscv
>>
>> _______________________________________________
>> linux-riscv mailing list
>> linux-riscv@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-riscv
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-09-08 14:29 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 7:21 [PATCH v3 0/5] Add workarounds for Picoheart erratas Yicong Yang
2026-09-07 7:21 ` [PATCH v3 1/5] riscv: Make get_insn public for instruction fault handling Yicong Yang
2026-09-07 7:21 ` [PATCH v3 2/5] riscv: insn: Support decoding of CBO instructions Yicong Yang
2026-09-07 7:21 ` [PATCH v3 3/5] riscv: errata: Add init framework for picoheart errata Yicong Yang
2026-09-07 7:21 ` [PATCH v3 4/5] riscv: errata: picoheart: Add workaround for cbo.clean errata Yicong Yang
2026-09-07 7:21 ` [PATCH v3 5/5] riscv: errata: picoheart: Add workaround for AMOCASQ errata Yicong Yang
2026-09-07 15:44 ` Conor Dooley
2026-09-08 11:41 ` Yicong Yang
2026-09-08 13:27 ` Conor Dooley
2026-09-08 14:28 ` Yicong Yang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.