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