Skip to content

Commit 9daca9a

Browse files
Merge patch series "riscv: improve boot time isa extensions handling"
Jisheng Zhang <jszhang@kernel.org> says: Generally, riscv ISA extensions are fixed for any specific hardware platform, so a hart's features won't change after booting, this chacteristic makes it straightforward to use a static branch to check a specific ISA extension is supported or not to optimize performance. However, some ISA extensions such as SVPBMT and ZICBOM are handled via. the alternative sequences. Basically, for ease of maintenance, we prefer to use static branches in C code, but recently, Samuel found that the static branch usage in cpu_relax() breaks building with CONFIG_CC_OPTIMIZE_FOR_SIZE[1]. As Samuel pointed out, "Having a static branch in cpu_relax() is problematic because that function is widely inlined, including in some quite complex functions like in the VDSO. A quick measurement shows this static branch is responsible by itself for around 40% of the jump table." Samuel's findings pointed out one of a few downsides of static branches usage in C code to handle ISA extensions detected at boot time: static branch's metadata in the __jump_table section, which is not discarded after ISA extensions are finalized, wastes some space. I want to try to solve the issue for all possible dynamic handling of ISA extensions at boot time. Inspired by Mark[2], this patch introduces riscv_has_extension_*() helpers, which work like static branches but are patched using alternatives, thus the metadata can be freed after patching. [1]https://lore.kernel.org/linux-riscv/20220922060958.44203-1-samuel@sholland.org/ [2]https://lore.kernel.org/linux-arm-kernel/20220912162210.3626215-8-mark.rutland@arm.com/ [3]https://lore.kernel.org/linux-riscv/20221130225614.1594256-1-heiko@sntech.de/ * b4-shazam-merge: riscv: remove riscv_isa_ext_keys[] array and related usage riscv: KVM: Switch has_svinval() to riscv_has_extension_unlikely() riscv: cpu_relax: switch to riscv_has_extension_likely() riscv: alternative: patch alternatives in the vDSO riscv: switch to relative alternative entries riscv: module: Add ADD16 and SUB16 rela types riscv: module: move find_section to module.h riscv: fpu: switch has_fpu() to riscv_has_extension_likely() riscv: introduce riscv_has_extension_[un]likely() riscv: cpufeature: extend riscv_cpufeature_patch_func to all ISA extensions riscv: hwcap: make ISA extension ids can be used in asm riscv: cpufeature: detect RISCV_ALTERNATIVES_EARLY_BOOT earlier riscv: move riscv_noncoherent_supported() out of ZICBOM probe Link: https://lore.kernel.org/r/20230128172856.3814-1-jszhang@kernel.org Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
2 parents 75ab93a + 0396659 commit 9daca9a

17 files changed

Lines changed: 179 additions & 178 deletions

File tree

arch/riscv/errata/sifive/errata.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
107107

108108
tmp = (1U << alt->errata_id);
109109
if (cpu_req_errata & tmp) {
110-
patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
110+
patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt),
111+
alt->alt_len);
111112
cpu_apply_errata |= tmp;
112113
}
113114
}

arch/riscv/errata/thead/errata.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
8787
struct alt_entry *alt;
8888
u32 cpu_req_errata = thead_errata_probe(stage, archid, impid);
8989
u32 tmp;
90+
void *oldptr, *altptr;
9091

