Home | History | Annotate | Line # | Download | only in vax
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    439 ka6400_cnintr(void)
    440 {
    441 	if (ch != 0)
    442 		gencnputc(0, ch);
    443 	ch = 0; /* Release slavecpu */
    444 }
    445 #endif
    446