~kris/9p

9hist

75715a005a7766e1e6f905a5ecb5c97d3ed4d4b3 — David du Colombier 27 years ago 48c919b
Plan 9 from Bell Labs 1999-04-22
8 files changed, 2237 insertions(+), 2 deletions(-)

A alphapc/ether2114x.c
A alphapc/memmove.s
A alphapc/memset.s
M alphapc/pci.c
A pc/devlml.c
A pc/devlml.h
M pc/dma.c
M pc/main.c
A alphapc/ether2114x.c => alphapc/ether2114x.c +1425 -0
@@ 0,0 1,1425 @@
/*
 * Digital Semiconductor DECchip 2114x PCI Fast Ethernet LAN Controller.
 * To do:
 *	thresholds;
 *	ring sizing;
 *	handle more error conditions;
 *	tidy setup packet mess;
 *	push initialisation back to attach;
 *	full SROM decoding.
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "etherif.h"

/* nasty PCI DMA hack... */

#undef	PADDR
#define	PADDR(a) ((ulong)(a))

#define DEBUG		0
#define debug		if(DEBUG)print

enum {
	Nrde		= 64,
	Ntde		= 64,
};

enum {					/* CRS0 - Bus Mode */
	Swr		= 0x00000001,	/* Software Reset */
	Bar		= 0x00000002,	/* Bus Arbitration */
	Dsl		= 0x0000007C,	/* Descriptor Skip Length (field) */
	Ble		= 0x00000080,	/* Big/Little Endian */
	Pbl		= 0x00003F00,	/* Programmable Burst Length (field) */
	Cal		= 0x0000C000,	/* Cache Alignment (field) */
	Cal8		= 0x00004000,	/* 8 longword boundary alignment */
	Cal16		= 0x00008000,	/* 16 longword boundary alignment */
	Cal32		= 0x0000C000,	/* 32 longword boundary alignment */
	Tap		= 0x000E0000,	/* Transmit Automatic Polling (field) */
	Dbo		= 0x00100000,	/* Descriptor Byte Ordering Mode */
	Rml		= 0x00200000,	/* Read Multiple */
}; 

enum {					/* CSR[57] - Status and Interrupt Enable */
	Ti		= 0x00000001,	/* Transmit Interrupt */
	Tps		= 0x00000002,	/* Transmit Process Stopped */
	Tu		= 0x00000004,	/* Transmit buffer Unavailable */
	Tjt		= 0x00000008,	/* Transmit Jabber Timeout */
	Unf		= 0x00000020,	/* transmit UNderFlow */
	Ri		= 0x00000040,	/* Receive Interrupt */
	Ru		= 0x00000080,	/* Receive buffer Unavailable */
	Rps		= 0x00000100,	/* Receive Process Stopped */
	Rwt		= 0x00000200,	/* Receive Watchdog Timeout */
	Eti		= 0x00000400,	/* Early Transmit Interrupt */
	Gte		= 0x00000800,	/* General purpose Timer Expired */
	Fbe		= 0x00002000,	/* Fatal Bit Error */
	Ais		= 0x00008000,	/* Abnormal Interrupt Summary */
	Nis		= 0x00010000,	/* Normal Interrupt Summary */
	Rs		= 0x000E0000,	/* Receive process State (field) */
	Ts		= 0x00700000,	/* Transmit process State (field) */
	Eb		= 0x03800000,	/* Error bits */
};

enum {					/* CSR6 - Operating Mode */
	Hp		= 0x00000001,	/* Hash/Perfect receive filtering mode */
	Sr		= 0x00000002,	/* Start/stop Receive */
	Ho		= 0x00000004,	/* Hash-Only filtering mode */
	Pb		= 0x00000008,	/* Pass Bad frames */
	If		= 0x00000010,	/* Inverse Filtering */
	Sb		= 0x00000020,	/* Start/stop Backoff counter */
	Pr		= 0x00000040,	/* Promiscuous Mode */
	Pm		= 0x00000080,	/* Pass all Multicast */
	Fd		= 0x00000200,	/* Full Duplex mode */
	Om		= 0x00000C00,	/* Operating Mode (field) */
	Fc		= 0x00001000,	/* Force Collision */
	St		= 0x00002000,	/* Start/stop Transmission Command */
	Tr		= 0x0000C000,	/* ThReshold control bits (field) */
	Tr128		= 0x00000000,
	Tr256		= 0x00004000,
	Tr512		= 0x00008000,
	Tr1024		= 0x0000C000,
	Ca		= 0x00020000,	/* CApture effect enable */
	Ps		= 0x00040000,	/* Port Select */
	Hbd		= 0x00080000,	/* HeartBeat Disable */
	Imm		= 0x00100000,	/* IMMediate mode */
	Sf		= 0x00200000,	/* Store and Forward */
	Ttm		= 0x00400000,	/* Transmit Threshold Mode */
	Pcs		= 0x00800000,	/* PCS function */
	Scr		= 0x01000000,	/* SCRambler mode */
	Mbo		= 0x02000000,	/* Must Be One */
	Ra		= 0x40000000,	/* Receive All */
	Sc		= 0x80000000,	/* Special Capture effect enable */

	TrMODE		= Tr512,	/* default transmission threshold */
};

enum {					/* CSR9 - ROM and MII Management */
	Scs		= 0x00000001,	/* serial ROM chip select */
	Sclk		= 0x00000002,	/* serial ROM clock */
	Sdi		= 0x00000004,	/* serial ROM data in */
	Sdo		= 0x00000008,	/* serial ROM data out */
	Ss		= 0x00000800,	/* serial ROM select */
	Wr		= 0x00002000,	/* write */
	Rd		= 0x00004000,	/* read */

	Mdc		= 0x00010000,	/* MII management clock */
	Mdo		= 0x00020000,	/* MII management write data */
	Mii		= 0x00040000,	/* MII management operation mode (W) */
	Mdi		= 0x00080000,	/* MII management data in */
};

enum {					/* CSR12 - General-Purpose Port */
	Gpc		= 0x00000100,	/* General Purpose Control */
};

typedef struct Des {
	int	status;
	int	control;
	ulong	addr;
	Block*	bp;
} Des;

enum {					/* status */
	Of		= 0x00000001,	/* Rx: OverFlow */
	Ce		= 0x00000002,	/* Rx: CRC Error */
	Db		= 0x00000004,	/* Rx: Dribbling Bit */
	Re		= 0x00000008,	/* Rx: Report on MII Error */
	Rw		= 0x00000010,	/* Rx: Receive Watchdog */
	Ft		= 0x00000020,	/* Rx: Frame Type */
	Cs		= 0x00000040,	/* Rx: Collision Seen */
	Tl		= 0x00000080,	/* Rx: Frame too Long */
	Ls		= 0x00000100,	/* Rx: Last deScriptor */
	Fs		= 0x00000200,	/* Rx: First deScriptor */
	Mf		= 0x00000400,	/* Rx: Multicast Frame */
	Rf		= 0x00000800,	/* Rx: Runt Frame */
	Dt		= 0x00003000,	/* Rx: Data Type (field) */
	De		= 0x00004000,	/* Rx: Descriptor Error */
	Fl		= 0x3FFF0000,	/* Rx: Frame Length (field) */
	Ff		= 0x40000000,	/* Rx: Filtering Fail */

	Def		= 0x00000001,	/* Tx: DEFerred */
	Uf		= 0x00000002,	/* Tx: UnderFlow error */
	Lf		= 0x00000004,	/* Tx: Link Fail report */
	Cc		= 0x00000078,	/* Tx: Collision Count (field) */
	Hf		= 0x00000080,	/* Tx: Heartbeat Fail */
	Ec		= 0x00000100,	/* Tx: Excessive Collisions */
	Lc		= 0x00000200,	/* Tx: Late Collision */
	Nc		= 0x00000400,	/* Tx: No Carrier */
	Lo		= 0x00000800,	/* Tx: LOss of carrier */
	To		= 0x00004000,	/* Tx: Transmission jabber timeOut */

	Es		= 0x00008000,	/* [RT]x: Error Summary */
	Own		= 0x80000000,	/* [RT]x: OWN bit */
};

enum {					/* control */
	Bs1		= 0x000007FF,	/* [RT]x: Buffer 1 Size */
	Bs2		= 0x003FF800,	/* [RT]x: Buffer 2 Size */

	Ch		= 0x01000000,	/* [RT]x: second address CHained */
	Er		= 0x02000000,	/* [RT]x: End of Ring */

	Ft0		= 0x00400000,	/* Tx: Filtering Type 0 */
	Dpd		= 0x00800000,	/* Tx: Disabled PaDding */
	Ac		= 0x04000000,	/* Tx: Add CRC disable */
	Set		= 0x08000000,	/* Tx: SETup packet */
	Ft1		= 0x10000000,	/* Tx: Filtering Type 1 */
	Fseg		= 0x20000000,	/* Tx: First SEGment */
	Lseg		= 0x40000000,	/* Tx: Last SEGment */
	Ic		= 0x80000000,	/* Tx: Interrupt on Completion */
};