9192
for (alt = begin; alt < end; alt++) {
9293
if (alt->vendor_id != THEAD_VENDOR_ID)
@@ -96,12 +97,16 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
9697

9798
tmp = (1U << alt->errata_id);
9899
if (cpu_req_errata & tmp) {
100+
oldptr = ALT_OLD_PTR(alt);
101+
altptr = ALT_ALT_PTR(alt);
102+
99103
/* On vm-alternatives, the mmu isn't running yet */
100104
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
101-
memcpy((void *)__pa_symbol(alt->old_ptr),
102-
(void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
105+
memcpy((void *)__pa_symbol(oldptr),
106+
(void *)__pa_symbol(altptr),
107+
alt->alt_len);
103108
else
104-
patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
109+
patch_text_nosync(oldptr, altptr, alt->alt_len);
105110
}
106111
}
107112

arch/riscv/include/asm/alternative-macros.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
#ifdef __ASSEMBLY__
88

99
.macro ALT_ENTRY oldptr newptr vendor_id errata_id new_len
10-
RISCV_PTR \oldptr
11-
RISCV_PTR \newptr
12-
REG_ASM \vendor_id
13-
REG_ASM \new_len
14-
.word \errata_id
10+
.4byte \oldptr - .
11+
.4byte \newptr - .
12+
.2byte \vendor_id
13+
.2byte \new_len
14+
.4byte \errata_id
1515
.endm
1616

1717
.macro ALT_NEW_CONTENT vendor_id, errata_id, enable = 1, new_c : vararg
@@ -59,11 +59,11 @@
5959
#include <linux/stringify.h>
6060

6161
#define ALT_ENTRY(oldptr, newptr, vendor_id, errata_id, newlen) \
62-
RISCV_PTR " " oldptr "\n" \
63-
RISCV_PTR " " newptr "\n" \
64-
REG_ASM " " vendor_id "\n" \
65-
REG_ASM " " newlen "\n" \
66-
".word " errata_id "\n"
62+
".4byte ((" oldptr ") - .) \n" \
63+
".4byte ((" newptr ") - .) \n" \
64+
".2byte " vendor_id "\n" \
65+
".2byte " newlen "\n" \
66+
".4byte " errata_id "\n"
6767

6868
#define ALT_NEW_CONTENT(vendor_id, errata_id, enable, new_c) \
6969
".if " __stringify(enable) " == 1\n" \

arch/riscv/include/asm/alternative.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
#define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */
2424
#define RISCV_ALTERNATIVES_EARLY_BOOT 2 /* alternatives applied before mmu start */
2525

26+
/* add the relative offset to the address of the offset to get the absolute address */
27+
#define __ALT_PTR(a, f) ((void *)&(a)->f + (a)->f)
28+
#define ALT_OLD_PTR(a) __ALT_PTR(a, old_offset)
29+
#define ALT_ALT_PTR(a) __ALT_PTR(a, alt_offset)
30+
2631
void __init apply_boot_alternatives(void);
2732
void __init apply_early_boot_alternatives(void);
2833
void apply_module_alternatives(void *start, size_t length);
@@ -31,12 +36,12 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len,
3136
int patch_offset);
3237

3338
struct alt_entry {
34-
void *old_ptr; /* address of original instruciton or data */
35-
void *alt_ptr; /* address of replacement instruction or data */
36-
unsigned long vendor_id; /* cpu vendor id */
37-
unsigned long alt_len; /* The replacement size */
38-
unsigned int errata_id; /* The errata id */
39-
} __packed;
39+
s32 old_offset; /* offset relative to original instruction or data */
40+
s32 alt_offset; /* offset relative to replacement instruction or data */
41+
u16 vendor_id; /* cpu vendor id */
42+
u16 alt_len; /* The replacement size */
43+
u32 errata_id; /* The errata id */
44+
};
4045

