xref: /netbsd-src/sys/arch/vax/vax/ka820.c (revision f82d7874c259b2a6cc59b714f844919f32bf7b51)
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