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