enum {					/* PHY registers */
	Bmcr		= 0,		/* Basic Mode Control */
	Bmsr		= 1,		/* Basic Mode Status */
	Phyidr1		= 2,		/* PHY Identifier #1 */
	Phyidr2		= 3,		/* PHY Identifier #2 */
	Anar		= 4,		/* Auto-Negotiation Advertisment */
	Anlpar		= 5,		/* Auto-Negotiation Link Partner Ability */
	Aner		= 6,		/* Auto-Negotiation Expansion */
};

typedef struct Ctlr Ctlr;
typedef struct Ctlr {
	int	port;
	Pcidev*	pcidev;
	Ctlr*	next;
	int	active;

	uchar	srom[128];
	uchar*	sromea;			/* MAC address */
	uchar*	leaf;
	int	sct;			/* selected connection type */
	int	k;			/* info block count */
	uchar*	infoblock[16];
	int	sctk;			/* sct block index */
	int	curk;			/* current block index */
	uchar*	type5block;

	int	phy[32];		/* logical to physical map */
	int	phyreset;		/* reset bitmap */
	int	curphyad;
	int	fdx;
	int	ttm;

	uchar	fd;			/* option */
	int	medium;			/* option */

	int	csr6;			/* CSR6 - operating mode */
	int	mask;			/* CSR[57] - interrupt mask */
	int	mbps;

	Lock	lock;

	Des*	rdr;			/* receive descriptor ring */
	int	nrdr;			/* size of rdr */
	int	rdrx;			/* index into rdr */

	Lock	tlock;
	Des*	tdr;			/* transmit descriptor ring */
	int	ntdr;			/* size of tdr */
	int	tdrh;			/* host index into tdr */
	int	tdri;			/* interface index into tdr */
	int	ntq;			/* descriptors active */
	int	ntqmax;
	Block*	setupbp;

	ulong	of;			/* receive statistics */
	ulong	ce;
	ulong	cs;
	ulong	tl;
	ulong	rf;
	ulong	de;

	ulong	ru;
	ulong	rps;
	ulong	rwt;

	ulong	uf;			/* transmit statistics */
	ulong	ec;
	ulong	lc;
	ulong	nc;
	ulong	lo;
	ulong	to;

	ulong	tps;
	ulong	tu;
	ulong	tjt;
	ulong	unf;
} Ctlr;

static Ctlr* ctlrhead;
static Ctlr* ctlrtail;

#define csr32r(c, r)	(inl((c)->port+((r)*8)))
#define csr32w(c, r, l)	(outl((c)->port+((r)*8), (ulong)(l)))

static void
promiscuous(void* arg, int on)
{
	Ctlr *ctlr;

	ctlr = ((Ether*)arg)->ctlr;
	ilock(&ctlr->lock);
	if(on)
		ctlr->csr6 |= Pr;
	else
		ctlr->csr6 &= ~Pr;
	csr32w(ctlr, 6, ctlr->csr6);
	iunlock(&ctlr->lock);
}

static void
attach(Ether* ether)
{
	Ctlr *ctlr;

	ctlr = ether->ctlr;
	ilock(&ctlr->lock);
	if(!(ctlr->csr6 & Sr)){
		ctlr->csr6 |= Sr;
		csr32w(ctlr, 6, ctlr->csr6);
	}
	iunlock(&ctlr->lock);
}

static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
	Ctlr *ctlr;
	char *buf, *p;
	int i, l, len;

	ctlr = ether->ctlr;

	ether->crcs = ctlr->ce;
	ether->frames = ctlr->rf+ctlr->cs;
	ether->buffs = ctlr->de+ctlr->tl;
	ether->overflows = ctlr->of;

	if(n == 0)
		return 0;

	p = malloc(READSTR);
	l = snprint(p, READSTR, "Overflow: %lud\n", ctlr->of);
	l += snprint(p+l, READSTR-l, "Ru: %lud\n", ctlr->ru);
	l += snprint(p+l, READSTR-l, "Rps: %lud\n", ctlr->rps);
	l += snprint(p+l, READSTR-l, "Rwt: %lud\n", ctlr->rwt);
	l += snprint(p+l, READSTR-l, "Tps: %lud\n", ctlr->tps);
	l += snprint(p+l, READSTR-l, "Tu: %lud\n", ctlr->tu);
	l += snprint(p+l, READSTR-l, "Tjt: %lud\n", ctlr->tjt);
	l += snprint(p+l, READSTR-l, "Unf: %lud\n", ctlr->unf);
	l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->ce);
	l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->cs);
	l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->tl);
	l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->rf);
	l += snprint(p+l, READSTR-l, "Descriptor Error: %lud\n", ctlr->de);
	l += snprint(p+l, READSTR-l, "Underflow Error: %lud\n", ctlr->uf);
	l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec);
	l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->lc);
	l += snprint(p+l, READSTR-l, "No Carrier: %lud\n", ctlr->nc);
	l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->lo);
	l += snprint(p+l, READSTR-l, "Transmit Jabber Timeout: %lud\n",
		ctlr->to);
	l += snprint(p+l, READSTR-l, "csr6: %luX %uX\n", csr32r(ctlr, 6),
		ctlr->csr6);
	snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax);
	ctlr->ntqmax = 0;
	buf = a;
	len = readstr(offset, buf, n, p);
	if(offset > l)
		offset -= l;
	else
		offset = 0;
	buf += len;
	n -= len;

	l = snprint(p, READSTR, "srom:");
	for(i = 0; i < sizeof(ctlr->srom); i++){
		if(i && ((i & 0x0F) == 0))
			l += snprint(p+l, READSTR-l, "\n     ");
		l += snprint(p+l, READSTR-l, " %2.2uX", ctlr->srom[i]);
	}

	snprint(p+l, READSTR-l, "\n");
	len += readstr(offset, buf, n, p);
	free(p);

	return len;
}

static void
txstart(Ether* ether)
{
	Ctlr *ctlr;
	Block *bp;
	Des *des;
	int control;

	ctlr = ether->ctlr;
	while(ctlr->ntq < (ctlr->ntdr-1)){
		if(ctlr->setupbp){
			bp = ctlr->setupbp;
			ctlr->setupbp = 0;
			control = Ic|Set|BLEN(bp);
		}
		else{
			bp = qget(ether->oq);
			if(bp == nil)
				break;
			control = Ic|Lseg|Fseg|BLEN(bp);
		}

		ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic;
		des = &ctlr->tdr[ctlr->tdrh];
		des->bp = bp;
		des->addr = PADDR(bp->rp);
		des->control |= control;
		ctlr->ntq++;
		coherence();
		des->status = Own;
		csr32w(ctlr, 1, 0);
		ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr);
	}

	if(ctlr->ntq > ctlr->ntqmax)
		ctlr->ntqmax = ctlr->ntq;
}

static void
transmit(Ether* ether)
{
	Ctlr *ctlr;

	ctlr = ether->ctlr;
	ilock(&ctlr->tlock);
	txstart(ether);
	iunlock(&ctlr->tlock);
}

static void
interrupt(Ureg*, void* arg)
{
	Ctlr *ctlr;
	Ether *ether;
	int len, status;
	Des *des;
	Block *bp;

	ether = arg;
	ctlr = ether->ctlr;

	while((status = csr32r(ctlr, 5)) & (Nis|Ais)){
		/*
		 * Acknowledge the interrupts and mask-out
		 * the ones that are implicitly handled.
		 */
		csr32w(ctlr, 5, status);
		status &= (ctlr->mask & ~(Nis|Ti));

		if(status & Ais){
			if(status & Tps)
				ctlr->tps++;
			if(status & Tu)
				ctlr->tu++;
			if(status & Tjt)
				ctlr->tjt++;
			if(status & Ru)
				ctlr->ru++;
			if(status & Rps)
				ctlr->rps++;
			if(status & Rwt)
				ctlr->rwt++;
			status &= ~(Ais|Rwt|Rps|Ru|Tjt|Tu|Tps);
		}

		/*
		 * Received packets.
		 */
		if(status & Ri){
			des = &ctlr->rdr[ctlr->rdrx];
			while(!(des->status & Own)){
				if(des->status & Es){
					if(des->status & Of)
						ctlr->of++;
					if(des->status & Ce)
						ctlr->ce++;
					if(des->status & Cs)
						ctlr->cs++;
					if(des->status & Tl)
						ctlr->tl++;
					if(des->status & Rf)
						ctlr->rf++;
					if(des->status & De)
						ctlr->de++;
				}
				else if(bp = iallocb(sizeof(Etherpkt)+4)){
					len = ((des->status & Fl)>>16)-4;
					des->bp->wp = des->bp->rp+len;
					etheriq(ether, des->bp, 1);
					des->bp = bp;
					des->addr = PADDR(bp->rp);
				}

				des->control &= Er;
				des->control |= ROUNDUP(sizeof(Etherpkt)+4, 4);
				coherence();
				des->status = Own;

				ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
				des = &ctlr->rdr[ctlr->rdrx];
			}
			status &= ~Ri;
		}

		/*
		 * Check the transmit side:
		 *	check for Transmit Underflow and Adjust
		 *	the threshold upwards;
		 *	free any transmitted buffers and try to
		 *	top-up the ring.
		 */
		if(status & Unf){
			ctlr->unf++;
			ilock(&ctlr->lock);
			csr32w(ctlr, 6, ctlr->csr6 & ~St);
			switch(ctlr->csr6 & Tr){
			case Tr128:
				len = Tr256;
				break;
			case Tr256:
				len = Tr512;
				break;
			case Tr512:
				len = Tr1024;
				break;
			default:
			case Tr1024:
				len = Sf;
				break;
			}
			ctlr->csr6 = (ctlr->csr6 & ~Tr)|len;
			csr32w(ctlr, 6, ctlr->csr6);
			iunlock(&ctlr->lock);
			csr32w(ctlr, 5, Tps);
			status &= ~(Unf|Tps);
		}

		ilock(&ctlr->tlock);
		while(ctlr->ntq){
			des = &ctlr->tdr[ctlr->tdri];
			if(des->status & Own)
				break;

			if(des->status & Es){
				if(des->status & Uf)
					ctlr->uf++;
				if(des->status & Ec)
					ctlr->ec++;
				if(des->status & Lc)
					ctlr->lc++;
				if(des->status & Nc)
					ctlr->nc++;
				if(des->status & Lo)
					ctlr->lo++;
				if(des->status & To)
					ctlr->to++;
				ether->oerrs++;
			}

			freeb(des->bp);
			des->control &= Er;

			ctlr->ntq--;
			ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr);
		}
		txstart(ether);
		iunlock(&ctlr->tlock);

		/*
		 * Anything left not catered for?
		 */
		if(status)
			panic("#l%d: status %8.8uX\n", ether->ctlrno, status);
	}
}

