diff --git a/sys/arch/macppc/macppc/cpu.c b/sys/arch/macppc/macppc/cpu.c index bb91392e9c18..1056fe10f113 100644 --- a/sys/arch/macppc/macppc/cpu.c +++ b/sys/arch/macppc/macppc/cpu.c @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.c,v 1.6 2000/02/08 12:49:06 tsubai Exp $ */ +/* $NetBSD: cpu.c,v 1.7 2000/07/05 16:02:38 tsubai Exp $ */ /*- * Copyright (C) 1998, 1999 Internet Research Institute, Inc. @@ -31,26 +31,55 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "opt_multiprocessor.h" + #include #include #include +#include #include + #include +#include +#include +#include -static int cpumatch __P((struct device *, struct cfdata *, void *)); -static void cpuattach __P((struct device *, struct device *, void *)); +int cpumatch(struct device *, struct cfdata *, void *); +void cpuattach(struct device *, struct device *, void *); -static void ohare_init __P((void)); -static void display_l2cr __P((void)); +void identifycpu(char *); +static void ohare_init(void); +static void display_l2cr(void); +int cpu_spinup(void); +void cpu_hatch(void); + +void cpu_spinup_trampoline(void); struct cfattach cpu_ca = { sizeof(struct device), cpumatch, cpuattach }; +int ncpus; + extern struct cfdriver cpu_cd; extern int powersave; +#define HAMMERHEAD 0xf8000000 +#define HH_ARBCONF (HAMMERHEAD + 0x90) +#define HH_INTR (HAMMERHEAD + 0xc0) + +/* XXX for now */ +#undef cpu_number +static inline int +cpu_number() +{ + int pir; + + asm ("mfspr %0,1023" : "=r"(pir)); + return pir; +} + int cpumatch(parent, cf, aux) struct device *parent; @@ -58,11 +87,23 @@ cpumatch(parent, cf, aux) void *aux; { struct confargs *ca = aux; + int *reg = ca->ca_reg; + int hammerhead; if (strcmp(ca->ca_name, cpu_cd.cd_name)) return 0; - return 1; + switch (reg[0]) { + case 0: /* master CPU */ + return 1; + case 1: /* secondary CPU */ + hammerhead = OF_finddevice("/hammerhead"); + if (hammerhead == -1) + return 0; + if (in32rb(HH_ARBCONF) & 0x02) + return 1; + } + return 0; } #define MPC601 1 @@ -83,7 +124,29 @@ cpuattach(parent, self, aux) struct device *parent, *self; void *aux; { + struct confargs *ca = aux; + int *reg = ca->ca_reg; int hid0, pvr; + char model[80]; + + ncpus++; + + switch (reg[0]) { + case 0: + asm volatile ("mtspr 1023,%0" :: "r"(0)); /* PIR */ + identifycpu(model); + printf(": %s, ID %d (primary)", model, cpu_number()); + break; +/* #ifdef MULTIPROCESSOR */ + case 1: + cpu_spinup(); + printf("\n"); + return; +/* #endif */ + default: + printf(": more than 2 cpus?\n"); + panic("cpuattach"); + } __asm __volatile ("mfpvr %0" : "=r"(pvr)); switch (pvr >> 16) { @@ -116,6 +179,47 @@ cpuattach(parent, self, aux) printf("\n"); } +struct cputab { + int version; + char *name; +}; +static struct cputab models[] = { + { 1, "601" }, + { 3, "603" }, + { 4, "604" }, + { 5, "602" }, + { 6, "603e" }, + { 7, "603ev" }, + { 8, "750" }, + { 9, "604ev" }, + { 12, "7400" }, + { 20, "620" }, + { 0, NULL } +}; + +void +identifycpu(cpu_model) + char *cpu_model; +{ + int pvr, vers, rev; + struct cputab *cp = models; + + asm ("mfpvr %0" : "=r"(pvr)); + vers = pvr >> 16; + rev = pvr & 0xffff; + + while (cp->name) { + if (cp->version == vers) + break; + cp++; + } + if (cp->name) + strcpy(cpu_model, cp->name); + else + sprintf(cpu_model, "Version %x", vers); + sprintf(cpu_model + strlen(cpu_model), " (Revision %x)", rev); +} + #define CACHE_REG 0xf8000000 void @@ -210,3 +314,162 @@ display_l2cr() } printf("\n"); } + +/* #ifdef MULTIPROCESSOR */ +struct cpu_hatch_data { + int running; + int pir; + int hid0; + int sdr1; + int sr[16]; + int tbu, tbl; +}; + +volatile struct cpu_hatch_data *cpu_hatch_data; +volatile int cpu_hatchstack; + +int +cpu_spinup() +{ + volatile struct cpu_hatch_data hatch_data, *h = &hatch_data; + int i; + struct pcb *pcb; + struct pglist mlist; + int error; + + /* + * Allocate UPAGES contiguous pages for the idle PCB and stack + * from the lowest 256MB (because bat0 always maps it va == pa). + */ + TAILQ_INIT(&mlist); + error = uvm_pglistalloc(USPACE, 0x0, 0x10000000, 0, 0, &mlist, 1, 1); + if (error) { + printf(": unable to allocate idle stack"); + return -1; + } + + pcb = (void *)VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); + bzero(pcb, USPACE); + + /* + * Initialize the idle stack pointer, reserving space for an + * (empty) trapframe (XXX is the trapframe really necessary?) + */ + pcb->pcb_sp = (paddr_t)pcb + USPACE - sizeof(struct trapframe); + + cpu_hatch_data = h; + h->running = 0; + h->pir = 1; + cpu_hatchstack = pcb->pcb_sp; + + /* copy special registers */ + asm volatile ("mfspr %0,1008" : "=r"(h->hid0)); + asm volatile ("mfsdr1 %0" : "=r"(h->sdr1)); + for (i = 0; i < 16; i++) + asm ("mfsrin %0,%1" : "=r"(h->sr[i]) : "r"(i << ADDR_SR_SHFT)); + + asm volatile ("sync; isync"); + + /* Start secondary cpu and stop timebase. */ + out32(0xf2800000, (int)cpu_spinup_trampoline); + out32(HH_INTR, ~0); + out32(HH_INTR, 0); + + /* sync timebase (XXX shouldn't be zero'ed) */ + asm volatile ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0)); + + /* + * wait for secondary spin up (1.5ms @ 604/200MHz) + * XXX we cannot use delay() here because timebase is not running. + */ + for (i = 0; i < 100000; i++) + if (h->running) + break; + + /* Start timebase. */ + out32(0xf2800000, 0x100); + out32(HH_INTR, ~0); + out32(HH_INTR, 0); + + delay(100000); /* wait for secondary printf */ + + if (h->running == 0) { + printf(": secondary cpu didn't start"); + return -1; + } + + return 0; +} + +void +cpu_hatch() +{ + volatile struct cpu_hatch_data *h = cpu_hatch_data; + u_int msr; + int i; + char model[80]; + + /* Initialize timebase. */ + asm ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0)); + + /* Set PIR (Processor Identification Register). i.e. whoami */ + asm volatile ("mtspr 1023,%0" :: "r"(h->pir)); + + /* Initialize MMU. */ + asm ("mtibatu 0,%0" :: "r"(0)); + asm ("mtibatu 1,%0" :: "r"(0)); + asm ("mtibatu 2,%0" :: "r"(0)); + asm ("mtibatu 3,%0" :: "r"(0)); + asm ("mtdbatu 0,%0" :: "r"(0)); + asm ("mtdbatu 1,%0" :: "r"(0)); + asm ("mtdbatu 2,%0" :: "r"(0)); + asm ("mtdbatu 3,%0" :: "r"(0)); + + asm ("mtspr 1008,%0" :: "r"(h->hid0)); + + asm ("mtibatl 0,%0; mtibatu 0,%1;" + "mtdbatl 0,%0; mtdbatu 0,%1;" + :: "r"(battable[0].batl), "r"(battable[0].batu)); + + /* XXX obio (for now) */ + asm ("mtibatl 1,%0; mtibatu 1,%1;" + "mtdbatl 1,%0; mtdbatu 1,%1;" + :: "r"(battable[0xf].batl), "r"(battable[0xf].batu)); + + for (i = 0; i < 16; i++) + asm ("mtsrin %0,%1" :: "r"(h->sr[i]), "r"(i << ADDR_SR_SHFT)); + asm ("mtsdr1 %0" :: "r"(h->sdr1)); + + asm volatile ("isync"); + + /* Enable I/D address translations. */ + asm volatile ("mfmsr %0" : "=r"(msr)); + msr |= PSL_IR|PSL_DR|PSL_ME|PSL_RI; + asm volatile ("mtmsr %0" :: "r"(msr)); + + asm volatile ("sync; isync"); + h->running = 1; + + identifycpu(model); + printf(": %s, ID %d", model, cpu_number()); + + /* XXX Enter power-saving mode and never return. */ + asm volatile (" + 1: + sync + mtmsr %0 + isync + b 1b + " :: "r"(PSL_POW)); + + for (;;); +} +/* #endif MULTIPROCESSOR */ + +#ifdef MULTIPROCESSOR +void +cpu_boot_secondary_processors() +{ + /* currently noop */ +} +#endif /* MULTIPROCESSOR */ diff --git a/sys/arch/macppc/macppc/locore.S b/sys/arch/macppc/macppc/locore.S index 76baa68b346c..47687684316e 100644 --- a/sys/arch/macppc/macppc/locore.S +++ b/sys/arch/macppc/macppc/locore.S @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.24 2000/05/31 05:09:17 thorpej Exp $ */ +/* $NetBSD: locore.S,v 1.25 2000/07/05 16:02:39 tsubai Exp $ */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. @@ -1486,3 +1486,25 @@ _C_LABEL(setfault): stmw 12,12(3) xor 3,3,3 blr + +/* #ifdef MULTIPROCESSOR */ + .globl _C_LABEL(cpu_spinup_trampoline) +_C_LABEL(cpu_spinup_trampoline): + li 0,0 + mtmsr 0 + isync + + lis 3,cpu_hatchstack@ha + lwz 1,cpu_hatchstack@l(3) + + bl _C_LABEL(cpu_hatch) + +1: + sync + mfmsr 3 + oris 3,3,PSL_POW@h + mtmsr 3 + isync + b 1b + +/* #endif */ diff --git a/sys/arch/macppc/macppc/machdep.c b/sys/arch/macppc/macppc/machdep.c index 3db568fdc7f4..925b7b81a1b7 100644 --- a/sys/arch/macppc/macppc/machdep.c +++ b/sys/arch/macppc/macppc/machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.77 2000/07/02 04:40:39 cgd Exp $ */ +/* $NetBSD: machdep.c,v 1.78 2000/07/05 16:02:39 tsubai Exp $ */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. @@ -392,60 +392,10 @@ restore_ofw_mapping() /* * This should probably be in autoconf! XXX */ -int cpu; char cpu_model[80]; char machine[] = MACHINE; /* from */ char machine_arch[] = MACHINE_ARCH; /* from */ -void -identifycpu() -{ - int pvr; - - /* - * Find cpu type (Do it by OpenFirmware?) - */ - asm ("mfpvr %0" : "=r"(pvr)); - cpu = pvr >> 16; - switch (cpu) { - case 1: - sprintf(cpu_model, "601"); - break; - case 3: - sprintf(cpu_model, "603"); - break; - case 4: - sprintf(cpu_model, "604"); - break; - case 5: - sprintf(cpu_model, "602"); - break; - case 6: - sprintf(cpu_model, "603e"); - break; - case 7: - sprintf(cpu_model, "603ev"); - break; - case 8: - sprintf(cpu_model, "750"); - break; - case 9: - sprintf(cpu_model, "604ev"); - break; - case 12: - sprintf(cpu_model, "7400"); - break; - case 20: - sprintf(cpu_model, "620"); - break; - default: - sprintf(cpu_model, "Version %x", cpu); - break; - } - sprintf(cpu_model + strlen(cpu_model), " (Revision %x)", pvr & 0xffff); - printf("CPU: %s\n", cpu_model); -} - void install_extint(handler) void (*handler) __P((void)); @@ -486,7 +436,7 @@ cpu_startup() v = (caddr_t)proc0paddr + USPACE; printf("%s", version); - identifycpu(); + identifycpu(cpu_model); format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); printf("total memory = %s\n", pbuf); diff --git a/sys/arch/macppc/macppc/mainbus.c b/sys/arch/macppc/macppc/mainbus.c index a687bd5fd80e..78bb2f6c6ab2 100644 --- a/sys/arch/macppc/macppc/mainbus.c +++ b/sys/arch/macppc/macppc/mainbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: mainbus.c,v 1.7 2000/02/03 19:27:45 tsubai Exp $ */ +/* $NetBSD: mainbus.c,v 1.8 2000/07/05 16:02:39 tsubai Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -69,12 +69,19 @@ mainbus_attach(parent, self, aux) { struct ofbus_attach_args oba; struct confargs ca; - int node; + int node, i; u_int32_t reg[4]; char name[32]; printf("\n"); + for (i = 0; i < 2; i++) { + ca.ca_name = "cpu"; + ca.ca_reg = reg; + reg[0] = i; + config_found(self, &ca, NULL); + } + node = OF_peer(0); if (node) { oba.oba_busname = "ofw"; @@ -82,9 +89,6 @@ mainbus_attach(parent, self, aux) config_found(self, &oba, NULL); } - ca.ca_name = "cpu"; - config_found(self, &ca, NULL); - for (node = OF_child(OF_finddevice("/")); node; node = OF_peer(node)) { bzero(name, sizeof(name)); if (OF_getprop(node, "name", name, sizeof(name)) == -1)