riscv: add cpufeature handling via alternatives

A patch from »riscv: support for svpbmt and D1 memory types« in state Mainline for linux-kernel

From: Heiko Stuebner <heiko@...> Date: Sun, 5 Dec 2021 12:01:49 +0100

Commit-Message

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

Patch-Comment

arch/riscv/include/asm/alternative.h | 3 ++ arch/riscv/include/asm/errata_list.h | 2 + arch/riscv/kernel/alternative.c | 2 + arch/riscv/kernel/cpufeature.c | 55 +++++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 1 deletion(-)

Statistics

  • 61 lines added
  • 1 lines removed

Changes

--------------------- arch/riscv/include/asm/alternative.h ---------------------
index f0657b1b3174..cf3b22173834 100644
@@ -39,5 +39,8 @@ struct errata_checkfunc_id {
void sifive_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);
#endif
#endif
--------------------- arch/riscv/include/asm/errata_list.h ---------------------
index 5f1046e82d9f..6b95bd9aee82 100644
@@ -14,6 +14,8 @@
#define ERRATA_SIFIVE_NUMBER 2
#endif
+#define CPUFEATURE_NUMBER 0
+
#ifdef __ASSEMBLY__
#define ALT_INSN_FAULT(x) \
----------------------- arch/riscv/kernel/alternative.c ------------------------
index e1849faa2fa1..54913857b682 100644
@@ -63,6 +63,8 @@ static void __init_or_module _apply_alternatives(struct alt_entry *begin,
struct alt_entry *end,
unsigned int stage)
{
+ riscv_cpufeature_patch_func(begin, end, stage);
+
if (!vendor_patch_func)
return;
------------------------ arch/riscv/kernel/cpufeature.c ------------------------
index d959d207a40d..fef804346d75 100644
@@ -8,8 +8,12 @@
#include <linux/bitmap.h>
#include <linux/of.h>
-#include <asm/processor.h>
+#include <asm/alternative.h>
+#include <asm/errata_list.h>
#include <asm/hwcap.h>
+#include <asm/patch.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
#include <asm/smp.h>
#include <asm/switch_to.h>
@@ -149,3 +153,52 @@ void __init riscv_fill_hwcap(void)
static_branch_enable(&cpu_hwcap_fpu);
#endif
}
+
+struct cpufeature_info {
+ char name[ERRATA_STRING_LENGTH_MAX];
+ bool (*check_func)(unsigned int stage);
+};
+
+static const struct cpufeature_info cpufeature_list[CPUFEATURE_NUMBER] = {
+};
+
+static u32 __init cpufeature_probe(unsigned int stage)
+{
+ const struct cpufeature_info *info;
+ u32 cpu_req_feature = 0;
+ int idx;
+
+ for (idx = 0; idx < CPUFEATURE_NUMBER; idx++) {
+ info = &cpufeature_list[idx];
+
+ if (info->check_func(stage))
+ cpu_req_feature |= (1U << idx);
+ }
+
+ return cpu_req_feature;
+}
+
+void riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *end,
+ unsigned int stage)
+{
+ u32 cpu_req_feature = cpufeature_probe(stage);
+ 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;
+ }
+ }
+}
 
 

Recent Patches

About Us

Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer.

Read More...