static void
ctlrinit(Ether* ether)
{
	Ctlr *ctlr;
	Des *des;
	Block *bp;
	int i;
	uchar bi[Eaddrlen*2];

	ctlr = ether->ctlr;

	/*
	 * Allocate and initialise the receive ring;
	 * allocate and initialise the transmit ring;
	 * unmask interrupts and start the transmit side;
	 * create and post a setup packet to initialise
	 * the physical ethernet address.
	 */
	ctlr->rdr = malloc(ctlr->nrdr*sizeof(Des));
	for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){
		des->bp = allocb(ROUNDUP(sizeof(Etherpkt)+4, 4));
		des->status = Own;
		des->control = ROUNDUP(sizeof(Etherpkt)+4, 4);
		des->addr = PADDR(des->bp->rp);
	}
	ctlr->rdr[ctlr->nrdr-1].control |= Er;
	ctlr->rdrx = 0;
	csr32w(ctlr, 3, PADDR(ctlr->rdr));

	ctlr->tdr = xspanalloc(ctlr->ntdr*sizeof(Des), 8*sizeof(ulong), 0);
	ctlr->tdr[ctlr->ntdr-1].control |= Er;
	ctlr->tdrh = 0;
	ctlr->tdri = 0;
	csr32w(ctlr, 4, PADDR(ctlr->tdr));

	ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti;
	csr32w(ctlr, 7, ctlr->mask);
	ctlr->csr6 |= St;
	csr32w(ctlr, 6, ctlr->csr6);

	for(i = 0; i < Eaddrlen/2; i++){
		bi[i*4] = ether->ea[i*2];
		bi[i*4+1] = ether->ea[i*2+1];
		bi[i*4+2] = ether->ea[i*2+1];
		bi[i*4+3] = ether->ea[i*2];
	}
	bp = allocb(Eaddrlen*2*16);
	memset(bp->rp, 0xFF, sizeof(bi));
	for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi))
		memmove(bp->rp+i, bi, sizeof(bi));
	bp->wp += sizeof(bi)*16;

	ctlr->setupbp = bp;
	ether->oq = qopen(256*1024, 1, 0, 0);
	transmit(ether);
}

static void
csr9w(Ctlr* ctlr, int data)
{
	csr32w(ctlr, 9, data);
	microdelay(1);
}

static int
miimdi(Ctlr* ctlr, int n)
{
	int data, i;

	/*
	 * Read n bits from the MII Management Register.
	 */
	data = 0;
	for(i = n-1; i >= 0; i--){
		if(csr32r(ctlr, 9) & Mdi)
			data |= (1<<i);
		csr9w(ctlr, Mii|Mdc);
		csr9w(ctlr, Mii);
	}
	csr9w(ctlr, 0);

	return data;
}

static void
miimdo(Ctlr* ctlr, int bits, int n)
{
	int i, mdo;

	/*
	 * Write n bits to the MII Management Register.
	 */
	for(i = n-1; i >= 0; i--){
		if(bits & (1<<i))
			mdo = Mdo;
		else
			mdo = 0;
		csr9w(ctlr, mdo);
		csr9w(ctlr, mdo|Mdc);
		csr9w(ctlr, mdo);
	}
}

static int
miir(Ctlr* ctlr, int phyad, int regad)
{
	int data;

	/*
	 * Preamble;
	 * ST+OP+PHYAD+REGAD;
	 * TA + 16 data bits.
	 */
	miimdo(ctlr, 0xFFFFFFFF, 32);
	miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14);
	data = miimdi(ctlr, 18);

	if(data & 0x10000)
		return -1;

	return data & 0xFFFF;
}

static void
miiw(Ctlr* ctlr, int phyad, int regad, int data)
{
	/*
	 * Preamble;
	 * ST+OP+PHYAD+REGAD+TA + 16 data bits;
	 * Z.
	 */
	miimdo(ctlr, 0xFFFFFFFF, 32);
	data &= 0xFFFF;
	data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16);
	miimdo(ctlr, data, 32);
	csr9w(ctlr, Mdc);
	csr9w(ctlr, 0);
}

static int
sromr(Ctlr* ctlr, int r)
{
	int i, op, data;

	/*
	 * This sequence for reading a 16-bit register 'r'
	 * in the EEPROM is taken straight from Section
	 * 7.4 of the 21140 Hardware Reference Manual.
	 */
	csr9w(ctlr, Rd|Ss);
	csr9w(ctlr, Rd|Ss|Scs);
	csr9w(ctlr, Rd|Ss|Sclk|Scs);
	csr9w(ctlr, Rd|Ss);

	op = 0x06;
	for(i = 3-1; i >= 0; i--){
		data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs;
		csr9w(ctlr, data);
		csr9w(ctlr, data|Sclk);
		csr9w(ctlr, data);
	}

	for(i = 6-1; i >= 0; i--){
		data = Rd|Ss|(((r>>i) & 0x01)<<2)|Scs;
		csr9w(ctlr, data);
		csr9w(ctlr, data|Sclk);
		csr9w(ctlr, data);
	}

	data = 0;
	for(i = 16-1; i >= 0; i--){
		csr9w(ctlr, Rd|Ss|Sclk|Scs);
		if(csr32r(ctlr, 9) & Sdo)
			data |= (1<<i);
		csr9w(ctlr, Rd|Ss|Scs);
	}

	csr9w(ctlr, 0);

	return data & 0xFFFF;
}

static void
softreset(Ctlr* ctlr)
{
	/*
	 * Soft-reset the controller and initialise bus mode.
	 * Delay should be >= 50 PCI cycles (2×S @ 25MHz).
	 */
	csr32w(ctlr, 0, Swr);
	microdelay(10);
	csr32w(ctlr, 0, Rml|Cal16);
	delay(1);
}

static int
type5block(Ctlr* ctlr, uchar* block)
{
	int csr15, i, len;

	/*
	 * Reset or GPR sequence. Reset should be once only,
	 * before the GPR sequence.
	 * Note 'block' is not a pointer to the block head but
	 * a pointer to the data in the block starting at the
	 * reset length value so type5block can be used for the
	 * sequences contained in type 1 and type 3 blocks.
	 * The SROM docs state the 21140 type 5 block is the
	 * same as that for the 21143, but the two controllers
	 * use different registers and sequence-element lengths
	 * so the 21140 code here is a guess for a real type 5
	 * sequence.
	 */
	len = *block++;
	if(ctlr->pcidev->did == 0x0009){
		for(i = 0; i < len; i++){
			csr32w(ctlr, 12, *block);
			block++;
		}
		return len;
	}

	for(i = 0; i < len; i++){
		csr15 = *block++<<16;
		csr15 |= *block++<<24;
		csr32w(ctlr, 15, csr15);
		debug("%8.8uX ", csr15);
	}
	return 2*len;
}

