V10/lsys/md/nexnaut.c

/*
 * stuff for dealing with bi nodes (io nexus) on nautilus
 *
 * iospace is an array of struct nexus (registers + window space),
 * followed by three pages of special registers:
 * NBIA0, NBIA1, and the memory controller
 */

#include "sys/param.h"
#include "sys/nexus.h"
#include "sys/biaddr.h"
#include "sys/biic.h"
#include "sys/pte.h"

static int nexcnt;
char *iospace;			/* array of struct nexus, plus some stuff */
struct nbia {
	long	csr0;
	long	csr1;
};
static struct nbia *nbia[2];
long *mcrcsr;

static int nexreg(), nexwind(), biainit(), bibinit(), nbiavec();

/*
 * how much address space
 * is needed for nexus space?
 * needed when allocating system page table
 * the fudge factor of 3: 2 pages for NBIAs, one for the memory controller
 */

mchiopsize()
{
	register int i;

	for (i = 0; nextab[i].bus >= 0; i++)
		;
	nexcnt = i;
	return (i * sizeof(struct nexus) + 3 * NBPG);
}

/*
 * map appropriate parts of nexus space into kernel space
 * called early on, before memory mapping is set up
 * argument is the first relevant spt entry
 */

mchiopinit(pt)
struct pte *pt;
{
	register long *p;
	register int i, n;
	register int b;

	p = (long *)pt;
	for (i = 0; i < nexcnt; i++) {
		b = nexreg(&nextab[i]);
		for (n = 0; n < btoc(NXSIZE); n++)
			if (b)
				*p++ = PG_V|PG_KW|(b+n);
			else
				*p++ = 0;
		b = nexwind(&nextab[i], 0);
		for (n = 0; n < btoc(NXWSIZE); n++)
			if (b)
				*p++ = PG_V|PG_KW|(b+n);
			else
				*p++ = 0;
	}
	/*
	 * map the remainder to NMI adapters
	 */
	*p++ = PG_KW|PG_V|(0x20080000/NBPG);	/* NBIA 0 */
	*p++ = PG_KW|PG_V|(0x24080000/NBPG);	/* NBIA 1 */
	*p++ = PG_KW|PG_V|(0x3e000000/NBPG);	/* memory */
	mcrcsr = (long *)(iospace + nexcnt * sizeof(struct nexus) + 2 * NBPG);
}

static
nexreg(n)
register struct nextab *n;
{
	if (n->bus >= 4 || n->adp >= 16)
		return(0);
	return (btoc(0x20000000 + (n->bus * 0x2000000) + (n->adp * NXSIZE)));
}

/*
 * `loc' requests local address within that BI
 * the local address is what we put in sadr/eadr
 * the global one is what we put in the page table
 */
static
nexwind(n, loc)
register struct nextab *n;
{
	register long addr;

	addr = 0x20400000 + (n->adp * NXWSIZE);
	if (loc == 0)
		addr += (n->bus * 0x2000000);
	return (btoc(addr));
}

/*
 * generic VAXBI routines
 */

extern int biacnt;
extern char bianode[];
extern struct biaddr biaaddr[];

#define	NNUM	017	/* node to receive interrupts */
#define	NOK	0200	/* this node has been initialized */

#define	DB88	0x106	/* DB88 device type */
#define	NBIE	0x200000	/* NBIA interrupt enable */
#define	NBINIT	0x1	/* NBIA CSR1 init */

#define	NBIASTALL	1000000

/*
 * return the address of a node's registers
 * make sure the adapter has been initialized
 */

caddr_t
biaddr(bi)
register struct biaddr *bi;
{
	register int a;

	if (bi->nexus < 0 || bi->nexus >= nexcnt)
		return (0);
	a = nextab[bi->nexus].bus;
	if (a != bi->adno)
		printf("nx%d adno%d bus%d\n", bi->nexus, bi->adno, a);
	if ((bianode[a] & NOK) == 0 && biainit(a) == 0)
		return (0);
	return ((caddr_t)(iospace + bi->nexus * sizeof(struct nexus)));
}
/*
 * set certain magic numbers in the BIIC:
 * interrupt destination and map
 * call after node reset stuff is all done,
 * lest the numbers disappear
 *
 * can't NRST or look at BROKE here,
 * as conventions vary too much among devices
 */

int
biinit(bi, mapwin)
struct biaddr *bi;
int mapwin;
{
	register struct biic *bp;
	long wind;

	if ((bp = (struct biic *)biaddr(bi)) == NULL)
		panic("biinit");
	bp->biintr = 1<<(bianode[bi->adno] & NNUM);
	if (mapwin == 0) {
		bp->bieadr = 0;
		bp->bisadr = 0;
	} else {
		wind = ctob(nexwind(&nextab[bi->nexus], 1));
		bp->bieadr = wind + NXWSIZE;
		bp->bisadr = wind;
	}
}

