ka88.c revision 1.14
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
72static void ka88_memerr(void);
73static void ka88_conf(void);
74static int ka88_mchk(void *);
75static void ka88_steal_pages(void);
76static int ka88_gettime(volatile struct timeval *);
77static void ka88_settime(volatile struct timeval *);
78static void ka88_badaddr(void);
79
80static long *ka88_mcl;
81static int mastercpu;
82
83static const char * const ka88_devs[] = { "nmi", NULL };
84
85const 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)
99static void ka88_startslave(struct cpu_info *);
100static void ka88_txrx(int, const char *, int);
101static void ka88_sendstr(int, const char *);
102static void ka88_sergeant(int);
103static int rxchar(void);
104static void ka88_putc(int);
105static void ka88_cnintr(void);
106cons_decl(gen);
107
108const struct cpu_mp_dep ka88_mp_calls = {
109	.cpu_startslave = ka88_startslave,
110	.cpu_cnintr = ka88_cnintr,
111};
112#endif
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#ifdef MULTIPROCESSOR
121	mp_dep_call = &ka88_mp_calls;
122#endif
123}
124
125static int
126ka88_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
138static void
139ka88_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
168CFATTACH_DECL_NEW(cpu_nmi, 0,
169    ka88_cpu_match, ka88_cpu_attach, NULL, NULL);
170
171struct mem_nmi_softc {
172	struct device *sc_dev;
173	bus_space_tag_t sc_iot;
174	bus_space_handle_t sc_ioh;
175};
176
177static int
178ms88_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
190static void
191ms88_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
202CFATTACH_DECL_NEW(mem_nmi, sizeof(struct mem_nmi_softc),
203    ms88_match, ms88_attach, NULL, NULL);
204
205static void
206ka88_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
219static void
220ka88_memerr(void)
221{
222	printf("ka88_memerr\n");
223}
224
225struct 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
236static int
237ka88_mchk(void *cmcf)
238{
239	return (MCHK_PANIC);
240}
241
242#if defined(MULTIPROCESSOR)
243#define RXBUF	80
244static char rxbuf[RXBUF];
245static int got = 0, taken = 0;
246static int expect = 0;
247#endif
248#if 0
249/*
250 * Receive a character from logical console.
251 */
252static void
253rxcdintr(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
276static void
277tocons(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
287static int
288fromcons(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
303static int
304ka88_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
318static void
319ka88_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
331void
332ka88_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)
359int
360rxchar(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
373static void
374ka88_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
402void
403ka88_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
412void
413ka88_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
439void
440ka88_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 */
463static volatile int ch = 0;
464
465void
466ka88_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 */
481void
482ka88_cnintr(void)
483{
484	if (ch != 0)
485		gencnputc(0, ch);
486	ch = 0; /* Release slavecpu */
487}
488#endif
489