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