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