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