static int
typephylink(Ctlr* ctlr, uchar*)
{
	int an, bmcr, bmsr, csr6, x;

	/*
	 * Fail if
	 *	auto-negotiataion enabled but not complete;
	 *	no valid link established.
	 */
	bmcr = miir(ctlr, ctlr->curphyad, Bmcr);
	miir(ctlr, ctlr->curphyad, Bmsr);
	bmsr = miir(ctlr, ctlr->curphyad, Bmsr);
	debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr);
	if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004))
		return 0;

	if(bmcr & 0x1000){
		an = miir(ctlr, ctlr->curphyad, Anar);
		an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0;
		debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n",
	    		miir(ctlr, ctlr->curphyad, Anar),
			miir(ctlr, ctlr->curphyad, Anlpar),
			an);
	
		if(an & 0x0100)
			x = 0x4000;
		else if(an & 0x0080)
			x = 0x2000;
		else if(an & 0x0040)
			x = 0x1000;
		else if(an & 0x0020)
			x = 0x0800;
		else
			x = 0;
	}
	else if((bmcr & 0x2100) == 0x2100)
		x = 0x4000;
	else if(bmcr & 0x2000)
		x = 0x2000;
	else if(bmcr & 0x0100)
		x = 0x1000;
	else
		x = 0x0800;

	csr6 = Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
	if(ctlr->fdx & x)
		csr6 |= Fd;
	if(ctlr->ttm & x)
		csr6 |= Ttm;
	debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n",
		csr6, ctlr->csr6, csr32r(ctlr, 6));
	if(csr6 != ctlr->csr6){
		ctlr->csr6 = csr6;
		csr32w(ctlr, 6, csr6);
	}

	return 1;
}

static int
typephymode(Ctlr* ctlr, uchar* block, int wait)
{
	uchar *p;
	int len, mc, nway, phyx, timeo;

	if(DEBUG){
		int i;

		len = (block[0] & ~0x80)+1;
		for(i = 0; i < len; i++)
			debug("%2.2uX ", block[i]);
		debug("\n");
	}

	if(block[1] == 1)
		len = 1;
	else if(block[1] == 3)
		len = 2;
	else
		return -1;

	/*
	 * Snarf the media capabilities, nway advertisment,
	 * FDX and TTM bitmaps.
	 */
	p = &block[5+len*block[3]+len*block[4+len*block[3]]];
	mc = *p++;
	mc |= *p++<<8;
	nway = *p++;
	nway |= *p++<<8;
	ctlr->fdx = *p++;
	ctlr->fdx |= *p++<<8;
	ctlr->ttm = *p++;
	ctlr->ttm |= *p<<8;
	debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n",
		mc, nway, ctlr->fdx, ctlr->ttm);
	USED(mc);

	phyx = block[2];
	ctlr->curphyad = ctlr->phy[phyx];

	ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
	//csr32w(ctlr, 6, ctlr->csr6);
	if(typephylink(ctlr, block))
		return 0;

	if(!(ctlr->phyreset & (1<<phyx))){
		debug("reset seq: len %d: ", block[3]);
		if(ctlr->type5block)
			type5block(ctlr, &ctlr->type5block[2]);
		else
			type5block(ctlr, &block[4+len*block[3]]);
		debug("\n");
		ctlr->phyreset |= (1<<phyx);
	}

	/*
	 * GPR sequence.
	 */
	debug("gpr seq: len %d: ", block[3]);
	type5block(ctlr, &block[3]);
	debug("\n");

	ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
	//csr32w(ctlr, 6, ctlr->csr6);
	if(typephylink(ctlr, block))
		return 0;

	/*
	 * Turn off auto-negotiation, set the auto-negotiation
	 * advertisment register then start the auto-negotiation
	 * process again.
	 */
	miiw(ctlr, ctlr->curphyad, Bmcr, 0);
	miiw(ctlr, ctlr->curphyad, Anar, nway|1);
	miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000);

	if(!wait)
		return 0;

	for(timeo = 0; timeo < 30; timeo++){
		if(typephylink(ctlr, block))
			return 0;
		delay(100);
	}

	return -1;
}

static int
type0link(Ctlr* ctlr, uchar* block)
{
	int m, polarity, sense;

	m = (block[3]<<8)|block[2];
	sense = 1<<((m & 0x000E)>>1);
	if(m & 0x0080)
		polarity = sense;
	else
		polarity = 0;

	return (csr32r(ctlr, 12) & sense)^polarity;
}

static int
type0mode(Ctlr* ctlr, uchar* block, int wait)
{
	int csr6, m, timeo;

	csr6 = Sc|Mbo|Hbd|Ca|Sb|TrMODE;
debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
    ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]); 
	switch(block[0]){
	default:
		break;

	case 0x04:			/* 10BASE-TFD */
	case 0x05:			/* 100BASE-TXFD */
	case 0x08:			/* 100BASE-FXFD */
		/*
		 * Don't attempt full-duplex
		 * unless explicitly requested.
		 */
		if(!ctlr->fd)
			return -1;
		csr6 |= Fd;
		break;
	}

	m = (block[3]<<8)|block[2];
	if(m & 0x0001)
		csr6 |= Ps;
	if(m & 0x0010)
		csr6 |= Ttm;
	if(m & 0x0020)
		csr6 |= Pcs;
	if(m & 0x0040)
		csr6 |= Scr;

	csr32w(ctlr, 12, block[1]);
	microdelay(10);
	csr32w(ctlr, 6, csr6);
	ctlr->csr6 = csr6;

	if(!wait)
		return 0;

	for(timeo = 0; timeo < 30; timeo++){
		if(type0link(ctlr, block))
			return 0;
		delay(100);
	}

	return -1;
}

static int
mediaxx(Ether* ether, int wait)
{
	Ctlr* ctlr;
	uchar *block;

	ctlr = ether->ctlr;
	block = ctlr->infoblock[ctlr->curk];
	if(block[0] & 0x80){
		switch(block[1]){
		default:
			return -1;
		case 0:
			if(ctlr->medium >= 0 && block[2] != ctlr->medium)
				return 0;
/* need this test? */	if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[2])
				return 0;
			if(type0mode(ctlr, block+2, wait))
				return 0;
			break;
		case 1:
			if(typephymode(ctlr, block, wait))
				return 0;
			break;
		case 3:
			if(typephymode(ctlr, block, wait))
				return 0;
			break;
		}
	}
	else{
		if(ctlr->medium >= 0 && block[0] != ctlr->medium)
			return 0;
/* need this test? */if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[0])
			return 0;
		if(type0mode(ctlr, block, wait))
			return 0;
	}

	if(ctlr->csr6){
		if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm))
			return 10;
		return 100;
	}

	return 0;
}

static int
media(Ether* ether, int wait)
{
	Ctlr* ctlr;
	int k, mbps;

	ctlr = ether->ctlr;
	for(k = 0; k < ctlr->k; k++){
		mbps = mediaxx(ether, wait);
		if(mbps > 0)
			return mbps;
		if(ctlr->curk == 0)
			ctlr->curk = ctlr->k-1;
		else
			ctlr->curk--;
	}

	return 0;
}

static char* mediatable[9] = {
	"10BASE-T",				/* TP */
	"10BASE-2",				/* BNC */
	"10BASE-5",				/* AUI */
	"100BASE-TX",
	"10BASE-TFD",
	"100BASE-TXFD",
	"100BASE-T4",
	"100BASE-FX",
	"100BASE-FXFD",
};

static uchar en1207[] = {		/* Accton EN1207-COMBO */
	0x00, 0x00, 0xE8,		/* [0]  vendor ethernet code */
	0x00,				/* [3]  spare */

	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
	0x1F,				/* [6]  general purpose control */
	2,				/* [7]  block count */

	0x00,				/* [8]  media code (10BASE-TX) */
	0x0B,				/* [9]  general purpose port data */
	0x9E, 0x00,			/* [10] command (LSB+MSB = 0x009E) */

	0x03,				/* [8]  media code (100BASE-TX) */
	0x1B,				/* [9]  general purpose port data */
	0x6D, 0x00,			/* [10] command (LSB+MSB = 0x006D) */

					/* There is 10BASE-2 as well, but... */
};

static uchar ana6910fx[] = {		/* Adaptec (Cogent) ANA-6910FX */
	0x00, 0x00, 0x92,		/* [0]  vendor ethernet code */
	0x00,				/* [3]  spare */

	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
	0x3F,				/* [6]  general purpose control */
	1,				/* [7]  block count */

	0x07,				/* [8]  media code (100BASE-FX) */
	0x03,				/* [9]  general purpose port data */
	0x2D, 0x00			/* [10] command (LSB+MSB = 0x000D) */
};

static uchar smc9332[] = {		/* SMC 9332 */
	0x00, 0x00, 0xC0,		/* [0]  vendor ethernet code */
	0x00,				/* [3]  spare */

	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
	0x1F,				/* [6]  general purpose control */
	2,				/* [7]  block count */

	0x00,				/* [8]  media code (10BASE-TX) */
	0x00,				/* [9]  general purpose port data */
	0x9E, 0x00,			/* [10] command (LSB+MSB = 0x009E) */

	0x03,				/* [8]  media code (100BASE-TX) */
	0x09,				/* [9]  general purpose port data */
	0x6D, 0x00,			/* [10] command (LSB+MSB = 0x006D) */
};

static uchar* leaf21140[] = {
	en1207,				/* Accton EN1207-COMBO */
	ana6910fx,			/* Adaptec (Cogent) ANA-6910FX */
	smc9332,			/* SMC 9332 */
	nil,
};

