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