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