1 /* $NetBSD: ka88.c,v 1.22 2023/12/20 15:34:45 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*
28 * KA88 specific CPU code.
29 */
30 /*
31 * TODO:
32 * - Machine check code
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: ka88.c,v 1.22 2023/12/20 15:34:45 thorpej Exp $");
37
38 #include "opt_multiprocessor.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/bus.h>
43 #include <sys/cpu.h>
44 #include <sys/device.h>
45 #include <sys/kernel.h>
46 #include <sys/lwp.h>
47
48 #include <machine/nexus.h>
49 #include <machine/clock.h>
50 #include <machine/scb.h>
51 #include <machine/sid.h>
52 #include <machine/rpb.h>
53 #include <machine/ka88.h>
54
55 #include <dev/cons.h>
56 #include <vax/vax/gencons.h>
57
58 #include "ioconf.h"
59 #include "locators.h"
60
61 static void ka88_memerr(void);
62 static void ka88_conf(void);
63 static int ka88_mchk(void *);
64 static void ka88_steal_pages(void);
65 static int ka88_gettime(volatile struct timeval *);
66 static void ka88_settime(volatile struct timeval *);
67 static void ka88_badaddr(void);
68
69 static long *ka88_mcl;
70 static int mastercpu;
71
72 static const char * const ka88_devs[] = { "nmi", NULL };
73
74 const struct cpu_dep ka88_calls = {
75 .cpu_steal_pages = ka88_steal_pages,
76 .cpu_mchk = ka88_mchk,
77 .cpu_memerr = ka88_memerr,
78 .cpu_conf = ka88_conf,
79 .cpu_gettime = ka88_gettime,
80 .cpu_settime = ka88_settime,
81 .cpu_vups = 6, /* ~VUPS */
82 .cpu_scbsz = 64, /* SCB pages */
83 .cpu_devs = ka88_devs,
84 .cpu_badaddr = ka88_badaddr,
85 };
86
87 #if defined(MULTIPROCESSOR)
88 static void ka88_startslave(struct cpu_info *);
89 static void ka88_txrx(int, const char *, ...) __printflike(2, 3);
90 static void ka88_sendstr(int, const char *);
91 static void ka88_sergeant(int);
92 static int rxchar(void);
93 static void ka88_putc(int);
94 static void ka88_cnintr(void);
95 cons_decl(gen);
96
97 const struct cpu_mp_dep ka88_mp_calls = {
98 .cpu_startslave = ka88_startslave,
99 .cpu_cnintr = ka88_cnintr,
100 };
101 #endif
102
103 static void
ka88_conf(void)104 ka88_conf(void)
105 {
106 ka88_mcl = (void *)vax_map_physmem(0x3e000000, 1);
107 printf("Serial number %d, rev %d\n",
108 mfpr(PR_SID) & 65535, (mfpr(PR_SID) >> 16) & 127);
109 #ifdef MULTIPROCESSOR
110 mp_dep_call = &ka88_mp_calls;
111 #endif
112 }
113
114 static int
ka88_cpu_match(device_t parent,cfdata_t cf,void * aux)115 ka88_cpu_match(device_t parent, cfdata_t cf, void *aux)
116 {
117 struct nmi_attach_args * const na = aux;
118
119 if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
120 cf->cf_loc[NMICF_SLOT] != na->na_slot)
121 return 0;
122 if (na->na_slot >= 20)
123 return 1;
124 return 0;
125 }
126
127 static void
ka88_cpu_attach(device_t parent,device_t self,void * aux)128 ka88_cpu_attach(device_t parent, device_t self, void *aux)
129 {
130 struct cpu_info *ci;
131 struct nmi_attach_args * const na = aux;
132 const char *ms, *lr;
133 const bool master = (na->na_slot == mastercpu);
134
135 if (((ka88_confdata & KA88_LEFTPRIM) && master) ||
136 ((ka88_confdata & KA88_LEFTPRIM) == 0 && !master))
137 lr = "left";
138 else
139 lr = "right";
140 ms = (master ? "master" : "slave");
141
142 aprint_normal(": KA88 %s %s\n", lr, ms);
143 if (!master) {
144 #if defined(MULTIPROCESSOR)
145 v_putc = ka88_putc; /* Need special console handling */
146 cpu_slavesetup(self, na->na_slot);
147 #endif
148 return;
149 }
150 ci = curcpu();
151 device_set_private(self, ci);
152 ci->ci_dev = self;
153 ci->ci_cpuid = device_unit(self);
154 ci->ci_slotid = na->na_slot;
155 }
156
157 CFATTACH_DECL_NEW(cpu_nmi, 0,
158 ka88_cpu_match, ka88_cpu_attach, NULL, NULL);
159
160 struct mem_nmi_softc {
161 device_t sc_dev;
162 bus_space_tag_t sc_iot;
163 bus_space_handle_t sc_ioh;
164 };
165
166 static int
ms88_match(device_t parent,cfdata_t cf,void * aux)167 ms88_match(device_t parent, cfdata_t cf, void *aux)
168 {
169 struct nmi_attach_args * const na = aux;
170
171 if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
172 cf->cf_loc[NMICF_SLOT] != na->na_slot)
173 return 0;
174 if (na->na_slot != 10)
175 return 0;
176 return 1;
177 }
178
179 static void
ms88_attach(device_t parent,device_t self,void * aux)180 ms88_attach(device_t parent, device_t self, void *aux)
181 {
182 struct nmi_attach_args * const na = aux;
183 struct mem_nmi_softc * const sc = device_private(self);
184
185 aprint_normal("\n");
186
187 sc->sc_dev = self;
188 sc->sc_iot = na->na_iot;
189 }
190
191 CFATTACH_DECL_NEW(mem_nmi, sizeof(struct mem_nmi_softc),
192 ms88_match, ms88_attach, NULL, NULL);
193
194 static void
ka88_badaddr(void)195 ka88_badaddr(void)
196 {
197 volatile int hej;
198 /*
199 * This is some magic to clear the NMI faults, described
200 * in section 7.9 in the VAX 8800 System Maintenance Guide.
201 */
202 hej = ka88_mcl[5];
203 hej = ka88_mcl[0];
204 ka88_mcl[0] = 0x04000000;
205 mtpr(1, 0x88);
206 }
207
208 static void
ka88_memerr(void)209 ka88_memerr(void)
210 {
211 printf("ka88_memerr\n");
212 }
213
214 struct mc88frame {
215 int mc64_summary; /* summary parameter */
216 int mc64_va; /* va register */
217 int mc64_vb; /* memory address */
218 int mc64_sisr; /* status word */
219 int mc64_state; /* error pc */
220 int mc64_sc; /* micro pc */
221 int mc64_pc; /* current pc */
222 int mc64_psl; /* current psl */
223 };
224
225 static int
ka88_mchk(void * cmcf)226 ka88_mchk(void *cmcf)
227 {
228 return (MCHK_PANIC);
229 }
230
231 #if defined(MULTIPROCESSOR)
232 #define RXBUF 80
233 static char rxbuf[RXBUF];
234 static int got = 0, taken = 0;
235 static int expect = 0;
236 #endif
237 #if 0
238 /*
239 * Receive a character from logical console.
240 */
241 static void
242 rxcdintr(void *arg)
243 {
244 int c = mfpr(PR_RXCD);
245
246 if (c == 0)
247 return;
248
249 #if defined(MULTIPROCESSOR)
250 if ((c & 0xff) == 0) {
251 if (curcpu()->ci_flags & CI_MASTERCPU)
252 ka88_cnintr();
253 return;
254 }
255
256 if (expect == ((c >> 8) & 0xf))
257 rxbuf[got++] = c & 0xff;
258
259 if (got == RXBUF)
260 got = 0;
261 #endif
262 }
263 #endif
264
265 static void
tocons(int val)266 tocons(int val)
267 {
268 int s = splhigh();
269
270 while ((mfpr(PR_TXCS) & GC_RDY) == 0) /* Wait until xmit ready */
271 ;
272 mtpr(val, PR_TXDB); /* xmit character */
273 splx(s);
274 }
275
276 static int
fromcons(int func)277 fromcons(int func)
278 {
279 int ret, s = splhigh();
280
281 while (1) {
282 while ((mfpr(PR_RXCS) & GC_DON) == 0)
283 ;
284 ret = mfpr(PR_RXDB);
285 if ((ret & 0xf00) == func)
286 break;
287 }
288 splx(s);
289 return ret;
290 }
291
292 static int
ka88_gettime(volatile struct timeval * tvp)293 ka88_gettime(volatile struct timeval *tvp)
294 {
295 union {u_int ret;u_char r[4];} u;
296 int i, s = splhigh();
297
298 tocons(KA88_COMM|KA88_TOYREAD);
299 for (i = 0; i < 4; i++) {
300 u.r[i] = fromcons(KA88_TOY) & 255;
301 }
302 splx(s);
303 tvp->tv_sec = u.ret;
304 return 0;
305 }
306
307 static void
ka88_settime(volatile struct timeval * tvp)308 ka88_settime(volatile struct timeval *tvp)
309 {
310 union {u_int ret;u_char r[4];} u;
311 int i, s = splhigh();
312
313 u.ret = tvp->tv_sec - yeartonum(numtoyear(tvp->tv_sec));
314 tocons(KA88_COMM|KA88_TOYWRITE);
315 for (i = 0; i < 4; i++)
316 tocons(KA88_TOY|u.r[i]);
317 splx(s);
318 }
319
320 void
ka88_steal_pages(void)321 ka88_steal_pages(void)
322 {
323 char c = '0', d = '0';
324 mtpr(1, PR_COR); /* Cache on */
325 tocons(KA88_COMM|KA88_GETCONF);
326 ka88_confdata = fromcons(KA88_CONFDATA);
327 ka88_confdata = mfpr(PR_RXDB);
328 mastercpu = 20;
329 if (vax_cputype == VAX_TYP_8NN) {
330 if (ka88_confdata & KA88_SMALL) {
331 c = '5';
332 if (ka88_confdata & KA88_SLOW) {
333 vax_boardtype = VAX_BTYP_8500;
334 d = '3';
335 } else {
336 vax_boardtype = VAX_BTYP_8550;
337 d = '5';
338 }
339 } else if (ka88_confdata & KA88_SINGLE) {
340 vax_boardtype = VAX_BTYP_8700;
341 c = '7';
342 }
343 }
344 cpu_setmodel("VAX 88%c%c", c, d);
345 }
346
347
348 #if defined(MULTIPROCESSOR)
349 int
rxchar(void)350 rxchar(void)
351 {
352 int ret;
353
354 if (got == taken)
355 return 0;
356
357 ret = rxbuf[taken++];
358 if (taken == RXBUF)
359 taken = 0;
360 return ret;
361 }
362
363 static void
ka88_startslave(struct cpu_info * ci)364 ka88_startslave(struct cpu_info *ci)
365 {
366 const struct pcb *pcb = lwp_getpcb(ci->ci_onproc);
367 const int id = ci->ci_slotid;
368 int i;
369
370 expect = id;
371 /* First empty queue */
372 for (i = 0; i < 10000; i++)
373 if (rxchar())
374 i = 0;
375 ka88_txrx(id, "\020"); /* Send ^P to get attention */
376 ka88_txrx(id, "I\r"); /* Init other end */
377 ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack); /* Interrupt stack */
378 ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR)); /* SBR */
379 ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR)); /* SLR */
380 ka88_txrx(id, "D/I 10 %x\r", pcb->pcb_paddr); /* PCB for idle proc */
381 ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB)); /* SCB */
382 ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
383 ka88_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */
384 expect = 0;
385 for (i = 0; i < 10000; i++)
386 if (ci->ci_flags & CI_RUNNING)
387 break;
388 if (i == 10000)
389 aprint_error_dev(ci->ci_dev, "(ID %d) failed starting!!\n", id);
390 }
391
392 static void
ka88_txrx(int id,const char * fmt,...)393 ka88_txrx(int id, const char *fmt, ...)
394 {
395 char buf[20];
396 va_list ap;
397
398 va_start(ap, fmt);
399 vsnprintf(buf, sizeof(buf), fmt, ap);
400 va_end(ap);
401 ka88_sendstr(id, buf);
402 ka88_sergeant(id);
403 }
404
405 void
ka88_sendstr(int id,const char * buf)406 ka88_sendstr(int id, const char *buf)
407 {
408 u_int utchr; /* Ends up in R11 with PCC */
409 int ch, i;
410
411 while (*buf) {
412 utchr = *buf | id << 8;
413
414 /*
415 * It seems like mtpr to TXCD sets the V flag if it fails.
416 * Cannot check that flag in C...
417 */
418 #ifdef __GNUC__
419 __asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
420 #else
421 __asm("1:;mtpr r11,$92;bvs 1b");
422 #endif
423 buf++;
424 i = 30000;
425 while ((ch = rxchar()) == 0 && --i)
426 ;
427 if (ch == 0)
428 continue; /* failed */
429 }
430 }
431
432 void
ka88_sergeant(int id)433 ka88_sergeant(int id)
434 {
435 int i, ch, nserg;
436
437 nserg = 0;
438 for (i = 0; i < 30000; i++) {
439 if ((ch = rxchar()) == 0)
440 continue;
441 if (ch == '>')
442 nserg++;
443 else
444 nserg = 0;
445 i = 0;
446 if (nserg == 3)
447 break;
448 }
449 /* What to do now??? */
450 }
451
452 /*
453 * Write to master console.
454 * Need no locking here; done in the print functions.
455 */
456 static volatile int ch = 0;
457
458 void
ka88_putc(int c)459 ka88_putc(int c)
460 {
461 if (curcpu()->ci_flags & CI_MASTERCPU) {
462 gencnputc(0, c);
463 return;
464 }
465 ch = c;
466 mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
467 while (ch != 0)
468 ; /* Wait for master to handle */
469 }
470
471 /*
472 * Got character IPI.
473 */
474 void
ka88_cnintr(void)475 ka88_cnintr(void)
476 {
477 if (ch != 0)
478 gencnputc(0, ch);
479 ch = 0; /* Release slavecpu */
480 }
481 #endif
482