#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/msgbuf.h>
#include <sys/tty.h>
#include <sys/user.h>
#include <sys/exec.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <sys/exec_elf.h>
#ifdef SYSVSHM
#include <sys/shm.h>
#endif
#ifdef SYSVSEM
#include <sys/sem.h>
#endif
#include <net/if.h>
#include <uvm/uvm_extern.h>
#include <machine/db_machdep.h>
#include <ddb/db_interface.h>
#include <machine/autoconf.h>
#include <mips64/cache.h>
#include <machine/cpu.h>
#include <mips64/mips_cpu.h>
#include <machine/memconf.h>
#include <machine/pmon.h>
#include <dev/cons.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
char machine[] = MACHINE;
char cpu_model[30];
char pmon_bootp[80];
struct uvm_constraint_range dma_constraint = { 0x0, 0xffffffffUL };
struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
vm_map_t exec_map;
vm_map_t phys_map;
int safepri = 0;
caddr_t msgbufbase;
int physmem;
int ncpu = 1;
int nnodes = 1;
struct user *proc0paddr;
int lid_action = 1;
int pwr_action = 1;
#ifdef MULTIPROCESSOR
uint64_t cpu_spinup_a0;
uint64_t cpu_spinup_sp;
uint32_t ipi_mask;
#endif
const struct platform *sys_platform;
struct cpu_hwinfo bootcpu_hwinfo;
void *loongson_videobios;
uint loongson_cpumask = 1;
uint loongson_ver;
caddr_t ssym;
caddr_t esym;
caddr_t ekern;
struct phys_mem_desc mem_layout[MAXMEMSEGS];
paddr_t loongson_memlo_alias;
pcitag_t (*pci_make_tag_early)(int, int, int);
pcireg_t (*pci_conf_read_early)(pcitag_t, int);
bus_space_tag_t early_mem_t;
bus_space_tag_t early_io_t;
static u_long atoi(const char *, uint);
static void dobootopts(int);
void dumpsys(void);
void dumpconf(void);
extern void parsepmonbp(void);
const struct platform *loongson_identify(const char *, int);
vaddr_t mips_init(uint64_t, uint64_t, uint64_t, uint64_t, char *);
extern void htb_early_setup(void);
extern void loongson2e_setup(u_long, u_long);
extern void loongson2f_setup(u_long, u_long);
extern void loongson3a_setup(u_long, u_long);
cons_decl(pmon);
struct consdev pmoncons = {
NULL,
NULL,
pmoncngetc,
pmoncnputc,
nullcnpollc,
NULL,
makedev(0, 0),
CN_DEAD
};
struct bonito_flavour {
const char *prefix;
const struct platform *platform;
};
extern const struct platform ebenton_platform;
extern const struct platform fuloong_platform;
extern const struct platform gdium_platform;
extern const struct platform generic2e_platform;
extern const struct platform lynloong_platform;
extern const struct platform rs780e_platform;
extern const struct platform yeeloong_platform;
const struct bonito_flavour bonito_flavours[] = {
#ifdef CPU_LOONGSON2
{ "EBT700", &ebenton_platform },
{ "LM6002", &fuloong_platform },
{ "LM6003", &fuloong_platform },
{ "LM6004", &fuloong_platform },
{ "Gdium", &gdium_platform },
{ "LM8089", &yeeloong_platform },
{ "LM8101", &yeeloong_platform },
{ "LM9001", &lynloong_platform },
{ "LM9002", &lynloong_platform },
{ "LM9003", &lynloong_platform },
{ "LM9013", &lynloong_platform },
#endif
#ifdef CPU_LOONGSON3
{ "A1004", &rs780e_platform },
{ "A1201", &rs780e_platform },
{ "A1101", &rs780e_platform },
{ "A1205", &rs780e_platform },
#endif
{ NULL }
};
const struct platform *
loongson_identify(const char *version, int envtype)
{
const struct bonito_flavour *f;
switch (envtype) {
#ifdef CPU_LOONGSON3
case PMON_ENVTYPE_EFI:
if (loongson_ver == 0x3a || loongson_ver == 0x3b) {
pcitag_t tag;
pcireg_t id;
htb_early_setup();
tag = pci_make_tag_early(0, 0, 0);
id = pci_conf_read_early(tag, PCI_ID_REG);
switch (id) {
case PCI_ID_CODE(PCI_VENDOR_AMD,
PCI_PRODUCT_AMD_RS780_HB):
return &rs780e_platform;
}
}
pmon_printf("Unable to figure out model!\n");
return NULL;
#endif
default:
case PMON_ENVTYPE_ENVP:
if (version == NULL) {
#ifdef CPU_LOONGSON2
if (loongson_ver == 0x2e)
return &generic2e_platform;
#endif
pmon_printf("Unable to figure out model!\n");
return NULL;
}
for (f = bonito_flavours; f->prefix != NULL; f++)
if (strncmp(version, f->prefix, strlen(f->prefix)) == 0)
return f->platform;
#ifdef CPU_LOONGSON2
if (strncmp(version, "1.2.", 4) == 0) {
const struct platform *p = NULL;
pcitag_t tag;
pcireg_t id, class;
int dev;
pmon_printf("No model prefix "
"in version string \"%s\".\n", version);
if (loongson_ver == 0x2f)
for (dev = 0; dev < 32; dev++) {
tag = pci_make_tag_early(0, dev, 0);
id = pci_conf_read_early(tag,
PCI_ID_REG);
if (id == 0 || PCI_VENDOR(id) ==
PCI_VENDOR_INVALID)
continue;
class = pci_conf_read_early(tag,
PCI_CLASS_REG);
if (PCI_CLASS(class) !=
PCI_CLASS_DISPLAY ||
(PCI_SUBCLASS(class) !=
PCI_SUBCLASS_DISPLAY_VGA &&
PCI_SUBCLASS(class) !=
PCI_SUBCLASS_DISPLAY_MISC))
continue;
switch (id) {
case PCI_ID_CODE(PCI_VENDOR_SIS,
PCI_PRODUCT_SIS_315PRO_VGA):
p = &fuloong_platform;
break;
case PCI_ID_CODE(PCI_VENDOR_SMI,
PCI_PRODUCT_SMI_SM712):
p = &ebenton_platform;
break;
}
}
if (p != NULL) {
pmon_printf("Attempting to match as "
"%s %s\n", p->vendor, p->product);
return p;
}
}
#endif
}
pmon_printf("This kernel doesn't support model \"%s\"." "\n", version);
return NULL;
}
int
loongson_efi_setup(void)
{
struct pmon_env_mem_entry entry;
const struct pmon_env_cpu *cpuenv;
const struct pmon_env_mem *mem;
paddr_t fp, lp;
uint32_t i, ncpus, seg = 0;
cpuenv = pmon_get_env_cpu();
bootcpu_hwinfo.clock = cpuenv->speed;
ncpus = cpuenv->ncpus;
if (ncpus > LOONGSON_MAXCPUS)
ncpus = LOONGSON_MAXCPUS;
loongson_cpumask = (1u << ncpus) - 1;
loongson_cpumask &= ~(uint)cpuenv->reserved_cores;
ncpusfound = 0;
for (i = 0; i < ncpus; i++) {
if (ISSET(loongson_cpumask, 1u << i))
ncpusfound++;
}
mem = pmon_get_env_mem();
physmem = 0;
for (i = 0; i < mem->nentries && seg < MAXMEMSEGS; i++) {
memcpy(&entry, &mem->mem_map[i], sizeof(entry));
if (entry.node != 0 ||
(entry.type != PMON_MEM_SYSTEM_LOW &&
entry.type != PMON_MEM_SYSTEM_HIGH))
continue;
fp = atop(entry.address);
lp = atop(entry.address + ((uint64_t)entry.size << 20));
if (lp > atop(pfn_to_pad(PG_FRAME)) + 1)
lp = atop(pfn_to_pad(PG_FRAME)) + 1;
if (fp >= lp)
continue;
physmem += lp - fp;
mem_layout[seg].mem_first_page = fp;
mem_layout[seg].mem_last_page = lp;
seg++;
}
return 0;
}
int
loongson_envp_setup(void)
{
const char *envvar;
u_long cpuspeed, memlo, memhi;
cpuspeed = 0;
envvar = pmon_getenv("cpuclock");
if (envvar != NULL)
cpuspeed = atoi(envvar, 10);
if (cpuspeed < 100 * 1000000)
cpuspeed = 797000000;
bootcpu_hwinfo.clock = cpuspeed;
switch (loongson_ver) {
#ifdef CPU_LOONGSON3
case 0x3a:
loongson_cpumask = 0x0f;
ncpusfound = 4;
break;
case 0x3b:
loongson_cpumask = 0xff;
ncpusfound = 8;
break;
#endif
}
envvar = pmon_getenv("memsize");
if (envvar == NULL) {
pmon_printf("Could not get memory information"
" from the firmware\n");
return -1;
}
memlo = atoi(envvar, 10);
if (memlo < 0 || memlo > 256) {
pmon_printf("Incorrect low memory size `%s'\n", envvar);
return -1;
}
if (memlo >= 240) {
envvar = pmon_getenv("highmemsize");
if (envvar == NULL)
memhi = 0;
else
memhi = atoi(envvar, 10);
if (memhi < 0 || memhi > (64 * 1024) - 256) {
pmon_printf("Incorrect high memory size `%s'\n",
envvar);
return -1;
}
} else
memhi = 0;
switch (loongson_ver) {
default:
#ifdef CPU_LOONGSON2
case 0x2e:
loongson2e_setup(memlo, memhi);
break;
case 0x2f:
loongson2f_setup(memlo, memhi);
break;
#endif
#ifdef CPU_LOONGSON3
case 0x3a:
loongson3a_setup(memlo, memhi);
break;
#endif
}
return 0;
}
vaddr_t
mips_init(uint64_t argc, uint64_t argv, uint64_t envp, uint64_t cv,
char *boot_esym)
{
uint32_t prid;
vaddr_t xtlb_handler;
const char *envvar;
int i;
extern char start[], edata[], end[];
extern char exception[], e_exception[];
extern void xtlb_miss;
#ifdef MULTIPROCESSOR
setcurcpu(&cpu_info_primary);
#endif
setsr(getsr() | SR_KX | SR_UX);
bzero(edata, end - edata);
prid = cp0_get_prid();
pmon_init((int32_t)argc, (int32_t)argv, (int32_t)envp, (int32_t)cv,
prid);
cn_tab = &pmoncons;
if (end[0] == ELFMAG0 && end[1] == ELFMAG1 &&
end[2] == ELFMAG2 && end[3] == ELFMAG3) {
ssym = end;
esym = boot_esym;
ekern = esym;
} else {
ssym = (char *)(vaddr_t)*(int32_t *)end;
if (((long)ssym - (long)end) >= 0 &&
((long)ssym - (long)end) <= 0x1000 &&
ssym[0] == ELFMAG0 && ssym[1] == ELFMAG1 &&
ssym[2] == ELFMAG2 && ssym[3] == ELFMAG3) {
esym = (char *)(vaddr_t)*((int32_t *)end + 1);
ekern = esym;
} else {
ssym = NULL;
esym = NULL;
ekern = end;
}
}
switch ((prid >> 8) & 0xff) {
case MIPS_LOONGSON2:
switch (prid & 0xff) {
#ifdef CPU_LOONGSON2
#ifdef CPU_LOONGSON2C
case 0x00:
loongson_ver = 0x2c;
break;
#endif
case 0x02:
loongson_ver = 0x2e;
break;
case 0x03:
loongson_ver = 0x2f;
break;
#endif
#ifdef CPU_LOONGSON3
case 0x05:
case 0x08:
loongson_ver = 0x3a;
break;
#endif
default:
break;
}
}
if (loongson_ver == 0) {
pmon_printf("This kernel doesn't support processor type 0x%x"
", version %d.%d.\n",
(prid >> 8) & 0xff, (prid >> 4) & 0x0f, prid & 0x0f);
goto unsupported;
}
switch (pmon_getenvtype()) {
default:
pmon_printf("Unable to figure out "
"firmware environment information!\n");
goto unsupported;
case PMON_ENVTYPE_EFI:
break;
case PMON_ENVTYPE_ENVP:
envvar = pmon_getenv("systype");
if (envvar == NULL) {
pmon_printf("Unable to figure out system type!\n");
goto unsupported;
}
if (strcmp(envvar, "Bonito") != 0) {
pmon_printf("This kernel doesn't support system type \"%s\".\n",
envvar);
goto unsupported;
}
}
if ((sys_platform = loongson_identify(pmon_getenv("Version"),
pmon_getenvtype())) == NULL)
goto unsupported;
hw_vendor = sys_platform->vendor;
hw_prod = sys_platform->product;
pmon_printf("Found %s %s, setting up.\n", hw_vendor, hw_prod);
snprintf(cpu_model, sizeof cpu_model, "Loongson %X", loongson_ver);
boothowto = RB_AUTOBOOT;
dobootopts(argc);
switch (pmon_getenvtype()) {
case PMON_ENVTYPE_EFI:
if (loongson_efi_setup() != 0)
goto unsupported;
break;
case PMON_ENVTYPE_ENVP:
if (loongson_envp_setup() != 0)
goto unsupported;
break;
}
if (sys_platform->setup != NULL)
(*(sys_platform->setup))();
uvmexp.pagesize = PAGE_SIZE;
uvm_setpagesize();
for (i = 0; i < MAXMEMSEGS && mem_layout[i].mem_last_page != 0; i++) {
uint64_t fp, lp;
uint64_t firstkernpage, lastkernpage;
paddr_t firstkernpa, lastkernpa;
firstkernpa = CKSEG0_TO_PHYS((vaddr_t)start);
lastkernpa = CKSEG0_TO_PHYS((vaddr_t)ekern);
firstkernpage = atop(trunc_page(firstkernpa));
lastkernpage = atop(round_page(lastkernpa));
if (loongson_memlo_alias != 0) {
firstkernpage += atop(loongson_memlo_alias);
lastkernpage += atop(loongson_memlo_alias);
}
fp = mem_layout[i].mem_first_page;
lp = mem_layout[i].mem_last_page;
if (fp >= firstkernpage && lp < lastkernpage)
continue;
if (lp < firstkernpage || fp > lastkernpage) {
uvm_page_physload(fp, lp, fp, lp, 0);
continue;
}
if (fp >= firstkernpage)
fp = lastkernpage;
else if (lp < lastkernpage)
lp = firstkernpage;
else {
uint64_t xp = firstkernpage;
uvm_page_physload(fp, xp, fp, xp, 0);
fp = lastkernpage;
}
if (lp > fp) {
uvm_page_physload(fp, lp, fp, lp, 0);
}
}
bootcpu_hwinfo.c0prid = prid;
bootcpu_hwinfo.type = (prid >> 8) & 0xff;
bootcpu_hwinfo.c1prid = bootcpu_hwinfo.c0prid;
switch (loongson_ver) {
default:
#ifdef CPU_LOONGSON2
#ifdef CPU_LOONGSON2C
case 0x2c:
#endif
case 0x2e:
case 0x2f:
bootcpu_hwinfo.tlbsize = 64;
Loongson2_ConfigCache(curcpu());
Loongson2_SyncCache(curcpu());
break;
#endif
#ifdef CPU_LOONGSON3
case 0x3a:
bootcpu_hwinfo.tlbsize =
1 + ((cp0_get_config_1() & CONFIG1_MMUSize1) >>
CONFIG1_MMUSize1_SHIFT);
Loongson3_ConfigCache(curcpu());
Loongson3_SyncCache(curcpu());
break;
#endif
}
tlb_init(bootcpu_hwinfo.tlbsize);
consinit();
printf("Initial setup done, switching console.\n");
for (i = 0; i < vm_nphysseg; i++) {
struct vm_physseg *vps = &vm_physmem[i];
uint npg = atop(round_page(MSGBUFSIZE));
int j;
if (vps->avail_start != vps->start ||
vps->avail_start >= vps->avail_end) {
continue;
}
if ((vps->avail_end - vps->avail_start) < npg)
continue;
msgbufbase = (caddr_t)PHYS_TO_XKPHYS(ptoa(vps->avail_start),
CCA_CACHED);
vps->avail_start += npg;
vps->start += npg;
if (vps->avail_start == vps->end) {
vm_nphysseg--;
for (j = i; j < vm_nphysseg; j++)
vm_physmem[j] = vm_physmem[j + 1];
}
break;
}
if (msgbufbase == NULL)
panic("not enough contiguous memory for message buffer");
initmsgbuf(msgbufbase, MSGBUFSIZE);
proc0.p_addr = proc0paddr = curcpu()->ci_curprocpaddr =
(struct user *)pmap_steal_memory(USPACE, NULL, NULL);
proc0.p_md.md_regs = (struct trapframe *)&proc0paddr->u_pcb.pcb_regs;
tlb_set_pid(MIN_USER_ASID);
pmap_bootstrap();
bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception);
bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception);
xtlb_handler = (vaddr_t)&xtlb_miss;
build_trampoline(TLB_MISS_EXC_VEC, xtlb_handler);
build_trampoline(XTLB_MISS_EXC_VEC, xtlb_handler);
setsr(getsr() & ~SR_BOOT_EXC_VEC);
proc0.p_md.md_regs->sr = getsr();
#ifdef DDB
db_machine_init();
if (boothowto & RB_KDB)
db_enter();
#endif
return ((vaddr_t)proc0paddr + USPACE - 64);
unsupported:
pmon_printf("Halting system.\nPress enter to return to PMON\n");
cngetc();
return 0;
}
static void
dobootopts(int argc)
{
const char *arg;
const char *cp;
int ignore = 1;
int i;
if (argc != 0) {
arg = pmon_getarg(0);
if (arg == NULL)
return;
if (*arg == 'g')
ignore = 0;
}
for (i = 1; i < argc; i++) {
arg = pmon_getarg(i);
if (arg == NULL)
continue;
if (*arg == '/' || strncmp(arg, "bootduid=", 9) == 0 ||
strncmp(arg, "tftp://", 7) == 0) {
if (*pmon_bootp == '\0') {
strlcpy(pmon_bootp, arg, sizeof pmon_bootp);
parsepmonbp();
}
ignore = 0;
continue;
}
if (*arg != '-' || ignore)
continue;
for (cp = arg + 1; *cp != '\0'; cp++)
switch (*cp) {
case '-':
break;
case 'a':
boothowto |= RB_ASKNAME;
break;
case 'c':
boothowto |= RB_CONFIG;
break;
case 'd':
boothowto |= RB_KDB;
break;
case 's':
boothowto |= RB_SINGLE;
break;
case 'g':
boothowto |= RB_GOODRANDOM;
break;
default:
pmon_printf("unrecognized option `%c'", *cp);
break;
}
}
}
void
consinit()
{
static int console_ok = 0;
if (console_ok == 0) {
cn_tab = NULL;
cninit();
console_ok = 1;
}
}
void
cpu_startup()
{
vaddr_t minaddr, maxaddr;
printf("%s", version);
printf("real mem = %lu (%luMB)\n", ptoa((psize_t)physmem),
ptoa((psize_t)physmem)/1024/1024);
minaddr = vm_map_min(kernel_map);
exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, 0, FALSE, NULL);
printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
ptoa(uvmexp.free)/1024/1024);
bufinit();
if (boothowto & RB_CONFIG) {
#ifdef BOOT_CONFIG
user_config();
#else
printf("kernel does not support -c; continuing..\n");
#endif
}
}
const struct sysctl_bounded_args cpuctl_vars[] = {
{ CPU_LIDACTION, &lid_action, 0, 2 },
};
int
cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
size_t newlen, struct proc *p)
{
return (sysctl_bounded_arr(cpuctl_vars, nitems(cpuctl_vars),
name, namelen, oldp, oldlenp, newp, newlen));
}
int waittime = -1;
__dead void
boot(int howto)
{
void (*__reset)(void) = (void (*)(void))RESET_EXC_VEC;
if ((howto & RB_RESET) != 0)
goto doreset;
if (curproc)
savectx(curproc->p_addr, 0);
if (cold) {
if ((howto & RB_USERREQ) == 0)
howto |= RB_HALT;
goto haltsys;
}
boothowto = howto;
if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
waittime = 0;
vfs_shutdown(curproc);
if ((howto & RB_TIMEBAD) == 0) {
resettodr();
} else {
printf("WARNING: not updating battery clock\n");
}
}
if_downall();
uvm_shutdown();
splhigh();
cold = 1;
if ((howto & RB_DUMP) != 0)
dumpsys();
haltsys:
pci_dopm = 0;
config_suspend_all(DVACT_POWERDOWN);
if ((howto & RB_HALT) != 0) {
if ((howto & RB_POWERDOWN) != 0) {
if (sys_platform->powerdown != NULL) {
printf("System Power Down.\n");
(*(sys_platform->powerdown))();
} else {
printf("System Power Down not supported,"
" halting system.\n");
}
} else
printf("System Halt.\n");
} else {
doreset:
printf("System restart.\n");
if (sys_platform->reset != NULL)
(*(sys_platform->reset))();
(void)disableintr();
tlb_set_wired(0);
tlb_flush(bootcpu_hwinfo.tlbsize);
__reset();
}
for (;;)
continue;
}
u_long dumpmag = 0x8fca0101;
int dumpsize = 0;
long dumplo = 0;
void
dumpconf(void)
{
int nblks;
if (dumpdev == NODEV ||
(nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
return;
if (nblks <= ctod(1))
return;
dumpsize = ptoa(physmem);
if (dumpsize > atop(round_page(dbtob(nblks - dumplo))))
dumpsize = atop(round_page(dbtob(nblks - dumplo)));
else if (dumplo == 0)
dumplo = nblks - btodb(ptoa(physmem));
if (dumplo < btodb(PAGE_SIZE))
dumplo = btodb(PAGE_SIZE);
}
void
dumpsys()
{
}
static u_long
atoi(const char *s, uint b)
{
int c;
uint base = b, d;
int neg = 0;
u_long val = 0;
if (s == NULL || *s == '\0')
return 0;
do {
c = *s++;
} while (c == ' ' || c == '\t');
while (c == '-') {
neg = !neg;
c = *s++;
}
if (base == 0 && c == '0') {
c = *s++;
switch (c) {
case 'X':
case 'x':
base = 16;
c = *s++;
break;
case 'B':
case 'b':
base = 2;
c = *s++;
break;
default:
base = 8;
break;
}
}
for (;;) {
if (c >= '0' && c <= '9')
d = c - '0';
else if (c >= 'a' && c <= 'z')
d = c - 'a' + 10;
else if (c >= 'A' && c <= 'Z')
d = c - 'A' + 10;
else
break;
if (d >= base)
break;
val *= base;
val += d;
c = *s++;
}
return neg ? -val : val;
}
int
pmoncngetc(dev_t dev)
{
static char buf[1 + PMON_MAXLN];
static char *bufpos = buf;
int c;
if (*bufpos == '\0') {
bufpos = buf;
if (pmon_gets(buf) == NULL) {
return (int)'\n';
} else {
buf[strlen(buf)] = '\n';
}
}
c = (int)*bufpos++;
if (bufpos - buf > PMON_MAXLN) {
bufpos = buf;
*bufpos = '\0';
}
return c;
}
void
pmoncnputc(dev_t dev, int c)
{
if (c == '\n')
pmon_printf("\n");
else
pmon_printf("%c", c);
}
void
intr_barrier(void *cookie)
{
sched_barrier(NULL);
}
#ifdef MULTIPROCESSOR
void
hw_cpu_hatch(struct cpu_info *ci)
{
setcurcpu(ci);
setsr(getsr() | SR_KX | SR_UX);
tlb_init(ci->ci_hw.tlbsize);
tlb_set_pid(0);
setsr(getsr() & ~SR_BOOT_EXC_VEC);
switch (loongson_ver) {
#ifdef CPU_LOONGSON3
case 0x3a:
case 0x3b:
Loongson3_ConfigCache(ci);
Loongson3_SyncCache(ci);
break;
#endif
default:
panic("%s: unhandled Loongson version %x", __func__,
loongson_ver);
}
(*md_startclock)(ci);
mips64_ipi_init();
ci->ci_flags |= CPUF_RUNNING;
membar_sync();
spl0();
(void)updateimask(0);
sched_toidle();
}
void
hw_cpu_boot_secondary(struct cpu_info *ci)
{
sys_platform->boot_secondary_cpu(ci);
}
int
hw_ipi_intr_establish(int (*func)(void *), u_long cpuid)
{
if (sys_platform->ipi_establish != NULL)
return sys_platform->ipi_establish(func, cpuid);
else
return 0;
}
void
hw_ipi_intr_set(u_long cpuid)
{
sys_platform->ipi_set(cpuid);
}
void
hw_ipi_intr_clear(u_long cpuid)
{
if (sys_platform->ipi_clear != NULL)
sys_platform->ipi_clear(cpuid);
}
#endif