static int
srom(Ctlr* ctlr)
{
	int i, k, oui, phy, x;
	uchar *p;

	/*
	 * This is a partial decoding of the SROM format described in
	 * 'Digital Semiconductor 21X4 Serial ROM Format, Version 4.05,
	 * 2-Mar-98'. Only the 2114[03] are handled, support for other
	 * controllers can be added as needed.
	 */
	for(i = 0; i < sizeof(ctlr->srom)/2; i++){
		x = sromr(ctlr, i);
		ctlr->srom[2*i] = x;
		ctlr->srom[2*i+1] = x>>8;
	}

	/*
	 * There are 2 SROM layouts:
	 *	e.g. Digital EtherWORKS	station address at offset 20;
	 *				this complies with the 21140A SROM
	 *				application note from Digital;
	 * 	e.g. SMC9332		station address at offset 0 followed by
	 *				2 additional bytes, repeated at offset
	 *				6; the 8 bytes are also repeated in
	 *				reverse order at offset 8.
	 * To check which it is, read the SROM and check for the repeating
	 * patterns of the non-compliant cards; if that fails use the one at
	 * offset 20.
	 */
	ctlr->sromea = ctlr->srom;
	for(i = 0; i < 8; i++){
		x = ctlr->srom[i];
		if(x != ctlr->srom[15-i] || x != ctlr->srom[16+i]){
			ctlr->sromea = &ctlr->srom[20];
			break;
		}
	}

	/*
	 * Next, try to find the info leaf in the SROM for media detection.
	 * If it's a non-conforming card try to match the vendor ethernet code
	 * and point p at a fake info leaf with compact 21140 entries.
	 */
	if(ctlr->sromea == ctlr->srom){
		p = nil;
		for(i = 0; leaf21140[i] != nil; i++){
			if(memcmp(leaf21140[i], ctlr->sromea, 3) == 0){
				p = &leaf21140[i][4];
				break;
			}
		}
		if(p == nil)
			return -1;
	}
	else
		p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]];

	/*
	 * Set up the info needed for later media detection.
	 * For the 21140, set the general-purpose mask in CSR12.
	 * The info block entries are stored in order of increasing
	 * precedence, so detection will work backwards through the
	 * stored indexes into ctlr->srom.
	 * If an entry is found which matches the selected connection
	 * type, save the index. Otherwise, start at the last entry.
	 * If any MII entries are found (type 1 and 3 blocks), scan
	 * for PHYs.
	 */
	ctlr->leaf = p;
	ctlr->sct = *p++;
	ctlr->sct |= *p++<<8;
	if(ctlr->pcidev->did == 0x0009){
		csr32w(ctlr, 12, Gpc|*p++);
		delay(200);
	}
	ctlr->k = *p++;
	if(ctlr->k >= nelem(ctlr->infoblock))
		ctlr->k = nelem(ctlr->infoblock)-1;
	ctlr->sctk = ctlr->k-1;
	phy = 0;
	for(k = 0; k < ctlr->k; k++){
		ctlr->infoblock[k] = p;
		/*
		 * The RAMIX PMC665 has a badly-coded SROM,
		 * hence the test for 21143 and type 3.
		 */
		if((*p & 0x80) || (ctlr->pcidev->did == 0x0019 && *(p+1) == 3)){
			*p |= 0x80;
			if(*(p+1) == 1 || *(p+1) == 3)
				phy = 1;
			if(*(p+1) == 5)
				ctlr->type5block = p;
			p += (*p & ~0x80)+1;
		}
		else{
			debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
				p[0], p[1], p[2], p[3]); 
			if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
				ctlr->sctk = k;
			p += 4;
		}
	}
	ctlr->curk = ctlr->sctk;
	debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n",
		ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy);

	if(phy){
		x = 0;
		for(k = 0; k < nelem(ctlr->phy); k++){
			if((oui = miir(ctlr, k, 2)) == -1 || oui == 0)
				continue;
			if(DEBUG){
				oui = (oui & 0x3FF)<<6;
				oui |= miir(ctlr, k, 3)>>10;
				miir(ctlr, k, 1);
				debug("phy%d: index %d oui %uX reg1 %uX\n",
					x, k, oui, miir(ctlr, k, 1));
				USED(oui);
			}
			ctlr->phy[x] = k;
		}
	}

	ctlr->fd = 0;
	ctlr->medium = -1;

	return 0;
}

static void
dec2114xpci(void)
{
	Ctlr *ctlr;
	Pcidev *p;
	int x;

	p = nil;
	while(p = pcimatch(p, 0x1011, 0)){
		switch(p->did){
		default:
			continue;

		case 0x0019:		/* 21143 */
			/*
			 * Exit sleep mode.
			 */
			x = pcicfgr32(p, 0x40);
			x &= ~0xc0000000;
			pcicfgw32(p, 0x40, x);
			/*FALLTHROUGH*/

		case 0x0009:		/* 21140 */
			break;
		}

		/*
		 * bar[0] is the I/O port register address and
		 * bar[1] is the memory-mapped register address.
		 */
		ctlr = malloc(sizeof(Ctlr));
		ctlr->port = p->mem[0].bar & ~0x01;
		ctlr->pcidev = p;

		/*
		 * Some cards (e.g. ANA-6910FX) seem to need the Ps bit
		 * set or they don't always work right after a hardware
		 * reset.
		 */
		csr32w(ctlr, 6, Mbo|Ps);
		softreset(ctlr);

		if(srom(ctlr)){
			free(ctlr);
			break;
		}

		if(ctlrhead != nil)
			ctlrtail->next = ctlr;
		else
			ctlrhead = ctlr;
		ctlrtail = ctlr;
	}
}

static int
reset(Ether* ether)
{
	Ctlr *ctlr;
	int i, x;
	uchar ea[Eaddrlen];
	static int scandone;

	if(scandone == 0){
		dec2114xpci();
		scandone = 1;
	}

	/*
	 * Any adapter matches if no ether->port is supplied,
	 * otherwise the ports must match.
	 */
	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
		if(ctlr->active)
			continue;
		if(ether->port == 0 || ether->port == ctlr->port){
			ctlr->active = 1;
			break;
		}
	}
	if(ctlr == nil)
		return -1;

	ether->ctlr = ctlr;
	ether->port = ctlr->port;
	ether->irq = ctlr->pcidev->intl;
	ether->tbdf = ctlr->pcidev->tbdf;

	/*
	 * Check if the adapter's station address is to be overridden.
	 * If not, read it from the EEPROM and set in ether->ea prior to
	 * loading the station address in the hardware.
	 */
	memset(ea, 0, Eaddrlen);
	if(memcmp(ea, ether->ea, Eaddrlen) == 0)
		memmove(ether->ea, ctlr->sromea, Eaddrlen);

	/*
	 * Look for a medium override in case there's no autonegotiation
	 * (no MII) or the autonegotiation fails.
	 */
	for(i = 0; i < ether->nopt; i++){
		if(cistrcmp(ether->opt[i], "FD") == 0){
			ctlr->fd = 1;
			continue;
		}
		for(x = 0; x < nelem(mediatable); x++){
			debug("compare <%s> <%s>\n", mediatable[x],
				ether->opt[i]);
			if(cistrcmp(mediatable[x], ether->opt[i]))
				continue;
			ctlr->medium = x;
	
			switch(ctlr->medium){
			default:
				ctlr->fd = 0;
				break;
	
			case 0x04:		/* 10BASE-TFD */
			case 0x05:		/* 100BASE-TXFD */
			case 0x08:		/* 100BASE-FXFD */
				ctlr->fd = 1;
				break;
			}
			break;
		}
	}

	ether->mbps = media(ether, 1);

	/*
	 * Initialise descriptor rings, ethernet address.
	 */
	ctlr->nrdr = Nrde;
	ctlr->ntdr = Ntde;
	pcisetbme(ctlr->pcidev);
	ctlrinit(ether);

	/*
	 * Linkage to the generic ethernet driver.
	 */
	ether->attach = attach;
	ether->transmit = transmit;
	ether->interrupt = interrupt;
	ether->ifstat = ifstat;

	ether->arg = ether;
	ether->promiscuous = promiscuous;

	return 0;
}

void
ether2114xlink(void)
{
	addethercard("21140",  reset);
}

A alphapc/memmove.s => alphapc/memmove.s +197 -0
@@ 0,0 1,197 @@
#define QUAD	8
#define ALIGN	64
#define BLOCK	64

TEXT memmove(SB), $0
	MOVL	from+4(FP), R7
	MOVL	n+8(FP), R10
	MOVQ	R0, R6

	CMPUGE	R7, R0, R5
	BNE	R5, _forward

	MOVQ	R6, R8			/* end to address */
	ADDL	R10, R6, R6		/* to+n */
	ADDL	R10, R7, R7		/* from+n */

	CMPUGE	$ALIGN, R10, R1		/* need at least ALIGN bytes */
	BNE	R1, _b1tail

_balign:
	AND	$(ALIGN-1), R6, R1
	BEQ	R1, _baligned

	MOVBU	-1(R7), R2
	ADDL	$-1, R6, R6
	MOVB	R2, (R6)
	ADDL	$-1, R7, R7
	JMP	_balign
	
_baligned:
	AND	$(QUAD-1), R7, R1	/* is the source quad-aligned */
	BNE	R1, _bunaligned

	ADDL	$(BLOCK-1), R8, R9
