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