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