/*
 * init an NBIA
 * and both the DB88s on this NBIA, if need be
 */

static int
biainit(a)
register int a;
{
	register caddr_t cp;
	register int v;
	register struct nbia *np;

	if (a >= biacnt)
		return (0);
	if (nbia[0] == 0) {
		cp = iospace + (nexcnt * sizeof(struct nexus));
		nbia[0] = (struct nbia *)cp;
		nbia[1] = (struct nbia *)(cp + NBPG);
	}
	np = ((a & 02) == 0) ? nbia[0] : nbia[1];
	if (badaddr(&np->csr0, sizeof(long))) {
		printf("nbia for bi%d not responding\n", a);
		return (0);
	}
	np->csr1 |= NBINIT;
	for (v = 0; v < NBIASTALL; v++)
		;
	if ((v = nbiavec(a & ~1)) == 0)
		return (0);
	bibinit(a & ~1);	/* the even one */
	bibinit(a | 1);		/* the odd one */
	v &= 0x7c00;	/* just the useful bits of vector */
	np->csr0 = np->csr0;	/* clear error complaints */
	np->csr1 = np->csr1;
	np->csr0 = v|NBIE;
	setnmi((a & 02) ? 1 : 0);
	return ((bianode[a] & NOK) != 0);
}

/*
 * init one DB88
 */

static
bibinit(a)
register int a;
{
	register struct biic *bp;
	register struct biaddr *bi;

	if (a >= biacnt || biaaddr[a].nexus < 0)
		return;
	bi = &biaaddr[a];
	if (bi->nexus < 0 || bi->nexus >= nexcnt)
		return;
	bp = (struct biic *)(iospace + bi->nexus * sizeof(struct nexus));
	bp->bitype = (bp->bitype & 0xffff0000)|DB88;
	bp->bisadr = 0;
	bp->bieadr = 0x20000000;	/* all non-IO space */
	bp->bieir = EIBR7|bi->vec;
	bp->bicsr |= BIBROKE|BIHEIE|BISEIE;	/* write BROKE to clear it */
	bp->biber = bp->biber;
	bp->bibci |= BCINTREN|BCRTOEN;
	bp->biintr = 1<<(bp->bicsr & BINODEID);
	if ((bp->bitype & 0xffff) != DB88)
		return;	/* oops */
	bianode[a] = NOK|(bp->bicsr & BINODEID);
}

/*
 * figure out the vector offset for the nbia
 * annoying sanity checks on the pair of DB88s
 */

static int
nbiavec(a)
register int a;
{
	register struct biaddr *o, *e;
	register int err;

	e = &biaaddr[a];
	o = &biaaddr[a+1];
	err = 0;
	if (a+1 < biacnt && e->nexus >= 0 && o->nexus >= 0)
		if (o->ovec != e->ovec+0x200)
			err++;
	if (e->nexus >= 0 && (e->ovec & 0x200) != 0)
		err++;
	if (a+1 < biacnt && o->nexus >= 0 && (o->ovec & 0x200) == 0)
		err++;
	if (err)
		printf("bi%d bi%d: fix the damned vectors\n", a, a+1);
	/*
	 * now for the vector
	 */
	if (e->nexus >= 0)
		return (e->ovec);
	if (a+1 < biacnt && o->nexus >= 0)
		return (o->ovec - 0x200);
	return (0);
}

/*
 * here on nbia interrupt
 * -- bi or nbi parity error, bi powerup
 * figure out how to ignore the latter
 */

nbiaintr(dev)
int dev;
{
	register struct nbia *np;
	register long csr0, csr1;

	np = nbia[dev];
	csr0 = np->csr0;
	csr1 = np->csr1;
	np->csr0 = csr0;	/* clear interrupt conditions */
	np->csr1 = csr1;
	printf("nbi%d intr csr0 %x csr1 %x\n", dev, csr0, csr1);
}

/*
 * here on nbib error interrupt
 */

bia0int(dev)
register int dev;
{
	register struct biic *bp;
	register long biber, bicsr;

	if (dev >= biacnt || biaaddr[dev].nexus < 0 || biaaddr[dev].nexus >= nexcnt)
		return;
	bp = (struct biic *)(iospace + biaaddr[dev].nexus * sizeof(struct nexus));
	bicsr = bp->bicsr;
	biber = bp->biber;
	bp->biber = biber;	/* clear latches */
	if ((biber & (BIHES|BISES)) == 0)
		return;
	if (cknofault())
		return;
	printf("bi%d: csr %x ber %x\n", dev, bicsr, biber);
}