1 /* $NetBSD: ka820.c,v 1.49 2008/03/11 05:34:03 matt Exp $ */ 2 /* 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Chris Torek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ka820.c 7.4 (Berkeley) 12/16/90 34 */ 35 36 /* 37 * KA820 specific CPU code. (Note that the VAX8200 uses a KA820, not 38 * a KA8200. Sigh.) 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: ka820.c,v 1.49 2008/03/11 05:34:03 matt Exp $"); 43 44 #include "opt_multiprocessor.h" 45 46 #include <sys/param.h> 47 #include <sys/time.h> 48 #include <sys/kernel.h> 49 #include <sys/device.h> 50 #include <sys/systm.h> 51 #include <sys/conf.h> 52 #include <sys/proc.h> 53 #include <sys/user.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #include <machine/ka820.h> 58 #include <machine/cpu.h> 59 #include <machine/mtpr.h> 60 #include <machine/nexus.h> 61 #include <machine/clock.h> 62 #include <machine/scb.h> 63 #include <machine/bus.h> 64 #include <machine/mainbus.h> 65 66 #include <dev/cons.h> 67 68 #include <dev/bi/bireg.h> 69 #include <dev/bi/bivar.h> 70 71 #include <vax/vax/crx.h> 72 73 #include "ioconf.h" 74 #include "locators.h" 75 76 struct ka820port *ka820port_ptr; 77 struct rx50device *rx50device_ptr; 78 static volatile struct ka820clock *ka820_clkpage; 79 static int mastercpu; 80 81 static int ka820_match(device_t, cfdata_t, void *); 82 static void ka820_attach(device_t, device_t, void*); 83 static void ka820_memerr(void); 84 static void ka820_conf(void); 85 static int ka820_mchk(void *); 86 static int ka820_gettime(volatile struct timeval *); 87 static void ka820_settime(volatile struct timeval *); 88 static void rxcdintr(void *); 89 static void vaxbierr(void *); 90 91 static const char * const ka820_devs[] = { "bi", NULL }; 92 93 const struct cpu_dep ka820_calls = { 94 .cpu_mchk = ka820_mchk, 95 .cpu_memerr = ka820_memerr, 96 .cpu_conf = ka820_conf, 97 .cpu_gettime = ka820_gettime, 98 .cpu_settime = ka820_settime, 99 .cpu_devs = ka820_devs, 100 .cpu_vups = 3, /* ~VUPS */ 101 .cpu_scbsz = 5, /* SCB pages */ 102 }; 103 104 #if defined(MULTIPROCESSOR) 105 static void ka820_startslave(struct cpu_info *); 106 static void ka820_send_ipi(struct cpu_info *); 107 static void ka820_txrx(int, const char *, int); 108 static void ka820_sendstr(int, const char *); 109 static void ka820_sergeant(int); 110 static int rxchar(void); 111 static void ka820_putc(int); 112 static void ka820_cnintr(void); 113 static void ka820_ipintr(void *); 114 cons_decl(gen); 115 116 const struct cpu_mp_dep ka820_mp_dep = { 117 .cpu_startslave = ka820_startslave, 118 .cpu_send_ipi = ka820_send_ipi, 119 .cpu_cnintr = ka820_cnintr, 120 }; 121 #endif 122 123 CFATTACH_DECL_NEW(cpu_bi, 0, 124 ka820_match, ka820_attach, NULL, NULL); 125 126 #ifdef notyet 127 extern struct pte BRAMmap[]; 128 extern struct pte EEPROMmap[]; 129 char bootram[KA820_BRPAGES * VAX_NBPG]; 130 char eeprom[KA820_EEPAGES * VAX_NBPG]; 131 #endif 132 133 static int 134 ka820_match(device_t parent, cfdata_t cf, void *aux) 135 { 136 struct bi_attach_args * const ba = aux; 137 138 if (bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) != BIDT_KA820) 139 return 0; 140 141 if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT && 142 cf->cf_loc[BICF_NODE] != ba->ba_nodenr) 143 return 0; 144 145 return 1; 146 } 147 148 static void 149 ka820_attach(device_t parent, device_t self, void *aux) 150 { 151 struct bi_attach_args * const ba = aux; 152 struct cpu_info *ci; 153 int csr; 154 u_short rev; 155 156 rev = bus_space_read_4(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) >> 16; 157 mastercpu = mfpr(PR_BINID); 158 strcpy(cpu_model, "VAX 8200"); 159 cpu_model[6] = rev & 0x8000 ? '5' : '0'; 160 printf(": ka82%c (%s) CPU rev %d, u patch rev %d, sec patch %d\n", 161 cpu_model[6], mastercpu == ba->ba_nodenr ? "master" : "slave", 162 ((rev >> 11) & 15), ((rev >> 1) &1023), rev & 1); 163 164 /* Allow for IPINTR */ 165 bus_space_write_4(ba->ba_iot, ba->ba_ioh, 166 BIREG_IPINTRMSK, BIIPINTR_MASK); 167 168 #if defined(MULTIPROCESSOR) 169 if (ba->ba_nodenr != mastercpu) { 170 v_putc = ka820_putc; /* Need special console handling */ 171 cpu_slavesetup(self, ba->ba_nodenr); 172 return; 173 } 174 #endif 175 176 ci = curcpu(); 177 self->dv_private = ci; /* eww. but curcpu() is already too */ 178 /* entrenched to change */ 179 ci->ci_slotid = ba->ba_nodenr; 180 ci->ci_cpuid = device_unit(self); 181 ci->ci_dev = self; 182 183 #if defined(MULTIPROCESSOR) 184 /* 185 * Catch interprocessor interrupts. 186 */ 187 scb_vecalloc(KA820_INT_IPINTR, ka820_ipintr, ci, SCB_ISTACK, NULL); 188 #endif 189 /* reset the console and enable the RX50 */ 190 ka820port_ptr = (void *)vax_map_physmem(KA820_PORTADDR, 1); 191 csr = ka820port_ptr->csr; 192 csr &= ~KA820PORT_RSTHALT; /* ??? */ 193 csr |= KA820PORT_CONSCLR | KA820PORT_CRDCLR | KA820PORT_CONSEN | 194 KA820PORT_RXIE; 195 ka820port_ptr->csr = csr; 196 bus_space_write_4(ba->ba_iot, ba->ba_ioh, 197 BIREG_INTRDES, ba->ba_intcpu); 198 bus_space_write_4(ba->ba_iot, ba->ba_ioh, BIREG_VAXBICSR, 199 bus_space_read_4(ba->ba_iot, ba->ba_ioh, BIREG_VAXBICSR) | 200 BICSR_SEIE | BICSR_HEIE); 201 } 202 203 void 204 ka820_conf(void) 205 { 206 /* 207 * Setup parameters necessary to read time from clock chip. 208 */ 209 ka820_clkpage = (void *)vax_map_physmem(KA820_CLOCKADDR, 1); 210 211 /* Enable cache */ 212 mtpr(0, PR_CADR); 213 214 /* Steal the interrupt vectors that are unique for us */ 215 scb_vecalloc(KA820_INT_RXCD, rxcdintr, NULL, SCB_ISTACK, NULL); 216 scb_vecalloc(0x50, vaxbierr, NULL, SCB_ISTACK, NULL); 217 218 /* XXX - should be done somewhere else */ 219 scb_vecalloc(SCB_RX50, crxintr, NULL, SCB_ISTACK, NULL); 220 rx50device_ptr = (void *)vax_map_physmem(KA820_RX50ADDR, 1); 221 #if defined(MULTIPROCESSOR) 222 mp_dep_call = &ka820_mp_dep; 223 #endif 224 } 225 226 void 227 vaxbierr(void *arg) 228 { 229 if (cold == 0) 230 panic("vaxbierr"); 231 } 232 233 #ifdef notdef 234 /* 235 * MS820 support. 236 */ 237 struct ms820regs { 238 struct biiregs biic; /* BI interface chip */ 239 u_long ms_gpr[4]; /* the four gprs (unused) */ 240 int ms_csr1; /* control/status register 1 */ 241 int ms_csr2; /* control/status register 2 */ 242 }; 243 #endif 244 245 #define MEMRD(reg) bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg)) 246 #define MEMWR(reg, val) bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val)) 247 248 #define MSREG_CSR1 0x100 249 #define MSREG_CSR2 0x104 250 /* 251 * Bits in CSR1. 252 */ 253 #define MS1_ERRSUM 0x80000000 /* error summary (ro) */ 254 #define MS1_ECCDIAG 0x40000000 /* ecc diagnostic (rw) */ 255 #define MS1_ECCDISABLE 0x20000000 /* ecc disable (rw) */ 256 #define MS1_MSIZEMASK 0x1ffc0000 /* mask for memory size (ro) */ 257 #define MS1_RAMTYMASK 0x00030000 /* mask for ram type (ro) */ 258 #define MS1_RAMTY64K 0x00000000 /* 64K chips */ 259 #define MS1_RAMTY256K 0x00010000 /* 256K chips */ 260 #define MS1_RAMTY1MB 0x00020000 /* 1MB chips */ 261 /* type 3 reserved */ 262 #define MS1_CRDINH 0x00008000 /* inhibit crd interrupts (rw) */ 263 #define MS1_MEMVALID 0x00004000 /* memory has been written (ro) */ 264 #define MS1_INTLK 0x00002000 /* interlock flag (ro) */ 265 #define MS1_BROKE 0x00001000 /* broken (rw) */ 266 #define MS1_MBZ 0x00000880 /* zero */ 267 #define MS1_MWRITEERR 0x00000400 /* rds during masked write (rw) */ 268 #define MS1_CNTLERR 0x00000200 /* internal timing busted (rw) */ 269 #define MS1_INTLV 0x00000100 /* internally interleaved (ro) */ 270 #define MS1_DIAGC 0x0000007f /* ecc diagnostic bits (rw) */ 271 272 /* 273 * Bits in CSR2. 274 */ 275 #define MS2_RDSERR 0x80000000 /* rds error (rw) */ 276 #define MS2_HIERR 0x40000000 /* high error rate (rw) */ 277 #define MS2_CRDERR 0x20000000 /* crd error (rw) */ 278 #define MS2_ADRSERR 0x10000000 /* rds due to addr par err (rw) */ 279 #define MS2_MBZ 0x0f000080 /* zero */ 280 #define MS2_ADDR 0x00fffe00 /* address in error (relative) (ro) */ 281 #define MS2_INTLVADDR 0x00000100 /* error was in bank 1 (ro) */ 282 #define MS2_SYN 0x0000007f /* error syndrome (ro, rw diag) */ 283 284 static int ms820_match(device_t, cfdata_t, void *); 285 static void ms820_attach(device_t, device_t, void*); 286 287 struct mem_bi_softc { 288 struct device *sc_dev; 289 bus_space_tag_t sc_iot; 290 bus_space_handle_t sc_ioh; 291 }; 292 293 CFATTACH_DECL_NEW(mem_bi, sizeof(struct mem_bi_softc), 294 ms820_match, ms820_attach, NULL, NULL); 295 296 static int 297 ms820_match(device_t parent, cfdata_t cf, void *aux) 298 { 299 struct bi_attach_args * const ba = aux; 300 301 if (bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) != BIDT_MS820) 302 return 0; 303 304 if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT && 305 cf->cf_loc[BICF_NODE] != ba->ba_nodenr) 306 return 0; 307 308 return 1; 309 } 310 311 static void 312 ms820_attach(device_t parent, device_t self, void *aux) 313 { 314 struct mem_bi_softc * const sc = device_private(self); 315 struct bi_attach_args * const ba = aux; 316 317 sc->sc_dev = self; 318 sc->sc_iot = ba->ba_iot; 319 sc->sc_ioh = ba->ba_ioh; 320 321 if ((MEMRD(BIREG_VAXBICSR) & BICSR_STS) == 0) 322 aprint_error(": failed self test\n"); 323 else 324 aprint_normal(": size %dMB, %s chips\n", ((MEMRD(MSREG_CSR1) & 325 MS1_MSIZEMASK) >> 20), (MEMRD(MSREG_CSR1) & MS1_RAMTYMASK 326 ? MEMRD(MSREG_CSR1) & MS1_RAMTY256K ? "256K":"1M":"64K")); 327 328 MEMWR(BIREG_INTRDES, ba->ba_intcpu); 329 MEMWR(BIREG_VAXBICSR, MEMRD(BIREG_VAXBICSR) | BICSR_SEIE | BICSR_HEIE); 330 331 MEMWR(MSREG_CSR1, MS1_MWRITEERR | MS1_CNTLERR); 332 MEMWR(MSREG_CSR2, MS2_RDSERR | MS2_HIERR | MS2_CRDERR | MS2_ADRSERR); 333 } 334 335 static void 336 ka820_memerr(void) 337 { 338 struct mem_bi_softc *sc; 339 int m, hard, csr1, csr2; 340 const char *type; 341 342 static const char b1[] = "\20\40ERRSUM\37ECCDIAG\36ECCDISABLE\20CRDINH\17VALID\ 343 \16INTLK\15BROKE\13MWRITEERR\12CNTLERR\11INTLV"; 344 static const char b2[] = "\20\40RDS\37HIERR\36CRD\35ADRS"; 345 346 char sbuf[sizeof(b1) + 64], sbuf2[sizeof(b2) + 64]; 347 348 for (m = 0; m < mem_cd.cd_ndevs; m++) { 349 sc = device_lookup_private(&mem_cd, m); 350 if (sc == NULL) 351 continue; 352 csr1 = MEMRD(MSREG_CSR1); 353 csr2 = MEMRD(MSREG_CSR2); 354 bitmask_snprintf(csr1, b1, sbuf, sizeof(sbuf)); 355 bitmask_snprintf(csr2, b2, sbuf2, sizeof(sbuf2)); 356 aprint_error_dev(sc->sc_dev, "csr1=%s csr2=%s\n", sbuf, sbuf2); 357 if ((csr1 & MS1_ERRSUM) == 0) 358 continue; 359 hard = 1; 360 if (csr1 & MS1_BROKE) 361 type = "broke"; 362 else if (csr1 & MS1_CNTLERR) 363 type = "cntl err"; 364 else if (csr2 & MS2_ADRSERR) 365 type = "address parity err"; 366 else if (csr2 & MS2_RDSERR) 367 type = "rds err"; 368 else if (csr2 & MS2_CRDERR) { 369 hard = 0; 370 type = ""; 371 } else 372 type = "mysterious error"; 373 aprint_error_dev(sc->sc_dev, "%s%s%s addr %x bank %x syn %x\n", 374 hard ? "hard error: " : "soft ecc", 375 type, csr2 & MS2_HIERR ? " (+ other rds or crd err)" : "", 376 ((csr2 & MS2_ADDR) + MEMRD(BIREG_SADR)) >> 9, 377 (csr2 & MS2_INTLVADDR) != 0, csr2 & MS2_SYN); 378 MEMWR(MSREG_CSR1, csr1 | MS1_CRDINH); 379 MEMWR(MSREG_CSR2, csr2); 380 } 381 } 382 383 /* these are bits 0 to 6 in the summary field */ 384 const char * const mc8200[] = { 385 "cpu bad ipl", "ucode lost err", 386 "ucode par err", "DAL par err", 387 "BI bus err", "BTB tag par", 388 "cache tag par", 389 }; 390 #define MC8200_BADIPL 0x01 391 #define MC8200_UERR 0x02 392 #define MC8200_UPAR 0x04 393 #define MC8200_DPAR 0x08 394 #define MC8200_BIERR 0x10 395 #define MC8200_BTAGPAR 0x20 396 #define MC8200_CTAGPAR 0x40 397 398 struct mc8200frame { 399 int mc82_bcnt; /* byte count == 0x20 */ 400 int mc82_summary; /* summary parameter */ 401 int mc82_param1; /* parameter 1 */ 402 int mc82_va; /* va register */ 403 int mc82_vap; /* va prime register */ 404 int mc82_ma; /* memory address */ 405 int mc82_status; /* status word */ 406 int mc82_epc; /* error pc */ 407 int mc82_upc; /* micro pc */ 408 int mc82_pc; /* current pc */ 409 int mc82_psl; /* current psl */ 410 }; 411 412 static int 413 ka820_mchk(void *cmcf) 414 { 415 struct mc8200frame *mcf = (struct mc8200frame *)cmcf; 416 int i, type = mcf->mc82_summary; 417 418 /* ignore BI bus errors during configuration */ 419 if (cold && type == MC8200_BIERR) { 420 mtpr(PR_MCESR, 0xf); 421 return (MCHK_RECOVERED); 422 } 423 424 /* 425 * SOME ERRORS ARE RECOVERABLE 426 * do it later 427 */ 428 printf("machine check %x: ", type); 429 for (i = 0; i < sizeof (mc8200) / sizeof (mc8200[0]); i++) 430 if (type & (1 << i)) 431 printf(" %s,", mc8200[i]); 432 printf(" param1 %x\n", mcf->mc82_param1); 433 printf( 434 "\tva %x va' %x ma %x pc %x psl %x\n\tstatus %x errpc %x upc %x\n", 435 mcf->mc82_va, mcf->mc82_vap, mcf->mc82_ma, 436 mcf->mc82_pc, mcf->mc82_psl, 437 mcf->mc82_status, mcf->mc82_epc, mcf->mc82_upc); 438 return (MCHK_PANIC); 439 } 440 441 #if defined(MULTIPROCESSOR) 442 #define RXBUF 80 443 static char rxbuf[RXBUF]; 444 static int got = 0, taken = 0; 445 static int expect = 0; 446 #endif 447 /* 448 * Receive a character from logical console. 449 */ 450 static void 451 rxcdintr(void *arg) 452 { 453 int c = mfpr(PR_RXCD); 454 455 if (c == 0) 456 return; 457 458 #if defined(MULTIPROCESSOR) 459 if (expect == ((c >> 8) & 0xf)) 460 rxbuf[got++] = c & 0xff; 461 462 if (got == RXBUF) 463 got = 0; 464 #endif 465 } 466 467 #if defined(MULTIPROCESSOR) 468 int 469 rxchar(void) 470 { 471 int ret; 472 473 if (got == taken) 474 return 0; 475 476 ret = rxbuf[taken++]; 477 if (taken == RXBUF) 478 taken = 0; 479 return ret; 480 } 481 #endif 482 483 int 484 ka820_gettime(volatile struct timeval *tvp) 485 { 486 struct clock_ymdhms c; 487 int s; 488 489 while (ka820_clkpage->csr0 & KA820CLK_0_BUSY) 490 ; 491 492 s = splhigh(); 493 c.dt_sec = ka820_clkpage->sec; 494 c.dt_min = ka820_clkpage->min; 495 c.dt_hour = ka820_clkpage->hr; 496 c.dt_wday = ka820_clkpage->dayofwk; 497 c.dt_day = ka820_clkpage->day; 498 c.dt_mon = ka820_clkpage->mon; 499 c.dt_year = ka820_clkpage->yr; 500 splx(s); 501 502 /* strange conversion */ 503 c.dt_sec = ((c.dt_sec << 7) | (c.dt_sec >> 1)) & 0377; 504 c.dt_min = ((c.dt_min << 7) | (c.dt_min >> 1)) & 0377; 505 c.dt_hour = ((c.dt_hour << 7) | (c.dt_hour >> 1)) & 0377; 506 c.dt_wday = ((c.dt_wday << 7) | (c.dt_wday >> 1)) & 0377; 507 c.dt_day = ((c.dt_day << 7) | (c.dt_day >> 1)) & 0377; 508 c.dt_mon = ((c.dt_mon << 7) | (c.dt_mon >> 1)) & 0377; 509 c.dt_year = ((c.dt_year << 7) | (c.dt_year >> 1)) & 0377; 510 511 tvp->tv_sec = clock_ymdhms_to_secs(&c); 512 return 0; 513 } 514 515 void 516 ka820_settime(volatile struct timeval *tvp) 517 { 518 struct clock_ymdhms c; 519 520 clock_secs_to_ymdhms(tvp->tv_sec, &c); 521 522 ka820_clkpage->csr1 = KA820CLK_1_SET; 523 ka820_clkpage->sec = ((c.dt_sec << 1) | (c.dt_sec >> 7)) & 0377; 524 ka820_clkpage->min = ((c.dt_min << 1) | (c.dt_min >> 7)) & 0377; 525 ka820_clkpage->hr = ((c.dt_hour << 1) | (c.dt_hour >> 7)) & 0377; 526 ka820_clkpage->dayofwk = ((c.dt_wday << 1) | (c.dt_wday >> 7)) & 0377; 527 ka820_clkpage->day = ((c.dt_day << 1) | (c.dt_day >> 7)) & 0377; 528 ka820_clkpage->mon = ((c.dt_mon << 1) | (c.dt_mon >> 7)) & 0377; 529 ka820_clkpage->yr = ((c.dt_year << 1) | (c.dt_year >> 7)) & 0377; 530 531 ka820_clkpage->csr1 = KA820CLK_1_GO; 532 } 533 534 #if defined(MULTIPROCESSOR) 535 static void 536 ka820_startslave(struct cpu_info *ci) 537 { 538 const int id = ci->ci_slotid; 539 int i; 540 541 expect = id; 542 /* First empty queue */ 543 for (i = 0; i < 10000; i++) 544 if (rxchar()) 545 i = 0; 546 ka820_txrx(id, "\020", 0); /* Send ^P to get attention */ 547 ka820_txrx(id, "I\r", 0); /* Init other end */ 548 ka820_txrx(id, "D/I 4 %x\r", ci->ci_istack); /* Interrupt stack */ 549 ka820_txrx(id, "D/I C %x\r", mfpr(PR_SBR)); /* SBR */ 550 ka820_txrx(id, "D/I D %x\r", mfpr(PR_SLR)); /* SLR */ 551 ka820_txrx(id, "D/I 10 %x\r", /* PCB for idle proc */ 552 ci->ci_data.cpu_onproc->l_addr->u_pcb.pcb_paddr); 553 ka820_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB)); /* SCB */ 554 ka820_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */ 555 ka820_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */ 556 expect = 0; 557 for (i = 0; i < 10000; i++) 558 if (ci->ci_flags & CI_RUNNING) 559 break; 560 if (i == 10000) 561 aprint_error_dev(ci->ci_dev, "(ID %d) failed starting??\n", id); 562 } 563 564 void 565 ka820_txrx(int id, const char *fmt, int arg) 566 { 567 char buf[20]; 568 569 sprintf(buf, fmt, arg); 570 ka820_sendstr(id, buf); 571 ka820_sergeant(id); 572 } 573 574 static void 575 ka820_sendchr(int chr) 576 { 577 /* 578 * It seems like mtpr to TXCD sets the V flag if it fails. 579 * Cannot check that flag in C... 580 */ 581 __asm volatile("1:;mtpr %0,$92;bvs 1b" :: "g"(chr)); 582 } 583 584 void 585 ka820_sendstr(int id, const char *buf) 586 { 587 u_int utchr; 588 int ch, i; 589 590 while (*buf) { 591 utchr = *buf | id << 8; 592 593 ka820_sendchr(utchr); 594 buf++; 595 i = 30000; 596 while ((ch = rxchar()) == 0 && --i) 597 ; 598 if (ch == 0) 599 continue; /* failed */ 600 } 601 } 602 603 void 604 ka820_sergeant(int id) 605 { 606 int i, ch, nserg; 607 608 nserg = 0; 609 for (i = 0; i < 30000; i++) { 610 if ((ch = rxchar()) == 0) 611 continue; 612 if (ch == '>') 613 nserg++; 614 else 615 nserg = 0; 616 i = 0; 617 if (nserg == 3) 618 break; 619 } 620 /* What to do now??? */ 621 } 622 623 /* 624 * Write to master console. 625 */ 626 static volatile int ch = 0; 627 628 void 629 ka820_putc(int c) 630 { 631 if (curcpu()->ci_flags & CI_MASTERCPU) { 632 gencnputc(0, c); 633 return; 634 } 635 ch = c; 636 637 cpu_send_ipi(IPI_DEST_MASTER, IPI_SEND_CNCHAR); 638 while (ch != 0) 639 ; /* Wait for master to handle */ 640 } 641 642 /* 643 * Got character IPI. 644 */ 645 void 646 ka820_cnintr(void) 647 { 648 if (ch != 0) 649 gencnputc(0, ch); 650 ch = 0; /* Release slavecpu */ 651 } 652 653 void 654 ka820_send_ipi(struct cpu_info *ci) 655 { 656 mtpr(1 << ci->ci_cpuid, PR_IPIR); 657 } 658 659 void 660 ka820_ipintr(void *arg) 661 { 662 cpu_handle_ipi(); 663 } 664 #endif 665