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