xref: /netbsd-src/sys/arch/riscv/riscv/cpu.c (revision e82e6746ddd0b1040b7e16a804b5ea6840952b12)
1*e82e6746Sskrll /*	$NetBSD: cpu.c,v 1.7 2024/08/10 07:27:04 skrll Exp $	*/
275b842b8Sskrll 
375b842b8Sskrll /*-
475b842b8Sskrll  * Copyright (c) 2023 The NetBSD Foundation, Inc.
575b842b8Sskrll  * All rights reserved.
675b842b8Sskrll  *
775b842b8Sskrll  * This code is derived from software contributed to The NetBSD Foundation
875b842b8Sskrll  * by Nick Hudson
975b842b8Sskrll  *
1075b842b8Sskrll  * Redistribution and use in source and binary forms, with or without
1175b842b8Sskrll  * modification, are permitted provided that the following conditions
1275b842b8Sskrll  * are met:
1375b842b8Sskrll  * 1. Redistributions of source code must retain the above copyright
1475b842b8Sskrll  *    notice, this list of conditions and the following disclaimer.
1575b842b8Sskrll  * 2. Redistributions in binary form must reproduce the above copyright
1675b842b8Sskrll  *    notice, this list of conditions and the following disclaimer in the
1775b842b8Sskrll  *    documentation and/or other materials provided with the distribution.
1875b842b8Sskrll  *
1975b842b8Sskrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2075b842b8Sskrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2175b842b8Sskrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2275b842b8Sskrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2375b842b8Sskrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2475b842b8Sskrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2575b842b8Sskrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2675b842b8Sskrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2775b842b8Sskrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2875b842b8Sskrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2975b842b8Sskrll  * POSSIBILITY OF SUCH DAMAGE.
3075b842b8Sskrll  */
3175b842b8Sskrll 
3208c3a075Sskrll #include "opt_multiprocessor.h"
3308c3a075Sskrll 
3475b842b8Sskrll #include <sys/cdefs.h>
35*e82e6746Sskrll __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.7 2024/08/10 07:27:04 skrll Exp $");
3675b842b8Sskrll 
3775b842b8Sskrll #include <sys/param.h>
3875b842b8Sskrll 
3975b842b8Sskrll #include <sys/cpu.h>
4075b842b8Sskrll #include <sys/device.h>
4108c3a075Sskrll #include <sys/kmem.h>
4208c3a075Sskrll #include <sys/reboot.h>
4375b842b8Sskrll #include <sys/sysctl.h>
4475b842b8Sskrll 
4575b842b8Sskrll #include <riscv/cpu.h>
4675b842b8Sskrll #include <riscv/cpuvar.h>
4708c3a075Sskrll #include <riscv/machdep.h>
4808c3a075Sskrll #include <riscv/sbi.h>
4975b842b8Sskrll 
5075b842b8Sskrll #ifdef MULTIPROCESSOR
5175b842b8Sskrll #define NCPUINFO	MAXCPUS
5275b842b8Sskrll #else
5375b842b8Sskrll #define NCPUINFO	1
5475b842b8Sskrll #endif /* MULTIPROCESSOR */
5575b842b8Sskrll 
5675b842b8Sskrll static void
5775b842b8Sskrll cache_nullop(vaddr_t va, paddr_t pa, psize_t sz)
5875b842b8Sskrll {
5975b842b8Sskrll }
6075b842b8Sskrll 
6175b842b8Sskrll void (*cpu_sdcache_wbinv_range)(vaddr_t, paddr_t, psize_t) = cache_nullop;
6275b842b8Sskrll void (*cpu_sdcache_inv_range)(vaddr_t, paddr_t, psize_t) = cache_nullop;
6375b842b8Sskrll void (*cpu_sdcache_wb_range)(vaddr_t, paddr_t, psize_t) = cache_nullop;
6475b842b8Sskrll 
6575b842b8Sskrll u_int   riscv_dcache_align = CACHE_LINE_SIZE;
6675b842b8Sskrll u_int   riscv_dcache_align_mask = CACHE_LINE_SIZE - 1;
6775b842b8Sskrll 
6808c3a075Sskrll #define CPU_VENDOR_SIFIVE	0x489
6908c3a075Sskrll 
7008c3a075Sskrll #define CPU_ARCH_7SERIES	0x8000000000000007
7108c3a075Sskrll 
72*e82e6746Sskrll #define CPU_VENDOR_THEAD	0x5b7
73*e82e6746Sskrll 
7408c3a075Sskrll struct cpu_arch {
7508c3a075Sskrll 	uint64_t	 ca_id;
7608c3a075Sskrll 	const char	*ca_name;
7708c3a075Sskrll };
7808c3a075Sskrll 
7908c3a075Sskrll struct cpu_arch cpu_arch_sifive[] = {
8008c3a075Sskrll     {
8108c3a075Sskrll 	.ca_id = CPU_ARCH_7SERIES,
8208c3a075Sskrll 	.ca_name = "7-Series Processor (E7, S7, U7 series)",
8308c3a075Sskrll     },
8408c3a075Sskrll     { },	// terminator
8508c3a075Sskrll };
8608c3a075Sskrll 
87*e82e6746Sskrll struct cpu_arch cpu_arch_thead[] = {
88*e82e6746Sskrll     {
89*e82e6746Sskrll 	.ca_id = 0,
90*e82e6746Sskrll 	.ca_name = "9-Series Processor (C9, E9 series)",
91*e82e6746Sskrll     },
92*e82e6746Sskrll     { },	// terminator
93*e82e6746Sskrll };
94*e82e6746Sskrll 
9508c3a075Sskrll struct cpu_vendor {
9608c3a075Sskrll 	uint32_t	 	 cv_id;
9708c3a075Sskrll 	const char		*cv_name;
9808c3a075Sskrll 	struct cpu_arch		*cv_arch;
9908c3a075Sskrll } cpu_vendors[] = {
10008c3a075Sskrll     {
10108c3a075Sskrll 	.cv_id = CPU_VENDOR_SIFIVE,
10208c3a075Sskrll 	.cv_name = "SiFive",
10308c3a075Sskrll 	.cv_arch = cpu_arch_sifive,
10408c3a075Sskrll     },
105*e82e6746Sskrll     {
106*e82e6746Sskrll 	.cv_id = CPU_VENDOR_THEAD,
107*e82e6746Sskrll 	.cv_name = "T-Head",
108*e82e6746Sskrll 	.cv_arch = cpu_arch_thead,
109*e82e6746Sskrll     },
11008c3a075Sskrll };
11108c3a075Sskrll 
11275b842b8Sskrll /*
1136345bad4Sskrll  * Our exported cpu_info structs; indexed by BP as 0 and APs [1, ncpu - 1]
11475b842b8Sskrll  */
11575b842b8Sskrll struct cpu_info cpu_info_store[NCPUINFO] = {
11675b842b8Sskrll 	[0] = {
11775b842b8Sskrll 		.ci_cpl = IPL_HIGH,
11808c3a075Sskrll 		.ci_curlwp = &lwp0,
11908c3a075Sskrll 		.ci_tlb_info = &pmap_tlb0_info,
120f2a6e48eSskrll #ifdef MULTIPROCESSOR
12108c3a075Sskrll 		.ci_flags = CPUF_PRIMARY | CPUF_PRESENT | CPUF_RUNNING,
12208c3a075Sskrll #endif
12375b842b8Sskrll 	}
12475b842b8Sskrll };
12575b842b8Sskrll 
12675b842b8Sskrll /*
12775b842b8Sskrll  * setup the per-cpu sysctl tree.
12875b842b8Sskrll  */
12975b842b8Sskrll static void
13075b842b8Sskrll cpu_setup_sysctl(device_t dv, struct cpu_info *ci)
13175b842b8Sskrll {
13275b842b8Sskrll 	const struct sysctlnode *cpunode = NULL;
13375b842b8Sskrll 
13475b842b8Sskrll 	sysctl_createv(NULL, 0, NULL, &cpunode,
13575b842b8Sskrll 		       CTLFLAG_PERMANENT,
13675b842b8Sskrll 		       CTLTYPE_NODE, device_xname(dv), NULL,
13775b842b8Sskrll 		       NULL, 0, NULL, 0,
13875b842b8Sskrll 		       CTL_MACHDEP,
13975b842b8Sskrll 		       CTL_CREATE, CTL_EOL);
14075b842b8Sskrll 
14175b842b8Sskrll 	if (cpunode == NULL)
14275b842b8Sskrll 		return;
14375b842b8Sskrll }
14475b842b8Sskrll 
14575b842b8Sskrll 
14608c3a075Sskrll static void
14708c3a075Sskrll cpu_identify(device_t self, struct cpu_info *ci)
14808c3a075Sskrll {
14908c3a075Sskrll 	const register_t mvendorid = sbi_get_mvendorid().value;
15008c3a075Sskrll 	const register_t marchid = sbi_get_marchid().value;
15108c3a075Sskrll 	const uint32_t mimpid = sbi_get_mimpid().value;
15208c3a075Sskrll 	struct cpu_arch *cv_arch = NULL;
15308c3a075Sskrll 	const char *cv_name = NULL;
15408c3a075Sskrll 	const char *ca_name = NULL;
15508c3a075Sskrll 	char vendor[128];
15608c3a075Sskrll 	char arch[128];
15708c3a075Sskrll 
15808c3a075Sskrll 	for (size_t i = 0; i < __arraycount(cpu_vendors); i++) {
15908c3a075Sskrll 		if (mvendorid == cpu_vendors[i].cv_id) {
16008c3a075Sskrll 			cv_name = cpu_vendors[i].cv_name;
16108c3a075Sskrll 			cv_arch = cpu_vendors[i].cv_arch;
16208c3a075Sskrll 			break;
16308c3a075Sskrll 		}
16408c3a075Sskrll 	}
16508c3a075Sskrll 
16608c3a075Sskrll 	if (cv_arch != NULL) {
16708c3a075Sskrll 		for (size_t i = 0; cv_arch[i].ca_name != NULL; i++) {
16808c3a075Sskrll 			if (marchid == cv_arch[i].ca_id) {
16908c3a075Sskrll 				ca_name = cv_arch[i].ca_name;
17008c3a075Sskrll 				break;
17108c3a075Sskrll 			}
17208c3a075Sskrll 		}
17308c3a075Sskrll 	}
17408c3a075Sskrll 
17508c3a075Sskrll 	if (cv_name == NULL) {
17608c3a075Sskrll 		snprintf(vendor, sizeof(vendor), "vendor %" PRIxREGISTER, mvendorid);
17708c3a075Sskrll 		cv_name = vendor;
17808c3a075Sskrll 	}
17908c3a075Sskrll 	if (ca_name == NULL) {
18008c3a075Sskrll 		snprintf(arch, sizeof(arch), "arch %" PRIxREGISTER, marchid);
18108c3a075Sskrll 		ca_name = arch;
18208c3a075Sskrll 	}
18308c3a075Sskrll 
18408c3a075Sskrll 	aprint_naive("\n");
18508c3a075Sskrll 	aprint_normal(": %s %s imp. %" PRIx32 "\n", cv_name, ca_name, mimpid);
18608c3a075Sskrll         aprint_verbose_dev(ci->ci_dev,
18708c3a075Sskrll 	    "vendor 0x%" PRIxREGISTER " arch. %" PRIxREGISTER " imp. %" PRIx32 "\n",
18808c3a075Sskrll 	    mvendorid, marchid, mimpid);
18908c3a075Sskrll }
19008c3a075Sskrll 
19108c3a075Sskrll 
19275b842b8Sskrll void
1936345bad4Sskrll cpu_attach(device_t dv, cpuid_t hartid)
19475b842b8Sskrll {
19508c3a075Sskrll 	struct cpu_info *ci;
19675b842b8Sskrll 
1976345bad4Sskrll 	/* Check for the BP */
1986345bad4Sskrll 	if (hartid == cpu_bphartid) {
19975b842b8Sskrll 		ci = curcpu();
2006345bad4Sskrll 		KASSERTMSG(ci == &cpu_info_store[0], "ci %p", ci);
2016345bad4Sskrll 		ci->ci_cpuid = hartid;
202876e9811Sriastradh 		ci->ci_cpu_freq = riscv_timer_frequency_get();
20375b842b8Sskrll 	} else {
20475b842b8Sskrll #ifdef MULTIPROCESSOR
20575b842b8Sskrll 		if ((boothowto & RB_MD1) != 0) {
20675b842b8Sskrll 			aprint_naive("\n");
20775b842b8Sskrll 			aprint_normal(": multiprocessor boot disabled\n");
20875b842b8Sskrll 			return;
20975b842b8Sskrll 		}
21075b842b8Sskrll 
2116345bad4Sskrll 		KASSERT(hartid < MAXCPUS);
2126345bad4Sskrll 		KASSERT(cpu_hartindex[hartid] < MAXCPUS);
2136345bad4Sskrll 
2146345bad4Sskrll 		ci = &cpu_info_store[cpu_hartindex[hartid]];
21575b842b8Sskrll 
21675b842b8Sskrll 		ci->ci_cpl = IPL_HIGH;
2176345bad4Sskrll 		ci->ci_cpuid = hartid;
21875b842b8Sskrll 
2196345bad4Sskrll 		if (!cpu_hatched_p(cpu_hartindex[hartid])) {
22075b842b8Sskrll 			ci->ci_dev = dv;
22175b842b8Sskrll 			device_set_private(dv, ci);
22275b842b8Sskrll 			ci->ci_index = -1;
22375b842b8Sskrll 
22475b842b8Sskrll 			aprint_naive(": disabled\n");
22575b842b8Sskrll 			aprint_normal(": disabled (unresponsive)\n");
22675b842b8Sskrll 			return;
22775b842b8Sskrll 		}
22875b842b8Sskrll #else /* MULTIPROCESSOR */
22975b842b8Sskrll 		aprint_naive(": disabled\n");
23075b842b8Sskrll 		aprint_normal(": disabled (uniprocessor kernel)\n");
23175b842b8Sskrll 		return;
23275b842b8Sskrll #endif /* MULTIPROCESSOR */
23375b842b8Sskrll 	}
23475b842b8Sskrll 
23575b842b8Sskrll 	ci->ci_dev = dv;
23675b842b8Sskrll 	device_set_private(dv, ci);
23708c3a075Sskrll 
23808c3a075Sskrll 	cpu_identify(dv, ci);
23975b842b8Sskrll 
24075b842b8Sskrll #ifdef MULTIPROCESSOR
24108c3a075Sskrll 	kcpuset_create(&ci->ci_shootdowncpus, true);
24208c3a075Sskrll 
24308c3a075Sskrll 	ipi_init(ci);
24408c3a075Sskrll 
24508c3a075Sskrll 	kcpuset_create(&ci->ci_multicastcpus, true);
24608c3a075Sskrll 	kcpuset_create(&ci->ci_watchcpus, true);
24708c3a075Sskrll 	kcpuset_create(&ci->ci_ddbcpus, true);
24808c3a075Sskrll 
2496345bad4Sskrll 	if (hartid != cpu_bphartid) {
25075b842b8Sskrll 		mi_cpu_attach(ci);
25175b842b8Sskrll 	}
25275b842b8Sskrll #endif /* MULTIPROCESSOR */
25308c3a075Sskrll 	cpu_setup_sysctl(dv, ci);
25475b842b8Sskrll }
25575b842b8Sskrll 
25675b842b8Sskrll #ifdef MULTIPROCESSOR
25775b842b8Sskrll /*
25875b842b8Sskrll  * Initialise a secondary processor.
25975b842b8Sskrll  *
26075b842b8Sskrll  * printf isn't available as kmutex(9) relies on curcpu which isn't setup yet.
26175b842b8Sskrll  *
26275b842b8Sskrll  */
26375b842b8Sskrll void __noasan
2646345bad4Sskrll cpu_init_secondary_processor(u_int cpuindex)
26575b842b8Sskrll {
26608c3a075Sskrll 	cpu_set_hatched(cpuindex);
26775b842b8Sskrll 
26808c3a075Sskrll 	/*
26908c3a075Sskrll 	 * return to assembly to wait for cpu_boot_secondary_processors
27008c3a075Sskrll 	 */
27175b842b8Sskrll }
27275b842b8Sskrll 
27375b842b8Sskrll 
27475b842b8Sskrll /*
27575b842b8Sskrll  * When we are called, the MMU and caches are on and we are running on the stack
27675b842b8Sskrll  * of the idlelwp for this cpu.
27775b842b8Sskrll  */
27875b842b8Sskrll void
2796345bad4Sskrll cpu_hatch(struct cpu_info *ci, unsigned long cpuindex)
28075b842b8Sskrll {
28175b842b8Sskrll 	KASSERT(curcpu() == ci);
28208c3a075Sskrll 
2836345bad4Sskrll 	// Show this CPU as present.
2846345bad4Sskrll 	atomic_or_ulong(&ci->ci_flags, CPUF_PRESENT);
2856345bad4Sskrll 
28608c3a075Sskrll 	ci->ci_cpu_freq = riscv_timer_frequency_get();
28708c3a075Sskrll 
28808c3a075Sskrll 	riscv_timer_init();
28908c3a075Sskrll 
2906345bad4Sskrll 	kcpuset_set(cpus_hatched, cpu_index(ci));
2916345bad4Sskrll 	kcpuset_set(cpus_running, cpu_index(ci));
2926345bad4Sskrll 
29308c3a075Sskrll 	/*
29408c3a075Sskrll 	 * clear my bit of the mailbox to tell cpu_boot_secondary_processors().
29508c3a075Sskrll 	 * Consider that if there are cpu0, 1, 2, 3, and cpu2 is unresponsive,
29608c3a075Sskrll 	 * ci_index for each would be cpu0=0, cpu1=1, cpu2=undef, cpu3=2.
29708c3a075Sskrll 	 * therefore we have to use device_unit instead of ci_index for mbox.
29808c3a075Sskrll 	 */
29908c3a075Sskrll 
3006345bad4Sskrll 	cpu_clr_mbox(cpuindex);
30175b842b8Sskrll }
30275b842b8Sskrll #endif /* MULTIPROCESSOR */
303