Skip to content

Commit 42b8944

Browse files
Merge patch series "ISA string parser cleanups"
Conor Dooley <[email protected]> says: From: Conor Dooley <[email protected]> Here are some bits that were discussed with Drew on the "should we allow caps" threads that I have now created patches for: - splitting of riscv_of_processor_hartid() into two distinct functions, one for use purely during early boot, prior to the establishment of the possible-cpus mask & another to fit the other current use-cases - that then allows us to then completely skip some validation of the hartid in the parser - the biggest diff in the series is a rework of the comments in the parser, as I have mostly found the existing (sparse) ones to not be all that helpful whenever I have to go back and look at it - from writing the comments, I found a conditional doing a bit of a dance that I found counter-intuitive, so I've had a go at making that match what I would expect a little better - `i` implies 4 other extensions, so add them as extensions and set them for the craic. Sure why not like... * b4-shazam-merge: RISC-V: always report presence of extensions formerly part of the base ISA dt-bindings: riscv: explicitly mention assumption of Zicntr & Zihpm support RISC-V: remove decrement/increment dance in ISA string parser RISC-V: rework comments in ISA string parser RISC-V: validate riscv,isa at boot, not during ISA string parsing RISC-V: split early & late of_node to hartid mapping RISC-V: simplify register width check in ISA string parsing Link: https://lore.kernel.org/r/20230607-audacity-overhaul-82bb867a825f@spud Signed-off-by: Palmer Dabbelt <[email protected]>
2 parents ee95b88 + 07edc32 commit 42b8944

File tree

6 files changed

+123
-30
lines changed

6 files changed

+123
-30
lines changed

Documentation/devicetree/bindings/riscv/cpus.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ properties:
8989
Due to revisions of the ISA specification, some deviations
9090
have arisen over time.
9191
Notably, riscv,isa was defined prior to the creation of the
92-
Zicsr and Zifencei extensions and thus "i" implies
93-
"zicsr_zifencei".
92+
Zicntr, Zicsr, Zifencei and Zihpm extensions and thus "i"
93+
implies "zicntr_zicsr_zifencei_zihpm".
9494

9595
While the isa strings in ISA specification are case
9696
insensitive, letters in the riscv,isa string must be all

arch/riscv/include/asm/hwcap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@
4949
#define RISCV_ISA_EXT_SSAIA 36
5050
#define RISCV_ISA_EXT_ZBA 37
5151
#define RISCV_ISA_EXT_ZBS 38
52+
#define RISCV_ISA_EXT_ZICNTR 39
53+
#define RISCV_ISA_EXT_ZICSR 40
54+
#define RISCV_ISA_EXT_ZIFENCEI 41
55+
#define RISCV_ISA_EXT_ZIHPM 42
5256

5357
#define RISCV_ISA_EXT_MAX 64
5458
#define RISCV_ISA_EXT_NAME_LEN_MAX 32

arch/riscv/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static inline void wait_for_interrupt(void)
7878

7979
struct device_node;
8080
int riscv_of_processor_hartid(struct device_node *node, unsigned long *hartid);
81+
int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hartid);
8182
int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid);
8283

8384
extern void riscv_fill_hwcap(void);

arch/riscv/kernel/cpu.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
* isn't an enabled and valid RISC-V hart node.
2323
*/
2424
int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart)
25+
{
26+
int cpu;
27+
28+
*hart = (unsigned long)of_get_cpu_hwid(node, 0);
29+
if (*hart == ~0UL) {
30+
pr_warn("Found CPU without hart ID\n");
31+
return -ENODEV;
32+
}
33+
34+
cpu = riscv_hartid_to_cpuid(*hart);
35+
if (cpu < 0)
36+
return cpu;
37+
38+
if (!cpu_possible(cpu))
39+
return -ENODEV;
40+
41+
return 0;
42+
}
43+
44+
int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hart)
2545
{
2646
const char *isa;
2747

@@ -30,7 +50,7 @@ int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart)
3050
return -ENODEV;
3151
}
3252

