xref: /netbsd-src/sys/arch/vax/vax/ka6400.c (revision da6ca23dfa92a09166f4655333ea6380b9b82691)
1 /*	$NetBSD: ka6400.c,v 1.21 2022/03/03 06:28:26 riastradh 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  * KA6400 specific CPU code.
29  */
30 /*
31  * TODO:
32  *	- Machine check code
33  *	- Vector processor code
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ka6400.c,v 1.21 2022/03/03 06:28:26 riastradh Exp $");
38 
39 #include "opt_multiprocessor.h"
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/bus.h>
44 #include <sys/cpu.h>
45 #include <sys/device.h>
46 #include <sys/kernel.h>
47 #include <sys/time.h>
48 
49 #include <machine/ka670.h>
50 #include <machine/nexus.h>
51 #include <machine/clock.h>
52 #include <machine/scb.h>
53 #include <machine/sid.h>
54 #include <machine/cca.h>
55 #include <machine/rpb.h>
56 
57 #include <dev/xmi/xmireg.h>
58 #include <dev/xmi/xmivar.h>
59 
60 #include "ioconf.h"
61 #include "locators.h"
62 
63 static int *rssc;
64 struct cca *cca;
65 int mastercpu;
66 
67 static int ka6400_match(device_t , cfdata_t, void *);
68 static void ka6400_attach(device_t , device_t , void*);
69 static void ka6400_memerr(void);
70 static void ka6400_conf(void);
71 static int ka6400_mchk(void *);
72 static void ka6400_steal_pages(void);
73 
74 static const char * const ka6400_devs[] = { "xmi", NULL };
75 
76 const struct cpu_dep ka6400_calls = {
77 	.cpu_steal_pages = ka6400_steal_pages,
78 	.cpu_mchk	= ka6400_mchk,
79 	.cpu_memerr	= ka6400_memerr,
80 	.cpu_conf	= ka6400_conf,
81 	.cpu_gettime	= generic_gettime,
82 	.cpu_settime	= generic_settime,
83 	.cpu_vups	= 12,	/* ~VUPS */
84 	.cpu_scbsz	= 16,	/* SCB pages */
85 };
86 
87 #if defined(MULTIPROCESSOR)
88 static void ka6400_startslave(struct cpu_info *);
89 static void ka6400_txrx(int, const char *, ...) __printflike(2, 3);
90 static void ka6400_sendstr(int, const char *);
91 static void ka6400_sergeant(int);
92 static int rxchar(void);
93 static void ka6400_putc(int);
94 static void ka6400_cnintr(void);
95 
96 #include <dev/cons.h>
97 #include <vax/vax/gencons.h>
98 cons_decl(gen);
99 
100 const struct cpu_mp_dep ka6400_mp_calls = {
101 	.cpu_startslave	= ka6400_startslave,
102 	.cpu_cnintr	= ka6400_cnintr,
103 };
104 #endif
105 
106 CFATTACH_DECL_NEW(cpu_xmi, 0,
107     ka6400_match, ka6400_attach, NULL, NULL);
108 
109 static int
ka6400_match(device_t parent,cfdata_t cf,void * aux)110 ka6400_match(device_t parent, cfdata_t cf, void *aux)
111 {
112 	struct xmi_attach_args * const xa = aux;
113 
114 	if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_KA64)
115 		return 0;
116 
117 	if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT &&
118 	    cf->cf_loc[XMICF_NODE] != xa->xa_nodenr)
119 		return 0;
120 
121 	return 1;
122 }
123 
124 static void
ka6400_attach(device_t parent,device_t self,void * aux)125 ka6400_attach(device_t parent, device_t self, void *aux)
126 {
127 	struct cpu_info *ci;
128 	struct xmi_attach_args * const xa = aux;
129 	int vp;
130 
131 	vp = (cca->cca_vecenab & (1 << xa->xa_nodenr));
132 	aprint_normal("\n");
133 	aprint_normal_dev(self, "KA6400 (%s) rev %d%s\n",
134 	    mastercpu == xa->xa_nodenr ? "master" : "slave",
135 	    bus_space_read_4(xa->xa_iot, xa->xa_ioh, XMI_TYPE) >> 16,
136 	    (vp ? ", vector processor present" : ""));
137 
138 	if (xa->xa_nodenr != mastercpu) {
139 #if defined(MULTIPROCESSOR)
140 		v_putc = ka6400_putc;	/* Need special console handling */
141 		cpu_slavesetup(self, xa->xa_nodenr);
142 #endif
143 		return;
144 	}
145 
146 	mtpr(0, PR_VPSR); /* Can't use vector processor */
147 
148 	ci = curcpu();
149 	device_set_private(self, ci);
150 	ci->ci_dev = self;
151 	ci->ci_cpuid = device_unit(self);
152 	ci->ci_slotid = xa->xa_nodenr;
153 }
154 
155 void
ka6400_conf(void)156 ka6400_conf(void)
157 {
158 	int mapaddr;
159 
160 	rssc = (void *)vax_map_physmem(RSSC_ADDR, 1);
161 	mastercpu = rssc[RSSC_IPORT/4] & 15;
162 	mapaddr = (cca ? (int)cca : rpb.cca_addr);
163 	cca = (void *)vax_map_physmem(mapaddr, vax_btoc(sizeof(struct cca)));
164 }
165 
166 /*
167  * MS62 support.
168  * This code should:
169  *	1: Be completed.
170  *	2: (eventually) move to dev/xmi/; it is used by Mips also.
171  */
172 #define MEMRD(reg) bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
173 #define MEMWR(reg, val) bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
174 
175 #define MS62_TYPE	0
176 #define MS62_XBE	4
177 #define MS62_SEADR	16
178 #define	MS62_CTL1	20
179 #define MS62_ECCERR	24
180 #define MS62_ECCEA	28
181 #define MS62_ILK0	32
182 #define MS62_ILK1	36
183 #define MS62_ILK2	40
184 #define MS62_ILK3	44
185 #define MS62_CTL2	48
186 
187 static int ms6400_match(device_t , cfdata_t, void *);
188 static void ms6400_attach(device_t , device_t , void*);
189 
190 struct mem_xmi_softc {
191 	device_t sc_dev;
192 	bus_space_tag_t sc_iot;
193 	bus_space_handle_t sc_ioh;
194 };
195 
196 CFATTACH_DECL_NEW(mem_xmi, sizeof(struct mem_xmi_softc),
197     ms6400_match, ms6400_attach, NULL, NULL);
198 
199 static int
ms6400_match(device_t parent,cfdata_t cf,void * aux)200 ms6400_match(device_t parent, cfdata_t cf, void *aux)
201 {
202 	struct xmi_attach_args * const xa = aux;
203 
204 	if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_MS62)
205 		return 0;
206 
207 	if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT &&
208 	    cf->cf_loc[XMICF_NODE] != xa->xa_nodenr)
209 		return 0;
210 
211 	return 1;
212 }
213 
214 static void
ms6400_attach(device_t parent,device_t self,void * aux)215 ms6400_attach(device_t parent, device_t self, void *aux)
216 {
217 	struct mem_xmi_softc * const sc = device_private(self);
218 	struct xmi_attach_args * const xa = aux;
219 
220 	sc->sc_dev = self;
221 	sc->sc_iot = xa->xa_iot;
222 	sc->sc_ioh = xa->xa_ioh;
223 	aprint_normal(": MS62, rev %d, size 32MB\n", MEMRD(MS62_TYPE) >> 16);
224 }
225 
226 static void
ka6400_memerr(void)227 ka6400_memerr(void)
228 {
229 	printf("ka6400_memerr\n");
230 }
231 
232 struct mc6400frame {
233 	int	mc64_summary;		/* summary parameter */
234 	int	mc64_va;		/* va register */
235 	int	mc64_vb;		/* memory address */
236 	int	mc64_sisr;		/* status word */
237 	int	mc64_state;		/* error pc */
238 	int	mc64_sc;		/* micro pc */
239 	int	mc64_pc;		/* current pc */
240 	int	mc64_psl;		/* current psl */
241 };
242 
243 static int
ka6400_mchk(void * cmcf)244 ka6400_mchk(void *cmcf)
245 {
246 	return (MCHK_PANIC);
247 }
248 
249 #if defined(MULTIPROCESSOR)
250 #define RXBUF	80
251 static char rxbuf[RXBUF];
252 static int got = 0, taken = 0;
253 static int expect = 0;
254 #endif
255 #if 0
256 /*
257  * Receive a character from logical console.
258  */
259 static void
260 rxcdintr(void *arg)
261 {
262 	int c = mfpr(PR_RXCD);
263 
264 	if (c == 0)
265 		return;
266 
267 #if defined(MULTIPROCESSOR)
268 	if ((c & 0xff) == 0) {
269 		if (curcpu()->ci_flags & CI_MASTERCPU)
270 			ka6400_cnintr();
271 		return;
272 	}
273 
274 	if (expect == ((c >> 8) & 0xf))
275 		rxbuf[got++] = c & 0xff;
276 
277 	if (got == RXBUF)
278 		got = 0;
279 #endif
280 }
281 #endif
282 
283 /*
284  * From ka670, which has the same cache structure.
285  */
286 static void
ka6400_enable_cache(void)287 ka6400_enable_cache(void)
288 {
289 	mtpr(KA670_PCS_REFRESH, PR_PCSTS);	/* disable primary cache */
290 	mtpr(mfpr(PR_PCSTS), PR_PCSTS);		/* clear error flags */
291 	mtpr(8, PR_BCCTL);			/* disable backup cache */
292 	mtpr(0, PR_BCFBTS);	/* flush backup cache tag store */
293 	mtpr(0, PR_BCFPTS);	/* flush primary cache tag store */
294 	mtpr(0x0e, PR_BCCTL);	/* enable backup cache */
295 	mtpr(KA670_PCS_FLUSH | KA670_PCS_REFRESH, PR_PCSTS);	/* flush primary cache */
296 	mtpr(KA670_PCS_ENABLE | KA670_PCS_REFRESH, PR_PCSTS);	/* flush primary cache */
297 }
298 
299 void
ka6400_steal_pages(void)300 ka6400_steal_pages(void)
301 {
302 	int i, ncpus;
303 
304 	ka6400_enable_cache(); /* Turn on cache early */
305 	if (cca == 0)
306 		cca = (void *)rpb.cca_addr;
307 	/* Is there any way to get number of CPUs easier??? */
308 	for (i = ncpus = 0; i < cca->cca_maxcpu; i++)
309 		if (cca->cca_console & (1 << i))
310 			ncpus++;
311 	cpu_setmodel("VAX 6000/4%x0", ncpus + 1);
312 }
313 
314 
315 #if defined(MULTIPROCESSOR)
316 int
rxchar(void)317 rxchar(void)
318 {
319 	int ret;
320 
321 	if (got == taken)
322 		return 0;
323 
324 	ret = rxbuf[taken++];
325 	if (taken == RXBUF)
326 		taken = 0;
327 	return ret;
328 }
329 
330 static void
ka6400_startslave(struct cpu_info * ci)331 ka6400_startslave(struct cpu_info *ci)
332 {
333 	const struct pcb *pcb = lwp_getpcb(ci->ci_onproc);
334 	const int id = ci->ci_slotid;
335 	int i;
336 
337 	expect = id;
338 	/* First empty queue */
339 	for (i = 0; i < 10000; i++)
340 		if (rxchar())
341 			i = 0;
342 	ka6400_txrx(id, "\020");		/* Send ^P to get attention */
343 	ka6400_txrx(id, "I\r");			/* Init other end */
344 	ka6400_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
345 	ka6400_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
346 	ka6400_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
347 	ka6400_txrx(id, "D/I 10 %x\r", pcb->pcb_paddr);	/* PCB for idle proc */
348 	ka6400_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
349 	ka6400_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
350 	ka6400_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */
351 	expect = 0;
352 	for (i = 0; i < 10000; i++)
353 		if (ci->ci_flags & CI_RUNNING)
354 			break;
355 	if (i == 10000)
356 		aprint_error_dev(ci->ci_dev, "(ID %d) failed starting!\n", id);
357 }
358 
359 void
ka6400_txrx(int id,const char * fmt,...)360 ka6400_txrx(int id, const char *fmt, ...)
361 {
362 	char buf[20];
363 	va_list ap;
364 
365 	va_start(ap, fmt);
366 	vsnprintf(buf, sizeof(buf), fmt, ap);
367 	va_end(ap);
368 
369 	ka6400_sendstr(id, buf);
370 	ka6400_sergeant(id);
371 }
372 
373 void
ka6400_sendstr(int id,const char * buf)374 ka6400_sendstr(int id, const char *buf)
375 {
376 	u_int utchr;
377 	int ch, i;
378 
379 	while (*buf) {
380 		utchr = *buf | id << 8;
381 
382 		/*
383 		 * It seems like mtpr to TXCD sets the V flag if it fails.
384 		 * Cannot check that flag in C...
385 		 */
386 		__asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
387 		buf++;
388 		i = 30000;
389 		while ((ch = rxchar()) == 0 && --i)
390 			;
391 		if (ch == 0)
392 			continue; /* failed */
393 	}
394 }
395 
396 void
ka6400_sergeant(int id)397 ka6400_sergeant(int id)
398 {
399 	int i, ch, nserg;
400 
401 	nserg = 0;
402 	for (i = 0; i < 30000; i++) {
403 		if ((ch = rxchar()) == 0)
404 			continue;
405 		if (ch == '>')
406 			nserg++;
407 		else
408 			nserg = 0;
409 		i = 0;
410 		if (nserg == 3)
411 			break;
412 	}
413 	/* What to do now??? */
414 }
415 
416 /*
417  * Write to master console.
418  * Need no locking here; done in the print functions.
419  */
420 static volatile int ch = 0;
421 
422 void
ka6400_putc(int c)423 ka6400_putc(int c)
424 {
425 	if (curcpu()->ci_flags & CI_MASTERCPU) {
426 		gencnputc(0, c);
427 		return;
428 	}
429 	ch = c;
430 	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
431 	while (ch != 0)
432 		; /* Wait for master to handle */
433 }
434 
435 /*
436  * Got character IPI.
437  */
438 void
ka6400_cnintr(void)439 ka6400_cnintr(void)
440 {
441 	if (ch != 0)
442 		gencnputc(0, ch);
443 	ch = 0; /* Release slavecpu */
444 }
445 #endif
446