ka88.c revision 1.6
11.6Slukem/*	$NetBSD: ka88.c,v 1.6 2003/07/15 02:15:04 lukem 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 * 3. All advertising materials mentioning features or use of this software
151.1Sragge *    must display the following acknowledgement:
161.1Sragge *	This product includes software developed at Ludd, University of
171.1Sragge *	Lule}, Sweden and its contributors.
181.1Sragge * 4. The name of the author may not be used to endorse or promote products
191.1Sragge *    derived from this software without specific prior written permission
201.1Sragge *
211.1Sragge * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
221.1Sragge * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
231.1Sragge * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
241.1Sragge * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
251.1Sragge * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
261.1Sragge * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
271.1Sragge * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
281.1Sragge * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
291.1Sragge * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
301.1Sragge * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
311.1Sragge */
321.1Sragge
331.1Sragge/*
341.1Sragge * KA88 specific CPU code.
351.1Sragge */
361.1Sragge/*
371.1Sragge * TODO:
381.1Sragge *	- Machine check code
391.1Sragge */
401.6Slukem
411.6Slukem#include <sys/cdefs.h>
421.6Slukem__KERNEL_RCSID(0, "$NetBSD: ka88.c,v 1.6 2003/07/15 02:15:04 lukem Exp $");
431.1Sragge
441.1Sragge#include "opt_multiprocessor.h"
451.1Sragge
461.1Sragge#include <sys/param.h>
471.1Sragge#include <sys/time.h>
481.1Sragge#include <sys/kernel.h>
491.1Sragge#include <sys/device.h>
501.1Sragge#include <sys/systm.h>
511.1Sragge#include <sys/conf.h>
521.1Sragge
531.1Sragge#include <machine/cpu.h>
541.1Sragge#include <machine/mtpr.h>
551.1Sragge#include <machine/nexus.h>
561.1Sragge#include <machine/clock.h>
571.1Sragge#include <machine/scb.h>
581.1Sragge#include <machine/bus.h>
591.1Sragge#include <machine/sid.h>
601.1Sragge#include <machine/rpb.h>
611.1Sragge#include <machine/ka88.h>
621.1Sragge
631.1Sragge#include <vax/vax/gencons.h>
641.1Sragge
651.1Sragge#include "ioconf.h"
661.1Sragge#include "locators.h"
671.1Sragge
681.1Sraggestatic void ka88_memerr(void);
691.1Sraggestatic void ka88_conf(void);
701.1Sraggestatic int ka88_mchk(caddr_t);
711.1Sraggestatic void ka88_steal_pages(void);
721.1Sraggestatic int ka88_clkread(time_t);
731.1Sraggestatic void ka88_clkwrite(void);
741.1Sraggestatic void ka88_badaddr(void);
751.1Sragge#if defined(MULTIPROCESSOR)
761.1Sraggestatic void ka88_startslave(struct device *, struct cpu_info *);
771.1Sraggestatic void ka88_txrx(int, char *, int);
781.1Sraggestatic void ka88_sendstr(int, char *);
791.1Sraggestatic void ka88_sergeant(int);
801.1Sraggestatic int rxchar(void);
811.1Sraggestatic void ka88_putc(int);
821.1Sraggestatic void ka88_cnintr(void);
831.1Sraggecons_decl(gen);
841.1Sragge#endif
851.1Sragge
861.1Sraggestatic	long *ka88_mcl;
871.1Sraggestatic int mastercpu;
881.1Sragge
891.1Sraggestruct	cpu_dep ka88_calls = {
901.1Sragge	ka88_steal_pages,
911.1Sragge	ka88_mchk,
921.1Sragge	ka88_memerr,
931.1Sragge	ka88_conf,
941.1Sragge	ka88_clkread,
951.1Sragge	ka88_clkwrite,
961.1Sragge	6,	/* ~VUPS */
971.1Sragge	64,	/* SCB pages */
981.1Sragge	0,
991.1Sragge	0,
1001.1Sragge	0,
1011.1Sragge	0,
1021.1Sragge	0,
1031.1Sragge#if defined(MULTIPROCESSOR)
1041.1Sragge	ka88_startslave,
1051.1Sragge#endif
1061.1Sragge	ka88_badaddr,
1071.1Sragge};
1081.1Sragge
1091.1Sraggestruct ka88_softc {
1101.1Sragge	struct device sc_dev;
1111.1Sragge	int sc_slot;
1121.1Sragge};
1131.1Sragge
1141.1Sraggestatic void
1151.1Sraggeka88_conf(void)
1161.1Sragge{
1171.1Sragge	ka88_mcl = (void *)vax_map_physmem(0x3e000000, 1);
1181.1Sragge	printf("Serial number %d, rev %d\n",
1191.1Sragge	    mfpr(PR_SID) & 65535, (mfpr(PR_SID) >> 16) & 127);
1201.1Sragge}
1211.1Sragge
1221.1Sraggestatic int
1231.1Sraggeka88_match(struct device *parent, struct cfdata *cf, void *aux)
1241.1Sragge{
1251.1Sragge	struct nmi_attach_args *na = aux;
1261.1Sragge
1271.1Sragge	if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
1281.1Sragge	    cf->cf_loc[NMICF_SLOT] != na->slot)
1291.1Sragge		return 0;
1301.1Sragge	if (na->slot >= 20)
1311.1Sragge		return 1;
1321.1Sragge	return 0;
1331.1Sragge}
1341.1Sragge
1351.1Sraggestatic void
1361.1Sraggeka88_attach(struct device *parent, struct device *self, void *aux)
1371.1Sragge{
1381.1Sragge	struct ka88_softc *sc = (void *)self;
1391.1Sragge	struct nmi_attach_args *na = aux;
1401.1Sragge	char *ms, *lr;
1411.1Sragge
1421.1Sragge	if (((ka88_confdata & KA88_LEFTPRIM) && (na->slot == 20)) ||
1431.1Sragge	    ((ka88_confdata & KA88_LEFTPRIM) == 0 && (na->slot != 20)))
1441.1Sragge		lr = "left";
1451.1Sragge	else
1461.1Sragge		lr = "right";
1471.1Sragge	ms = na->slot == 20 ? "master" : "slave";
1481.1Sragge
1491.1Sragge	printf(": ka88 (%s) (%s)\n", lr, ms);
1501.1Sragge	sc->sc_slot = na->slot;
1511.1Sragge	if (na->slot != mastercpu) {
1521.1Sragge#if defined(MULTIPROCESSOR)
1531.1Sragge		sc->sc_ci = cpu_slavesetup(self);
1541.1Sragge		v_putc = ka88_putc;	/* Need special console handling */
1551.1Sragge#endif
1561.1Sragge		return;
1571.1Sragge	}
1581.1Sragge	curcpu()->ci_dev = self;
1591.1Sragge}
1601.1Sragge
1611.4SthorpejCFATTACH_DECL(cpu_nmi, sizeof(struct ka88_softc),
1621.5Sthorpej    ka88_match, ka88_attach, NULL, NULL);
1631.1Sragge
1641.1Sraggestruct mem_nmi_softc {
1651.1Sragge	struct device sc_dev;
1661.1Sragge	bus_space_tag_t sc_iot;
1671.1Sragge	bus_space_handle_t sc_ioh;
1681.1Sragge};
1691.1Sragge
1701.1Sraggestatic int
1711.1Sraggems88_match(struct device *parent, struct cfdata *cf, void *aux)
1721.1Sragge{
1731.1Sragge	struct nmi_attach_args *na = aux;
1741.1Sragge
1751.1Sragge	if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
1761.1Sragge	    cf->cf_loc[NMICF_SLOT] != na->slot)
1771.1Sragge		return 0;
1781.1Sragge	if (na->slot != 10)
1791.1Sragge		return 0;
1801.1Sragge	return 1;
1811.1Sragge}
1821.1Sragge
1831.1Sraggestatic void
1841.1Sraggems88_attach(struct device *parent, struct device *self, void *aux)
1851.1Sragge{
1861.1Sragge	printf("\n");
1871.1Sragge}
1881.1Sragge
1891.4SthorpejCFATTACH_DECL(mem_nmi, sizeof(struct mem_nmi_softc),
1901.5Sthorpej    ms88_match, ms88_attach, NULL, NULL);
1911.1Sragge
1921.1Sraggestatic void
1931.1Sraggeka88_badaddr(void)
1941.1Sragge{
1951.1Sragge	volatile int hej;
1961.1Sragge	/*
1971.1Sragge	 * This is some magic to clear the NMI faults, described
1981.1Sragge	 * in section 7.9 in the VAX 8800 System Maintenance Guide.
1991.1Sragge	 */
2001.1Sragge	hej = ka88_mcl[5];
2011.1Sragge	hej = ka88_mcl[0];
2021.1Sragge	ka88_mcl[0] = 0x04000000;
2031.1Sragge	mtpr(1, 0x88);
2041.1Sragge}
2051.1Sragge
2061.1Sraggestatic void
2071.1Sraggeka88_memerr()
2081.1Sragge{
2091.1Sragge	printf("ka88_memerr\n");
2101.1Sragge}
2111.1Sragge
2121.1Sraggestruct mc88frame {
2131.1Sragge	int	mc64_summary;		/* summary parameter */
2141.1Sragge	int	mc64_va;		/* va register */
2151.1Sragge	int	mc64_vb;		/* memory address */
2161.1Sragge	int	mc64_sisr;		/* status word */
2171.1Sragge	int	mc64_state;		/* error pc */
2181.1Sragge	int	mc64_sc;		/* micro pc */
2191.1Sragge	int	mc64_pc;		/* current pc */
2201.1Sragge	int	mc64_psl;		/* current psl */
2211.1Sragge};
2221.1Sragge
2231.1Sraggestatic int
2241.1Sraggeka88_mchk(caddr_t cmcf)
2251.1Sragge{
2261.1Sragge	return (MCHK_PANIC);
2271.1Sragge}
2281.1Sragge
2291.1Sragge#if defined(MULTIPROCESSOR)
2301.1Sragge#define RXBUF	80
2311.1Sraggestatic char rxbuf[RXBUF];
2321.1Sraggestatic int got = 0, taken = 0;
2331.1Sraggestatic int expect = 0;
2341.1Sragge#endif
2351.1Sragge#if 0
2361.1Sragge/*
2371.1Sragge * Receive a character from logical console.
2381.1Sragge */
2391.1Sraggestatic void
2401.1Sraggerxcdintr(void *arg)
2411.1Sragge{
2421.1Sragge	int c = mfpr(PR_RXCD);
2431.1Sragge
2441.1Sragge	if (c == 0)
2451.1Sragge		return;
2461.1Sragge
2471.1Sragge#if defined(MULTIPROCESSOR)
2481.1Sragge	if ((c & 0xff) == 0) {
2491.1Sragge		if (curcpu()->ci_flags & CI_MASTERCPU)
2501.1Sragge			ka88_cnintr();
2511.1Sragge		return;
2521.1Sragge	}
2531.1Sragge
2541.1Sragge	if (expect == ((c >> 8) & 0xf))
2551.1Sragge		rxbuf[got++] = c & 0xff;
2561.1Sragge
2571.1Sragge	if (got == RXBUF)
2581.1Sragge		got = 0;
2591.1Sragge#endif
2601.1Sragge}
2611.1Sragge#endif
2621.1Sragge
2631.1Sraggestatic void
2641.1Sraggetocons(int val)
2651.1Sragge{
2661.2Sthorpej	int s = splhigh();
2671.1Sragge
2681.1Sragge	while ((mfpr(PR_TXCS) & GC_RDY) == 0)  /* Wait until xmit ready */
2691.1Sragge		;
2701.1Sragge	mtpr(val, PR_TXDB);		/* xmit character */
2711.1Sragge	splx(s);
2721.1Sragge}
2731.1Sragge
2741.1Sraggestatic int
2751.1Sraggefromcons(int func)
2761.1Sragge{
2771.2Sthorpej	int ret, s = splhigh();
2781.1Sragge
2791.1Sragge	while (1) {
2801.1Sragge		while ((mfpr(PR_RXCS) & GC_DON) == 0)
2811.1Sragge			;
2821.1Sragge		ret = mfpr(PR_RXDB);
2831.1Sragge		if ((ret & 0xf00) == func)
2841.1Sragge			break;
2851.1Sragge	}
2861.1Sragge	splx(s);
2871.1Sragge	return ret;
2881.1Sragge}
2891.1Sragge
2901.1Sraggestatic int
2911.1Sraggeka88_clkread(time_t base)
2921.1Sragge{
2931.1Sragge	union {u_int ret;u_char r[4];} u;
2941.2Sthorpej	int i, s = splhigh();
2951.1Sragge
2961.1Sragge	tocons(KA88_COMM|KA88_TOYREAD);
2971.1Sragge	for (i = 0; i < 4; i++) {
2981.1Sragge		u.r[i] = fromcons(KA88_TOY) & 255;
2991.1Sragge	}
3001.1Sragge	splx(s);
3011.1Sragge	return u.ret;
3021.1Sragge}
3031.1Sragge
3041.1Sraggestatic void
3051.1Sraggeka88_clkwrite(void)
3061.1Sragge{
3071.1Sragge	union {u_int ret;u_char r[4];} u;
3081.2Sthorpej	int i, s = splhigh();
3091.1Sragge
3101.1Sragge	u.ret = time.tv_sec - yeartonum(numtoyear(time.tv_sec));
3111.1Sragge	tocons(KA88_COMM|KA88_TOYWRITE);
3121.1Sragge	for (i = 0; i < 4; i++)
3131.1Sragge		tocons(KA88_TOY|u.r[i]);
3141.1Sragge	splx(s);
3151.1Sragge}
3161.1Sragge
3171.1Sraggevoid
3181.1Sraggeka88_steal_pages(void)
3191.1Sragge{
3201.1Sragge	mtpr(1, PR_COR); /* Cache on */
3211.1Sragge	strcpy(cpu_model, "VAX 8800");
3221.1Sragge	tocons(KA88_COMM|KA88_GETCONF);
3231.1Sragge	ka88_confdata = fromcons(KA88_CONFDATA);
3241.1Sragge	ka88_confdata = mfpr(PR_RXDB);
3251.1Sragge	mastercpu = 20;
3261.1Sragge	if (vax_cputype == VAX_TYP_8NN) {
3271.1Sragge		if (ka88_confdata & KA88_SMALL) {
3281.1Sragge			cpu_model[5] = '5';
3291.1Sragge			if (ka88_confdata & KA88_SLOW) {
3301.1Sragge				vax_boardtype = VAX_BTYP_8500;
3311.1Sragge				cpu_model[6] = '3';
3321.1Sragge			} else {
3331.1Sragge				vax_boardtype = VAX_BTYP_8550;
3341.1Sragge				cpu_model[6] = '5';
3351.1Sragge			}
3361.1Sragge		} else if (ka88_confdata & KA88_SINGLE) {
3371.1Sragge			vax_boardtype = VAX_BTYP_8700;
3381.1Sragge			cpu_model[5] = '7';
3391.1Sragge		}
3401.1Sragge	}
3411.1Sragge}
3421.1Sragge
3431.1Sragge
3441.1Sragge#if defined(MULTIPROCESSOR) && 0
3451.1Sraggeint
3461.1Sraggerxchar()
3471.1Sragge{
3481.1Sragge	int ret;
3491.1Sragge
3501.1Sragge	if (got == taken)
3511.1Sragge		return 0;
3521.1Sragge
3531.1Sragge	ret = rxbuf[taken++];
3541.1Sragge	if (taken == RXBUF)
3551.1Sragge		taken = 0;
3561.1Sragge	return ret;
3571.1Sragge}
3581.1Sragge
3591.1Sraggestatic void
3601.1Sraggeka88_startslave(struct device *dev, struct cpu_info *ci)
3611.1Sragge{
3621.1Sragge	struct ka88_softc *sc = (void *)dev;
3631.1Sragge	int id = sc->sc_binid;
3641.1Sragge	int i;
3651.1Sragge
3661.1Sragge	expect = sc->sc_binid;
3671.1Sragge	/* First empty queue */
3681.1Sragge	for (i = 0; i < 10000; i++)
3691.1Sragge		if (rxchar())
3701.1Sragge			i = 0;
3711.1Sragge	ka88_txrx(id, "\020", 0);		/* Send ^P to get attention */
3721.1Sragge	ka88_txrx(id, "I\r", 0);			/* Init other end */
3731.1Sragge	ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
3741.1Sragge	ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
3751.1Sragge	ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
3761.1Sragge	ka88_txrx(id, "D/I 10 %x\r", (int)ci->ci_pcb);	/* PCB for idle proc */
3771.1Sragge	ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
3781.1Sragge	ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
3791.1Sragge	ka88_txrx(id, "S %x\r", (int)&tramp); /* Start! */
3801.1Sragge	expect = 0;
3811.1Sragge	for (i = 0; i < 10000; i++)
3821.1Sragge		if ((volatile)ci->ci_flags & CI_RUNNING)
3831.1Sragge			break;
3841.1Sragge	if (i == 10000)
3851.1Sragge		printf("%s: (ID %d) failed starting??!!??\n",
3861.1Sragge		    dev->dv_xname, sc->sc_binid);
3871.1Sragge}
3881.1Sragge
3891.1Sraggevoid
3901.1Sraggeka88_txrx(int id, char *fmt, int arg)
3911.1Sragge{
3921.1Sragge	char buf[20];
3931.1Sragge
3941.1Sragge	sprintf(buf, fmt, arg);
3951.1Sragge	ka88_sendstr(id, buf);
3961.1Sragge	ka88_sergeant(id);
3971.1Sragge}
3981.1Sragge
3991.1Sraggevoid
4001.1Sraggeka88_sendstr(int id, char *buf)
4011.1Sragge{
4021.1Sragge	register u_int utchr; /* Ends up in R11 with PCC */
4031.1Sragge	int ch, i;
4041.1Sragge
4051.1Sragge	while (*buf) {
4061.1Sragge		utchr = *buf | id << 8;
4071.1Sragge
4081.1Sragge		/*
4091.1Sragge		 * It seems like mtpr to TXCD sets the V flag if it fails.
4101.1Sragge		 * Cannot check that flag in C...
4111.1Sragge		 */
4121.1Sragge#ifdef __GNUC__
4131.1Sragge		asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
4141.1Sragge#else
4151.1Sragge		asm("1:;mtpr r11,$92;bvs 1b");
4161.1Sragge#endif
4171.1Sragge		buf++;
4181.1Sragge		i = 30000;
4191.1Sragge		while ((ch = rxchar()) == 0 && --i)
4201.1Sragge			;
4211.1Sragge		if (ch == 0)
4221.1Sragge			continue; /* failed */
4231.1Sragge	}
4241.1Sragge}
4251.1Sragge
4261.1Sraggevoid
4271.1Sraggeka88_sergeant(int id)
4281.1Sragge{
4291.1Sragge	int i, ch, nserg;
4301.1Sragge
4311.1Sragge	nserg = 0;
4321.1Sragge	for (i = 0; i < 30000; i++) {
4331.1Sragge		if ((ch = rxchar()) == 0)
4341.1Sragge			continue;
4351.1Sragge		if (ch == '>')
4361.1Sragge			nserg++;
4371.1Sragge		else
4381.1Sragge			nserg = 0;
4391.1Sragge		i = 0;
4401.1Sragge		if (nserg == 3)
4411.1Sragge			break;
4421.1Sragge	}
4431.1Sragge	/* What to do now??? */
4441.1Sragge}
4451.1Sragge
4461.1Sragge/*
4471.1Sragge * Write to master console.
4481.1Sragge * Need no locking here; done in the print functions.
4491.1Sragge */
4501.1Sraggestatic volatile int ch = 0;
4511.1Sragge
4521.1Sraggevoid
4531.1Sraggeka88_putc(int c)
4541.1Sragge{
4551.1Sragge	if (curcpu()->ci_flags & CI_MASTERCPU) {
4561.1Sragge		gencnputc(0, c);
4571.1Sragge		return;
4581.1Sragge	}
4591.1Sragge	ch = c;
4601.1Sragge	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
4611.1Sragge	while (ch != 0)
4621.1Sragge		; /* Wait for master to handle */
4631.1Sragge}
4641.1Sragge
4651.1Sragge/*
4661.1Sragge * Got character IPI.
4671.1Sragge */
4681.1Sraggevoid
4691.1Sraggeka88_cnintr()
4701.1Sragge{
4711.1Sragge	if (ch != 0)
4721.1Sragge		gencnputc(0, ch);
4731.1Sragge	ch = 0; /* Release slavecpu */
4741.1Sragge}
4751.1Sragge#endif
476