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