Skip to content

Commit

Permalink
riscv: add cpufeature handling via alternatives
Browse files Browse the repository at this point in the history
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@sntech.de>
  • Loading branch information
mmind authored and guoren83 committed Feb 10, 2022
1 parent 2bd218e commit 9a8cf89
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 1 deletion.
3 changes: 3 additions & 0 deletions arch/riscv/include/asm/alternative.h
Expand Up @@ -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
2 changes: 2 additions & 0 deletions arch/riscv/include/asm/errata_list.h
Expand Up @@ -14,6 +14,8 @@
#define ERRATA_SIFIVE_NUMBER 2
#endif

#define CPUFEATURE_NUMBER 0

#ifdef __ASSEMBLY__

#define ALT_INSN_FAULT(x) \
Expand Down
2 changes: 2 additions & 0 deletions arch/riscv/kernel/alternative.c
Expand Up @@ -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;

Expand Down
55 changes: 54 additions & 1 deletion arch/riscv/kernel/cpufeature.c
Expand Up @@ -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>

Expand Down Expand Up @@ -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;
}
}
}

0 comments on commit 9a8cf89

Please sign in to comment.