[PATCH v2 4/6] riscv: errata: Add init framework for picoheart errata
Yicong Yang
yang.yicong at picoheart.com
Tue Jul 28 02:46:25 PDT 2026
Add init framework for handling upcoming picoheart erratas.
Signed-off-by: Yicong Yang <yang.yicong at 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 at 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 beaf9236dba7..dba770b8503c 100644
--- a/arch/riscv/include/asm/vendorid_list.h
+++ b/arch/riscv/include/asm/vendorid_list.h
@@ -10,6 +10,7 @@
#define MIPS_VENDOR_ID 0x127
#define SIFIVE_VENDOR_ID 0x489
#define THEAD_VENDOR_ID 0x5b7
+#define PICOHEART_VENDOR_ID 0x77d
#define QEMU_VIRT_VENDOR_ID 0x000
#define QEMU_VIRT_IMPL_ID 0x000
diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
index 104dc0862c5c..88639918ee7d 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)
More information about the linux-riscv
mailing list