Annotation of sys/arch/macppc/macppc/cpu.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cpu.c,v 1.43 2007/05/23 23:40:21 kettenis Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1997 Per Fogelstrom
! 5: * Copyright (c) 1997 RTMX Inc
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed under OpenBSD for RTMX Inc
! 18: * North Carolina, USA, by Per Fogelstrom, Opsycon AB, Sweden.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
! 23: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 24: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 25: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
! 26: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 32: * SUCH DAMAGE.
! 33: *
! 34: */
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/proc.h>
! 39: #include <sys/user.h>
! 40: #include <sys/device.h>
! 41:
! 42: #include <dev/ofw/openfirm.h>
! 43:
! 44: #include <machine/autoconf.h>
! 45: #include <machine/bat.h>
! 46: #include <machine/trap.h>
! 47:
! 48: /* only valid on 603(e,ev) and G3, G4 */
! 49: #define HID0_DOZE (1 << (31-8))
! 50: #define HID0_NAP (1 << (31-9))
! 51: #define HID0_SLEEP (1 << (31-10))
! 52: #define HID0_DPM (1 << (31-11))
! 53: #define HID0_SGE (1 << (31-24))
! 54: #define HID0_BTIC (1 << (31-26))
! 55: #define HID0_LRSTK (1 << (31-27))
! 56: #define HID0_FOLD (1 << (31-28))
! 57: #define HID0_BHT (1 << (31-29))
! 58:
! 59: /* SCOM addresses (24-bit) */
! 60: #define SCOM_PCR 0x0aa001 /* Power Control Register */
! 61: #define SCOM_PSR 0x408001 /* Power Tuning Status Register */
! 62:
! 63: /* SCOMC format */
! 64: #define SCOMC_ADDR_SHIFT 8
! 65: #define SCOMC_ADDR_MASK 0xffff0000
! 66: #define SCOMC_READ 0x00008000
! 67:
! 68: /* Frequency scaling */
! 69: #define FREQ_FULL 0
! 70: #define FREQ_HALF 1
! 71: #define FREQ_QUARTER 2 /* Not supported on IBM 970FX */
! 72:
! 73: /* Power (Tuning) Status Register */
! 74: #define PSR_CMD_RECEIVED 0x2000000000000000LL
! 75: #define PSR_CMD_COMPLETED 0x1000000000000000LL
! 76: #define PSR_FREQ_MASK 0x0300000000000000LL
! 77: #define PSR_FREQ_HALF 0x0100000000000000LL
! 78:
! 79: struct cpu_info cpu_info[PPC_MAXPROCS];
! 80:
! 81: char cpu_model[80];
! 82: char machine[] = MACHINE; /* cpu architecture */
! 83:
! 84: /* Definition of the driver for autoconfig. */
! 85: int cpumatch(struct device *, void *, void *);
! 86: void cpuattach(struct device *, struct device *, void *);
! 87:
! 88: struct cfattach cpu_ca = {
! 89: sizeof(struct device), cpumatch, cpuattach
! 90: };
! 91:
! 92: struct cfdriver cpu_cd = {
! 93: NULL, "cpu", DV_DULL
! 94: };
! 95:
! 96: void ppc64_scale_frequency(u_int);
! 97: void (*ppc64_slew_voltage)(u_int);
! 98: void ppc64_setperf(int);
! 99:
! 100: void config_l2cr(int);
! 101:
! 102: int
! 103: cpumatch(struct device *parent, void *cfdata, void *aux)
! 104: {
! 105: struct confargs *ca = aux;
! 106: int *reg = ca->ca_reg;
! 107:
! 108: /* make sure that we're looking for a CPU. */
! 109: if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0)
! 110: return (0);
! 111:
! 112: if (reg[0] >= PPC_MAXPROCS)
! 113: return (0);
! 114:
! 115: return (1);
! 116: }
! 117:
! 118: static u_int32_t ppc_curfreq;
! 119: static u_int32_t ppc_maxfreq;
! 120: int ppc_altivec;
! 121:
! 122:
! 123: int
! 124: ppc_cpuspeed(int *freq)
! 125: {
! 126: *freq = ppc_curfreq;
! 127:
! 128: return (0);
! 129: }
! 130:
! 131: static u_int32_t ppc_power_mode_data[2];
! 132:
! 133: void
! 134: ppc64_scale_frequency(u_int freq_scale)
! 135: {
! 136: u_int64_t psr;
! 137: int s;
! 138:
! 139: s = ppc_intr_disable();
! 140:
! 141: /* Clear PCRH and PCR. */
! 142: ppc_mtscomd(0x00000000);
! 143: ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);
! 144: ppc_mtscomd(0x80000000);
! 145: ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);
! 146:
! 147: /* Set PCR. */
! 148: ppc_mtscomd(ppc_power_mode_data[freq_scale] | 0x80000000);
! 149: ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);
! 150:
! 151: /* Wait until frequency change is completed. */
! 152: do {
! 153: ppc64_mtscomc((SCOM_PSR << SCOMC_ADDR_SHIFT) | SCOMC_READ);
! 154: psr = ppc64_mfscomd();
! 155: ppc64_mfscomc();
! 156: if (psr & PSR_CMD_COMPLETED)
! 157: break;
! 158: DELAY(100);
! 159: } while (psr & PSR_CMD_RECEIVED);
! 160:
! 161: if ((psr & PSR_FREQ_MASK) == PSR_FREQ_HALF)
! 162: ppc_curfreq = ppc_maxfreq / 2;
! 163: else
! 164: ppc_curfreq = ppc_maxfreq;
! 165:
! 166: ppc_intr_enable(s);
! 167: }
! 168:
! 169: extern int perflevel;
! 170:
! 171: void
! 172: ppc64_setperf(int speed)
! 173: {
! 174: if (speed <= 50) {
! 175: if (ppc_curfreq == ppc_maxfreq / 2)
! 176: return;
! 177:
! 178: ppc64_scale_frequency(FREQ_HALF);
! 179: if (ppc64_slew_voltage)
! 180: ppc64_slew_voltage(FREQ_HALF);
! 181: } else {
! 182: if (ppc_curfreq == ppc_maxfreq)
! 183: return;
! 184:
! 185: if (ppc64_slew_voltage)
! 186: ppc64_slew_voltage(FREQ_FULL);
! 187: ppc64_scale_frequency(FREQ_FULL);
! 188: }
! 189: }
! 190:
! 191: int ppc_proc_is_64b;
! 192: extern u_int32_t rfi_inst, rfid_inst, nop_inst;
! 193: struct patch {
! 194: u_int32_t *s;
! 195: u_int32_t *e;
! 196: };
! 197: extern struct patch rfi_start;
! 198: extern struct patch nop32_start;
! 199: extern struct patch nop64_start;
! 200:
! 201:
! 202: void
! 203: ppc_check_procid()
! 204: {
! 205: u_int32_t cpu, pvr;
! 206: u_int32_t *inst;
! 207: struct patch *p;
! 208:
! 209: pvr = ppc_mfpvr();
! 210: cpu = pvr >> 16;
! 211:
! 212: switch (cpu) {
! 213: case PPC_CPU_IBM970FX:
! 214: case PPC_CPU_IBM970MP:
! 215: ppc_proc_is_64b = 1;
! 216: for (p = &rfi_start; p->s; p++) {
! 217: for (inst = p->s; inst < p->e; inst++)
! 218: *inst = rfid_inst;
! 219: syncicache(p->s, (p->e - p->s) * sizeof(*p->e));
! 220: }
! 221: for (p = &nop64_start; p->s; p++) {
! 222: for (inst = p->s; inst < p->e; inst++)
! 223: *inst = nop_inst;
! 224: syncicache(p->s, (p->e - p->s) * sizeof(*p->e));
! 225: }
! 226:
! 227: break;
! 228: default:
! 229: ppc_proc_is_64b = 0;
! 230: for (p = &nop32_start; p->s; p++) {
! 231: for (inst = p->s; inst < p->e; inst++)
! 232: *inst = nop_inst;
! 233: syncicache(p->s, (p->e - p->s) * sizeof(p->e));
! 234: }
! 235: }
! 236: }
! 237:
! 238: void
! 239: cpuattach(struct device *parent, struct device *dev, void *aux)
! 240: {
! 241: struct confargs *ca = aux;
! 242: int *reg = ca->ca_reg;
! 243: u_int32_t cpu, pvr, hid0;
! 244: char name[32];
! 245: int qhandle, phandle;
! 246: u_int32_t clock_freq = 0;
! 247: struct cpu_info *ci;
! 248:
! 249: ci = &cpu_info[reg[0]];
! 250: ci->ci_cpuid = reg[0];
! 251: ci->ci_intrdepth = -1;
! 252: ci->ci_dev = dev;
! 253:
! 254: pvr = ppc_mfpvr();
! 255: cpu = pvr >> 16;
! 256: switch (cpu) {
! 257: case PPC_CPU_MPC601:
! 258: snprintf(cpu_model, sizeof(cpu_model), "601");
! 259: break;
! 260: case PPC_CPU_MPC603:
! 261: snprintf(cpu_model, sizeof(cpu_model), "603");
! 262: break;
! 263: case PPC_CPU_MPC604:
! 264: snprintf(cpu_model, sizeof(cpu_model), "604");
! 265: break;
! 266: case PPC_CPU_MPC603e:
! 267: snprintf(cpu_model, sizeof(cpu_model), "603e");
! 268: break;
! 269: case PPC_CPU_MPC603ev:
! 270: snprintf(cpu_model, sizeof(cpu_model), "603ev");
! 271: break;
! 272: case PPC_CPU_MPC750:
! 273: snprintf(cpu_model, sizeof(cpu_model), "750");
! 274: break;
! 275: case PPC_CPU_MPC604ev:
! 276: snprintf(cpu_model, sizeof(cpu_model), "604ev");
! 277: break;
! 278: case PPC_CPU_MPC7400:
! 279: ppc_altivec = 1;
! 280: snprintf(cpu_model, sizeof(cpu_model), "7400");
! 281: break;
! 282: case PPC_CPU_MPC7447A:
! 283: ppc_altivec = 1;
! 284: snprintf(cpu_model, sizeof(cpu_model), "7447A");
! 285: break;
! 286: case PPC_CPU_IBM970FX:
! 287: ppc_altivec = 1;
! 288: snprintf(cpu_model, sizeof(cpu_model), "970FX");
! 289: break;
! 290: case PPC_CPU_IBM750FX:
! 291: snprintf(cpu_model, sizeof(cpu_model), "750FX");
! 292: break;
! 293: case PPC_CPU_MPC7410:
! 294: ppc_altivec = 1;
! 295: snprintf(cpu_model, sizeof(cpu_model), "7410");
! 296: break;
! 297: case PPC_CPU_MPC7450:
! 298: ppc_altivec = 1;
! 299: if ((pvr & 0xf) < 3)
! 300: snprintf(cpu_model, sizeof(cpu_model), "7450");
! 301: else
! 302: snprintf(cpu_model, sizeof(cpu_model), "7451");
! 303: break;
! 304: case PPC_CPU_MPC7455:
! 305: ppc_altivec = 1;
! 306: snprintf(cpu_model, sizeof(cpu_model), "7455");
! 307: break;
! 308: case PPC_CPU_MPC7457:
! 309: ppc_altivec = 1;
! 310: snprintf(cpu_model, sizeof(cpu_model), "7457");
! 311: break;
! 312: default:
! 313: snprintf(cpu_model, sizeof(cpu_model), "Version %x", cpu);
! 314: break;
! 315: }
! 316: snprintf(cpu_model + strlen(cpu_model),
! 317: sizeof(cpu_model) - strlen(cpu_model),
! 318: " (Revision 0x%x)", pvr & 0xffff);
! 319: printf(": %s", cpu_model);
! 320:
! 321: /* This should only be executed on openfirmware systems... */
! 322:
! 323: for (qhandle = OF_peer(0); qhandle; qhandle = phandle) {
! 324: if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0
! 325: && !strcmp(name, "cpu")
! 326: && OF_getprop(qhandle, "clock-frequency",
! 327: &clock_freq, sizeof clock_freq) >= 0)
! 328: {
! 329: break;
! 330: }
! 331: if ((phandle = OF_child(qhandle)))
! 332: continue;
! 333: while (qhandle) {
! 334: if ((phandle = OF_peer(qhandle)))
! 335: break;
! 336: qhandle = OF_parent(qhandle);
! 337: }
! 338: }
! 339:
! 340: if (clock_freq != 0) {
! 341: /* Openfirmware stores clock in Hz, not MHz */
! 342: clock_freq /= 1000000;
! 343: printf(": %d MHz", clock_freq);
! 344: ppc_curfreq = ppc_maxfreq = clock_freq;
! 345: cpu_cpuspeed = ppc_cpuspeed;
! 346: }
! 347:
! 348: if (cpu == PPC_CPU_IBM970FX) {
! 349: u_int64_t psr;
! 350: int s;
! 351:
! 352: s = ppc_intr_disable();
! 353: ppc64_mtscomc((SCOM_PSR << SCOMC_ADDR_SHIFT) | SCOMC_READ);
! 354: psr = ppc64_mfscomd();
! 355: ppc64_mfscomc();
! 356: ppc_intr_enable(s);
! 357:
! 358: if ((psr & PSR_FREQ_MASK) == PSR_FREQ_HALF) {
! 359: ppc_curfreq = ppc_maxfreq / 2;
! 360: perflevel = 50;
! 361: }
! 362:
! 363: if (OF_getprop(qhandle, "power-mode-data",
! 364: &ppc_power_mode_data, sizeof ppc_power_mode_data) >= 8)
! 365: cpu_setperf = ppc64_setperf;
! 366: }
! 367:
! 368: /* power savings mode */
! 369: if (ppc_proc_is_64b == 0)
! 370: hid0 = ppc_mfhid0();
! 371: switch (cpu) {
! 372: case PPC_CPU_MPC603:
! 373: case PPC_CPU_MPC603e:
! 374: case PPC_CPU_MPC750:
! 375: case PPC_CPU_MPC7400:
! 376: case PPC_CPU_IBM750FX:
! 377: case PPC_CPU_MPC7410:
! 378: /* select DOZE mode */
! 379: hid0 &= ~(HID0_NAP | HID0_SLEEP);
! 380: hid0 |= HID0_DOZE | HID0_DPM;
! 381: break;
! 382: case PPC_CPU_MPC7447A:
! 383: case PPC_CPU_MPC7450:
! 384: case PPC_CPU_MPC7455:
! 385: case PPC_CPU_MPC7457:
! 386: /* select NAP mode */
! 387: hid0 &= ~(HID0_DOZE | HID0_SLEEP);
! 388: hid0 |= HID0_NAP | HID0_DPM;
! 389: /* try some other flags */
! 390: hid0 |= HID0_SGE | HID0_BTIC;
! 391: hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT;
! 392: /* Disable BTIC on 7450 Rev 2.0 or earlier */
! 393: if (cpu == PPC_CPU_MPC7450 && (pvr & 0xffff) < 0x0200)
! 394: hid0 &= ~HID0_BTIC;
! 395: break;
! 396: case PPC_CPU_IBM970FX:
! 397: /* select NAP mode */
! 398: hid0 &= ~(HID0_DOZE | HID0_SLEEP);
! 399: hid0 |= HID0_NAP | HID0_DPM;
! 400: break;
! 401: }
! 402: if (ppc_proc_is_64b == 0)
! 403: ppc_mthid0(hid0);
! 404:
! 405: /* if processor is G3 or G4, configure l2 cache */
! 406: if (cpu == PPC_CPU_MPC750 || cpu == PPC_CPU_MPC7400 ||
! 407: cpu == PPC_CPU_IBM750FX || cpu == PPC_CPU_MPC7410 ||
! 408: cpu == PPC_CPU_MPC7447A || cpu == PPC_CPU_MPC7450 ||
! 409: cpu == PPC_CPU_MPC7455 || cpu == PPC_CPU_MPC7457) {
! 410: config_l2cr(cpu);
! 411: }
! 412: printf("\n");
! 413: }
! 414:
! 415: /* L2CR bit definitions */
! 416: #define L2CR_L2E 0x80000000 /* 0: L2 enable */
! 417: #define L2CR_L2PE 0x40000000 /* 1: L2 data parity enable */
! 418: #define L2CR_L2SIZ 0x30000000 /* 2-3: L2 size */
! 419: #define L2SIZ_RESERVED 0x00000000
! 420: #define L2SIZ_256K 0x10000000
! 421: #define L2SIZ_512K 0x20000000
! 422: #define L2SIZ_1M 0x30000000
! 423: #define L2CR_L2CLK 0x0e000000 /* 4-6: L2 clock ratio */
! 424: #define L2CLK_DIS 0x00000000 /* disable L2 clock */
! 425: #define L2CLK_10 0x02000000 /* core clock / 1 */
! 426: #define L2CLK_15 0x04000000 /* / 1.5 */
! 427: #define L2CLK_20 0x08000000 /* / 2 */
! 428: #define L2CLK_25 0x0a000000 /* / 2.5 */
! 429: #define L2CLK_30 0x0c000000 /* / 3 */
! 430: #define L2CR_L2RAM 0x01800000 /* 7-8: L2 RAM type */
! 431: #define L2RAM_FLOWTHRU_BURST 0x00000000
! 432: #define L2RAM_PIPELINE_BURST 0x01000000
! 433: #define L2RAM_PIPELINE_LATE 0x01800000
! 434: #define L2CR_L2DO 0x00400000 /* 9: L2 data-only.
! 435: Setting this bit disables instruction
! 436: caching. */
! 437: #define L2CR_L2I 0x00200000 /* 10: L2 global invalidate. */
! 438: #define L2CR_L2CTL 0x00100000 /* 11: L2 RAM control (ZZ enable).
! 439: Enables automatic operation of the
! 440: L2ZZ (low-power mode) signal. */
! 441: #define L2CR_L2WT 0x00080000 /* 12: L2 write-through. */
! 442: #define L2CR_L2TS 0x00040000 /* 13: L2 test support. */
! 443: #define L2CR_L2OH 0x00030000 /* 14-15: L2 output hold. */
! 444: #define L2CR_L2SL 0x00008000 /* 16: L2 DLL slow. */
! 445: #define L2CR_L2DF 0x00004000 /* 17: L2 differential clock. */
! 446: #define L2CR_L2BYP 0x00002000 /* 18: L2 DLL bypass. */
! 447: #define L2CR_L2IP 0x00000001 /* 31: L2 global invalidate in progress
! 448: (read only). */
! 449: #ifdef L2CR_CONFIG
! 450: u_int l2cr_config = L2CR_CONFIG;
! 451: #else
! 452: u_int l2cr_config = 0;
! 453: #endif
! 454:
! 455: /* L3CR bit definitions */
! 456: #define L3CR_L3E 0x80000000 /* 0: L3 enable */
! 457: #define L3CR_L3SIZ 0x10000000 /* 3: L3 size (0=1MB, 1=2MB) */
! 458:
! 459: void
! 460: config_l2cr(int cpu)
! 461: {
! 462: u_int l2cr, x;
! 463:
! 464: l2cr = ppc_mfl2cr();
! 465:
! 466: /*
! 467: * Configure L2 cache if not enabled.
! 468: */
! 469: if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) {
! 470: l2cr = l2cr_config;
! 471: ppc_mtl2cr(l2cr);
! 472:
! 473: /* Wait for L2 clock to be stable (640 L2 clocks). */
! 474: delay(100);
! 475:
! 476: /* Invalidate all L2 contents. */
! 477: l2cr |= L2CR_L2I;
! 478: ppc_mtl2cr(l2cr);
! 479: do {
! 480: x = ppc_mfl2cr();
! 481: } while (x & L2CR_L2IP);
! 482:
! 483: /* Enable L2 cache. */
! 484: l2cr &= ~L2CR_L2I;
! 485: l2cr |= L2CR_L2E;
! 486: ppc_mtl2cr(l2cr);
! 487: }
! 488:
! 489: if (l2cr & L2CR_L2E) {
! 490: if (cpu == PPC_CPU_MPC7450 || cpu == PPC_CPU_MPC7455) {
! 491: u_int l3cr;
! 492:
! 493: printf(": 256KB L2 cache");
! 494:
! 495: l3cr = ppc_mfl3cr();
! 496: if (l3cr & L3CR_L3E)
! 497: printf(", %cMB L3 cache",
! 498: l3cr & L3CR_L3SIZ ? '2' : '1');
! 499: } else if (cpu == PPC_CPU_IBM750FX ||
! 500: cpu == PPC_CPU_MPC7447A || cpu == PPC_CPU_MPC7457)
! 501: printf(": 512KB L2 cache");
! 502: else {
! 503: switch (l2cr & L2CR_L2SIZ) {
! 504: case L2SIZ_256K:
! 505: printf(": 256KB");
! 506: break;
! 507: case L2SIZ_512K:
! 508: printf(": 512KB");
! 509: break;
! 510: case L2SIZ_1M:
! 511: printf(": 1MB");
! 512: break;
! 513: default:
! 514: printf(": unknown size");
! 515: }
! 516: printf(" backside cache");
! 517: }
! 518: #if 0
! 519: switch (l2cr & L2CR_L2RAM) {
! 520: case L2RAM_FLOWTHRU_BURST:
! 521: printf(" Flow-through synchronous burst SRAM");
! 522: break;
! 523: case L2RAM_PIPELINE_BURST:
! 524: printf(" Pipelined synchronous burst SRAM");
! 525: break;
! 526: case L2RAM_PIPELINE_LATE:
! 527: printf(" Pipelined synchronous late-write SRAM");
! 528: break;
! 529: default:
! 530: printf(" unknown type");
! 531: }
! 532:
! 533: if (l2cr & L2CR_L2PE)
! 534: printf(" with parity");
! 535: #endif
! 536: } else
! 537: printf(": L2 cache not enabled");
! 538: }
! 539:
! 540: #ifdef MULTIPROCESSOR
! 541:
! 542: #define INTSTK (8*1024) /* 8K interrupt stack */
! 543:
! 544: int cpu_spinup(struct device *, struct cpu_info *);
! 545: void cpu_hatch(void);
! 546: void cpu_spinup_trampoline(void);
! 547:
! 548: struct cpu_hatch_data {
! 549: struct cpu_info *ci;
! 550: int running;
! 551: int hid0;
! 552: int sdr1;
! 553: int tbu, tbl;
! 554: };
! 555:
! 556: volatile struct cpu_hatch_data *cpu_hatch_data;
! 557: volatile int cpu_hatch_stack;
! 558:
! 559: int
! 560: cpu_spinup(struct device *self, struct cpu_info *ci)
! 561: {
! 562: volatile struct cpu_hatch_data hatch_data, *h = &hatch_data;
! 563: int i;
! 564: struct pcb *pcb;
! 565: struct pglist mlist;
! 566: struct vm_page *m;
! 567: int error;
! 568: int size = 0;
! 569: char *cp;
! 570: u_char *reset_cpu;
! 571:
! 572: /*
! 573: * Allocate some contiguous pages for the idle PCB and stack
! 574: * from the lowest 256MB (because bat0 always maps it va == pa).
! 575: */
! 576: size += USPACE;
! 577: size += INTSTK;
! 578: size += 4096; /* SPILLSTK */
! 579:
! 580: TAILQ_INIT(&mlist);
! 581: error = uvm_pglistalloc(size, 0x0, 0x10000000, 0, 0, &mlist, 1, 1);
! 582: if (error) {
! 583: printf(": unable to allocate idle stack\n");
! 584: return -1;
! 585: }
! 586:
! 587: m = TAILQ_FIRST(&mlist);
! 588: cp = (char *)VM_PAGE_TO_PHYS(m);
! 589: bzero(cp, size);
! 590:
! 591: pcb = (struct pcb *)cp;
! 592: ci->ci_idle_pcb = pcb;
! 593: ci->ci_intstk = cp + USPACE + INTSTK;
! 594:
! 595: /*
! 596: * Initialize the idle stack pointer, reserving space for an
! 597: * (empty) trapframe (XXX is the trapframe really necessary?)
! 598: */
! 599: pcb->pcb_sp = (paddr_t)pcb + USPACE - sizeof(struct trapframe);
! 600: cpu_hatch_stack = ci->ci_idle_pcb->pcb_sp;
! 601:
! 602: h->ci = ci;
! 603: h->running = 0;
! 604: h->hid0 = ppc_mfhid0();
! 605: h->sdr1 = ppc_mfsdr1();
! 606: cpu_hatch_data = h;
! 607:
! 608: #ifdef notyet
! 609: ci->ci_lasttb = curcpu()->ci_lasttb;
! 610: #endif
! 611:
! 612: __asm volatile ("sync; isync");
! 613:
! 614: /* XXX OpenPIC */
! 615: {
! 616: uint64_t tb;
! 617:
! 618: *(u_int *)EXC_RST = 0x48000002 | (u_int)cpu_spinup_trampoline;
! 619: syncicache((void *)EXC_RST, 0x100);
! 620:
! 621: h->running = -1;
! 622:
! 623: /* Start secondary CPU. */
! 624: reset_cpu = mapiodev(0x80000000 + 0x5c, 1);
! 625: *reset_cpu = 0x4;
! 626: __asm volatile ("eieio" ::: "memory");
! 627: *reset_cpu = 0x5;
! 628: __asm volatile ("eieio" ::: "memory");
! 629:
! 630: /* Sync timebase. */
! 631: tb = ppc_mftb();
! 632: tb += 100000; /* 3ms @ 33MHz */
! 633:
! 634: h->tbu = tb >> 32;
! 635: h->tbl = tb & 0xffffffff;
! 636:
! 637: while (tb > ppc_mftb())
! 638: ;
! 639: __asm volatile ("sync; isync");
! 640: h->running = 0;
! 641:
! 642: delay(500000);
! 643: }
! 644:
! 645: printf("cpu%d: timebase %llx\n", cpu_number(), ppc_mftb());
! 646:
! 647: for (i = 0; i < 0x3fffffff; i++)
! 648: if (h->running) {
! 649: printf("running\n");
! 650: break;
! 651: }
! 652:
! 653: return 0;
! 654: }
! 655:
! 656: volatile static int start_secondary_cpu;
! 657:
! 658: void
! 659: cpu_boot_secondary_processors(void)
! 660: {
! 661: struct cpu_info *ci;
! 662: int i;
! 663:
! 664: for (i = 0; i < PPC_MAXPROCS; i++) {
! 665: ci = &cpu_info[i];
! 666: if (ci->ci_cpuid == 0)
! 667: continue;
! 668: cpu_spinup(NULL, ci);
! 669: }
! 670:
! 671: start_secondary_cpu = 1;
! 672: __asm volatile ("sync");
! 673: }
! 674:
! 675: void
! 676: cpu_hatch(void)
! 677: {
! 678: volatile struct cpu_hatch_data *h = cpu_hatch_data;
! 679: int scratch, i;
! 680:
! 681: /* Initialize timebase. */
! 682: __asm ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0));
! 683:
! 684: /* Initialize curcpu(). */
! 685: ppc_mtsprg0((u_int)h->ci);
! 686:
! 687: /* Set PIR . */
! 688: ppc_mtpir(curcpu()->ci_cpuid);
! 689:
! 690: /*
! 691: * Initialize BAT registers to unmapped to not generate
! 692: * overlapping mappings below.
! 693: */
! 694: ppc_mtibat0u(0);
! 695: ppc_mtibat1u(0);
! 696: ppc_mtibat2u(0);
! 697: ppc_mtibat3u(0);
! 698: ppc_mtdbat0u(0);
! 699: ppc_mtdbat1u(0);
! 700: ppc_mtdbat2u(0);
! 701: ppc_mtdbat3u(0);
! 702:
! 703: /*
! 704: * Now setup fixed bat registers
! 705: *
! 706: * Note that we still run in real mode, and the BAT
! 707: * registers were cleared above.
! 708: */
! 709: /* IBAT0 used for initial 256 MB segment */
! 710: ppc_mtibat0l(battable[0].batl);
! 711: ppc_mtibat0u(battable[0].batu);
! 712:
! 713: /* DBAT0 used similar */
! 714: ppc_mtdbat0l(battable[0].batl);
! 715: ppc_mtdbat0u(battable[0].batu);
! 716:
! 717: /*
! 718: * Initialize segment registers.
! 719: */
! 720: for (i = 0; i < 16; i++)
! 721: ppc_mtsrin(PPC_KERNEL_SEG0 + i, i << ADDR_SR_SHIFT);
! 722:
! 723: ppc_mthid0(h->hid0);
! 724: ppc_mtsdr1(h->sdr1);
! 725:
! 726: /*
! 727: * Now enable translation (and machine checks/recoverable interrupts).
! 728: */
! 729: __asm__ volatile ("eieio; mfmsr %0; ori %0,%0,%1; mtmsr %0; sync;isync"
! 730: : "=r"(scratch) : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));
! 731:
! 732: /* XXX OpenPIC */
! 733: {
! 734: /* Sync timebase. */
! 735: u_int tbu = h->tbu;
! 736: u_int tbl = h->tbl;
! 737: while (h->running == -1)
! 738: ;
! 739: __asm volatile ("sync; isync");
! 740: __asm volatile ("mttbl %0" :: "r"(0));
! 741: __asm volatile ("mttbu %0" :: "r"(tbu));
! 742: __asm volatile ("mttbl %0" :: "r"(tbl));
! 743: }
! 744:
! 745: ncpus++;
! 746: h->running = 1;
! 747: __asm volatile ("eieio" ::: "memory");
! 748:
! 749: while (start_secondary_cpu == 0)
! 750: ;
! 751:
! 752: __asm volatile ("sync; isync");
! 753:
! 754: printf("cpu%d: running\n", cpu_number());
! 755: printf("cpu%d: timebase %llx\n", cpu_number(), ppc_mftb());
! 756: #ifdef notyet
! 757: ppc_mtdec(ticks_per_intr);
! 758: #endif
! 759:
! 760: curcpu()->ci_ipending = 0;
! 761: curcpu()->ci_cpl = 0;
! 762: }
! 763: #endif
CVSweb