#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.260 2021/05/29 02:58:37 mrg Exp $");
#include "opt_multiprocessor.h"
#include "opt_lockdebug.h"
#include "opt_ddb.h"
#include "opt_sparc_arch.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/evcnt.h>
#include <sys/xcall.h>
#include <sys/ipi.h>
#include <sys/cpu.h>
#include <sys/reboot.h>
#include <sys/sysctl.h>
#include <sys/kmem.h>
#include <uvm/uvm.h>
#include <machine/promlib.h>
#include <machine/autoconf.h>
#include <machine/cpu.h>
#include <machine/reg.h>
#include <machine/ctlreg.h>
#include <machine/trap.h>
#include <machine/pcb.h>
#include <machine/pmap.h>
#include <machine/locore.h>
#if defined(MULTIPROCESSOR) && defined(DDB)
#include <ddb/db_output.h>
#include <machine/db_machdep.h>
#endif
#include <sparc/sparc/cache.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/cpuvar.h>
#include <sparc/sparc/memreg.h>
#include <sparc/sparc/cache_print.h>
#if defined(SUN4D)
#include <sparc/sparc/cpuunitvar.h>
#endif
#ifdef DEBUG
#ifndef DEBUG_XCALL
#define DEBUG_XCALL 0
#endif
int debug_xcall = DEBUG_XCALL;
#else
#define debug_xcall 0
#endif
struct cpu_softc {
device_t sc_dev;
struct cpu_info *sc_cpuinfo;
};
char machine[] = MACHINE;
char machine_arch[] = MACHINE_ARCH;
int cpu_arch;
int sparc_ncpus;
struct cpu_info *cpus[_MAXNCPU+1];
static void cpu_mainbus_attach(device_t, device_t, void *);
int cpu_mainbus_match(device_t, cfdata_t, void *);
CFATTACH_DECL_NEW(cpu_mainbus, sizeof(struct cpu_softc),
cpu_mainbus_match, cpu_mainbus_attach, NULL, NULL);
#if defined(SUN4D)
static int cpu_cpuunit_match(device_t, cfdata_t, void *);
static void cpu_cpuunit_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(cpu_cpuunit, sizeof(struct cpu_softc),
cpu_cpuunit_match, cpu_cpuunit_attach, NULL, NULL);
#endif
static void cpu_setup_sysctl(struct cpu_softc *);
static void cpu_init_evcnt(struct cpu_info *);
static void cpu_attach(struct cpu_softc *, int, int);
static const char *fsrtoname(int, int, int);
static void cache_print(struct cpu_softc *);
void cpu_setup(void);
void fpu_init(struct cpu_info *);
#define IU_IMPL(psr) ((u_int)(psr) >> 28)
#define IU_VERS(psr) (((psr) >> 24) & 0xf)
#define SRMMU_IMPL(mmusr) ((u_int)(mmusr) >> 28)
#define SRMMU_VERS(mmusr) (((mmusr) >> 24) & 0xf)
int bootmid;
#ifdef notdef
static char *iu_vendor[16] = {
"Fujitsu",
"ROSS",
"BIT",
"LSIL",
"TI",
"Matsushita",
"Philips",
"Harvest",
"SPEC",
"Weitek",
"vendor#10",
"vendor#11",
"vendor#12",
"vendor#13",
"vendor#14",
"vendor#15"
};
#endif
#if defined(MULTIPROCESSOR)
u_int cpu_ready_mask;
void cpu_spinup(struct cpu_info *);
static void cpu_attach_non_boot(struct cpu_softc *, struct cpu_info *, int);
int go_smp_cpus = 0;
kmutex_t xpmsg_mutex;
#endif
int
cpu_mainbus_match(device_t parent, cfdata_t cf, void *aux)
{
struct mainbus_attach_args *ma = aux;
return (strcmp(cf->cf_name, ma->ma_name) == 0);
}
static void
cpu_mainbus_attach(device_t parent, device_t self, void *aux)
{
struct mainbus_attach_args *ma = aux;
struct { uint32_t va; uint32_t size; } *mbprop = NULL;
struct openprom_addr *rrp = NULL;
struct cpu_info *cpi;
struct cpu_softc *sc;
int mid, node;
int error, n;
node = ma->ma_node;
mid = (node != 0) ? prom_getpropint(node, "mid", 0) : 0;
sc = device_private(self);
sc->sc_dev = self;
cpu_attach(sc, node, mid);
cpi = sc->sc_cpuinfo;
if (cpi == NULL)
return;
if (node != 0 && (error = prom_getprop(node, "mailbox-virtual",
sizeof(*mbprop),
&n, &mbprop)) == 0) {
cpi->mailbox = mbprop->va;
free(mbprop, M_DEVBUF);
} else if (node != 0 && (error = prom_getprop(node, "mailbox",
sizeof(struct openprom_addr),
&n, &rrp)) == 0) {
if (rrp[0].oa_space == 0)
printf("%s: mailbox in mem space\n", device_xname(self));
if (bus_space_map(ma->ma_bustag,
BUS_ADDR(rrp[0].oa_space, rrp[0].oa_base),
rrp[0].oa_size,
BUS_SPACE_MAP_LINEAR,
&cpi->mailbox) != 0)
panic("%s: can't map CPU mailbox", device_xname(self));
free(rrp, M_DEVBUF);
}
if (cpi->mxcc == 0)
return;
rrp = NULL;
if (node == 0 || (error = prom_getprop(node, "reg",
sizeof(struct openprom_addr),
&n, &rrp)) != 0)
return;
if (bus_space_map(ma->ma_bustag,
BUS_ADDR(rrp[0].oa_space, rrp[0].oa_base),
rrp[0].oa_size,
BUS_SPACE_MAP_LINEAR,
&cpi->ci_mbusport) != 0) {
panic("%s: can't map CPU regs", device_xname(self));
}
if (bus_space_map(ma->ma_bustag,
BUS_ADDR(rrp[1].oa_space, rrp[1].oa_base),
rrp[1].oa_size,
BUS_SPACE_MAP_LINEAR,
&cpi->ci_mxccregs) != 0) {
panic("%s: can't map CPU regs", device_xname(self));
}
free(rrp, M_DEVBUF);
}
#if defined(SUN4D)
static int
cpu_cpuunit_match(device_t parent, cfdata_t cf, void *aux)
{
struct cpuunit_attach_args *cpua = aux;
return (strcmp(cf->cf_name, cpua->cpua_type) == 0);
}
static void
cpu_cpuunit_attach(device_t parent, device_t self, void *aux)
{
struct cpuunit_attach_args *cpua = aux;
struct cpu_softc *sc = device_private(self);
sc->sc_dev = self;
cpu_attach(sc, cpua->cpua_node, cpua->cpua_device_id);
}
#endif
static const char * const hard_intr_names[] = {
"spur hard",
"lev1 hard",
"lev2 hard",
"lev3 hard",
"lev4 hard",
"lev5 hard",
"lev6 hard",
"lev7 hard",
"lev8 hard",
"lev9 hard",
"clock hard",
"lev11 hard",
"lev12 hard",
"lev13 hard",
"prof hard",
"nmi hard",
};
static const char * const soft_intr_names[] = {
"spur soft",
"lev1 soft",
"lev2 soft",
"lev3 soft",
"lev4 soft",
"lev5 soft",
"lev6 soft",
"lev7 soft",
"lev8 soft",
"lev9 soft",
"lev10 soft",
"lev11 soft",
"lev12 soft",
"xcall std",
"xcall fast",
"nmi soft",
};
static void
cpu_init_evcnt(struct cpu_info *cpi)
{
int i;
evcnt_attach_dynamic(&cpi->ci_savefpstate, EVCNT_TYPE_INTR,
NULL, cpu_name(cpi), "savefp ipi");
evcnt_attach_dynamic(&cpi->ci_savefpstate_null, EVCNT_TYPE_MISC,
NULL, cpu_name(cpi), "savefp null ipi");
evcnt_attach_dynamic(&cpi->ci_xpmsg_mutex_fail, EVCNT_TYPE_MISC,
NULL, cpu_name(cpi), "IPI mutex_trylock fail");
evcnt_attach_dynamic(&cpi->ci_xpmsg_mutex_fail_call, EVCNT_TYPE_MISC,
NULL, cpu_name(cpi), "IPI mutex_trylock fail/call");
evcnt_attach_dynamic(&cpi->ci_xpmsg_mutex_not_held, EVCNT_TYPE_MISC,
NULL, cpu_name(cpi), "IPI with mutex not held");
evcnt_attach_dynamic(&cpi->ci_xpmsg_bogus, EVCNT_TYPE_MISC,
NULL, cpu_name(cpi), "bogus IPI");
for (i = 0; i < 16; i++) {
evcnt_attach_dynamic(&cpi->ci_intrcnt[i], EVCNT_TYPE_INTR,
NULL, cpu_name(cpi), hard_intr_names[i]);
evcnt_attach_dynamic(&cpi->ci_sintrcnt[i], EVCNT_TYPE_INTR,
NULL, cpu_name(cpi), soft_intr_names[i]);
}
}
static void
cpu_setup_sysctl(struct cpu_softc *sc)
{
struct cpu_info *ci = sc->sc_cpuinfo;
const struct sysctlnode *cpunode = NULL;
sysctl_createv(NULL, 0, NULL, &cpunode,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
NULL, 0, NULL, 0,
CTL_HW,
CTL_CREATE, CTL_EOL);
if (cpunode == NULL)
return;
#define SETUPS(name, member) \
sysctl_createv(NULL, 0, &cpunode, NULL, \
CTLFLAG_PERMANENT, \
CTLTYPE_STRING, name, NULL, \
NULL, 0, member, 0, \
CTL_CREATE, CTL_EOL);
SETUPS("name", __UNCONST(ci->cpu_longname))
SETUPS("fpuname", __UNCONST(ci->fpu_name))
#undef SETUPS
#define SETUPI(name, member) \
sysctl_createv(NULL, 0, &cpunode, NULL, \
CTLFLAG_PERMANENT, \
CTLTYPE_INT, name, NULL, \
NULL, 0, member, 0, \
CTL_CREATE, CTL_EOL);
SETUPI("mid", &ci->mid)
SETUPI("clock_frequency", &ci->hz)
SETUPI("psr_implementation", &ci->cpu_impl)
SETUPI("psr_version", &ci->cpu_vers)
SETUPI("mmu_implementation", &ci->mmu_impl)
SETUPI("mmu_version", &ci->mmu_vers)
SETUPI("mmu_nctx", &ci->mmu_ncontext)
#undef SETUPI
sysctl_createv(NULL, 0, &cpunode, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRUCT, "cacheinfo", NULL,
NULL, 0, &ci->cacheinfo, sizeof(ci->cacheinfo),
CTL_CREATE, CTL_EOL);
}
static void
cpu_attach(struct cpu_softc *sc, int node, int mid)
{
char buf[100];
struct cpu_info *cpi;
int idx;
static int cpu_attach_count = 0;
idx = cpu_attach_count++;
#if !defined(MULTIPROCESSOR)
if (cpu_attach_count > 1) {
printf(": no SMP support in kernel\n");
return;
}
#endif
cpi = sc->sc_cpuinfo = cpus[idx];
getcpuinfo(cpi, node);
cpi->ci_cpuid = idx;
cpi->mid = mid;
cpi->node = node;
#ifdef DEBUG
cpi->redzone = (void *)((long)cpi->eintstack + REDSIZE);
#endif
if (sparc_ncpus > 1) {
printf(": mid %d", mid);
if (mid == 0 && !CPU_ISSUN4D)
printf(" [WARNING: mid should not be 0]");
}
#if defined(MULTIPROCESSOR)
if (cpu_attach_count > 1) {
if ((boothowto & RB_MD1) != 0) {
aprint_naive("\n");
aprint_normal(": multiprocessor boot disabled\n");
return;
}
cpu_attach_non_boot(sc, cpi, node);
cpu_init_evcnt(cpi);
cpu_setup_sysctl(sc);
return;
}
#endif
cpu_init_evcnt(cpi);
cpu_setup();
snprintf(buf, sizeof buf, "%s @ %s MHz, %s FPU",
cpi->cpu_longname, clockfreq(cpi->hz), cpi->fpu_name);
cpu_setmodel("%s (%s)", machine_model, buf);
printf(": %s\n", buf);
cache_print(sc);
cpu_setup_sysctl(sc);
cpi->master = 1;
cpi->eintstack = eintstack;
if (bootmid == 0)
bootmid = mid;
if (sparc_ncpus > 1 && sparc_ncpus == cpu_attach_count) {
CPU_INFO_ITERATOR n;
unsigned best_hz = 0;
for (CPU_INFO_FOREACH(n, cpi))
best_hz = MAX(cpi->hz, best_hz);
for (CPU_INFO_FOREACH(n, cpi))
cpu_topology_setspeed(cpi, cpi->hz < best_hz);
}
}
void
cpu_setup(void)
{
if (cpuinfo.hotfix)
(*cpuinfo.hotfix)(&cpuinfo);
fpu_init(&cpuinfo);
cpuinfo.cache_enable();
cpuinfo.flags |= CPUFLG_HATCHED;
}
#if defined(MULTIPROCESSOR)
static void
cpu_attach_non_boot(struct cpu_softc *sc, struct cpu_info *cpi, int node)
{
vaddr_t intstack, va;
int error;
intstack = uvm_km_alloc(kernel_map, INT_STACK_SIZE, 0, UVM_KMF_WIRED);
if (intstack == 0)
panic("%s: no uspace/intstack", __func__);
cpi->eintstack = (void*)(intstack + INT_STACK_SIZE);
va = uvm_km_alloc(kernel_map, 2*PAGE_SIZE, 0, UVM_KMF_VAONLY);
if (va == 0)
panic("%s: no virtual space", __func__);
cpi->vpage[0] = (void *)(va + 0);
cpi->vpage[1] = (void *)(va + PAGE_SIZE);
error = mi_cpu_attach(cpi);
if (error != 0) {
aprint_normal("\n");
aprint_error("%s: mi_cpu_attach failed with %d\n",
device_xname(sc->sc_dev), error);
return;
}
cpi->ci_curlwp = cpi->ci_data.cpu_idlelwp;
cpi->curpcb = lwp_getpcb(cpi->ci_curlwp);
cpi->curpcb->pcb_wim = 1;
cpi->intreg_4m = (struct icr_pi *)
(PI_INTR_VA + (_MAXNBPG * CPU_MID2CPUNO(cpi->mid)));
cpu_spinup(cpi);
printf(": %s @ %s MHz, %s FPU\n", cpi->cpu_longname,
clockfreq(cpi->hz), cpi->fpu_name);
cache_print(sc);
if (sparc_ncpus > 1 && cpi->ci_cpuid == sparc_ncpus - 1) {
CPU_INFO_ITERATOR n;
for (CPU_INFO_FOREACH(n, cpi)) {
#define SET_CACHE_FUNC(x) \
if (cpi->x != __CONCAT(noop_,x)) cpi->x = __CONCAT(smp_,x)
SET_CACHE_FUNC(vcache_flush_page);
SET_CACHE_FUNC(vcache_flush_segment);
SET_CACHE_FUNC(vcache_flush_region);
SET_CACHE_FUNC(vcache_flush_context);
}
}
#undef SET_CACHE_FUNC
}
void
cpu_boot_secondary_processors(void)
{
CPU_INFO_ITERATOR n;
struct cpu_info *cpi;
printf("cpu0: booting secondary processors:");
for (CPU_INFO_FOREACH(n, cpi)) {
if (cpuinfo.mid == cpi->mid ||
(cpi->flags & CPUFLG_HATCHED) == 0)
continue;
printf(" cpu%d", cpi->ci_cpuid);
cpu_ready_mask |= (1 << n);
}
cpu_ready_mask |= (1 << 0);
go_smp_cpus = 1;
printf("\n");
}
void
cpu_init_system(void)
{
mutex_init(&xpmsg_mutex, MUTEX_SPIN, IPL_SCHED);
}
void
cpu_spinup(struct cpu_info *cpi)
{
struct openprom_addr oa;
void *pc;
int n;
pc = (void *)cpu_hatch;
pmap_alloc_cpu(cpi);
cpi->flags &= ~CPUFLG_HATCHED;
oa.oa_space = 0;
oa.oa_base = (uint32_t)cpi->ctx_tbl_pa;
oa.oa_size = cpi->mmu_ncontext * sizeof(cpi->ctx_tbl[0]);
cpuinfo.cache_flush_all();
prom_cpustart(cpi->node, &oa, 0, pc);
for (n = 10000; n != 0; n--) {
cache_flush((void *) __UNVOLATILE(&cpi->flags),
sizeof(cpi->flags));
if (cpi->flags & CPUFLG_HATCHED)
return;
delay(100);
}
printf("CPU did not spin up\n");
}
void
xcall(xcall_func_t func, xcall_trap_t trap, int arg0, int arg1, int arg2,
u_int cpuset)
{
struct cpu_info *cpi;
int n, i, done, callself, mybit;
volatile struct xpmsg_func *p;
u_int pil;
int fasttrap;
int is_noop = func == (xcall_func_t)sparc_noop;
static char errbuf[160];
char *bufp = errbuf;
size_t bufsz = sizeof errbuf, wrsz;
if (is_noop) return;
mybit = (1 << cpuinfo.ci_cpuid);
callself = func && (cpuset & mybit) != 0;
cpuset &= ~mybit;
cpuset &= cpu_ready_mask;
#if 0
mutex_spin_enter(&xpmsg_mutex);
#else
pil = (getpsr() & PSR_PIL) >> 8;
if (cold || pil <= IPL_SCHED)
mutex_spin_enter(&xpmsg_mutex);
else {
if (debug_xcall && (void *)func != sparc_noop) {
u_int pc;
__asm("mov %%i7, %0" : "=r" (pc) : );
printf_nolog("%d: xcall %p at lvl %u from 0x%x\n",
cpu_number(), func, pil, pc);
}
while (mutex_tryenter(&xpmsg_mutex) == 0) {
cpuinfo.ci_xpmsg_mutex_fail.ev_count++;
if (cpuinfo.msg.tag) {
cpuinfo.ci_xpmsg_mutex_fail_call.ev_count++;
xcallintr(xcallintr);
}
}
}
#endif
fasttrap = trap != NULL ? 1 : 0;
for (CPU_INFO_FOREACH(n, cpi)) {
if ((cpuset & (1 << n)) == 0)
continue;
cpi->msg.complete = 0;
p = &cpi->msg.u.xpmsg_func;
p->func = func;
p->trap = trap;
p->arg0 = arg0;
p->arg1 = arg1;
p->arg2 = arg2;
__insn_barrier();
cpi->msg.tag = XPMSG_FUNC;
__insn_barrier();
raise_ipi(cpi,13+fasttrap);
}
if (callself)
(*func)(arg0, arg1, arg2);
done = 0;
i = 1000000;
while (!done) {
if (--i < 0) {
wrsz = snprintf(bufp, bufsz,
"xcall(cpu%d,%p) from %p: couldn't ping cpus:",
cpu_number(), fasttrap ? trap : func,
__builtin_return_address(0));
if (wrsz > bufsz)
break;
bufsz -= wrsz;
bufp += wrsz;
}
done = 1;
for (CPU_INFO_FOREACH(n, cpi)) {
if ((cpuset & (1 << n)) == 0)
continue;
if (cpi->msg.complete == 0) {
if (i < 0) {
wrsz = snprintf(bufp, bufsz,
" cpu%d", cpi->ci_cpuid);
if (wrsz > bufsz)
break;
bufsz -= wrsz;
bufp += wrsz;
} else {
done = 0;
break;
}
}
}
}
if (i >= 0 || debug_xcall == 0) {
if (i < 0)
aprint_error("%s\n", errbuf);
mutex_spin_exit(&xpmsg_mutex);
return;
}
#ifdef DDB
mp_pause_cpus_ddb();
#else
mp_pause_cpus();
#endif
printf_nolog("%s\n", errbuf);
mutex_spin_exit(&xpmsg_mutex);
panic("failed to ping cpus");
}
void
xc_send_ipi(struct cpu_info *target)
{
u_int cpuset;
KASSERT(kpreempt_disabled());
KASSERT(curcpu() != target);
if (target)
cpuset = 1 << target->ci_cpuid;
else
cpuset = CPUSET_ALL & ~(1 << cpuinfo.ci_cpuid);
XCALL0(xc_ipi_handler, cpuset);
}
void
cpu_ipi(struct cpu_info *target)
{
u_int cpuset;
KASSERT(kpreempt_disabled());
KASSERT(curcpu() != target);
if (target)
cpuset = 1 << target->ci_cpuid;
else
cpuset = CPUSET_ALL & ~(1 << cpuinfo.ci_cpuid);
XCALL0(ipi_cpu_handler, cpuset);
}
void
mp_pause_cpus(void)
{
CPU_INFO_ITERATOR n;
struct cpu_info *cpi;
for (CPU_INFO_FOREACH(n, cpi)) {
if (cpuinfo.mid == cpi->mid ||
(cpi->flags & CPUFLG_HATCHED) == 0)
continue;
if (prom_cpuidle(cpi->node) != 0)
printf("cpu%d could not be paused\n", cpi->ci_cpuid);
}
}
void
mp_resume_cpus(void)
{
CPU_INFO_ITERATOR n;
struct cpu_info *cpi;
for (CPU_INFO_FOREACH(n, cpi)) {
if (cpuinfo.mid == cpi->mid ||
(cpi->flags & CPUFLG_HATCHED) == 0)
continue;
if (prom_cpuresume(cpi->node) != 0)
printf("cpu%d could not be resumed\n", cpi->ci_cpuid);
}
}
void
mp_halt_cpus(void)
{
CPU_INFO_ITERATOR n;
struct cpu_info *cpi;
for (CPU_INFO_FOREACH(n, cpi)) {
int r;
if (cpuinfo.mid == cpi->mid)
continue;
r = prom_cpustop(cpi->node);
printf("cpu%d %shalted\n", cpi->ci_cpuid,
r == 0 ? "" : "(boot CPU?) can not be ");
}
}
#if defined(DDB)
void
mp_pause_cpus_ddb(void)
{
CPU_INFO_ITERATOR n;
struct cpu_info *cpi;
for (CPU_INFO_FOREACH(n, cpi)) {
if (cpi == NULL || cpi->mid == cpuinfo.mid ||
(cpi->flags & CPUFLG_HATCHED) == 0)
continue;
cpi->msg_lev15.tag = XPMSG15_PAUSECPU;
raise_ipi(cpi,15);
}
}
void
mp_resume_cpus_ddb(void)
{
CPU_INFO_ITERATOR n;
struct cpu_info *cpi;
for (CPU_INFO_FOREACH(n, cpi)) {
if (cpi == NULL || cpuinfo.mid == cpi->mid ||
(cpi->flags & CPUFLG_PAUSED) == 0)
continue;
cpi->flags &= ~CPUFLG_PAUSED;
}
}
#endif
#endif
void
fpu_init(struct cpu_info *sc)
{
struct fpstate fpstate;
int fpuvers;
fpstate.fs_fsr = 7 << FSR_VER_SHIFT;
savefpstate(&fpstate);
sc->fpuvers = fpuvers =
(fpstate.fs_fsr >> FSR_VER_SHIFT) & (FSR_VER >> FSR_VER_SHIFT);
if (fpuvers == 7) {
sc->fpu_name = "no";
return;
}
sc->fpupresent = 1;
sc->fpu_name = fsrtoname(sc->cpu_impl, sc->cpu_vers, fpuvers);
if (sc->fpu_name == NULL) {
snprintf(sc->fpu_namebuf, sizeof(sc->fpu_namebuf),
"version 0x%x", fpuvers);
sc->fpu_name = sc->fpu_namebuf;
}
}
static void
cache_print(struct cpu_softc *sc)
{
struct cacheinfo *ci = &sc->sc_cpuinfo->cacheinfo;
cache_printf_backend(ci, device_xname(sc->sc_dev));
}
void cpumatch_unknown(struct cpu_info *, struct module_info *, int);
void cpumatch_sun4(struct cpu_info *, struct module_info *, int);
void cpumatch_sun4c(struct cpu_info *, struct module_info *, int);
void cpumatch_ms1(struct cpu_info *, struct module_info *, int);
void cpumatch_viking(struct cpu_info *, struct module_info *, int);
void cpumatch_hypersparc(struct cpu_info *, struct module_info *, int);
void cpumatch_turbosparc(struct cpu_info *, struct module_info *, int);
void getcacheinfo_sun4(struct cpu_info *, int node);
void getcacheinfo_sun4c(struct cpu_info *, int node);
void getcacheinfo_obp(struct cpu_info *, int node);
void getcacheinfo_sun4d(struct cpu_info *, int node);
void sun4_hotfix(struct cpu_info *);
void viking_hotfix(struct cpu_info *);
void turbosparc_hotfix(struct cpu_info *);
void swift_hotfix(struct cpu_info *);
void ms1_mmu_enable(void);
void viking_mmu_enable(void);
void swift_mmu_enable(void);
void hypersparc_mmu_enable(void);
void srmmu_get_syncflt(void);
void ms1_get_syncflt(void);
void viking_get_syncflt(void);
void swift_get_syncflt(void);
void turbosparc_get_syncflt(void);
void hypersparc_get_syncflt(void);
void cypress_get_syncflt(void);
int srmmu_get_asyncflt(u_int *, u_int *);
int hypersparc_get_asyncflt(u_int *, u_int *);
int cypress_get_asyncflt(u_int *, u_int *);
int no_asyncflt_regs(u_int *, u_int *);
int hypersparc_getmid(void);
#define cypress_getmid hypersparc_getmid
int viking_getmid(void);
#if (defined(SUN4M) && !defined(MSIIEP)) || defined(SUN4D)
int viking_module_error(void);
#endif
struct module_info module_unknown = {
CPUTYP_UNKNOWN,
VAC_UNKNOWN,
cpumatch_unknown
};
void
cpumatch_unknown(struct cpu_info *sc, struct module_info *mp, int node)
{
panic("Unknown CPU type: "
"cpu: impl %d, vers %d; mmu: impl %d, vers %d",
sc->cpu_impl, sc->cpu_vers,
sc->mmu_impl, sc->mmu_vers);
}
#if defined(SUN4)
struct module_info module_sun4 = {
CPUTYP_UNKNOWN,
VAC_WRITETHROUGH,
cpumatch_sun4,
getcacheinfo_sun4,
sun4_hotfix,
0,
sun4_cache_enable,
0,
0,
0,
0,
sun4_cache_flush,
sun4_vcache_flush_page, NULL,
sun4_vcache_flush_segment, NULL,
sun4_vcache_flush_region, NULL,
sun4_vcache_flush_context, NULL,
NULL, NULL,
noop_pcache_flush_page,
noop_pure_vcache_flush,
noop_cache_flush_all,
0,
pmap_zero_page4_4c,
pmap_copy_page4_4c
};
void
getcacheinfo_sun4(struct cpu_info *sc, int node)
{
struct cacheinfo *ci = &sc->cacheinfo;
switch (sc->cpu_type) {
case CPUTYP_4_100:
ci->c_vactype = VAC_NONE;
ci->c_totalsize = 0;
ci->c_hwflush = 0;
ci->c_linesize = 0;
ci->c_l2linesize = 0;
ci->c_split = 0;
ci->c_nlines = 0;
sc->cache_flush = noop_cache_flush;
sc->sp_vcache_flush_page = noop_vcache_flush_page;
sc->sp_vcache_flush_segment = noop_vcache_flush_segment;
sc->sp_vcache_flush_region = noop_vcache_flush_region;
sc->sp_vcache_flush_context = noop_vcache_flush_context;
break;
case CPUTYP_4_200:
ci->c_vactype = VAC_WRITEBACK;
ci->c_totalsize = 128*1024;
ci->c_hwflush = 0;
ci->c_linesize = 16;
ci->c_l2linesize = 4;
ci->c_split = 0;
ci->c_nlines = ci->c_totalsize >> ci->c_l2linesize;
break;
case CPUTYP_4_300:
ci->c_vactype = VAC_WRITEBACK;
ci->c_totalsize = 128*1024;
ci->c_hwflush = 0;
ci->c_linesize = 16;
ci->c_l2linesize = 4;
ci->c_split = 0;
ci->c_nlines = ci->c_totalsize >> ci->c_l2linesize;
sc->cacheinfo.c_flags |= CACHE_TRAPPAGEBUG;
break;
case CPUTYP_4_400:
ci->c_vactype = VAC_WRITEBACK;
ci->c_totalsize = 128 * 1024;
ci->c_hwflush = 0;
ci->c_linesize = 32;
ci->c_l2linesize = 5;
ci->c_split = 0;
ci->c_nlines = ci->c_totalsize >> ci->c_l2linesize;
break;
}
}
void
cpumatch_sun4(struct cpu_info *sc, struct module_info *mp, int node)
{
struct idprom *idp = prom_getidprom();
switch (idp->idp_machtype) {
case ID_SUN4_100:
sc->cpu_type = CPUTYP_4_100;
sc->classlvl = 100;
sc->mmu_ncontext = 8;
sc->mmu_nsegment = 256;
sc->hz = 14280000;
break;
case ID_SUN4_200:
sc->cpu_type = CPUTYP_4_200;
sc->classlvl = 200;
sc->mmu_nsegment = 512;
sc->mmu_ncontext = 16;
sc->hz = 16670000;
break;
case ID_SUN4_300:
sc->cpu_type = CPUTYP_4_300;
sc->classlvl = 300;
sc->mmu_nsegment = 256;
sc->mmu_ncontext = 16;
sc->hz = 25000000;
break;
case ID_SUN4_400:
sc->cpu_type = CPUTYP_4_400;
sc->classlvl = 400;
sc->mmu_nsegment = 1024;
sc->mmu_ncontext = 64;
sc->mmu_nregion = 256;
sc->hz = 33000000;
sc->sun4_mmu3l = 1;
break;
}
}
#endif
#if defined(SUN4C)
struct module_info module_sun4c = {
CPUTYP_UNKNOWN,
VAC_WRITETHROUGH,
cpumatch_sun4c,
getcacheinfo_sun4c,
sun4_hotfix,
0,
sun4_cache_enable,
0,
0,
0,
0,
sun4_cache_flush,
sun4_vcache_flush_page, NULL,
sun4_vcache_flush_segment, NULL,
sun4_vcache_flush_region, NULL,
sun4_vcache_flush_context, NULL,
NULL, NULL,
noop_pcache_flush_page,
noop_pure_vcache_flush,
noop_cache_flush_all,
0,
pmap_zero_page4_4c,
pmap_copy_page4_4c
};
void
cpumatch_sun4c(struct cpu_info *sc, struct module_info *mp, int node)
{
int rnode;
rnode = findroot();
sc->mmu_npmeg = sc->mmu_nsegment =
prom_getpropint(rnode, "mmu-npmg", 128);
sc->mmu_ncontext = prom_getpropint(rnode, "mmu-nctx", 8);
sc->hz = prom_getpropint(rnode, "clock-frequency", 0);
}
void
getcacheinfo_sun4c(struct cpu_info *sc, int node)
{
struct cacheinfo *ci = &sc->cacheinfo;
int i, l;
if (node == 0)
return;
ci->c_physical = 0;
ci->c_totalsize = prom_getpropint(node, "vac-size", 65536);
ci->c_hwflush =
prom_getpropint(node, "vac_hwflush", 0) |
prom_getpropint(node, "vac-hwflush", 0);
ci->c_linesize = l = prom_getpropint(node, "vac-linesize", 16);
for (i = 0; (1 << i) < l; i++)
;
if ((1 << i) != l)
panic("bad cache line size %d", l);
ci->c_l2linesize = i;
ci->c_associativity = 1;
ci->c_nlines = ci->c_totalsize >> i;
ci->c_vactype = VAC_WRITETHROUGH;
if (prom_getpropint(node, "buserr-type", 0) == 1)
sc->cacheinfo.c_flags |= CACHE_TRAPPAGEBUG;
}
#endif
void
sun4_hotfix(struct cpu_info *sc)
{
if ((sc->cacheinfo.c_flags & CACHE_TRAPPAGEBUG) != 0)
kvm_uncache((char *)trapbase, 1);
if (sc->cacheinfo.c_hwflush)
sc->vcache_flush_page = sun4_vcache_flush_page_hw;
}
#if defined(SUN4M)
void
getcacheinfo_obp(struct cpu_info *sc, int node)
{
struct cacheinfo *ci = &sc->cacheinfo;
int i, l;
#if defined(MULTIPROCESSOR)
if (node == 0 && CPU_ISSUN4M && bootmid != 0) {
const char *cp;
char namebuf[32];
int mid, node2;
for (node2 = firstchild(findroot());
node2;
node2 = nextsibling(node2)) {
cp = prom_getpropstringA(node2, "device_type",
namebuf, sizeof namebuf);
if (strcmp(cp, "cpu") != 0)
continue;
mid = prom_getpropint(node2, "mid", -1);
if (mid == bootmid) {
node = node2;
break;
}
}
}
#endif
if (node == 0)
return;
ci->c_physical = node_has_property(node, "cache-physical?");
if (prom_getpropint(node, "ncaches", 1) == 2)
ci->c_split = 1;
else
ci->c_split = 0;
ci->c_hwflush = 0;
if (node_has_property(node, "icache-nlines") &&
node_has_property(node, "dcache-nlines") &&
ci->c_split) {
ci->ic_nlines = prom_getpropint(node, "icache-nlines", 0);
ci->ic_linesize = l =
prom_getpropint(node, "icache-line-size", 0);
for (i = 0; (1 << i) < l && l; i++)
;
if ((1 << i) != l && l)
panic("bad icache line size %d", l);
ci->ic_l2linesize = i;
ci->ic_associativity =
prom_getpropint(node, "icache-associativity", 1);
ci->ic_totalsize = l * ci->ic_nlines * ci->ic_associativity;
ci->dc_nlines = prom_getpropint(node, "dcache-nlines", 0);
ci->dc_linesize = l =
prom_getpropint(node, "dcache-line-size",0);
for (i = 0; (1 << i) < l && l; i++)
;
if ((1 << i) != l && l)
panic("bad dcache line size %d", l);
ci->dc_l2linesize = i;
ci->dc_associativity =
prom_getpropint(node, "dcache-associativity", 1);
ci->dc_totalsize = l * ci->dc_nlines * ci->dc_associativity;
ci->c_l2linesize = uimin(ci->ic_l2linesize, ci->dc_l2linesize);
ci->c_linesize = uimin(ci->ic_linesize, ci->dc_linesize);
ci->c_totalsize = uimax(ci->ic_totalsize, ci->dc_totalsize);
ci->c_nlines = ci->c_totalsize >> ci->c_l2linesize;
} else {
ci->c_nlines = prom_getpropint(node, "cache-nlines", 128);
ci->c_linesize = l =
prom_getpropint(node, "cache-line-size", 0);
for (i = 0; (1 << i) < l && l; i++)
;
if ((1 << i) != l && l)
panic("bad cache line size %d", l);
ci->c_l2linesize = i;
ci->c_associativity =
prom_getpropint(node, "cache-associativity", 1);
ci->dc_associativity = ci->ic_associativity =
ci->c_associativity;
ci->c_totalsize = l * ci->c_nlines * ci->c_associativity;
}
if (node_has_property(node, "ecache-nlines")) {
ci->ec_nlines = prom_getpropint(node, "ecache-nlines", 32768);
ci->ec_linesize = l = prom_getpropint(node, "ecache-line-size", 0);
for (i = 0; (1 << i) < l && l; i++)
;
if ((1 << i) != l && l)
panic("bad ecache line size %d", l);
ci->ec_l2linesize = i;
ci->ec_associativity =
prom_getpropint(node, "ecache-associativity", 1);
ci->ec_totalsize = l * ci->ec_nlines * ci->ec_associativity;
}
if (ci->c_totalsize == 0)
printf("warning: couldn't identify cache\n");
}
struct module_info module_ms1 = {
CPUTYP_MS1,
VAC_NONE,
cpumatch_ms1,
getcacheinfo_obp,
0,
ms1_mmu_enable,
ms1_cache_enable,
0,
64,
ms1_get_syncflt,
no_asyncflt_regs,
ms1_cache_flush,
noop_vcache_flush_page, NULL,
noop_vcache_flush_segment, NULL,
noop_vcache_flush_region, NULL,
noop_vcache_flush_context, NULL,
noop_vcache_flush_range, NULL,
noop_pcache_flush_page,
noop_pure_vcache_flush,
ms1_cache_flush_all,
memerr4m,
pmap_zero_page4m,
pmap_copy_page4m
};
void
cpumatch_ms1(struct cpu_info *sc, struct module_info *mp, int node)
{
}
void
ms1_mmu_enable(void)
{
}
struct module_info module_ms2 = {
CPUTYP_MS2,
VAC_WRITETHROUGH,
0,
getcacheinfo_obp,
0,
0,
swift_cache_enable,
0,
256,
srmmu_get_syncflt,
srmmu_get_asyncflt,
srmmu_cache_flush,
srmmu_vcache_flush_page, NULL,
srmmu_vcache_flush_segment, NULL,
srmmu_vcache_flush_region, NULL,
srmmu_vcache_flush_context, NULL,
srmmu_vcache_flush_range, NULL,
noop_pcache_flush_page,
noop_pure_vcache_flush,
srmmu_cache_flush_all,
memerr4m,
pmap_zero_page4m,
pmap_copy_page4m
};
struct module_info module_swift = {
CPUTYP_MS2,
VAC_WRITETHROUGH,
0,
getcacheinfo_obp,
swift_hotfix,
0,
swift_cache_enable,
0,
256,
swift_get_syncflt,
no_asyncflt_regs,
srmmu_cache_flush,
srmmu_vcache_flush_page, NULL,
srmmu_vcache_flush_segment, NULL,
srmmu_vcache_flush_region, NULL,
srmmu_vcache_flush_context, NULL,
srmmu_vcache_flush_range, NULL,
noop_pcache_flush_page,
noop_pure_vcache_flush,
srmmu_cache_flush_all,
memerr4m,
pmap_zero_page4m,
pmap_copy_page4m
};
void
swift_hotfix(struct cpu_info *sc)
{
int pcr = lda(SRMMU_PCR, ASI_SRMMU);
pcr &= ~SWIFT_PCR_BF;
sta(SRMMU_PCR, ASI_SRMMU, pcr);
}
void
swift_mmu_enable(void)
{
}
struct module_info module_hypersparc = {
CPUTYP_UNKNOWN,
VAC_WRITEBACK,
cpumatch_hypersparc,
getcacheinfo_obp,
0,
hypersparc_mmu_enable,
hypersparc_cache_enable,
hypersparc_getmid,
4096,
hypersparc_get_syncflt,
hypersparc_get_asyncflt,
srmmu_cache_flush,
srmmu_vcache_flush_page, ft_srmmu_vcache_flush_page,
srmmu_vcache_flush_segment, ft_srmmu_vcache_flush_segment,
srmmu_vcache_flush_region, ft_srmmu_vcache_flush_region,
srmmu_vcache_flush_context, ft_srmmu_vcache_flush_context,
srmmu_vcache_flush_range, ft_srmmu_vcache_flush_range,
noop_pcache_flush_page,
hypersparc_pure_vcache_flush,
hypersparc_cache_flush_all,
hypersparc_memerr,
pmap_zero_page4m,
pmap_copy_page4m
};
void
cpumatch_hypersparc(struct cpu_info *sc, struct module_info *mp, int node)
{
sc->cpu_type = CPUTYP_HS_MBUS;
if (node == 0) {
sta(0, ASI_HICACHECLR, 0);
wrasr(rdasr(HYPERSPARC_ASRNUM_ICCR) | HYPERSPARC_ICCR_FTD,
HYPERSPARC_ASRNUM_ICCR);
}
}
void
hypersparc_mmu_enable(void)
{
#if 0
int pcr;
pcr = lda(SRMMU_PCR, ASI_SRMMU);
pcr |= HYPERSPARC_PCR_C;
pcr &= ~HYPERSPARC_PCR_CE;
sta(SRMMU_PCR, ASI_SRMMU, pcr);
#endif
}
int
hypersparc_getmid(void)
{
u_int pcr = lda(SRMMU_PCR, ASI_SRMMU);
return ((pcr & HYPERSPARC_PCR_MID) >> 15);
}
struct module_info module_cypress = {
CPUTYP_CYPRESS,
VAC_WRITEBACK,
0,
getcacheinfo_obp,
0,
0,
cypress_cache_enable,
cypress_getmid,
4096,
cypress_get_syncflt,
cypress_get_asyncflt,
srmmu_cache_flush,
srmmu_vcache_flush_page, ft_srmmu_vcache_flush_page,
srmmu_vcache_flush_segment, ft_srmmu_vcache_flush_segment,
srmmu_vcache_flush_region, ft_srmmu_vcache_flush_region,
srmmu_vcache_flush_context, ft_srmmu_vcache_flush_context,
srmmu_vcache_flush_range, ft_srmmu_vcache_flush_range,
noop_pcache_flush_page,
noop_pure_vcache_flush,
cypress_cache_flush_all,
memerr4m,
pmap_zero_page4m,
pmap_copy_page4m
};
struct module_info module_turbosparc = {
CPUTYP_MS2,
VAC_WRITEBACK,
cpumatch_turbosparc,
getcacheinfo_obp,
turbosparc_hotfix,
0,
turbosparc_cache_enable,
0,
256,
turbosparc_get_syncflt,
no_asyncflt_regs,
srmmu_cache_flush,
srmmu_vcache_flush_page, NULL,
srmmu_vcache_flush_segment, NULL,
srmmu_vcache_flush_region, NULL,
srmmu_vcache_flush_context, NULL,
srmmu_vcache_flush_range, NULL,
noop_pcache_flush_page,
noop_pure_vcache_flush,
srmmu_cache_flush_all,
memerr4m,
pmap_zero_page4m,
pmap_copy_page4m
};
void
cpumatch_turbosparc(struct cpu_info *sc, struct module_info *mp, int node)
{
int i;
if (node == 0 || sc->master == 0)
return;
i = getpsr();
if (sc->cpu_vers == IU_VERS(i))
return;
sc->cpu_longname = 0;
sc->mmu_ncontext = 0;
sc->cpu_type = 0;
sc->cacheinfo.c_vactype = 0;
sc->hotfix = 0;
sc->mmu_enable = 0;
sc->cache_enable = 0;
sc->get_syncflt = 0;
sc->cache_flush = 0;
sc->sp_vcache_flush_page = 0;
sc->sp_vcache_flush_segment = 0;
sc->sp_vcache_flush_region = 0;
sc->sp_vcache_flush_context = 0;
sc->pcache_flush_page = 0;
}
void
turbosparc_hotfix(struct cpu_info *sc)
{
int pcf;
pcf = lda(SRMMU_PCFG, ASI_SRMMU);
if (pcf & TURBOSPARC_PCFG_US2) {
pcf &= ~TURBOSPARC_PCFG_US2;
sta(SRMMU_PCFG, ASI_SRMMU, pcf);
}
}
#endif
#if defined(SUN4M)
struct module_info module_viking = {
CPUTYP_UNKNOWN,
VAC_NONE,
cpumatch_viking,
getcacheinfo_obp,
viking_hotfix,
viking_mmu_enable,
viking_cache_enable,
viking_getmid,
4096,
viking_get_syncflt,
no_asyncflt_regs,
noop_cache_flush,
noop_vcache_flush_page, NULL,
noop_vcache_flush_segment, NULL,
noop_vcache_flush_region, NULL,
noop_vcache_flush_context, NULL,
noop_vcache_flush_range, NULL,
viking_pcache_flush_page,
noop_pure_vcache_flush,
noop_cache_flush_all,
viking_memerr,
pmap_zero_page4m,
pmap_copy_page4m
};
#endif
#if defined(SUN4M) || defined(SUN4D)
void
cpumatch_viking(struct cpu_info *sc, struct module_info *mp, int node)
{
if (node == 0)
viking_hotfix(sc);
}
void
viking_hotfix(struct cpu_info *sc)
{
static int mxcc = -1;
int pcr = lda(SRMMU_PCR, ASI_SRMMU);
if ((pcr & VIKING_PCR_MB) == 0) {
sc->mxcc = 1;
sc->cacheinfo.c_flags |= CACHE_MANDATORY;
sc->zero_page = pmap_zero_page_viking_mxcc;
sc->copy_page = pmap_copy_page_viking_mxcc;
#if !defined(MSIIEP)
moduleerr_handler = viking_module_error;
#endif
if ((pcr & VIKING_PCR_TC) == 0)
printf("[viking: PCR_TC is off]");
else
sc->cacheinfo.c_flags |= CACHE_PAGETABLES;
} else {
#ifdef MULTIPROCESSOR
if (sparc_ncpus > 1 && sc->cacheinfo.ec_totalsize == 0)
sc->cache_flush = srmmu_cache_flush;
#endif
}
if (mxcc != -1 && sc->mxcc != mxcc)
panic("MXCC module mismatch");
mxcc = sc->mxcc;
if (sc->mxcc)
sc->cpu_type = CPUTYP_SS1_MBUS_MXCC;
else
sc->cpu_type = CPUTYP_SS1_MBUS_NOMXCC;
}
void
viking_mmu_enable(void)
{
int pcr;
pcr = lda(SRMMU_PCR, ASI_SRMMU);
if (cpuinfo.mxcc) {
if ((pcr & VIKING_PCR_TC) == 0) {
printf("[viking: turn on PCR_TC]");
}
pcr |= VIKING_PCR_TC;
CACHEINFO.c_flags |= CACHE_PAGETABLES;
} else
pcr &= ~VIKING_PCR_TC;
sta(SRMMU_PCR, ASI_SRMMU, pcr);
}
int
viking_getmid(void)
{
if (cpuinfo.mxcc) {
u_int v = ldda(MXCC_MBUSPORT, ASI_CONTROL) & 0xffffffff;
return ((v >> 24) & 0xf);
}
return (0);
}
#if !defined(MSIIEP)
int
viking_module_error(void)
{
uint64_t v;
int fatal = 0;
CPU_INFO_ITERATOR n;
struct cpu_info *cpi;
for (CPU_INFO_FOREACH(n, cpi)) {
if (cpi->ci_mxccregs == 0) {
printf("\tMXCC registers not mapped\n");
continue;
}
printf("module%d:\n", cpi->ci_cpuid);
v = *((uint64_t *)(cpi->ci_mxccregs + 0xe00));
printf("\tmxcc error 0x%llx\n", v);
v = *((uint64_t *)(cpi->ci_mxccregs + 0xb00));
printf("\tmxcc status 0x%llx\n", v);
v = *((uint64_t *)(cpi->ci_mxccregs + 0xc00));
printf("\tmxcc reset 0x%llx", v);
if (v & MXCC_MRST_WD)
printf(" (WATCHDOG RESET)"), fatal = 1;
if (v & MXCC_MRST_SI)
printf(" (SOFTWARE RESET)"), fatal = 1;
printf("\n");
}
return (fatal);
}
#endif
#endif
#if defined(SUN4D)
void
getcacheinfo_sun4d(struct cpu_info *sc, int node)
{
struct cacheinfo *ci = &sc->cacheinfo;
int i, l;
if (node == 0)
return;
ci->c_physical = 1;
ci->c_split = 1;
ci->c_hwflush = 0;
ci->ic_nlines = 0x00000040;
ci->ic_linesize = 0x00000040;
ci->ic_l2linesize = 6;
ci->ic_associativity = 0x00000005;
ci->ic_totalsize = ci->ic_linesize * ci->ic_nlines *
ci->ic_associativity;
ci->dc_nlines = 0x00000080;
ci->dc_linesize = 0x00000020;
ci->dc_l2linesize = 5;
ci->dc_associativity = 0x00000004;
ci->dc_totalsize = ci->dc_linesize * ci->dc_nlines *
ci->dc_associativity;
ci->c_l2linesize = uimin(ci->ic_l2linesize, ci->dc_l2linesize);
ci->c_linesize = uimin(ci->ic_linesize, ci->dc_linesize);
ci->c_totalsize = uimax(ci->ic_totalsize, ci->dc_totalsize);
ci->c_nlines = ci->c_totalsize >> ci->c_l2linesize;
if (node_has_property(node, "ecache-nlines")) {
ci->ec_nlines = prom_getpropint(node, "ecache-nlines", 32768);
ci->ec_linesize = l = prom_getpropint(node, "ecache-line-size", 0);
for (i = 0; (1 << i) < l && l; i++)
;
if ((1 << i) != l && l)
panic("bad ecache line size %d", l);
ci->ec_l2linesize = i;
ci->ec_associativity =
prom_getpropint(node, "ecache-associativity", 1);
ci->ec_totalsize = l * ci->ec_nlines * ci->ec_associativity;
}
}
struct module_info module_viking_sun4d = {
CPUTYP_UNKNOWN,
VAC_NONE,
cpumatch_viking,
getcacheinfo_sun4d,
viking_hotfix,
viking_mmu_enable,
viking_cache_enable,
viking_getmid,
4096,
viking_get_syncflt,
no_asyncflt_regs,
noop_cache_flush,
noop_vcache_flush_page, NULL,
noop_vcache_flush_segment, NULL,
noop_vcache_flush_region, NULL,
noop_vcache_flush_context, NULL,
noop_vcache_flush_range, NULL,
viking_pcache_flush_page,
noop_pure_vcache_flush,
noop_cache_flush_all,
viking_memerr,
pmap_zero_page4m,
pmap_copy_page4m
};
#endif
#define ANY -1
struct cpu_conf {
int arch;
int cpu_impl;
int cpu_vers;
int mmu_impl;
int mmu_vers;
const char *name;
struct module_info *minfo;
} cpu_conf[] = {
#if defined(SUN4)
{ CPU_SUN4, 0, 0, ANY, ANY, "MB86900/1A or L64801", &module_sun4 },
{ CPU_SUN4, 1, 0, ANY, ANY, "L64811", &module_sun4 },
{ CPU_SUN4, 1, 1, ANY, ANY, "CY7C601", &module_sun4 },
#endif
#if defined(SUN4C)
{ CPU_SUN4C, 0, 0, ANY, ANY, "MB86900/1A or L64801", &module_sun4c },
{ CPU_SUN4C, 1, 0, ANY, ANY, "L64811", &module_sun4c },
{ CPU_SUN4C, 1, 1, ANY, ANY, "CY7C601", &module_sun4c },
{ CPU_SUN4C, 9, 0, ANY, ANY, "W8601/8701 or MB86903", &module_sun4c },
#endif
#if defined(SUN4M)
{ CPU_SUN4M, 0, 4, 0, 4, "MB86904", &module_swift },
{ CPU_SUN4M, 0, 5, 0, 5, "MB86907", &module_turbosparc },
{ CPU_SUN4M, 1, 1, 1, 0, "CY7C601/604", &module_cypress },
{ CPU_SUN4M, 1, 1, 1, 0xb, "CY7C601/605 (v.b)", &module_cypress },
{ CPU_SUN4M, 1, 1, 1, 0xc, "CY7C601/605 (v.c)", &module_cypress },
{ CPU_SUN4M, 1, 1, 1, 0xf, "CY7C601/605 (v.f)", &module_cypress },
{ CPU_SUN4M, 1, 3, 1, ANY, "CY7C611", &module_cypress },
{ CPU_SUN4M, 1, 0xe, 1, 7, "RT620/625", &module_hypersparc },
{ CPU_SUN4M, 1, 0xf, 1, 7, "RT620/625", &module_hypersparc },
{ CPU_SUN4M, 4, 0, 0, 1, "SuperSPARC v3", &module_viking },
{ CPU_SUN4M, 4, 0, 0, 2, "SuperSPARC v4", &module_viking },
{ CPU_SUN4M, 4, 0, 0, 3, "SuperSPARC v5", &module_viking },
{ CPU_SUN4M, 4, 0, 0, 8, "SuperSPARC II v1", &module_viking },
{ CPU_SUN4M, 4, 0, 0, 10, "SuperSPARC II v2", &module_viking },
{ CPU_SUN4M, 4, 0, 0, 12, "SuperSPARC II v3", &module_viking },
{ CPU_SUN4M, 4, 0, 0, ANY, "TMS390Z50 v0 or TMS390Z55", &module_viking },
{ CPU_SUN4M, 4, 1, 0, ANY, "TMS390Z50 v1", &module_viking },
{ CPU_SUN4M, 4, 1, 4, ANY, "TMS390S10", &module_ms1 },
{ CPU_SUN4M, 4, 2, 0, ANY, "TI_MS2", &module_ms2 },
{ CPU_SUN4M, 4, 3, ANY, ANY, "TI_4_3", &module_viking },
{ CPU_SUN4M, 4, 4, ANY, ANY, "TI_4_4", &module_viking },
#endif
#if defined(SUN4D)
{ CPU_SUN4D, 4, 0, 0, ANY, "TMS390Z50 v0 or TMS390Z55",
&module_viking_sun4d },
#endif
{ ANY, ANY, ANY, ANY, ANY, "Unknown", &module_unknown }
};
void
getcpuinfo(struct cpu_info *sc, int node)
{
struct cpu_conf *mp;
int i;
int cpu_impl, cpu_vers;
int mmu_impl, mmu_vers;
if (sc->master) {
i = getpsr();
if (node == 0 ||
(cpu_impl =
prom_getpropint(node, "psr-implementation", -1)) == -1)
cpu_impl = IU_IMPL(i);
if (node == 0 ||
(cpu_vers = prom_getpropint(node, "psr-version", -1)) == -1)
cpu_vers = IU_VERS(i);
if (CPU_HAS_SRMMU) {
i = lda(SRMMU_PCR, ASI_SRMMU);
if (node == 0 ||
(mmu_impl =
prom_getpropint(node, "implementation", -1)) == -1)
mmu_impl = SRMMU_IMPL(i);
if (node == 0 ||
(mmu_vers = prom_getpropint(node, "version", -1)) == -1)
mmu_vers = SRMMU_VERS(i);
} else {
mmu_impl = ANY;
mmu_vers = ANY;
}
} else {
cpu_impl = prom_getpropint(node, "psr-implementation",
cpuinfo.cpu_impl);
cpu_vers = prom_getpropint(node, "psr-version",
cpuinfo.cpu_vers);
mmu_impl = prom_getpropint(node, "implementation", -1);
mmu_vers = prom_getpropint(node, "version", -1);
}
if (node != 0) {
char *cpu_name;
char namebuf[64];
cpu_name = prom_getpropstringA(node, "name", namebuf,
sizeof namebuf);
if (cpu_name && cpu_name[0])
sc->cpu_longname = kmem_strdupsize(cpu_name, NULL,
KM_SLEEP);
}
for (mp = cpu_conf; ; mp++) {
if (mp->arch != cputyp && mp->arch != ANY)
continue;
#define MATCH(x) (mp->x == x || mp->x == ANY)
if (!MATCH(cpu_impl) ||
!MATCH(cpu_vers) ||
!MATCH(mmu_impl) ||
!MATCH(mmu_vers))
continue;
#undef MATCH
sc->cpu_impl = cpu_impl;
sc->cpu_vers = cpu_vers;
sc->mmu_impl = mmu_impl;
sc->mmu_vers = mmu_vers;
if (mp->minfo->cpu_match) {
mp->minfo->cpu_match(sc, mp->minfo, node);
}
if (sc->cpu_longname == 0)
sc->cpu_longname = mp->name;
if (sc->mmu_ncontext == 0)
sc->mmu_ncontext = mp->minfo->ncontext;
if (sc->cpu_type == 0)
sc->cpu_type = mp->minfo->cpu_type;
if (sc->cacheinfo.c_vactype == VAC_UNKNOWN)
sc->cacheinfo.c_vactype = mp->minfo->vactype;
if (sc->master && mp->minfo->getmid != NULL)
bootmid = mp->minfo->getmid();
mp->minfo->getcacheinfo(sc, node);
if (node && sc->hz == 0 && !CPU_ISSUN4) {
sc->hz = prom_getpropint(node, "clock-frequency", 0);
if (sc->hz == 0) {
sc->hz = prom_getpropint(findroot(),
"clock-frequency", 0);
}
}
#define MPCOPY(x) if (sc->x == 0) sc->x = mp->minfo->x;
MPCOPY(hotfix);
MPCOPY(mmu_enable);
MPCOPY(cache_enable);
MPCOPY(get_syncflt);
MPCOPY(get_asyncflt);
MPCOPY(cache_flush);
MPCOPY(sp_vcache_flush_page);
MPCOPY(sp_vcache_flush_segment);
MPCOPY(sp_vcache_flush_region);
MPCOPY(sp_vcache_flush_context);
MPCOPY(sp_vcache_flush_range);
MPCOPY(ft_vcache_flush_page);
MPCOPY(ft_vcache_flush_segment);
MPCOPY(ft_vcache_flush_region);
MPCOPY(ft_vcache_flush_context);
MPCOPY(ft_vcache_flush_range);
MPCOPY(pcache_flush_page);
MPCOPY(pure_vcache_flush);
MPCOPY(cache_flush_all);
MPCOPY(memerr);
MPCOPY(zero_page);
MPCOPY(copy_page);
#undef MPCOPY
sc->vcache_flush_page = sc->sp_vcache_flush_page;
sc->vcache_flush_segment = sc->sp_vcache_flush_segment;
sc->vcache_flush_region = sc->sp_vcache_flush_region;
sc->vcache_flush_context = sc->sp_vcache_flush_context;
(*sc->cache_flush_all)();
return;
}
panic("Out of CPUs");
}
struct info {
int valid;
int iu_impl;
int iu_vers;
int fpu_vers;
const char *name;
};
static struct info fpu_types[] = {
{ 1, 0x0, ANY, 0, "MB86910 or WTL1164/5" },
{ 1, 0x0, ANY, 1, "MB86911 or WTL1164/5" },
{ 1, 0x0, ANY, 2, "L64802 or ACT8847" },
{ 1, 0x0, ANY, 3, "WTL3170/2" },
{ 1, 0x0, 4, 4, "on-chip" },
{ 1, 0x0, 5, 5, "on-chip" },
{ 1, 0x0, ANY, 4, "L64804" },
{ 1, 0x1, 0xf, 0, "on-chip" },
{ 1, 0x1, 0xe, 0, "on-chip" },
{ 1, 0x1, ANY, 0, "L64812 or ACT8847" },
{ 1, 0x1, ANY, 1, "L64814" },
{ 1, 0x1, ANY, 2, "TMS390C602A" },
{ 1, 0x1, ANY, 3, "RT602 or WTL3171" },
{ 1, 0x2, ANY, 0, "B5010 or B5110/20 or B5210" },
{ 1, 0x4, ANY, 0, "on-chip" },
{ 1, 0x4, ANY, 4, "on-chip" },
{ 1, 0x5, ANY, 0, "on-chip" },
{ 1, 0x9, ANY, 3, "on-chip" },
{ 0 }
};
static const char *
fsrtoname(int impl, int vers, int fver)
{
struct info *p;
for (p = fpu_types; p->valid; p++) {
if (p->iu_impl == impl &&
(p->iu_vers == vers || p->iu_vers == ANY) &&
(p->fpu_vers == fver))
return (p->name);
}
return (NULL);
}
#ifdef DDB
#include <ddb/db_output.h>
#include <machine/db_machdep.h>
#include "ioconf.h"
void
cpu_debug_dump(void)
{
struct cpu_info *ci;
CPU_INFO_ITERATOR cii;
db_printf("%-4s %-10s %-8s %-10s %-10s %-10s %-10s\n",
"CPU#", "CPUINFO", "FLAGS", "CURLWP", "CURPROC", "FPLWP", "CPCB");
for (CPU_INFO_FOREACH(cii, ci)) {
db_printf("%-4d %-10p %-8x %-10p %-10p %-10p %-10p\n",
ci->ci_cpuid,
ci,
ci->flags,
ci->ci_curlwp,
ci->ci_curlwp == NULL ? NULL : ci->ci_curlwp->l_proc,
ci->fplwp,
ci->curpcb);
}
}
#if defined(MULTIPROCESSOR)
void
cpu_xcall_dump(void)
{
struct cpu_info *ci;
CPU_INFO_ITERATOR cii;
db_printf("%-4s %-10s %-10s %-10s %-10s %-10s "
"%-4s %-4s %-4s\n",
"CPU#", "FUNC", "TRAP", "ARG0", "ARG1", "ARG2",
"TAG", "RECV", "COMPL");
for (CPU_INFO_FOREACH(cii, ci)) {
db_printf("%-4d %-10p %-10p 0x%-8x 0x%-8x 0x%-8x "
"%-4d %-4d %-4d\n",
ci->ci_cpuid,
ci->msg.u.xpmsg_func.func,
ci->msg.u.xpmsg_func.trap,
ci->msg.u.xpmsg_func.arg0,
ci->msg.u.xpmsg_func.arg1,
ci->msg.u.xpmsg_func.arg2,
ci->msg.tag,
ci->msg.received,
ci->msg.complete);
}
}
#endif
#endif