RISC-V: shunt isa_ext_arr to cpufeature.c
[linux-block.git] / arch / riscv / kernel / cpu.c
CommitLineData
50acfb2b 1// SPDX-License-Identifier: GPL-2.0-only
76d2a049
PD
2/*
3 * Copyright (C) 2012 Regents of the University of California
76d2a049
PD
4 */
5
0b144c81 6#include <linux/acpi.h>
3baca1a4 7#include <linux/cpu.h>
255b34d7 8#include <linux/ctype.h>
76d2a049
PD
9#include <linux/init.h>
10#include <linux/seq_file.h>
11#include <linux/of.h>
0b144c81 12#include <asm/acpi.h>
ff77cf5b 13#include <asm/cpufeature.h>
3baca1a4 14#include <asm/csr.h>
a9b20260 15#include <asm/hwcap.h>
3baca1a4 16#include <asm/sbi.h>
f99fb607 17#include <asm/smp.h>
73c7c8f6 18#include <asm/pgtable.h>
76d2a049 19
b2f8cfa7 20/*
149820c6
JH
21 * Returns the hart ID of the given device tree node, or -ENODEV if the node
22 * isn't an enabled and valid RISC-V hart node.
b2f8cfa7 23 */
ad635e72 24int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart)
2ac87434
CD
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
44int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hart)
76d2a049 45{
e3d794d5 46 const char *isa;
76d2a049
PD
47
48 if (!of_device_is_compatible(node, "riscv")) {
49 pr_warn("Found incompatible CPU\n");
149820c6 50 return -ENODEV;
76d2a049
PD
51 }
52
2ac87434 53 *hart = (unsigned long)of_get_cpu_hwid(node, 0);
ad635e72 54 if (*hart == ~0UL) {
76d2a049 55 pr_warn("Found CPU without hart ID\n");
149820c6 56 return -ENODEV;
76d2a049 57 }
76d2a049 58
e3d794d5 59 if (!of_device_is_available(node)) {
ad635e72 60 pr_info("CPU with hartid=%lu is not available\n", *hart);
149820c6 61 return -ENODEV;
76d2a049
PD
62 }
63
64 if (of_property_read_string(node, "riscv,isa", &isa)) {
ad635e72 65 pr_warn("CPU with hartid=%lu has no \"riscv,isa\" property\n", *hart);
149820c6 66 return -ENODEV;
76d2a049 67 }
069b0d51 68
23059893
PD
69 if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32ima", 7)) {
70 pr_warn("CPU with hartid=%lu does not support rv32ima", *hart);
069b0d51 71 return -ENODEV;
23059893 72 }
069b0d51 73
23059893
PD
74 if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64ima", 7)) {
75 pr_warn("CPU with hartid=%lu does not support rv64ima", *hart);
149820c6 76 return -ENODEV;
23059893 77 }
76d2a049 78
ad635e72 79 return 0;
76d2a049
PD
80}
81
d175d699
AP
82/*
83 * Find hart ID of the CPU DT node under which given DT node falls.
84 *
85 * To achieve this, we walk up the DT tree until we find an active
86 * RISC-V core (HART) node and extract the cpuid from it.
87 */
ad635e72 88int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid)
d175d699 89{
ad635e72
S
90 int rc;
91
d175d699 92 for (; node; node = node->parent) {
ad635e72
S
93 if (of_device_is_compatible(node, "riscv")) {
94 rc = riscv_of_processor_hartid(node, hartid);
95 if (!rc)
96 return 0;
97 }
d175d699
AP
98 }
99
100 return -1;
101}
102
ff77cf5b 103DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
3baca1a4 104
5e9c68ea
HS
105unsigned long riscv_cached_mvendorid(unsigned int cpu_id)
106{
107 struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
108
109 return ci->mvendorid;
110}
111EXPORT_SYMBOL(riscv_cached_mvendorid);
112
113unsigned long riscv_cached_marchid(unsigned int cpu_id)
114{
115 struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
116
117 return ci->marchid;
118}
119EXPORT_SYMBOL(riscv_cached_marchid);
120
121unsigned long riscv_cached_mimpid(unsigned int cpu_id)
122{
123 struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
124
125 return ci->mimpid;
126}
127EXPORT_SYMBOL(riscv_cached_mimpid);
128
3baca1a4
AP
129static int riscv_cpuinfo_starting(unsigned int cpu)
130{
131 struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo);
132
133#if IS_ENABLED(CONFIG_RISCV_SBI)
134 ci->mvendorid = sbi_spec_is_0_1() ? 0 : sbi_get_mvendorid();
135 ci->marchid = sbi_spec_is_0_1() ? 0 : sbi_get_marchid();
136 ci->mimpid = sbi_spec_is_0_1() ? 0 : sbi_get_mimpid();
137#elif IS_ENABLED(CONFIG_RISCV_M_MODE)
138 ci->mvendorid = csr_read(CSR_MVENDORID);
139 ci->marchid = csr_read(CSR_MARCHID);
140 ci->mimpid = csr_read(CSR_MIMPID);
141#else
142 ci->mvendorid = 0;
143 ci->marchid = 0;
144 ci->mimpid = 0;
145#endif
146
147 return 0;
148}
149
150static int __init riscv_cpuinfo_init(void)
151{
152 int ret;
153
154 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/cpuinfo:starting",
155 riscv_cpuinfo_starting, NULL);
156 if (ret < 0) {
157 pr_err("cpuinfo: failed to register hotplug callbacks.\n");
158 return ret;
159 }
160
161 return 0;
162}
5e9c68ea
HS
163arch_initcall(riscv_cpuinfo_init);
164
165#ifdef CONFIG_PROC_FS
3baca1a4 166
a9b20260
AP
167static void print_isa_ext(struct seq_file *f)
168{
8135ade3
CD
169 for (int i = 0; i < riscv_isa_ext_count; i++) {
170 const struct riscv_isa_ext_data *edata = &riscv_isa_ext[i];
a9b20260
AP
171 if (!__riscv_isa_extension_available(NULL, edata->isa_ext_id))
172 continue;
173 seq_printf(f, "_%s", edata->uprop);
174 }
175}
176
e634ff77 177/*
a9b20260
AP
178 * These are the only valid base (single letter) ISA extensions as per the spec.
179 * It also specifies the canonical order in which it appears in the spec.
180 * Some of the extension may just be a place holder for now (B, K, P, J).
181 * This should be updated once corresponding extensions are ratified.
182 */
183static const char base_riscv_exts[13] = "imafdqcbkjpvh";
76d2a049 184
67270fb3 185static void print_isa(struct seq_file *f)
19ccf29b 186{
a9b20260
AP
187 int i;
188
4b26d22f 189 seq_puts(f, "isa\t\t: ");
67270fb3
HS
190 if (IS_ENABLED(CONFIG_32BIT))
191 seq_write(f, "rv32", 4);
192 else
193 seq_write(f, "rv64", 4);
194
a9b20260
AP
195 for (i = 0; i < sizeof(base_riscv_exts); i++) {
196 if (__riscv_isa_extension_available(NULL, base_riscv_exts[i] - 'a'))
197 /* Print only enabled the base ISA extensions */
198 seq_write(f, &base_riscv_exts[i], 1);
199 }
200 print_isa_ext(f);
4b26d22f 201 seq_puts(f, "\n");
19ccf29b
PD
202}
203
73c7c8f6 204static void print_mmu(struct seq_file *f)
19ccf29b 205{
73c7c8f6
AG
206 char sv_type[16];
207
8810d7fe 208#ifdef CONFIG_MMU
19ccf29b 209#if defined(CONFIG_32BIT)
73c7c8f6 210 strncpy(sv_type, "sv32", 5);
19ccf29b 211#elif defined(CONFIG_64BIT)
011f09d1
QP
212 if (pgtable_l5_enabled)
213 strncpy(sv_type, "sv57", 5);
214 else if (pgtable_l4_enabled)
73c7c8f6
AG
215 strncpy(sv_type, "sv48", 5);
216 else
217 strncpy(sv_type, "sv39", 5);
19ccf29b 218#endif
8810d7fe
NC
219#else
220 strncpy(sv_type, "none", 5);
221#endif /* CONFIG_MMU */
73c7c8f6 222 seq_printf(f, "mmu\t\t: %s\n", sv_type);
19ccf29b
PD
223}
224
76d2a049
PD
225static void *c_start(struct seq_file *m, loff_t *pos)
226{
d14e99bf
AJ
227 if (*pos == nr_cpu_ids)
228 return NULL;
229
76d2a049
PD
230 *pos = cpumask_next(*pos - 1, cpu_online_mask);
231 if ((*pos) < nr_cpu_ids)
232 return (void *)(uintptr_t)(1 + *pos);
233 return NULL;
234}
235
236static void *c_next(struct seq_file *m, void *v, loff_t *pos)
237{
238 (*pos)++;
239 return c_start(m, pos);
240}
241
242static void c_stop(struct seq_file *m, void *v)
243{
244}
245
246static int c_show(struct seq_file *m, void *v)
247{
f99fb607 248 unsigned long cpu_id = (unsigned long)v - 1;
3baca1a4 249 struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
0b144c81 250 struct device_node *node;
67270fb3 251 const char *compat;
76d2a049 252
4b26d22f
AP
253 seq_printf(m, "processor\t: %lu\n", cpu_id);
254 seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id));
67270fb3
HS
255 print_isa(m);
256 print_mmu(m);
0b144c81
S
257
258 if (acpi_disabled) {
259 node = of_get_cpu_node(cpu_id, NULL);
0b144c81 260
0b144c81
S
261 if (!of_property_read_string(node, "compatible", &compat) &&
262 strcmp(compat, "riscv"))
263 seq_printf(m, "uarch\t\t: %s\n", compat);
264
265 of_node_put(node);
0b144c81
S
266 }
267
3baca1a4
AP
268 seq_printf(m, "mvendorid\t: 0x%lx\n", ci->mvendorid);
269 seq_printf(m, "marchid\t\t: 0x%lx\n", ci->marchid);
270 seq_printf(m, "mimpid\t\t: 0x%lx\n", ci->mimpid);
76d2a049
PD
271 seq_puts(m, "\n");
272
273 return 0;
274}
275
276const struct seq_operations cpuinfo_op = {
277 .start = c_start,
278 .next = c_next,
279 .stop = c_stop,
280 .show = c_show
281};
282
283#endif /* CONFIG_PROC_FS */