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