_bblock:
	CMPUGE	R9, R6, R1
	BNE	R1, _b8tail

	MOVQ	-64(R7), R22
	MOVQ	-56(R7), R23
	MOVQ	-48(R7), R24
	MOVQ	-40(R7), R25
	MOVQ	-32(R7), R2
	MOVQ	-24(R7), R3
	MOVQ	-16(R7), R4
	MOVQ	-8(R7), R5

	SUBL	$64, R6, R6
	SUBL	$64, R7, R7

	MOVQ	R22, (R6)
	MOVQ	R23, 8(R6)
	MOVQ	R24, 16(R6)
	MOVQ	R25, 24(R6)
	MOVQ	R2, 32(R6)
	MOVQ	R3, 40(R6)
	MOVQ	R4, 48(R6)
	MOVQ	R5, 56(R6)
	JMP	_bblock

_b8tail:
	ADDL	$(QUAD-1), R8, R9
_b8block:
	CMPUGE	R9, R6, R1
	BNE	R1, _b1tail

	MOVQ	-8(R7), R2
	SUBL	$8, R6
	MOVQ	R2, (R6)
	SUBL	$8, R7
	JMP	_b8block

_b1tail:
	CMPUGE	R8, R6, R1
	BNE	R1, _ret

	MOVBU	-1(R7), R2
	SUBL	$1, R6, R6
	MOVB	R2, (R6)
	SUBL	$1, R7, R7
	JMP	_b1tail
_ret:
	RET

_bunaligned:
	ADDL	$(16-1), R8, R9

_bu8block:
	CMPUGE	R9, R6, R1
	BNE	R1, _b1tail

	MOVQU	-16(R7), R4
	MOVQU	-8(R7), R3
	MOVQU	(R7), R2
	SUBL	$16, R6
	EXTQH	R7, R2, R2
	EXTQL	R7, R3, R5
	OR	R5, R2, R11
	EXTQH	R7, R3, R3
	EXTQL	R7, R4, R4
	OR	R3, R4, R13
	MOVQ	R11, 8(R6)
	MOVQ	R13, (R6)
	SUBL	$16, R7
	JMP	_bu8block

_forward:
	ADDL	R10, R6, R8		/* end to address */

	CMPUGE	$ALIGN, R10, R1		/* need at least ALIGN bytes */
	BNE	R1, _f1tail

_falign:
	AND	$(ALIGN-1), R6, R1
	BEQ	R1, _faligned

	MOVBU	(R7), R2
	ADDL	$1, R6, R6
	ADDL	$1, R7, R7
	MOVB	R2, -1(R6)
	JMP	_falign

_faligned:
	AND	$(QUAD-1), R7, R1	/* is the source quad-aligned */
	BNE	R1, _funaligned

	SUBL	$(BLOCK-1), R8, R9
_fblock:
	CMPUGT	R9, R6, R1
	BEQ	R1, _f8tail

	MOVQ	(R7), R2
	MOVQ	8(R7), R3
	MOVQ	16(R7), R4
	MOVQ	24(R7), R5
	MOVQ	32(R7), R22
	MOVQ	40(R7), R23
	MOVQ	48(R7), R24
	MOVQ	56(R7), R25

	ADDL	$64, R6, R6
	ADDL	$64, R7, R7

	MOVQ	R2, -64(R6)
	MOVQ	R3, -56(R6)
	MOVQ	R4, -48(R6)
	MOVQ	R5, -40(R6)
	MOVQ	R22, -32(R6)
	MOVQ	R23, -24(R6)
	MOVQ	R24, -16(R6)
	MOVQ	R25, -8(R6)
	JMP	_fblock

_f8tail:
	SUBL	$(QUAD-1), R8, R9
_f8block:
	CMPUGT	R9, R6, R1
	BEQ	R1, _f1tail

	MOVQ	(R7), R2
	ADDL	$8, R6
	ADDL	$8, R7
	MOVQ	R2, -8(R6)
	JMP	_f8block

_f1tail:
	CMPUGT	R8, R6, R1
	BEQ	R1, _fret
	MOVBU	(R7), R2
	ADDL	$1, R6, R6
	ADDL	$1, R7, R7
	MOVB	R2, -1(R6)
	JMP	_f1tail

_fret:
	RET

_funaligned:
	SUBL	$(16-1), R8, R9
_fu8block:
	CMPUGT	R9, R6, R1
	BEQ	R1, _f1tail

	MOVQU	(R7), R2
	MOVQU	8(R7), R3
	MOVQU	16(R7), R4
	EXTQL	R7, R2, R2
	EXTQH	R7, R3, R5
	OR	R5, R2, R11
	EXTQL	R7, R3, R3
	MOVQ	R11, (R6)
	EXTQH	R7, R4, R4
	OR	R3, R4, R11
	MOVQ	R11, 8(R6)
	ADDL	$16, R6
	ADDL	$16, R7
	JMP	_fu8block

A alphapc/memset.s => alphapc/memset.s +61 -0
@@ 0,0 1,61 @@
TEXT memset(SB), $0
	MOVL	R0, R6
	MOVBU	data+4(FP), R2
	MOVL	n+8(FP), R10

	ADDL	R10, R0, R8

	CMPUGE	$8, R10, R1		/* need at least 8 bytes */
	BNE	R1, _1loop

	SLLQ	$8, R2, R1		/* replicate the byte */
	OR	R1, R2
	SLLQ	$16, R2, R1
	OR	R1, R2
	SLLQ	$32, R2, R1
	OR	R1, R2

_align:
	AND	$(8-1), R6, R1
	BEQ	R1, _aligned

	MOVB	R2, (R6)
	ADDL	$1, R6, R6
	JMP	_align

_aligned:
	SUBL	$(64-1), R8, R9		/* end pointer minus slop */
_64loop:
	CMPUGT	R9, R6, R1
	BEQ	R1, _8tail

	MOVQ	R2, (R6)
	MOVQ	R2, 8(R6)
	MOVQ	R2, 16(R6)
	MOVQ	R2, 24(R6)
	MOVQ	R2, 32(R6)
	MOVQ	R2, 40(R6)
	MOVQ	R2, 48(R6)
	MOVQ	R2, 56(R6)
	ADDL	$64, R6, R6
	JMP	_64loop

_8tail:
	SUBL	$(8-1), R8, R9
_8loop:
	CMPUGT	R9, R6, R1
	BEQ	R1, _1loop

	MOVQ	R2, (R6)
	ADDL	$8, R6
	JMP	_8loop

_1loop:
	CMPUGT	R8, R6, R1
	BEQ	R1, _ret
	MOVB	R2, (R6)
	ADDL	$1, R6
	JMP	_1loop

_ret:
	RET

M alphapc/pci.c => alphapc/pci.c +10 -0
@@ 349,3 349,13 @@ pcireset(void)
		pcicfgw16(p, PciPSR, pcr & ~0x04);
	}
}

void
pcisetbme(Pcidev* p)
{
	int pcr;

	pcr = pcicfgr16(p, PciPCR);
	pcr |= 0x0004;
	pcicfgw16(p, PciPCR, pcr);
}

A pc/devlml.c => pc/devlml.c +219 -0
@@ 0,0 1,219 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"io.h"

#include	"devlml.h"

// Lml 22 driver

enum{
	Q819,
	Q856,
	Qi22,
	Q060,
	Q067,
	Qstat,
	Qvideo,
	Qjframe,
};

static Dirtab viddir[]={
//	 name,		 qid,	  size,		mode
	"vid819",	{Q819},		0,		0644,
	"vid856",	{Q856},		0,		0644,
	"vidi22",	{Qi22},		0,		0644,
	"vid060",	{Q060},		0,		0644,
	"vid067",	{Q067},		0,		0644,
	"vidstat",	{Qstat},	0,		0444,
	"video",	{Qvideo},	0,		0666,
	"jframe",	{Qjframe},	0,		0666,
};

CodeData *	codeData;
MjpgDrv *	mjpgDrv;

static void lmlintr(Ureg *ur, void *arg);

