#include "opt_multiprocessor.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.11 2026/03/18 06:41:41 skrll Exp $");
#include <sys/param.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/kmem.h>
#include <sys/reboot.h>
#include <sys/sysctl.h>
#include <riscv/cpu.h>
#include <riscv/cpuvar.h>
#include <riscv/machdep.h>
#include <riscv/sbi.h>
#include <riscv/sysreg.h>
#ifdef MULTIPROCESSOR
#define NCPUINFO MAXCPUS
#else
#define NCPUINFO 1
#endif
struct cpu_arch {
uint64_t ca_id;
const char *ca_name;
};
struct cpu_arch cpu_arch_sifive[] = {
{
.ca_id = CPU_SIFIVE_ARCH_7SERIES,
.ca_name = "7-Series Processor (E7, S7, U7 series)",
},
{ },
};
struct cpu_arch cpu_arch_thead[] = {
{
.ca_id = 0,
.ca_name = "9-Series Processor (C9, E9 series)",
},
{ },
};
struct cpu_vendor {
uint32_t cv_id;
const char *cv_name;
struct cpu_arch *cv_arch;
} cpu_vendors[] = {
{
.cv_id = CPU_VENDOR_SIFIVE,
.cv_name = "SiFive",
.cv_arch = cpu_arch_sifive,
},
{
.cv_id = CPU_VENDOR_THEAD,
.cv_name = "T-Head",
.cv_arch = cpu_arch_thead,
},
};
struct cpu_info cpu_info_store[NCPUINFO] = {
[0] = {
.ci_cpl = IPL_HIGH,
.ci_curlwp = &lwp0,
.ci_tlb_info = &pmap_tlb0_info,
#ifdef MULTIPROCESSOR
.ci_flags = CPUF_PRIMARY | CPUF_PRESENT | CPUF_RUNNING,
#endif
}
};
static void
cpu_setup_sysctl(device_t dv, struct cpu_info *ci)
{
const struct sysctlnode *cpunode = NULL;
sysctl_createv(NULL, 0, NULL, &cpunode,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, device_xname(dv), NULL,
NULL, 0, NULL, 0,
CTL_MACHDEP,
CTL_CREATE, CTL_EOL);
if (cpunode == NULL)
return;
}
static void
cpu_identify(device_t self, struct cpu_info *ci)
{
const register_t mvendorid = sbi_get_mvendorid().value;
const register_t marchid = sbi_get_marchid().value;
const uint32_t mimpid = sbi_get_mimpid().value;
struct cpu_arch *cv_arch = NULL;
const char *cv_name = NULL;
const char *ca_name = NULL;
char vendor[128];
char arch[128];
for (size_t i = 0; i < __arraycount(cpu_vendors); i++) {
if (mvendorid == cpu_vendors[i].cv_id) {
cv_name = cpu_vendors[i].cv_name;
cv_arch = cpu_vendors[i].cv_arch;
break;
}
}
if (cv_arch != NULL) {
for (size_t i = 0; cv_arch[i].ca_name != NULL; i++) {
if (marchid == cv_arch[i].ca_id) {
ca_name = cv_arch[i].ca_name;
break;
}
}
}
if (cv_name == NULL) {
snprintf(vendor, sizeof(vendor), "vendor %" PRIxREGISTER, mvendorid);
cv_name = vendor;
}
if (ca_name == NULL) {
snprintf(arch, sizeof(arch), "arch %" PRIxREGISTER, marchid);
ca_name = arch;
}
aprint_naive("\n");
aprint_normal(": %s %s imp. %" PRIx32 "\n", cv_name, ca_name, mimpid);
aprint_verbose_dev(ci->ci_dev,
"vendor 0x%" PRIxREGISTER " arch. %" PRIxREGISTER " imp. %" PRIx32 "\n",
mvendorid, marchid, mimpid);
}
void
cpu_attach(device_t dv, cpuid_t hartid)
{
struct cpu_info *ci;
if (hartid == cpu_bphartid) {
ci = curcpu();
KASSERTMSG(ci == &cpu_info_store[0], "ci %p", ci);
ci->ci_cpuid = hartid;
ci->ci_cpu_freq = riscv_timer_frequency_get();
} else {
#ifdef MULTIPROCESSOR
if ((boothowto & RB_MD1) != 0) {
aprint_naive("\n");
aprint_normal(": multiprocessor boot disabled\n");
return;
}
KASSERT(hartid < MAXCPUS);
KASSERT(cpu_hartindex[hartid] < MAXCPUS);
ci = &cpu_info_store[cpu_hartindex[hartid]];
ci->ci_cpl = IPL_HIGH;
ci->ci_cpuid = hartid;
if (!cpu_hatched_p(cpu_hartindex[hartid])) {
ci->ci_dev = dv;
device_set_private(dv, ci);
ci->ci_index = -1;
aprint_naive(": disabled\n");
aprint_normal(": disabled (unresponsive)\n");
return;
}
#else
aprint_naive(": disabled\n");
aprint_normal(": disabled (uniprocessor kernel)\n");
return;
#endif
}
ci->ci_dev = dv;
device_set_private(dv, ci);
const char * const xname = device_xname(dv);
evcnt_attach_dynamic(&ci->ci_ev_fpu_loads, EVCNT_TYPE_MISC, NULL,
xname, "fpu loads");
evcnt_attach_dynamic(&ci->ci_ev_fpu_saves, EVCNT_TYPE_MISC, NULL,
xname, "fpu saves");
evcnt_attach_dynamic(&ci->ci_ev_fpu_reenables, EVCNT_TYPE_MISC, NULL,
xname, "fpu reenables");
cpu_identify(dv, ci);
#ifdef MULTIPROCESSOR
kcpuset_create(&ci->ci_shootdowncpus, true);
ipi_init(ci);
kcpuset_create(&ci->ci_multicastcpus, true);
kcpuset_create(&ci->ci_watchcpus, true);
kcpuset_create(&ci->ci_ddbcpus, true);
if (hartid != cpu_bphartid) {
mi_cpu_attach(ci);
}
#endif
cpu_setup_sysctl(dv, ci);
}
#ifdef MULTIPROCESSOR
void __noasan
cpu_init_secondary_processor(u_int cpuindex)
{
cpu_set_hatched(cpuindex);
}
void
cpu_hatch(struct cpu_info *ci, unsigned long cpuindex)
{
KASSERT(curcpu() == ci);
atomic_or_ulong(&ci->ci_flags, CPUF_PRESENT);
ci->ci_cpu_freq = riscv_timer_frequency_get();
riscv_timer_init();
kcpuset_set(cpus_hatched, cpu_index(ci));
kcpuset_set(cpus_running, cpu_index(ci));
cpu_clr_mbox(cpuindex);
}
#endif