/* * 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); }