xref: /netbsd/sys/arch/alpha/alpha/cpu.c (revision 6550d01e)
1 /* $NetBSD: cpu.c,v 1.90 2010/12/17 02:36:35 joerg 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  *
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  */
32 
33 /*
34  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
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  */
59 
60 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
61 
62 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.90 2010/12/17 02:36:35 joerg Exp $");
63 
64 #include "opt_ddb.h"
65 #include "opt_multiprocessor.h"
66 
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/device.h>
70 #include <sys/malloc.h>
71 #include <sys/proc.h>
72 #include <sys/atomic.h>
73 #include <sys/cpu.h>
74 
75 #include <uvm/uvm_extern.h>
76 
77 #include <machine/autoconf.h>
78 #include <machine/cpuvar.h>
79 #include <machine/rpb.h>
80 #include <machine/prom.h>
81 #include <machine/alpha.h>
82 
83 struct cpu_info cpu_info_primary = {
84 	.ci_curlwp = &lwp0
85 };
86 struct cpu_info *cpu_info_list = &cpu_info_primary;
87 
88 #if defined(MULTIPROCESSOR)
89 /*
90  * Array of CPU info structures.  Must be statically-allocated because
91  * curproc, etc. are used early.
92  */
93 struct cpu_info *cpu_info[ALPHA_MAXPROCS];
94 
95 /* Bitmask of CPUs booted, currently running, and paused. */
96 volatile u_long cpus_booted;
97 volatile u_long cpus_running;
98 volatile u_long cpus_paused;
99 
100 void	cpu_boot_secondary(struct cpu_info *);
101 #endif /* MULTIPROCESSOR */
102 
103 /*
104  * The Implementation Version and the Architecture Mask must be
105  * consistent across all CPUs in the system, so we set it for the
106  * primary and announce the AMASK extensions if they exist.
107  *
108  * Note, we invert the AMASK so that if a bit is set, it means "has
109  * extension".
110  */
111 u_long	cpu_implver, cpu_amask;
112 
113 /* Definition of the driver for autoconfig. */
114 static int	cpumatch(struct device *, struct cfdata *, void *);
115 static void	cpuattach(struct device *, struct device *, void *);
116 
117 CFATTACH_DECL(cpu, sizeof(struct cpu_softc),
118     cpumatch, cpuattach, NULL, NULL);
119 
120 static void	cpu_announce_extensions(struct cpu_info *);
121 
122 extern struct cfdriver cpu_cd;
123 
124 static const char *lcaminor[] = {
125 	"",
126 	"21066", "21066",
127 	"21068", "21068",
128 	"21066A", "21068A", 0
129 };
130 
131 struct cputable_struct {
132 	int	cpu_major_code;
133 	const char *cpu_major_name;
134 	const char **cpu_minor_names;
135 } cpunametable[] = {
136 	{ PCS_PROC_EV3,		"EV3",		NULL		},
137 	{ PCS_PROC_EV4,		"21064",	NULL		},
138 	{ PCS_PROC_SIMULATION,	"Sim",		NULL		},
139 	{ PCS_PROC_LCA4,	"LCA",		lcaminor	},
140 	{ PCS_PROC_EV5,		"21164",	NULL		},
141 	{ PCS_PROC_EV45,	"21064A",	NULL		},
142 	{ PCS_PROC_EV56,	"21164A",	NULL		},
143 	{ PCS_PROC_EV6,		"21264",	NULL		},
144 	{ PCS_PROC_PCA56,	"PCA56",	NULL		},
145 	{ PCS_PROC_PCA57,	"PCA57",	NULL		},
146 	{ PCS_PROC_EV67,	"21264A",	NULL		},
147 	{ PCS_PROC_EV68CB,	"21264C",	NULL		},
148 	{ PCS_PROC_EV68AL,	"21264B",	NULL		},
149 	{ PCS_PROC_EV68CX,	"21264D",	NULL		},
150 };
151 
152 /*
153  * The following is an attempt to map out how booting secondary CPUs
154  * works.
155  *
156  * As we find processors during the autoconfiguration sequence, all
157  * processors have idle stacks and PCBs created for them, including
158  * the primary (although the primary idles on lwp0's PCB until its
159  * idle PCB is created).
160  *
161  * Right before calling uvm_scheduler(), main() calls, on lwp0's
162  * context, cpu_boot_secondary_processors().  This is our key to
163  * actually spin up the additional processor's we've found.  We
164  * run through our cpu_info[] array looking for secondary processors
165  * with idle PCBs, and spin them up.
166  *
167  * The spinup involves switching the secondary processor to the
168  * OSF/1 PALcode, setting the entry point to cpu_spinup_trampoline(),
169  * and sending a "START" message to the secondary's console.
170  *
171  * Upon successful processor bootup, the cpu_spinup_trampoline will call
172  * cpu_hatch(), which will print a message indicating that the processor
173  * is running, and will set the "hatched" flag in its softc.  At the end
174  * of cpu_hatch() is a spin-forever loop; we do not yet attempt to schedule
175  * anything on secondary CPUs.
176  */
177 
178 static int
179 cpumatch(struct device *parent, struct cfdata *cfdata, void *aux)
180 {
181 	struct mainbus_attach_args *ma = aux;
182 
183 	/* make sure that we're looking for a CPU. */
184 	if (strcmp(ma->ma_name, cpu_cd.cd_name) != 0)
185 		return (0);
186 
187 	/* XXX CHECK SLOT? */
188 	/* XXX CHECK PRIMARY? */
189 
190 	return (1);
191 }
192 
193 static void
194 cpuattach(struct device *parent, struct device *self, void *aux)
195 {
196 	struct cpu_softc *sc = (void *) self;
197 	struct mainbus_attach_args *ma = aux;
198 	int i;
199 	const char **s;
200 	struct pcs *p;
201 #ifdef DEBUG
202 	int needcomma;
203 #endif
204 	u_int32_t major, minor;
205 	struct cpu_info *ci;
206 
207 	p = LOCATE_PCS(hwrpb, ma->ma_slot);
208 	major = PCS_CPU_MAJORTYPE(p);
209 	minor = PCS_CPU_MINORTYPE(p);
210 
211 	printf(": ID %d%s, ", ma->ma_slot,
212 	    ma->ma_slot == hwrpb->rpb_primary_cpu_id ? " (primary)" : "");
213 
214 	for(i = 0; i < sizeof cpunametable / sizeof cpunametable[0]; ++i) {
215 		if (cpunametable[i].cpu_major_code == major) {
216 			printf("%s-%d", cpunametable[i].cpu_major_name, minor);
217 			s = cpunametable[i].cpu_minor_names;
218 			for(i = 0; s && s[i]; ++i) {
219 				if (i == minor && strlen(s[i]) != 0) {
220 					printf(" (%s)\n", s[i]);
221 					goto recognized;
222 				}
223 			}
224 			goto recognized;
225 		}
226 	}
227 	printf("UNKNOWN CPU TYPE (%d:%d)", major, minor);
228 
229 recognized:
230 	printf("\n");
231 
232 #ifdef DEBUG
233 	if (p->pcs_proc_var != 0) {
234 		printf("%s: ", sc->sc_dev.dv_xname);
235 
236 		needcomma = 0;
237 		if (p->pcs_proc_var & PCS_VAR_VAXFP) {
238 			printf("VAX FP support");
239 			needcomma = 1;
240 		}
241 		if (p->pcs_proc_var & PCS_VAR_IEEEFP) {
242 			printf("%sIEEE FP support", needcomma ? ", " : "");
243 			needcomma = 1;
244 		}
245 		if (p->pcs_proc_var & PCS_VAR_PE) {
246 			printf("%sPrimary Eligible", needcomma ? ", " : "");
247 			needcomma = 1;
248 		}
249 		if (p->pcs_proc_var & PCS_VAR_RESERVED)
250 			printf("%sreserved bits: 0x%lx", needcomma ? ", " : "",
251 			    p->pcs_proc_var & PCS_VAR_RESERVED);
252 		printf("\n");
253 	}
254 #endif
255 
256 	if (ma->ma_slot > ALPHA_WHAMI_MAXID) {
257 		if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
258 			panic("cpu_attach: primary CPU ID too large");
259 		printf("%s: procssor ID too large, ignoring\n",
260 		    sc->sc_dev.dv_xname);
261 		return;
262 	}
263 
264 	if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
265 		ci = &cpu_info_primary;
266 	else {
267 		ci = malloc(sizeof(*ci), M_DEVBUF, M_WAITOK);
268 		memset(ci, 0, sizeof(*ci));
269 	}
270 #if defined(MULTIPROCESSOR)
271 	cpu_info[ma->ma_slot] = ci;
272 #endif
273 	ci->ci_cpuid = ma->ma_slot;
274 	ci->ci_softc = sc;
275 	ci->ci_pcc_freq = hwrpb->rpb_cc_freq;
276 
277 	/*
278 	 * Though we could (should?) attach the LCA cpus' PCI
279 	 * bus here there is no good reason to do so, and
280 	 * the bus attachment code is easier to understand
281 	 * and more compact if done the 'normal' way.
282 	 */
283 
284 #if defined(MULTIPROCESSOR)
285 	/*
286 	 * Make sure the processor is available for use.
287 	 */
288 	if ((p->pcs_flags & PCS_PA) == 0) {
289 		if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
290 			panic("cpu_attach: primary not available?!");
291 		printf("%s: processor not available for use\n",
292 		    sc->sc_dev.dv_xname);
293 		return;
294 	}
295 
296 	/* Make sure the processor has valid PALcode. */
297 	if ((p->pcs_flags & PCS_PV) == 0) {
298 		if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
299 			panic("cpu_attach: primary has invalid PALcode?!");
300 		printf("%s: PALcode not valid\n", sc->sc_dev.dv_xname);
301 		return;
302 	}
303 #endif /* MULTIPROCESSOR */
304 
305 	/*
306 	 * If we're the primary CPU, no more work to do; we're already
307 	 * running!
308 	 */
309 	if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) {
310 		cpu_announce_extensions(ci);
311 #if defined(MULTIPROCESSOR)
312 		ci->ci_flags |= CPUF_PRIMARY|CPUF_RUNNING;
313 		atomic_or_ulong(&cpus_booted, (1UL << ma->ma_slot));
314 		atomic_or_ulong(&cpus_running, (1UL << ma->ma_slot));
315 #endif /* MULTIPROCESSOR */
316 	} else {
317 #if defined(MULTIPROCESSOR)
318 		int error;
319 
320 		error = mi_cpu_attach(ci);
321 		if (error != 0) {
322 			aprint_error("%s: mi_cpu_attach failed with %d\n",
323 			    sc->sc_dev.dv_xname, error);
324 			return;
325 		}
326 
327 		/*
328 		 * Boot the secondary processor.  It will announce its
329 		 * extensions, and then spin until we tell it to go
330 		 * on its merry way.
331 		 */
332 		cpu_boot_secondary(ci);
333 
334 		/*
335 		 * Link the processor into the list.
336 		 */
337 		ci->ci_next = cpu_info_list->ci_next;
338 		cpu_info_list->ci_next = ci;
339 #else /* ! MULTIPROCESSOR */
340 		printf("%s: processor off-line; multiprocessor support "
341 		    "not present in kernel\n", sc->sc_dev.dv_xname);
342 #endif /* MULTIPROCESSOR */
343 	}
344 
345 	evcnt_attach_dynamic(&sc->sc_evcnt_clock, EVCNT_TYPE_INTR,
346 	    NULL, sc->sc_dev.dv_xname, "clock");
347 	evcnt_attach_dynamic(&sc->sc_evcnt_device, EVCNT_TYPE_INTR,
348 	    NULL, sc->sc_dev.dv_xname, "device");
349 #if defined(MULTIPROCESSOR)
350 	alpha_ipi_init(ci);
351 #endif
352 }
353 
354 static void
355 cpu_announce_extensions(struct cpu_info *ci)
356 {
357 	u_long implver, amask = 0;
358 	char bits[64];
359 
360 	implver = alpha_implver();
361 	if (implver >= ALPHA_IMPLVER_EV5)
362 		amask = (~alpha_amask(ALPHA_AMASK_ALL)) & ALPHA_AMASK_ALL;
363 
364 	if (ci->ci_cpuid == hwrpb->rpb_primary_cpu_id) {
365 		cpu_implver = implver;
366 		cpu_amask = amask;
367 	} else {
368 		if (implver < cpu_implver)
369 			printf("%s: WARNING: IMPLVER %lu < %lu\n",
370 			    ci->ci_softc->sc_dev.dv_xname,
371 			    implver, cpu_implver);
372 
373 		/*
374 		 * Cap the system architecture mask to the intersection
375 		 * of features supported by all processors in the system.
376 		 */
377 		cpu_amask &= amask;
378 	}
379 
380 	if (amask) {
381 		snprintb(bits, sizeof(bits),
382 		    ALPHA_AMASK_BITS, cpu_amask);
383 		printf("%s: Architecture extensions: %s\n",
384 		    ci->ci_softc->sc_dev.dv_xname, bits);
385 	}
386 }
387 
388 #if defined(MULTIPROCESSOR)
389 void
390 cpu_boot_secondary_processors(void)
391 {
392 	struct cpu_info *ci;
393 	u_long i;
394 	bool did_patch = false;
395 
396 	for (i = 0; i < ALPHA_MAXPROCS; i++) {
397 		ci = cpu_info[i];
398 		if (ci == NULL || ci->ci_data.cpu_idlelwp == NULL)
399 			continue;
400 		if (ci->ci_flags & CPUF_PRIMARY)
401 			continue;
402 		if ((cpus_booted & (1UL << i)) == 0)
403 			continue;
404 
405 		/* Patch MP-criticial kernel routines. */
406 		if (did_patch == false) {
407 			alpha_patch(true);
408 			did_patch = true;
409 		}
410 
411 		/*
412 		 * Launch the processor.
413 		 */
414 		atomic_or_ulong(&ci->ci_flags, CPUF_RUNNING);
415 		atomic_or_ulong(&cpus_running, (1U << i));
416 	}
417 }
418 
419 void
420 cpu_boot_secondary(struct cpu_info *ci)
421 {
422 	long timeout;
423 	struct pcs *pcsp, *primary_pcsp;
424 	struct pcb *pcb;
425 	u_long cpumask;
426 
427 	pcb = lwp_getpcb(ci->ci_data.cpu_idlelwp);
428 	primary_pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
429 	pcsp = LOCATE_PCS(hwrpb, ci->ci_cpuid);
430 	cpumask = (1UL << ci->ci_cpuid);
431 
432 	/*
433 	 * Set up the PCS's HWPCB to match ours.
434 	 */
435 	memcpy(pcsp->pcs_hwpcb, &pcb->pcb_hw, sizeof(pcb->pcb_hw));
436 
437 	/*
438 	 * Set up the HWRPB to restart the secondary processor
439 	 * with our spin-up trampoline.
440 	 */
441 	hwrpb->rpb_restart = (u_int64_t) cpu_spinup_trampoline;
442 	hwrpb->rpb_restart_val = (u_int64_t) ci;
443 	hwrpb->rpb_checksum = hwrpb_checksum();
444 
445 	/*
446 	 * Configure the CPU to start in OSF/1 PALcode by copying
447 	 * the primary CPU's PALcode revision info to the secondary
448 	 * CPUs PCS.
449 	 */
450 	memcpy(&pcsp->pcs_pal_rev, &primary_pcsp->pcs_pal_rev,
451 	    sizeof(pcsp->pcs_pal_rev));
452 	pcsp->pcs_flags |= (PCS_CV|PCS_RC);
453 	pcsp->pcs_flags &= ~PCS_BIP;
454 
455 	/* Make sure the secondary console sees all this. */
456 	alpha_mb();
457 
458 	/* Send a "START" command to the secondary CPU's console. */
459 	if (cpu_iccb_send(ci->ci_cpuid, "START\r\n")) {
460 		printf("%s: unable to issue `START' command\n",
461 		    ci->ci_softc->sc_dev.dv_xname);
462 		return;
463 	}
464 
465 	/* Wait for the processor to boot. */
466 	for (timeout = 10000; timeout != 0; timeout--) {
467 		alpha_mb();
468 		if (pcsp->pcs_flags & PCS_BIP)
469 			break;
470 		delay(1000);
471 	}
472 	if (timeout == 0)
473 		printf("%s: processor failed to boot\n",
474 		    ci->ci_softc->sc_dev.dv_xname);
475 
476 	/*
477 	 * ...and now wait for verification that it's running kernel
478 	 * code.
479 	 */
480 	for (timeout = 10000; timeout != 0; timeout--) {
481 		alpha_mb();
482 		if (cpus_booted & cpumask)
483 			break;
484 		delay(1000);
485 	}
486 	if (timeout == 0)
487 		printf("%s: processor failed to hatch\n",
488 		    ci->ci_softc->sc_dev.dv_xname);
489 }
490 
491 void
492 cpu_pause_resume(u_long cpu_id, int pause)
493 {
494 	u_long cpu_mask = (1UL << cpu_id);
495 
496 	if (pause) {
497 		atomic_or_ulong(&cpus_paused, cpu_mask);
498 		alpha_send_ipi(cpu_id, ALPHA_IPI_PAUSE);
499 	} else
500 		atomic_and_ulong(&cpus_paused, ~cpu_mask);
501 }
502 
503 void
504 cpu_pause_resume_all(int pause)
505 {
506 	struct cpu_info *ci, *self = curcpu();
507 	CPU_INFO_ITERATOR cii;
508 
509 	for (CPU_INFO_FOREACH(cii, ci)) {
510 		if (ci == self)
511 			continue;
512 		cpu_pause_resume(ci->ci_cpuid, pause);
513 	}
514 }
515 
516 void
517 cpu_halt(void)
518 {
519 	struct cpu_info *ci = curcpu();
520 	u_long cpu_id = cpu_number();
521 	struct pcs *pcsp = LOCATE_PCS(hwrpb, cpu_id);
522 
523 	printf("%s: shutting down...\n", ci->ci_softc->sc_dev.dv_xname);
524 
525 	pcsp->pcs_flags &= ~(PCS_RC | PCS_HALT_REQ);
526 	pcsp->pcs_flags |= PCS_HALT_STAY_HALTED;
527 
528 	atomic_and_ulong(&cpus_running, ~(1UL << cpu_id));
529 	atomic_and_ulong(&cpus_booted, ~(1U << cpu_id));
530 
531 	alpha_pal_halt();
532 	/* NOTREACHED */
533 }
534 
535 void
536 cpu_hatch(struct cpu_info *ci)
537 {
538 	u_long cpu_id = cpu_number();
539 	u_long cpumask = (1UL << cpu_id);
540 
541 	/* Mark the kernel pmap active on this processor. */
542 	atomic_or_ulong(&pmap_kernel()->pm_cpus, cpumask);
543 
544 	/* Initialize trap vectors for this processor. */
545 	trap_init();
546 
547 	/* Yahoo!  We're running kernel code!  Announce it! */
548 	cpu_announce_extensions(ci);
549 
550 	atomic_or_ulong(&cpus_booted, cpumask);
551 
552 	/*
553 	 * Spin here until we're told we can start.
554 	 */
555 	while ((cpus_running & cpumask) == 0)
556 		/* spin */ ;
557 
558 	/*
559 	 * Invalidate the TLB and sync the I-stream before we
560 	 * jump into the kernel proper.  We have to do this
561 	 * beacause we haven't been getting IPIs while we've
562 	 * been spinning.
563 	 */
564 	ALPHA_TBIA();
565 	alpha_pal_imb();
566 
567 	cc_calibrate_cpu(ci);
568 }
569 
570 int
571 cpu_iccb_send(long cpu_id, const char *msg)
572 {
573 	struct pcs *pcsp = LOCATE_PCS(hwrpb, cpu_id);
574 	int timeout;
575 	u_long cpumask = (1UL << cpu_id);
576 
577 	/* Wait for the ICCB to become available. */
578 	for (timeout = 10000; timeout != 0; timeout--) {
579 		alpha_mb();
580 		if ((hwrpb->rpb_rxrdy & cpumask) == 0)
581 			break;
582 		delay(1000);
583 	}
584 	if (timeout == 0)
585 		return (EIO);
586 
587 	/*
588 	 * Copy the message into the ICCB, and tell the secondary console
589 	 * that it's there.
590 	 */
591 	strcpy(pcsp->pcs_iccb.iccb_rxbuf, msg);
592 	pcsp->pcs_iccb.iccb_rxlen = strlen(msg);
593 	atomic_or_ulong(&hwrpb->rpb_rxrdy, cpumask);
594 	membar_sync();
595 
596 	/* Wait for the message to be received. */
597 	for (timeout = 10000; timeout != 0; timeout--) {
598 		alpha_mb();
599 		if ((hwrpb->rpb_rxrdy & cpumask) == 0)
600 			break;
601 		delay(1000);
602 	}
603 	if (timeout == 0)
604 		return (EIO);
605 
606 	return (0);
607 }
608 
609 void
610 cpu_iccb_receive(void)
611 {
612 #if 0	/* Don't bother... we don't get any important messages anyhow. */
613 	u_int64_t txrdy;
614 	char *cp1, *cp2, buf[80];
615 	struct pcs *pcsp;
616 	u_int cnt;
617 	long cpu_id;
618 
619 	txrdy = hwrpb->rpb_txrdy;
620 
621 	for (cpu_id = 0; cpu_id < hwrpb->rpb_pcs_cnt; cpu_id++) {
622 		if (txrdy & (1UL << cpu_id)) {
623 			pcsp = LOCATE_PCS(hwrpb, cpu_id);
624 			printf("Inter-console message from CPU %lu "
625 			    "HALT REASON = 0x%lx, FLAGS = 0x%lx\n",
626 			    cpu_id, pcsp->pcs_halt_reason, pcsp->pcs_flags);
627 
628 			cnt = pcsp->pcs_iccb.iccb_txlen;
629 			if (cnt >= 80) {
630 				printf("Malformed inter-console message\n");
631 				continue;
632 			}
633 			cp1 = pcsp->pcs_iccb.iccb_txbuf;
634 			cp2 = buf;
635 			while (cnt--) {
636 				if (*cp1 != '\r' && *cp1 != '\n')
637 					*cp2++ = *cp1;
638 				cp1++;
639 			}
640 			*cp2 = '\0';
641 			printf("Message from CPU %lu: %s\n", cpu_id, buf);
642 		}
643 	}
644 #endif /* 0 */
645 	hwrpb->rpb_txrdy = 0;
646 	alpha_mb();
647 }
648 
649 #if defined(DDB)
650 
651 #include <ddb/db_output.h>
652 #include <machine/db_machdep.h>
653 
654 /*
655  * Dump CPU information from DDB.
656  */
657 void
658 cpu_debug_dump(void)
659 {
660 	struct cpu_info *ci;
661 	CPU_INFO_ITERATOR cii;
662 
663 	db_printf("addr		dev	id	flags	ipis	curproc		fpcurproc\n");
664 	for (CPU_INFO_FOREACH(cii, ci)) {
665 		db_printf("%p	%s	%lu	%lx	%lx	%p	%p\n",
666 		    ci,
667 		    ci->ci_softc->sc_dev.dv_xname,
668 		    ci->ci_cpuid,
669 		    ci->ci_flags,
670 		    ci->ci_ipis,
671 		    ci->ci_curlwp,
672 		    ci->ci_fpcurlwp);
673 	}
674 }
675 
676 #endif /* DDB */
677 
678 #endif /* MULTIPROCESSOR */
679