xref: /openbsd/sys/arch/alpha/alpha/cpu.c (revision 487a9f35)
1 /* $OpenBSD: cpu.c,v 1.49 2024/04/10 15:38:11 mpi Exp $ */
2 /* $NetBSD: cpu.c,v 1.44 2000/05/23 05:12:53 thorpej Exp $ */
3 
4 /*-
5  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
36  * All rights reserved.
37  *
38  * Author: Chris G. Demetriou
39  *
40  * Permission to use, copy, modify and distribute this software and
41  * its documentation is hereby granted, provided that both the copyright
42  * notice and this permission notice appear in all copies of the
43  * software, derivative works or modified versions, and any portions
44  * thereof, and that both notices appear in supporting documentation.
45  *
46  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
48  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49  *
50  * Carnegie Mellon requests users of this software to return to
51  *
52  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53  *  School of Computer Science
54  *  Carnegie Mellon University
55  *  Pittsburgh PA 15213-3890
56  *
57  * any improvements or extensions that they make and grant Carnegie the
58  * rights to redistribute these changes.
59  */
60 
61 
62 #include <sys/param.h>
63 #include <sys/clockintr.h>
64 #include <sys/systm.h>
65 #include <sys/device.h>
66 #include <sys/proc.h>
67 #include <sys/user.h>
68 
69 #include <uvm/uvm_extern.h>
70 
71 #include <machine/atomic.h>
72 #include <machine/autoconf.h>
73 #include <machine/cpu.h>
74 #include <machine/rpb.h>
75 #include <machine/prom.h>
76 
77 struct cpu_info cpu_info_primary;
78 struct cpu_info *cpu_info_list = &cpu_info_primary;
79 
80 #if defined(MULTIPROCESSOR)
81 #include <sys/malloc.h>
82 
83 /*
84  * Array of CPU info structures.  Must be statically-allocated because
85  * curproc, etc. are used early.
86  */
87 struct cpu_info *cpu_info[ALPHA_MAXPROCS];
88 
89 /* Bitmask of CPUs booted, currently running, and paused. */
90 volatile u_long cpus_booted;
91 volatile u_long cpus_running;
92 volatile u_long cpus_paused;
93 
94 void	cpu_boot_secondary(struct cpu_info *);
95 #endif /* MULTIPROCESSOR */
96 
97 /*
98  * The Implementation Version and the Architecture Mask must be
99  * consistent across all CPUs in the system, so we set it for the
100  * primary and announce the AMASK extensions if they exist.
101  *
102  * Note, we invert the AMASK so that if a bit is set, it means "has
103  * extension".
104  */
105 u_long	cpu_implver, cpu_amask;
106 
107 /* Definition of the driver for autoconfig. */
108 int	cpumatch(struct device *, void *, void *);
109 void	cpuattach(struct device *, struct device *, void *);
110 
111 const struct cfattach cpu_ca = {
112 	sizeof(struct device), cpumatch, cpuattach
113 };
114 
115 struct cfdriver cpu_cd = {
116 	NULL, "cpu", DV_DULL
117 };
118 
119 void	cpu_announce_extensions(struct cpu_info *);
120 
121 static const char *ev4minor[] = {
122 	"pass 2 or 2.1", "pass 3", 0
123 }, *lcaminor[] = {
124 	"",
125 	"21066 pass 1 or 1.1", "21066 pass 2",
126 	"21068 pass 1 or 1.1", "21068 pass 2",
127 	"21066A pass 1", "21068A pass 1", 0
128 }, *ev5minor[] = {
129 	"", "pass 2, rev BA or 2.2, rev CA", "pass 2.3, rev DA or EA",
130 	"pass 3", "pass 3.2", "pass 4", 0
131 }, *ev45minor[] = {
132 	"", "pass 1", "pass 1.1", "pass 2", 0
133 }, *ev56minor[] = {
134 	"", "pass 1", "pass 2", 0
135 }, *ev6minor[] = {
136 	"", "pass 1", "pass 2 or 2.1", "pass 2.2", "pass 2.3", "pass 3",
137 	"pass 2.4", "pass 2.5", 0
138 }, *pca56minor[] = {
139 	"", "pass 1", 0
140 }, *pca57minor[] = {
141 	"", "pass 1", 0
142 }, *ev67minor[] = {
143 	"", "pass 1", "pass 2.1", "pass 2.2", "pass 2.1.1",
144 	"pass 2.2.1", "pass 2.3 or 2.4", "pass 2.1.2", "pass 2.2.2",
145 	"pass 2.2.3 or 2.2.5", "pass 2.2.4", "pass 2.5", "pass 2.4.1",
146 	"pass 2.5.1", "pass 2.6", 0
147 }, *ev68cbminor[] = {
148 	/* what is the value for pass 2.3? */
149 	"", "", "", "", "",
150 	"pass 2.4", "pass 4.0", 0
151 };
152 
153 struct cputable_struct {
154 	int	cpu_major_code;
155 	const char *cpu_major_name;
156 	const char **cpu_minor_names;
157 } cpunametable[] = {
158 	{ PCS_PROC_EV3,		"EV3",		0		},
159 	{ PCS_PROC_EV4,		"21064",	ev4minor	},
160 	{ PCS_PROC_SIMULATION,	"Sim",		0		},
161 	{ PCS_PROC_LCA4,	"LCA",		lcaminor	},
162 	{ PCS_PROC_EV5,		"21164",	ev5minor	},
163 	{ PCS_PROC_EV45,	"21064A",	ev45minor	},
164 	{ PCS_PROC_EV56,	"21164A",	ev56minor	},
165 	{ PCS_PROC_EV6,		"21264",	ev6minor	},
166 	{ PCS_PROC_PCA56,	"PCA56",	pca56minor	},
167 	{ PCS_PROC_PCA57,	"PCA57",	pca57minor	},
168 	{ PCS_PROC_EV67,	"21264A",	ev67minor	},
169 	{ PCS_PROC_EV68CB,	"21264C",	ev68cbminor	},
170 	{ PCS_PROC_EV68AL,	"21264B",	NULL		},
171 	{ PCS_PROC_EV68CX,	"21264D",	NULL		},
172 };
173 
174 /*
175  * The following is an attempt to map out how booting secondary CPUs
176  * works.
177  *
178  * As we find processors during the autoconfiguration sequence, all
179  * processors have idle stacks and PCBs created for them, including
180  * the primary (although the primary idles on proc0's PCB until its
181  * idle PCB is created).
182  *
183  * As one of the last steps in booting, main() calls, on proc0's
184  * context, cpu_boot_secondary_processors().  This is our key to
185  * actually spin up the additional processors we've found.  We
186  * run through our cpu_info[] array looking for secondary processors
187  * with idle PCBs, and spin them up.
188  *
189  * The spinup involves switching the secondary processor to the
190  * OSF/1 PALcode, setting the entry point to cpu_spinup_trampoline(),
191  * and sending a "START" message to the secondary's console.
192  *
193  * Upon successful processor bootup, the cpu_spinup_trampoline will call
194  * cpu_hatch(), which will print a message indicating that the processor
195  * is running, and will set the "hatched" flag in its softc.  At the end
196  * of cpu_hatch() is a spin-forever loop; we do not yet attempt to schedule
197  * anything on secondary CPUs.
198  */
199 
200 int
cpumatch(struct device * parent,void * cfdata,void * aux)201 cpumatch(struct device *parent, void *cfdata, void *aux)
202 {
203 	struct mainbus_attach_args *ma = aux;
204 
205 	/* make sure that we're looking for a CPU. */
206 	if (strcmp(ma->ma_name, cpu_cd.cd_name) != 0)
207 		return (0);
208 
209 #ifndef MULTIPROCESSOR
210 	/* Only attach the boot processor. */
211 	if (ma->ma_slot != hwrpb->rpb_primary_cpu_id)
212 		return (0);
213 #endif
214 
215 	return (1);
216 }
217 
218 void
cpuattach(struct device * parent,struct device * dev,void * aux)219 cpuattach(struct device *parent, struct device *dev, void *aux)
220 {
221 	struct mainbus_attach_args *ma = aux;
222 	struct cpu_info *ci;
223 	int i;
224 	const char **s;
225 	struct pcs *p;
226 #ifdef DEBUG
227 	int needcomma;
228 #endif
229 	u_int32_t major, minor;
230 #if defined(MULTIPROCESSOR)
231 	vaddr_t pcbva;
232 	struct pcb *pcb;
233 	const struct kmem_pa_mode kp_contig = {
234 		.kp_constraint = &no_constraint,
235 		.kp_maxseg = 1,
236 		.kp_zero = 1
237 	};
238 #endif
239 
240 	p = LOCATE_PCS(hwrpb, ma->ma_slot);
241 	major = PCS_CPU_MAJORTYPE(p);
242 	minor = PCS_CPU_MINORTYPE(p);
243 
244 	printf(": ID %d%s, ", ma->ma_slot,
245 	    ma->ma_slot == hwrpb->rpb_primary_cpu_id ? " (primary)" : "");
246 
247 	for (i = 0; i < sizeof cpunametable / sizeof cpunametable[0]; ++i) {
248 		if (cpunametable[i].cpu_major_code == major) {
249 			printf("%s-%d", cpunametable[i].cpu_major_name, minor);
250 			s = cpunametable[i].cpu_minor_names;
251 			for (i = 0; s && s[i]; ++i) {
252 				if (i == minor && strlen(s[i]) != 0) {
253 					printf(" (%s)", s[i]);
254 					goto recognized;
255 				}
256 			}
257 			printf(" (unknown minor type %d)", minor);
258 			goto recognized;
259 		}
260 	}
261 	printf("UNKNOWN CPU TYPE (%d:%d)", major, minor);
262 
263 recognized:
264 	printf("\n");
265 
266 #ifdef DEBUG
267 	if (p->pcs_proc_var != 0) {
268 		printf("%s: ", dev->dv_xname);
269 
270 		needcomma = 0;
271 		if (p->pcs_proc_var & PCS_VAR_VAXFP) {
272 			printf("VAX FP support");
273 			needcomma = 1;
274 		}
275 		if (p->pcs_proc_var & PCS_VAR_IEEEFP) {
276 			printf("%sIEEE FP support", needcomma ? ", " : "");
277 			needcomma = 1;
278 		}
279 		if (p->pcs_proc_var & PCS_VAR_PE) {
280 			printf("%sPrimary Eligible", needcomma ? ", " : "");
281 			needcomma = 1;
282 		}
283 		if (p->pcs_proc_var & PCS_VAR_RESERVED)
284 			printf("%sreserved bits: 0x%lx", needcomma ? ", " : "",
285 			    p->pcs_proc_var & PCS_VAR_RESERVED);
286 		printf("\n");
287 	}
288 #endif
289 
290 #if defined(MULTIPROCESSOR)
291 	if (ma->ma_slot > ALPHA_WHAMI_MAXID) {
292 		printf("%s: processor ID too large, ignoring\n", dev->dv_xname);
293 		return;
294 	}
295 #endif /* MULTIPROCESSOR */
296 
297 #if defined(MULTIPROCESSOR)
298 	if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
299 		ci = &cpu_info_primary;
300 	else
301 		ci = malloc(sizeof(*ci), M_DEVBUF, M_WAITOK | M_ZERO);
302 
303 	cpu_info[ma->ma_slot] = ci;
304 #else
305 	ci = &cpu_info_primary;
306 #endif
307 	ci->ci_cpuid = ma->ma_slot;
308 	ci->ci_dev = dev;
309 
310 #if defined(MULTIPROCESSOR)
311 	/*
312 	 * Make sure the processor is available for use.
313 	 */
314 	if ((p->pcs_flags & PCS_PA) == 0) {
315 		if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
316 			panic("cpu_attach: primary not available?!");
317 		printf("%s: processor not available for use\n", dev->dv_xname);
318 		return;
319 	}
320 
321 	/* Make sure the processor has valid PALcode. */
322 	if ((p->pcs_flags & PCS_PV) == 0) {
323 		if (ma->ma_slot == hwrpb->rpb_primary_cpu_id)
324 			panic("cpu_attach: primary has invalid PALcode?!");
325 		printf("%s: PALcode not valid\n", ci->ci_dev->dv_xname);
326 		return;
327 	}
328 
329 	/*
330 	 * Allocate UPAGES contiguous pages for the idle PCB and stack.
331 	 */
332 	pcbva = (vaddr_t)km_alloc(USPACE, &kv_any, &kp_contig, &kd_waitok);
333 	if (pcbva == 0) {
334 		if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) {
335 			panic("cpu_attach: unable to allocate idle stack for"
336 			    " primary");
337 		}
338 		printf("%s: unable to allocate idle stack\n", dev->dv_xname);
339 		return;
340 	}
341 
342 	ci->ci_idle_pcb_paddr = ALPHA_K0SEG_TO_PHYS(pcbva);
343 	pcb = ci->ci_idle_pcb = (struct pcb *)pcbva;
344 
345 	/*
346 	 * Initialize the idle stack pointer, reserving space for an
347 	 * (empty) trapframe (XXX is the trapframe really necessary?)
348 	 */
349 	pcb->pcb_hw.apcb_ksp =
350 	    (u_int64_t)pcb + USPACE - sizeof(struct trapframe);
351 
352 	/*
353 	 * Initialize the idle PCB.
354 	 */
355 	pcb->pcb_hw.apcb_asn = proc0.p_addr->u_pcb.pcb_hw.apcb_asn;
356 	pcb->pcb_hw.apcb_ptbr = proc0.p_addr->u_pcb.pcb_hw.apcb_ptbr;
357 #if 0
358 	printf("%s: hwpcb ksp = 0x%lx\n", dev->dv_xname,
359 	    pcb->pcb_hw.apcb_ksp);
360 	printf("%s: hwpcb ptbr = 0x%lx\n", dev->dv_xname,
361 	    pcb->pcb_hw.apcb_ptbr);
362 #endif
363 #endif /* MULTIPROCESSOR */
364 
365 	/*
366 	 * If we're the primary CPU, no more work to do; we're already
367 	 * running!
368 	 */
369 	if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) {
370 		cpu_announce_extensions(ci);
371 #if defined(MULTIPROCESSOR)
372 		ci->ci_flags |= CPUF_PRIMARY | CPUF_RUNNING;
373 		atomic_setbits_ulong(&cpus_booted, (1UL << ma->ma_slot));
374 		atomic_setbits_ulong(&cpus_running, (1UL << ma->ma_slot));
375 #endif /* MULTIPROCESSOR */
376 	} else {
377 #if defined(MULTIPROCESSOR)
378 		/*
379 		 * Boot the secondary processor.  It will announce its
380 		 * extensions, and then spin up until we tell it to go
381 		 * on its merry way.
382 		 */
383 		cpu_boot_secondary(ci);
384 #endif /* MULTIPROCESSOR */
385 	}
386 }
387 
388 void
cpu_announce_extensions(struct cpu_info * ci)389 cpu_announce_extensions(struct cpu_info *ci)
390 {
391 	u_long implver, amask = 0;
392 
393 	implver = alpha_implver();
394 	if (implver >= ALPHA_IMPLVER_EV5)
395 		amask = (~alpha_amask(ALPHA_AMASK_ALL)) & ALPHA_AMASK_ALL;
396 
397 	if (ci->ci_cpuid == hwrpb->rpb_primary_cpu_id) {
398 		cpu_implver = implver;
399 		cpu_amask = amask;
400 	} else {
401 		if (implver < cpu_implver)
402 			printf("%s: WARNING: IMPLVER %lu < %lu\n",
403 			    ci->ci_dev->dv_xname, implver, cpu_implver);
404 
405 		/*
406 		 * Cap the system architecture mask to the intersection
407 		 * of features supported by all processors in the system.
408 		 */
409 		cpu_amask &= amask;
410 	}
411 
412 	if (amask) {
413 		printf("%s: architecture extensions: %lb\n",
414 		    ci->ci_dev->dv_xname, amask, ALPHA_AMASK_BITS);
415 	}
416 }
417 
418 #if defined(MULTIPROCESSOR)
419 void
cpu_boot_secondary_processors(void)420 cpu_boot_secondary_processors(void)
421 {
422 	struct cpu_info *ci;
423 	u_long i;
424 
425 	for (i = 0; i < ALPHA_MAXPROCS; i++) {
426 		ci = cpu_info[i];
427 		if (ci == NULL || ci->ci_idle_pcb == NULL)
428 			continue;
429 		if (CPU_IS_PRIMARY(ci))
430 			continue;
431 		if ((cpus_booted & (1UL << i)) == 0)
432 			continue;
433 
434 		/*
435 		 * Link the processor into the list, and launch it.
436 		 */
437 		ci->ci_next = cpu_info_list->ci_next;
438 		cpu_info_list->ci_next = ci;
439 		atomic_setbits_ulong(&ci->ci_flags, CPUF_RUNNING);
440 		atomic_setbits_ulong(&cpus_running, (1UL << i));
441 		ncpus++;
442 	}
443 
444 	/*
445 	 * Reset the HWRPB to prevent processors resetting from
446 	 * running through the hatching code again.
447 	 */
448 	hwrpb->rpb_restart = (u_int64_t) cpu_halt;
449 	hwrpb->rpb_checksum = hwrpb_checksum();
450 }
451 
452 void
cpu_boot_secondary(struct cpu_info * ci)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_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", ci->ci_dev->dv_xname);
507 
508 	/*
509 	 * ...and now wait for verification that it's running kernel
510 	 * code.
511 	 */
512 	for (timeout = 10000; timeout != 0; timeout--) {
513 		alpha_mb();
514 		if (cpus_booted & cpumask)
515 			break;
516 		delay(1000);
517 	}
518 	if (timeout == 0)
519 		printf("%s: processor failed to hatch\n", ci->ci_dev->dv_xname);
520 }
521 
522 void
cpu_pause_resume(u_long cpu_id,int pause)523 cpu_pause_resume(u_long cpu_id, int pause)
524 {
525 	u_long cpu_mask = (1UL << cpu_id);
526 
527 	if (pause) {
528 		atomic_setbits_ulong(&cpus_paused, cpu_mask);
529 		alpha_send_ipi(cpu_id, ALPHA_IPI_PAUSE);
530 	} else
531 		atomic_clearbits_ulong(&cpus_paused, cpu_mask);
532 }
533 
534 void
cpu_pause_resume_all(int pause)535 cpu_pause_resume_all(int pause)
536 {
537 	struct cpu_info *ci, *self = curcpu();
538 	CPU_INFO_ITERATOR cii;
539 
540 	CPU_INFO_FOREACH(cii, ci) {
541 		if (ci == self)
542 			continue;
543 		cpu_pause_resume(ci->ci_cpuid, pause);
544 	}
545 }
546 
547 void
cpu_halt(void)548 cpu_halt(void)
549 {
550 	struct cpu_info *ci = curcpu();
551 	u_long cpu_id = cpu_number();
552 	struct pcs *pcsp = LOCATE_PCS(hwrpb, cpu_id);
553 
554 	printf("%s: shutting down...\n", ci->ci_dev->dv_xname);
555 
556 	pcsp->pcs_flags &= ~(PCS_RC | PCS_HALT_REQ);
557 	pcsp->pcs_flags |= PCS_HALT_STAY_HALTED;
558 
559 	atomic_clearbits_ulong(&cpus_running, (1UL << cpu_id));
560 	atomic_clearbits_ulong(&cpus_booted, (1U << cpu_id));
561 
562 	alpha_pal_halt();
563 	/* NOTREACHED */
564 }
565 
566 void
cpu_hatch(struct cpu_info * ci)567 cpu_hatch(struct cpu_info *ci)
568 {
569 	u_long cpu_id = cpu_number();
570 	u_long cpumask = (1UL << cpu_id);
571 
572 	/* Mark the kernel pmap active on this processor. */
573 	atomic_setbits_ulong(&pmap_kernel()->pm_cpus, cpumask);
574 
575 	/* Initialize trap vectors for this processor. */
576 	trap_init();
577 
578 	/* Yahoo!  We're running kernel code!  Announce it! */
579 	cpu_announce_extensions(ci);
580 
581 	atomic_setbits_ulong(&cpus_booted, cpumask);
582 
583 	/*
584 	 * Spin here until we're told we can start.
585 	 */
586 	while ((cpus_running & cpumask) == 0)
587 		/* spin */ ;
588 
589 	/*
590 	 * Invalidate the TLB and sync the I-stream before we
591 	 * jump into the kernel proper.  We have to do this
592 	 * because we haven't been getting IPIs while we've
593 	 * been spinning.
594 	 */
595 	ALPHA_TBIA();
596 	alpha_pal_imb();
597 
598 	clockqueue_init(&ci->ci_queue);
599 	KERNEL_LOCK();
600 	sched_init_cpu(ci);
601 	ci->ci_curproc = ci->ci_fpcurproc = NULL;
602 	ci->ci_randseed = (arc4random() & 0x7fffffff) + 1;
603 	KERNEL_UNLOCK();
604 
605 	clockintr_cpu_init(NULL);
606 
607 	(void) alpha_pal_swpipl(ALPHA_PSL_IPL_0);
608 	sched_toidle();
609 	/* NOTREACHED */
610 }
611 
612 int
cpu_iccb_send(cpuid_t cpu_id,const char * msg)613 cpu_iccb_send(cpuid_t cpu_id, const char *msg)
614 {
615 	struct pcs *pcsp = LOCATE_PCS(hwrpb, cpu_id);
616 	int timeout;
617 	u_long cpumask = (1UL << cpu_id);
618 
619 	/* Wait for the ICCB to become available. */
620 	for (timeout = 10000; timeout != 0; timeout--) {
621 		alpha_mb();
622 		if ((hwrpb->rpb_rxrdy & cpumask) == 0)
623 			break;
624 		delay(1000);
625 	}
626 	if (timeout == 0)
627 		return (EIO);
628 
629 	/*
630 	 * Copy the message into the ICCB, and tell the secondary console
631 	 * that it's there.  The atomic operation performs a memory barrier.
632 	 */
633 	strlcpy(pcsp->pcs_iccb.iccb_rxbuf, msg,
634 	    sizeof pcsp->pcs_iccb.iccb_rxbuf);
635 	pcsp->pcs_iccb.iccb_rxlen = strlen(msg);
636 	/* XXX cast to volatile */
637 	atomic_setbits_ulong((volatile u_long *)&hwrpb->rpb_rxrdy, cpumask);
638 	alpha_mb();
639 
640 	/* Wait for the message to be received. */
641 	for (timeout = 10000; timeout != 0; timeout--) {
642 		alpha_mb();
643 		if ((hwrpb->rpb_rxrdy & cpumask) == 0)
644 			break;
645 		delay(1000);
646 	}
647 	if (timeout == 0)
648 		return (EIO);
649 
650 	return (0);
651 }
652 
653 void
cpu_iccb_receive(void)654 cpu_iccb_receive(void)
655 {
656 #if 0	/* Don't bother... we don't get any important messages anyhow. */
657 	u_int64_t txrdy;
658 	char *cp1, *cp2, buf[80];
659 	struct pcs *pcsp;
660 	u_int cnt;
661 	cpuid_t cpu_id;
662 
663 	txrdy = hwrpb->rpb_txrdy;
664 
665 	for (cpu_id = 0; cpu_id < hwrpb->rpb_pcs_cnt; cpu_id++) {
666 		if (txrdy & (1UL << cpu_id)) {
667 			pcsp = LOCATE_PCS(hwrpb, cpu_id);
668 			printf("Inter-console message from CPU %lu "
669 			    "HALT REASON = 0x%lx, FLAGS = 0x%lx\n",
670 			    cpu_id, pcsp->pcs_halt_reason, pcsp->pcs_flags);
671 
672 			cnt = pcsp->pcs_iccb.iccb_txlen;
673 			if (cnt >= 80) {
674 				printf("Malformed inter-console message\n");
675 				continue;
676 			}
677 			cp1 = pcsp->pcs_iccb.iccb_txbuf;
678 			cp2 = buf;
679 			while (cnt--) {
680 				if (*cp1 != '\r' && *cp1 != '\n')
681 					*cp2++ = *cp1;
682 				cp1++;
683 			}
684 			*cp2 = '\0';
685 			printf("Message from CPU %lu: %s\n", cpu_id, buf);
686 		}
687 	}
688 #endif /* 0 */
689 	hwrpb->rpb_txrdy = 0;
690 	alpha_mb();
691 }
692 
693 void
cpu_unidle(struct cpu_info * ci)694 cpu_unidle(struct cpu_info *ci)
695 {
696 	if (ci != curcpu())
697 		alpha_send_ipi(ci->ci_cpuid, ALPHA_IPI_AST);
698 }
699 #endif /* MULTIPROCESSOR */
700