~kris/9p

9hist

5bf63a04db2ab7bd233a9c949499b8a8604f8a42 — David du Colombier 33 years ago 51b7b95
Plan 9 from Bell Labs 1993-09-04
M carrera/clock.c => carrera/clock.c +1 -1
@@ 92,7 92,7 @@ clock(Ureg *ur)
		return;

	if(anyready())
		sched(); /**/
		sched();

	/* user profiling clock */
	if(ur->status & KUSER)

M carrera/dat.h => carrera/dat.h +1 -1
@@ 146,7 146,7 @@ struct KMap
};

#define	VA(k)		((k)->virt)
#define PPN(x)		((x)>>6)
#define PPN(x)		((ulong)(x)>>6)

struct Softtlb
{

M carrera/devether.c => carrera/devether.c +477 -290
@@ 8,268 8,479 @@
#include	"../port/netif.h"

/*
 *  ethernet address stored in prom
 * National Semiconductor DP83932
 * Systems-Oriented Network Interface Controller
 * (SONIC)
 */

#define SONICADDR	((Sonic*)Sonicbase)

#define RD(rn)		(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4))
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = v)

typedef struct
{
	ulong	pad0;
	ulong	byte;
	uvlong	pad1;
} Etheraddr;
#define	EPCENETPROM	EPCSWIN(Etheraddr, 0x2000)
	ulong	cr;		/* command */
	ulong	dcr;		/* data configuration */
	ulong	rcr;		/* receive control */
	ulong	tcr;		/* transmit control */
	ulong	imr;		/* interrupt mask */
	ulong	isr;		/* interrupt status */
	ulong	utda;		/* upper transmit descriptor address */
	ulong	ctda;		/* current transmit descriptor address */
	ulong	pad0x08[5];	/*  */
	ulong	urda;		/* upper receive descriptor address */
	ulong	crda;		/* current receive descriptor address */
	ulong	pad0x0F[4];	/*  */
	ulong	eobc;		/* end of buffer word count */
	ulong	urra;		/* upper receive resource address */
	ulong	rsa;		/* resource start address */
	ulong	rea;		/* resource end address */
	ulong	rrp;		/* resource read pointer */
	ulong	rwp;		/* resource write pointer */
	ulong	pad0x19[8];	/*  */
	ulong	cep;		/* CAM entry pointer */
	ulong	cap2;		/* CAM address port 2 */
	ulong	cap1;		/* CAM address port 1 */
	ulong	cap0;		/* CAM address port 0 */
	ulong	ce;		/* CAM enable */
	ulong	cdp;		/* CAM descriptor pointer */
	ulong	cdc;		/* CAM descriptor count */
	ulong	sr;		/* silicon revision */
	ulong	wt0;		/* watchdog timer 0 */
	ulong	wt1;		/* watchdog timer 1 */
	ulong	rsc;		/* receive sequence counter */
	ulong	crct;		/* CRC error tally */
	ulong	faet;		/* FAE tally */
	ulong	mpt;		/* missed packet tally */
	ulong	mdt;		/* maximum deferral timer */
	ulong	pad0x30[15];	/*  */
	ulong	dcr2;		/* data configuration 2 */
} Sonic;

enum
{
	Nrb		= 16,		/* receive buffers */
	Ntb		= 8,		/* transmit buffers */
};

enum
{
	Htx	= 0x0001,	/* halt transmission */
	Txp	= 0x0002,	/* transmit packet(s) */
	Rxdis	= 0x0004,	/* receiver disable */
	Rxen	= 0x0008,	/* receiver enable */
	Stp	= 0x0010,	/* stop timer */
	St	= 0x0020,	/* start timer */
	Rst	= 0x0080,	/* software reset */
	Rrra	= 0x0100,	/* read RRA */
	Lcam	= 0x0200,	/* load CAM */

	Dw32	= 0x0020,	/* data width select */
	Sterm	= 0x0400,	/* synchronous termination */
	Lbr	= 0x4000,	/* latched bus retry */
	Efm	= 0x0010,	/* Empty fill mode */
	W14tf	= 0x0003,	/* 14 Word transmit fifo */

	Prx	= 0x0001,	/* packet received ok */
	Fae	= 0x0004,	/* frame alignment error */
	Crc	= 0x0008,	/* CRC error */
	Lpkt	= 0x0040,	/* last packet in rba */
	Bc	= 0x0080,	/* broadcast packet received */
	Pro	= 0x1000,	/* physical promiscuous mode */
	Brd	= 0x2000,	/* accept broadcast packets */
	Rnt	= 0x4000,	/* accept runt packets */
	Err	= 0x8000,	/* accept packets with errors */

	Ptx	= 0x0001,	/* packet transmitted ok */
	Pintr	= 0x8000,	/* programmable interrupt */

	Rfo	= 0x0001,	/* receive fifo overrun */
	MpTally	= 0x0002,	/* missed packet tally counter rollover */
	FaeTally= 0x0004,	/* frame alignment error tally counter rollover */
	CrcTally= 0x0008,	/* Crc tally counter rollover */
	Rbae	= 0x0010,	/* receive buffer area exceeded */
	Rbe	= 0x0020,	/* receive buffer exhausted */
	Rde	= 0x0040,	/* receive descriptors exhausted */
	Txer	= 0x0100,	/* transmit error */
	Txdn	= 0x0200,	/* transmission done */
	Pktrx	= 0x0400,	/* packet received */
	Pint	= 0x0800,	/* programmed interrupt */
	Lcd	= 0x1000,	/* load CAM done */
	Hbl	= 0x2000,	/* CD heartbeat lost */
	Br	= 0x4000,	/* bus retry occurred */
	AllIntr	= 0x7771,	/* all of the above */
};

/*
 *  SEEQ/EDLC device registers
 * Receive Resource Descriptor.
 */
