xref: /linux/arch/riscv/kernel/cpu.c (revision 9bb956508c9d94935bedba4f13901fb2b7468e91)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2012 Regents of the University of California
4  */
5 
6 #include <linux/acpi.h>
7 #include <linux/cpu.h>
8 #include <linux/ctype.h>
9 #include <linux/init.h>
10 #include <linux/seq_file.h>
11 #include <linux/of.h>
12 #include <asm/acpi.h>
13 #include <asm/cpufeature.h>
14 #include <asm/csr.h>
15 #include <asm/hwcap.h>
16 #include <asm/sbi.h>
17 #include <asm/smp.h>
18 #include <asm/pgtable.h>
19 #include <asm/vendor_extensions.h>
20 
arch_match_cpu_phys_id(int cpu,u64 phys_id)21 bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
22 {
23 	return phys_id == cpuid_to_hartid_map(cpu);
24 }
25 
26 /*
27  * Returns the hart ID of the given device tree node, or -ENODEV if the node
28  * isn't an enabled and valid RISC-V hart node.
29  */
riscv_of_processor_hartid(struct device_node * node,unsigned long * hart)30 int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart)
31 {
32 	int cpu;
33 
34 	*hart = (unsigned long)of_get_cpu_hwid(node, 0);
35 	if (*hart == ~0UL) {
36 		pr_warn("Found CPU without hart ID\n");
37 		return -ENODEV;
38 	}
39 
40 	cpu = riscv_hartid_to_cpuid(*hart);
41 	if (cpu < 0)
42 		return cpu;
43 
44 	if (!cpu_possible(cpu))
45 		return -ENODEV;
46 
47 	return 0;
48 }
49 
riscv_early_of_processor_hartid(struct device_node * node,unsigned long * hart)50 int __init riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hart)
51 {
52 	const char *isa;
53 
54 	if (!of_device_is_compatible(node, "riscv")) {
55 		pr_warn("Found incompatible CPU\n");
56 		return -ENODEV;
57 	}
58 
59 	*hart = (unsigned long)of_get_cpu_hwid(node, 0);
60 	if (*hart == ~0UL) {
61 		pr_warn("Found CPU without hart ID\n");
62 		return -ENODEV;
63 	}
64 
65 	if (!of_device_is_available(node))
66 		return -ENODEV;
67 
68 	if (of_property_read_string(node, "riscv,isa-base", &isa))
69 		goto old_interface;
70 
71 	if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32i", 5)) {
72 		pr_warn("CPU with hartid=%lu does not support rv32i", *hart);
73 		return -ENODEV;
74 	}
75 
76 	if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64i", 5)) {
77 		pr_warn("CPU with hartid=%lu does not support rv64i", *hart);
78 		return -ENODEV;
79 	}
80 
81 	if (!of_property_present(node, "riscv,isa-extensions"))
82 		return -ENODEV;
83 
84 	if (of_property_match_string(node, "riscv,isa-extensions", "i") < 0 ||
85 	    of_property_match_string(node, "riscv,isa-extensions", "m") < 0 ||
86 	    of_property_match_string(node, "riscv,isa-extensions", "a") < 0) {
87 		pr_warn("CPU with hartid=%lu does not support ima", *hart);
88 		return -ENODEV;
89 	}
90 
91 	return 0;
92 
93 old_interface:
94 	if (!riscv_isa_fallback) {
95 		pr_warn("CPU with hartid=%lu is invalid: this kernel does not parse \"riscv,isa\"",
96 			*hart);
97 		return -ENODEV;
98 	}
99 
100 	if (of_property_read_string(node, "riscv,isa", &isa)) {
101 		pr_warn("CPU with hartid=%lu has no \"riscv,isa-base\" or \"riscv,isa\" property\n",
102 			*hart);
103 		return -ENODEV;
104 	}
105 
106 	if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32ima", 7)) {
107 		pr_warn("CPU with hartid=%lu does not support rv32ima", *hart);
108 		return -ENODEV;
109 	}
110 
111 	if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64ima", 7)) {
112 		pr_warn("CPU with hartid=%lu does not support rv64ima", *hart);
113 		return -ENODEV;
114 	}
115 
116 	return 0;
117 }
118 
119 /*
120  * Find hart ID of the CPU DT node under which given DT node falls.
121  *
122  * To achieve this, we walk up the DT tree until we find an active
123  * RISC-V core (HART) node and extract the cpuid from it.
124  */
riscv_of_parent_hartid(struct device_node * node,unsigned long * hartid)125 int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid)
126 {
127 	for (; node; node = node->parent) {
128 		if (of_device_is_compatible(node, "riscv")) {
129 			*hartid = (unsigned long)of_get_cpu_hwid(node, 0);
130 			if (*hartid == ~0UL) {
131 				pr_warn("Found CPU without hart ID\n");
132 				return -ENODEV;
133 			}
134 			return 0;
135 		}
136 	}
137 
138 	return -1;
139 }
140 
riscv_get_marchid(void)141 unsigned long __init riscv_get_marchid(void)
142 {
143 	struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo);
144 
145 #if IS_ENABLED(CONFIG_RISCV_SBI)
146 	ci->marchid = sbi_spec_is_0_1() ? 0 : sbi_get_marchid();
147 #elif IS_ENABLED(CONFIG_RISCV_M_MODE)
148 	ci->marchid = csr_read(CSR_MARCHID);
149 #else
150 	ci->marchid = 0;
151 #endif
152 	return ci->marchid;
153 }
154 
riscv_get_mvendorid(void)155 unsigned long __init riscv_get_mvendorid(void)
156 {
157 	struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo);
158 
159 #if IS_ENABLED(CONFIG_RISCV_SBI)
160 	ci->mvendorid = sbi_spec_is_0_1() ? 0 : sbi_get_mvendorid();
161 #elif IS_ENABLED(CONFIG_RISCV_M_MODE)
162 	ci->mvendorid = csr_read(CSR_MVENDORID);
163 #else
164 	ci->mvendorid = 0;
165 #endif
166 	return ci->mvendorid;
167 }
168 
169 DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
170 
riscv_cached_mvendorid(unsigned int cpu_id)171 unsigned long riscv_cached_mvendorid(unsigned int cpu_id)
172 {
173 	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
174 
175 	return ci->mvendorid;
176 }
177 EXPORT_SYMBOL(riscv_cached_mvendorid);
178 
riscv_cached_marchid(unsigned int cpu_id)179 unsigned long riscv_cached_marchid(unsigned int cpu_id)
180 {
181 	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
182 
183 	return ci->marchid;
184 }
185 EXPORT_SYMBOL(riscv_cached_marchid);
186 
riscv_cached_mimpid(unsigned int cpu_id)187 unsigned long riscv_cached_mimpid(unsigned int cpu_id)
188 {
189 	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
190 
191 	return ci->mimpid;
192 }
193 EXPORT_SYMBOL(riscv_cached_mimpid);
194 
riscv_cpuinfo_starting(unsigned int cpu)195 static int riscv_cpuinfo_starting(unsigned int cpu)
196 {
197 	struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo);
198 
199 #if IS_ENABLED(CONFIG_RISCV_SBI)
200 	if (!ci->mvendorid)
201 		ci->mvendorid = sbi_spec_is_0_1() ? 0 : sbi_get_mvendorid();
202 	if (!ci->marchid)
203 		ci->marchid = sbi_spec_is_0_1() ? 0 : sbi_get_marchid();
204 	ci->mimpid = sbi_spec_is_0_1() ? 0 : sbi_get_mimpid();
205 #elif IS_ENABLED(CONFIG_RISCV_M_MODE)
206 	if (!ci->mvendorid)
207 		ci->mvendorid = csr_read(CSR_MVENDORID);
208 	if (!ci->marchid)
209 		ci->marchid = csr_read(CSR_MARCHID);
210 	ci->mimpid = csr_read(CSR_MIMPID);
211 #else
212 	ci->mvendorid = 0;
213 	ci->marchid = 0;
214 	ci->mimpid = 0;
215 #endif
216 
217 	return 0;
218 }
219 
riscv_cpuinfo_init(void)220 static int __init riscv_cpuinfo_init(void)
221 {
222 	int ret;
223 
224 	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/cpuinfo:starting",
225 				riscv_cpuinfo_starting, NULL);
226 	if (ret < 0) {
227 		pr_err("cpuinfo: failed to register hotplug callbacks.\n");
228 		return ret;
229 	}
230 
231 	return 0;
232 }
233 arch_initcall(riscv_cpuinfo_init);
234 
235 #ifdef CONFIG_PROC_FS
236 
237 #define ALL_CPUS -1
238 
print_vendor_isa(struct seq_file * f,int cpu)239 static void print_vendor_isa(struct seq_file *f, int cpu)
240 {
241 	struct riscv_isavendorinfo *vendor_bitmap;
242 	struct riscv_isa_vendor_ext_data_list *ext_list;
243 	const struct riscv_isa_ext_data *ext_data;
244 
245 	for (int i = 0; i < riscv_isa_vendor_ext_list_size; i++) {
246 		ext_list = riscv_isa_vendor_ext_list[i];
247 		ext_data = riscv_isa_vendor_ext_list[i]->ext_data;
248 
249 		if (cpu == ALL_CPUS)
250 			vendor_bitmap = &ext_list->all_harts_isa_bitmap;
251 		else
252 			vendor_bitmap = &ext_list->per_hart_isa_bitmap[cpu];
253 
254 		for (int j = 0; j < ext_list->ext_data_count; j++) {
255 			if (!__riscv_isa_extension_available(vendor_bitmap->isa, ext_data[j].id))
256 				continue;
257 
258 			seq_printf(f, "_%s", ext_data[j].name);
259 		}
260 	}
261 }
262 
print_isa(struct seq_file * f,const unsigned long * isa_bitmap,int cpu)263 static void print_isa(struct seq_file *f, const unsigned long *isa_bitmap, int cpu)
264 {
265 
266 	if (IS_ENABLED(CONFIG_32BIT))
267 		seq_write(f, "rv32", 4);
268 	else
269 		seq_write(f, "rv64", 4);
270 
271 	for (int i = 0; i < riscv_isa_ext_count; i++) {
272 		if (!__riscv_isa_extension_available(isa_bitmap, riscv_isa_ext[i].id))
273 			continue;
274 
275 		/* Only multi-letter extensions are split by underscores */
276 		if (strnlen(riscv_isa_ext[i].name, 2) != 1)
277 			seq_puts(f, "_");
278 
279 		seq_printf(f, "%s", riscv_isa_ext[i].name);
280 	}
281 
282 	print_vendor_isa(f, cpu);
283 
284 	seq_puts(f, "\n");
285 }
286 
print_mmu(struct seq_file * f)287 static void print_mmu(struct seq_file *f)
288 {
289 	const char *sv_type;
290 
291 #ifdef CONFIG_MMU
292 #if defined(CONFIG_32BIT)
293 	sv_type = "sv32";
294 #elif defined(CONFIG_64BIT)
295 	if (pgtable_l5_enabled)
296 		sv_type = "sv57";
297 	else if (pgtable_l4_enabled)
298 		sv_type = "sv48";
299 	else
300 		sv_type = "sv39";
301 #endif
302 #else
303 	sv_type = "none";
304 #endif /* CONFIG_MMU */
305 	seq_printf(f, "mmu\t\t: %s\n", sv_type);
306 }
307 
c_start(struct seq_file * m,loff_t * pos)308 static void *c_start(struct seq_file *m, loff_t *pos)
309 {
310 	if (*pos == nr_cpu_ids)
311 		return NULL;
312 
313 	*pos = cpumask_next(*pos - 1, cpu_online_mask);
314 	if ((*pos) < nr_cpu_ids)
315 		return (void *)(uintptr_t)(1 + *pos);
316 	return NULL;
317 }
318 
c_next(struct seq_file * m,void * v,loff_t * pos)319 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
320 {
321 	(*pos)++;
322 	return c_start(m, pos);
323 }
324 
c_stop(struct seq_file * m,void * v)325 static void c_stop(struct seq_file *m, void *v)
326 {
327 }
328 
c_show(struct seq_file * m,void * v)329 static int c_show(struct seq_file *m, void *v)
330 {
331 	unsigned long cpu_id = (unsigned long)v - 1;
332 	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
333 	struct device_node *node;
334 	const char *compat;
335 
336 	seq_printf(m, "processor\t: %lu\n", cpu_id);
337 	seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id));
338 
339 	/*
340 	 * For historical raisins, the isa: line is limited to the lowest common
341 	 * denominator of extensions supported across all harts. A true list of
342 	 * extensions supported on this hart is printed later in the hart isa:
343 	 * line.
344 	 */
345 	seq_puts(m, "isa\t\t: ");
346 	print_isa(m, NULL, ALL_CPUS);
347 	print_mmu(m);
348 
349 	if (acpi_disabled) {
350 		node = of_get_cpu_node(cpu_id, NULL);
351 
352 		if (!of_property_read_string(node, "compatible", &compat) &&
353 		    strcmp(compat, "riscv"))
354 			seq_printf(m, "uarch\t\t: %s\n", compat);
355 
356 		of_node_put(node);
357 	}
358 
359 	seq_printf(m, "mvendorid\t: 0x%lx\n", ci->mvendorid);
360 	seq_printf(m, "marchid\t\t: 0x%lx\n", ci->marchid);
361 	seq_printf(m, "mimpid\t\t: 0x%lx\n", ci->mimpid);
362 
363 	/*
364 	 * Print the ISA extensions specific to this hart, which may show
365 	 * additional extensions not present across all harts.
366 	 */
367 	seq_puts(m, "hart isa\t: ");
368 	print_isa(m, hart_isa[cpu_id].isa, cpu_id);
369 	seq_puts(m, "\n");
370 
371 	return 0;
372 }
373 
374 const struct seq_operations cpuinfo_op = {
375 	.start	= c_start,
376 	.next	= c_next,
377 	.stop	= c_stop,
378 	.show	= c_show
379 };
380 
381 #endif /* CONFIG_PROC_FS */
382