11.22Sthorpej/*	$NetBSD: ka88.c,v 1.22 2023/12/20 15:34:45 thorpej Exp $	*/
21.1Sragge
31.1Sragge/*
41.1Sragge * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
51.1Sragge *
61.1Sragge * Redistribution and use in source and binary forms, with or without
71.1Sragge * modification, are permitted provided that the following conditions
81.1Sragge * are met:
91.1Sragge * 1. Redistributions of source code must retain the above copyright
101.1Sragge *    notice, this list of conditions and the following disclaimer.
111.1Sragge * 2. Redistributions in binary form must reproduce the above copyright
121.1Sragge *    notice, this list of conditions and the following disclaimer in the
131.1Sragge *    documentation and/or other materials provided with the distribution.
141.1Sragge *
151.1Sragge * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
161.1Sragge * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
171.1Sragge * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
181.1Sragge * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
191.1Sragge * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201.1Sragge * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
211.1Sragge * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
221.1Sragge * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231.1Sragge * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
241.1Sragge * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251.1Sragge */
261.1Sragge
271.1Sragge/*
281.1Sragge * KA88 specific CPU code.
291.1Sragge */
301.1Sragge/*
311.1Sragge * TODO:
321.1Sragge *	- Machine check code
331.1Sragge */
341.6Slukem
351.6Slukem#include <sys/cdefs.h>
361.22Sthorpej__KERNEL_RCSID(0, "$NetBSD: ka88.c,v 1.22 2023/12/20 15:34:45 thorpej Exp $");
371.1Sragge
381.1Sragge#include "opt_multiprocessor.h"
391.1Sragge
401.1Sragge#include <sys/param.h>
411.1Sragge#include <sys/systm.h>
421.15Smatt#include <sys/bus.h>
431.13Smatt#include <sys/cpu.h>
441.15Smatt#include <sys/device.h>
451.15Smatt#include <sys/kernel.h>
461.13Smatt#include <sys/lwp.h>
471.1Sragge
481.1Sragge#include <machine/nexus.h>
491.1Sragge#include <machine/clock.h>
501.1Sragge#include <machine/scb.h>
511.1Sragge#include <machine/sid.h>
521.1Sragge#include <machine/rpb.h>
531.1Sragge#include <machine/ka88.h>
541.1Sragge
551.13Smatt#include <dev/cons.h>
561.1Sragge#include <vax/vax/gencons.h>
571.1Sragge
581.1Sragge#include "ioconf.h"
591.1Sragge#include "locators.h"
601.1Sragge
611.1Sraggestatic void ka88_memerr(void);
621.1Sraggestatic void ka88_conf(void);
631.11Schristosstatic int ka88_mchk(void *);
641.1Sraggestatic void ka88_steal_pages(void);
651.10Smattstatic int ka88_gettime(volatile struct timeval *);
661.10Smattstatic void ka88_settime(volatile struct timeval *);
671.1Sraggestatic void ka88_badaddr(void);
681.13Smatt
691.13Smattstatic long *ka88_mcl;
701.13Smattstatic int mastercpu;
711.13Smatt
721.13Smattstatic const char * const ka88_devs[] = { "nmi", NULL };
731.13Smatt
741.13Smattconst struct cpu_dep ka88_calls = {
751.13Smatt	.cpu_steal_pages = ka88_steal_pages,
761.13Smatt	.cpu_mchk	= ka88_mchk,
771.13Smatt	.cpu_memerr	= ka88_memerr,
781.13Smatt	.cpu_conf	= ka88_conf,
791.13Smatt	.cpu_gettime	= ka88_gettime,
801.13Smatt	.cpu_settime	= ka88_settime,
811.13Smatt	.cpu_vups	= 6,	/* ~VUPS */
821.13Smatt	.cpu_scbsz	= 64,	/* SCB pages */
831.13Smatt	.cpu_devs	= ka88_devs,
841.13Smatt	.cpu_badaddr	= ka88_badaddr,
851.13Smatt};
861.13Smatt
871.1Sragge#if defined(MULTIPROCESSOR)
881.13Smattstatic void ka88_startslave(struct cpu_info *);
891.18Schristosstatic void ka88_txrx(int, const char *, ...) __printflike(2, 3);
901.7Shestatic void ka88_sendstr(int, const char *);
911.1Sraggestatic void ka88_sergeant(int);
921.1Sraggestatic int rxchar(void);
931.1Sraggestatic void ka88_putc(int);
941.1Sraggestatic void ka88_cnintr(void);
951.1Sraggecons_decl(gen);
961.1Sragge
971.13Smattconst struct cpu_mp_dep ka88_mp_calls = {
981.13Smatt	.cpu_startslave = ka88_startslave,
991.13Smatt	.cpu_cnintr = ka88_cnintr,
1001.13Smatt};
1011.1Sragge#endif
1021.1Sragge
1031.1Sraggestatic void
1041.1Sraggeka88_conf(void)
1051.1Sragge{
1061.1Sragge	ka88_mcl = (void *)vax_map_physmem(0x3e000000, 1);
1071.1Sragge	printf("Serial number %d, rev %d\n",
1081.1Sragge	    mfpr(PR_SID) & 65535, (mfpr(PR_SID) >> 16) & 127);
1091.13Smatt#ifdef MULTIPROCESSOR
1101.13Smatt	mp_dep_call = &ka88_mp_calls;
1111.13Smatt#endif
1121.1Sragge}
1131.1Sragge
1141.1Sraggestatic int
1151.13Smattka88_cpu_match(device_t parent, cfdata_t cf, void *aux)
1161.1Sragge{
1171.13Smatt	struct nmi_attach_args * const na = aux;
1181.1Sragge
1191.1Sragge	if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
1201.13Smatt	    cf->cf_loc[NMICF_SLOT] != na->na_slot)
1211.1Sragge		return 0;
1221.13Smatt	if (na->na_slot >= 20)
1231.1Sragge		return 1;
1241.1Sragge	return 0;
1251.1Sragge}
1261.1Sragge
1271.1Sraggestatic void
1281.13Smattka88_cpu_attach(device_t parent, device_t self, void *aux)
1291.1Sragge{
1301.13Smatt	struct cpu_info *ci;
1311.13Smatt	struct nmi_attach_args * const na = aux;
1321.13Smatt	const char *ms, *lr;
1331.13Smatt	const bool master = (na->na_slot == mastercpu);
1341.1Sragge
1351.13Smatt	if (((ka88_confdata & KA88_LEFTPRIM) && master) ||
1361.13Smatt	    ((ka88_confdata & KA88_LEFTPRIM) == 0 && !master))
1371.1Sragge		lr = "left";
1381.1Sragge	else
1391.1Sragge		lr = "right";
1401.13Smatt	ms = (master ? "master" : "slave");
1411.1Sragge
1421.13Smatt	aprint_normal(": KA88 %s %s\n", lr, ms);
1431.13Smatt	if (!master) {
1441.1Sragge#if defined(MULTIPROCESSOR)
1451.1Sragge		v_putc = ka88_putc;	/* Need special console handling */
1461.13Smatt		cpu_slavesetup(self, na->na_slot);
1471.1Sragge#endif
1481.1Sragge		return;
1491.1Sragge	}
1501.13Smatt	ci = curcpu();
1511.21Sriastrad	device_set_private(self, ci);
1521.13Smatt	ci->ci_dev = self;
1531.13Smatt	ci->ci_cpuid = device_unit(self);
1541.13Smatt	ci->ci_slotid = na->na_slot;
1551.1Sragge}
1561.1Sragge
1571.13SmattCFATTACH_DECL_NEW(cpu_nmi, 0,
1581.13Smatt    ka88_cpu_match, ka88_cpu_attach, NULL, NULL);
1591.1Sragge
1601.1Sraggestruct mem_nmi_softc {
1611.16Smatt	device_t sc_dev;
1621.1Sragge	bus_space_tag_t sc_iot;
1631.1Sragge	bus_space_handle_t sc_ioh;
1641.1Sragge};
1651.1Sragge
1661.1Sraggestatic int
1671.13Smattms88_match(device_t parent, cfdata_t cf, void *aux)
1681.1Sragge{
1691.13Smatt	struct nmi_attach_args * const na = aux;
1701.1Sragge
1711.1Sragge	if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
1721.13Smatt	    cf->cf_loc[NMICF_SLOT] != na->na_slot)
1731.1Sragge		return 0;
1741.13Smatt	if (na->na_slot != 10)
1751.1Sragge		return 0;
1761.1Sragge	return 1;
1771.1Sragge}
1781.1Sragge
1791.1Sraggestatic void
1801.13Smattms88_attach(device_t parent, device_t self, void *aux)
1811.1Sragge{
1821.13Smatt	struct nmi_attach_args * const na = aux;
1831.13Smatt	struct mem_nmi_softc * const sc = device_private(self);
1841.13Smatt
1851.13Smatt	aprint_normal("\n");
1861.13Smatt
1871.13Smatt	sc->sc_dev = self;
1881.13Smatt	sc->sc_iot = na->na_iot;
1891.1Sragge}
1901.1Sragge
1911.13SmattCFATTACH_DECL_NEW(mem_nmi, sizeof(struct mem_nmi_softc),
1921.5Sthorpej    ms88_match, ms88_attach, NULL, NULL);
1931.1Sragge
1941.1Sraggestatic void
1951.1Sraggeka88_badaddr(void)
1961.1Sragge{
1971.1Sragge	volatile int hej;
1981.1Sragge	/*
1991.1Sragge	 * This is some magic to clear the NMI faults, described
2001.1Sragge	 * in section 7.9 in the VAX 8800 System Maintenance Guide.
2011.1Sragge	 */
2021.1Sragge	hej = ka88_mcl[5];
2031.1Sragge	hej = ka88_mcl[0];
2041.1Sragge	ka88_mcl[0] = 0x04000000;
2051.1Sragge	mtpr(1, 0x88);
2061.1Sragge}
2071.1Sragge
2081.1Sraggestatic void
2091.13Smattka88_memerr(void)
2101.1Sragge{
2111.1Sragge	printf("ka88_memerr\n");
2121.1Sragge}
2131.1Sragge
2141.1Sraggestruct mc88frame {
2151.1Sragge	int	mc64_summary;		/* summary parameter */
2161.1Sragge	int	mc64_va;		/* va register */
2171.1Sragge	int	mc64_vb;		/* memory address */
2181.1Sragge	int	mc64_sisr;		/* status word */
2191.1Sragge	int	mc64_state;		/* error pc */
2201.1Sragge	int	mc64_sc;		/* micro pc */
2211.1Sragge	int	mc64_pc;		/* current pc */
2221.1Sragge	int	mc64_psl;		/* current psl */
2231.1Sragge};
2241.1Sragge
2251.1Sraggestatic int
2261.11Schristoska88_mchk(void *cmcf)
2271.1Sragge{
2281.1Sragge	return (MCHK_PANIC);
2291.1Sragge}
2301.1Sragge
2311.1Sragge#if defined(MULTIPROCESSOR)
2321.1Sragge#define RXBUF	80
2331.1Sraggestatic char rxbuf[RXBUF];
2341.1Sraggestatic int got = 0, taken = 0;
2351.1Sraggestatic int expect = 0;
2361.1Sragge#endif
2371.1Sragge#if 0
2381.1Sragge/*
2391.1Sragge * Receive a character from logical console.
2401.1Sragge */
2411.1Sraggestatic void
2421.1Sraggerxcdintr(void *arg)
2431.1Sragge{
2441.1Sragge	int c = mfpr(PR_RXCD);
2451.1Sragge
2461.1Sragge	if (c == 0)
2471.1Sragge		return;
2481.1Sragge
2491.1Sragge#if defined(MULTIPROCESSOR)
2501.1Sragge	if ((c & 0xff) == 0) {
2511.1Sragge		if (curcpu()->ci_flags & CI_MASTERCPU)
2521.1Sragge			ka88_cnintr();
2531.1Sragge		return;
2541.1Sragge	}
2551.1Sragge
2561.1Sragge	if (expect == ((c >> 8) & 0xf))
2571.1Sragge		rxbuf[got++] = c & 0xff;
2581.1Sragge
2591.1Sragge	if (got == RXBUF)
2601.1Sragge		got = 0;
2611.1Sragge#endif
2621.1Sragge}
2631.1Sragge#endif
2641.1Sragge
2651.1Sraggestatic void
2661.1Sraggetocons(int val)
2671.1Sragge{
2681.2Sthorpej	int s = splhigh();
2691.1Sragge
2701.1Sragge	while ((mfpr(PR_TXCS) & GC_RDY) == 0)  /* Wait until xmit ready */
2711.1Sragge		;
2721.1Sragge	mtpr(val, PR_TXDB);		/* xmit character */
2731.1Sragge	splx(s);
2741.1Sragge}
2751.1Sragge
2761.1Sraggestatic int
2771.1Sraggefromcons(int func)
2781.1Sragge{
2791.2Sthorpej	int ret, s = splhigh();
2801.1Sragge
2811.1Sragge	while (1) {
2821.1Sragge		while ((mfpr(PR_RXCS) & GC_DON) == 0)
2831.1Sragge			;
2841.1Sragge		ret = mfpr(PR_RXDB);
2851.1Sragge		if ((ret & 0xf00) == func)
2861.1Sragge			break;
2871.1Sragge	}
2881.1Sragge	splx(s);
2891.1Sragge	return ret;
2901.1Sragge}
2911.1Sragge
2921.1Sraggestatic int
2931.10Smattka88_gettime(volatile struct timeval *tvp)
2941.1Sragge{
2951.1Sragge	union {u_int ret;u_char r[4];} u;
2961.2Sthorpej	int i, s = splhigh();
2971.1Sragge
2981.1Sragge	tocons(KA88_COMM|KA88_TOYREAD);
2991.1Sragge	for (i = 0; i < 4; i++) {
3001.1Sragge		u.r[i] = fromcons(KA88_TOY) & 255;
3011.1Sragge	}
3021.1Sragge	splx(s);
3031.10Smatt	tvp->tv_sec = u.ret;
3041.10Smatt	return 0;
3051.1Sragge}
3061.1Sragge
3071.1Sraggestatic void
3081.10Smattka88_settime(volatile struct timeval *tvp)
3091.1Sragge{
3101.1Sragge	union {u_int ret;u_char r[4];} u;
3111.2Sthorpej	int i, s = splhigh();
3121.1Sragge
3131.10Smatt	u.ret = tvp->tv_sec - yeartonum(numtoyear(tvp->tv_sec));
3141.1Sragge	tocons(KA88_COMM|KA88_TOYWRITE);
3151.1Sragge	for (i = 0; i < 4; i++)
3161.1Sragge		tocons(KA88_TOY|u.r[i]);
3171.1Sragge	splx(s);
3181.1Sragge}
3191.1Sragge
3201.1Sraggevoid
3211.1Sraggeka88_steal_pages(void)
3221.1Sragge{
3231.17Schristos	char c = '0', d = '0';
3241.1Sragge	mtpr(1, PR_COR); /* Cache on */
3251.1Sragge	tocons(KA88_COMM|KA88_GETCONF);
3261.1Sragge	ka88_confdata = fromcons(KA88_CONFDATA);
3271.1Sragge	ka88_confdata = mfpr(PR_RXDB);
3281.1Sragge	mastercpu = 20;
3291.1Sragge	if (vax_cputype == VAX_TYP_8NN) {
3301.1Sragge		if (ka88_confdata & KA88_SMALL) {
3311.17Schristos			c = '5';
3321.1Sragge			if (ka88_confdata & KA88_SLOW) {
3331.1Sragge				vax_boardtype = VAX_BTYP_8500;
3341.17Schristos				d = '3';
3351.1Sragge			} else {
3361.1Sragge				vax_boardtype = VAX_BTYP_8550;
3371.17Schristos				d = '5';
3381.1Sragge			}
3391.1Sragge		} else if (ka88_confdata & KA88_SINGLE) {
3401.1Sragge			vax_boardtype = VAX_BTYP_8700;
3411.17Schristos			c = '7';
3421.1Sragge		}
3431.1Sragge	}
3441.17Schristos	cpu_setmodel("VAX 88%c%c", c, d);
3451.1Sragge}
3461.1Sragge
3471.1Sragge
3481.13Smatt#if defined(MULTIPROCESSOR)
3491.1Sraggeint
3501.13Smattrxchar(void)
3511.1Sragge{
3521.1Sragge	int ret;
3531.1Sragge
3541.1Sragge	if (got == taken)
3551.1Sragge		return 0;
3561.1Sragge
3571.1Sragge	ret = rxbuf[taken++];
3581.1Sragge	if (taken == RXBUF)
3591.1Sragge		taken = 0;
3601.1Sragge	return ret;
3611.1Sragge}
3621.1Sragge
3631.1Sraggestatic void
3641.13Smattka88_startslave(struct cpu_info *ci)
3651.1Sragge{
3661.20Sad	const struct pcb *pcb = lwp_getpcb(ci->ci_onproc);
3671.13Smatt	const int id = ci->ci_slotid;
3681.1Sragge	int i;
3691.1Sragge
3701.13Smatt	expect = id;
3711.1Sragge	/* First empty queue */
3721.1Sragge	for (i = 0; i < 10000; i++)
3731.1Sragge		if (rxchar())
3741.1Sragge			i = 0;
3751.18Schristos	ka88_txrx(id, "\020");		/* Send ^P to get attention */
3761.18Schristos	ka88_txrx(id, "I\r");			/* Init other end */
3771.1Sragge	ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
3781.1Sragge	ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
3791.1Sragge	ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
3801.14Srmind	ka88_txrx(id, "D/I 10 %x\r", pcb->pcb_paddr);	/* PCB for idle proc */
3811.1Sragge	ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
3821.1Sragge	ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
3831.7She	ka88_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */
3841.1Sragge	expect = 0;
3851.1Sragge	for (i = 0; i < 10000; i++)
3861.13Smatt		if (ci->ci_flags & CI_RUNNING)
3871.1Sragge			break;
3881.1Sragge	if (i == 10000)
3891.13Smatt		aprint_error_dev(ci->ci_dev, "(ID %d) failed starting!!\n", id);
3901.1Sragge}
3911.1Sragge
3921.18Schristosstatic void
3931.18Schristoska88_txrx(int id, const char *fmt, ...)
3941.1Sragge{
3951.1Sragge	char buf[20];
3961.18Schristos	va_list ap;
3971.1Sragge
3981.18Schristos	va_start(ap, fmt);
3991.18Schristos	vsnprintf(buf, sizeof(buf), fmt, ap);
4001.18Schristos	va_end(ap);
4011.1Sragge	ka88_sendstr(id, buf);
4021.1Sragge	ka88_sergeant(id);
4031.1Sragge}
4041.1Sragge
4051.1Sraggevoid
4061.7Sheka88_sendstr(int id, const char *buf)
4071.1Sragge{
4081.13Smatt	u_int utchr; /* Ends up in R11 with PCC */
4091.1Sragge	int ch, i;
4101.1Sragge
4111.1Sragge	while (*buf) {
4121.1Sragge		utchr = *buf | id << 8;
4131.1Sragge
4141.1Sragge		/*
4151.1Sragge		 * It seems like mtpr to TXCD sets the V flag if it fails.
4161.1Sragge		 * Cannot check that flag in C...
4171.1Sragge		 */
4181.1Sragge#ifdef __GNUC__
4191.9Sperry		__asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
4201.1Sragge#else
4211.9Sperry		__asm("1:;mtpr r11,$92;bvs 1b");
4221.1Sragge#endif
4231.1Sragge		buf++;
4241.1Sragge		i = 30000;
4251.1Sragge		while ((ch = rxchar()) == 0 && --i)
4261.1Sragge			;
4271.1Sragge		if (ch == 0)
4281.1Sragge			continue; /* failed */
4291.1Sragge	}
4301.1Sragge}
4311.1Sragge
4321.1Sraggevoid
4331.1Sraggeka88_sergeant(int id)
4341.1Sragge{
4351.1Sragge	int i, ch, nserg;
4361.1Sragge
4371.1Sragge	nserg = 0;
4381.1Sragge	for (i = 0; i < 30000; i++) {
4391.1Sragge		if ((ch = rxchar()) == 0)
4401.1Sragge			continue;
4411.1Sragge		if (ch == '>')
4421.1Sragge			nserg++;
4431.1Sragge		else
4441.1Sragge			nserg = 0;
4451.1Sragge		i = 0;
4461.1Sragge		if (nserg == 3)
4471.1Sragge			break;
4481.1Sragge	}
4491.1Sragge	/* What to do now??? */
4501.1Sragge}
4511.1Sragge
4521.1Sragge/*
4531.1Sragge * Write to master console.
4541.1Sragge * Need no locking here; done in the print functions.
4551.1Sragge */
4561.1Sraggestatic volatile int ch = 0;
4571.1Sragge
4581.1Sraggevoid
4591.1Sraggeka88_putc(int c)
4601.1Sragge{
4611.1Sragge	if (curcpu()->ci_flags & CI_MASTERCPU) {
4621.1Sragge		gencnputc(0, c);
4631.1Sragge		return;
4641.1Sragge	}
4651.1Sragge	ch = c;
4661.1Sragge	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
4671.1Sragge	while (ch != 0)
4681.1Sragge		; /* Wait for master to handle */
4691.1Sragge}
4701.1Sragge
4711.1Sragge/*
4721.1Sragge * Got character IPI.
4731.1Sragge */
4741.1Sraggevoid
4751.13Smattka88_cnintr(void)
4761.1Sragge{
4771.1Sragge	if (ch != 0)
4781.1Sragge		gencnputc(0, ch);
4791.1Sragge	ch = 0; /* Release slavecpu */
4801.1Sragge}
4811.1Sragge#endif
482