1 /* $NetBSD: cpu.c,v 1.25 2001/12/05 05:02:11 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 Tsubai Masanari. 5 * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by 19 * Internet Research Institute, Inc. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "opt_l2cr_config.h" 36 #include "opt_multiprocessor.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 42 #include <uvm/uvm_extern.h> 43 #include <dev/ofw/openfirm.h> 44 #include <powerpc/mpc6xx/hid.h> 45 #include <powerpc/openpic.h> 46 47 #include <machine/autoconf.h> 48 #include <machine/bat.h> 49 #include <machine/fpu.h> 50 #include <machine/pcb.h> 51 #include <machine/pio.h> 52 53 int cpumatch(struct device *, struct cfdata *, void *); 54 void cpuattach(struct device *, struct device *, void *); 55 56 void identifycpu(char *); 57 static void ohare_init(void); 58 int cpu_spinup(void); 59 void cpu_hatch(void); 60 void cpu_spinup_trampoline(void); 61 int cpuintr(void *v); 62 63 struct cfattach cpu_ca = { 64 sizeof(struct device), cpumatch, cpuattach 65 }; 66 67 extern struct cfdriver cpu_cd; 68 69 #define HH_ARBCONF 0xf8000090 70 #define HH_INTR_SECONDARY 0xf80000c0 71 #define HH_INTR_PRIMARY 0xf3019000 72 #define GC_IPI_IRQ 30 73 74 int 75 cpumatch(parent, cf, aux) 76 struct device *parent; 77 struct cfdata *cf; 78 void *aux; 79 { 80 struct confargs *ca = aux; 81 int *reg = ca->ca_reg; 82 int node; 83 84 if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0) 85 return 0; 86 87 node = OF_finddevice("/cpus"); 88 if (node != -1) { 89 for (node = OF_child(node); node != 0; node = OF_peer(node)) { 90 uint32_t cpunum; 91 int l; 92 l = OF_getprop(node, "reg", &cpunum, sizeof(cpunum)); 93 if (l == 4 && reg[0] == cpunum) 94 return 1; 95 } 96 } 97 switch (reg[0]) { 98 case 0: /* primary CPU */ 99 return 1; 100 case 1: /* secondary CPU */ 101 if (OF_finddevice("/hammerhead") != -1) 102 if (in32rb(HH_ARBCONF) & 0x02) 103 return 1; 104 break; 105 } 106 107 return 0; 108 } 109 110 void 111 cpuattach(parent, self, aux) 112 struct device *parent, *self; 113 void *aux; 114 { 115 struct cpu_info *ci; 116 struct confargs *ca = aux; 117 int id = ca->ca_reg[0]; 118 119 ci = cpu_attach_common(self, id); 120 121 if (id > 0) { 122 #ifdef MULTIPROCESSOR 123 if (ci != NULL) 124 cpu_spinup(); 125 #endif 126 return; 127 } 128 if (ci == NULL) 129 return; 130 131 if (OF_finddevice("/bandit/ohare") != -1) { 132 printf("%s", self->dv_xname); 133 ohare_init(); 134 } 135 } 136 137 #define CACHE_REG 0xf8000000 138 139 void 140 ohare_init() 141 { 142 u_int *cache_reg, x; 143 144 /* enable L2 cache */ 145 cache_reg = mapiodev(CACHE_REG, NBPG); 146 if (((cache_reg[2] >> 24) & 0x0f) >= 3) { 147 x = cache_reg[4]; 148 if ((x & 0x10) == 0) 149 x |= 0x04000000; 150 else 151 x |= 0x04000020; 152 153 cache_reg[4] = x; 154 printf(": ohare L2 cache enabled\n"); 155 } 156 } 157 158 #ifdef MULTIPROCESSOR 159 160 struct cpu_hatch_data { 161 int running; 162 int pir; 163 int hid0; 164 int sdr1; 165 int sr[16]; 166 int tbu, tbl; 167 }; 168 169 volatile struct cpu_hatch_data *cpu_hatch_data; 170 volatile int cpu_hatch_stack; 171 172 int 173 cpu_spinup() 174 { 175 volatile struct cpu_hatch_data hatch_data, *h = &hatch_data; 176 int i; 177 struct pcb *pcb; 178 struct pglist mlist; 179 int error; 180 int size = 0; 181 char *cp; 182 183 /* 184 * Allocate some contiguous pages for the idle PCB and stack 185 * from the lowest 256MB (because bat0 always maps it va == pa). 186 */ 187 TAILQ_INIT(&mlist); 188 size += USPACE; 189 size += 8192; /* INTSTK */ 190 size += 4096; /* SPILLSTK */ 191 192 error = uvm_pglistalloc(size, 0x0, 0x10000000, 0, 0, &mlist, 1, 1); 193 if (error) { 194 printf(": unable to allocate idle stack\n"); 195 return -1; 196 } 197 198 cp = (void *)VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); 199 memset(cp, 0, size); 200 201 pcb = (struct pcb *)cp; 202 cp += USPACE; 203 cpu_info[1].ci_idle_pcb = pcb; 204 205 cpu_info[1].ci_intstk = cp + 8192; 206 cp += 8192; 207 cpu_info[1].ci_spillstk = cp + 4096; 208 cp += 4096; 209 210 /* 211 * Initialize the idle stack pointer, reserving space for an 212 * (empty) trapframe (XXX is the trapframe really necessary?) 213 */ 214 pcb->pcb_sp = (paddr_t)pcb + USPACE - sizeof(struct trapframe); 215 216 cpu_hatch_data = h; 217 h->running = 0; 218 h->pir = 1; 219 cpu_hatch_stack = pcb->pcb_sp; 220 cpu_info[1].ci_lasttb = cpu_info[0].ci_lasttb; 221 222 /* copy special registers */ 223 asm volatile ("mfspr %0,1008" : "=r"(h->hid0)); 224 asm volatile ("mfsdr1 %0" : "=r"(h->sdr1)); 225 for (i = 0; i < 16; i++) 226 asm ("mfsrin %0,%1" : "=r"(h->sr[i]) : "r"(i << ADDR_SR_SHFT)); 227 228 asm volatile ("sync; isync"); 229 230 if (openpic_base) { 231 /* XXX */ 232 panic("cpu_spinup"); 233 } else { 234 /* Start secondary cpu and stop timebase. */ 235 out32(0xf2800000, (int)cpu_spinup_trampoline); 236 out32(HH_INTR_SECONDARY, ~0); 237 out32(HH_INTR_SECONDARY, 0); 238 239 /* sync timebase (XXX shouldn't be zero'ed) */ 240 asm volatile ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0)); 241 242 /* 243 * wait for secondary spin up (1.5ms @ 604/200MHz) 244 * XXX we cannot use delay() here because timebase is not 245 * running. 246 */ 247 for (i = 0; i < 100000; i++) 248 if (h->running) 249 break; 250 251 /* Start timebase. */ 252 out32(0xf2800000, 0x100); 253 out32(HH_INTR_SECONDARY, ~0); 254 out32(HH_INTR_SECONDARY, 0); 255 } 256 257 delay(100000); /* wait for secondary printf */ 258 259 if (h->running == 0) { 260 printf(": secondary cpu didn't start\n"); 261 return -1; 262 } 263 264 if (!openpic_base) { 265 /* Register IPI. */ 266 intr_establish(GC_IPI_IRQ, IST_LEVEL, IPL_HIGH, cpuintr, NULL); 267 } 268 269 return 0; 270 } 271 272 volatile static int start_secondary_cpu; 273 extern long ticks_per_intr; 274 275 void 276 cpu_hatch() 277 { 278 volatile struct cpu_hatch_data *h = cpu_hatch_data; 279 u_int msr; 280 int i; 281 char model[80]; 282 283 /* Initialize timebase. */ 284 asm ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0)); 285 286 /* Set PIR (Processor Identification Register). i.e. whoami */ 287 asm volatile ("mtspr 1023,%0" :: "r"(h->pir)); 288 asm volatile ("mtsprg 0,%0" :: "r"(&cpu_info[h->pir])); 289 290 /* Initialize MMU. */ 291 asm ("mtibatu 0,%0" :: "r"(0)); 292 asm ("mtibatu 1,%0" :: "r"(0)); 293 asm ("mtibatu 2,%0" :: "r"(0)); 294 asm ("mtibatu 3,%0" :: "r"(0)); 295 asm ("mtdbatu 0,%0" :: "r"(0)); 296 asm ("mtdbatu 1,%0" :: "r"(0)); 297 asm ("mtdbatu 2,%0" :: "r"(0)); 298 asm ("mtdbatu 3,%0" :: "r"(0)); 299 300 asm ("mtspr 1008,%0" :: "r"(h->hid0)); 301 302 asm ("mtibatl 0,%0; mtibatu 0,%1;" 303 "mtdbatl 0,%0; mtdbatu 0,%1;" 304 :: "r"(battable[0].batl), "r"(battable[0].batu)); 305 306 /* XXX obio (for now) */ 307 asm ("mtibatl 1,%0; mtibatu 1,%1;" 308 "mtdbatl 1,%0; mtdbatu 1,%1;" 309 :: "r"(battable[0xf].batl), "r"(battable[0xf].batu)); 310 311 for (i = 0; i < 16; i++) 312 asm ("mtsrin %0,%1" :: "r"(h->sr[i]), "r"(i << ADDR_SR_SHFT)); 313 asm ("mtsdr1 %0" :: "r"(h->sdr1)); 314 315 asm volatile ("isync"); 316 317 /* Enable I/D address translations. */ 318 asm volatile ("mfmsr %0" : "=r"(msr)); 319 msr |= PSL_IR|PSL_DR|PSL_ME|PSL_RI; 320 asm volatile ("mtmsr %0" :: "r"(msr)); 321 322 asm volatile ("sync; isync"); 323 h->running = 1; 324 325 cpu_identify(model, sizeof(model)); 326 printf(": %s, ID %d\n", model, cpu_number()); 327 328 while (start_secondary_cpu == 0); 329 330 printf("secondary CPU started\n"); 331 asm volatile ("mtdec %0" :: "r"(ticks_per_intr)); 332 333 if (!openpic_base) 334 out32(HH_INTR_SECONDARY, ~0); /* Reset interrupt. */ 335 336 curcpu()->ci_ipending = 0; 337 curcpu()->ci_cpl = 0; 338 } 339 340 void 341 cpu_boot_secondary_processors() 342 { 343 start_secondary_cpu = 1; 344 } 345 346 /*static*/ volatile int IPI[2]; 347 348 void 349 macppc_send_ipi(ci, mesg) 350 volatile struct cpu_info *ci; 351 int mesg; 352 { 353 int cpu_id = ci->ci_cpuid; 354 355 /* printf("send_ipi(%d,%d)\n", cpu_id, mesg); */ 356 IPI[cpu_id] |= mesg; 357 358 if (openpic_base) { 359 /* XXX */ 360 } else { 361 switch (cpu_id) { 362 case 0: 363 in32(HH_INTR_PRIMARY); 364 break; 365 case 1: 366 out32(HH_INTR_SECONDARY, ~0); 367 out32(HH_INTR_SECONDARY, 0); 368 break; 369 } 370 } 371 } 372 373 int 374 cpuintr(v) 375 void *v; 376 { 377 int cpu_id = cpu_number(); 378 int msr; 379 380 /* printf("cpuintr{%d}\n", cpu_id); */ 381 382 if (IPI[cpu_id] & MACPPC_IPI_FLUSH_FPU) { 383 if (curcpu()->ci_fpuproc) { 384 save_fpu(curcpu()->ci_fpuproc); 385 if (curcpu()->ci_fpuproc) 386 panic("cpuintr"); 387 } 388 } 389 if (IPI[cpu_id] & MACPPC_IPI_HALT) { 390 printf("halt{%d}\n", cpu_id); 391 asm volatile ("mfmsr %0" : "=r"(msr)); 392 msr &= ~PSL_EE; 393 msr |= PSL_POW; 394 for (;;) { 395 asm volatile ("sync; isync"); 396 asm volatile ("mtmsr %0" :: "r"(msr)); 397 } 398 } 399 IPI[cpu_id] = 0; 400 401 return 1; 402 } 403 #endif /* MULTIPROCESSOR */ 404