typedef struct
{
	struct
	{
	  ulong	pad;
	  ulong	byte;
	}	addr[6];	/* address */

	ulong	 pad;
	ulong	tcmd;		/* transmit command */
	ulong	 pad0;
	ulong	rcmd;		/* receive command */
	ulong	 pad1[5];
	ulong	tbaselo;	/* low bits of xmit buff base */
	ulong	 pad2;
	ulong	tbasehi;	/* high bits of xmit buff base */
	ulong	 pad3;
	ulong	tlimit;		/* xmit buffer limit */
	ulong	 pad4;
	ulong	tindex;		/* xmit buffer limit */
	ulong	 pad5;
	ulong	ttop;		/* xmit buffer top */
	ulong	 pad6;
	ulong	tbptr;		/* xmit buffer byte pointer */
	ulong	 pad7;
	ulong	tstat;		/* transmit status */
	ulong	 pad8;
	ulong	titimer;	/* transmit interrupt timer */
	ulong	 pad9[5];
	ulong	rbaselo;	/* rcv buffer base addr */
	ulong	 pad10;
	ulong	rbasehi;	/* high bits of rcv buffer base addr */
	ulong	 pad11;
	ulong	rlimit;		/* rcv buffer limit */
	ulong	 pad12;
	ulong	rindex;		/* rcv buffer index */
	ulong	 pad13;
	ulong	rtop;		/* rcv buffer top */
	ulong	 pad14;
	ulong	rbptr;		/* rcv buffer byte pointer */
	ulong	 pad15;
	ulong	rstat;		/* rcv status */
	ulong	 pad16;
	ulong	ritimer;	/* rcv interrupt timer */
} EDLCdev;
#define EPCEDLC	EPCSWIN(EDLCdev, 0xa200)
	uchar	pad0[2];
	ushort	ptr0;		/* buffer pointer in the RRA */
	uchar	pad1[2];
	ushort	ptr1;
	uchar	pad2[2];
	ushort	wc0;		/* buffer word count in the RRA */
	uchar	pad3[2];
	ushort	wc1;
} RXrsc;

/*
 *  LXT901 device registers
 * Receive Packet Descriptor.
 */
typedef struct {
	ulong	 pad0;
	ulong	stat;		/* some LXT901 pins + SQE ctrl (r/w) */
	ulong	 pad1;
	ulong	collisions;	/* total collisions -- 16 bits (r) */
	uchar	 pad2[7];
	uchar	loopback;	/* loopback enable -- 1 bit (w) */
	ulong	 pad3;
	ulong	edlcself;	/* EDLC self rcv enable -- 1 bit (w) */
} LXTdev;
#define EPCLXT	EPCSWIN(LXTdev, 0x8000)

enum
typedef struct
{
	/* transmit command bits */
	Tigood=		1<<3,		/* interrupt on good xmit */
	Ti16tries=	1<<2,		/* interrupt on 16 retries */
	Ticoll=		1<<1,		/* interrupt on collision */
	Tiunder=	1<<0,		/* interrupt on underflow */

	/* receive command bits */
	Rmulti=		3<<6,		/* recv station/broadcast/multicast */
	Rnormal=	2<<6,		/* recv station/broadcast */
	Rall=		1<<6,		/* receive all frames */
	Rigood=		1<<5,	 	/* interrupt on good frames */
	Riend=		1<<4,		/* interrupt on end of frame */
	Rishort=	1<<3,		/* interrupt on short frame */
	Ridrbl=		1<<2,		/* interrupt on dribble error */
	Ricrc=		1<<1,		/* interrupt on CRC error */
	Riover=		1<<0,		/* interrupt on overflow error */

	Renab=		(Rigood|Riend|Rishort|Ridrbl|Ricrc),

	/* receive status bits */
	Rgood=		1<<5,		/* good frame */
	Rend=		1<<4,		/* end of frame */
	Rshort=		1<<3,		/* short frame */
	Rdrbl=		1<<2,		/* dribble error */
	Rcrc=		1<<1,		/* CRC error */
	Rover=		1<<0,		/* overflow error */

	/* interrupt level for ether */
	ILenet=		0x60,

	/* manifest constants */
	logNxmt=	8,
	Nxmt=		1<<logNxmt,
	Tmask=		Nxmt-1,
	logNrcv=	8,
	Nrcv=		1<<logNrcv,
	Rmask=		Nrcv-1,
	Ntypes=		8,

	/* hold off values */
	ho800us=	0x100,	/* 800 us hold-off */
	ho1500us=	0x080,	/* 1500 us hold-off */
	ho2500us=	0x000,	/* 2500 us hold-off */
};

#define RSUCC(i)	(((i)+1)&Rmask)
#define RPREV(i)	(((i)-1)&Rmask)
#define TSUCC(i)	(((i)+1)&Tmask)
#define TPREV(i)	(((i)-1)&Tmask)
	uchar	pad0[2];
	ushort	status;		/* receive status */
	uchar	pad1[2];
	ushort	count;		/* packet byte count */
	uchar	pad2[2];
	ushort	ptr0;		/* buffer pointer */
	uchar	pad3[2];
	ushort	ptr1;
	uchar	pad4[2];
	ushort	seqno;		/*  */
	uchar	pad5[2];
	ushort	link;		/* descriptor link and EOL */
	uchar	pad6[2];
	ushort	owner;		/* in use */
} RXpkt;

/*
 *  a hardware packet buffer
 * Transmit Packet Descriptor.
 */
typedef struct
{
	uchar	tlen[2];	/* transmit length */
	uchar	d[Eaddrlen];
	uchar	s[Eaddrlen];
	uchar	type[2];
	uchar	data[1500];
	uchar	pad1[2043-ETHERMAXTU];
	uchar	stat;
	uchar	rlen[2];	/* receive length */
} Pbuf;
	uchar	pad0[2];
	ushort	status;		/* transmit status */
	uchar	pad1[2];
	ushort	config;		/*  */
	uchar	pad2[2];
	ushort	size;		/* byte count of entire packet */
	uchar	pad3[2];
	ushort	count;		/* fragment count */
	uchar	pad4[2];
	ushort	ptr0;		/* packet pointer */
	uchar	pad5[2];
	ushort	ptr1;
	uchar	pad6[2];
	ushort	fsize;		/* fragment size */
	uchar	pad7[2];
	ushort	link;		/* descriptor link */
} TXpkt;

