riscv: sifive: Add SiFive alternative ports

Add required ports of the Alternative scheme for SiFive.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
This commit is contained in:
Vincent Chen 2021-03-22 22:26:04 +08:00 committed by Palmer Dabbelt
parent 6f4eea9046
commit 1a0e5dbd37
No known key found for this signature in database
GPG key ID: 2E1319F35FBB1889
7 changed files with 89 additions and 0 deletions

View file

@ -9,4 +9,14 @@ config RISCV_ERRATA_ALTERNATIVE
code patching is performed once in the boot stages. It means code patching is performed once in the boot stages. It means
that the overhead from this mechanism is just taken once. that the overhead from this mechanism is just taken once.
config ERRATA_SIFIVE
bool "SiFive errata"
depends on RISCV_ERRATA_ALTERNATIVE
help
All SiFive errata Kconfig depend on this Kconfig. Disabling
this Kconfig will disable all SiFive errata. Please say "Y"
here if your platform uses SiFive CPU cores.
Otherwise, please say "N" here to avoid unnecessary overhead.
endmenu endmenu

View file

@ -7,6 +7,7 @@ config SOC_SIFIVE
select CLK_SIFIVE select CLK_SIFIVE
select CLK_SIFIVE_PRCI select CLK_SIFIVE_PRCI
select SIFIVE_PLIC select SIFIVE_PLIC
select ERRATA_SIFIVE
help help
This enables support for SiFive SoC platform hardware. This enables support for SiFive SoC platform hardware.

View file

@ -1 +1,2 @@
obj-y += alternative.o obj-y += alternative.o
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/

View file

@ -42,6 +42,11 @@ static void __init init_alternative(void)
riscv_fill_cpu_mfr_info(); riscv_fill_cpu_mfr_info();
switch (cpu_mfr_info.vendor_id) { switch (cpu_mfr_info.vendor_id) {
#ifdef CONFIG_ERRATA_SIFIVE
case SIFIVE_VENDOR_ID:
vendor_patch_func = sifive_errata_patch_func;
break;
#endif
default: default:
vendor_patch_func = NULL; vendor_patch_func = NULL;
} }

View file

@ -0,0 +1 @@
obj-y += errata.o

View file

@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Sifive.
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/bug.h>
#include <asm/patch.h>
#include <asm/alternative.h>
#include <asm/vendorid_list.h>
#include <asm/errata_list.h>
struct errata_info_t {
char name[ERRATA_STRING_LENGTH_MAX];
bool (*check_func)(unsigned long arch_id, unsigned long impid);
};
static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
{
int idx;
u32 cpu_req_errata = 0;
for (idx = 0; idx < ERRATA_SIFIVE_NUMBER; idx++)
if (errata_list[idx].check_func(archid, impid))
cpu_req_errata |= (1U << idx);
return cpu_req_errata;
}
static void __init warn_miss_errata(u32 miss_errata)
{
int i;
pr_warn("----------------------------------------------------------------\n");
pr_warn("WARNING: Missing the following errata may cause potential issues\n");
for (i = 0; i < ERRATA_SIFIVE_NUMBER; i++)
if (miss_errata & 0x1 << i)
pr_warn("\tSiFive Errata[%d]:%s\n", i, errata_list[i].name);
pr_warn("Please enable the corresponding Kconfig to apply them\n");
pr_warn("----------------------------------------------------------------\n");
}
void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid)
{
struct alt_entry *alt;
u32 cpu_req_errata = sifive_errata_probe(archid, impid);
u32 cpu_apply_errata = 0;
u32 tmp;
for (alt = begin; alt < end; alt++) {
if (alt->vendor_id != SIFIVE_VENDOR_ID)
continue;
if (alt->errata_id >= ERRATA_SIFIVE_NUMBER) {
WARN(1, "This errata id:%d is not in kernel errata list", alt->errata_id);
continue;
}
tmp = (1U << alt->errata_id);
if (cpu_req_errata & tmp) {
patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
cpu_apply_errata |= tmp;
}
}
if (cpu_apply_errata != cpu_req_errata)
warn_miss_errata(cpu_req_errata - cpu_apply_errata);
}

View file

@ -32,5 +32,8 @@ struct errata_checkfunc_id {
bool (*func)(struct alt_entry *alt); bool (*func)(struct alt_entry *alt);
}; };
void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid);
#endif #endif
#endif #endif