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