V10/sys/md/ubauvax.c

/*
 * Q-bus adapter routines for MicroVAX II
 * The names imply `UNIBUS'; most of the system knows no difference
 */

#include "sys/param.h"
#include "sys/ubaddr.h"
#include "sys/map.h"
#include "sys/uba.h"
#include "sys/pte.h"
#include "sys/vmparam.h"
#include "sys/qbio.h"

extern struct uba uba[];
extern struct nxaddr ubaaddr[];
extern int ubacnt;

/*
 * bits in map register
 */

#define	MPAGE	0x3fff		/* physical page number -- small on comet */
#define	MRV	0x80000000	/* map register valid */

#define	QIOBASE	0760000		/* base address in Q-bus io space */

#define	ICR	0777500		/* interprocessor control register */
#define	LMEAE	040		/* local memory external access enable */

/*
 * return the register address for a unibus device
 */

caddr_t
ubaddr(up)
register struct ubaddr *up;
{
	register struct uba *ub;

	if (up->ubno < 0 || up->ubno > ubacnt) {
		printf("bad qbus no %d\n", up->ubno);
		return (0);
	}
	ub = &uba[up->ubno];
	if ((ub->flags & UBINIT) == 0)
		if (ubstart(up->ubno) == 0)
			return (0);
	return ((caddr_t)&ub->addr->ioreg[up->uboff-QIOBASE]);
}

/*
 * init the unibus adapter
 */

ubstart(u)
int u;
{
	register struct uba *ub;
	extern caddr_t qbaaddr();

	ub = &uba[u];
	if ((ub->addr = (struct ubadev *)qbaaddr(u)) == 0)
		return (0);
	rminit(ub->map, UBNMAP, NQMREG-1, 1);	/* NQMREG-1 because can't alloc 0 */
	if (ubmstart(u) == 0)
		return (0);
	ubinit(u);
	ub->flags |= UBINIT|UBQBUS;
	return (1);
}

/*
 * init the unibus adapter hardware
 */

ubinit(u)
int u;
{
	register struct uba *ub;
	register int i;
	register long *p;

	ub = &uba[u];
	*(short *)&ub->addr->ioreg[ICR-QIOBASE] |= LMEAE;
	for (i = 0, p = ub->addr->mreg; i < NQMREG; i++)
		*p++ = 0;
	ubminit(u);
}

/*
 * determine whether a particular address,
 * which happens to be in UNIBUS space,
 * exists
 * -- on MicroVAX, you just get a machine check on error
 */
ubbadaddr(u, a, s)
int u, s;
caddr_t a;
{

	return (badaddr(a, s));
}

/*
 * get/put a single byte to a particular unibus address
 * intended for use by ECC code
 * work it out from first principles,
 * because UNIBUS adapter may loop and hang otherwise
 */

static long
ubphys(ubno, addr)
unsigned int ubno;
uaddr_t addr;
{
	register struct uba *ub;
	register int pg;
	register long m;

	if (ubno >= ubacnt)
		panic("ubphys");
	ub = &uba[ubno];
	if (ub->addr == NULL)
		panic("ubphys");
	pg = addr / NBPG;
	if (pg >= NQMREG)
		return (-1);	/* addr too big */
	m = ub->addr->mreg[pg];
	if ((m & MRV) == 0)
		return (-1);	/* invalid */
	return ((m & MPAGE) * NBPG + addr % NBPG);
}

int
ubgetc(ubno, addr)
unsigned int ubno;
uaddr_t addr;
{
	register long phys;

	phys = ubphys(ubno, addr);
	if (phys < 0)
		return (-1);
	return (phgetc(phys));
}

int
ubputc(ubno, addr, c)
unsigned int ubno;
uaddr_t addr;
char c;
{
	register long phys;

	phys = ubphys(ubno, addr);
	if (phys < 0)
		return (-1);
	return (phputc(phys, c));
}

/*
 * allocate a BDP: MicroVAXes have none
 */

int
ubmapath(u)
int u;
{
	return (0);
}

ubmflush(u, path)
int u;
int path;
{
}

/*
 * fill in a piece of unibus map
 * return the address of the base
 *
 * hardware bug: successive writes to map registers
 * can block Q-bus DMA
 * workaround: CPU write to memory after each map reg write,
 * to slow it down enough
 */

uaddr_t
ubmsetmap(u, p, nreg, um)
int u;
register struct pte *p;
register int nreg;
ubm_t um;
{
	register long *m;
	int junk;

	m = &uba[u].addr->mreg[ubmfirst(um)];
	if (nreg > ubmsize(um)-1)
		panic("ubmsetmap");
	while (--nreg >= 0) {
		*m++ = p++->pg_pfnum | MRV;
		junk = 0;
	}
	return (ctob(ubmfirst(um)));
}