33-
*hart = (unsigned long) of_get_cpu_hwid(node, 0);
53+
*hart = (unsigned long)of_get_cpu_hwid(node, 0);
3454
if (*hart == ~0UL) {
3555
pr_warn("Found CPU without hart ID\n");
3656
return -ENODEV;
@@ -45,10 +65,12 @@ int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart)
4565
pr_warn("CPU with hartid=%lu has no \"riscv,isa\" property\n", *hart);
4666
return -ENODEV;
4767
}
48-
if (tolower(isa[0]) != 'r' || tolower(isa[1]) != 'v') {
49-
pr_warn("CPU with hartid=%lu has an invalid ISA of \"%s\"\n", *hart, isa);
68+
69+
if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32ima", 7))
70+
return -ENODEV;
71+
72+
if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64ima", 7))
5073
return -ENODEV;
51-
}
5274

5375
return 0;
5476
}
@@ -186,7 +208,11 @@ arch_initcall(riscv_cpuinfo_init);
186208
static struct riscv_isa_ext_data isa_ext_arr[] = {
187209
__RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
188210
__RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ),
211+
__RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR),
212+
__RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR),
213+
__RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI),
189214
__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
215+
__RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM),
190216
__RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA),
191217
__RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
192218
__RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS),

arch/riscv/kernel/cpufeature.c

Lines changed: 85 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ void __init riscv_fill_hwcap(void)
131131
for_each_possible_cpu(cpu) {
132132
struct riscv_isainfo *isainfo = &hart_isa[cpu];
133133
unsigned long this_hwcap = 0;
134-
const char *temp;
135134

136135
if (acpi_disabled) {
137136
node = of_cpu_device_node_get(cpu);
@@ -154,22 +153,22 @@ void __init riscv_fill_hwcap(void)
154153
}
155154
}
156155