static void
vidreset(void)
{
	ulong regpa;
	int i;

	codeData = (CodeData*)xspanalloc(sizeof(CodeData), BY2PG, 0);
	if (codeData == nil) {
		print("devlml: xspanalloc(%ux, %ux, 0)\n", sizeof(CodeData), BY2PG);
		return;
	}

	print("Installing Motion JPEG driver %s\n", MJPG_VERSION); 
	print("Buffer size %ux\n", sizeof(CodeData)); 

	// Get access to DMA memory buffer
	memset(codeData, 0xAA, sizeof(CodeData));
	strncpy(codeData->idString, MJPG_VERSION, strlen(MJPG_VERSION));

	for(i = 0; i < NBUF; i++) {
		codeData->statCom[i] = PADDR(&(codeData->fragmDescr[i]));
		codeData->statComInitial[i] = codeData->statCom[i];
		codeData->fragmDescr[i].fragmAddress =
			(H33_Fragment *)PADDR(&(codeData->frag[i]));
		// Length is in double words, in position 1..20
		codeData->fragmDescr[i].fragmLength = (FRAGSIZE >> 1) | FRAGM_FINAL_B;
	}

	// Get dynamic kernel memory allocaton for the driver
	if((mjpgDrv = xallocz(sizeof(MjpgDrv), 0)) == nil) {
		print("LML33: can't allocate dynamic memory for MjpgDrv\n");
		return;
	}
	if((lml33Board = xallocz(sizeof(LML33Board), 0)) == nil) {
		print("LML33: can't allocate dynamic memory for lml33Board\n");
		return;
	}

	print("initializing LML33 board...");

	lml33Board->pcidev = pcimatch(nil, PCI_VENDOR_ZORAN, PCI_DEVICE_ZORAN_36067);
	if (lml33Board->pcidev == nil) {
		print("zr36067 not found. Install aborted.\n");
		return;
	}
	lml33Board->pciPhysBaseAddr =
		(void *)(lml33Board->pcidev->mem[0].bar & ~0x0F);

	print("zr36067 found at %lux\n", lml33Board->pciPhysBaseAddr);

	regpa = upamalloc(lml33Board->pcidev->mem[0].bar & ~0x0F, lml33Board->pcidev->mem[0].size, 0);
	if (regpa == 0) {
		print("lml: failed to map registers\n");
		return;
	}
	lml33Board->pciBaseAddr = KADDR(regpa);

	// make sure the device will respond to mem accesses
	// (pcicmd_master | pcicmd_memory) -- probably superfluous
//	pcicfgw32(lml33Board->pcidev, PciPCR, 0x04 | 0x02);

	// set bus latency -- probably superfluous
//	pcicfgw8(lml33Board->pcidev, PciLTR, 64);

	// Interrupt handler
	intrenable(lml33Board->pcidev->intl, lmlintr, lml33Board, lml33Board->pcidev->tbdf);

	print("LML33 Installed\n"); 
	return; 
}

static Chan*
vidattach(char *spec)
{
	return devattach('V', spec);
}

static int
vidwalk(Chan *c, char *name)
{
	return devwalk(c, name, viddir, nelem(viddir), devgen);
}

static void
vidstat(Chan *c, char *dp)
{
	devstat(c, dp, viddir, nelem(viddir), devgen);
}

static Chan*
vidopen(Chan *c, int omode)
{
	c->aux = 0;
	switch(c->qid.path){
	case Q819:
	case Q856:
	case Qi22:
	case Q060:
	case Q067:
		// allow one open per file
		break;
	case Qstat:
		// allow many opens
		break;
	case Qvideo:
	case Qjframe:
		// allow one open total for these two
		break;
	}
	return devopen(c, omode, viddir, nelem(viddir), devgen);
}

static void
vidclose(Chan *c)
{
	switch(c->qid.path){
	case Q819:
	case Q856:
	case Qi22:
	case Q060:
	case Q067:
	case Qstat:
	case Qvideo:
	case Qjframe:
		authclose(c);
	}
}

static long
vidread(Chan *c, void *buf, long n, vlong off)
{
	switch(c->qid.path){
	case Q819:
	case Q856:
	case Qi22:
	case Q060:
	case Q067:
		return chipread(c, buf, n, off);
	case Qstat:
		return statread(c, buf, n, off);
	case Qvideo:
	case Qjframe:
		return videoread(c, buf, n, off);
	}
}

static long
vidwrite(Chan *c, void *va, long n, vlong off)
{
}

Dev viddevtab = {
	'V',
	"video",

	vidreset,
	devinit,
	vidattach,
	devclone,
	vidwalk,
	vidstat,
	vidopen,
	devcreate,
	vidclose,
	vidread,
	devbread,
	vidwrite,
	devbwrite,
	devremove,
	devwstat,
};

static void
lmlintr(Ureg *ur, void *arg)
{
	LML33Board *lml33Board = (Lml33Board *)arg;

	
}

A pc/devlml.h => pc/devlml.h +319 -0
@@ 0,0 1,319 @@
// Lml 22 driver

#define MJPG_VERSION "LML33 v0.2"

// Various minor numbers (functions) of the device
#define MJPG_MINOR_STATUS 0
#define MJPG_MINOR_VIDEO 1
#define MJPG_MINOR_FRAME 2
#define MJPG_MINOR_STILL 3

// The following values can be modified to tune/set default behaviour of the
// driver.

// The number of uS delay in I2C state transitions
#define H33_I2C_DELAY 10

// The amount of spinning to do before the I2C bus is timed out
#define H33_I2C_TIMEOUT 10000000

// The amount of spinning to do before the guest bus is timed out
#define H33_GUEST_TIMEOUT 10000000

// The amount of spinning to do before the polling of the still
// transfer port is aborted.
#define H33_STILL_TIMEOUT 1000000

// The following number is the maximum number of cards permited. Each
// card found is mapped to a device minor number starting from 0.
#define H33_MAX_CARDS 1

// The following is the number of device types supported.
#define H33_DEVICE_COUNT 2

// The number of 8K pages per buffer, we will allocate four buffers,
// locked into memory whenever the device is open so modify with care.
#define H33_PAGES 32

// The following are the datastructures needed by the device.

// A H33_Device records the properties of the various card types supported.
typedef struct {
	int		number;			// The H33_CARDTYPE_ assigned
	char	*card_name;		// A string name
	int		zr060addr;		// Which guest bus address for the ZR36060
} H33_Device;

// An entry in the fragment table
typedef struct {
	ulong	address;		// bus address of page
	int		length;			// length of page
} H33_RingPage;

// The structure that we will use to tell the '57 about the buffers
// The sizeof(H33_RingData) should not exceed page size
typedef struct {
	void			*buffer[4];
	ulong			i_stat_com[4];
	H33_RingPage	ring_pages[4][H33_PAGES];
} H33_RingData;

typedef struct {
	int		expect;			// the buffer the int routine expects next
	int		which;			// which ring buffer the read or write uses
	int		filled;			// the current number of filled buffers
	int		pages;			// the number of complete pages
	int		remainder;		// the number of bytes in incomplete page
} H33_RingPtr;

// The remainder of the #defs are constants which should not need changing.

// The PCI vendor and device ids of the zoran chipset on the dc30
// these really belong in pci.h
#define PCI_VENDOR_ZORAN				0x11de
#define PCI_DEVICE_ZORAN_36057			0x6057

// The ZR36057 is mapped into a 4Kbyte block of the address space
// starting at PCI_BASE_ADDRESS_0. Its application specific registers
// are layed out within that space as follows.
#define ZR36057_VFEND_HORCON			0x000
#define ZR36057_VFEND_VERCON			0x004
#define ZR36057_VFEND_SCLPIX			0x008
#define ZR36057_VDISP_TOP				0x00c
#define ZR36057_VDISP_BOT				0x010
#define ZR36057_VSTRD_GRB				0x014
#define ZR36057_VDISP_CONF				0x018
#define ZR36057_MASK_TOP				0x01c
#define ZR36057_MASK_BOT				0x020
#define ZR36057_OVRLY_CTL				0x024
#define ZR36057_SYS_PCI					0x028
#define ZR36057_GPIO_CTL				0x02c
#define ZR36057_MPEG_SRCW				0x030
#define ZR36057_MPEG_CTFR_CTL			0x034
#define ZR36057_MPEG_MEM_PTR			0x038
#define ZR36057_INTR_STAT				0x03c
#define ZR36057_INTR_CTL				0x040
#define ZR36057_I2C_BUS					0x044
#define ZR36057_JPEG_MODE_CTL			0x100
#define ZR36057_JPEG_PROC_CTL			0x104
#define ZR36057_VSYNC_PARM				0x108
#define ZR36057_HSYNC_PARM				0x10c
#define ZR36057_HOR_ACTIVE				0x110
#define ZR36057_VER_ACTIVE				0x114
#define ZR36057_FIELD_PROC				0x118
#define ZR36057_JPEG_CODE_BASE			0x11C
#define ZR36057_JPEG_FIFO_THRHLD		0x120
#define ZR36057_JPEG_GUESTID			0x124
#define ZR36057_GUEST_CTL				0x12c
#define ZR36057_POST_OFFICE				0x200
#define ZR36057_STILL_TRANS				0x300
// The datasheet says that STILL_TRANS is 0x140, but the errata says it's 0x300

// which bits of the ZR36057_INTR... mean something special
#define ZR36057_INTR_GIRQ1              0x40000000
#define ZR36057_INTR_GIRQ0              0x20000000
#define ZR36057_INTR_CODREP             0x10000000
#define ZR36057_INTR_JPEGREP            0x08000000
#define ZR36057_INTR_ENABLE             0x01000000


// which bits of ZR36057_I2C_BUS mean something special
#define ZR36057_POST_PEND               0x02000000
#define ZR36057_POST_TIME               0x01000000
#define ZR36057_POST_DIR                0x00800000

// function of the Guest CS outputs
#define ZR36060_GUEST_DATA              0
#define ZR36060_GUEST_START             1
#define ZR36060_GUEST_RESET             3

// the still busy bit in ZR36057_STILL_TRANS
// this assumes we are working in little endian mode
#define ZR36057_STILL_BUSY              0x80000000