enum{
	Eol		= 1,	/* end of list bit in descriptor link */
	Host		= 0,	/* descriptor belongs to host */
	Interface	= -1,	/* descriptor belongs to interface */

	Nether		= 1,
	Ntypes=		8,
};

/*
 * CAM Descriptor
 */
typedef struct {
	uchar	pad0[2];
	ushort	cep;		/* CAM entry pointer */
	uchar	pad1[2];
	ushort	cap0;		/* CAM address port 0 */
	uchar	pad2[2];
	ushort	cap1;		/* CAM address port 1 */
	uchar	pad3[2];
	ushort	cap2;		/* CAM address port 2 */
	uchar	pad4[2];
	ushort	ce;		/* CAM enable */
} Cam;

typedef struct Ether Ether;
struct Ether
{
	uchar	ea[6];
	uchar	ba[6];

	int	rindex;		/* first rcv buffer owned by hardware */
	int	rtop;		/* first rcv buffer owned by software */
	int	tindex;		/* first rcv buffer owned by hardware */
	int	ttop;		/* first rcv buffer owned by software */

	Pbuf	*tbuf;		/* transmit buffers */
	Pbuf	*rbuf;		/* receive buffers */
	Sonic	*sonic;		/* SONIC registers */

	QLock	tlock;		/* lock for grabbing transmitter queue */
	Rendez	tr;		/* wait here for free xmit buffer */
	int	th;		/* first transmit buffer owned by host */	
	int	ti;		/* first transmit buffer owned by interface */

	int	rh;		/* first receive buffer owned by host */
	int	ri;		/* first receive buffer owned by interface */

	RXrsc	rra[Nrb];	/* receive resource area */
	RXpkt	rda[Nrb];	/* receive descriptor area */
	uchar	rb[Nrb][sizeof(Etherpkt)+4];	/* receive buffer area */
	TXpkt	tda[Ntb];	/* transmit descriptor area */
	uchar	tb[Ntb][sizeof(Etherpkt)];	/* transmit buffer area */
	Cam	cda;		/* CAM descriptor area */

	Netif;
} ether;
};

Ether *ether[Nether];

#define NEXT(x, l)	(((x)+1)%(l))
#define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1)
#define LS16(addr)	(PADDR(addr) & 0xFFFF)
#define MS16(addr)	((PADDR(addr)>>16) & 0xFFFF)

/*
 *  The dance in this code is very dangerous to change.  Do not
 *  change the order of any of the labeled steps.  This should run splhi.
 */
static void
etherhardreset(void)
reset(Ether *ctlr)
{
	EDLCdev *edlc = EPCEDLC;
	LXTdev *lxt = EPCLXT;
	EPCmisc *misc = EPCMISC;
	ulong x, i;

	/* step 1: isolate from ether */
	lxt->loopback = 1;
	x = lxt->loopback; USED(x);

	/* step 2: shut off transmitter */
	while(edlc->ttop != edlc->tindex)
		edlc->ttop = edlc->tindex;
	ether.tindex = ether.ttop = edlc->ttop;

	/* step 3: reset edlc */
	misc->set = 0x200;
	x = misc->reset; USED(x);
	delay(1);	/* 1ms but 10micros is enough */
	misc->clr = 0x200;
	x = misc->reset; USED(x);

	/* step 4: enable transmitter interrupts */
	edlc->tcmd = Tigood | Ti16tries | Ticoll | Tiunder;

	/* step 5: set address from prom, start receiver,
	 * and reset receive pointer
	int i;

iprint("reset sonic dcr=#%lux mydcr=#%lux\n", RD(dcr), Sterm|Dw32|Lbr|Efm|W14tf);
	/*
	 * Reset the SONIC, toggle the Rst bit.
	 * Set the data config register for synchronous termination
	 * and 32-bit data-path width.
	 * Clear the descriptor and buffer area.
	 */
	WR(cr, Rst);
	WR(dcr, Sterm|Dw32|Lbr|Efm|W14tf);
	WR(cr, 0);

	/*
	 * Initialise the receive resource area (RRA) and
	 * the receive descriptor area (RDA).
	 *
	 * We use a simple scheme of one packet per descriptor.
	 * We achieve this by setting the EOBC register to be
	 * 2 (16-bit words) less than the buffer size;
	 * thus the size of the receive buffers must be sizeof(Etherpkt)+4.
	 * Set up the receive descriptors as a ring.
	 */
	for(i = 0; i < Netheraddr; i++)
		edlc->addr[i].byte = EPCENETPROM[5-i].byte & 0xff;
	for(i = 0; i < Nrb; i++){
		ctlr->rra[i].wc0 = (sizeof(ctlr->rb[0])/2) & 0xFFFF;
		ctlr->rra[i].wc1 = ((sizeof(ctlr->rb[0])/2)>>16) & 0xFFFF;

	if(ether.prom)
		edlc->rcmd = Renab | Rall;
	else
		edlc->rcmd = Renab | Rnormal;
		ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]);
		ctlr->rda[i].owner = Interface;

		ctlr->rra[i].ptr0 = ctlr->rda[i].ptr0 = LS16(ctlr->rb[i]);
		ctlr->rra[i].ptr1 = ctlr->rda[i].ptr1 = MS16(ctlr->rb[i]);
	}

	/*
	 * Terminate the receive descriptor ring
	 * and load the SONIC registers to describe the RDA.
	 */
	ctlr->rda[Nrb-1].link |= Eol;

	WR(crda, LS16(ctlr->rda));
	WR(urda, MS16(ctlr->rda));
	WR(eobc, sizeof(ctlr->rb[0])/2 - 2);

	/*
	 * Load the SONIC registers to describe the RRA.
	 * We set the rwp to beyond the area delimited by rsa and
	 * rea. This means that since we've already allocated all
	 * the buffers, we'll never get a 'receive buffer area
	 * exhausted' interrupt and the rrp will just wrap round.
	 * Tell the SONIC to load the RRA and wait for
	 * it to complete.
	 */
	WR(urra, MS16(&ctlr->rra[0]));
	WR(rsa, LS16(&ctlr->rra[0]));
	WR(rrp, LS16(&ctlr->rra[0]));
	WR(rea, LS16(&ctlr->rra[Nrb]));
	WR(rwp, LS16(&ctlr->rra[Nrb+1]));

