ka88.c revision 1.17
1/*	$NetBSD: ka88.c,v 1.17 2014/03/24 20:06:33 christos 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.17 2014/03/24 20:06:33 christos 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
68static void ka88_memerr(void);
69static void ka88_conf(void);
70static int ka88_mchk(void *);
71static void ka88_steal_pages(void);
72static int ka88_gettime(volatile struct timeval *);
73static void ka88_settime(volatile struct timeval *);
74static void ka88_badaddr(void);
75
76static long *ka88_mcl;
77static int mastercpu;
78
79static const char * const ka88_devs[] = { "nmi", NULL };
80
81const 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)
95static void ka88_startslave(struct cpu_info *);
96static void ka88_txrx(int, const char *, int);
97static void ka88_sendstr(int, const char *);
98static void ka88_sergeant(int);
99static int rxchar(void);
100static void ka88_putc(int);
101static void ka88_cnintr(void);
102cons_decl(gen);
103
104const struct cpu_mp_dep ka88_mp_calls = {
105	.cpu_startslave = ka88_startslave,
106	.cpu_cnintr = ka88_cnintr,
107};
108#endif
109
110static void
111ka88_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
121static int
122ka88_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
134static void
135ka88_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
164CFATTACH_DECL_NEW(cpu_nmi, 0,
165    ka88_cpu_match, ka88_cpu_attach, NULL, NULL);
166
167struct mem_nmi_softc {
168	device_t sc_dev;
169	bus_space_tag_t sc_iot;
170	bus_space_handle_t sc_ioh;
171};
172
173static int
174ms88_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
186static void
187ms88_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
198CFATTACH_DECL_NEW(mem_nmi, sizeof(struct mem_nmi_softc),
199    ms88_match, ms88_attach, NULL, NULL);
200
201static void
202ka88_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
215static void
216ka88_memerr(void)
217{
218	printf("ka88_memerr\n");
219}
220
221struct 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
232static int
233ka88_mchk(void *cmcf)
234{
235	return (MCHK_PANIC);
236}
237
238#if defined(MULTIPROCESSOR)
239#define RXBUF	80
240static char rxbuf[RXBUF];
241static int got = 0, taken = 0;
242static int expect = 0;
243#endif
244#if 0
245/*
246 * Receive a character from logical console.
247 */
248static void
249rxcdintr(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
272static void
273tocons(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
283static int
284fromcons(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
299static int
300ka88_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
314static void
315ka88_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
327void
328ka88_steal_pages(void)
329{
330	char c = '0', d = '0';
331	mtpr(1, PR_COR); /* Cache on */
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			c = '5';
339			if (ka88_confdata & KA88_SLOW) {
340				vax_boardtype = VAX_BTYP_8500;
341				d = '3';
342			} else {
343				vax_boardtype = VAX_BTYP_8550;
344				d = '5';
345			}
346		} else if (ka88_confdata & KA88_SINGLE) {
347			vax_boardtype = VAX_BTYP_8700;
348			c = '7';
349		}
350	}
351	cpu_setmodel("VAX 88%c%c", c, d);
352}
353
354
355#if defined(MULTIPROCESSOR)
356int
357rxchar(void)
358{
359	int ret;
360
361	if (got == taken)
362		return 0;
363
364	ret = rxbuf[taken++];
365	if (taken == RXBUF)
366		taken = 0;
367	return ret;
368}
369
370static void
371ka88_startslave(struct cpu_info *ci)
372{
373	const struct pcb *pcb = lwp_getpcb(ci->ci_data.cpu_onproc);
374	const int id = ci->ci_slotid;
375	int i;
376
377	expect = id;
378	/* First empty queue */
379	for (i = 0; i < 10000; i++)
380		if (rxchar())
381			i = 0;
382	ka88_txrx(id, "\020", 0);		/* Send ^P to get attention */
383	ka88_txrx(id, "I\r", 0);			/* Init other end */
384	ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
385	ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
386	ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
387	ka88_txrx(id, "D/I 10 %x\r", pcb->pcb_paddr);	/* PCB for idle proc */
388	ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
389	ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
390	ka88_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */
391	expect = 0;
392	for (i = 0; i < 10000; i++)
393		if (ci->ci_flags & CI_RUNNING)
394			break;
395	if (i == 10000)
396		aprint_error_dev(ci->ci_dev, "(ID %d) failed starting!!\n", id);
397}
398
399void
400ka88_txrx(int id, const char *fmt, int arg)
401{
402	char buf[20];
403
404	sprintf(buf, fmt, arg);
405	ka88_sendstr(id, buf);
406	ka88_sergeant(id);
407}
408
409void
410ka88_sendstr(int id, const char *buf)
411{
412	u_int utchr; /* Ends up in R11 with PCC */
413	int ch, i;
414
415	while (*buf) {
416		utchr = *buf | id << 8;
417
418		/*
419		 * It seems like mtpr to TXCD sets the V flag if it fails.
420		 * Cannot check that flag in C...
421		 */
422#ifdef __GNUC__
423		__asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
424#else
425		__asm("1:;mtpr r11,$92;bvs 1b");
426#endif
427		buf++;
428		i = 30000;
429		while ((ch = rxchar()) == 0 && --i)
430			;
431		if (ch == 0)
432			continue; /* failed */
433	}
434}
435
436void
437ka88_sergeant(int id)
438{
439	int i, ch, nserg;
440
441	nserg = 0;
442	for (i = 0; i < 30000; i++) {
443		if ((ch = rxchar()) == 0)
444			continue;
445		if (ch == '>')
446			nserg++;
447		else
448			nserg = 0;
449		i = 0;
450		if (nserg == 3)
451			break;
452	}
453	/* What to do now??? */
454}
455
456/*
457 * Write to master console.
458 * Need no locking here; done in the print functions.
459 */
460static volatile int ch = 0;
461
462void
463ka88_putc(int c)
464{
465	if (curcpu()->ci_flags & CI_MASTERCPU) {
466		gencnputc(0, c);
467		return;
468	}
469	ch = c;
470	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
471	while (ch != 0)
472		; /* Wait for master to handle */
473}
474
475/*
476 * Got character IPI.
477 */
478void
479ka88_cnintr(void)
480{
481	if (ch != 0)
482		gencnputc(0, ch);
483	ch = 0; /* Release slavecpu */
484}
485#endif
486