4146
struct errata_checkfunc_id {
4247
unsigned long vendor_id;

arch/riscv/include/asm/errata_list.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <asm/alternative.h>
99
#include <asm/csr.h>
10+
#include <asm/hwcap.h>
1011
#include <asm/vendorid_list.h>
1112

1213
#ifdef CONFIG_ERRATA_SIFIVE
@@ -56,7 +57,7 @@ asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID, \
5657
#define ALT_SVPBMT(_val, prot) \
5758
asm(ALTERNATIVE_2("li %0, 0\t\nnop", \
5859
"li %0, %1\t\nslli %0,%0,%3", 0, \
59-
CPUFEATURE_SVPBMT, CONFIG_RISCV_ISA_SVPBMT, \
60+
RISCV_ISA_EXT_SVPBMT, CONFIG_RISCV_ISA_SVPBMT, \
6061
"li %0, %2\t\nslli %0,%0,%4", THEAD_VENDOR_ID, \
6162
ERRATA_THEAD_PBMT, CONFIG_ERRATA_THEAD_PBMT) \
6263
: "=r"(_val) \
@@ -130,7 +131,7 @@ asm volatile(ALTERNATIVE_2( \
130131
"add a0, a0, %0\n\t" \
131132
"2:\n\t" \
132133
"bltu a0, %2, 3b\n\t" \
133-
"nop", 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \
134+
"nop", 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \
134135
"mv a0, %1\n\t" \
135136
"j 2f\n\t" \
136137
"3:\n\t" \

arch/riscv/include/asm/hwcap.h

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,11 @@
88
#ifndef _ASM_RISCV_HWCAP_H
99
#define _ASM_RISCV_HWCAP_H
1010

11+
#include <asm/alternative-macros.h>
1112
#include <asm/errno.h>
1213
#include <linux/bits.h>
1314
#include <uapi/asm/hwcap.h>
1415

15-
#ifndef __ASSEMBLY__
16-
#include <linux/jump_label.h>
17-
/*
18-
* This yields a mask that user programs can use to figure out what
19-
* instruction set this cpu supports.
20-
*/
21-
#define ELF_HWCAP (elf_hwcap)
22-
23-
enum {
24-
CAP_HWCAP = 1,
25-
};
26-
27-
extern unsigned long elf_hwcap;
28-
2916
#define RISCV_ISA_EXT_a ('a' - 'a')
3017
#define RISCV_ISA_EXT_c ('c' - 'a')
3118
#define RISCV_ISA_EXT_d ('d' - 'a')
@@ -46,61 +33,78 @@ extern unsigned long elf_hwcap;
4633
#define RISCV_ISA_EXT_BASE 26
4734

4835
/*
49-
* This enum represent the logical ID for each multi-letter RISC-V ISA extension.
36+
* These macros represent the logical ID for each multi-letter RISC-V ISA extension.
5037
* The logical ID should start from RISCV_ISA_EXT_BASE and must not exceed
5138
* RISCV_ISA_EXT_MAX. 0-25 range is reserved for single letter
5239
* extensions while all the multi-letter extensions should define the next
5340
* available logical extension id.
5441
* Entries are sorted alphabetically.
5542
*/
56-
enum riscv_isa_ext_id {
57-
RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE,
58-
RISCV_ISA_EXT_SSTC,
59-
RISCV_ISA_EXT_SVINVAL,
60-
RISCV_ISA_EXT_SVPBMT,
61-
RISCV_ISA_EXT_ZBB,
62-
RISCV_ISA_EXT_ZICBOM,
63-
RISCV_ISA_EXT_ZIHINTPAUSE,
64-
RISCV_ISA_EXT_ID_MAX
65-
};
66-
static_assert(RISCV_ISA_EXT_ID_MAX <= RISCV_ISA_EXT_MAX);
43+
#define RISCV_ISA_EXT_SSCOFPMF 26
44+
#define RISCV_ISA_EXT_SSTC 27
45+
#define RISCV_ISA_EXT_SVINVAL 28
46+
#define RISCV_ISA_EXT_SVPBMT 29
47+
#define RISCV_ISA_EXT_ZBB 30
48+
#define RISCV_ISA_EXT_ZICBOM 31
49+
#define RISCV_ISA_EXT_ZIHINTPAUSE 32
50+
51+
#ifndef __ASSEMBLY__
52+
53+
#include <linux/jump_label.h>
6754

6855
/*
69-
* This enum represents the logical ID for each RISC-V ISA extension static
70-
* keys. We can use static key to optimize code path if some ISA extensions
71-
* are available.
72-
* Entries are sorted alphabetically.
56+
* This yields a mask that user programs can use to figure out what
57+
* instruction set this cpu supports.
7358
*/
74-
enum riscv_isa_ext_key {
75-
RISCV_ISA_EXT_KEY_FPU, /* For 'F' and 'D' */
76-
RISCV_ISA_EXT_KEY_SVINVAL,
77-
RISCV_ISA_EXT_KEY_ZIHINTPAUSE,
78-
RISCV_ISA_EXT_KEY_MAX,
59+
#define ELF_HWCAP (elf_hwcap)
60+
61+
enum {
62+
CAP_HWCAP = 1,
7963
};
8064

65+
extern unsigned long elf_hwcap;
66+
8167
struct riscv_isa_ext_data {
8268
/* Name of the extension displayed to userspace via /proc/cpuinfo */
8369
char uprop[RISCV_ISA_EXT_NAME_LEN_MAX];
8470
/* The logical ISA extension ID */
8571
unsigned int isa_ext_id;
8672
};
8773

88-
extern struct static_key_false riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_MAX];
74+
static __always_inline bool
75+
riscv_has_extension_likely(const unsigned long ext)
76+
{
77+
compiletime_assert(ext < RISCV_ISA_EXT_MAX,
78+
"ext must be < RISCV_ISA_EXT_MAX");
79+
80+
asm_volatile_goto(
81+
ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1)
82+
:
83+
: [ext] "i" (ext)
84+
:
85+
: l_no);
86+
87+
return true;
88+
l_no:
89+
return false;
90+
}
8991

90-
static __always_inline int riscv_isa_ext2key(int num)
92+
static __always_inline bool
93+
riscv_has_extension_unlikely(const unsigned long ext)
9194
{
92-
switch (num) {
93-
case RISCV_ISA_EXT_f:
94-
return RISCV_ISA_EXT_KEY_FPU;
95-
case RISCV_ISA_EXT_d:
96-
return RISCV_ISA_EXT_KEY_FPU;
97-
case RISCV_ISA_EXT_SVINVAL:
98-
return RISCV_ISA_EXT_KEY_SVINVAL;
99-
case RISCV_ISA_EXT_ZIHINTPAUSE:
100-
return RISCV_ISA_EXT_KEY_ZIHINTPAUSE;
101-
default:
102-
return -EINVAL;
103-
}
95+
compiletime_assert(ext < RISCV_ISA_EXT_MAX,
96+
"ext must be < RISCV_ISA_EXT_MAX");
97+
98+
asm_volatile_goto(
99+
ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1)
100+
:
101+
: [ext] "i" (ext)
102+
:
103+
: l_yes);
104+
105+
return false;
106+
l_yes:
107+
return true;
104108
}
105109

106110
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);

arch/riscv/include/asm/module.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define _ASM_RISCV_MODULE_H
66

77
#include <asm-generic/module.h>
8+
#include <linux/elf.h>
89

910
struct module;
1011
unsigned long module_emit_got_entry(struct module *mod, unsigned long val);
@@ -111,4 +112,19 @@ static inline struct plt_entry *get_plt_entry(unsigned long val,
111112

112113
#endif /* CONFIG_MODULE_SECTIONS */
113114

115+
static inline const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
116+
const Elf_Shdr *sechdrs,
117+
const char *name)
118+
{
119+
const Elf_Shdr *s, *se;
120+
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
121+
122+
for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
123+
if (strcmp(name, secstrs + s->sh_name) == 0)
124+
return s;
125+
}
126+
127+
return NULL;
128+
}
129+
114130
#endif /* _ASM_RISCV_MODULE_H */