iprint("wait rra\n");
	WR(cr, Rrra);
	while(RD(cr) & Rrra)
		;
iprint("rra done\n");

	/*
	 * Initialise the transmit descriptor area (TDA).
	 * Each descriptor describes one packet, we make no use
	 * of having the packet in multiple fragments.
	 * The descriptors are linked in a ring; overlapping transmission
	 * with buffer queueing will cause some packets to
	 * go out back-to-back.
	 *
	 * Load the SONIC registers to describe the TDA.
	 */
	for(i = 0; i < Ntb; i++){
		ctlr->tda[i].status = Host;
		ctlr->tda[i].config = 0;
		ctlr->tda[i].count = 1;
		ctlr->tda[i].ptr0 = LS16(ctlr->tb[i]);
		ctlr->tda[i].ptr1 = MS16(ctlr->tb[i]);
		ctlr->tda[i].link = LS16(&ctlr->tda[NEXT(i, Ntb)]);
	}

	ether.rindex = edlc->rindex;
	ether.rtop = edlc->rtop = RPREV(ether.rindex);
	WR(ctda, LS16(&ctlr->tda[0]));
	WR(utda, MS16(&ctlr->tda[0]));

	/* step 6: attach to ether */
	lxt->loopback = 0;
	/*
	 * Initialise the software receive and transmit
	 * ring indexes.
	 */
	ctlr->rh = 0;
	ctlr->ri = 0;
	ctlr->th = 0;
	ctlr->ti = 0;

	/*
	 * Initialise the CAM descriptor area (CDA).
	 * We only have one ethernet address to load,
	 * broadcast is defined by the SONIC as all 1s.
	 *
	 * Load the SONIC registers to describe the CDA.
	 * Tell the SONIC to load the CDA and wait for it
	 * to complete.
	 */
	ctlr->cda.cep = 0;
	ctlr->cda.cap0 = (ctlr->ea[1]<<8)|ctlr->ea[0];
	ctlr->cda.cap1 = (ctlr->ea[3]<<8)|ctlr->ea[2];
	ctlr->cda.cap2 = (ctlr->ea[5]<<8)|ctlr->ea[4];
	ctlr->cda.ce = 1;

	WR(cdp, LS16(&ctlr->cda));
	WR(cdc, 1);

	WR(cr, Lcam);
	while(RD(cr) & Lcam)
		;

	/*
	 * Configure the receive control, transmit control
	 * and interrupt-mask registers.
	 * The SONIC is now initialised, but not enabled.
	 */
	WR(rcr, Err|Rnt|Brd);
	WR(tcr, 0);
	WR(imr, AllIntr);
iprint("reset done\n");
}

