From 0b144c8189895038cd624035b0cee24869de54f7 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 15 May 2023 11:19:22 +0530 Subject: RISC-V: cpu: Enable cpuinfo for ACPI systems On ACPI based platforms, few details like ISA need to be read from the ACPI table. Enable cpuinfo on ACPI based systems. ACPI has nothing similar to DT compatible property for each CPU. Hence, cpuinfo will not print "uarch". Signed-off-by: Sunil V L Acked-by: Rafael J. Wysocki Reviewed-by: Andrew Jones Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230515054928.2079268-16-sunilvl@ventanamicro.com Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/cpu.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'arch/riscv/kernel/cpu.c') diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index c96aa56cf1c7..5de6fb703cc2 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -3,10 +3,12 @@ * Copyright (C) 2012 Regents of the University of California */ +#include #include #include #include #include +#include #include #include #include @@ -283,23 +285,35 @@ static void c_stop(struct seq_file *m, void *v) static int c_show(struct seq_file *m, void *v) { unsigned long cpu_id = (unsigned long)v - 1; - struct device_node *node = of_get_cpu_node(cpu_id, NULL); struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id); + struct device_node *node; const char *compat, *isa; seq_printf(m, "processor\t: %lu\n", cpu_id); seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id)); - if (!of_property_read_string(node, "riscv,isa", &isa)) - print_isa(m, isa); - print_mmu(m); - if (!of_property_read_string(node, "compatible", &compat) - && strcmp(compat, "riscv")) - seq_printf(m, "uarch\t\t: %s\n", compat); + + if (acpi_disabled) { + node = of_get_cpu_node(cpu_id, NULL); + if (!of_property_read_string(node, "riscv,isa", &isa)) + print_isa(m, isa); + + print_mmu(m); + if (!of_property_read_string(node, "compatible", &compat) && + strcmp(compat, "riscv")) + seq_printf(m, "uarch\t\t: %s\n", compat); + + of_node_put(node); + } else { + if (!acpi_get_riscv_isa(NULL, cpu_id, &isa)) + print_isa(m, isa); + + print_mmu(m); + } + seq_printf(m, "mvendorid\t: 0x%lx\n", ci->mvendorid); seq_printf(m, "marchid\t\t: 0x%lx\n", ci->marchid); seq_printf(m, "mimpid\t\t: 0x%lx\n", ci->mimpid); seq_puts(m, "\n"); - of_node_put(node); return 0; } -- cgit v1.2.3 From 255b34d799ddaaef5e8672b96c47a3b94fe85da9 Mon Sep 17 00:00:00 2001 From: Yangyu Chen Date: Tue, 2 May 2023 00:17:38 +0800 Subject: riscv: allow case-insensitive ISA string parsing According to RISC-V Hart Capabilities Table (RHCT) description in UEFI Forum ECR, the format of the ISA string is defined in the RISC-V unprivileged specification which is case-insensitive. However, the current ISA string parser in the kernel does not support ISA strings with uppercase letters. This patch modifies the ISA string parser in the kernel to support case-insensitive ISA string parsing. Reviewed-by: Andrew Jones Reviewed-by: Conor Dooley Signed-off-by: Yangyu Chen Link: https://lore.kernel.org/r/tencent_B30EED51C7235CA1988890E5C658BE35C107@qq.com Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/cpu.c | 3 ++- arch/riscv/kernel/cpufeature.c | 35 +++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'arch/riscv/kernel/cpu.c') diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index c96aa56cf1c7..9d3a5363037b 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -42,7 +43,7 @@ int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart) pr_warn("CPU with hartid=%lu has no \"riscv,isa\" property\n", *hart); return -ENODEV; } - if (isa[0] != 'r' || isa[1] != 'v') { + if (tolower(isa[0]) != 'r' || tolower(isa[1]) != 'v') { pr_warn("CPU with hartid=%lu has an invalid ISA of \"%s\"\n", *hart, isa); return -ENODEV; } diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index b1d6b7e4b829..157687965ce5 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -127,13 +127,10 @@ void __init riscv_fill_hwcap(void) } temp = isa; -#if IS_ENABLED(CONFIG_32BIT) - if (!strncmp(isa, "rv32", 4)) + if (IS_ENABLED(CONFIG_32BIT) && !strncasecmp(isa, "rv32", 4)) isa += 4; -#elif IS_ENABLED(CONFIG_64BIT) - if (!strncmp(isa, "rv64", 4)) + else if (IS_ENABLED(CONFIG_64BIT) && !strncasecmp(isa, "rv64", 4)) isa += 4; -#endif /* The riscv,isa DT property must start with rv64 or rv32 */ if (temp == isa) continue; @@ -157,13 +154,15 @@ void __init riscv_fill_hwcap(void) break; } fallthrough; + case 'S': case 'x': + case 'X': case 'z': + case 'Z': ext_long = true; /* Multi-letter extension must be delimited */ for (; *isa && *isa != '_'; ++isa) - if (unlikely(!islower(*isa) - && !isdigit(*isa))) + if (unlikely(!isalnum(*isa))) ext_err = true; /* Parse backwards */ ext_end = isa; @@ -174,7 +173,7 @@ void __init riscv_fill_hwcap(void) /* Skip the minor version */ while (isdigit(*--ext_end)) ; - if (ext_end[0] != 'p' + if (tolower(ext_end[0]) != 'p' || !isdigit(ext_end[-1])) { /* Advance it to offset the pre-decrement */ ++ext_end; @@ -186,7 +185,7 @@ void __init riscv_fill_hwcap(void) ++ext_end; break; default: - if (unlikely(!islower(*ext))) { + if (unlikely(!isalpha(*ext))) { ext_err = true; break; } @@ -196,7 +195,7 @@ void __init riscv_fill_hwcap(void) /* Skip the minor version */ while (isdigit(*++isa)) ; - if (*isa != 'p') + if (tolower(*isa) != 'p') break; if (!isdigit(*++isa)) { --isa; @@ -210,18 +209,18 @@ void __init riscv_fill_hwcap(void) if (*isa != '_') --isa; -#define SET_ISA_EXT_MAP(name, bit) \ - do { \ - if ((ext_end - ext == sizeof(name) - 1) && \ - !memcmp(ext, name, sizeof(name) - 1) && \ - riscv_isa_extension_check(bit)) \ - set_bit(bit, this_isa); \ - } while (false) \ +#define SET_ISA_EXT_MAP(name, bit) \ + do { \ + if ((ext_end - ext == sizeof(name) - 1) && \ + !strncasecmp(ext, name, sizeof(name) - 1) && \ + riscv_isa_extension_check(bit)) \ + set_bit(bit, this_isa); \ + } while (false) \ if (unlikely(ext_err)) continue; if (!ext_long) { - int nr = *ext - 'a'; + int nr = tolower(*ext) - 'a'; if (riscv_isa_extension_check(nr)) { this_hwcap |= isa2hwcap[nr]; -- cgit v1.2.3 From c6699baf10647b87b075bf6c65d25b4cd52d4830 Mon Sep 17 00:00:00 2001 From: Evan Green Date: Tue, 9 May 2023 11:25:01 -0700 Subject: RISC-V: Add Zba, Zbs extension probing Add the Zba address bit manipulation extension and Zbs single bit instructions extension into those the kernel is aware of and maintains in its riscv_isa bitmap. Signed-off-by: Evan Green Reviewed-by: Andrew Jones Reviewed-by: Palmer Dabbelt Reviewed-by: Conor Dooley Reviewed-by: Heiko Stuebner Link: https://lore.kernel.org/r/20230509182504.2997252-2-evan@rivosinc.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/hwcap.h | 2 ++ arch/riscv/kernel/cpu.c | 2 ++ arch/riscv/kernel/cpufeature.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'arch/riscv/kernel/cpu.c') diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index e0c40a4c63d5..6b2e8ff4638c 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -46,6 +46,8 @@ #define RISCV_ISA_EXT_ZICBOZ 34 #define RISCV_ISA_EXT_SMAIA 35 #define RISCV_ISA_EXT_SSAIA 36 +#define RISCV_ISA_EXT_ZBA 37 +#define RISCV_ISA_EXT_ZBS 38 #define RISCV_ISA_EXT_MAX 64 #define RISCV_ISA_EXT_NAME_LEN_MAX 32 diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index c96aa56cf1c7..bd294364390d 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -184,7 +184,9 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), __RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ), __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), + __RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA), __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB), + __RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS), __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA), __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA), __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index b1d6b7e4b829..a1954c83638f 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -236,7 +236,9 @@ void __init riscv_fill_hwcap(void) SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL); SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT); + SET_ISA_EXT_MAP("zba", RISCV_ISA_EXT_ZBA); SET_ISA_EXT_MAP("zbb", RISCV_ISA_EXT_ZBB); + SET_ISA_EXT_MAP("zbs", RISCV_ISA_EXT_ZBS); SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM); SET_ISA_EXT_MAP("zicboz", RISCV_ISA_EXT_ZICBOZ); SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); -- cgit v1.2.3 From 2ac874343749b76e069cff5fea09c49e0bd365a0 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Wed, 7 Jun 2023 21:28:26 +0100 Subject: RISC-V: split early & late of_node to hartid mapping Some back and forth with Drew [1] about riscv_fill_hwcap() resulted in the realisation that it is not very useful to parse the DT & perform validation of riscv,isa every time we would like to get the id for a hart. Although it is no longer called in riscv_fill_hwcap(), riscv_of_processor_hartid() is called in several other places. Notably in setup_smp() it forms part of the logic for filling the mask of possible CPUs. Since a possible CPU must have passed this basic validation of riscv,isa, a repeat validation is not required. Rename riscv_of_processor_id() to riscv_early_of_processor_id(), which will be called from setup_smp() & introduce a new riscv_of_processor_id() which makes use of the pre-populated mask of possible cpus. Link: https://lore.kernel.org/linux-riscv/xvdswl3iyikwvamny7ikrxo2ncuixshtg3f6uucjahpe3xpc5c@ud4cz4fkg5dj/ [1] Reviewed-by: Andrew Jones Signed-off-by: Conor Dooley Reviewed-by: Sunil V L Link: https://lore.kernel.org/r/20230607-glade-pastel-d8cbd9d9f3c6@spud Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/processor.h | 1 + arch/riscv/kernel/cpu.c | 22 +++++++++++++++++++++- arch/riscv/kernel/smpboot.c | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'arch/riscv/kernel/cpu.c') diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 94a0590c6971..3479f9fca4b0 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -75,6 +75,7 @@ static inline void wait_for_interrupt(void) struct device_node; int riscv_of_processor_hartid(struct device_node *node, unsigned long *hartid); +int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hartid); int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid); extern void riscv_fill_hwcap(void); diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index 637263f9a7b9..8025de06edb7 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -22,6 +22,26 @@ * isn't an enabled and valid RISC-V hart node. */ int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart) +{ + int cpu; + + *hart = (unsigned long)of_get_cpu_hwid(node, 0); + if (*hart == ~0UL) { + pr_warn("Found CPU without hart ID\n"); + return -ENODEV; + } + + cpu = riscv_hartid_to_cpuid(*hart); + if (cpu < 0) + return cpu; + + if (!cpu_possible(cpu)) + return -ENODEV; + + return 0; +} + +int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hart) { const char *isa; @@ -30,7 +50,7 @@ int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart) return -ENODEV; } - *hart = (unsigned long) of_get_cpu_hwid(node, 0); + *hart = (unsigned long)of_get_cpu_hwid(node, 0); if (*hart == ~0UL) { pr_warn("Found CPU without hart ID\n"); return -ENODEV; diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 67bc5ef3e8b2..3f42331c8912 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -148,7 +148,7 @@ static void __init of_parse_and_init_cpus(void) cpu_set_ops(0); for_each_of_cpu_node(dn) { - rc = riscv_of_processor_hartid(dn, &hart); + rc = riscv_early_of_processor_hartid(dn, &hart); if (rc < 0) continue; -- cgit v1.2.3 From 069b0d51707721d5ab2001df866b66b82e4c1c35 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Wed, 7 Jun 2023 21:28:27 +0100 Subject: RISC-V: validate riscv,isa at boot, not during ISA string parsing Since riscv_fill_hwcap() now only iterates over possible cpus, the basic validation of whether riscv,isa contains "rv" can be moved to riscv_early_of_processor_hartid(). Further, "ima" support is required by the kernel, so reject any CPU not fitting the bill. Reviewed-by: Andrew Jones Signed-off-by: Conor Dooley Reviewed-by: Sunil V L Link: https://lore.kernel.org/r/20230607-guts-blurry-67e711acf328@spud Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/cpu.c | 8 +++++--- arch/riscv/kernel/cpufeature.c | 12 ++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'arch/riscv/kernel/cpu.c') diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index 8025de06edb7..dfb4a2a61050 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -65,10 +65,12 @@ int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *har pr_warn("CPU with hartid=%lu has no \"riscv,isa\" property\n", *hart); return -ENODEV; } - if (tolower(isa[0]) != 'r' || tolower(isa[1]) != 'v') { - pr_warn("CPU with hartid=%lu has an invalid ISA of \"%s\"\n", *hart, isa); + + if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32ima", 7)) + return -ENODEV; + + if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64ima", 7)) return -ENODEV; - } return 0; } diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index c8635211fc18..c3851c8cfa9c 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -148,12 +148,12 @@ void __init riscv_fill_hwcap(void) } } - if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32", 4)) - continue; - - if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64", 4)) - continue; - + /* + * For all possible cpus, we have already validated in + * the boot process that they at least contain "rv" and + * whichever of "32"/"64" this kernel supports, and so this + * section can be skipped. + */ isa += 4; bitmap_zero(this_isa, RISCV_ISA_EXT_MAX); -- cgit v1.2.3 From 07edc32779e3dfe164970fc254291258277219c9 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Wed, 7 Jun 2023 21:28:31 +0100 Subject: RISC-V: always report presence of extensions formerly part of the base ISA Of these four extensions, two were part of the base ISA when the port was written and are required by the kernel. The other two are implied when `i` is in riscv,isa on DT systems. There's not much that userspace can do with this extra information, but there is no harm in reporting an ISA string that closer resembles the current versions of the specifications either. Signed-off-by: Conor Dooley Link: https://lore.kernel.org/r/20230607-nest-collision-5796b6be8be6@spud Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/hwcap.h | 4 ++++ arch/riscv/kernel/cpu.c | 4 ++++ arch/riscv/kernel/cpufeature.c | 17 +++++++++++++++++ 3 files changed, 25 insertions(+) (limited to 'arch/riscv/kernel/cpu.c') diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index e0c40a4c63d5..e0eb9ad06805 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -46,6 +46,10 @@ #define RISCV_ISA_EXT_ZICBOZ 34 #define RISCV_ISA_EXT_SMAIA 35 #define RISCV_ISA_EXT_SSAIA 36 +#define RISCV_ISA_EXT_ZICNTR 37 +#define RISCV_ISA_EXT_ZICSR 38 +#define RISCV_ISA_EXT_ZIFENCEI 39 +#define RISCV_ISA_EXT_ZIHPM 40 #define RISCV_ISA_EXT_MAX 64 #define RISCV_ISA_EXT_NAME_LEN_MAX 32 diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index dfb4a2a61050..6aea6412cf65 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -208,7 +208,11 @@ arch_initcall(riscv_cpuinfo_init); static struct riscv_isa_ext_data isa_ext_arr[] = { __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), __RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ), + __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR), + __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR), + __RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI), __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), + __RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM), __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB), __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA), __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA), diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 84dc44a3e6e5..d21f7e8a33ef 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -311,6 +311,23 @@ void __init riscv_fill_hwcap(void) #undef SET_ISA_EXT_MAP } + /* + * Linux requires the following extensions, so we may as well + * always set them. + */ + set_bit(RISCV_ISA_EXT_ZICSR, this_isa); + set_bit(RISCV_ISA_EXT_ZIFENCEI, this_isa); + + /* + * These ones were as they were part of the base ISA when the + * port & dt-bindings were upstreamed, and so can be set + * unconditionally where `i` is in riscv,isa on DT systems. + */ + if (acpi_disabled) { + set_bit(RISCV_ISA_EXT_ZICNTR, this_isa); + set_bit(RISCV_ISA_EXT_ZIHPM, this_isa); + } + /* * All "okay" hart should have same isa. Set HWCAP based on * common capabilities of every "okay" hart, in case they don't -- cgit v1.2.3