arch/riscv/include/asm/switch_to.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ static inline void __switch_to_aux(struct task_struct *prev,
5959

6060
static __always_inline bool has_fpu(void)
6161
{
62-
return static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_FPU]);
62+
return riscv_has_extension_likely(RISCV_ISA_EXT_f) ||
63+
riscv_has_extension_likely(RISCV_ISA_EXT_d);
6364
}
6465
#else
6566
static __always_inline bool has_fpu(void) { return false; }

arch/riscv/include/asm/vdso.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@
2828
#define COMPAT_VDSO_SYMBOL(base, name) \
2929
(void __user *)((unsigned long)(base) + compat__vdso_##name##_offset)
3030

31+
extern char compat_vdso_start[], compat_vdso_end[];
32+
3133
#endif /* CONFIG_COMPAT */
3234

35+
extern char vdso_start[], vdso_end[];
36+
3337
#endif /* !__ASSEMBLY__ */
3438

3539
#endif /* CONFIG_MMU */

arch/riscv/include/asm/vdso/processor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
static inline void cpu_relax(void)
1212
{
13-
if (!static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_ZIHINTPAUSE])) {
13+
if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZIHINTPAUSE)) {
1414
#ifdef __riscv_muldiv
1515
int dummy;
1616
/* In lieu of a halt instruction, induce a long-latency stall. */

0 commit comments

Comments
 (0)