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