157-
temp = isa;
158-
if (IS_ENABLED(CONFIG_32BIT) && !strncasecmp(isa, "rv32", 4))
159-
isa += 4;
160-
else if (IS_ENABLED(CONFIG_64BIT) && !strncasecmp(isa, "rv64", 4))
161-
isa += 4;
162-
/* The riscv,isa DT property must start with rv64 or rv32 */
163-
if (temp == isa)
164-
continue;
165-
for (; *isa; ++isa) {
156+
/*
157+
* For all possible cpus, we have already validated in
158+
* the boot process that they at least contain "rv" and
159+
* whichever of "32"/"64" this kernel supports, and so this
160+
* section can be skipped.
161+
*/
162+
isa += 4;
163+
164+
while (*isa) {
166165
const char *ext = isa++;
167166
const char *ext_end = isa;
168167
bool ext_long = false, ext_err = false;
169168

170169
switch (*ext) {
171170
case 's':
172-
/**
171+
/*
173172
* Workaround for invalid single-letter 's' & 'u'(QEMU).
174173
* No need to set the bit in riscv_isa as 's' & 'u' are
175174
* not valid ISA extensions. It works until multi-letter
@@ -186,55 +185,101 @@ void __init riscv_fill_hwcap(void)
186185
case 'X':
187186
case 'z':
188187
case 'Z':
188+
/*
189+
* Before attempting to parse the extension itself, we find its end.
190+
* As multi-letter extensions must be split from other multi-letter
191+
* extensions with an "_", the end of a multi-letter extension will
192+
* either be the null character or the "_" at the start of the next
193+
* multi-letter extension.
194+
*
195+
* Next, as the extensions version is currently ignored, we
196+
* eliminate that portion. This is done by parsing backwards from
197+
* the end of the extension, removing any numbers. This may be a
198+
* major or minor number however, so the process is repeated if a
199+
* minor number was found.
200+
*
201+
* ext_end is intended to represent the first character *after* the
202+
* name portion of an extension, but will be decremented to the last
203+
* character itself while eliminating the extensions version number.
204+
* A simple re-increment solves this problem.
205+
*/
189206
ext_long = true;
190-
/* Multi-letter extension must be delimited */
191207
for (; *isa && *isa != '_'; ++isa)
192208
if (unlikely(!isalnum(*isa)))
193209
ext_err = true;
194-
/* Parse backwards */
210+
195211
ext_end = isa;
196212
if (unlikely(ext_err))
197213
break;
214+
198215
if (!isdigit(ext_end[-1]))
199216
break;
200-
/* Skip the minor version */
217+
201218
while (isdigit(*--ext_end))
202219
;
203-
if (tolower(ext_end[0]) != 'p'
204-
|| !isdigit(ext_end[-1])) {
205-
/* Advance it to offset the pre-decrement */
220+
221+
if (tolower(ext_end[0]) != 'p' || !isdigit(ext_end[-1])) {
206222
++ext_end;
207223
break;
208224
}
209-
/* Skip the major version */
225+
210226
while (isdigit(*--ext_end))
211227
;
228+
212229
++ext_end;
213230
break;
214231
default:
232+
/*
233+
* Things are a little easier for single-letter extensions, as they
234+
* are parsed forwards.
235+
*
236+
* After checking that our starting position is valid, we need to
237+
* ensure that, when isa was incremented at the start of the loop,
238+
* that it arrived at the start of the next extension.
239+
*
240+
* If we are already on a non-digit, there is nothing to do. Either
241+
* we have a multi-letter extension's _, or the start of an
242+
* extension.
243+
*
244+
* Otherwise we have found the current extension's major version
245+
* number. Parse past it, and a subsequent p/minor version number
246+
* if present. The `p` extension must not appear immediately after
247+
* a number, so there is no fear of missing it.
248+
*
249+
*/
215250
if (unlikely(!isalpha(*ext))) {
216251
ext_err = true;
217252
break;
218253
}
219-
/* Find next extension */
254+
220255
if (!isdigit(*isa))
221256
break;
222-
/* Skip the minor version */
257+
223258
while (isdigit(*++isa))
224259
;
260+
225261
if (tolower(*isa) != 'p')
226262
break;
263+
227264
if (!isdigit(*++isa)) {
228265
--isa;
229266
break;
230267
}
231-
/* Skip the major version */
268+
232269
while (isdigit(*++isa))
233270
;
271+
234272
break;
235273
}
236-
if (*isa != '_')
237-
--isa;
274+
275+
/*
276+
* The parser expects that at the start of an iteration isa points to the
277+
* first character of the next extension. As we stop parsing an extension
278+
* on meeting a non-alphanumeric character, an extra increment is needed
279+
* where the succeeding extension is a multi-letter prefixed with an "_".
280+
*/
281+
if (*isa == '_')
282+
++isa;
238283

239284
#define SET_ISA_EXT_MAP(name, bit) \
240285
do { \
@@ -272,6 +317,23 @@ void __init riscv_fill_hwcap(void)
272317
#undef SET_ISA_EXT_MAP
273318
}
274319

320+
/*
321+
* Linux requires the following extensions, so we may as well
322+
* always set them.
323+
*/
324+
set_bit(RISCV_ISA_EXT_ZICSR, isainfo->isa);
325+
set_bit(RISCV_ISA_EXT_ZIFENCEI, isainfo->isa);
326+
327+
/*
328+
* These ones were as they were part of the base ISA when the
329+
* port & dt-bindings were upstreamed, and so can be set
330+
* unconditionally where `i` is in riscv,isa on DT systems.
331+
*/
332+
if (acpi_disabled) {
333+
set_bit(RISCV_ISA_EXT_ZICNTR, isainfo->isa);
334+
set_bit(RISCV_ISA_EXT_ZIHPM, isainfo->isa);
335+
}
336+
275337
/*
276338
* All "okay" hart should have same isa. Set HWCAP based on
277339
* common capabilities of every "okay" hart, in case they don't

arch/riscv/kernel/smpboot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ static void __init of_parse_and_init_cpus(void)
150150
cpu_set_ops(0);
151151

152152
for_each_of_cpu_node(dn) {
153-
rc = riscv_of_processor_hartid(dn, &hart);
153+
rc = riscv_early_of_processor_hartid(dn, &hart);
154154
if (rc < 0)
155155
continue;
156156

0 commit comments

Comments
 (0)