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