Skip to content

Commit 1a0e5db

Browse files
VincentZWCpalmer-dabbelt
authored andcommitted
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>
1 parent 6f4eea9 commit 1a0e5db

File tree

7 files changed

+89
-0
lines changed

7 files changed

+89
-0
lines changed

arch/riscv/Kconfig.erratas

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,14 @@ config RISCV_ERRATA_ALTERNATIVE
99
code patching is performed once in the boot stages. It means
1010
that the overhead from this mechanism is just taken once.
1111

12+
config ERRATA_SIFIVE
13+
bool "SiFive errata"
14+
depends on RISCV_ERRATA_ALTERNATIVE
15+
help
16+
All SiFive errata Kconfig depend on this Kconfig. Disabling
17+
this Kconfig will disable all SiFive errata. Please say "Y"
18+
here if your platform uses SiFive CPU cores.
19+
20+
Otherwise, please say "N" here to avoid unnecessary overhead.
21+
1222
endmenu

arch/riscv/Kconfig.socs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ config SOC_SIFIVE
77
select CLK_SIFIVE
88
select CLK_SIFIVE_PRCI
99
select SIFIVE_PLIC
10+
select ERRATA_SIFIVE
1011
help
1112
This enables support for SiFive SoC platform hardware.
1213

arch/riscv/errata/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
obj-y += alternative.o
2+
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/

arch/riscv/errata/alternative.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ static void __init init_alternative(void)
4242
riscv_fill_cpu_mfr_info();
4343

4444
switch (cpu_mfr_info.vendor_id) {
45+
#ifdef CONFIG_ERRATA_SIFIVE
46+
case SIFIVE_VENDOR_ID:
47+
vendor_patch_func = sifive_errata_patch_func;
48+
break;
49+
#endif
4550
default:
4651
vendor_patch_func = NULL;
4752
}

arch/riscv/errata/sifive/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-y += errata.o

arch/riscv/errata/sifive/errata.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2021 Sifive.
4+
*/
5+
6+
#include <linux/kernel.h>
7+
#include <linux/string.h>
8+
#include <linux/bug.h>
9+
#include <asm/patch.h>
10+
#include <asm/alternative.h>
11+
#include <asm/vendorid_list.h>
12+
#include <asm/errata_list.h>
13+
14+
struct errata_info_t {
15+
char name[ERRATA_STRING_LENGTH_MAX];
16+
bool (*check_func)(unsigned long arch_id, unsigned long impid);
17+
};
18+
19+
static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
20+
{
21+
int idx;
22+
u32 cpu_req_errata = 0;
23+
24+
for (idx = 0; idx < ERRATA_SIFIVE_NUMBER; idx++)
25+
if (errata_list[idx].check_func(archid, impid))
26+
cpu_req_errata |= (1U << idx);
27+
28+
return cpu_req_errata;
29+
}
30+
31+
static void __init warn_miss_errata(u32 miss_errata)
32+
{
33+
int i;
34+
35+
pr_warn("----------------------------------------------------------------\n");
36+
pr_warn("WARNING: Missing the following errata may cause potential issues\n");
37+
for (i = 0; i < ERRATA_SIFIVE_NUMBER; i++)
38+
if (miss_errata & 0x1 << i)
39+
pr_warn("\tSiFive Errata[%d]:%s\n", i, errata_list[i].name);
40+
pr_warn("Please enable the corresponding Kconfig to apply them\n");
41+
pr_warn("----------------------------------------------------------------\n");
42+
}
43+
44+
void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
45+
unsigned long archid, unsigned long impid)
46+
{
47+
struct alt_entry *alt;
48+
u32 cpu_req_errata = sifive_errata_probe(archid, impid);
49+
u32 cpu_apply_errata = 0;
50+
u32 tmp;
51+
52+
for (alt = begin; alt < end; alt++) {
53+
if (alt->vendor_id != SIFIVE_VENDOR_ID)
54+
continue;
55+
if (alt->errata_id >= ERRATA_SIFIVE_NUMBER) {
56+
WARN(1, "This errata id:%d is not in kernel errata list", alt->errata_id);
57+
continue;
58+
}
59+
60+
tmp = (1U << alt->errata_id);
61+
if (cpu_req_errata & tmp) {
62+
patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
63+
cpu_apply_errata |= tmp;
64+
}
65+
}
66+
if (cpu_apply_errata != cpu_req_errata)
67+
warn_miss_errata(cpu_req_errata - cpu_apply_errata);
68+
}

arch/riscv/include/asm/alternative.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,8 @@ struct errata_checkfunc_id {
3232
bool (*func)(struct alt_entry *alt);
3333
};
3434

35+
void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
36+
unsigned long archid, unsigned long impid);
37+
3538
#endif
3639
#endif

0 commit comments

Comments
 (0)