Skip to content

Commit

Permalink
riscv: sifive: Add SiFive alternative ports
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
VincentZWC authored and palmer-dabbelt committed Apr 26, 2021
1 parent 6f4eea9 commit 1a0e5db
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 0 deletions.
10 changes: 10 additions & 0 deletions arch/riscv/Kconfig.erratas
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@ config RISCV_ERRATA_ALTERNATIVE
code patching is performed once in the boot stages. It means
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
1 change: 1 addition & 0 deletions arch/riscv/Kconfig.socs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ config SOC_SIFIVE
select CLK_SIFIVE
select CLK_SIFIVE_PRCI
select SIFIVE_PLIC
select ERRATA_SIFIVE
help
This enables support for SiFive SoC platform hardware.

Expand Down
1 change: 1 addition & 0 deletions arch/riscv/errata/Makefile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
obj-y += alternative.o
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
5 changes: 5 additions & 0 deletions arch/riscv/errata/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ static void __init init_alternative(void)
riscv_fill_cpu_mfr_info();

switch (cpu_mfr_info.vendor_id) {
#ifdef CONFIG_ERRATA_SIFIVE
case SIFIVE_VENDOR_ID:
vendor_patch_func = sifive_errata_patch_func;
break;
#endif
default:
vendor_patch_func = NULL;
}
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/errata/sifive/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
obj-y += errata.o
68 changes: 68 additions & 0 deletions arch/riscv/errata/sifive/errata.c
Original file line number Diff line number Diff line change
@@ -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);
}
3 changes: 3 additions & 0 deletions arch/riscv/include/asm/alternative.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,8 @@ struct errata_checkfunc_id {
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

0 comments on commit 1a0e5db

Please sign in to comment.