void
etherintr(void)
{
	EDLCdev *edlc = EPCEDLC;
	EPCmisc *misc = EPCMISC;
	Netfile *f, **fp;
	Pbuf *p;
	int x;
	ushort t;
	Ether *ctlr;
	ulong status;
	TXpkt *txpkt;
	RXpkt *rxpkt;
	Etherpkt *p;
	Netfile *f, **fp;

	ctlr = ether[0];

	while(edlc->rindex != ether.rindex){
		p = &ether.rbuf[ether.rindex];

		/* statistics */
		if(p->stat & (Rshort|Rdrbl|Rcrc|Rover)){
			if(p->stat & (Rdrbl|Rcrc))
				ether.crcs++;
			if(p->stat & Rover)
				ether.overflows++;
			if(p->stat & Rshort)
				ether.frames++;
	for(;;) {
		status = RD(isr) & AllIntr;
		if(status == 0)
			break;

		WR(isr, status);
	
		/*
		 * Transmission complete, for good or bad.
		 */
		if(status & (Txdn|Txer)){
			txpkt = &ctlr->tda[ctlr->ti];
			while(txpkt->status != Host){
				if(txpkt->status == Interface){
					WR(ctda, LS16(txpkt));
					WR(cr, Txp);
					break;
				}
	
				if((txpkt->status & Ptx) == 0)
					ctlr->oerrs++;
	
				txpkt->status = Host;
				ctlr->ti = NEXT(ctlr->ti, Ntb);
				txpkt = &ctlr->tda[ctlr->ti];
			}
			status &= ~(Txdn|Txer);
		}
		if(p->stat & Rgood){
			x = (p->rlen[0]<<8) | p->rlen[1];
			t = (p->type[0]<<8) | p->type[1];
			for(fp = ether.f; fp < &ether.f[Ntypes]; fp++){
				f = *fp;
				if(f == 0)
					continue;
				if(f->type == t || f->type < 0)
					qproduce(f->in, p->d, x);

		if((status & (Pktrx|Rde)) == 0)
			goto noinput;

		/*
		 * A packet arrived or we ran out of descriptors.
		 */
		status &= ~(Pktrx|Rde);
		rxpkt = &ctlr->rda[ctlr->rh];
		while(rxpkt->owner == Host){
			ctlr->inpackets++;
	
			/*
			 * If the packet was received OK, pass it up,
			 * otherwise log the error.
			 * SONIC gives us the CRC in the packet, so
			 * remember to subtract it from the length.
			 */

			if(rxpkt->status & Prx) {
				x = (rxpkt->count & 0xFFFF)-4;
				p = (Etherpkt*)ctlr->rb[ctlr->rh];
				t = (p->type[0]<<8) | p->type[1];
				for(fp = ctlr->f; fp < &ctlr->f[Ntypes]; fp++){
					f = *fp;
					if(f == 0)
						continue;
					if(f->type == t || f->type < 0)
						qproduce(f->in, p->d, x);
				}
			}
			else
			if(rxpkt->status & Fae)
				ctlr->frames++;
			else
			if(rxpkt->status & Crc)
				ctlr->crcs++;
			else
				ctlr->buffs++;
	
			/*
			 * Finished with this packet, it becomes the
			 * last free packet in the ring, so give it Eol,
			 * and take the Eol bit off the previous packet.
			 * Move the ring index on.
			 */
			rxpkt->link |= Eol;
			rxpkt->owner = Interface;
			ctlr->rda[PREV(ctlr->rh, Nrb)].link &= ~Eol;
			ctlr->rh = NEXT(ctlr->rh, Nrb);
	
			rxpkt = &ctlr->rda[ctlr->rh];
		}
		status &= ~(Pktrx|Rde);

	noinput:
		/*
		 * We get a 'load CAM done' interrupt
		 * after initialisation. Ignore it.
		 */
		if(status & Lcd)
			status &= ~Lcd;
	
		/*
		 *  because of a chip bug, we have to reset if rtop
		 *  and rindex get too close.
		 * Warnings that something is afoot.
		 */
		x = edlc->rtop - edlc->rindex;
		if(x < 0)
			x += Nrcv;
		if(x <= 64){
			etherhardreset();
		} else {
			edlc->rtop = ether.rindex;
			ether.rindex = RSUCC(ether.rindex);
		if(status & Hbl){
			print("sonic: cd heartbeat lost\n");
			status &= ~Hbl;
		}
		if(status & Br){
			print("sonic: bus retry occurred\n");
			status &= ~Br;
		}
	
		if(status & AllIntr)
			print("sonic %ux\n", status);
	}
	/* reenable holdoff and EPC interrupts */
	misc->clr = 0x10;
	misc->set = 0x10;
	epcenable(EIenet);
}

/*


@@ 278,75 489,45 @@ etherintr(void)
static void
promiscuous(void *arg, int on)
{
	EDLCdev *edlc = EPCEDLC;
	ushort reg;

	USED(arg);

	reg = RD(rcr);
	if(on)
		edlc->rcmd = Renab | Rall;
		WR(rcr, reg|Pro);
	else
		edlc->rcmd = Renab | Rnormal;
		WR(rcr, reg&~Pro);
}

void
etherreset(void)
{
	EDLCdev *edlc = EPCEDLC;
	EPCmisc *misc = EPCMISC;
	ulong x, i;

	/* setup xmit buffers (pointers on chip assume KSEG0) */
	edlc->tlimit = logNxmt - 1;
	ether.tbuf = xspanalloc(Nxmt*sizeof(Pbuf), 512*1024, 0);
	x = ((ulong)ether.tbuf) & ~KSEGM;
	edlc->tbasehi = 0;
	edlc->tbaselo = x;

	/* setup rcv buffers (pointers on chip assume KSEG0) */
	edlc->rlimit = logNrcv - 1;
	ether.rbuf = xspanalloc(Nrcv*sizeof(Pbuf), 512*1024, 0);
	x = ((ulong)ether.rbuf) & ~KSEGM;
	edlc->rbasehi = 0;
	edlc->rbaselo = x;

	/* install interrupt handler */
	sethandler(ILenet, etherintr);
	setleveldest(ILenet, 0, &EPCINTR->enetdest);
	epcenable(EIenet);

	/* turn off receive */
	edlc->rcmd = 0;

	/* stop transmitter, we can't change tindex so we change ttop */
	while(edlc->ttop != edlc->tindex)
		edlc->ttop = edlc->tindex;
	ether.tindex = ether.ttop = edlc->ttop;

	/* enable transmitter interrupts */
	edlc->tcmd = Tigood | Ti16tries | Ticoll | Tiunder;

	/* set address from prom, start receiver, and reset receive pointer */
	for(i = 0; i < Netheraddr; i++){
		ether.ea[i] = EPCENETPROM[5-i].byte & 0xff;
		edlc->addr[i].byte = ether.ea[i];
	Ether *ctlr;

	/*
	 * Map the device registers and allocate
	 * memory for the receive/transmit rings.
	 * Set the physical ethernet address and
	 * prime the interrupt handler.
	 */
	if(ether[0] == 0) {
		ether[0] = xspanalloc(sizeof(Ether), BY2PG, 64*1024);
/*		memmove(ether[0]->ea, eeprom.ea, sizeof(ether[0]->ea)); */
	}
	ether.rindex = edlc->rindex;
	ether.rtop = edlc->rtop = RPREV(ether.rindex);
	ctlr = ether[0];

	edlc->rcmd = Renab | Rnormal;
	reset(ctlr);

	/* set hold off timer value, and enable its interrupts (pulse) */
	misc->set = ho800us;
	misc->clr = (~ho800us)&0x180;
	misc->clr = 0x10;
	misc->set = 0x10;
	memset(ctlr->ba, 0xFF, sizeof(ctlr->ba));

	/* general network interface structure */
	netifinit(&ether, "ether", Ntypes, 32*1024);
	ether.alen = 6;
	memmove(ether.addr, ether.ea, 6);
	memmove(ether.bcast, etherbcast, 6);
	ether.promiscuous = promiscuous;
	ether.arg = &ether;
	netifinit(ether[0], "ether", Ntypes, 32*1024);
	ether[0]->alen = 6;
	memmove(ether[0]->addr, ether[0]->ea, 6);
	memmove(ether[0]->bcast, ctlr->ba, 6);
	ether[0]->promiscuous = promiscuous;
	ether[0]->arg = ether[0];
}

void


@@ 369,13 550,13 @@ etherclone(Chan *c, Chan *nc)
int
etherwalk(Chan *c, char *name)
{
	return netifwalk(&ether, c, name);
	return netifwalk(ether[0], c, name);
}

Chan*
etheropen(Chan *c, int omode)
{
	return netifopen(&ether, c, omode);
	return netifopen(ether[0], c, omode);
}

void


@@ 387,30 568,29 @@ ethercreate(Chan *c, char *name, int omode, ulong perm)
void
etherclose(Chan *c)
{
	netifclose(&ether, c);
	netifclose(ether[0], c);
}

long
etherread(Chan *c, void *buf, long n, ulong offset)
{
	return netifread(&ether, c, buf, n, offset);
	return netifread(ether[0], c, buf, n, offset);
}

static int
isoutbuf(void *arg)
{
	EDLCdev *edlc = arg;
	Ether *ctlr = arg;

	USED(arg);
	ether.tindex = edlc->tindex;
	return TSUCC(ether.ttop) != ether.tindex;
	return ctlr->tda[ctlr->th].status == Host;
}

long
etherwrite(Chan *c, void *buf, long n, ulong offset)
{
	Pbuf *p;
	EDLCdev *edlc = EPCEDLC;
	Etherpkt *p;
	TXpkt *txpkt;
	Ether *ctlr = ether[0];

	USED(offset);



@@ 419,27 599,34 @@ etherwrite(Chan *c, void *buf, long n, ulong offset)

	/* etherif.c handles structure */
	if(NETTYPE(c->qid.path) != Ndataqid)
		return netifwrite(&ether, c, buf, n);
		return netifwrite(ether[0], c, buf, n);

	/* we handle data */
	qlock(&ether.tlock);
	tsleep(&ether.tr, isoutbuf, edlc, 10000);
	if(!isoutbuf(edlc)){
	qlock(&ctlr->tlock);
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000);
	if(!isoutbuf(ctlr)){
		print("ether transmitter jammed\n");
	} else {
		p = &ether.tbuf[ether.ttop];
	}
	else {
		p =(Etherpkt*)ctlr->tb[ctlr->th];
		memmove(p->d, buf, n);
		if(n < 60) {
			memset(p->d+n, 0, 60-n);
			n = 60;
		}
		memmove(p->s, ether.ea, sizeof(ether.ea));
		p->tlen[0] = n;
		p->tlen[1] = n>>8;
		ether.ttop = TSUCC(ether.ttop);
		edlc->ttop = ether.ttop;
		memmove(p->s, ctlr->ea, sizeof(ctlr->ea));

		txpkt = &ctlr->tda[ctlr->th];
		txpkt->size = n;
		txpkt->fsize = n;
		txpkt->link |= Eol;
		txpkt->status = Interface;
		ctlr->tda[PREV(ctlr->th, Ntb)].link &= ~Eol;

		ctlr->th = NEXT(ctlr->th, Ntb);
		WR(cr, Txp);
	}
	qunlock(&ether.tlock);
	qunlock(&ctlr->tlock);
	return n;
}



@@ 452,11 639,11 @@ etherremove(Chan *c)
void
etherstat(Chan *c, char *dp)
{
	netifstat(&ether, c, dp);
	netifstat(ether[0], c, dp);
}

void
etherwstat(Chan *c, char *dp)
{
	netifwstat(&ether, c, dp);
	netifwstat(ether[0], c, dp);
}

M carrera/faultmips.c => carrera/faultmips.c +1 -1
@@ 122,7 122,7 @@ faultmips(Ureg *ur, int user, int code)
	addr &= ~(BY2PG-1);
	read = !(code==CTLBM || code==CTLBS);

/*	print("fault: %s code %d va %lux pc %lux r31 %lux %lux\n", up->text, code, ur->badvaddr, ur->pc, ur->r31, tlbvirt());/**/
	print("fault: %s code %d va %lux pc %lux r31 %lux %lux\n", up->text, code, ur->badvaddr, ur->pc, ur->r31, tlbvirt());/**/

	if(fault(addr, read) == 0)
		return;

M carrera/fns.h => carrera/fns.h +2 -3
@@ 4,7 4,6 @@ void	DEBUG(void);

void	addportintr(int(*)(void));
void	allflush(void*, ulong);
void	audiointr(void);
void	arginit(void);
int	busprobe(ulong);
void	cleancache(void);


@@ 19,7 18,6 @@ void	consoff(void);
int	consputc(int);
void	dcflush(void*, ulong);
void	dcinvalidate(void*, ulong);
void	devportintr(void);
void	epcenable(ulong);
void	epcinit(int, int);
void	evenaddr(ulong);


@@ 55,7 53,6 @@ void	kunmap(KMap*);
void	launchinit(void);
void	launch(int);
void	lightbits(int, int);
void	lptintr(void);
ulong	machstatus(void);
void	mmunewpage(Page*);
void	mntdump(void);


@@ 107,6 104,8 @@ void	Xdelay(int);

void	NS16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
void	NS16552setup(ulong, ulong);
void	NS16552intr(int);
void	etherintr(void);

#define	waserror()	setlabel(&up->errlab[up->nerrlab++])
#define	kmapperm(x)	kmap(x)

M carrera/io.h => carrera/io.h +16 -5
@@ 9,7 9,7 @@ enum
	Clockbase	= 0xE0004000,	
	Uart0		= 0xE0006000,	
	Uart1		= 0xE0007000,	
	  UartFREQ	= 4233600,
	  UartFREQ	= 8000000,
	Centronics	= 0xE0008000,
	Nvram		= 0xE0009000, 	
	NvramRW		= 0xE000A000,


@@ 21,8 21,19 @@ enum
	Diag		= 0xE000F000,
	VideoCTL	= 0x60000000,	
	VideoMEM	= 0x40000000, 	
	EisaIO		= 0xE2000000,	
	EisaMEM		= 0xE3000000,
	PromMEM		= 0xE1000000,   	
	Intctl		= 0xE0100000,
	I386ack		= 0xE000023f,
	Intctlphys	= 0xF0000000,	
	Intctlvirt	= 0xE0040000,
	  Uart1int	= (1<<9),
	  Uart0int	= (1<<8),
	  Mouseint	= (1<<7),
	  Keybint	= (1<<6),
	  Scsiint	= (1<<5),
	  Etherint	= (1<<4),
	  Videoint	= (1<<3),
	  Soundint	= (1<<2),
	  Floppyint	= (1<<1),
	  Parallelint	= (1<<0),
	Intenareg	= 0xE0040004,
	Intcause	= 0xE0040007
};

M carrera/l.s => carrera/l.s +24 -15
@@ 417,7 417,7 @@ wasuser:

	MOVW	$setR30(SB), R30
	CONST	(MACHADDR, R1)
	ADDU	R1, R(MACH)			/* R(MACH) = m-> */
	MOVW	R1, R(MACH)			/* R(MACH) = m-> */
	MOVW	8(R(MACH)), R(USER)		/* up = m->proc */
	MOVW	4(SP), R1			/* first arg for syscall/trap */
	BNE	R26, notsys


@@ 744,17 744,23 @@ TEXT	icflush(SB), $-4			/* icflush(virtaddr, count) */
	MOVW	4(FP), R9
	MOVW	$0, M(STATUS)
	WAIT
	ADDU	R1, R9			/* R9 = last address */
	MOVW	$(~0x3f), R8
	AND	R1, R8			/* R8 = first address, rounded down */
	ADD	$0x3f, R9
	AND	$(~0x3f), R9		/* round last address up */
	SUB	R8, R9			/* R9 = revised count */
icflush1:			/* primary cache line size is 16 bytes */
	/*
	 * Due to a challenge bug PD+HWB DOES NOT WORK - philw
	 */
	WAIT
	WAIT
	CACHE	SD+HWBI, (R1)
	WAIT
	WAIT
	SUBU	$128, R9
	ADDU	$128, R1
	CACHE	PD+HWB, 0x00(R8)
	CACHE	PI+HI, 0x00(R8)
	CACHE	PD+HWB, 0x10(R8)
	CACHE	PI+HI, 0x10(R8)
	CACHE	PD+HWB, 0x20(R8)
	CACHE	PI+HI, 0x20(R8)
	CACHE	PD+HWB, 0x30(R8)
	CACHE	PI+HI, 0x30(R8)
	SUB	$0x40, R9
	ADD	$0x40, R8
	BGTZ	R9, icflush1
	MOVW	R10, M(STATUS)
	WAIT


@@ 782,11 788,14 @@ TEXT	cleancache(SB), $-4
	WAIT
	MOVW	$0, M(STATUS)
	WAIT
	MOVW	$(4*1024*1024), R9
	MOVW	$(32*1024), R9
ccache:
	CACHE	SD+IWBI, 0x00(R1)
	SUBU	$128, R9
	ADDU	$128, R1
	CACHE	PD+IWBI, 0x00(R1)
	WAIT
	CACHE	PI+IWBI, 0x00(R1)
	WAIT
	SUBU	$16, R9
	ADDU	$16, R1
	BGTZ	R9, ccache
	MOVW	R10, M(STATUS)
	WAIT

M carrera/main.c => carrera/main.c +22 -13
@@ 34,7 34,6 @@ FPsave	initfp;
void
main(void)
{
	*(uchar*)(Uart0) = '*';
	tlbinit();		/* Very early to establish IO mappings */
	ioinit();
	arginit();


@@ 46,8 45,10 @@ main(void)
	kmapinit();
	xinit();
	printinit();
	NS16552setup(Uart0, UartFREQ);

	NS16552setup(Uart1, UartFREQ);
	NS16552special(0, 9600, &kbdq, &printq, kbdcr2nl);

	vecinit();
	iprint("\n\nBrazil\n");
	pageinit();


@@ 60,7 61,6 @@ main(void)
	schedinit();
}


/*
 *  copy arguments passed by the boot kernel (or ROM) into a temporary buffer.
 *  we do this because the arguments are in memory that may be allocated


@@ 72,7 72,8 @@ struct
{
	char	*name;
	char	*val;
}bootenv[] = {
}bootenv[] =
{
	{"netaddr=",	sysname},
	{"console=",	consname},
	{"bootdisk=",	bootdisk},


@@ 141,6 142,7 @@ machinit(void)

	n = m->machno;
	m->stb = &stlb[n][0];

	clockinit();
}



@@ 152,9 154,19 @@ ioinit(void)
{
	ulong phys;

	/*
	 * Map devices
	 */
	phys = PPN(Devicephys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;
	puttlbx(1, Devicevirt, phys, PTEGLOBL, PGSZ64K);

	puttlbx(1, Devicevirt, phys, PTEGLOBL, PGSZ256K);
	/*
	 * Map Interrupt control
	 */
	phys = PPN(Intctlphys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;
	puttlbx(2, Intctlvirt, phys, PTEGLOBL, PGSZ4K);

	*(ushort*)Intenareg = 0xffff;
}

/*


@@ 166,7 178,8 @@ vecinit(void)
	memmove((ulong*)UTLBMISS, (ulong*)vector0, 0x100);
	memmove((ulong*)CACHETRAP, (ulong*)vector100, 0x80);
	memmove((ulong*)EXCEPTION, (ulong*)vector180, 0x80);
	icflush((ulong*)UTLBMISS, 32*1024);

	icflush((ulong*)UTLBMISS, 8*1024);
}

void


@@ 263,12 276,8 @@ exit(long type)

	spllo();
	print("cpu %d exiting %d\n", m->machno, type);
	timer = 0;
	while(active.machs || consactive()) {
		if(timer++ > 400)
			break;
	while(consactive())
		delay(10);
	}
	splhi();
	for(;;)
		;


@@ 296,7 305,7 @@ confinit(void)
	conf.npage1 = 0;
	conf.base1 = 0;

	conf.upages = (conf.npage*90)/100;
	conf.upages = (conf.npage*70)/100;
	if(top - conf.upages > (256*1024*1024)/BY2PG)
		conf.upages = top - (256*1024*1024)/BY2PG;



@@ 304,7 313,7 @@ confinit(void)

	/* set up other configuration parameters */
	conf.nproc = 100;
	conf.nswap = 262144;
	conf.nswap = conf.npage*3;
	conf.nimage = 200;
	conf.ipif = 8;
	conf.ip = 64;

M carrera/mem.h => carrera/mem.h +1 -0
@@ 109,6 109,7 @@
 */

#define PGSZ4K		(0x00<<13)
#define PGSZ64K		(0x0F<<13)
#define PGSZ256K	(0x3F<<13)
	
#define	KUSEG	0x00000000

M carrera/mmu.c => carrera/mmu.c +5 -3
@@ 52,6 52,8 @@ kmapinit(void)
		k->next = k+1;
	k->next = 0;
	unlock(&kmaplock);

	m->ktlbnext = TLBROFF;
}

/*


@@ 107,7 109,7 @@ kmap(Page *pg)
	puttlbx(x, (virt & ~BY2PG)|TLBPID(tlbvirt()), k->phys0, k->phys1, PGSZ4K);
	m->ktlbx[x] = 1;
	if(++x >= NTLB)
		m->ktlbnext = 1;
		m->ktlbnext = TLBROFF;
	else
		m->ktlbnext = x;



@@ 164,7 166,7 @@ kfault(ulong addr)
	puttlbx(x, (k->virt & ~BY2PG)|TLBPID(tlbvirt()), k->phys0, k->phys1, PGSZ4K);
	m->ktlbx[x] = 1;
	if(++x >= NTLB)
		m->ktlbnext = 1;
		m->ktlbnext = TLBROFF;
	else
		m->ktlbnext = x;
}


@@ 196,7 198,7 @@ kmapinval()
		kunmap(k);
	}
	m->kactive = 0;
	m->ktlbnext = 1;
	m->ktlbnext = TLBROFF;
}

void

M carrera/trap.c => carrera/trap.c +57 -19
@@ 278,12 278,46 @@ trap(Ureg *ur)
void
intr(Ureg *ur)
{
	uchar devint;
	ulong cause = ur->cause;

	m->intr++;
	cause &= INTR7|INTR6|INTR5|INTR4|INTR3|INTR2|INTR1|INTR0;

	iprint("intr %lux\n", cause);
	if(cause & INTR3) {
		devint = *(uchar*)Intcause;
		switch(devint) {
		default:
			panic("unknown devint=#%lux", devint);

		case 0x28:		/* Serial 1 */
			NS16552intr(0);
			break;
		case 0x24:		/* Serial 2 */
			NS16552intr(1);
			break;
		case 0x14:
			etherintr();
			break;
		}
		cause &= ~INTR3;
	}

	if(cause & INTR4) {
		devint = *(uchar*)I386ack;
		iprint("i386ack=#%lux\n", devint);
		cause &= ~INTR4;
	}

	if(cause & INTR7) {
		clock(ur);
		cause &= ~INTR7;
	}

	if(cause) {
		iprint("cause %lux\n", cause);
		exit(1);
	}
}

char*


@@ 512,27 546,31 @@ syscall(Ureg *aur)
	up->nerrlab = 0;
	sp = ur->sp;
	ret = -1;
	if(!waserror()) {
		if(up->scallnr >= sizeof systab/sizeof systab[0]){
			pprint("bad sys call number %d pc %lux\n", up->scallnr, ur->pc);
			postnote(up, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp);
			postnote(up, 1, "sys: odd stack", NDebug);
			error(Ebadarg);
		}
	if(waserror())
		goto error;

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
			validaddr(sp, sizeof(Sargs), 0);
	if(up->scallnr >= sizeof systab/sizeof systab[0]){
		pprint("bad sys call %d pc %lux\n", up->scallnr, ur->pc);
		postnote(up, 1, "sys: bad sys call", NDebug);
		error(Ebadarg);
	}

		up->s = *((Sargs*)(sp+BY2WD));
		up->psstate = sysctab[up->scallnr];
		ret = (*systab[up->scallnr])(up->s.args);
		poperror();
	if(sp & (BY2WD-1)){
		pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp);
		postnote(up, 1, "sys: odd stack", NDebug);
		error(Ebadarg);
	}

	if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
		validaddr(sp, sizeof(Sargs), 0);

	up->s = *((Sargs*)(sp+BY2WD));
	up->psstate = sysctab[up->scallnr];

	ret = (*systab[up->scallnr])(up->s.args);
	poperror();

error:
	ur->pc += 4;
	up->nerrlab = 0;
	up->psstate = 0;

M port/proc.c => port/proc.c +1 -0
@@ 145,6 145,7 @@ loop:
	spllo();
	while(runhiq.head == 0 && runloq.head == 0)
		;

	splhi();

	lock(&runhiq);

M port/segment.c => port/segment.c +0 -2
@@ 476,8 476,6 @@ syssegflush(ulong *arg)
	j = (soff&(PTEMAPMEM-1))/BY2PG;
	len = arg[1]+BY2PG;

print("%s segflush 0x%lux %d\n", up->text, arg[0], arg[1]);

	for(i = soff/PTEMAPMEM; len > 0 && i < SEGMAPSIZE; i++) {
		if(s->map[i] == 0) {
			len -= PTEMAPMEM;