Home | History | Annotate | Line # | Download | only in riscv
cpu.c revision 1.3
      1  1.3  skrll /*	$NetBSD: cpu.c,v 1.3 2023/06/24 07:23:07 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.3  skrll __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.3 2023/06/24 07:23:07 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.2  skrll struct cpu_arch {
     73  1.2  skrll 	uint64_t	 ca_id;
     74  1.2  skrll 	const char	*ca_name;
     75  1.2  skrll };
     76  1.2  skrll 
     77  1.2  skrll struct cpu_arch cpu_arch_sifive[] = {
     78  1.2  skrll     {
     79  1.2  skrll 	.ca_id = CPU_ARCH_7SERIES,
     80  1.2  skrll 	.ca_name = "7-Series Processor (E7, S7, U7 series)",
     81  1.2  skrll     },
     82  1.2  skrll     { },	// terminator
     83  1.2  skrll };
     84  1.2  skrll 
     85  1.2  skrll struct cpu_vendor {
     86  1.2  skrll 	uint32_t	 	 cv_id;
     87  1.2  skrll 	const char		*cv_name;
     88  1.2  skrll 	struct cpu_arch		*cv_arch;
     89  1.2  skrll } cpu_vendors[] = {
     90  1.2  skrll     {
     91  1.2  skrll 	.cv_id = CPU_VENDOR_SIFIVE,
     92  1.2  skrll 	.cv_name = "SiFive",
     93  1.2  skrll 	.cv_arch = cpu_arch_sifive,
     94  1.2  skrll     },
     95  1.2  skrll };
     96  1.2  skrll 
     97  1.1  skrll /*
     98  1.1  skrll  * Our exported cpu_info structs; these will be first used by the
     99  1.1  skrll  * secondary cpus as part of cpu_mpstart and the hatching process.
    100  1.1  skrll  */
    101  1.1  skrll struct cpu_info cpu_info_store[NCPUINFO] = {
    102  1.1  skrll 	[0] = {
    103  1.1  skrll 		.ci_cpl = IPL_HIGH,
    104  1.2  skrll 		.ci_curlwp = &lwp0,
    105  1.2  skrll 		.ci_cpl = IPL_HIGH,
    106  1.3  skrll 		.ci_tlb_info = &pmap_tlb0_info,
    107  1.2  skrll #ifdef MULTIPROCESSOR
    108  1.2  skrll 		.ci_flags = CPUF_PRIMARY | CPUF_PRESENT | CPUF_RUNNING,
    109  1.2  skrll #endif
    110  1.1  skrll 	}
    111  1.1  skrll };
    112  1.1  skrll 
    113  1.1  skrll 
    114  1.1  skrll /*
    115  1.1  skrll  * setup the per-cpu sysctl tree.
    116  1.1  skrll  */
    117  1.1  skrll static void
    118  1.1  skrll cpu_setup_sysctl(device_t dv, struct cpu_info *ci)
    119  1.1  skrll {
    120  1.1  skrll 	const struct sysctlnode *cpunode = NULL;
    121  1.1  skrll 
    122  1.1  skrll 	sysctl_createv(NULL, 0, NULL, &cpunode,
    123  1.1  skrll 		       CTLFLAG_PERMANENT,
    124  1.1  skrll 		       CTLTYPE_NODE, device_xname(dv), NULL,
    125  1.1  skrll 		       NULL, 0, NULL, 0,
    126  1.1  skrll 		       CTL_MACHDEP,
    127  1.1  skrll 		       CTL_CREATE, CTL_EOL);
    128  1.1  skrll 
    129  1.1  skrll 	if (cpunode == NULL)
    130  1.1  skrll 		return;
    131  1.1  skrll }
    132  1.1  skrll 
    133  1.1  skrll 
    134  1.2  skrll static void
    135  1.2  skrll cpu_identify(device_t self, struct cpu_info *ci)
    136  1.2  skrll {
    137  1.2  skrll 	const register_t mvendorid = sbi_get_mvendorid().value;
    138  1.2  skrll 	const register_t marchid = sbi_get_marchid().value;
    139  1.2  skrll 	const uint32_t mimpid = sbi_get_mimpid().value;
    140  1.2  skrll 	struct cpu_arch *cv_arch = NULL;
    141  1.2  skrll 	const char *cv_name = NULL;
    142  1.2  skrll 	const char *ca_name = NULL;
    143  1.2  skrll 	char vendor[128];
    144  1.2  skrll 	char arch[128];
    145  1.2  skrll 
    146  1.2  skrll 	for (size_t i = 0; i < __arraycount(cpu_vendors); i++) {
    147  1.2  skrll 		if (mvendorid == cpu_vendors[i].cv_id) {
    148  1.2  skrll 			cv_name = cpu_vendors[i].cv_name;
    149  1.2  skrll 			cv_arch = cpu_vendors[i].cv_arch;
    150  1.2  skrll 			break;
    151  1.2  skrll 		}
    152  1.2  skrll 	}
    153  1.2  skrll 
    154  1.2  skrll 	if (cv_arch != NULL) {
    155  1.2  skrll 		for (size_t i = 0; cv_arch[i].ca_name != NULL; i++) {
    156  1.2  skrll 			if (marchid == cv_arch[i].ca_id) {
    157  1.2  skrll 				ca_name = cv_arch[i].ca_name;
    158  1.2  skrll 				break;
    159  1.2  skrll 			}
    160  1.2  skrll 		}
    161  1.2  skrll 	}
    162  1.2  skrll 
    163  1.2  skrll 	if (cv_name == NULL) {
    164  1.2  skrll 		snprintf(vendor, sizeof(vendor), "vendor %" PRIxREGISTER, mvendorid);
    165  1.2  skrll 		cv_name = vendor;
    166  1.2  skrll 	}
    167  1.2  skrll 	if (ca_name == NULL) {
    168  1.2  skrll 		snprintf(arch, sizeof(arch), "arch %" PRIxREGISTER, marchid);
    169  1.2  skrll 		ca_name = arch;
    170  1.2  skrll 	}
    171  1.2  skrll 
    172  1.2  skrll 	aprint_naive("\n");
    173  1.2  skrll 	aprint_normal(": %s %s imp. %" PRIx32 "\n", cv_name, ca_name, mimpid);
    174  1.2  skrll         aprint_verbose_dev(ci->ci_dev,
    175  1.2  skrll 	    "vendor 0x%" PRIxREGISTER " arch. %" PRIxREGISTER " imp. %" PRIx32 "\n",
    176  1.2  skrll 	    mvendorid, marchid, mimpid);
    177  1.2  skrll }
    178  1.2  skrll 
    179  1.2  skrll 
    180  1.1  skrll void
    181  1.1  skrll cpu_attach(device_t dv, cpuid_t id)
    182  1.1  skrll {
    183  1.1  skrll 	const int unit = device_unit(dv);
    184  1.2  skrll 	struct cpu_info *ci;
    185  1.1  skrll 
    186  1.1  skrll 	if (unit == 0) {
    187  1.1  skrll 		ci = curcpu();
    188  1.1  skrll 		ci->ci_cpuid = id;
    189  1.1  skrll 	} else {
    190  1.1  skrll #ifdef MULTIPROCESSOR
    191  1.1  skrll 		if ((boothowto & RB_MD1) != 0) {
    192  1.1  skrll 			aprint_naive("\n");
    193  1.1  skrll 			aprint_normal(": multiprocessor boot disabled\n");
    194  1.1  skrll 			return;
    195  1.1  skrll 		}
    196  1.1  skrll 
    197  1.1  skrll 		KASSERT(unit < MAXCPUS);
    198  1.1  skrll 		ci = &cpu_info_store[unit];
    199  1.1  skrll 
    200  1.1  skrll 		ci->ci_cpl = IPL_HIGH;
    201  1.1  skrll 		ci->ci_cpuid = id;
    202  1.1  skrll 		/* ci_cpuid is stored by own cpus when hatching */
    203  1.1  skrll 
    204  1.1  skrll 		if (cpu_hatched_p(unit) == 0) {
    205  1.1  skrll 			ci->ci_dev = dv;
    206  1.1  skrll 			device_set_private(dv, ci);
    207  1.1  skrll 			ci->ci_index = -1;
    208  1.1  skrll 
    209  1.1  skrll 			aprint_naive(": disabled\n");
    210  1.1  skrll 			aprint_normal(": disabled (unresponsive)\n");
    211  1.1  skrll 			return;
    212  1.1  skrll 		}
    213  1.1  skrll #else /* MULTIPROCESSOR */
    214  1.1  skrll 		aprint_naive(": disabled\n");
    215  1.1  skrll 		aprint_normal(": disabled (uniprocessor kernel)\n");
    216  1.1  skrll 		return;
    217  1.1  skrll #endif /* MULTIPROCESSOR */
    218  1.1  skrll 	}
    219  1.1  skrll 
    220  1.1  skrll 	ci->ci_dev = dv;
    221  1.1  skrll 	device_set_private(dv, ci);
    222  1.2  skrll 
    223  1.2  skrll 	cpu_identify(dv, ci);
    224  1.1  skrll 
    225  1.1  skrll #ifdef MULTIPROCESSOR
    226  1.2  skrll 	kcpuset_create(&ci->ci_shootdowncpus, true);
    227  1.2  skrll 
    228  1.2  skrll 	ipi_init(ci);
    229  1.2  skrll 
    230  1.2  skrll 	kcpuset_create(&ci->ci_multicastcpus, true);
    231  1.2  skrll 	kcpuset_create(&ci->ci_watchcpus, true);
    232  1.2  skrll 	kcpuset_create(&ci->ci_ddbcpus, true);
    233  1.2  skrll 
    234  1.1  skrll 	if (unit != 0) {
    235  1.1  skrll 		mi_cpu_attach(ci);
    236  1.2  skrll 		struct pmap_tlb_info *ti = kmem_zalloc(sizeof(*ti), KM_SLEEP);
    237  1.2  skrll 		pmap_tlb_info_init(ti);
    238  1.2  skrll 		pmap_tlb_info_attach(ti, ci);
    239  1.1  skrll 	}
    240  1.1  skrll #endif /* MULTIPROCESSOR */
    241  1.2  skrll 	cpu_setup_sysctl(dv, ci);
    242  1.1  skrll 
    243  1.1  skrll 	if (unit != 0) {
    244  1.1  skrll 	    return;
    245  1.1  skrll 	}
    246  1.1  skrll }
    247  1.1  skrll 
    248  1.1  skrll #ifdef MULTIPROCESSOR
    249  1.1  skrll /*
    250  1.1  skrll  * Initialise a secondary processor.
    251  1.1  skrll  *
    252  1.1  skrll  * printf isn't available as kmutex(9) relies on curcpu which isn't setup yet.
    253  1.1  skrll  *
    254  1.1  skrll  */
    255  1.1  skrll void __noasan
    256  1.1  skrll cpu_init_secondary_processor(int cpuindex)
    257  1.1  skrll {
    258  1.2  skrll 	cpu_set_hatched(cpuindex);
    259  1.1  skrll 
    260  1.2  skrll 	/*
    261  1.2  skrll 	 * return to assembly to wait for cpu_boot_secondary_processors
    262  1.2  skrll 	 */
    263  1.1  skrll }
    264  1.1  skrll 
    265  1.1  skrll 
    266  1.1  skrll /*
    267  1.1  skrll  * When we are called, the MMU and caches are on and we are running on the stack
    268  1.1  skrll  * of the idlelwp for this cpu.
    269  1.1  skrll  */
    270  1.1  skrll void
    271  1.1  skrll cpu_hatch(struct cpu_info *ci)
    272  1.1  skrll {
    273  1.1  skrll 	KASSERT(curcpu() == ci);
    274  1.2  skrll 
    275  1.2  skrll 	ci->ci_cpu_freq = riscv_timer_frequency_get();
    276  1.2  skrll 
    277  1.2  skrll 	riscv_timer_init();
    278  1.2  skrll 
    279  1.2  skrll 	/*
    280  1.2  skrll 	 * clear my bit of the mailbox to tell cpu_boot_secondary_processors().
    281  1.2  skrll 	 * Consider that if there are cpu0, 1, 2, 3, and cpu2 is unresponsive,
    282  1.2  skrll 	 * ci_index for each would be cpu0=0, cpu1=1, cpu2=undef, cpu3=2.
    283  1.2  skrll 	 * therefore we have to use device_unit instead of ci_index for mbox.
    284  1.2  skrll 	 */
    285  1.2  skrll 
    286  1.2  skrll 	cpu_clr_mbox(device_unit(ci->ci_dev));
    287  1.1  skrll }
    288  1.1  skrll #endif /* MULTIPROCESSOR */
    289