Annotation of src/sys/arch/alpha/alpha/cpu.c, Revision 1.80.14.2
1.80.14.1 mjf 1: /* $NetBSD$ */
1.27 thorpej 2:
3: /*-
1.64 thorpej 4: * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
1.27 thorpej 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9: * NASA Ames Research Center.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30: * POSSIBILITY OF SUCH DAMAGE.
31: */
1.1 cgd 32:
33: /*
1.6 cgd 34: * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
1.1 cgd 35: * All rights reserved.
36: *
37: * Author: Chris G. Demetriou
38: *
39: * Permission to use, copy, modify and distribute this software and
40: * its documentation is hereby granted, provided that both the copyright
41: * notice and this permission notice appear in all copies of the
42: * software, derivative works or modified versions, and any portions
43: * thereof, and that both notices appear in supporting documentation.
44: *
45: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
47: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48: *
49: * Carnegie Mellon requests users of this software to return to
50: *
51: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
52: * School of Computer Science
53: * Carnegie Mellon University
54: * Pittsburgh PA 15213-3890
55: *
56: * any improvements or extensions that they make and grant Carnegie the
57: * rights to redistribute these changes.
58: */
1.20 cgd 59:
1.21 cgd 60: #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
61:
1.80.14.1 mjf 62: __KERNEL_RCSID(0, "$NetBSD$");
1.27 thorpej 63:
1.60 thorpej 64: #include "opt_ddb.h"
1.27 thorpej 65: #include "opt_multiprocessor.h"
1.1 cgd 66:
67: #include <sys/param.h>
1.10 cgd 68: #include <sys/systm.h>
1.1 cgd 69: #include <sys/device.h>
1.62 thorpej 70: #include <sys/malloc.h>
1.27 thorpej 71: #include <sys/proc.h>
72: #include <sys/user.h>
1.80.14.1 mjf 73: #include <sys/atomic.h>
74: #include <sys/cpu.h>
1.27 thorpej 75:
1.52 mrg 76: #include <uvm/uvm_extern.h>
1.1 cgd 77:
78: #include <machine/autoconf.h>
1.50 thorpej 79: #include <machine/cpuvar.h>
1.1 cgd 80: #include <machine/rpb.h>
1.27 thorpej 81: #include <machine/prom.h>
1.33 ross 82: #include <machine/alpha.h>
1.27 thorpej 83:
1.79 ad 84: struct cpu_info cpu_info_primary = {
85: .ci_curlwp = &lwp0
86: };
1.61 thorpej 87: struct cpu_info *cpu_info_list = &cpu_info_primary;
88:
1.27 thorpej 89: #if defined(MULTIPROCESSOR)
1.34 thorpej 90: /*
91: * Array of CPU info structures. Must be statically-allocated because
92: * curproc, etc. are used early.
93: */
1.61 thorpej 94: struct cpu_info *cpu_info[ALPHA_MAXPROCS];
1.32 thorpej 95:
1.64 thorpej 96: /* Bitmask of CPUs booted, currently running, and paused. */
1.73 perry 97: volatile u_long cpus_booted;
98: volatile u_long cpus_running;
99: volatile u_long cpus_paused;
1.34 thorpej 100:
1.41 thorpej 101: void cpu_boot_secondary __P((struct cpu_info *));
1.27 thorpej 102: #endif /* MULTIPROCESSOR */
1.1 cgd 103:
1.43 thorpej 104: /*
105: * The Implementation Version and the Architecture Mask must be
106: * consistent across all CPUs in the system, so we set it for the
107: * primary and announce the AMASK extensions if they exist.
108: *
109: * Note, we invert the AMASK so that if a bit is set, it means "has
110: * extension".
111: */
112: u_long cpu_implver, cpu_amask;
113:
1.1 cgd 114: /* Definition of the driver for autoconfig. */
1.16 cgd 115: static int cpumatch(struct device *, struct cfdata *, void *);
1.1 cgd 116: static void cpuattach(struct device *, struct device *, void *);
1.5 thorpej 117:
1.68 thorpej 118: CFATTACH_DECL(cpu, sizeof(struct cpu_softc),
119: cpumatch, cpuattach, NULL, NULL);
1.5 thorpej 120:
1.64 thorpej 121: static void cpu_announce_extensions(struct cpu_info *);
122:
1.23 thorpej 123: extern struct cfdriver cpu_cd;
1.1 cgd 124:
1.53 thorpej 125: static const char *lcaminor[] = {
1.26 ross 126: "",
1.53 thorpej 127: "21066", "21066",
128: "21068", "21068",
129: "21066A", "21068A", 0
1.26 ross 130: };
131:
132: struct cputable_struct {
133: int cpu_major_code;
1.53 thorpej 134: const char *cpu_major_name;
135: const char **cpu_minor_names;
1.26 ross 136: } cpunametable[] = {
1.48 thorpej 137: { PCS_PROC_EV3, "EV3", NULL },
1.53 thorpej 138: { PCS_PROC_EV4, "21064", NULL },
1.48 thorpej 139: { PCS_PROC_SIMULATION, "Sim", NULL },
1.26 ross 140: { PCS_PROC_LCA4, "LCA", lcaminor },
1.53 thorpej 141: { PCS_PROC_EV5, "21164", NULL },
142: { PCS_PROC_EV45, "21064A", NULL },
143: { PCS_PROC_EV56, "21164A", NULL },
144: { PCS_PROC_EV6, "21264", NULL },
145: { PCS_PROC_PCA56, "PCA56", NULL },
1.48 thorpej 146: { PCS_PROC_PCA57, "PCA57", NULL },
1.49 thorpej 147: { PCS_PROC_EV67, "21264A", NULL },
1.66 he 148: { PCS_PROC_EV68CB, "21264C", NULL },
149: { PCS_PROC_EV68AL, "21264B", NULL },
150: { PCS_PROC_EV68CX, "21264D", NULL },
1.26 ross 151: };
152:
1.27 thorpej 153: /*
154: * The following is an attempt to map out how booting secondary CPUs
155: * works.
156: *
157: * As we find processors during the autoconfiguration sequence, all
1.41 thorpej 158: * processors have idle stacks and PCBs created for them, including
159: * the primary (although the primary idles on proc0's PCB until its
160: * idle PCB is created).
1.34 thorpej 161: *
1.41 thorpej 162: * Right before calling uvm_scheduler(), main() calls, on proc0's
163: * context, cpu_boot_secondary_processors(). This is our key to
164: * actually spin up the additional processor's we've found. We
165: * run through our cpu_info[] array looking for secondary processors
166: * with idle PCBs, and spin them up.
167: *
168: * The spinup involves switching the secondary processor to the
169: * OSF/1 PALcode, setting the entry point to cpu_spinup_trampoline(),
170: * and sending a "START" message to the secondary's console.
1.27 thorpej 171: *
172: * Upon successful processor bootup, the cpu_spinup_trampoline will call
173: * cpu_hatch(), which will print a message indicating that the processor
174: * is running, and will set the "hatched" flag in its softc. At the end
175: * of cpu_hatch() is a spin-forever loop; we do not yet attempt to schedule
176: * anything on secondary CPUs.
177: */
178:
1.1 cgd 179: static int
180: cpumatch(parent, cfdata, aux)
181: struct device *parent;
1.16 cgd 182: struct cfdata *cfdata;
1.1 cgd 183: void *aux;
184: {
1.24 thorpej 185: struct mainbus_attach_args *ma = aux;
1.1 cgd 186:
187: /* make sure that we're looking for a CPU. */
1.24 thorpej 188: if (strcmp(ma->ma_name, cpu_cd.cd_name) != 0)
1.1 cgd 189: return (0);
190:
1.18 cgd 191: /* XXX CHECK SLOT? */
192: /* XXX CHECK PRIMARY? */
193:
1.1 cgd 194: return (1);
195: }
196:
197: static void
1.50 thorpej 198: cpuattach(parent, self, aux)
1.1 cgd 199: struct device *parent;
1.50 thorpej 200: struct device *self;
1.1 cgd 201: void *aux;
202: {
1.50 thorpej 203: struct cpu_softc *sc = (void *) self;
1.24 thorpej 204: struct mainbus_attach_args *ma = aux;
1.26 ross 205: int i;
1.53 thorpej 206: const char **s;
1.43 thorpej 207: struct pcs *p;
1.19 mycroft 208: #ifdef DEBUG
1.14 cgd 209: int needcomma;
1.19 mycroft 210: #endif
1.2 cgd 211: u_int32_t major, minor;
1.46 thorpej 212: struct cpu_info *ci;
1.1 cgd 213:
1.25 ross 214: p = LOCATE_PCS(hwrpb, ma->ma_slot);
215: major = PCS_CPU_MAJORTYPE(p);
216: minor = PCS_CPU_MINORTYPE(p);
1.14 cgd 217:
1.24 thorpej 218: printf(": ID %d%s, ", ma->ma_slot,
219: ma->ma_slot == hwrpb->rpb_primary_cpu_id ? " (primary)" : "");
1.18 cgd 220:
1.26 ross 221: for(i = 0; i < sizeof cpunametable / sizeof cpunametable[0]; ++i) {
222: if (cpunametable[i].cpu_major_code == major) {
1.36 ross 223: printf("%s-%d", cpunametable[i].cpu_major_name, minor);
1.26 ross 224: s = cpunametable[i].cpu_minor_names;
225: for(i = 0; s && s[i]; ++i) {
1.39 ross 226: if (i == minor && strlen(s[i]) != 0) {
1.26 ross 227: printf(" (%s)\n", s[i]);
228: goto recognized;
229: }
230: }
231: goto recognized;
1.14 cgd 232: }
1.26 ross 233: }
1.53 thorpej 234: printf("UNKNOWN CPU TYPE (%d:%d)", major, minor);
1.4 cgd 235:
1.26 ross 236: recognized:
1.53 thorpej 237: printf("\n");
1.2 cgd 238:
1.18 cgd 239: #ifdef DEBUG
1.2 cgd 240: if (p->pcs_proc_var != 0) {
1.51 sommerfe 241: printf("%s: ", sc->sc_dev.dv_xname);
1.2 cgd 242:
243: needcomma = 0;
244: if (p->pcs_proc_var & PCS_VAR_VAXFP) {
1.12 christos 245: printf("VAX FP support");
1.2 cgd 246: needcomma = 1;
247: }
248: if (p->pcs_proc_var & PCS_VAR_IEEEFP) {
1.12 christos 249: printf("%sIEEE FP support", needcomma ? ", " : "");
1.2 cgd 250: needcomma = 1;
251: }
1.8 cgd 252: if (p->pcs_proc_var & PCS_VAR_PE) {
1.12 christos 253: printf("%sPrimary Eligible", needcomma ? ", " : "");
1.3 cgd 254: needcomma = 1;
255: }
1.2 cgd 256: if (p->pcs_proc_var & PCS_VAR_RESERVED)
1.12 christos 257: printf("%sreserved bits: 0x%lx", needcomma ? ", " : "",
1.2 cgd 258: p->pcs_proc_var & PCS_VAR_RESERVED);
1.12 christos 259: printf("\n");
1.2 cgd 260: }
1.18 cgd 261: #endif
1.3 cgd 262:
1.27 thorpej 263: if (ma->ma_slot > ALPHA_WHAMI_MAXID) {
1.46 thorpej 264: if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
265: panic("cpu_attach: primary CPU ID too large");
1.50 thorpej 266: printf("%s: procssor ID too large, ignoring\n",
267: sc->sc_dev.dv_xname);
1.27 thorpej 268: return;
269: }
270:
1.62 thorpej 271: if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
1.61 thorpej 272: ci = &cpu_info_primary;
273: else {
274: ci = malloc(sizeof(*ci), M_DEVBUF, M_WAITOK);
275: memset(ci, 0, sizeof(*ci));
276: }
1.62 thorpej 277: #if defined(MULTIPROCESSOR)
278: cpu_info[ma->ma_slot] = ci;
1.46 thorpej 279: #endif
1.34 thorpej 280: ci->ci_cpuid = ma->ma_slot;
1.62 thorpej 281: ci->ci_softc = sc;
1.76 tsutsui 282: ci->ci_pcc_freq = hwrpb->rpb_cc_freq;
1.27 thorpej 283:
1.4 cgd 284: /*
1.14 cgd 285: * Though we could (should?) attach the LCA cpus' PCI
1.4 cgd 286: * bus here there is no good reason to do so, and
287: * the bus attachment code is easier to understand
288: * and more compact if done the 'normal' way.
289: */
1.27 thorpej 290:
291: #if defined(MULTIPROCESSOR)
292: /*
1.41 thorpej 293: * Make sure the processor is available for use.
1.27 thorpej 294: */
1.41 thorpej 295: if ((p->pcs_flags & PCS_PA) == 0) {
296: if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
297: panic("cpu_attach: primary not available?!");
1.50 thorpej 298: printf("%s: processor not available for use\n",
299: sc->sc_dev.dv_xname);
1.41 thorpej 300: return;
301: }
1.32 thorpej 302:
1.41 thorpej 303: /* Make sure the processor has valid PALcode. */
304: if ((p->pcs_flags & PCS_PV) == 0) {
305: if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
306: panic("cpu_attach: primary has invalid PALcode?!");
1.50 thorpej 307: printf("%s: PALcode not valid\n", sc->sc_dev.dv_xname);
1.27 thorpej 308: return;
309: }
1.64 thorpej 310: #endif /* MULTIPROCESSOR */
1.41 thorpej 311:
312: /*
313: * If we're the primary CPU, no more work to do; we're already
314: * running!
315: */
316: if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) {
1.64 thorpej 317: cpu_announce_extensions(ci);
318: #if defined(MULTIPROCESSOR)
1.61 thorpej 319: ci->ci_flags |= CPUF_PRIMARY|CPUF_RUNNING;
1.80.14.1 mjf 320: atomic_or_ulong(&cpus_booted, (1UL << ma->ma_slot));
321: atomic_or_ulong(&cpus_running, (1UL << ma->ma_slot));
1.64 thorpej 322: #endif /* MULTIPROCESSOR */
323: } else {
324: #if defined(MULTIPROCESSOR)
1.74 yamt 325: int error;
326:
327: error = mi_cpu_attach(ci);
328: if (error != 0) {
329: aprint_error("%s: mi_cpu_attach failed with %d\n",
330: sc->sc_dev.dv_xname, error);
331: return;
332: }
333:
1.64 thorpej 334: /*
335: * Boot the secondary processor. It will announce its
336: * extensions, and then spin until we tell it to go
337: * on its merry way.
338: */
339: cpu_boot_secondary(ci);
340: #else /* ! MULTIPROCESSOR */
341: printf("%s: processor off-line; multiprocessor support "
342: "not present in kernel\n", sc->sc_dev.dv_xname);
343: #endif /* MULTIPROCESSOR */
1.41 thorpej 344: }
1.50 thorpej 345:
346: evcnt_attach_dynamic(&sc->sc_evcnt_clock, EVCNT_TYPE_INTR,
347: NULL, sc->sc_dev.dv_xname, "clock");
348: evcnt_attach_dynamic(&sc->sc_evcnt_device, EVCNT_TYPE_INTR,
349: NULL, sc->sc_dev.dv_xname, "device");
350: #if defined(MULTIPROCESSOR)
1.58 thorpej 351: alpha_ipi_init(ci);
1.50 thorpej 352: #endif
1.27 thorpej 353: }
354:
1.64 thorpej 355: static void
356: cpu_announce_extensions(struct cpu_info *ci)
357: {
1.71 chs 358: u_long implver, amask = 0;
1.64 thorpej 359: char bits[64];
360:
361: implver = alpha_implver();
362: if (implver >= ALPHA_IMPLVER_EV5)
363: amask = (~alpha_amask(ALPHA_AMASK_ALL)) & ALPHA_AMASK_ALL;
364:
365: if (ci->ci_cpuid == hwrpb->rpb_primary_cpu_id) {
366: cpu_implver = implver;
367: cpu_amask = amask;
368: } else {
369: if (implver < cpu_implver)
370: printf("%s: WARNING: IMPLVER %lu < %lu\n",
371: ci->ci_softc->sc_dev.dv_xname,
372: implver, cpu_implver);
373:
374: /*
375: * Cap the system architecture mask to the intersection
376: * of features supported by all processors in the system.
377: */
378: cpu_amask &= amask;
379: }
380:
381: if (amask)
382: printf("%s: Architecture extensions: %s\n",
383: ci->ci_softc->sc_dev.dv_xname, bitmask_snprintf(cpu_amask,
384: ALPHA_AMASK_BITS, bits, sizeof(bits)));
385: }
386:
1.27 thorpej 387: #if defined(MULTIPROCESSOR)
388: void
1.64 thorpej 389: cpu_boot_secondary_processors(void)
1.41 thorpej 390: {
391: struct cpu_info *ci;
392: u_long i;
1.80 ad 393: bool did_patch = false;
1.41 thorpej 394:
395: for (i = 0; i < ALPHA_MAXPROCS; i++) {
1.61 thorpej 396: ci = cpu_info[i];
1.75 mhitch 397: if (ci == NULL || ci->ci_data.cpu_idlelwp == NULL)
1.41 thorpej 398: continue;
399: if (ci->ci_flags & CPUF_PRIMARY)
400: continue;
1.64 thorpej 401: if ((cpus_booted & (1UL << i)) == 0)
402: continue;
1.41 thorpej 403:
1.80 ad 404: /* Patch MP-criticial kernel routines. */
405: if (did_patch == false) {
406: alpha_patch(true);
407: did_patch = true;
408: }
409:
1.64 thorpej 410: /*
411: * Link the processor into the list, and launch it.
412: */
413: ci->ci_next = cpu_info_list->ci_next;
414: cpu_info_list->ci_next = ci;
1.80.14.1 mjf 415: atomic_or_ulong(&ci->ci_flags, CPUF_RUNNING);
416: atomic_or_ulong(&cpus_running, (1U << i));
1.41 thorpej 417: }
418: }
419:
420: void
1.64 thorpej 421: cpu_boot_secondary(struct cpu_info *ci)
1.27 thorpej 422: {
423: long timeout;
424: struct pcs *pcsp, *primary_pcsp;
425: struct pcb *pcb;
1.32 thorpej 426: u_long cpumask;
1.27 thorpej 427:
1.75 mhitch 428: pcb = &ci->ci_data.cpu_idlelwp->l_addr->u_pcb;
1.27 thorpej 429: primary_pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
1.34 thorpej 430: pcsp = LOCATE_PCS(hwrpb, ci->ci_cpuid);
431: cpumask = (1UL << ci->ci_cpuid);
1.27 thorpej 432:
1.34 thorpej 433: /*
1.41 thorpej 434: * Set up the PCS's HWPCB to match ours.
1.34 thorpej 435: */
436: memcpy(pcsp->pcs_hwpcb, &pcb->pcb_hw, sizeof(pcb->pcb_hw));
1.27 thorpej 437:
1.34 thorpej 438: /*
439: * Set up the HWRPB to restart the secondary processor
440: * with our spin-up trampoline.
441: */
442: hwrpb->rpb_restart = (u_int64_t) cpu_spinup_trampoline;
443: hwrpb->rpb_restart_val = (u_int64_t) ci;
444: hwrpb->rpb_checksum = hwrpb_checksum();
445:
446: /*
447: * Configure the CPU to start in OSF/1 PALcode by copying
448: * the primary CPU's PALcode revision info to the secondary
449: * CPUs PCS.
450: */
451: memcpy(&pcsp->pcs_pal_rev, &primary_pcsp->pcs_pal_rev,
452: sizeof(pcsp->pcs_pal_rev));
453: pcsp->pcs_flags |= (PCS_CV|PCS_RC);
454: pcsp->pcs_flags &= ~PCS_BIP;
455:
456: /* Make sure the secondary console sees all this. */
457: alpha_mb();
458:
459: /* Send a "START" command to the secondary CPU's console. */
460: if (cpu_iccb_send(ci->ci_cpuid, "START\r\n")) {
461: printf("%s: unable to issue `START' command\n",
1.50 thorpej 462: ci->ci_softc->sc_dev.dv_xname);
1.34 thorpej 463: return;
464: }
1.27 thorpej 465:
1.34 thorpej 466: /* Wait for the processor to boot. */
467: for (timeout = 10000; timeout != 0; timeout--) {
1.27 thorpej 468: alpha_mb();
1.34 thorpej 469: if (pcsp->pcs_flags & PCS_BIP)
470: break;
471: delay(1000);
472: }
473: if (timeout == 0)
1.50 thorpej 474: printf("%s: processor failed to boot\n",
475: ci->ci_softc->sc_dev.dv_xname);
1.27 thorpej 476:
1.34 thorpej 477: /*
478: * ...and now wait for verification that it's running kernel
479: * code.
480: */
481: for (timeout = 10000; timeout != 0; timeout--) {
482: alpha_mb();
1.64 thorpej 483: if (cpus_booted & cpumask)
1.34 thorpej 484: break;
485: delay(1000);
1.27 thorpej 486: }
1.34 thorpej 487: if (timeout == 0)
1.50 thorpej 488: printf("%s: processor failed to hatch\n",
489: ci->ci_softc->sc_dev.dv_xname);
1.54 thorpej 490: }
491:
492: void
493: cpu_pause_resume(u_long cpu_id, int pause)
494: {
495: u_long cpu_mask = (1UL << cpu_id);
496:
497: if (pause) {
1.80.14.1 mjf 498: atomic_or_ulong(&cpus_paused, cpu_mask);
1.54 thorpej 499: alpha_send_ipi(cpu_id, ALPHA_IPI_PAUSE);
500: } else
1.80.14.1 mjf 501: atomic_and_ulong(&cpus_paused, ~cpu_mask);
1.54 thorpej 502: }
503:
504: void
505: cpu_pause_resume_all(int pause)
506: {
1.61 thorpej 507: struct cpu_info *ci, *self = curcpu();
508: CPU_INFO_ITERATOR cii;
1.54 thorpej 509:
1.61 thorpej 510: for (CPU_INFO_FOREACH(cii, ci)) {
511: if (ci == self)
1.54 thorpej 512: continue;
1.61 thorpej 513: cpu_pause_resume(ci->ci_cpuid, pause);
1.54 thorpej 514: }
1.27 thorpej 515: }
516:
517: void
1.60 thorpej 518: cpu_halt(void)
1.32 thorpej 519: {
1.60 thorpej 520: struct cpu_info *ci = curcpu();
521: u_long cpu_id = cpu_number();
522: struct pcs *pcsp = LOCATE_PCS(hwrpb, cpu_id);
1.32 thorpej 523:
1.60 thorpej 524: printf("%s: shutting down...\n", ci->ci_softc->sc_dev.dv_xname);
1.32 thorpej 525:
1.60 thorpej 526: pcsp->pcs_flags &= ~(PCS_RC | PCS_HALT_REQ);
527: pcsp->pcs_flags |= PCS_HALT_STAY_HALTED;
1.32 thorpej 528:
1.80.14.1 mjf 529: atomic_and_ulong(&cpus_running, ~(1UL << cpu_id));
530: atomic_and_ulong(&cpus_booted, ~(1U << cpu_id));
1.32 thorpej 531:
1.60 thorpej 532: alpha_pal_halt();
533: /* NOTREACHED */
1.32 thorpej 534: }
535:
536: void
1.64 thorpej 537: cpu_hatch(struct cpu_info *ci)
1.27 thorpej 538: {
1.55 thorpej 539: u_long cpu_id = cpu_number();
540: u_long cpumask = (1UL << cpu_id);
1.34 thorpej 541:
1.41 thorpej 542: /* Mark the kernel pmap active on this processor. */
1.80.14.1 mjf 543: atomic_or_ulong(&pmap_kernel()->pm_cpus, cpumask);
1.27 thorpej 544:
545: /* Initialize trap vectors for this processor. */
546: trap_init();
547:
548: /* Yahoo! We're running kernel code! Announce it! */
1.64 thorpej 549: cpu_announce_extensions(ci);
550:
1.80.14.1 mjf 551: atomic_or_ulong(&cpus_booted, cpumask);
1.64 thorpej 552:
553: /*
554: * Spin here until we're told we can start.
555: */
556: while ((cpus_running & cpumask) == 0)
557: /* spin */ ;
558:
559: /*
560: * Invalidate the TLB and sync the I-stream before we
561: * jump into the kernel proper. We have to do this
562: * beacause we haven't been getting IPIs while we've
563: * been spinning.
564: */
565: ALPHA_TBIA();
566: alpha_pal_imb();
1.63 sommerfe 567:
1.76 tsutsui 568: cc_calibrate_cpu(ci);
1.27 thorpej 569: }
570:
571: int
1.64 thorpej 572: cpu_iccb_send(long cpu_id, const char *msg)
1.27 thorpej 573: {
574: struct pcs *pcsp = LOCATE_PCS(hwrpb, cpu_id);
575: int timeout;
576: u_long cpumask = (1UL << cpu_id);
577:
578: /* Wait for the ICCB to become available. */
579: for (timeout = 10000; timeout != 0; timeout--) {
580: alpha_mb();
581: if ((hwrpb->rpb_rxrdy & cpumask) == 0)
582: break;
583: delay(1000);
584: }
585: if (timeout == 0)
586: return (EIO);
587:
588: /*
589: * Copy the message into the ICCB, and tell the secondary console
1.80.14.1 mjf 590: * that it's there.
1.27 thorpej 591: */
592: strcpy(pcsp->pcs_iccb.iccb_rxbuf, msg);
593: pcsp->pcs_iccb.iccb_rxlen = strlen(msg);
1.80.14.1 mjf 594: atomic_or_ulong(&hwrpb->rpb_rxrdy, cpumask);
595: membar_sync();
1.27 thorpej 596:
597: /* Wait for the message to be received. */
598: for (timeout = 10000; timeout != 0; timeout--) {
599: alpha_mb();
600: if ((hwrpb->rpb_rxrdy & cpumask) == 0)
601: break;
602: delay(1000);
603: }
604: if (timeout == 0)
605: return (EIO);
606:
607: return (0);
608: }
609:
610: void
1.64 thorpej 611: cpu_iccb_receive(void)
1.27 thorpej 612: {
1.28 thorpej 613: #if 0 /* Don't bother... we don't get any important messages anyhow. */
1.27 thorpej 614: u_int64_t txrdy;
615: char *cp1, *cp2, buf[80];
616: struct pcs *pcsp;
617: u_int cnt;
618: long cpu_id;
619:
620: txrdy = hwrpb->rpb_txrdy;
621:
622: for (cpu_id = 0; cpu_id < hwrpb->rpb_pcs_cnt; cpu_id++) {
623: if (txrdy & (1UL << cpu_id)) {
624: pcsp = LOCATE_PCS(hwrpb, cpu_id);
625: printf("Inter-console message from CPU %lu "
626: "HALT REASON = 0x%lx, FLAGS = 0x%lx\n",
627: cpu_id, pcsp->pcs_halt_reason, pcsp->pcs_flags);
628:
629: cnt = pcsp->pcs_iccb.iccb_txlen;
630: if (cnt >= 80) {
631: printf("Malformed inter-console message\n");
632: continue;
633: }
634: cp1 = pcsp->pcs_iccb.iccb_txbuf;
635: cp2 = buf;
636: while (cnt--) {
637: if (*cp1 != '\r' && *cp1 != '\n')
638: *cp2++ = *cp1;
639: cp1++;
640: }
641: *cp2 = '\0';
642: printf("Message from CPU %lu: %s\n", cpu_id, buf);
643: }
644: }
1.28 thorpej 645: #endif /* 0 */
1.27 thorpej 646: hwrpb->rpb_txrdy = 0;
647: alpha_mb();
1.1 cgd 648: }
1.60 thorpej 649:
650: #if defined(DDB)
651:
652: #include <ddb/db_output.h>
653: #include <machine/db_machdep.h>
654:
655: /*
656: * Dump CPU information from DDB.
657: */
658: void
659: cpu_debug_dump(void)
660: {
661: struct cpu_info *ci;
1.61 thorpej 662: CPU_INFO_ITERATOR cii;
1.60 thorpej 663:
664: db_printf("addr dev id flags ipis curproc fpcurproc\n");
1.61 thorpej 665: for (CPU_INFO_FOREACH(cii, ci)) {
1.60 thorpej 666: db_printf("%p %s %lu %lx %lx %p %p\n",
667: ci,
668: ci->ci_softc->sc_dev.dv_xname,
669: ci->ci_cpuid,
670: ci->ci_flags,
671: ci->ci_ipis,
1.69 thorpej 672: ci->ci_curlwp,
673: ci->ci_fpcurlwp);
1.60 thorpej 674: }
675: }
676:
677: #endif /* DDB */
678:
1.27 thorpej 679: #endif /* MULTIPROCESSOR */
CVSweb <webmaster@jp.NetBSD.org>