// which bit of ZR36057_I2C_BUS is which
#define ZR36057_I2C_SCL                 1
#define ZR36057_I2C_SDA                 2

// The ZR36060 registers
#define ZR36060_LOAD                    0x000
#define ZR36060_FIFO_STAT               0x001
#define ZR36060_INTERFACE               0x002
#define ZR36060_MODE                    0x003
#define ZR36060_ZERO                    0x004
#define ZR36060_MBCV                    0x005
#define ZR36060_MARKERS_EN              0x006
#define ZR36060_INT_MASK                0x007
#define ZR36060_INT_STAT                0x008
#define ZR36060_TCV_NEThi               0x009
#define ZR36060_TCV_NETmh               0x00a
#define ZR36060_TCV_NETml               0x00b
#define ZR36060_TCV_NETlo               0x00c
#define ZR36060_TCV_DATAhi              0x00d
#define ZR36060_TCV_DATAmh              0x00e
#define ZR36060_TCV_DATAml              0x00f
#define ZR36060_TCV_DATAlo              0x010
#define ZR36060_SFhi                    0x011
#define ZR36060_SFlo                    0x012
#define ZR36060_AFhi                    0x013
#define ZR36060_AFme                    0x014
#define ZR36060_AFlo                    0x015
#define ZR36060_ACVhi                   0x016
#define ZR36060_ACVmh                   0x017
#define ZR36060_ACVml                   0x018
#define ZR36060_ACVlo                   0x019
#define ZR36060_ATAhi                   0x01a
#define ZR36060_ATAmh                   0x01b
#define ZR36060_ATAml                   0x01c
#define ZR36060_ATAlo                   0x01d
#define ZR36060_ACV_TRUNhi              0x01e
#define ZR36060_ACV_TRUNmh              0x01f
#define ZR36060_ACV_TRUNml              0x020
#define ZR36060_ACV_TRUNlo              0x021
#define ZR36060_DEV_ID                  0x022
#define ZR36060_DEV_REV                 0x023
#define ZR36060_TEST_1                  0x024
#define ZR36060_TEST_2                  0x025
#define ZR36060_VCR                     0x030
#define ZR36060_VPR                     0x031
#define ZR36060_SCALE                   0x032
#define ZR36060_BKG_CLR_Y               0x033
#define ZR36060_BKG_CLR_U               0x034
#define ZR36060_BKG_CLR_V               0x035
#define ZR36060_SYNC_VTOTALhi           0x036
#define ZR36060_SYNC_VTOTALlo           0x037
#define ZR36060_SYNC_HTOTALhi           0x038
#define ZR36060_SYNC_HTOTALlo           0x039
#define ZR36060_SYNC_VSIZE              0x03a
#define ZR36060_SYNC_HSIZE              0x03b
#define ZR36060_SYNC_BVSTART            0x03c
#define ZR36060_SYNC_BHSTART            0x03d
#define ZR36060_SYNC_BVENDhi            0x03e
#define ZR36060_SYNC_BVENDlo            0x03f
#define ZR36060_SYNC_BHENDhi            0x040
#define ZR36060_SYNC_BHENDlo            0x041
#define ZR36060_AA_VSTARThi             0x042
#define ZR36060_AA_VSTARTlo             0x043
#define ZR36060_AA_VENDhi               0x044
#define ZR36060_AA_VENDlo               0x045
#define ZR36060_AA_HSTARThi             0x046
#define ZR36060_AA_HSTARTlo             0x047
#define ZR36060_AA_HENDhi               0x048
#define ZR36060_AA_HENDlo               0x049
#define ZR36060_SW_VSTARThi             0x04a
#define ZR36060_SW_VSTARTlo             0x04b
#define ZR36060_SW_VENDhi               0x04c
#define ZR36060_SW_VENDlo               0x04d
#define ZR36060_SW_HSTARThi             0x04e
#define ZR36060_SW_HSTARTlo             0x04f
#define ZR36060_SW_HENDhi               0x050
#define ZR36060_SW_HENDlo               0x051

#define MB 0x100000
#define NBUF 4

#define FRAGM_FINAL_B 1
#define STAT_BIT 1

typedef struct MjpgDrv				MjpgDrv;
typedef struct H33_Fragment			H33_Fragment;
typedef struct H33_FragmentTable	H33_FragmentTable;
typedef struct CodeData				CodeData;
typedef struct ML33Board			LML33Board;

#define FRAGSIZE (MB/NBUF)

struct H33_Fragment {
	uchar	fragbytes[FRAGSIZE];
};

struct H33_FragmentTable {
	H33_Fragment *	fragmAddress;			// Physical address
	ulong			fragmLength;
};

struct CodeData {
	char				idString[16];
	ulong				statCom[4];			// Physical address
	ulong				statComInitial[4];	// Physical address
	H33_FragmentTable	fragmDescr[4];
	H33_Fragment		frag[4];
};

extern char static_MjpgDrv_GPL_Notice[];
extern struct file_operations static_MjpgDrv_fOps;

struct MjpgDrv {
	int					openCount;
	int					sleepFlag;
	struct wait_queue *	intrWaitQ;
};

#define PCI_DEVICE_ZORAN_36067 PCI_DEVICE_ZORAN_36057

struct ML33Board
{
	void *		pciPhysBaseAddr;
	void *		pciBaseAddr;
	Pcidev *	pcidev;
};

extern void *		H33Addr;
extern LML33Board *	lml33Board;

void	LML33Board_ctor(LML33Board*);
void	LML33Board_dtor(LML33Board*);
int		LML33Board_installInterruptHandler(LML33Board*);
void	LML33Board_initHardware(LML33Board*);
void	LML33Board_mjpegGo(LML33Board*);


// ZR36067 (PCI controller) register memory access
ulong	LML33Board_readL(LML33Board*,int addr);
void	LML33Board_writeL(LML33Board*,int addr,ulong);
ushort	LML33Board_readW(LML33Board*,int addr);
void	LML33Board_writeW(LML33Board*,int addr,ushort);
uchar	LML33Board_readB(LML33Board*,int addr);
void	LML33Board_writeB(LML33Board*,int addr,uchar);
int		LML33Board_getBit(LML33Board*,int addr,int);
void	LML33Board_setBit(LML33Board*,int addr,int,int);

// I2C (video encoder/decoder) manipulation functions
void	h33_i2c_pause(LML33Board*);
int		h33_i2c_waitscl(LML33Board*);
void	h33_i2c_start(LML33Board*);
void	h33_i2c_stop(LML33Board*);
void	h33_i2c_wrbit(LML33Board*,int bit);
int		h33_i2c_rdbit(LML33Board*);
int		h33_i2c_wrbyte(LML33Board*,int value);
int		h33_i2c_rdbyte(LML33Board*,int* value);
int		h33_i2c_probe(LML33Board*,int addr);
int		h33_i2c_wr8(LML33Board*,int addr, int sub, int value);
int		h33_i2c_rd8(LML33Board*,int addr, int sub, int *value);
int		h33_i2c_bt856rd8 (LML33Board*,int addr, int *msb);

// GPIO access
void	gpioSetDirection(int gpIO,int dir);
void	gpioSet(int gpIO,int value);
int		gpioGet(int gpIO);

// PostOffice access functions 
int		h33_post_idle(void);
int		h33_post_write(int guest, int reg, int value);
int		h33_post_read(int guest, int reg);

// ZR36060
void	h33_zr060_write(int reg, int value);
int		h33_zr060_read(int reg);

void	MjpgDrv_ctor(MjpgDrv*);
void	MjpgDrv_dtor(MjpgDrv*);
int		MjpgDrv_open(struct inode *iNode, struct file *filePtr);
void	MjpgDrv_release(struct inode *iNode, struct file *filePtr);
void	MjpgDrv_intrHandler(int irqNo, void *devId, struct pt_regs *ptRegs);

void *	static_CodeData_map(ulong h33PHighMemory,ulong h33BufferSize);
int		CodeData_getReadyBuffer(CodeData*);
int		CodeData_getProcessedBuffer(CodeData*this);
int		CodeData_getBuffer(CodeData *,int bufferNo,void** bufferPtr,ushort* frameNo);
int		CodeData_prepareBuffer(CodeData *, int bufferNo);

M pc/dma.c => pc/dma.c +5 -1
@@ 107,7 107,11 @@ dmainit(int chan, int maxtransfer)
		return 1;
	xp->bpa = PADDR(xp->bva);
	if(xp->bpa >= 16*MB){
		xfree(xp->bva);		/* doesn't work... */
		/*
		 * This will panic with the current
		 * implementation of xspanalloc().
		xfree(xp->bva);
		 */
		xp->bva = nil;
		return 1;
	}

M pc/main.c => pc/main.c +1 -1
@@ 144,7 144,6 @@ main(void)
	cpuidprint();
	if(isoldbcom)
		print("    ****OLD B.COM - UPGRADE****\n");
	pageinit();
	mmuinit();
	if(arch->intrinit)
		arch->intrinit();


@@ 158,6 157,7 @@ main(void)
	links();
conf.monitor = 1;
	chandevreset();
	pageinit();
	swapinit();
	userinit();
	schedinit();