riscv: add cpufeature handling via alternatives

A patch from »svpbmt and t-head 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 | 56 +++++++++++++++++++++++++++- 4 files changed, 62 insertions(+), 1 deletion(-)

Statistics

  • 62 lines added
  • 1 lines removed

Changes

--------------------- arch/riscv/include/asm/alternative.h ---------------------
index 973892e61c07..3ed027113526 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 8ad76b290c59..6acb324f4815 100644
@@ -62,6 +62,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..dba8fc688303 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,53 @@ void __init riscv_fill_hwcap(void)
static_branch_enable(&cpu_hwcap_fpu);
#endif
}
+
+struct cpufeature_info {
+ char name[ERRATA_STRING_LENGTH_MAX];
+ unsigned int stage;
+ 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 ((stage == RISCV_ALTERNATIVES_MODULE ||
+ info->stage == stage) && 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...