xref: /netbsd-src/sys/arch/riscv/riscv/cpu.c (revision e82e6746ddd0b1040b7e16a804b5ea6840952b12)
1 /*	$NetBSD: cpu.c,v 1.7 2024/08/10 07:27:04 skrll Exp $	*/
2 
3 /*-
4  * Copyright (c) 2023 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Nick Hudson
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "opt_multiprocessor.h"
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.7 2024/08/10 07:27:04 skrll Exp $");
36 
37 #include <sys/param.h>
38 
39 #include <sys/cpu.h>
40 #include <sys/device.h>
41 #include <sys/kmem.h>
42 #include <sys/reboot.h>
43 #include <sys/sysctl.h>
44 
45 #include <riscv/cpu.h>
46 #include <riscv/cpuvar.h>
47 #include <riscv/machdep.h>
48 #include <riscv/sbi.h>
49 
50 #ifdef MULTIPROCESSOR
51 #define NCPUINFO	MAXCPUS
52 #else
53 #define NCPUINFO	1
54 #endif /* MULTIPROCESSOR */
55 
56 static void
57 cache_nullop(vaddr_t va, paddr_t pa, psize_t sz)
58 {
59 }
60 
61 void (*cpu_sdcache_wbinv_range)(vaddr_t, paddr_t, psize_t) = cache_nullop;
62 void (*cpu_sdcache_inv_range)(vaddr_t, paddr_t, psize_t) = cache_nullop;
63 void (*cpu_sdcache_wb_range)(vaddr_t, paddr_t, psize_t) = cache_nullop;
64 
65 u_int   riscv_dcache_align = CACHE_LINE_SIZE;
66 u_int   riscv_dcache_align_mask = CACHE_LINE_SIZE - 1;
67 
68 #define CPU_VENDOR_SIFIVE	0x489
69 
70 #define CPU_ARCH_7SERIES	0x8000000000000007
71 
72 #define CPU_VENDOR_THEAD	0x5b7
73 
74 struct cpu_arch {
75 	uint64_t	 ca_id;
76 	const char	*ca_name;
77 };
78 
79 struct cpu_arch cpu_arch_sifive[] = {
80     {
81 	.ca_id = CPU_ARCH_7SERIES,
82 	.ca_name = "7-Series Processor (E7, S7, U7 series)",
83     },
84     { },	// terminator
85 };
86 
87 struct cpu_arch cpu_arch_thead[] = {
88     {
89 	.ca_id = 0,
90 	.ca_name = "9-Series Processor (C9, E9 series)",
91     },
92     { },	// terminator
93 };
94 
95 struct cpu_vendor {
96 	uint32_t	 	 cv_id;
97 	const char		*cv_name;
98 	struct cpu_arch		*cv_arch;
99 } cpu_vendors[] = {
100     {
101 	.cv_id = CPU_VENDOR_SIFIVE,
102 	.cv_name = "SiFive",
103 	.cv_arch = cpu_arch_sifive,
104     },
105     {
106 	.cv_id = CPU_VENDOR_THEAD,
107 	.cv_name = "T-Head",
108 	.cv_arch = cpu_arch_thead,
109     },
110 };
111 
112 /*
113  * Our exported cpu_info structs; indexed by BP as 0 and APs [1, ncpu - 1]
114  */
115 struct cpu_info cpu_info_store[NCPUINFO] = {
116 	[0] = {
117 		.ci_cpl = IPL_HIGH,
118 		.ci_curlwp = &lwp0,
119 		.ci_tlb_info = &pmap_tlb0_info,
120 #ifdef MULTIPROCESSOR
121 		.ci_flags = CPUF_PRIMARY | CPUF_PRESENT | CPUF_RUNNING,
122 #endif
123 	}
124 };
125 
126 /*
127  * setup the per-cpu sysctl tree.
128  */
129 static void
130 cpu_setup_sysctl(device_t dv, struct cpu_info *ci)
131 {
132 	const struct sysctlnode *cpunode = NULL;
133 
134 	sysctl_createv(NULL, 0, NULL, &cpunode,
135 		       CTLFLAG_PERMANENT,
136 		       CTLTYPE_NODE, device_xname(dv), NULL,
137 		       NULL, 0, NULL, 0,
138 		       CTL_MACHDEP,
139 		       CTL_CREATE, CTL_EOL);
140 
141 	if (cpunode == NULL)
142 		return;
143 }
144 
145 
146 static void
147 cpu_identify(device_t self, struct cpu_info *ci)
148 {
149 	const register_t mvendorid = sbi_get_mvendorid().value;
150 	const register_t marchid = sbi_get_marchid().value;
151 	const uint32_t mimpid = sbi_get_mimpid().value;
152 	struct cpu_arch *cv_arch = NULL;
153 	const char *cv_name = NULL;
154 	const char *ca_name = NULL;
155 	char vendor[128];
156 	char arch[128];
157 
158 	for (size_t i = 0; i < __arraycount(cpu_vendors); i++) {
159 		if (mvendorid == cpu_vendors[i].cv_id) {
160 			cv_name = cpu_vendors[i].cv_name;
161 			cv_arch = cpu_vendors[i].cv_arch;
162 			break;
163 		}
164 	}
165 
166 	if (cv_arch != NULL) {
167 		for (size_t i = 0; cv_arch[i].ca_name != NULL; i++) {
168 			if (marchid == cv_arch[i].ca_id) {
169 				ca_name = cv_arch[i].ca_name;
170 				break;
171 			}
172 		}
173 	}
174 
175 	if (cv_name == NULL) {
176 		snprintf(vendor, sizeof(vendor), "vendor %" PRIxREGISTER, mvendorid);
177 		cv_name = vendor;
178 	}
179 	if (ca_name == NULL) {
180 		snprintf(arch, sizeof(arch), "arch %" PRIxREGISTER, marchid);
181 		ca_name = arch;
182 	}
183 
184 	aprint_naive("\n");
185 	aprint_normal(": %s %s imp. %" PRIx32 "\n", cv_name, ca_name, mimpid);
186         aprint_verbose_dev(ci->ci_dev,
187 	    "vendor 0x%" PRIxREGISTER " arch. %" PRIxREGISTER " imp. %" PRIx32 "\n",
188 	    mvendorid, marchid, mimpid);
189 }
190 
191 
192 void
193 cpu_attach(device_t dv, cpuid_t hartid)
194 {
195 	struct cpu_info *ci;
196 
197 	/* Check for the BP */
198 	if (hartid == cpu_bphartid) {
199 		ci = curcpu();
200 		KASSERTMSG(ci == &cpu_info_store[0], "ci %p", ci);
201 		ci->ci_cpuid = hartid;
202 		ci->ci_cpu_freq = riscv_timer_frequency_get();
203 	} else {
204 #ifdef MULTIPROCESSOR
205 		if ((boothowto & RB_MD1) != 0) {
206 			aprint_naive("\n");
207 			aprint_normal(": multiprocessor boot disabled\n");
208 			return;
209 		}
210 
211 		KASSERT(hartid < MAXCPUS);
212 		KASSERT(cpu_hartindex[hartid] < MAXCPUS);
213 
214 		ci = &cpu_info_store[cpu_hartindex[hartid]];
215 
216 		ci->ci_cpl = IPL_HIGH;
217 		ci->ci_cpuid = hartid;
218 
219 		if (!cpu_hatched_p(cpu_hartindex[hartid])) {
220 			ci->ci_dev = dv;
221 			device_set_private(dv, ci);
222 			ci->ci_index = -1;
223 
224 			aprint_naive(": disabled\n");
225 			aprint_normal(": disabled (unresponsive)\n");
226 			return;
227 		}
228 #else /* MULTIPROCESSOR */
229 		aprint_naive(": disabled\n");
230 		aprint_normal(": disabled (uniprocessor kernel)\n");
231 		return;
232 #endif /* MULTIPROCESSOR */
233 	}
234 
235 	ci->ci_dev = dv;
236 	device_set_private(dv, ci);
237 
238 	cpu_identify(dv, ci);
239 
240 #ifdef MULTIPROCESSOR
241 	kcpuset_create(&ci->ci_shootdowncpus, true);
242 
243 	ipi_init(ci);
244 
245 	kcpuset_create(&ci->ci_multicastcpus, true);
246 	kcpuset_create(&ci->ci_watchcpus, true);
247 	kcpuset_create(&ci->ci_ddbcpus, true);
248 
249 	if (hartid != cpu_bphartid) {
250 		mi_cpu_attach(ci);
251 	}
252 #endif /* MULTIPROCESSOR */
253 	cpu_setup_sysctl(dv, ci);
254 }
255 
256 #ifdef MULTIPROCESSOR
257 /*
258  * Initialise a secondary processor.
259  *
260  * printf isn't available as kmutex(9) relies on curcpu which isn't setup yet.
261  *
262  */
263 void __noasan
264 cpu_init_secondary_processor(u_int cpuindex)
265 {
266 	cpu_set_hatched(cpuindex);
267 
268 	/*
269 	 * return to assembly to wait for cpu_boot_secondary_processors
270 	 */
271 }
272 
273 
274 /*
275  * When we are called, the MMU and caches are on and we are running on the stack
276  * of the idlelwp for this cpu.
277  */
278 void
279 cpu_hatch(struct cpu_info *ci, unsigned long cpuindex)
280 {
281 	KASSERT(curcpu() == ci);
282 
283 	// Show this CPU as present.
284 	atomic_or_ulong(&ci->ci_flags, CPUF_PRESENT);
285 
286 	ci->ci_cpu_freq = riscv_timer_frequency_get();
287 
288 	riscv_timer_init();
289 
290 	kcpuset_set(cpus_hatched, cpu_index(ci));
291 	kcpuset_set(cpus_running, cpu_index(ci));
292 
293 	/*
294 	 * clear my bit of the mailbox to tell cpu_boot_secondary_processors().
295 	 * Consider that if there are cpu0, 1, 2, 3, and cpu2 is unresponsive,
296 	 * ci_index for each would be cpu0=0, cpu1=1, cpu2=undef, cpu3=2.
297 	 * therefore we have to use device_unit instead of ci_index for mbox.
298 	 */
299 
300 	cpu_clr_mbox(cpuindex);
301 }
302 #endif /* MULTIPROCESSOR */
303