Skip to content

Commit b9a603d

Browse files
Merge patch series "riscv: Separate vendor extensions from standard extensions"
Charlie Jenkins <[email protected]> says: All extensions, both standard and vendor, live in one struct "riscv_isa_ext". There is currently one vendor extension, xandespmu, but it is likely that more vendor extensions will be added to the kernel in the future. As more vendor extensions (and standard extensions) are added, riscv_isa_ext will become more bloated with a mix of vendor and standard extensions. This also allows each vendor to be conditionally enabled through Kconfig. * b4-shazam-merge: riscv: cpufeature: Extract common elements from extension checking riscv: Introduce vendor variants of extension helpers riscv: Add vendor extensions to /proc/cpuinfo riscv: Extend cpufeature.c to detect vendor extensions Link: https://lore.kernel.org/r/20240719-support_vendor_extensions-v3-0-0af7587bbec0@rivosinc.com Signed-off-by: Palmer Dabbelt <[email protected]>
2 parents 82b4616 + d4c8d79 commit b9a603d

File tree

16 files changed

+456
-93
lines changed

16 files changed

+456
-93
lines changed

arch/riscv/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,8 @@ config RISCV_EFFICIENT_UNALIGNED_ACCESS
820820

821821
endchoice
822822

823+
source "arch/riscv/Kconfig.vendor"
824+
823825
endmenu # "Platform type"
824826

825827
menu "Kernel features"

arch/riscv/Kconfig.vendor

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
menu "Vendor extensions"
2+
3+
config RISCV_ISA_VENDOR_EXT
4+
bool
5+
6+
menu "Andes"
7+
config RISCV_ISA_VENDOR_EXT_ANDES
8+
bool "Andes vendor extension support"
9+
select RISCV_ISA_VENDOR_EXT
10+
default y
11+
help
12+
Say N here if you want to disable all Andes vendor extension
13+
support. This will cause any Andes vendor extensions that are
14+
requested by hardware probing to be ignored.
15+
16+
If you don't know what to do here, say Y.
17+
endmenu
18+
19+
endmenu

arch/riscv/errata/andes/errata.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <asm/processor.h>
1818
#include <asm/sbi.h>
1919
#include <asm/vendorid_list.h>
20+
#include <asm/vendor_extensions.h>
2021

