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