Some cpufeatures should be handled via the alternatives mechanism
to not incur penalties on unsupporting variants.
So add a mechanism to handle these similar to cpu erratas.
Signed-off-by: Heiko Stuebner <heiko@...>
arch/riscv/errata/Makefile | 1 +
arch/riscv/errata/alternative.c | 3 ++
arch/riscv/errata/cpufeatures.c | 55 ++++++++++++++++++++++++++++
arch/riscv/include/asm/alternative.h | 1 +
arch/riscv/include/asm/errata_list.h | 2 +
5 files changed, 62 insertions(+)
create mode 100644 arch/riscv/errata/cpufeatures.c
@@ -1,2 +1,3 @@
obj-y += alternative.o
+obj-y += cpufeatures.o
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
@@ -64,6 +64,9 @@ void __init apply_boot_alternatives(void)
init_alternative();
+ riscv_apply_cpufeatures((struct alt_entry *)__alt_start,
+ (struct alt_entry *)__alt_end);
+
if (!vendor_patch_func)
return;
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cpufeatures runtime patching
+ *
+ * Copyright (C) 2021 ?????
+ */
+
+#include <linux/init.h>
+#include <linux/of.h>
+#include <asm/alternative.h>
+#include <asm/errata_list.h>
+#include <asm/patch.h>
+
+struct cpufeature_info_t {
+ char name[ERRATA_STRING_LENGTH_MAX];
+ bool (*check_func)(void);
+};
+
+static struct cpufeature_info_t cpufeature_list[CPUFEATURE_NUMBER] = {
+};
+
+static u32 __init cpufeature_probe(void)
+{
+ u32 cpu_req_feature = 0;
+ int idx;
+
+ for (idx = 0; idx < CPUFEATURE_NUMBER; idx++)
+ if (cpufeature_list[idx].check_func())
+ cpu_req_feature |= (1U << idx);
+
+ return cpu_req_feature;
+}
+
+void riscv_apply_cpufeatures(struct alt_entry *begin, struct alt_entry *end)
+{
+ u32 cpu_req_feature = cpufeature_probe();
+ u32 cpu_apply_feature = 0;
+ struct alt_entry *alt;
+ u32 tmp;
+
+ for (alt = begin; alt < end; alt++) {
+ if (alt->vendor_id != 0)
+ continue;
+ if (alt->errata_id >= CPUFEATURE_NUMBER) {
+ WARN(1, "This feature id:%d is not in kernel cpufeature list", alt->errata_id);
+ continue;
+ }
+
+ tmp = (1U << alt->errata_id);
+ if (cpu_req_feature & tmp) {
+ patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
+ cpu_apply_feature |= tmp;
+ }
+ }
+}
@@ -35,5 +35,6 @@ struct errata_checkfunc_id {
void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid);
+void riscv_apply_cpufeatures(struct alt_entry *begin, struct alt_entry *end);
#endif
#endif
@@ -14,6 +14,8 @@
#define ERRATA_SIFIVE_NUMBER 2
#endif
+#define CPUFEATURE_NUMBER 0
+
#ifdef __ASSEMBLY__
#define ALT_INSN_FAULT(x) \