2122
#define ANDES_AX45MP_MARCHID 0x8000000000008a45UL
2223
#define ANDES_AX45MP_MIMPID 0x500UL
@@ -65,6 +66,8 @@ void __init_or_module andes_errata_patch_func(struct alt_entry *begin, struct al
6566
unsigned long archid, unsigned long impid,
6667
unsigned int stage)
6768
{
69+
BUILD_BUG_ON(ERRATA_ANDES_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
70+
6871
if (stage == RISCV_ALTERNATIVES_BOOT)
6972
errata_probe_iocp(stage, archid, impid);
7073

arch/riscv/errata/sifive/errata.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <asm/alternative.h>
1313
#include <asm/vendorid_list.h>
1414
#include <asm/errata_list.h>
15+
#include <asm/vendor_extensions.h>
1516

1617
struct errata_info_t {
1718
char name[32];
@@ -96,6 +97,8 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
9697
u32 cpu_apply_errata = 0;
9798
u32 tmp;
9899

100+
BUILD_BUG_ON(ERRATA_SIFIVE_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
101+
99102
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
100103
return;
101104

arch/riscv/errata/thead/errata.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <asm/io.h>
1919
#include <asm/patch.h>
2020
#include <asm/vendorid_list.h>
21+
#include <asm/vendor_extensions.h>
2122

2223
#define CSR_TH_SXSTATUS 0x5c0
2324
#define SXSTATUS_MAEE _AC(0x200000, UL)
@@ -166,6 +167,8 @@ void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
166167
u32 tmp;
167168
void *oldptr, *altptr;
168169

170+
BUILD_BUG_ON(ERRATA_THEAD_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
171+
169172
for (alt = begin; alt < end; alt++) {
170173
if (alt->vendor_id != THEAD_VENDOR_ID)
171174
continue;

arch/riscv/include/asm/cpufeature.h

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,31 @@ extern struct riscv_isainfo hart_isa[NR_CPUS];
3333

3434
void riscv_user_isa_enable(void);
3535

36+
#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \
37+
.name = #_name, \
38+
.property = #_name, \
39+
.id = _id, \
40+
.subset_ext_ids = _subset_exts, \
41+
.subset_ext_size = _subset_exts_size, \
42+
.validate = _validate \
43+
}
44+
45+
#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, NULL)
46+
47+
#define __RISCV_ISA_EXT_DATA_VALIDATE(_name, _id, _validate) \
48+
_RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, _validate)
49+
50+
/* Used to declare pure "lasso" extension (Zk for instance) */
51+
#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
52+
_RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
53+
ARRAY_SIZE(_bundled_exts), NULL)
54+
55+
/* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
56+
#define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
57+
_RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), NULL)
58+
#define __RISCV_ISA_EXT_SUPERSET_VALIDATE(_name, _id, _sub_exts, _validate) \
59+
_RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate)
60+
3661
#if defined(CONFIG_RISCV_MISALIGNED)
3762
bool check_unaligned_access_emulated_all_cpus(void);
3863
void unaligned_emulation_finish(void);
@@ -79,67 +104,77 @@ extern bool riscv_isa_fallback;
79104

80105
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
81106

107+
#define STANDARD_EXT 0
108+
82109
bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit);
83110
#define riscv_isa_extension_available(isa_bitmap, ext) \
84111
__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
85112

86-
static __always_inline bool
87-
riscv_has_extension_likely(const unsigned long ext)
113+
static __always_inline bool __riscv_has_extension_likely(const unsigned long vendor,
114+
const unsigned long ext)
88115
{
89-
compiletime_assert(ext < RISCV_ISA_EXT_MAX,
90-
"ext must be < RISCV_ISA_EXT_MAX");
91-
92-
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
93-
asm goto(
94-
ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1)
95-
:
96-
: [ext] "i" (ext)
97-
:
98-
: l_no);
99-
} else {
100-
if (!__riscv_isa_extension_available(NULL, ext))
101-
goto l_no;
102-
}
116+
asm goto(ALTERNATIVE("j %l[l_no]", "nop", %[vendor], %[ext], 1)
117+
:
118+
: [vendor] "i" (vendor), [ext] "i" (ext)
119+
:
120+
: l_no);
103121

104122
return true;
105123
l_no:
106124
return false;
107125
}
108126

109-
static __always_inline bool
110-
riscv_has_extension_unlikely(const unsigned long ext)
127+
static __always_inline bool __riscv_has_extension_unlikely(const unsigned long vendor,
128+
const unsigned long ext)
111129
{
112-
compiletime_assert(ext < RISCV_ISA_EXT_MAX,
113-
"ext must be < RISCV_ISA_EXT_MAX");
114-
115-
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
116-
asm goto(
117-
ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1)
118-
:
119-
: [ext] "i" (ext)
120-
:
121-
: l_yes);
122-
} else {
123-
if (__riscv_isa_extension_available(NULL, ext))
124-
goto l_yes;
125-
}
130+
asm goto(ALTERNATIVE("nop", "j %l[l_yes]", %[vendor], %[ext], 1)
131+
:
132+
: [vendor] "i" (vendor), [ext] "i" (ext)
133+
:
134+
: l_yes);
126135

127136
return false;
128137
l_yes:
129138
return true;
130139
}
131140

141+
static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
142+
{
143+
compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
144+
145+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
146+
return __riscv_has_extension_unlikely(STANDARD_EXT, ext);
147+
148+
return __riscv_isa_extension_available(NULL, ext);
149+
}
150+
151+
static __always_inline bool riscv_has_extension_likely(const unsigned long ext)
152+
{
153+
compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
154+
155+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
156+
return __riscv_has_extension_likely(STANDARD_EXT, ext);
157+
158+
return __riscv_isa_extension_available(NULL, ext);
159+
}
160+
132161
static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
133162
{
134-
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext))
163+
compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
164+
165+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
166+
__riscv_has_extension_likely(STANDARD_EXT, ext))
135167
return true;
136168

137169
return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
138170
}
139171

140172
static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext)
141173
{
142-
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext))
174+
compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
175+
176+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
177+
__riscv_has_extension_unlikely(STANDARD_EXT, ext))
143178
return true;
144179

145180
return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);

arch/riscv/include/asm/hwcap.h

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,18 @@
8080
#define RISCV_ISA_EXT_ZFA 71
8181
#define RISCV_ISA_EXT_ZTSO 72
8282
#define RISCV_ISA_EXT_ZACAS 73
83-
#define RISCV_ISA_EXT_XANDESPMU 74
84-
#define RISCV_ISA_EXT_ZVE32X 75
85-
#define RISCV_ISA_EXT_ZVE32F 76
86-
#define RISCV_ISA_EXT_ZVE64X 77
87-
#define RISCV_ISA_EXT_ZVE64F 78
88-
#define RISCV_ISA_EXT_ZVE64D 79
89-
#define RISCV_ISA_EXT_ZIMOP 80
90-
#define RISCV_ISA_EXT_ZCA 81
91-
#define RISCV_ISA_EXT_ZCB 82
92-
#define RISCV_ISA_EXT_ZCD 83
93-
#define RISCV_ISA_EXT_ZCF 84
94-
#define RISCV_ISA_EXT_ZCMOP 85
95-
#define RISCV_ISA_EXT_ZAWRS 86
83+
#define RISCV_ISA_EXT_ZVE32X 74
84+
#define RISCV_ISA_EXT_ZVE32F 75
85+
#define RISCV_ISA_EXT_ZVE64X 76
86+
#define RISCV_ISA_EXT_ZVE64F 77
87+
#define RISCV_ISA_EXT_ZVE64D 78
88+
#define RISCV_ISA_EXT_ZIMOP 79
89+
#define RISCV_ISA_EXT_ZCA 80
90+
#define RISCV_ISA_EXT_ZCB 81
91+
#define RISCV_ISA_EXT_ZCD 82
92+
#define RISCV_ISA_EXT_ZCF 83
93+
#define RISCV_ISA_EXT_ZCMOP 84
94+
#define RISCV_ISA_EXT_ZAWRS 85
9695

9796
#define RISCV_ISA_EXT_XLINUXENVCFG 127
9897

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright 2024 Rivos, Inc
4+
*/
5+
6+
#ifndef _ASM_VENDOR_EXTENSIONS_H
7+
#define _ASM_VENDOR_EXTENSIONS_H
8+
9+
#include <asm/cpufeature.h>
10+
11+
#include <linux/array_size.h>
12+
#include <linux/types.h>
13+
14+
/*
15+
* The extension keys of each vendor must be strictly less than this value.
16+
*/
17+
#define RISCV_ISA_VENDOR_EXT_MAX 32
18+
19+
struct riscv_isavendorinfo {
20+
DECLARE_BITMAP(isa, RISCV_ISA_VENDOR_EXT_MAX);
21+
};
22+
23+
struct riscv_isa_vendor_ext_data_list {
24+
bool is_initialized;
25+
const size_t ext_data_count;
26+
const struct riscv_isa_ext_data *ext_data;
27+
struct riscv_isavendorinfo per_hart_isa_bitmap[NR_CPUS];
28+
struct riscv_isavendorinfo all_harts_isa_bitmap;
29+
};
30+
31+
extern struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
32+
33+
extern const size_t riscv_isa_vendor_ext_list_size;
34+
35+
/*
36+
* The alternatives need some way of distinguishing between vendor extensions
37+
* and errata. Incrementing all of the vendor extension keys so they are at
38+
* least 0x8000 accomplishes that.
39+
*/
40+
#define RISCV_VENDOR_EXT_ALTERNATIVES_BASE 0x8000
41+
42+
#define VENDOR_EXT_ALL_CPUS -1
43+
44+
bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit);
45+
#define riscv_cpu_isa_vendor_extension_available(cpu, vendor, ext) \
46+
__riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext)
47+
#define riscv_isa_vendor_extension_available(vendor, ext) \
48+
__riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, \
49+
RISCV_ISA_VENDOR_EXT_##ext)
50+
51+
static __always_inline bool riscv_has_vendor_extension_likely(const unsigned long vendor,
52+
const unsigned long ext)
53+
{
54+
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
55+
return false;
56+
57+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
58+
return __riscv_has_extension_likely(vendor,
59+
ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
60+
61+
return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext);
62+
}
63+
64+
static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor,
65+
const unsigned long ext)
66+
{
67+
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
68+
return false;
69+
70+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
71+
return __riscv_has_extension_unlikely(vendor,
72+
ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
73+
74+
return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext);
75+
}
76+
77+
static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor,
78+
int cpu, const unsigned long ext)
79+
{
80+
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
81+
return false;
82+
83+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
84+
__riscv_has_extension_likely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
85+
return true;
86+
87+
return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
88+
}
89+
90+
static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor,
91+
int cpu,
92+
const unsigned long ext)
93+
{
94+
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
95+
return false;
96+
97+
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
98+
__riscv_has_extension_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
99+
return true;
100+
101+
return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
102+
}
103+
104+
#endif /* _ASM_VENDOR_EXTENSIONS_H */
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_RISCV_VENDOR_EXTENSIONS_ANDES_H
3+
#define _ASM_RISCV_VENDOR_EXTENSIONS_ANDES_H
4+
5+
#include <asm/vendor_extensions.h>
6+
7+
#include <linux/types.h>
8+
9+
#define RISCV_ISA_VENDOR_EXT_XANDESPMU 0
10+
11+
/*
12+
* Extension keys should be strictly less than max.
13+
* It is safe to increment this when necessary.
14+
*/
15+
#define RISCV_ISA_VENDOR_EXT_MAX_ANDES 32
16+
17+
extern struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_andes;
18+
19+
#endif

arch/riscv/kernel/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ obj-y += riscv_ksyms.o
5858
obj-y += stacktrace.o
5959
obj-y += cacheinfo.o
6060
obj-y += patch.o
61+
obj-y += vendor_extensions.o
62+
obj-y += vendor_extensions/
6163
obj-y += probes/
6264
obj-y += tests/
6365
obj-$(CONFIG_MMU) += vdso.o vdso/

0 commit comments

Comments
 (0)