plan 9 kernel history: overview | file list | diff list

2000/0713/carrera/devether.c (diff list | history)

1993/0903/sys/src/9/carrera/devether.c:8,2751993/0904/sys/src/9/carrera/devether.c:8,486 (short | long)
1993/0903    
#include	"../port/netif.h" 
 
/* 
 *  ethernet address stored in prom 
1993/0904    
 * National Semiconductor DP83932 
 * Systems-Oriented Network Interface Controller 
 * (SONIC) 
1993/0903    
 */ 
typedef struct 
{ 
	ulong	pad0; 
	ulong	byte; 
	uvlong	pad1; 
} Etheraddr; 
#define	EPCENETPROM	EPCSWIN(Etheraddr, 0x2000) 
 
/* 
 *  SEEQ/EDLC device registers 
 */ 
typedef struct 
{ 
	struct 
	{ 
	  ulong	pad; 
	  ulong	byte; 
	}	addr[6];	/* address */ 
1993/0904    
#define SONICADDR	((Sonic*)Sonicbase) 
1993/0903    
 
	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) 
1993/0904    
#define RD(rn)		(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = v) 
1993/0903    
 
/* 
 *  LXT901 device registers 
 */ 
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) 
1993/0904    
typedef struct 
{ 
	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; 
1993/0903    
 
enum 
{ 
	/* 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 */ 
1993/0904    
	Nrb		= 16,		/* receive buffers */ 
	Ntb		= 8,		/* transmit buffers */ 
}; 
1993/0903    
 
	/* 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 */ 
1993/0904    
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 */ 
1993/0903    
 
	Renab=		(Rigood|Riend|Rishort|Ridrbl|Ricrc), 
1993/0904    
	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 */ 
1993/0903    
 
	/* 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 */ 
1993/0904    
	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 */ 
1993/0903    
 
	/* interrupt level for ether */ 
	ILenet=		0x60, 
1993/0904    
	Ptx	= 0x0001,	/* packet transmitted ok */ 
	Pintr	= 0x8000,	/* programmable interrupt */ 
1993/0903    
 
	/* 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 */ 
1993/0904    
	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 */ 
1993/0903    
}; 
 
#define RSUCC(i)	(((i)+1)&Rmask) 
#define RPREV(i)	(((i)-1)&Rmask) 
#define TSUCC(i)	(((i)+1)&Tmask) 
#define TPREV(i)	(((i)-1)&Tmask) 
1993/0904    
/* 
 * Receive Resource Descriptor. 
 */ 
typedef struct 
{ 
	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; 
1993/0903    
 
/* 
 *  a hardware packet buffer 
1993/0904    
 * Receive Packet Descriptor. 
1993/0903    
 */ 
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; 
1993/0904    
	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; 
1993/0903    
 
1993/0904    
/* 
 * Transmit Packet Descriptor. 
 */ 
typedef struct 
{ 
	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; 
1993/0903    
struct Ether 
{ 
	uchar	ea[6]; 
1993/0904    
	uchar	ba[6]; 
1993/0903    
 
	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 */ 
1993/0904    
	Sonic	*sonic;		/* SONIC registers */ 
1993/0903    
 
	Pbuf	*tbuf;		/* transmit buffers */ 
	Pbuf	*rbuf;		/* receive buffers */ 
                 
	QLock	tlock;		/* lock for grabbing transmitter queue */ 
	Rendez	tr;		/* wait here for free xmit buffer */ 
1993/0904    
	int	th;		/* first transmit buffer owned by host */	 
	int	ti;		/* first transmit buffer owned by interface */ 
1993/0903    
 
1993/0904    
	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 */ 
 
1993/0903    
	Netif; 
} ether; 
1993/0904    
}; 
1993/0903    
 
1993/0904    
Ether *ether[Nether]; 
1993/0903    
 
/* 
 *  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. 
 */ 
1993/0904    
#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) 
 
1993/0903    
static void 
etherhardreset(void) 
1993/0904    
reset(Ether *ctlr) 
1993/0903    
{ 
	EDLCdev *edlc = EPCEDLC; 
	LXTdev *lxt = EPCLXT; 
	EPCmisc *misc = EPCMISC; 
	ulong x, i; 
1993/0904    
	int i; 
1993/0903    
 
	/* step 1: isolate from ether */ 
	lxt->loopback = 1; 
	x = lxt->loopback; USED(x); 
1993/0904    
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); 
1993/0903    
 
	/* step 2: shut off transmitter */ 
	while(edlc->ttop != edlc->tindex) 
		edlc->ttop = edlc->tindex; 
	ether.tindex = ether.ttop = edlc->ttop; 
1993/0904    
	/* 
	 * 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 < Nrb; i++){ 
		ctlr->rra[i].wc0 = (sizeof(ctlr->rb[0])/2) & 0xFFFF; 
		ctlr->rra[i].wc1 = ((sizeof(ctlr->rb[0])/2)>>16) & 0xFFFF; 
1993/0903    
 
	/* 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); 
1993/0904    
		ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]); 
		ctlr->rda[i].owner = Interface; 
1993/0903    
 
	/* step 4: enable transmitter interrupts */ 
	edlc->tcmd = Tigood | Ti16tries | Ticoll | Tiunder; 
1993/0904    
		ctlr->rra[i].ptr0 = ctlr->rda[i].ptr0 = LS16(ctlr->rb[i]); 
		ctlr->rra[i].ptr1 = ctlr->rda[i].ptr1 = MS16(ctlr->rb[i]); 
	} 
1993/0903    
 
	/* step 5: set address from prom, start receiver, 
	 * and reset receive pointer 
1993/0904    
	/* 
	 * Terminate the receive descriptor ring 
	 * and load the SONIC registers to describe the RDA. 
1993/0903    
	 */ 
	for(i = 0; i < Netheraddr; i++) 
		edlc->addr[i].byte = EPCENETPROM[5-i].byte & 0xff; 
1993/0904    
	ctlr->rda[Nrb-1].link |= Eol; 
1993/0903    
 
	if(ether.prom) 
		edlc->rcmd = Renab | Rall; 
	else 
		edlc->rcmd = Renab | Rnormal; 
1993/0904    
	WR(crda, LS16(ctlr->rda)); 
	WR(urda, MS16(ctlr->rda)); 
	WR(eobc, sizeof(ctlr->rb[0])/2 - 2); 
1993/0903    
 
	ether.rindex = edlc->rindex; 
	ether.rtop = edlc->rtop = RPREV(ether.rindex); 
1993/0904    
	/* 
	 * 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])); 
1993/0903    
 
	/* step 6: attach to ether */ 
	lxt->loopback = 0; 
1993/0904    
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)]); 
	} 
 
	WR(ctda, LS16(&ctlr->tda[0])); 
	WR(utda, MS16(&ctlr->tda[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"); 
1993/0903    
} 
 
void 
etherintr(void) 
{ 
	EDLCdev *edlc = EPCEDLC; 
	EPCmisc *misc = EPCMISC; 
	Netfile *f, **fp; 
	Pbuf *p; 
	int x; 
	ushort t; 
1993/0904    
	Ether *ctlr; 
	ulong status; 
	TXpkt *txpkt; 
	RXpkt *rxpkt; 
	Etherpkt *p; 
	Netfile *f, **fp; 
1993/0903    
 
	while(edlc->rindex != ether.rindex){ 
		p = ðer.rbuf[ether.rindex]; 
1993/0904    
	ctlr = ether[0]; 
1993/0903    
 
		/* 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++; 
1993/0904    
	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); 
1993/0903    
		} 
		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 < ðer.f[Ntypes]; fp++){ 
				f = *fp; 
				if(f == 0) 
					continue; 
				if(f->type == t || f->type < 0) 
					qproduce(f->in, p->d, x); 
1993/0904    
 
		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); 
				} 
1993/0903    
			} 
1993/0904    
			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]; 
1993/0903    
		} 
1993/0904    
		status &= ~(Pktrx|Rde); 
1993/0903    
 
1993/0904    
	noinput: 
1993/0903    
		/* 
		 *  because of a chip bug, we have to reset if rtop 
		 *  and rindex get too close. 
1993/0904    
		 * We get a 'load CAM done' interrupt 
		 * after initialisation. Ignore it. 
1993/0903    
		 */ 
		x = edlc->rtop - edlc->rindex; 
		if(x < 0) 
			x += Nrcv; 
		if(x <= 64){ 
			etherhardreset(); 
		} else { 
			edlc->rtop = ether.rindex; 
			ether.rindex = RSUCC(ether.rindex); 
1993/0904    
		if(status & Lcd) 
			status &= ~Lcd; 
	 
		/* 
		 * Warnings that something is afoot. 
		 */ 
		if(status & Hbl){ 
			print("sonic: cd heartbeat lost\n"); 
			status &= ~Hbl; 
1993/0903    
		} 
1993/0904    
		if(status & Br){ 
			print("sonic: bus retry occurred\n"); 
			status &= ~Br; 
		} 
	 
		if(status & AllIntr) 
			print("sonic %ux\n", status); 
1993/0903    
	} 
	/* reenable holdoff and EPC interrupts */ 
	misc->clr = 0x10; 
	misc->set = 0x10; 
	epcenable(EIenet); 
} 
 
/* 
1993/0903/sys/src/9/carrera/devether.c:278,3521993/0904/sys/src/9/carrera/devether.c:489,533
1993/0903    
static void 
promiscuous(void *arg, int on) 
{ 
	EDLCdev *edlc = EPCEDLC; 
1993/0904    
	ushort reg; 
1993/0903    
 
	USED(arg); 
1993/0904    
 
	reg = RD(rcr); 
1993/0903    
	if(on) 
		edlc->rcmd = Renab | Rall; 
1993/0904    
		WR(rcr, reg|Pro); 
1993/0903    
	else 
		edlc->rcmd = Renab | Rnormal; 
1993/0904    
		WR(rcr, reg&~Pro); 
1993/0903    
} 
 
void 
etherreset(void) 
{ 
	EDLCdev *edlc = EPCEDLC; 
	EPCmisc *misc = EPCMISC; 
	ulong x, i; 
1993/0904    
	Ether *ctlr; 
1993/0903    
 
	/* 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]; 
1993/0904    
	/* 
	 * 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)); */ 
1993/0903    
	} 
	ether.rindex = edlc->rindex; 
	ether.rtop = edlc->rtop = RPREV(ether.rindex); 
1993/0904    
	ctlr = ether[0]; 
1993/0903    
 
	edlc->rcmd = Renab | Rnormal; 
1993/0904    
	reset(ctlr); 
1993/0903    
 
	/* set hold off timer value, and enable its interrupts (pulse) */ 
	misc->set = ho800us; 
	misc->clr = (~ho800us)&0x180; 
	misc->clr = 0x10; 
	misc->set = 0x10; 
1993/0904    
	memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); 
1993/0903    
 
	/* general network interface structure */ 
	netifinit(ðer, "ether", Ntypes, 32*1024); 
	ether.alen = 6; 
	memmove(ether.addr, ether.ea, 6); 
	memmove(ether.bcast, etherbcast, 6); 
	ether.promiscuous = promiscuous; 
	ether.arg = ðer; 
1993/0904    
	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]; 
1993/0903    
} 
 
void 
1993/0903/sys/src/9/carrera/devether.c:369,3811993/0904/sys/src/9/carrera/devether.c:550,562
1993/0903    
int 
etherwalk(Chan *c, char *name) 
{ 
	return netifwalk(ðer, c, name); 
1993/0904    
	return netifwalk(ether[0], c, name); 
1993/0903    
} 
 
Chan* 
etheropen(Chan *c, int omode) 
{ 
	return netifopen(ðer, c, omode); 
1993/0904    
	return netifopen(ether[0], c, omode); 
1993/0903    
} 
 
void 
1993/0903/sys/src/9/carrera/devether.c:387,4161993/0904/sys/src/9/carrera/devether.c:568,596
1993/0903    
void 
etherclose(Chan *c) 
{ 
	netifclose(ðer, c); 
1993/0904    
	netifclose(ether[0], c); 
1993/0903    
} 
 
long 
etherread(Chan *c, void *buf, long n, ulong offset) 
{ 
	return netifread(ðer, c, buf, n, offset); 
1993/0904    
	return netifread(ether[0], c, buf, n, offset); 
1993/0903    
} 
 
static int 
isoutbuf(void *arg) 
{ 
	EDLCdev *edlc = arg; 
1993/0904    
	Ether *ctlr = arg; 
1993/0903    
 
	USED(arg); 
	ether.tindex = edlc->tindex; 
	return TSUCC(ether.ttop) != ether.tindex; 
1993/0904    
	return ctlr->tda[ctlr->th].status == Host; 
1993/0903    
} 
 
long 
etherwrite(Chan *c, void *buf, long n, ulong offset) 
{ 
	Pbuf *p; 
	EDLCdev *edlc = EPCEDLC; 
1993/0904    
	Etherpkt *p; 
	TXpkt *txpkt; 
	Ether *ctlr = ether[0]; 
1993/0903    
 
	USED(offset); 
 
1993/0903/sys/src/9/carrera/devether.c:419,4451993/0904/sys/src/9/carrera/devether.c:599,632
1993/0903    
 
	/* etherif.c handles structure */ 
	if(NETTYPE(c->qid.path) != Ndataqid) 
		return netifwrite(ðer, c, buf, n); 
1993/0904    
		return netifwrite(ether[0], c, buf, n); 
1993/0903    
 
	/* we handle data */ 
	qlock(ðer.tlock); 
	tsleep(ðer.tr, isoutbuf, edlc, 10000); 
	if(!isoutbuf(edlc)){ 
1993/0904    
	qlock(&ctlr->tlock); 
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); 
	if(!isoutbuf(ctlr)){ 
1993/0903    
		print("ether transmitter jammed\n"); 
	} else { 
		p = ðer.tbuf[ether.ttop]; 
1993/0904    
	} 
	else { 
		p =(Etherpkt*)ctlr->tb[ctlr->th]; 
1993/0903    
		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; 
1993/0904    
		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); 
1993/0903    
	} 
	qunlock(ðer.tlock); 
1993/0904    
	qunlock(&ctlr->tlock); 
1993/0903    
	return n; 
} 
 
1993/0903/sys/src/9/carrera/devether.c:452,4621993/0904/sys/src/9/carrera/devether.c:639,649
1993/0903    
void 
etherstat(Chan *c, char *dp) 
{ 
	netifstat(ðer, c, dp); 
1993/0904    
	netifstat(ether[0], c, dp); 
1993/0903    
} 
 
void 
etherwstat(Chan *c, char *dp) 
{ 
	netifwstat(ðer, c, dp); 
1993/0904    
	netifwstat(ether[0], c, dp); 
1993/0903    
} 
1993/0904/sys/src/9/carrera/devether.c:17,221993/0905/sys/src/9/carrera/devether.c:17,23 (short | long)
1993/0903    
 
1993/0904    
#define RD(rn)		(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = v) 
1993/0905    
#define ISquad(s)	if((ulong)s & 0x7) panic("sonoc: Quad alignment"); 
1993/0903    
 
1993/0904    
typedef struct 
{ 
1993/0904/sys/src/9/carrera/devether.c:177,1891993/0905/sys/src/9/carrera/devether.c:178,191
1993/0904    
	Interface	= -1,	/* descriptor belongs to interface */ 
 
	Nether		= 1, 
	Ntypes=		8, 
1993/0905    
	Ntypes		= 8, 
1993/0904    
}; 
 
/* 
 * CAM Descriptor 
 */ 
typedef struct { 
1993/0905    
typedef struct 
{ 
1993/0904    
	uchar	pad0[2]; 
	ushort	cep;		/* CAM entry pointer */ 
	uchar	pad1[2]; 
1993/0904/sys/src/9/carrera/devether.c:234,2401993/0905/sys/src/9/carrera/devether.c:236,241
1993/0903    
{ 
1993/0904    
	int i; 
1993/0903    
 
1993/0904    
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 
1993/0904/sys/src/9/carrera/devether.c:242,2481993/0905/sys/src/9/carrera/devether.c:243,250
1993/0904    
	 * Clear the descriptor and buffer area. 
	 */ 
	WR(cr, Rst); 
	WR(dcr, Sterm|Dw32|Lbr|Efm|W14tf); 
1993/0905    
	WR(dcr, 0x2423);	/* 5-19 Carrera manual */ 
iprint("eobc #%lux\n", RD(eobc)); 
1993/0904    
	WR(cr, 0); 
1993/0903    
 
1993/0904    
	/* 
1993/0904/sys/src/9/carrera/devether.c:255,2611993/0905/sys/src/9/carrera/devether.c:257,263
1993/0904    
	 * thus the size of the receive buffers must be sizeof(Etherpkt)+4. 
	 * Set up the receive descriptors as a ring. 
	 */ 
	for(i = 0; i < Nrb; i++){ 
1993/0905    
	for(i = 0; i < Nrb; i++) { 
1993/0904    
		ctlr->rra[i].wc0 = (sizeof(ctlr->rb[0])/2) & 0xFFFF; 
		ctlr->rra[i].wc1 = ((sizeof(ctlr->rb[0])/2)>>16) & 0xFFFF; 
1993/0903    
 
1993/0904/sys/src/9/carrera/devether.c:266,2711993/0905/sys/src/9/carrera/devether.c:268,277
1993/0904    
		ctlr->rra[i].ptr1 = ctlr->rda[i].ptr1 = MS16(ctlr->rb[i]); 
	} 
1993/0903    
 
1993/0905    
	ISquad(ctlr->rra); 
	ISquad(ctlr->rda); 
	ISquad(ctlr->rb); 
 
1993/0904    
	/* 
	 * Terminate the receive descriptor ring 
	 * and load the SONIC registers to describe the RDA. 
1993/0904/sys/src/9/carrera/devether.c:275,2801993/0905/sys/src/9/carrera/devether.c:281,287
1993/0904    
	WR(crda, LS16(ctlr->rda)); 
	WR(urda, MS16(ctlr->rda)); 
	WR(eobc, sizeof(ctlr->rb[0])/2 - 2); 
1993/0905    
iprint("eobc #%lux\n", RD(eobc)); 
1993/0903    
 
1993/0904    
	/* 
	 * Load the SONIC registers to describe the RRA. 
1993/0904/sys/src/9/carrera/devether.c:291,3011993/0905/sys/src/9/carrera/devether.c:298,306
1993/0904    
	WR(rea, LS16(&ctlr->rra[Nrb])); 
	WR(rwp, LS16(&ctlr->rra[Nrb+1])); 
1993/0903    
 
1993/0904    
iprint("wait rra\n"); 
	WR(cr, Rrra); 
	while(RD(cr) & Rrra) 
		; 
iprint("rra done\n"); 
 
	/* 
	 * Initialise the transmit descriptor area (TDA). 
1993/0904/sys/src/9/carrera/devether.c:358,3671993/0905/sys/src/9/carrera/devether.c:363,390
1993/0904    
	WR(rcr, Err|Rnt|Brd); 
	WR(tcr, 0); 
	WR(imr, AllIntr); 
iprint("reset done\n"); 
1993/0903    
} 
 
void 
1993/0905    
pxp(RXpkt *rxpkt) 
{ 
	print("%lux %lux\n", rxpkt->pad0[0], rxpkt->pad0[1]); 
	print("status %lux\n", rxpkt->status);		/* receive status */ 
	print("%lux %lux\n", rxpkt->pad1[0], rxpkt->pad1[1]); 
	print("count %lux\n", rxpkt->count);		/* packet byte count */ 
	print("%lux %lux\n", rxpkt->pad2[0], rxpkt->pad2[1]); 
	print("ptr0 %lux\n", rxpkt->ptr0);		/* buffer pointer */ 
	print("%lux %lux\n", rxpkt->pad3[0], rxpkt->pad3[1]); 
	print("ptr1 %lux\n", rxpkt->ptr1); 
	print("%lux %lux\n", rxpkt->pad4[0], rxpkt->pad4[1]); 
	print("seqno %lux\n", rxpkt->seqno);		/*  */ 
	print("%lux %lux\n", rxpkt->pad5[0], rxpkt->pad5[1]); 
	print("link %lux\n", rxpkt->link);		/* descriptor link and EOL */ 
	print("%lux %lux\n", rxpkt->pad6[0], rxpkt->pad6[1]); 
	print("owner %lux\n", rxpkt->owner);		/* in use */ 
} 
 
void 
1993/0903    
etherintr(void) 
{ 
	int x; 
1993/0904/sys/src/9/carrera/devether.c:379,3841993/0905/sys/src/9/carrera/devether.c:402,408
1993/0904    
		status = RD(isr) & AllIntr; 
		if(status == 0) 
			break; 
1993/0905    
print("s %lux\n", status);	 
1993/0904    
 
		WR(isr, status); 
	 
1993/0904/sys/src/9/carrera/devether.c:410,4171993/0905/sys/src/9/carrera/devether.c:434,441
1993/0904    
		/* 
		 * A packet arrived or we ran out of descriptors. 
		 */ 
		status &= ~(Pktrx|Rde); 
		rxpkt = &ctlr->rda[ctlr->rh]; 
1993/0905    
pxp(rxpkt); 
1993/0904    
		while(rxpkt->owner == Host){ 
			ctlr->inpackets++; 
	 
1993/0904/sys/src/9/carrera/devether.c:470,4851993/0905/sys/src/9/carrera/devether.c:494,509
1993/0904    
		 * Warnings that something is afoot. 
		 */ 
		if(status & Hbl){ 
			print("sonic: cd heartbeat lost\n"); 
1993/0905    
			iprint("sonic: cd heartbeat lost\n"); 
1993/0904    
			status &= ~Hbl; 
1993/0903    
		} 
1993/0904    
		if(status & Br){ 
			print("sonic: bus retry occurred\n"); 
1993/0905    
			iprint("sonic: bus retry occurred\n"); 
1993/0904    
			status &= ~Br; 
		} 
	 
		if(status & AllIntr) 
			print("sonic %ux\n", status); 
1993/0905    
			iprint("sonic #%lux\n", status); 
1993/0903    
	} 
} 
 
1993/0904/sys/src/9/carrera/devether.c:513,5191993/0905/sys/src/9/carrera/devether.c:537,547
1993/0904    
	 */ 
	if(ether[0] == 0) { 
		ether[0] = xspanalloc(sizeof(Ether), BY2PG, 64*1024); 
/*		memmove(ether[0]->ea, eeprom.ea, sizeof(ether[0]->ea)); */ 
1993/0905    
 
		if(PADDR(ether[0])+sizeof(Ether) > Ntranslation*BY2PG) 
			panic("sonic: 16M io map"); 
 
		enetaddr(ether[0]->ea); 
1993/0903    
	} 
1993/0904    
	ctlr = ether[0]; 
1993/0903    
 
1993/0904/sys/src/9/carrera/devether.c:531,5361993/0905/sys/src/9/carrera/devether.c:559,570
1993/0903    
} 
 
void 
1993/0905    
enab(void) 
{ 
	WR(cr, Rxen); 
} 
 
void 
1993/0903    
etherinit(void) 
{ 
} 
1993/0904/sys/src/9/carrera/devether.c:538,5431993/0905/sys/src/9/carrera/devether.c:572,584
1993/0903    
Chan* 
etherattach(char *spec) 
{ 
1993/0905    
	static int enable; 
 
	if(enable == 0) { 
		enable = 1; 
		WR(cr, Rxen); 
	} 
 
1993/0903    
	return devattach('l', spec); 
} 
 
1993/0904/sys/src/9/carrera/devether.c:594,5991993/0905/sys/src/9/carrera/devether.c:635,642
1993/0903    
 
	USED(offset); 
 
1993/0905    
iprint("ether tx\n"); 
 
1993/0903    
	if(n > ETHERMAXTU) 
		error(Ebadarg); 
 
1993/0904/sys/src/9/carrera/devether.c:604,6121993/0905/sys/src/9/carrera/devether.c:647,655
1993/0903    
	/* we handle data */ 
1993/0904    
	qlock(&ctlr->tlock); 
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); 
	if(!isoutbuf(ctlr)){ 
1993/0905    
 
	if(!isoutbuf(ctlr)) 
1993/0903    
		print("ether transmitter jammed\n"); 
1993/0904    
	} 
	else { 
		p =(Etherpkt*)ctlr->tb[ctlr->th]; 
1993/0903    
		memmove(p->d, buf, n); 
1993/0904/sys/src/9/carrera/devether.c:627,6321993/0905/sys/src/9/carrera/devether.c:670,678
1993/0904    
		WR(cr, Txp); 
1993/0903    
	} 
1993/0904    
	qunlock(&ctlr->tlock); 
1993/0905    
 
iprint("tx done %d\n", n); 
 
1993/0903    
	return n; 
} 
 
1993/0905/sys/src/9/carrera/devether.c:16,241993/0906/sys/src/9/carrera/devether.c:16,34 (short | long)
1993/0904    
#define SONICADDR	((Sonic*)Sonicbase) 
1993/0903    
 
1993/0904    
#define RD(rn)		(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = v) 
1993/0905    
#define ISquad(s)	if((ulong)s & 0x7) panic("sonoc: Quad alignment"); 
1993/0906    
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
#define ISquad(s)	if((ulong)s & 0x7) panic("sonic: Quad alignment"); 
1993/0903    
 
1993/0906    
typedef struct Pbuf Pbuf; 
struct Pbuf 
{ 
	uchar	d[6]; 
	uchar	s[6]; 
	uchar	type[2]; 
	uchar	data[1500]; 
	uchar	crc[4]; 
}; 
 
1993/0904    
typedef struct 
{ 
	ulong	cr;		/* command */ 
1993/0905/sys/src/9/carrera/devether.c:32,381993/0906/sys/src/9/carrera/devether.c:42,51
1993/0904    
	ulong	pad0x08[5];	/*  */ 
	ulong	urda;		/* upper receive descriptor address */ 
	ulong	crda;		/* current receive descriptor address */ 
	ulong	pad0x0F[4];	/*  */ 
1993/0906    
	ulong	crba0;		/* DO NOT WRITE THESE */ 
	ulong	crba1; 
	ulong	rbwc0; 
	ulong	rbwc1; 
1993/0904    
	ulong	eobc;		/* end of buffer word count */ 
	ulong	urra;		/* upper receive resource address */ 
	ulong	rsa;		/* resource start address */ 
1993/0905/sys/src/9/carrera/devether.c:111,1161993/0906/sys/src/9/carrera/devether.c:124,132
1993/0904    
	Hbl	= 0x2000,	/* CD heartbeat lost */ 
	Br	= 0x4000,	/* bus retry occurred */ 
	AllIntr	= 0x7771,	/* all of the above */ 
1993/0906    
 
	Rxbuf	= sizeof(Pbuf)+4, 
	Txbuf	= sizeof(Pbuf), 
1993/0903    
}; 
 
1993/0904    
/* 
1993/0905/sys/src/9/carrera/devether.c:118,1311993/0906/sys/src/9/carrera/devether.c:134,147
1993/0904    
 */ 
typedef struct 
{ 
	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; 
1993/0906    
	ushort	pad1; 
	ushort		ptr1;		/* buffer pointer in the RRA */ 
	ushort  pad2; 
	ushort		ptr0; 
	ushort  pad3; 
	ushort		wc1;		/* buffer word count in the RRA */ 
	ushort  pad4; 
	ushort		wc0; 
1993/0904    
} RXrsc; 
1993/0903    
 
/* 
1993/0905/sys/src/9/carrera/devether.c:133,1521993/0906/sys/src/9/carrera/devether.c:149,169
1993/0903    
 */ 
typedef struct 
{ 
1993/0904    
	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 */ 
1993/0906    
	ushort	pad0; 
		ushort	count;		/* packet byte count */ 
	ushort	pad1; 
		ushort	status;		/* receive status */ 
	ushort	pad2; 
		ushort	ptr1;		/* buffer pointer */ 
	ushort	pad3; 
		ushort	ptr0; 
	ushort  pad4; 
		ushort	link;		/* descriptor link and EOL */ 
	ushort	pad5; 
		ushort	seqno;		/*  */ 
	ulong	pad6; 
	ushort  pad7; 
		ushort	owner;		/* in use */ 
1993/0904    
} RXpkt; 
1993/0903    
 
1993/0904    
/* 
1993/0905/sys/src/9/carrera/devether.c:154,1751993/0906/sys/src/9/carrera/devether.c:171,192
1993/0904    
 */ 
typedef struct 
{ 
	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 */ 
1993/0906    
	ushort	pad1; 
		ushort	config;		/*  */ 
	ushort	pad0; 
		ushort	status;		/* transmit status */ 
	ushort	pad3; 
		ushort	count;		/* fragment count */ 
	ushort	pad2; 
		ushort	size;		/* byte count of entire packet */ 
	ushort	pad5; 
		ushort	ptr1; 
	ushort	pad4; 
		ushort	ptr0;		/* packet pointer */ 
	ushort	pad7; 
		ushort	link;		/* descriptor link */ 
	ushort	pad6; 
		ushort	fsize;		/* fragment size */ 
1993/0904    
} TXpkt; 
 
enum{ 
1993/0905/sys/src/9/carrera/devether.c:186,2011993/0906/sys/src/9/carrera/devether.c:203,219
1993/0904    
 */ 
1993/0905    
typedef struct 
{ 
1993/0904    
	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 */ 
1993/0906    
	ushort	pad0; 
		ushort	cap0;		/* CAM address port 0 */ 
	ushort	pad1; 
		ushort	cep;		/* CAM entry pointer */ 
	ushort	pad2; 
		ushort	cap2;		/* CAM address port 2 */ 
	ushort	pad3; 
		ushort	cap1;		/* CAM address port 1 */ 
	ulong	pad4; 
	ushort	pad5; 
		ushort	ce;		/* CAM enable */ 
1993/0904    
} Cam; 
 
typedef struct Ether Ether; 
1993/0905/sys/src/9/carrera/devether.c:204,2111993/0906/sys/src/9/carrera/devether.c:222,227
1993/0903    
	uchar	ea[6]; 
1993/0904    
	uchar	ba[6]; 
1993/0903    
 
1993/0904    
	Sonic	*sonic;		/* SONIC registers */ 
1993/0903    
                 
	QLock	tlock;		/* lock for grabbing transmitter queue */ 
	Rendez	tr;		/* wait here for free xmit buffer */ 
1993/0904    
	int	th;		/* first transmit buffer owned by host */	 
1993/0905/sys/src/9/carrera/devether.c:214,2261993/0906/sys/src/9/carrera/devether.c:230,243
1993/0904    
	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 */ 
1993/0906    
	RXrsc	*rra;		/* receive resource area */ 
	RXpkt	*rda;		/* receive descriptor area */ 
	TXpkt	*tda;		/* transmit descriptor area */ 
	Cam	*cda;		/* CAM descriptor area */ 
1993/0904    
 
1993/0906    
	uchar	*rb[Nrb];	/* receive buffer area */ 
	uchar	*tb[Ntb];	/* transmit buffer area */ 
 
1993/0903    
	Netif; 
1993/0904    
}; 
1993/0903    
 
1993/0905/sys/src/9/carrera/devether.c:231,2511993/0906/sys/src/9/carrera/devether.c:248,276
1993/0904    
#define LS16(addr)	(PADDR(addr) & 0xFFFF) 
#define MS16(addr)	((PADDR(addr)>>16) & 0xFFFF) 
 
1993/0906    
void sonicswap(void*, int); 
 
1993/0903    
static void 
1993/0906    
wus(ushort *a, ushort v) 
{ 
	a[0] = v; 
	a[-1] = v; 
} 
 
static void 
1993/0904    
reset(Ether *ctlr) 
1993/0903    
{ 
1993/0904    
	int i; 
1993/0906    
	ushort lolen, hilen, loadr, hiadr; 
1993/0903    
 
1993/0904    
	/* 
	 * 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. 
1993/0906    
	 * Setup the descriptor and buffer area. 
1993/0904    
	 */ 
	WR(cr, Rst); 
1993/0905    
	WR(dcr, 0x2423);	/* 5-19 Carrera manual */ 
iprint("eobc #%lux\n", RD(eobc)); 
1993/0904    
	WR(cr, 0); 
1993/0903    
 
1993/0904    
	/* 
	 * Initialise the receive resource area (RRA) and 
1993/0905/sys/src/9/carrera/devether.c:254,2761993/0906/sys/src/9/carrera/devether.c:279,312
1993/0904    
	 * 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. 
1993/0906    
	 * thus the size of the receive buffers must be sizeof(Pbuf)+4. 
1993/0904    
	 * Set up the receive descriptors as a ring. 
	 */ 
1993/0906    
 
	lolen = (Rxbuf/2) & 0xFFFF; 
	hilen = ((Rxbuf/2)>>16) & 0xFFFF; 
 
1993/0905    
	for(i = 0; i < Nrb; i++) { 
1993/0904    
		ctlr->rra[i].wc0 = (sizeof(ctlr->rb[0])/2) & 0xFFFF; 
		ctlr->rra[i].wc1 = ((sizeof(ctlr->rb[0])/2)>>16) & 0xFFFF; 
1993/0906    
		wus(&ctlr->rra[i].wc0, lolen); 
		wus(&ctlr->rra[i].wc1, hilen); 
1993/0903    
 
1993/0904    
		ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]); 
1993/0906    
		ctlr->rda[i].link =  LS16(&ctlr->rda[NEXT(i, Nrb)]); 
1993/0904    
		ctlr->rda[i].owner = Interface; 
1993/0903    
 
1993/0904    
		ctlr->rra[i].ptr0 = ctlr->rda[i].ptr0 = LS16(ctlr->rb[i]); 
		ctlr->rra[i].ptr1 = ctlr->rda[i].ptr1 = MS16(ctlr->rb[i]); 
1993/0906    
		loadr = LS16(ctlr->rb[i]); 
		wus(&ctlr->rra[i].ptr0, loadr); 
		wus(&ctlr->rda[i].ptr0, loadr); 
 
		hiadr = MS16(ctlr->rb[i]); 
		wus(&ctlr->rra[i].ptr1, hiadr); 
		wus(&ctlr->rda[i].ptr1, hiadr); 
1993/0904    
	} 
1993/0903    
 
1993/0906    
	/* 
	 * Check the important resources are QUAD aligned 
	 */ 
1993/0905    
	ISquad(ctlr->rra); 
	ISquad(ctlr->rda); 
	ISquad(ctlr->rb); 
 
1993/0904    
	/* 
	 * Terminate the receive descriptor ring 
1993/0905/sys/src/9/carrera/devether.c:280,2871993/0906/sys/src/9/carrera/devether.c:316,322
1993/0903    
 
1993/0904    
	WR(crda, LS16(ctlr->rda)); 
	WR(urda, MS16(ctlr->rda)); 
	WR(eobc, sizeof(ctlr->rb[0])/2 - 2); 
1993/0905    
iprint("eobc #%lux\n", RD(eobc)); 
1993/0906    
	WR(eobc, Rxbuf/2 - 2); 
1993/0903    
 
1993/0904    
	/* 
	 * Load the SONIC registers to describe the RRA. 
1993/0905/sys/src/9/carrera/devether.c:289,2961993/0906/sys/src/9/carrera/devether.c:324,329
1993/0904    
	 * 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])); 
1993/0905/sys/src/9/carrera/devether.c:298,3071993/0906/sys/src/9/carrera/devether.c:331,336
1993/0904    
	WR(rea, LS16(&ctlr->rra[Nrb])); 
	WR(rwp, LS16(&ctlr->rra[Nrb+1])); 
1993/0903    
 
1993/0904    
	WR(cr, Rrra); 
	while(RD(cr) & Rrra) 
		; 
                 
	/* 
	 * Initialise the transmit descriptor area (TDA). 
	 * Each descriptor describes one packet, we make no use 
1993/0905/sys/src/9/carrera/devether.c:339,3561993/0906/sys/src/9/carrera/devether.c:368,393
1993/0904    
	 * 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; 
1993/0906    
	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; 
1993/0904    
 
	WR(cdp, LS16(&ctlr->cda)); 
1993/0906    
	WR(cdp, LS16(ctlr->cda)); 
1993/0904    
	WR(cdc, 1); 
 
1993/0906    
	/* 
	 * End the reset 
	 * Load the Resource Descriptors and Cam contents 
	 */ 
	WR(cr, 0); 
 
	WR(cr, Rrra); 
	while(RD(cr) & Rrra) 
		; 
 
1993/0904    
	WR(cr, Lcam); 
	while(RD(cr) & Lcam) 
		; 
1993/0905/sys/src/9/carrera/devether.c:366,4081993/0906/sys/src/9/carrera/devether.c:403,444
1993/0903    
} 
 
void 
1993/0905    
pxp(RXpkt *rxpkt) 
1993/0906    
sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p) 
1993/0905    
{ 
	print("%lux %lux\n", rxpkt->pad0[0], rxpkt->pad0[1]); 
	print("status %lux\n", rxpkt->status);		/* receive status */ 
	print("%lux %lux\n", rxpkt->pad1[0], rxpkt->pad1[1]); 
	print("count %lux\n", rxpkt->count);		/* packet byte count */ 
	print("%lux %lux\n", rxpkt->pad2[0], rxpkt->pad2[1]); 
	print("ptr0 %lux\n", rxpkt->ptr0);		/* buffer pointer */ 
	print("%lux %lux\n", rxpkt->pad3[0], rxpkt->pad3[1]); 
	print("ptr1 %lux\n", rxpkt->ptr1); 
	print("%lux %lux\n", rxpkt->pad4[0], rxpkt->pad4[1]); 
	print("seqno %lux\n", rxpkt->seqno);		/*  */ 
	print("%lux %lux\n", rxpkt->pad5[0], rxpkt->pad5[1]); 
	print("link %lux\n", rxpkt->link);		/* descriptor link and EOL */ 
	print("%lux %lux\n", rxpkt->pad6[0], rxpkt->pad6[1]); 
	print("owner %lux\n", rxpkt->owner);		/* in use */ 
1993/0906    
	int len; 
	ushort type; 
	Netfile *f, **fp, **ep; 
 
	/* 
	 * Sonic delivers CRC as part of the packet count 
	 */ 
	len = (r->count & 0xFFFF)-4; 
 
	sonicswap(p, len); 
 
	type = (p->type[0]<<8) | p->type[1]; 
	ep = &ctlr->f[Ntypes]; 
	for(fp = ctlr->f; fp < ep; fp++) { 
		f = *fp; 
		if(f && (f->type == type || f->type < 0)) 
			qproduce(f->in, p->d, len); 
	} 
1993/0905    
} 
 
void 
1993/0903    
etherintr(void) 
{ 
	int x; 
	ushort t; 
1993/0904    
	Ether *ctlr; 
1993/0906    
	Ether *c; 
1993/0904    
	ulong status; 
	TXpkt *txpkt; 
	RXpkt *rxpkt; 
	Etherpkt *p; 
	Netfile *f, **fp; 
1993/0903    
 
1993/0904    
	ctlr = ether[0]; 
1993/0906    
	c = ether[0]; 
1993/0903    
 
1993/0904    
	for(;;) { 
		status = RD(isr) & AllIntr; 
		if(status == 0) 
			break; 
1993/0905    
print("s %lux\n", status);	 
1993/0904    
 
		WR(isr, status); 
	 
1993/0905/sys/src/9/carrera/devether.c:410,4161993/0906/sys/src/9/carrera/devether.c:446,452
1993/0904    
		 * Transmission complete, for good or bad. 
		 */ 
		if(status & (Txdn|Txer)){ 
			txpkt = &ctlr->tda[ctlr->ti]; 
1993/0906    
			txpkt = &c->tda[c->ti]; 
1993/0904    
			while(txpkt->status != Host){ 
				if(txpkt->status == Interface){ 
					WR(ctda, LS16(txpkt)); 
1993/0905/sys/src/9/carrera/devether.c:419,4291993/0906/sys/src/9/carrera/devether.c:455,465
1993/0904    
				} 
	 
				if((txpkt->status & Ptx) == 0) 
					ctlr->oerrs++; 
1993/0906    
					c->oerrs++; 
1993/0904    
	 
				txpkt->status = Host; 
				ctlr->ti = NEXT(ctlr->ti, Ntb); 
				txpkt = &ctlr->tda[ctlr->ti]; 
1993/0906    
				c->ti = NEXT(c->ti, Ntb); 
				txpkt = &c->tda[c->ti]; 
1993/0904    
			} 
			status &= ~(Txdn|Txer); 
1993/0903    
		} 
1993/0905/sys/src/9/carrera/devether.c:434,4711993/0906/sys/src/9/carrera/devether.c:470,493
1993/0904    
		/* 
		 * A packet arrived or we ran out of descriptors. 
		 */ 
		rxpkt = &ctlr->rda[ctlr->rh]; 
1993/0905    
pxp(rxpkt); 
1993/0906    
		rxpkt = &c->rda[c->rh]; 
1993/0904    
		while(rxpkt->owner == Host){ 
			ctlr->inpackets++; 
1993/0906    
			c->inpackets++; 
1993/0904    
	 
			/* 
			 * 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); 
				} 
1993/0903    
			} 
1993/0906    
			if(rxpkt->status & Prx) 
				sonicpkt(c, rxpkt, (Pbuf*)c->rb[c->rh]); 
1993/0904    
			else 
			if(rxpkt->status & Fae) 
				ctlr->frames++; 
1993/0906    
				c->frames++; 
1993/0904    
			else 
			if(rxpkt->status & Crc) 
				ctlr->crcs++; 
1993/0906    
				c->crcs++; 
1993/0904    
			else 
				ctlr->buffs++; 
1993/0906    
				c->buffs++; 
1993/0904    
	 
			/* 
			 * Finished with this packet, it becomes the 
1993/0905/sys/src/9/carrera/devether.c:475,4841993/0906/sys/src/9/carrera/devether.c:497,506
1993/0904    
			 */ 
			rxpkt->link |= Eol; 
			rxpkt->owner = Interface; 
			ctlr->rda[PREV(ctlr->rh, Nrb)].link &= ~Eol; 
			ctlr->rh = NEXT(ctlr->rh, Nrb); 
1993/0906    
			c->rda[PREV(c->rh, Nrb)].link &= ~Eol; 
			c->rh = NEXT(c->rh, Nrb); 
1993/0904    
	 
			rxpkt = &ctlr->rda[ctlr->rh]; 
1993/0906    
			rxpkt = &c->rda[c->rh]; 
1993/0903    
		} 
1993/0904    
		status &= ~(Pktrx|Rde); 
1993/0903    
 
1993/0905/sys/src/9/carrera/devether.c:494,5091993/0906/sys/src/9/carrera/devether.c:516,531
1993/0904    
		 * Warnings that something is afoot. 
		 */ 
		if(status & Hbl){ 
1993/0905    
			iprint("sonic: cd heartbeat lost\n"); 
1993/0906    
			print("sonic: cd heartbeat lost\n"); 
1993/0904    
			status &= ~Hbl; 
1993/0903    
		} 
1993/0904    
		if(status & Br){ 
1993/0905    
			iprint("sonic: bus retry occurred\n"); 
1993/0906    
			print("sonic: bus retry occurred\n"); 
1993/0904    
			status &= ~Br; 
		} 
	 
		if(status & AllIntr) 
1993/0905    
			iprint("sonic #%lux\n", status); 
1993/0906    
			print("sonic #%lux\n", status); 
1993/0903    
	} 
} 
 
1993/0905/sys/src/9/carrera/devether.c:524,5291993/0906/sys/src/9/carrera/devether.c:546,592
1993/0904    
		WR(rcr, reg&~Pro); 
1993/0903    
} 
 
1993/0906    
static void 
initbufs(Ether *c) 
{ 
	int i; 
	uchar *mem; 
 
	mem = xspanalloc(64*1024, BY2PG, 0); 
	mem = CACHELINE(uchar, mem); 
 
	/* 
	 * Descriptors must be built in uncached space 
	 */ 
	c->rra = UNCACHED(RXrsc, mem); 
	mem = QUAD(uchar, mem+Nrb*sizeof(RXrsc)); 
 
	c->rda = UNCACHED(RXpkt, mem); 
	mem = QUAD(uchar, mem+Nrb*sizeof(RXpkt)); 
 
	c->tda = UNCACHED(TXpkt, mem); 
	mem = QUAD(uchar, mem+Ntb*sizeof(TXpkt)); 
 
	c->cda = UNCACHED(Cam, mem); 
 
	/* 
	 * DMA buffers are cache coherent - but we must not straddle 
	 * a cache line 
	 */ 
	mem = CACHELINE(uchar, mem+sizeof(Cam)); 
 
	for(i = 0; i < Nrb; i++) { 
		c->rb[i] = UNCACHED(uchar, mem); 
		mem += sizeof(Pbuf)+4; 
		mem = QUAD(uchar, mem); 
	} 
	for(i = 0; i < Ntb; i++) { 
		c->tb[i] = UNCACHED(uchar, mem); 
		mem += sizeof(Pbuf); 
		mem = QUAD(uchar, mem); 
	} 
} 
 
1993/0903    
void 
etherreset(void) 
{ 
1993/0905/sys/src/9/carrera/devether.c:535,5461993/0906/sys/src/9/carrera/devether.c:598,608
1993/0904    
	 * Set the physical ethernet address and 
	 * prime the interrupt handler. 
	 */ 
	if(ether[0] == 0) { 
		ether[0] = xspanalloc(sizeof(Ether), BY2PG, 64*1024); 
1993/0905    
 
		if(PADDR(ether[0])+sizeof(Ether) > Ntranslation*BY2PG) 
			panic("sonic: 16M io map"); 
                 
1993/0906    
	if(ether[0] == 0) { 
		ctlr = malloc(sizeof(Ether)); 
		ether[0] = ctlr; 
		initbufs(ctlr); 
1993/0905    
		enetaddr(ether[0]->ea); 
1993/0903    
	} 
1993/0904    
	ctlr = ether[0]; 
1993/0905/sys/src/9/carrera/devether.c:559,5701993/0906/sys/src/9/carrera/devether.c:621,626
1993/0903    
} 
 
void 
1993/0905    
enab(void) 
{ 
	WR(cr, Rxen); 
} 
                 
void 
1993/0903    
etherinit(void) 
{ 
} 
1993/0905/sys/src/9/carrera/devether.c:578,5841993/0906/sys/src/9/carrera/devether.c:634,639
1993/0905    
		enable = 1; 
		WR(cr, Rxen); 
	} 
                 
1993/0903    
	return devattach('l', spec); 
} 
 
1993/0905/sys/src/9/carrera/devether.c:629,6421993/0906/sys/src/9/carrera/devether.c:684,695
1993/0903    
long 
etherwrite(Chan *c, void *buf, long n, ulong offset) 
{ 
1993/0904    
	Etherpkt *p; 
1993/0906    
	Pbuf *p; 
1993/0904    
	TXpkt *txpkt; 
	Ether *ctlr = ether[0]; 
1993/0903    
 
	USED(offset); 
 
1993/0905    
iprint("ether tx\n"); 
                 
1993/0903    
	if(n > ETHERMAXTU) 
		error(Ebadarg); 
 
1993/0905/sys/src/9/carrera/devether.c:651,6571993/0906/sys/src/9/carrera/devether.c:704,710
1993/0905    
	if(!isoutbuf(ctlr)) 
1993/0903    
		print("ether transmitter jammed\n"); 
1993/0904    
	else { 
		p =(Etherpkt*)ctlr->tb[ctlr->th]; 
1993/0906    
		p =(Pbuf*)ctlr->tb[ctlr->th]; 
1993/0903    
		memmove(p->d, buf, n); 
		if(n < 60) { 
			memset(p->d+n, 0, 60-n); 
1993/0905/sys/src/9/carrera/devether.c:658,6631993/0906/sys/src/9/carrera/devether.c:711,717
1993/0903    
			n = 60; 
		} 
1993/0904    
		memmove(p->s, ctlr->ea, sizeof(ctlr->ea)); 
1993/0906    
		sonicswap(p, n); 
1993/0904    
 
		txpkt = &ctlr->tda[ctlr->th]; 
		txpkt->size = n; 
1993/0905/sys/src/9/carrera/devether.c:671,6781993/0906/sys/src/9/carrera/devether.c:725,730
1993/0903    
	} 
1993/0904    
	qunlock(&ctlr->tlock); 
1993/0905    
 
iprint("tx done %d\n", n); 
                 
1993/0903    
	return n; 
} 
 
1993/0905/sys/src/9/carrera/devether.c:692,6951993/0906/sys/src/9/carrera/devether.c:744,766
1993/0903    
etherwstat(Chan *c, char *dp) 
{ 
1993/0904    
	netifwstat(ether[0], c, dp); 
1993/0906    
} 
 
#define swiz(s)	(s<<24)|((s>>8)&0xff00)|((s<<8)&0xff0000)|(s>>24) 
 
void 
sonicswap(void *a, int n) 
{ 
	ulong *p, t0, t1; 
 
	n = ((n+8)/8)*8; 
	p = a; 
	while(n) { 
		t0 = p[0]; 
		t1 = p[1]; 
		p[0] = swiz(t1); 
		p[1] = swiz(t0); 
		p += 2; 
		n -= 8; 
	} 
1993/0903    
} 
1993/0906/sys/src/9/carrera/devether.c:462,4671993/0918/sys/src/9/carrera/devether.c:462,468 (short | long)
1993/0906    
				txpkt = &c->tda[c->ti]; 
1993/0904    
			} 
			status &= ~(Txdn|Txer); 
1993/0918    
			wakeup(&c->tr); 
1993/0903    
		} 
1993/0904    
 
		if((status & (Pktrx|Rde)) == 0) 
1993/0906/sys/src/9/carrera/devether.c:699,7041993/0918/sys/src/9/carrera/devether.c:700,710
1993/0903    
 
	/* we handle data */ 
1993/0904    
	qlock(&ctlr->tlock); 
1993/0918    
	if(waserror()) { 
		qunlock(&ctlr->tlock); 
		nexterror(); 
	} 
 
1993/0904    
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); 
1993/0905    
 
	if(!isoutbuf(ctlr)) 
1993/0906/sys/src/9/carrera/devether.c:723,7281993/0918/sys/src/9/carrera/devether.c:729,735
1993/0904    
		ctlr->th = NEXT(ctlr->th, Ntb); 
		WR(cr, Txp); 
1993/0903    
	} 
1993/0918    
	poperror(); 
1993/0904    
	qunlock(&ctlr->tlock); 
1993/0905    
 
1993/0903    
	return n; 
1993/0918/sys/src/9/carrera/devether.c:682,6871993/1202/sys/src/9/carrera/devether.c:682,718 (short | long)
1993/0904    
	return ctlr->tda[ctlr->th].status == Host; 
1993/0903    
} 
 
1993/1202    
static int 
etherloop(Etherpkt *p, long n) 
{ 
	int s, different; 
	ushort t; 
	Netfile *f, **fp; 
 
	different = memcmp(p->d, p->s, sizeof(p->s)); 
	if(different && memcmp(p->d, ether.bcast, sizeof(p->d))) 
		return 0; 
 
	s = splhi(); 
	t = (p->type[0]<<8) | p->type[1]; 
	for(fp = ether.f; fp < ðer.f[Ntypes]; fp++) { 
		f = *fp; 
		if(f == 0) 
			continue; 
		if(f->type == t || f->type < 0) 
			switch(qproduce(f->in, p->d, n)){ 
			case -1: 
				print("etherloop overflow\n"); 
				break; 
			case -2: 
				print("etherloop memory\n"); 
				break; 
			} 
	} 
	splx(s); 
	return !different; 
} 
 
1993/0903    
long 
etherwrite(Chan *c, void *buf, long n, ulong offset) 
{ 
1993/0918/sys/src/9/carrera/devether.c:699,7041993/1202/sys/src/9/carrera/devether.c:730,738
1993/0904    
		return netifwrite(ether[0], c, buf, n); 
1993/0903    
 
	/* we handle data */ 
1993/1202    
	if(etherloop(buf, n)) 
		return n; 
 
1993/0904    
	qlock(&ctlr->tlock); 
1993/0918    
	if(waserror()) { 
		qunlock(&ctlr->tlock); 
1993/1202/sys/src/9/carrera/devether.c:690,7011993/1208/sys/src/9/carrera/devether.c:690,701 (short | long)
1993/1202    
	Netfile *f, **fp; 
 
	different = memcmp(p->d, p->s, sizeof(p->s)); 
	if(different && memcmp(p->d, ether.bcast, sizeof(p->d))) 
1993/1208    
	if(different && memcmp(p->d, ether[0]->bcast, sizeof(p->d))) 
1993/1202    
		return 0; 
 
	s = splhi(); 
	t = (p->type[0]<<8) | p->type[1]; 
	for(fp = ether.f; fp < ðer.f[Ntypes]; fp++) { 
1993/1208    
	for(fp = ether[0]->f; fp < ðer[0]->f[Ntypes]; fp++) { 
1993/1202    
		f = *fp; 
		if(f == 0) 
			continue; 
1993/1208/sys/src/9/carrera/devether.c:739,7481993/1211/sys/src/9/carrera/devether.c:739,751 (short | long)
1993/0918    
		nexterror(); 
	} 
 
1993/0904    
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); 
1993/1211    
	tsleep(&ctlr->tr, isoutbuf, ctlr, 1000); 
1993/0905    
 
	if(!isoutbuf(ctlr)) 
1993/1211    
	if(!isoutbuf(ctlr)) { 
1993/0903    
		print("ether transmitter jammed\n"); 
1993/1211    
		reset(ctlr); 
		WR(cr, Rxen); 
	} 
1993/0904    
	else { 
1993/0906    
		p =(Pbuf*)ctlr->tb[ctlr->th]; 
1993/0903    
		memmove(p->d, buf, n); 
1993/1211/sys/src/9/carrera/devether.c:75,811993/1212/sys/src/9/carrera/devether.c:75,81 (short | long)
1993/0903    
enum 
{ 
1993/0904    
	Nrb		= 16,		/* receive buffers */ 
	Ntb		= 8,		/* transmit buffers */ 
1993/1212    
	Ntb		= 16,		/* transmit buffers */ 
1993/0904    
}; 
1993/0903    
 
1993/0904    
enum 
1993/1211/sys/src/9/carrera/devether.c:425,4301993/1212/sys/src/9/carrera/devether.c:425,438
1993/0906    
	} 
1993/0905    
} 
 
1993/1212    
static int 
isoutbuf(void *arg) 
{ 
	Ether *ctlr = arg; 
 
	return ctlr->tda[ctlr->th].status == Host; 
} 
 
1993/0905    
void 
1993/0903    
etherintr(void) 
{ 
1993/1211/sys/src/9/carrera/devether.c:462,4681993/1212/sys/src/9/carrera/devether.c:470,477
1993/0906    
				txpkt = &c->tda[c->ti]; 
1993/0904    
			} 
			status &= ~(Txdn|Txer); 
1993/0918    
			wakeup(&c->tr); 
1993/1212    
			if(isoutbuf(c)) 
				wakeup(&c->tr); 
1993/0903    
		} 
1993/0904    
 
		if((status & (Pktrx|Rde)) == 0) 
1993/1211/sys/src/9/carrera/devether.c:514,5201993/1212/sys/src/9/carrera/devether.c:523,529
1993/0904    
			status &= ~Lcd; 
	 
		/* 
		 * Warnings that something is afoot. 
1993/1212    
		 * Warnings that something is atoe. 
1993/0904    
		 */ 
		if(status & Hbl){ 
1993/0906    
			print("sonic: cd heartbeat lost\n"); 
1993/1211/sys/src/9/carrera/devether.c:675,6881993/1212/sys/src/9/carrera/devether.c:684,689
1993/0903    
} 
 
static int 
isoutbuf(void *arg) 
{ 
1993/0904    
	Ether *ctlr = arg; 
1993/0903    
                 
1993/0904    
	return ctlr->tda[ctlr->th].status == Host; 
1993/0903    
} 
                 
1993/1202    
static int 
etherloop(Etherpkt *p, long n) 
{ 
	int s, different; 
1993/1211/sys/src/9/carrera/devether.c:722,7341993/1212/sys/src/9/carrera/devether.c:723,735
1993/0903    
 
	USED(offset); 
 
	if(n > ETHERMAXTU) 
		error(Ebadarg); 
                 
	/* etherif.c handles structure */ 
	if(NETTYPE(c->qid.path) != Ndataqid) 
1993/0904    
		return netifwrite(ether[0], c, buf, n); 
1993/0903    
 
1993/1212    
	if(n > ETHERMAXTU) 
		error(Ebadarg); 
 
1993/0903    
	/* we handle data */ 
1993/1202    
	if(etherloop(buf, n)) 
		return n; 
1993/1211/sys/src/9/carrera/devether.c:739,7531993/1212/sys/src/9/carrera/devether.c:740,751
1993/0918    
		nexterror(); 
	} 
 
1993/1211    
	tsleep(&ctlr->tr, isoutbuf, ctlr, 1000); 
1993/1212    
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); 
1993/0905    
 
1993/1211    
	if(!isoutbuf(ctlr)) { 
1993/0903    
		print("ether transmitter jammed\n"); 
1993/1211    
		reset(ctlr); 
		WR(cr, Rxen); 
	} 
1993/1212    
	if(!isoutbuf(ctlr)) 
		print("ether transmitter jammed cr #%lux\n", RD(cr)); 
1993/0904    
	else { 
1993/0906    
		p =(Pbuf*)ctlr->tb[ctlr->th]; 
1993/1212    
		p = (Pbuf*)ctlr->tb[ctlr->th]; 
1993/0903    
		memmove(p->d, buf, n); 
		if(n < 60) { 
			memset(p->d+n, 0, 60-n); 
1993/1212/sys/src/9/carrera/devether.c:15,221993/1217/sys/src/9/carrera/devether.c:15,22 (short | long)
1993/0903    
 
1993/0904    
#define SONICADDR	((Sonic*)Sonicbase) 
1993/0903    
 
1993/0904    
#define RD(rn)		(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4)) 
1993/0906    
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
1993/1217    
#define RD(rn)		(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
1993/0906    
#define ISquad(s)	if((ulong)s & 0x7) panic("sonic: Quad alignment"); 
1993/0903    
 
1993/0906    
typedef struct Pbuf Pbuf; 
1993/1212/sys/src/9/carrera/devether.c:74,811993/1217/sys/src/9/carrera/devether.c:74,81
1993/0903    
 
enum 
{ 
1993/0904    
	Nrb		= 16,		/* receive buffers */ 
1993/1212    
	Ntb		= 16,		/* transmit buffers */ 
1993/1217    
	Nrb		= 8,		/* receive buffers */ 
	Ntb		= 8,		/* transmit buffers */ 
1993/0904    
}; 
1993/0903    
 
1993/0904    
enum 
1993/1212/sys/src/9/carrera/devether.c:530,5371993/1217/sys/src/9/carrera/devether.c:530,539
1993/0904    
			status &= ~Hbl; 
1993/0903    
		} 
1993/0904    
		if(status & Br){ 
1993/0906    
			print("sonic: bus retry occurred\n"); 
1993/1217    
			WR(cr, 0); 
			iprint("sonic: bus retry occurred\n"); 
1993/0904    
			status &= ~Br; 
1993/1217    
			for(;;); 
1993/0904    
		} 
	 
		if(status & AllIntr) 
1993/1212/sys/src/9/carrera/devether.c:560,5681993/1217/sys/src/9/carrera/devether.c:562,571
1993/0906    
initbufs(Ether *c) 
{ 
	int i; 
	uchar *mem; 
1993/1217    
	uchar *mem, *base; 
1993/0906    
 
	mem = xspanalloc(64*1024, BY2PG, 0); 
1993/1217    
	base = mem; 
1993/0906    
	mem = CACHELINE(uchar, mem); 
 
	/* 
1993/1212/sys/src/9/carrera/devether.c:595,6001993/1217/sys/src/9/carrera/devether.c:598,605
1993/0906    
		mem += sizeof(Pbuf); 
		mem = QUAD(uchar, mem); 
	} 
1993/1217    
	if(mem >= base+64*1024) 
		panic("sonic init"); 
1993/0906    
} 
 
1993/0903    
void 
1993/1217/sys/src/9/carrera/devether.c:15,221993/1218/sys/src/9/carrera/devether.c:15,22 (short | long)
1993/0903    
 
1993/0904    
#define SONICADDR	((Sonic*)Sonicbase) 
1993/0903    
 
1993/1217    
#define RD(rn)		(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
1993/1218    
#define RD(rn)		(sncdly(), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(sncdly(), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
1993/0906    
#define ISquad(s)	if((ulong)s & 0x7) panic("sonic: Quad alignment"); 
1993/0903    
 
1993/0906    
typedef struct Pbuf Pbuf; 
1993/1217/sys/src/9/carrera/devether.c:74,801993/1218/sys/src/9/carrera/devether.c:74,80
1993/0903    
 
enum 
{ 
1993/1217    
	Nrb		= 8,		/* receive buffers */ 
1993/1218    
	Nrb		= 16,		/* receive buffers */ 
1993/1217    
	Ntb		= 8,		/* transmit buffers */ 
1993/0904    
}; 
1993/0903    
 
1993/1217/sys/src/9/carrera/devether.c:251,2561993/1218/sys/src/9/carrera/devether.c:251,266
1993/0906    
void sonicswap(void*, int); 
 
1993/0903    
static void 
1993/1218    
sncdly(void) 
{ 
	int i, j, *pj; 
 
	pj = &j; 
	for(i = 0; i < 200; i++) 
		*pj++; 
} 
 
static void 
1993/0906    
wus(ushort *a, ushort v) 
{ 
	a[0] = v; 
1993/1217/sys/src/9/carrera/devether.c:530,5391993/1218/sys/src/9/carrera/devether.c:540,547
1993/0904    
			status &= ~Hbl; 
1993/0903    
		} 
1993/0904    
		if(status & Br){ 
1993/1217    
			WR(cr, 0); 
			iprint("sonic: bus retry occurred\n"); 
1993/1218    
			print("sonic: bus retry occurred\n"); 
1993/0904    
			status &= ~Br; 
1993/1217    
			for(;;); 
1993/0904    
		} 
	 
		if(status & AllIntr) 
1993/1218/sys/src/9/carrera/devether.c:15,221993/1219/sys/src/9/carrera/devether.c:15,22 (short | long)
1993/0903    
 
1993/0904    
#define SONICADDR	((Sonic*)Sonicbase) 
1993/0903    
 
1993/1218    
#define RD(rn)		(sncdly(), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(sncdly(), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
1993/1219    
#define RD(rn)		(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
1993/0906    
#define ISquad(s)	if((ulong)s & 0x7) panic("sonic: Quad alignment"); 
1993/0903    
 
1993/0906    
typedef struct Pbuf Pbuf; 
1993/1218/sys/src/9/carrera/devether.c:251,2661993/1219/sys/src/9/carrera/devether.c:251,256
1993/0906    
void sonicswap(void*, int); 
 
1993/0903    
static void 
1993/1218    
sncdly(void) 
{ 
	int i, j, *pj; 
                 
	pj = &j; 
	for(i = 0; i < 200; i++) 
		*pj++; 
} 
                 
static void 
1993/0906    
wus(ushort *a, ushort v) 
{ 
	a[0] = v; 
1993/1218/sys/src/9/carrera/devether.c:458,4691993/1219/sys/src/9/carrera/devether.c:448,460
1993/0904    
		if(status == 0) 
			break; 
 
1993/1219    
		/* Clear the interrupt cause */ 
1993/0904    
		WR(isr, status); 
	 
		/* 
		 * Transmission complete, for good or bad. 
		 */ 
		if(status & (Txdn|Txer)){ 
1993/1219    
		if(status & (Txdn|Txer)) { 
1993/0906    
			txpkt = &c->tda[c->ti]; 
1993/0904    
			while(txpkt->status != Host){ 
				if(txpkt->status == Interface){ 
1993/1218/sys/src/9/carrera/devether.c:621,6271993/1219/sys/src/9/carrera/devether.c:612,617
1993/0904    
	 * Set the physical ethernet address and 
	 * prime the interrupt handler. 
	 */ 
1993/0905    
                 
1993/0906    
	if(ether[0] == 0) { 
		ctlr = malloc(sizeof(Ether)); 
		ether[0] = ctlr; 
1993/1219/sys/src/9/carrera/devether.c:563,5691993/1231/sys/src/9/carrera/devether.c:563,569 (short | long)
1993/0906    
	int i; 
1993/1217    
	uchar *mem, *base; 
1993/0906    
 
	mem = xspanalloc(64*1024, BY2PG, 0); 
1993/1231    
	mem = xspanalloc(64*1024, 8, 64*1024); 
1993/1217    
	base = mem; 
1993/0906    
	mem = CACHELINE(uchar, mem); 
 
1993/1219/sys/src/9/carrera/devether.c:581,5921993/1231/sys/src/9/carrera/devether.c:581,587
1993/0906    
 
	c->cda = UNCACHED(Cam, mem); 
 
	/* 
	 * DMA buffers are cache coherent - but we must not straddle 
	 * a cache line 
	 */ 
	mem = CACHELINE(uchar, mem+sizeof(Cam)); 
                 
	for(i = 0; i < Nrb; i++) { 
		c->rb[i] = UNCACHED(uchar, mem); 
		mem += sizeof(Pbuf)+4; 
1993/1231/sys/src/9/carrera/devether.c:271,2761994/0107/sys/src/9/carrera/devether.c:271,277 (short | long)
1993/0904    
	 */ 
	WR(cr, Rst); 
1993/0905    
	WR(dcr, 0x2423);	/* 5-19 Carrera manual */ 
1994/0107    
	WR(cr, 0); 
1993/0903    
 
1993/0904    
	/* 
	 * Initialise the receive resource area (RRA) and 
1993/1231/sys/src/9/carrera/devether.c:379,3891994/0107/sys/src/9/carrera/devether.c:380,387
1993/0904    
	WR(cdc, 1); 
 
1993/0906    
	/* 
	 * End the reset 
	 * Load the Resource Descriptors and Cam contents 
	 */ 
	WR(cr, 0); 
                 
	WR(cr, Rrra); 
	while(RD(cr) & Rrra) 
		; 
1993/1231/sys/src/9/carrera/devether.c:397,4031994/0107/sys/src/9/carrera/devether.c:395,401
1993/0904    
	 * and interrupt-mask registers. 
	 * The SONIC is now initialised, but not enabled. 
	 */ 
	WR(rcr, Err|Rnt|Brd); 
1994/0107    
	WR(rcr, Brd); 
1993/0904    
	WR(tcr, 0); 
	WR(imr, AllIntr); 
1993/0903    
} 
1993/1231/sys/src/9/carrera/devether.c:437,4421994/0107/sys/src/9/carrera/devether.c:435,441
1993/0903    
etherintr(void) 
{ 
1993/0906    
	Ether *c; 
1994/0107    
	ushort *s; 
1993/0904    
	ulong status; 
	TXpkt *txpkt; 
	RXpkt *rxpkt; 
1993/1231/sys/src/9/carrera/devether.c:448,4551994/0107/sys/src/9/carrera/devether.c:447,466
1993/0904    
		if(status == 0) 
			break; 
 
1993/1219    
		/* Clear the interrupt cause */ 
1993/0904    
		WR(isr, status); 
1994/0107    
		/* 
		 * Warnings that something is atoe. 
		 */ 
		if(status & Hbl){ 
			WR(isr, Hbl); 
			status &= ~Hbl; 
			print("sonic: cd heartbeat lost\n"); 
		} 
		if(status & Br){ 
WR(cr, Rst); 
			print("sonic: bus retry occurred\n"); 
(*(void(*)(void))0xA001C020)(); 
			status &= ~Br; 
		} 
1993/0904    
	 
		/* 
		 * Transmission complete, for good or bad. 
1993/1231/sys/src/9/carrera/devether.c:470,4751994/0107/sys/src/9/carrera/devether.c:481,487
1993/0906    
				c->ti = NEXT(c->ti, Ntb); 
				txpkt = &c->tda[c->ti]; 
1993/0904    
			} 
1994/0107    
			WR(isr, status & (Txdn|Txer)); 
1993/0904    
			status &= ~(Txdn|Txer); 
1993/1212    
			if(isoutbuf(c)) 
				wakeup(&c->tr); 
1993/1231/sys/src/9/carrera/devether.c:500,5051994/0107/sys/src/9/carrera/devether.c:512,518
1993/0904    
			else 
1993/0906    
				c->buffs++; 
1993/0904    
	 
1994/0107    
			rxpkt->status  = 0; 
1993/0904    
			/* 
			 * Finished with this packet, it becomes the 
			 * last free packet in the ring, so give it Eol, 
1993/1231/sys/src/9/carrera/devether.c:506,5181994/0107/sys/src/9/carrera/devether.c:519,533
1993/0904    
			 * and take the Eol bit off the previous packet. 
			 * Move the ring index on. 
			 */ 
			rxpkt->link |= Eol; 
1994/0107    
			wus(&rxpkt->link,  rxpkt->link|Eol); 
1993/0904    
			rxpkt->owner = Interface; 
1993/0906    
			c->rda[PREV(c->rh, Nrb)].link &= ~Eol; 
1994/0107    
			s = &c->rda[PREV(c->rh, Nrb)].link; 
			wus(s, *s & ~Eol); 
1993/0906    
			c->rh = NEXT(c->rh, Nrb); 
1993/0904    
	 
1993/0906    
			rxpkt = &c->rda[c->rh]; 
1993/0903    
		} 
1994/0107    
		WR(isr, status & (Pktrx|Rde)); 
1993/0904    
		status &= ~(Pktrx|Rde); 
1993/0903    
 
1993/0904    
	noinput: 
1993/1231/sys/src/9/carrera/devether.c:520,5421994/0107/sys/src/9/carrera/devether.c:535,549
1993/0904    
		 * We get a 'load CAM done' interrupt 
		 * after initialisation. Ignore it. 
1993/0903    
		 */ 
1993/0904    
		if(status & Lcd) 
1994/0107    
		if(status & Lcd) { 
			WR(isr, Lcd); 
1993/0904    
			status &= ~Lcd; 
	                 
		/* 
1993/1212    
		 * Warnings that something is atoe. 
1993/0904    
		 */ 
		if(status & Hbl){ 
1993/0906    
			print("sonic: cd heartbeat lost\n"); 
1993/0904    
			status &= ~Hbl; 
1993/0903    
		} 
1993/0904    
		if(status & Br){ 
1993/1218    
			print("sonic: bus retry occurred\n"); 
1993/0904    
			status &= ~Br; 
		} 
	 
		if(status & AllIntr) 
1994/0107    
		if(status & AllIntr) { 
			WR(isr, status); 
1993/0906    
			print("sonic #%lux\n", status); 
1994/0107    
		} 
1993/0903    
	} 
} 
 
1993/1231/sys/src/9/carrera/devether.c:716,7211994/0107/sys/src/9/carrera/devether.c:723,729
1993/0903    
etherwrite(Chan *c, void *buf, long n, ulong offset) 
{ 
1993/0906    
	Pbuf *p; 
1994/0107    
	ushort *s; 
1993/0904    
	TXpkt *txpkt; 
	Ether *ctlr = ether[0]; 
1993/0903    
 
1993/1231/sys/src/9/carrera/devether.c:733,7381994/0107/sys/src/9/carrera/devether.c:741,747
1993/1202    
		return n; 
 
1993/0904    
	qlock(&ctlr->tlock); 
1994/0107    
	ctlr->outpackets++; 
1993/0918    
	if(waserror()) { 
		qunlock(&ctlr->tlock); 
		nexterror(); 
1993/1231/sys/src/9/carrera/devether.c:755,7631994/0107/sys/src/9/carrera/devether.c:764,773
1993/0904    
		txpkt = &ctlr->tda[ctlr->th]; 
		txpkt->size = n; 
		txpkt->fsize = n; 
		txpkt->link |= Eol; 
1994/0107    
		wus(&txpkt->link, txpkt->link|Eol); 
1993/0904    
		txpkt->status = Interface; 
		ctlr->tda[PREV(ctlr->th, Ntb)].link &= ~Eol; 
1994/0107    
		s = &ctlr->tda[PREV(ctlr->th, Ntb)].link; 
		wus(s, *s & ~Eol); 
1993/0904    
 
		ctlr->th = NEXT(ctlr->th, Ntb); 
		WR(cr, Txp); 
1994/0107/sys/src/9/carrera/devether.c:570,5761994/0524/sys/src/9/carrera/devether.c:570,579 (short | long)
1993/0906    
	int i; 
1993/1217    
	uchar *mem, *base; 
1993/0906    
 
1993/1231    
	mem = xspanalloc(64*1024, 8, 64*1024); 
1994/0524    
	/* Put the ethernet buffers in the same place 
	 * as the bootrom 
	 */ 
	mem = (void*)(KZERO|0x2000); 
1993/1217    
	base = mem; 
1993/0906    
	mem = CACHELINE(uchar, mem); 
 
1994/0524/sys/src/9/carrera/devether.c:691,6961995/0108/sys/src/9/carrera/devether.c:691,702 (short | long)
1993/0904    
	return netifread(ether[0], c, buf, n, offset); 
1993/0903    
} 
 
1995/0108    
Block* 
etherbread(Chan *c, long n, ulong offset) 
{ 
	return devbread(c, n, offset); 
} 
 
1993/0903    
static int 
1993/1202    
etherloop(Etherpkt *p, long n) 
{ 
1994/0524/sys/src/9/carrera/devether.c:779,7841995/0108/sys/src/9/carrera/devether.c:785,796
1993/0904    
	qunlock(&ctlr->tlock); 
1993/0905    
 
1993/0903    
	return n; 
1995/0108    
} 
 
long 
etherbwrite(Chan *c, Block *bp, ulong offset) 
{ 
	return devbwrite(c, bp, offset); 
1993/0903    
} 
 
void 
1995/0108/sys/src/9/carrera/devether.c:703,7161995/0114/sys/src/9/carrera/devether.c:703,717 (short | long)
1993/1202    
	int s, different; 
	ushort t; 
	Netfile *f, **fp; 
1995/0114    
	Ether *ctlr = ether[0]; 
1993/1202    
 
	different = memcmp(p->d, p->s, sizeof(p->s)); 
1993/1208    
	if(different && memcmp(p->d, ether[0]->bcast, sizeof(p->d))) 
1995/0114    
	different = memcmp(p->d, ctlr->ea, sizeof(ctlr->ea)); 
	if(different && memcmp(p->d, ctlr->bcast, sizeof(p->d))) 
1993/1202    
		return 0; 
 
	s = splhi(); 
	t = (p->type[0]<<8) | p->type[1]; 
1993/1208    
	for(fp = ether[0]->f; fp < ðer[0]->f[Ntypes]; fp++) { 
1995/0114    
	for(fp = ctlr->f; fp < &ctlr->f[Ntypes]; fp++) { 
1993/1202    
		f = *fp; 
		if(f == 0) 
			continue; 
1995/0108/sys/src/9/carrera/devether.c:745,7501995/0114/sys/src/9/carrera/devether.c:746,754
1993/1212    
	if(n > ETHERMAXTU) 
		error(Ebadarg); 
 
1995/0114    
	p = buf; 
	memmove(p->s, ctlr->ea, sizeof(ctlr->ea)); 
 
1993/0903    
	/* we handle data */ 
1993/1202    
	if(etherloop(buf, n)) 
		return n; 
1995/0108/sys/src/9/carrera/devether.c:767,7731995/0114/sys/src/9/carrera/devether.c:771,776
1993/0903    
			memset(p->d+n, 0, 60-n); 
			n = 60; 
		} 
1993/0904    
		memmove(p->s, ctlr->ea, sizeof(ctlr->ea)); 
1993/0906    
		sonicswap(p, n); 
1993/0904    
 
		txpkt = &ctlr->tda[ctlr->th]; 
1995/0114/sys/src/9/carrera/devether.c:652,6571995/0520/sys/src/9/carrera/devether.c:652,659 (short | long)
1993/0905    
		enable = 1; 
		WR(cr, Rxen); 
	} 
1995/0520    
	if(*spec && strcmp(spec, "0") != 0) 
		error(Eio); 
1993/0903    
	return devattach('l', spec); 
} 
 
1995/0520/sys/src/9/carrera/devether.c:241,2471997/0327/sys/src/9/carrera/devether.c:241,247 (short | long)
1993/0903    
	Netif; 
1993/0904    
}; 
1993/0903    
 
1993/0904    
Ether *ether[Nether]; 
1997/0327    
static Ether *ether[Nether]; 
1993/0903    
 
1993/0904    
#define NEXT(x, l)	(((x)+1)%(l)) 
#define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1) 
1995/0520/sys/src/9/carrera/devether.c:248,2541997/0327/sys/src/9/carrera/devether.c:248,254
1993/0904    
#define LS16(addr)	(PADDR(addr) & 0xFFFF) 
#define MS16(addr)	((PADDR(addr)>>16) & 0xFFFF) 
 
1993/0906    
void sonicswap(void*, int); 
1997/0327    
static void sonicswap(void*, int); 
1993/0906    
 
1993/0903    
static void 
1993/0906    
wus(ushort *a, ushort v) 
1995/0520/sys/src/9/carrera/devether.c:400,4061997/0327/sys/src/9/carrera/devether.c:400,406
1993/0904    
	WR(imr, AllIntr); 
1993/0903    
} 
 
void 
1997/0327    
static void 
1993/0906    
sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p) 
1993/0905    
{ 
1993/0906    
	int len; 
1995/0520/sys/src/9/carrera/devether.c:606,6121997/0327/sys/src/9/carrera/devether.c:606,612
1993/1217    
		panic("sonic init"); 
1993/0906    
} 
 
1993/0903    
void 
1997/0327    
static void 
1993/0903    
etherreset(void) 
{ 
1993/0904    
	Ether *ctlr; 
1995/0520/sys/src/9/carrera/devether.c:630,6361997/0327/sys/src/9/carrera/devether.c:630,636
1993/0904    
	memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); 
1993/0903    
 
	/* general network interface structure */ 
1993/0904    
	netifinit(ether[0], "ether", Ntypes, 32*1024); 
1997/0327    
	netifinit(ether[0], "ether0", Ntypes, 32*1024); 
1993/0904    
	ether[0]->alen = 6; 
	memmove(ether[0]->addr, ether[0]->ea, 6); 
	memmove(ether[0]->bcast, ctlr->ba, 6); 
1995/0520/sys/src/9/carrera/devether.c:638,6491997/0327/sys/src/9/carrera/devether.c:638,644
1993/0904    
	ether[0]->arg = ether[0]; 
1993/0903    
} 
 
void 
etherinit(void) 
{ 
} 
                 
Chan* 
1997/0327    
static Chan* 
1993/0903    
etherattach(char *spec) 
{ 
1993/0905    
	static int enable; 
1995/0520/sys/src/9/carrera/devether.c:657,6871997/0327/sys/src/9/carrera/devether.c:652,676
1993/0903    
	return devattach('l', spec); 
} 
 
Chan* 
etherclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
                 
int 
1997/0327    
static int 
1993/0903    
etherwalk(Chan *c, char *name) 
{ 
1993/0904    
	return netifwalk(ether[0], c, name); 
1993/0903    
} 
 
Chan* 
1997/0327    
static Chan* 
1993/0903    
etheropen(Chan *c, int omode) 
{ 
1993/0904    
	return netifopen(ether[0], c, omode); 
1993/0903    
} 
 
void 
1997/0327    
static void 
1993/0903    
ethercreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	USED(c, name, omode, perm); 
} 
 
void 
1997/0327    
static void 
1993/0903    
etherclose(Chan *c) 
{ 
1993/0904    
	netifclose(ether[0], c); 
1995/0520/sys/src/9/carrera/devether.c:693,7041997/0327/sys/src/9/carrera/devether.c:682,687
1993/0904    
	return netifread(ether[0], c, buf, n, offset); 
1993/0903    
} 
 
1995/0108    
Block* 
etherbread(Chan *c, long n, ulong offset) 
{ 
	return devbread(c, n, offset); 
} 
                 
1993/0903    
static int 
1993/1202    
etherloop(Etherpkt *p, long n) 
{ 
1995/0520/sys/src/9/carrera/devether.c:731,7371997/0327/sys/src/9/carrera/devether.c:714,720
1993/1202    
	return !different; 
} 
 
1993/0903    
long 
1997/0327    
static long 
1993/0903    
etherwrite(Chan *c, void *buf, long n, ulong offset) 
{ 
1993/0906    
	Pbuf *p; 
1995/0520/sys/src/9/carrera/devether.c:792,8161997/0327/sys/src/9/carrera/devether.c:775,793
1993/0903    
	return n; 
1995/0108    
} 
 
long 
etherbwrite(Chan *c, Block *bp, ulong offset) 
{ 
	return devbwrite(c, bp, offset); 
1993/0903    
} 
                 
void 
1997/0327    
static void 
1993/0903    
etherremove(Chan *c) 
{ 
	USED(c); 
} 
 
void 
1997/0327    
static void 
1993/0903    
etherstat(Chan *c, char *dp) 
{ 
1993/0904    
	netifstat(ether[0], c, dp); 
1993/0903    
} 
 
void 
1997/0327    
static void 
1993/0903    
etherwstat(Chan *c, char *dp) 
{ 
1993/0904    
	netifwstat(ether[0], c, dp); 
1995/0520/sys/src/9/carrera/devether.c:818,8241997/0327/sys/src/9/carrera/devether.c:795,801
1993/0906    
 
#define swiz(s)	(s<<24)|((s>>8)&0xff00)|((s<<8)&0xff0000)|(s>>24) 
 
void 
1997/0327    
static void 
1993/0906    
sonicswap(void *a, int n) 
{ 
	ulong *p, t0, t1; 
1995/0520/sys/src/9/carrera/devether.c:834,8361997/0327/sys/src/9/carrera/devether.c:811,854
1993/0906    
		n -= 8; 
	} 
1993/0903    
} 
1997/0327    
 
int 
parseether(uchar *to, char *from) 
{ 
	char nip[4]; 
	char *p; 
	int i; 
 
	p = from; 
	for(i = 0; i < 6; i++){ 
		if(*p == 0) 
			return -1; 
		nip[0] = *p++; 
		if(*p == 0) 
			return -1; 
		nip[1] = *p++; 
		nip[2] = 0; 
		to[i] = strtoul(nip, 0, 16); 
		if(*p == ':') 
			p++; 
	} 
	return 0; 
} 
 
Dev etherdevtab = { 
	etherreset, 
	devinit, 
	etherattach, 
	devclone, 
	etherwalk, 
	etherstat, 
	etheropen, 
	ethercreate, 
	etherclose, 
	etherread, 
	devbread, 
	etherwrite, 
	devbwrite, 
	etherremove, 
	etherwstat, 
}; 
1997/0327/sys/src/9/carrera/devether.c:836,8411997/0408/sys/src/9/carrera/devether.c:836,844 (short | long)
1997/0327    
} 
 
Dev etherdevtab = { 
1997/0408    
	'l', 
	"ether", 
 
1997/0327    
	etherreset, 
	devinit, 
	etherattach, 
1997/0408/sys/src/9/carrera/devether.c:1,8191997/1210/sys/src/9/carrera/devether.c:1,372 (short | long)
1993/0903    
#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" 
1997/1210    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
#include "ureg.h" 
#include "../port/error.h" 
#include "../port/netif.h" 
1993/0903    
 
/* 
1993/0904    
 * National Semiconductor DP83932 
 * Systems-Oriented Network Interface Controller 
 * (SONIC) 
1993/0903    
 */ 
1997/1210    
#include "etherif.h" 
1993/0903    
 
1993/0904    
#define SONICADDR	((Sonic*)Sonicbase) 
1997/1210    
static Ether *etherxx[MaxEther]; 
1993/0903    
 
1993/1219    
#define RD(rn)		(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4)) 
#define WR(rn, v)	(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) 
1993/0906    
#define ISquad(s)	if((ulong)s & 0x7) panic("sonic: Quad alignment"); 
1993/0903    
                 
1993/0906    
typedef struct Pbuf Pbuf; 
struct Pbuf 
1997/1210    
Chan* 
etherattach(char* spec) 
1993/0906    
{ 
	uchar	d[6]; 
	uchar	s[6]; 
	uchar	type[2]; 
	uchar	data[1500]; 
	uchar	crc[4]; 
}; 
1997/1210    
	ulong ctlrno; 
	char *p; 
	Chan *chan; 
1993/0906    
 
1993/0904    
typedef struct 
{ 
	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 */ 
1993/0906    
	ulong	crba0;		/* DO NOT WRITE THESE */ 
	ulong	crba1; 
	ulong	rbwc0; 
	ulong	rbwc1; 
1993/0904    
	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; 
1997/1210    
	ctlrno = 0; 
	if(spec && *spec){ 
		ctlrno = strtoul(spec, &p, 0); 
		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) 
			error(Ebadarg); 
	} 
	if(etherxx[ctlrno] == 0) 
		error(Enodev); 
1993/0903    
 
enum 
{ 
1993/1218    
	Nrb		= 16,		/* receive buffers */ 
1993/1217    
	Ntb		= 8,		/* transmit buffers */ 
1993/0904    
}; 
1997/1210    
	chan = devattach('l', spec); 
	chan->dev = ctlrno; 
	if(etherxx[ctlrno]->dev && etherxx[ctlrno]->dev->attach) 
		etherxx[ctlrno]->dev->attach(etherxx[ctlrno]); 
	return chan; 
} 
1993/0903    
 
1993/0904    
enum 
1997/1210    
static int 
etherwalk(Chan* chan, char* name) 
1993/0904    
{ 
	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 */ 
1997/1210    
	return netifwalk(etherxx[chan->dev], chan, name); 
} 
1993/0903    
 
1993/0904    
	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 */ 
1993/0903    
                 
1993/0904    
	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 */ 
1993/0903    
                 
1993/0904    
	Ptx	= 0x0001,	/* packet transmitted ok */ 
	Pintr	= 0x8000,	/* programmable interrupt */ 
1993/0903    
                 
1993/0904    
	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 */ 
1993/0906    
                 
	Rxbuf	= sizeof(Pbuf)+4, 
	Txbuf	= sizeof(Pbuf), 
1993/0903    
}; 
                 
1993/0904    
/* 
 * Receive Resource Descriptor. 
 */ 
typedef struct 
1997/1210    
static void 
etherstat(Chan* chan, char* dp) 
1993/0904    
{ 
1993/0906    
	ushort	pad1; 
	ushort		ptr1;		/* buffer pointer in the RRA */ 
	ushort  pad2; 
	ushort		ptr0; 
	ushort  pad3; 
	ushort		wc1;		/* buffer word count in the RRA */ 
	ushort  pad4; 
	ushort		wc0; 
1993/0904    
} RXrsc; 
1997/1210    
	netifstat(etherxx[chan->dev], chan, dp); 
} 
1993/0903    
 
/* 
1993/0904    
 * Receive Packet Descriptor. 
1993/0903    
 */ 
typedef struct 
1997/1210    
static Chan* 
etheropen(Chan* chan, int omode) 
1993/0903    
{ 
1993/0906    
	ushort	pad0; 
		ushort	count;		/* packet byte count */ 
	ushort	pad1; 
		ushort	status;		/* receive status */ 
	ushort	pad2; 
		ushort	ptr1;		/* buffer pointer */ 
	ushort	pad3; 
		ushort	ptr0; 
	ushort  pad4; 
		ushort	link;		/* descriptor link and EOL */ 
	ushort	pad5; 
		ushort	seqno;		/*  */ 
	ulong	pad6; 
	ushort  pad7; 
		ushort	owner;		/* in use */ 
1993/0904    
} RXpkt; 
1997/1210    
	return netifopen(etherxx[chan->dev], chan, omode); 
} 
1993/0903    
 
1993/0904    
/* 
 * Transmit Packet Descriptor. 
 */ 
typedef struct 
1997/1210    
static void 
ethercreate(Chan*, char*, int, ulong) 
1993/0904    
{ 
1993/0906    
	ushort	pad1; 
		ushort	config;		/*  */ 
	ushort	pad0; 
		ushort	status;		/* transmit status */ 
	ushort	pad3; 
		ushort	count;		/* fragment count */ 
	ushort	pad2; 
		ushort	size;		/* byte count of entire packet */ 
	ushort	pad5; 
		ushort	ptr1; 
	ushort	pad4; 
		ushort	ptr0;		/* packet pointer */ 
	ushort	pad7; 
		ushort	link;		/* descriptor link */ 
	ushort	pad6; 
		ushort	fsize;		/* fragment size */ 
1993/0904    
} TXpkt; 
1997/1210    
} 
1993/0904    
 
enum{ 
	Eol		= 1,	/* end of list bit in descriptor link */ 
	Host		= 0,	/* descriptor belongs to host */ 
	Interface	= -1,	/* descriptor belongs to interface */ 
                 
	Nether		= 1, 
1993/0905    
	Ntypes		= 8, 
1993/0904    
}; 
                 
/* 
 * CAM Descriptor 
 */ 
1993/0905    
typedef struct 
1997/1210    
static void 
etherclose(Chan* chan) 
1993/0905    
{ 
1993/0906    
	ushort	pad0; 
		ushort	cap0;		/* CAM address port 0 */ 
	ushort	pad1; 
		ushort	cep;		/* CAM entry pointer */ 
	ushort	pad2; 
		ushort	cap2;		/* CAM address port 2 */ 
	ushort	pad3; 
		ushort	cap1;		/* CAM address port 1 */ 
	ulong	pad4; 
	ushort	pad5; 
		ushort	ce;		/* CAM enable */ 
1993/0904    
} Cam; 
1997/1210    
	netifclose(etherxx[chan->dev], chan); 
} 
1993/0904    
 
typedef struct Ether Ether; 
1993/0903    
struct Ether 
1997/1210    
static long 
etherread(Chan* chan, void* buf, long n, ulong offset) 
1993/0903    
{ 
	uchar	ea[6]; 
1993/0904    
	uchar	ba[6]; 
1997/1210    
	Ether *ether; 
1993/0903    
 
	QLock	tlock;		/* lock for grabbing transmitter queue */ 
	Rendez	tr;		/* wait here for free xmit buffer */ 
1993/0904    
	int	th;		/* first transmit buffer owned by host */	 
	int	ti;		/* first transmit buffer owned by interface */ 
1997/1210    
	ether = etherxx[chan->dev]; 
	if((chan->qid.path & CHDIR) == 0 && ether->dev && ether->dev->ifstat){ 
		/* 
		 * With some controllers it is necessary to reach 
		 * into the chip to extract statistics. 
		 */ 
		if(NETTYPE(chan->qid.path) == Nifstatqid) 
			return ether->dev->ifstat(ether, buf, n, offset); 
		else if(NETTYPE(chan->qid.path) == Nstatqid) 
			ether->dev->ifstat(ether, buf, 0, offset); 
	} 
1993/0903    
 
1993/0904    
	int	rh;		/* first receive buffer owned by host */ 
	int	ri;		/* first receive buffer owned by interface */ 
1997/1210    
	return netifread(ether, chan, buf, n, offset); 
} 
1993/0904    
 
1993/0906    
	RXrsc	*rra;		/* receive resource area */ 
	RXpkt	*rda;		/* receive descriptor area */ 
	TXpkt	*tda;		/* transmit descriptor area */ 
	Cam	*cda;		/* CAM descriptor area */ 
1993/0904    
                 
1993/0906    
	uchar	*rb[Nrb];	/* receive buffer area */ 
	uchar	*tb[Ntb];	/* transmit buffer area */ 
                 
1993/0903    
	Netif; 
1993/0904    
}; 
1993/0903    
                 
1997/0327    
static Ether *ether[Nether]; 
1993/0903    
                 
1993/0904    
#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) 
                 
1997/0327    
static void sonicswap(void*, int); 
1993/0906    
                 
1993/0903    
static void 
1993/0906    
wus(ushort *a, ushort v) 
1997/1210    
static Block* 
etherbread(Chan* chan, long n, ulong offset) 
1993/0906    
{ 
	a[0] = v; 
	a[-1] = v; 
1997/1210    
	return netifbread(etherxx[chan->dev], chan, n, offset); 
1993/0906    
} 
 
static void 
1993/0904    
reset(Ether *ctlr) 
1997/1210    
etherremove(Chan*) 
1993/0903    
{ 
1993/0904    
	int i; 
1993/0906    
	ushort lolen, hilen, loadr, hiadr; 
1993/0903    
                 
1993/0904    
	/* 
	 * Reset the SONIC, toggle the Rst bit. 
	 * Set the data config register for synchronous termination 
	 * and 32-bit data-path width. 
1993/0906    
	 * Setup the descriptor and buffer area. 
1993/0904    
	 */ 
	WR(cr, Rst); 
1993/0905    
	WR(dcr, 0x2423);	/* 5-19 Carrera manual */ 
1994/0107    
	WR(cr, 0); 
1993/0903    
                 
1993/0904    
	/* 
	 * 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; 
1993/0906    
	 * thus the size of the receive buffers must be sizeof(Pbuf)+4. 
1993/0904    
	 * Set up the receive descriptors as a ring. 
	 */ 
1993/0906    
                 
	lolen = (Rxbuf/2) & 0xFFFF; 
	hilen = ((Rxbuf/2)>>16) & 0xFFFF; 
                 
1993/0905    
	for(i = 0; i < Nrb; i++) { 
1993/0906    
		wus(&ctlr->rra[i].wc0, lolen); 
		wus(&ctlr->rra[i].wc1, hilen); 
1993/0903    
                 
1993/0906    
		ctlr->rda[i].link =  LS16(&ctlr->rda[NEXT(i, Nrb)]); 
1993/0904    
		ctlr->rda[i].owner = Interface; 
1993/0903    
                 
1993/0906    
		loadr = LS16(ctlr->rb[i]); 
		wus(&ctlr->rra[i].ptr0, loadr); 
		wus(&ctlr->rda[i].ptr0, loadr); 
                 
		hiadr = MS16(ctlr->rb[i]); 
		wus(&ctlr->rra[i].ptr1, hiadr); 
		wus(&ctlr->rda[i].ptr1, hiadr); 
1993/0904    
	} 
1993/0903    
                 
1993/0906    
	/* 
	 * Check the important resources are QUAD aligned 
	 */ 
1993/0905    
	ISquad(ctlr->rra); 
	ISquad(ctlr->rda); 
                 
1993/0904    
	/* 
	 * Terminate the receive descriptor ring 
	 * and load the SONIC registers to describe the RDA. 
1993/0903    
	 */ 
1993/0904    
	ctlr->rda[Nrb-1].link |= Eol; 
1993/0903    
                 
1993/0904    
	WR(crda, LS16(ctlr->rda)); 
	WR(urda, MS16(ctlr->rda)); 
1993/0906    
	WR(eobc, Rxbuf/2 - 2); 
1993/0903    
                 
1993/0904    
	/* 
	 * 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. 
	 */ 
	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])); 
1993/0903    
                 
1993/0904    
	/* 
	 * 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)]); 
	} 
                 
	WR(ctda, LS16(&ctlr->tda[0])); 
	WR(utda, MS16(&ctlr->tda[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. 
	 */ 
1993/0906    
	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; 
1993/0904    
                 
1993/0906    
	WR(cdp, LS16(ctlr->cda)); 
1993/0904    
	WR(cdc, 1); 
                 
1993/0906    
	/* 
	 * Load the Resource Descriptors and Cam contents 
	 */ 
	WR(cr, Rrra); 
	while(RD(cr) & Rrra) 
		; 
                 
1993/0904    
	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. 
	 */ 
1994/0107    
	WR(rcr, Brd); 
1993/0904    
	WR(tcr, 0); 
	WR(imr, AllIntr); 
1993/0903    
} 
 
1997/0327    
static void 
1993/0906    
sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p) 
1997/1210    
etherwstat(Chan* chan, char* dp) 
1993/0905    
{ 
1993/0906    
	int len; 
	ushort type; 
	Netfile *f, **fp, **ep; 
                 
	/* 
	 * Sonic delivers CRC as part of the packet count 
	 */ 
	len = (r->count & 0xFFFF)-4; 
                 
	sonicswap(p, len); 
                 
	type = (p->type[0]<<8) | p->type[1]; 
	ep = &ctlr->f[Ntypes]; 
	for(fp = ctlr->f; fp < ep; fp++) { 
		f = *fp; 
		if(f && (f->type == type || f->type < 0)) 
			qproduce(f->in, p->d, len); 
	} 
1997/1210    
	netifwstat(etherxx[chan->dev], chan, dp); 
1993/0905    
} 
 
1993/1212    
static int 
isoutbuf(void *arg) 
1997/1210    
static void 
etherrtrace(Netfile* f, Etherpkt* pkt, int len) 
1993/1212    
{ 
	Ether *ctlr = arg; 
1997/1210    
	int i, n; 
	Block *bp; 
1993/1212    
 
	return ctlr->tda[ctlr->th].status == Host; 
1997/1210    
	if(qwindow(f->in) <= 0) 
		return; 
	if(len > 64) 
		n = 64; 
	else 
		n = len; 
	bp = iallocb(n); 
	if(bp == 0) 
		return; 
	memmove(bp->wp, pkt->d, n); 
	i = TK2MS(MACHP(0)->ticks); 
	bp->wp[58] = len>>8; 
	bp->wp[59] = len; 
	bp->wp[60] = i>>24; 
	bp->wp[61] = i>>16; 
	bp->wp[62] = i>>8; 
	bp->wp[63] = i; 
	bp->wp += 64; 
	qpass(f->in, bp); 
1993/1212    
} 
 
1993/0905    
void 
1993/0903    
etherintr(void) 
1997/1210    
Block* 
etheriq(Ether* ether, Block* bp, int freebp) 
1993/0903    
{ 
1993/0906    
	Ether *c; 
1994/0107    
	ushort *s; 
1993/0904    
	ulong status; 
	TXpkt *txpkt; 
	RXpkt *rxpkt; 
1997/1210    
	Etherpkt *pkt; 
	ushort type; 
	int len; 
	Netfile **ep, *f, **fp, *fx; 
	Block *xbp; 
1993/0903    
 
1993/0906    
	c = ether[0]; 
1997/1210    
	ether->inpackets++; 
1993/0903    
 
1993/0904    
	for(;;) { 
		status = RD(isr) & AllIntr; 
		if(status == 0) 
			break; 
1997/1210    
	pkt = (Etherpkt*)bp->rp; 
	len = BLEN(bp); 
	type = (pkt->type[0]<<8)|pkt->type[1]; 
	fx = 0; 
	ep = ðer->f[Ntypes]; 
1993/0904    
 
1994/0107    
		/* 
		 * Warnings that something is atoe. 
		 */ 
		if(status & Hbl){ 
			WR(isr, Hbl); 
			status &= ~Hbl; 
			print("sonic: cd heartbeat lost\n"); 
		} 
		if(status & Br){ 
WR(cr, Rst); 
			print("sonic: bus retry occurred\n"); 
(*(void(*)(void))0xA001C020)(); 
			status &= ~Br; 
		} 
1993/0904    
	                 
		/* 
		 * Transmission complete, for good or bad. 
		 */ 
1993/1219    
		if(status & (Txdn|Txer)) { 
1993/0906    
			txpkt = &c->tda[c->ti]; 
1993/0904    
			while(txpkt->status != Host){ 
				if(txpkt->status == Interface){ 
					WR(ctda, LS16(txpkt)); 
					WR(cr, Txp); 
					break; 
				} 
	                 
				if((txpkt->status & Ptx) == 0) 
1993/0906    
					c->oerrs++; 
1993/0904    
	                 
				txpkt->status = Host; 
1993/0906    
				c->ti = NEXT(c->ti, Ntb); 
				txpkt = &c->tda[c->ti]; 
1997/1210    
	/* check for valid multcast addresses */ 
	if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){ 
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ 
			if(freebp){ 
				freeb(bp); 
				bp = 0; 
1993/0904    
			} 
1994/0107    
			WR(isr, status & (Txdn|Txer)); 
1993/0904    
			status &= ~(Txdn|Txer); 
1993/1212    
			if(isoutbuf(c)) 
				wakeup(&c->tr); 
1997/1210    
			return bp; 
1993/0903    
		} 
1997/1210    
	} 
1993/0904    
 
		if((status & (Pktrx|Rde)) == 0) 
			goto noinput; 
                 
		/* 
		 * A packet arrived or we ran out of descriptors. 
		 */ 
1993/0906    
		rxpkt = &c->rda[c->rh]; 
1993/0904    
		while(rxpkt->owner == Host){ 
1993/0906    
			c->inpackets++; 
1993/0904    
	                 
			/* 
			 * If the packet was received OK, pass it up, 
			 * otherwise log the error. 
			 */ 
1993/0906    
			if(rxpkt->status & Prx) 
				sonicpkt(c, rxpkt, (Pbuf*)c->rb[c->rh]); 
1997/1210    
	/* 
	 * Multiplex the packet to all the connections which want it. 
	 * If the packet is not to be used subsequently (freebp != 0), 
	 * attempt to simply pass it into one of the connections, thereby 
	 * saving a copy of the data (usual case hopefully). 
	 */ 
	for(fp = ether->f; fp < ep; fp++){ 
		if((f = *fp) && (f->type == type || f->type < 0)){ 
			if(f->type > -2){ 
				if(freebp && fx == 0) 
					fx = f; 
				else if(xbp = iallocb(len)){ 
					memmove(xbp->wp, pkt, len); 
					xbp->wp += len; 
					qpass(f->in, xbp); 
				} 
				else 
					ether->soverflows++; 
			} 
1993/0904    
			else 
			if(rxpkt->status & Fae) 
1993/0906    
				c->frames++; 
1993/0904    
			else 
			if(rxpkt->status & Crc) 
1993/0906    
				c->crcs++; 
1993/0904    
			else 
1993/0906    
				c->buffs++; 
1993/0904    
	                 
1994/0107    
			rxpkt->status  = 0; 
1993/0904    
			/* 
			 * 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. 
			 */ 
1994/0107    
			wus(&rxpkt->link,  rxpkt->link|Eol); 
1993/0904    
			rxpkt->owner = Interface; 
1994/0107    
			s = &c->rda[PREV(c->rh, Nrb)].link; 
			wus(s, *s & ~Eol); 
1993/0906    
			c->rh = NEXT(c->rh, Nrb); 
1993/0904    
	                 
1993/0906    
			rxpkt = &c->rda[c->rh]; 
1997/1210    
				etherrtrace(f, pkt, len); 
1993/0903    
		} 
1994/0107    
		WR(isr, status & (Pktrx|Rde)); 
1993/0904    
		status &= ~(Pktrx|Rde); 
1997/1210    
	} 
1993/0903    
 
1993/0904    
	noinput: 
1993/0903    
		/* 
1993/0904    
		 * We get a 'load CAM done' interrupt 
		 * after initialisation. Ignore it. 
1993/0903    
		 */ 
1994/0107    
		if(status & Lcd) { 
			WR(isr, Lcd); 
1993/0904    
			status &= ~Lcd; 
1993/0903    
		} 
1993/0904    
	                 
1994/0107    
		if(status & AllIntr) { 
			WR(isr, status); 
1993/0906    
			print("sonic #%lux\n", status); 
1994/0107    
		} 
1997/1210    
	if(fx){ 
		qpass(fx->in, bp); 
		return 0; 
1993/0903    
	} 
} 
1997/1210    
	if(freebp){ 
		freeb(bp); 
		return 0; 
	} 
1993/0903    
 
/* 
 *  turn promiscuous mode on/off 
 */ 
static void 
promiscuous(void *arg, int on) 
{ 
1993/0904    
	ushort reg; 
1993/0903    
                 
	USED(arg); 
1993/0904    
                 
	reg = RD(rcr); 
1993/0903    
	if(on) 
1993/0904    
		WR(rcr, reg|Pro); 
1993/0903    
	else 
1993/0904    
		WR(rcr, reg&~Pro); 
1997/1210    
	return bp; 
1993/0903    
} 
 
1993/0906    
static void 
initbufs(Ether *c) 
1997/1210    
static int 
etheroq(Ether* ether, Block* bp) 
1993/0906    
{ 
	int i; 
1993/1217    
	uchar *mem, *base; 
1997/1210    
	int len, loopback, s; 
	Etherpkt *pkt; 
1993/0906    
 
1994/0524    
	/* Put the ethernet buffers in the same place 
	 * as the bootrom 
	 */ 
	mem = (void*)(KZERO|0x2000); 
1993/1217    
	base = mem; 
1993/0906    
	mem = CACHELINE(uchar, mem); 
1997/1210    
	ether->outpackets++; 
1993/0906    
 
	/* 
	 * Descriptors must be built in uncached space 
1997/1210    
	 * Check if the packet has to be placed back onto the input queue, 
	 * i.e. if it's a loopback or broadcast packet or the interface is 
	 * in promiscuous mode. 
	 * If it's a loopback packet indicate to etheriq that the data isn't 
	 * needed and return, etheriq will pass-on or free the block. 
1993/0906    
	 */ 
	c->rra = UNCACHED(RXrsc, mem); 
	mem = QUAD(uchar, mem+Nrb*sizeof(RXrsc)); 
                 
	c->rda = UNCACHED(RXpkt, mem); 
	mem = QUAD(uchar, mem+Nrb*sizeof(RXpkt)); 
                 
	c->tda = UNCACHED(TXpkt, mem); 
	mem = QUAD(uchar, mem+Ntb*sizeof(TXpkt)); 
                 
	c->cda = UNCACHED(Cam, mem); 
                 
	mem = CACHELINE(uchar, mem+sizeof(Cam)); 
	for(i = 0; i < Nrb; i++) { 
		c->rb[i] = UNCACHED(uchar, mem); 
		mem += sizeof(Pbuf)+4; 
		mem = QUAD(uchar, mem); 
1997/1210    
	pkt = (Etherpkt*)bp->rp; 
	len = BLEN(bp); 
	loopback = (memcmp(pkt->d, ether->addr, sizeof(pkt->d)) == 0); 
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){ 
		s = splhi(); 
		etheriq(ether, bp, loopback); 
		splx(s); 
1993/0906    
	} 
	for(i = 0; i < Ntb; i++) { 
		c->tb[i] = UNCACHED(uchar, mem); 
		mem += sizeof(Pbuf); 
		mem = QUAD(uchar, mem); 
	} 
1993/1217    
	if(mem >= base+64*1024) 
		panic("sonic init"); 
1993/0906    
} 
 
1997/0327    
static void 
1993/0903    
etherreset(void) 
{ 
1993/0904    
	Ether *ctlr; 
1993/0903    
                 
1993/0904    
	/* 
	 * Map the device registers and allocate 
	 * memory for the receive/transmit rings. 
	 * Set the physical ethernet address and 
	 * prime the interrupt handler. 
	 */ 
1993/0906    
	if(ether[0] == 0) { 
		ctlr = malloc(sizeof(Ether)); 
		ether[0] = ctlr; 
		initbufs(ctlr); 
1993/0905    
		enetaddr(ether[0]->ea); 
1997/1210    
	if(!loopback){ 
		if(ether->dev && ether->dev->transmit){ 
			qbwrite(ether->oq, bp); 
			ether->dev->transmit(ether); 
		} 
		else{ 
			freeb(bp); 
			return 0; 
		} 
1993/0903    
	} 
1993/0904    
	ctlr = ether[0]; 
1993/0903    
 
1993/0904    
	reset(ctlr); 
1993/0903    
                 
1993/0904    
	memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); 
1993/0903    
                 
	/* general network interface structure */ 
1997/0327    
	netifinit(ether[0], "ether0", Ntypes, 32*1024); 
1993/0904    
	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]; 
1997/1210    
	return len; 
1993/0903    
} 
 
1997/0327    
static Chan* 
1993/0903    
etherattach(char *spec) 
1997/1210    
static long 
etherwrite(Chan* chan, void* buf, long n, ulong) 
1993/0903    
{ 
1993/0905    
	static int enable; 
1997/1210    
	Ether *ether; 
	Block *bp; 
1993/0905    
 
	if(enable == 0) { 
		enable = 1; 
		WR(cr, Rxen); 
	} 
1995/0520    
	if(*spec && strcmp(spec, "0") != 0) 
		error(Eio); 
1993/0903    
	return devattach('l', spec); 
} 
1997/1210    
	ether = etherxx[chan->dev]; 
	if(NETTYPE(chan->qid.path) != Ndataqid) 
		return netifwrite(ether, chan, buf, n); 
1993/0903    
 
1997/0327    
static int 
1993/0903    
etherwalk(Chan *c, char *name) 
{ 
1993/0904    
	return netifwalk(ether[0], c, name); 
1993/0903    
} 
1997/1210    
	if(n > ETHERMAXTU) 
		error(Etoobig); 
	if(n < ETHERMINTU) 
		error(Etoosmall); 
1993/0903    
 
1997/0327    
static Chan* 
1993/0903    
etheropen(Chan *c, int omode) 
{ 
1993/0904    
	return netifopen(ether[0], c, omode); 
1993/0903    
} 
1997/1210    
	bp = allocb(n); 
	if(waserror()){ 
		freeb(bp); 
		nexterror(); 
	} 
	memmove(bp->rp, buf, n); 
	memmove(bp->rp+Eaddrlen, ether->addr, Eaddrlen); 
	poperror(); 
	bp->wp += n; 
1993/0903    
 
1997/0327    
static void 
1993/0903    
ethercreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	USED(c, name, omode, perm); 
1997/1210    
	return etheroq(ether, bp); 
1993/0903    
} 
 
1997/0327    
static void 
1993/0903    
etherclose(Chan *c) 
{ 
1993/0904    
	netifclose(ether[0], c); 
1993/0903    
} 
                 
long 
etherread(Chan *c, void *buf, long n, ulong offset) 
{ 
1993/0904    
	return netifread(ether[0], c, buf, n, offset); 
1993/0903    
} 
                 
static int 
1993/1202    
etherloop(Etherpkt *p, long n) 
{ 
	int s, different; 
	ushort t; 
	Netfile *f, **fp; 
1995/0114    
	Ether *ctlr = ether[0]; 
1993/1202    
                 
1995/0114    
	different = memcmp(p->d, ctlr->ea, sizeof(ctlr->ea)); 
	if(different && memcmp(p->d, ctlr->bcast, sizeof(p->d))) 
1993/1202    
		return 0; 
                 
	s = splhi(); 
	t = (p->type[0]<<8) | p->type[1]; 
1995/0114    
	for(fp = ctlr->f; fp < &ctlr->f[Ntypes]; fp++) { 
1993/1202    
		f = *fp; 
		if(f == 0) 
			continue; 
		if(f->type == t || f->type < 0) 
			switch(qproduce(f->in, p->d, n)){ 
			case -1: 
				print("etherloop overflow\n"); 
				break; 
			case -2: 
				print("etherloop memory\n"); 
				break; 
			} 
	} 
	splx(s); 
	return !different; 
} 
                 
1997/0327    
static long 
1993/0903    
etherwrite(Chan *c, void *buf, long n, ulong offset) 
1997/1210    
etherbwrite(Chan* chan, Block* bp, ulong) 
1993/0903    
{ 
1993/0906    
	Pbuf *p; 
1994/0107    
	ushort *s; 
1993/0904    
	TXpkt *txpkt; 
	Ether *ctlr = ether[0]; 
1997/1210    
	Ether *ether; 
	long n; 
1993/0903    
 
	USED(offset); 
                 
	/* etherif.c handles structure */ 
	if(NETTYPE(c->qid.path) != Ndataqid) 
1993/0904    
		return netifwrite(ether[0], c, buf, n); 
1993/0903    
                 
1993/1212    
	if(n > ETHERMAXTU) 
		error(Ebadarg); 
                 
1995/0114    
	p = buf; 
	memmove(p->s, ctlr->ea, sizeof(ctlr->ea)); 
                 
1993/0903    
	/* we handle data */ 
1993/1202    
	if(etherloop(buf, n)) 
1997/1210    
	n = BLEN(bp); 
	ether = etherxx[chan->dev]; 
	if(NETTYPE(chan->qid.path) != Ndataqid){ 
		n = netifwrite(ether, chan, bp->rp, n); 
		freeb(bp); 
1993/1202    
		return n; 
                 
1993/0904    
	qlock(&ctlr->tlock); 
1994/0107    
	ctlr->outpackets++; 
1993/0918    
	if(waserror()) { 
		qunlock(&ctlr->tlock); 
		nexterror(); 
	} 
 
1993/1212    
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); 
1993/0905    
                 
1993/1212    
	if(!isoutbuf(ctlr)) 
		print("ether transmitter jammed cr #%lux\n", RD(cr)); 
1993/0904    
	else { 
1993/1212    
		p = (Pbuf*)ctlr->tb[ctlr->th]; 
1993/0903    
		memmove(p->d, buf, n); 
		if(n < 60) { 
			memset(p->d+n, 0, 60-n); 
			n = 60; 
		} 
1993/0906    
		sonicswap(p, n); 
1993/0904    
                 
		txpkt = &ctlr->tda[ctlr->th]; 
		txpkt->size = n; 
		txpkt->fsize = n; 
1994/0107    
		wus(&txpkt->link, txpkt->link|Eol); 
1993/0904    
		txpkt->status = Interface; 
1994/0107    
		s = &ctlr->tda[PREV(ctlr->th, Ntb)].link; 
		wus(s, *s & ~Eol); 
1993/0904    
                 
		ctlr->th = NEXT(ctlr->th, Ntb); 
		WR(cr, Txp); 
1997/1210    
	if(n > ETHERMAXTU){ 
		freeb(bp); 
		error(Ebadarg); 
1993/0903    
	} 
1993/0918    
	poperror(); 
1993/0904    
	qunlock(&ctlr->tlock); 
1997/1210    
	if(n < ETHERMINTU){ 
		freeb(bp); 
		error(Etoosmall); 
	} 
1993/0905    
 
1993/0903    
	return n; 
1997/1210    
	return etheroq(ether, bp); 
1995/0108    
} 
 
1997/0327    
static void 
1993/0903    
etherremove(Chan *c) 
1997/1210    
void 
etherreset(void) 
1993/0903    
{ 
	USED(c); 
} 
1997/1210    
	Ether *ether; 
	int i, n, ctlrno; 
	char name[NAMELEN], buf[128]; 
1993/0903    
 
1997/0327    
static void 
1993/0903    
etherstat(Chan *c, char *dp) 
{ 
1993/0904    
	netifstat(ether[0], c, dp); 
1993/0903    
} 
1997/1210    
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ 
		if(ether == 0) 
			ether = malloc(sizeof(Ether)); 
		memset(ether, 0, sizeof(Ether)); 
		ether->ctlrno = ctlrno; 
		ether->tbdf = BUSUNKNOWN; 
		ether->mbps = 10; 
		if(isaconfig("ether", ctlrno, ether) == 0) 
			continue; 
		for(n = 0; endev[n]; n++){ 
			if(cistrcmp(endev[n]->name, ether->type)) 
				continue; 
			ether->dev = endev[n]; 
			for(i = 0; i < ether->nopt; i++){ 
				if(strncmp(ether->opt[i], "ea=", 3)) 
					continue; 
				if(parseether(ether->addr, ðer->opt[i][3]) == -1) 
					memset(ether->addr, 0, Eaddrlen); 
			}	 
			if(endev[n]->reset(ether)) 
				break; 
1993/0903    
 
1997/0327    
static void 
1993/0903    
etherwstat(Chan *c, char *dp) 
{ 
1993/0904    
	netifwstat(ether[0], c, dp); 
1993/0906    
} 
1997/1210    
			/* 
			 * IRQ2 doesn't really exist, it's used to gang the interrupt 
			 * controllers together. A device set to IRQ2 will appear on 
			 * the second interrupt controller as IRQ9. 
			 */ 
			if(ether->irq == 2) 
				ether->irq = 9; 
			intrenable(VectorPIC+ether->irq, ether->interrupt, ether, ether->tbdf); 
1993/0906    
 
#define swiz(s)	(s<<24)|((s>>8)&0xff00)|((s<<8)&0xff0000)|(s>>24) 
1997/1210    
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX", 
				ctlrno, ether->type, ether->mbps, ether->port); 
			if(ether->irq) 
				i += sprint(buf+i, " irq %d", ether->irq); 
			if(ether->mem) 
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); 
			if(ether->size) 
				i += sprint(buf+i, " size 0x%luX", ether->size); 
			i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", 
				ether->addr[0], ether->addr[1], ether->addr[2], 
				ether->addr[3], ether->addr[4], ether->addr[5]); 
			sprint(buf+i, "\n"); 
			print(buf); 
1993/0906    
 
1997/0327    
static void 
1993/0906    
sonicswap(void *a, int n) 
{ 
	ulong *p, t0, t1; 
1997/1210    
			snprint(name, sizeof(name), "ether%d", ctlrno); 
			if(ether->mbps == 100){ 
				netifinit(ether, name, Ntypes, 256*1024); 
				if(ether->oq == 0) 
					ether->oq = qopen(256*1024, 1, 0, 0); 
			} 
			else{ 
				netifinit(ether, name, Ntypes, 32*1024); 
				if(ether->oq == 0) 
					ether->oq = qopen(64*1024, 1, 0, 0); 
			} 
			if(ether->oq == 0) 
				panic("etherreset %s", name); 
1993/0906    
 
	n = ((n+8)/8)*8; 
	p = a; 
	while(n) { 
		t0 = p[0]; 
		t1 = p[1]; 
		p[0] = swiz(t1); 
		p[1] = swiz(t0); 
		p += 2; 
		n -= 8; 
1997/1210    
			ether->alen = Eaddrlen; 
			memset(ether->bcast, 0xFF, Eaddrlen); 
			ether->arg = ether; 
			ether->promiscuous = ether->dev->promiscuous; 
			ether->multicast = ether->dev->multicast; 
 
			etherxx[ctlrno] = ether; 
			ether = 0; 
			break; 
		} 
1993/0906    
	} 
1997/1210    
	if(ether) 
		free(ether); 
1993/0903    
} 
1997/0327    
 
int 
parseether(uchar *to, char *from) 
1997/1210    
parseether(uchar* to, char* from) 
1997/0327    
{ 
	char nip[4]; 
	char *p; 
1997/0408/sys/src/9/carrera/devether.c:835,8401997/1210/sys/src/9/carrera/devether.c:388,413
1997/0327    
	return 0; 
} 
 
1997/1210    
#define POLY 0xedb88320 
 
/* really slow 32 bit crc for ethers */ 
ulong 
ethercrc(uchar* p, int len) 
{ 
	int i, j; 
	ulong crc, b; 
 
	crc = 0xffffffff; 
	for(i = 0; i < len; i++){ 
		b = *p++; 
		for(j = 0; j < 8; j++){ 
			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0); 
			b >>= 1; 
		} 
	} 
	return crc; 
} 
 
1997/0327    
Dev etherdevtab = { 
1997/0408    
	'l', 
	"ether", 
1997/0408/sys/src/9/carrera/devether.c:849,8571997/1210/sys/src/9/carrera/devether.c:422,430
1997/0327    
	ethercreate, 
	etherclose, 
	etherread, 
	devbread, 
1997/1210    
	etherbread, 
1997/0327    
	etherwrite, 
	devbwrite, 
1997/1210    
	etherbwrite, 
1997/0327    
	etherremove, 
	etherwstat, 
}; 
1997/1210/sys/src/9/carrera/devether.c:65,731998/0319/sys/src/9/carrera/devether.c:65,74 (short | long)
Change dev read and write to use vlong offset.
rsc Fri Mar 4 12:44:25 2005
1997/1210    
} 
1993/0904    
 
1997/1210    
static long 
etherread(Chan* chan, void* buf, long n, ulong offset) 
1998/0319    
etherread(Chan* chan, void* buf, long n, vlong off) 
1993/0903    
{ 
1997/1210    
	Ether *ether; 
1998/0319    
	ulong offset = off; 
1993/0903    
 
1997/1210    
	ether = etherxx[chan->dev]; 
	if((chan->qid.path & CHDIR) == 0 && ether->dev && ether->dev->ifstat){ 
1997/1210/sys/src/9/carrera/devether.c:231,2371998/0319/sys/src/9/carrera/devether.c:232,238
1993/0903    
} 
 
1997/1210    
static long 
etherwrite(Chan* chan, void* buf, long n, ulong) 
1998/0319    
etherwrite(Chan* chan, void* buf, long n, vlong) 
1993/0903    
{ 
1997/1210    
	Ether *ether; 
	Block *bp; 
1998/0319/sys/src/9/carrera/devether.c:326,3321999/0629/sys/src/9/carrera/devether.c:326,332 (short | long)
1997/1210    
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX", 
				ctlrno, ether->type, ether->mbps, ether->port); 
			if(ether->irq) 
				i += sprint(buf+i, " irq %d", ether->irq); 
1999/0629    
				i += sprint(buf+i, " irq %ld", ether->irq); 
1997/1210    
			if(ether->mem) 
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); 
			if(ether->size) 
1999/0629/sys/src/9/carrera/devether.c:110,1212000/0713/sys/src/9/carrera/devether.c:110,121 (short | long)
1993/1212    
 
1997/1210    
	if(qwindow(f->in) <= 0) 
		return; 
	if(len > 64) 
		n = 64; 
2000/0713    
	if(len > 58) 
		n = 58; 
1997/1210    
	else 
		n = len; 
	bp = iallocb(n); 
	if(bp == 0) 
2000/0713    
	bp = iallocb(64); 
	if(bp == nil) 
1997/1210    
		return; 
	memmove(bp->wp, pkt->d, n); 
	i = TK2MS(MACHP(0)->ticks); 
2000/0713/sys/src/9/carrera/devether.c:1,4312001/0527/sys/src/9/carrera/devether.c:0 (short | long)
Deleted.
rsc Mon Mar 7 10:21:06 2005
1997/1210    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
#include "ureg.h" 
#include "../port/error.h" 
#include "../port/netif.h" 
1993/0903    
                 
1997/1210    
#include "etherif.h" 
1993/0903    
                 
1997/1210    
static Ether *etherxx[MaxEther]; 
1993/0903    
                 
1997/1210    
Chan* 
etherattach(char* spec) 
1993/0906    
{ 
1997/1210    
	ulong ctlrno; 
	char *p; 
	Chan *chan; 
1993/0906    
                 
1997/1210    
	ctlrno = 0; 
	if(spec && *spec){ 
		ctlrno = strtoul(spec, &p, 0); 
		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) 
			error(Ebadarg); 
	} 
	if(etherxx[ctlrno] == 0) 
		error(Enodev); 
1993/0903    
                 
1997/1210    
	chan = devattach('l', spec); 
	chan->dev = ctlrno; 
	if(etherxx[ctlrno]->dev && etherxx[ctlrno]->dev->attach) 
		etherxx[ctlrno]->dev->attach(etherxx[ctlrno]); 
	return chan; 
} 
1993/0903    
                 
1997/1210    
static int 
etherwalk(Chan* chan, char* name) 
1993/0904    
{ 
1997/1210    
	return netifwalk(etherxx[chan->dev], chan, name); 
} 
1993/0903    
                 
1997/1210    
static void 
etherstat(Chan* chan, char* dp) 
1993/0904    
{ 
1997/1210    
	netifstat(etherxx[chan->dev], chan, dp); 
} 
1993/0903    
                 
1997/1210    
static Chan* 
etheropen(Chan* chan, int omode) 
1993/0903    
{ 
1997/1210    
	return netifopen(etherxx[chan->dev], chan, omode); 
} 
1993/0903    
                 
1997/1210    
static void 
ethercreate(Chan*, char*, int, ulong) 
1993/0904    
{ 
1997/1210    
} 
1993/0904    
                 
1997/1210    
static void 
etherclose(Chan* chan) 
1993/0905    
{ 
1997/1210    
	netifclose(etherxx[chan->dev], chan); 
} 
1993/0904    
                 
1997/1210    
static long 
1998/0319    
etherread(Chan* chan, void* buf, long n, vlong off) 
1993/0903    
{ 
1997/1210    
	Ether *ether; 
1998/0319    
	ulong offset = off; 
1993/0903    
                 
1997/1210    
	ether = etherxx[chan->dev]; 
	if((chan->qid.path & CHDIR) == 0 && ether->dev && ether->dev->ifstat){ 
		/* 
		 * With some controllers it is necessary to reach 
		 * into the chip to extract statistics. 
		 */ 
		if(NETTYPE(chan->qid.path) == Nifstatqid) 
			return ether->dev->ifstat(ether, buf, n, offset); 
		else if(NETTYPE(chan->qid.path) == Nstatqid) 
			ether->dev->ifstat(ether, buf, 0, offset); 
	} 
1993/0903    
                 
1997/1210    
	return netifread(ether, chan, buf, n, offset); 
} 
1993/0904    
                 
1997/1210    
static Block* 
etherbread(Chan* chan, long n, ulong offset) 
1993/0906    
{ 
1997/1210    
	return netifbread(etherxx[chan->dev], chan, n, offset); 
1993/0906    
} 
                 
static void 
1997/1210    
etherremove(Chan*) 
1993/0903    
{ 
} 
                 
1997/0327    
static void 
1997/1210    
etherwstat(Chan* chan, char* dp) 
1993/0905    
{ 
1997/1210    
	netifwstat(etherxx[chan->dev], chan, dp); 
1993/0905    
} 
                 
1997/1210    
static void 
etherrtrace(Netfile* f, Etherpkt* pkt, int len) 
1993/1212    
{ 
1997/1210    
	int i, n; 
	Block *bp; 
1993/1212    
                 
1997/1210    
	if(qwindow(f->in) <= 0) 
		return; 
2000/0713    
	if(len > 58) 
		n = 58; 
1997/1210    
	else 
		n = len; 
2000/0713    
	bp = iallocb(64); 
	if(bp == nil) 
1997/1210    
		return; 
	memmove(bp->wp, pkt->d, n); 
	i = TK2MS(MACHP(0)->ticks); 
	bp->wp[58] = len>>8; 
	bp->wp[59] = len; 
	bp->wp[60] = i>>24; 
	bp->wp[61] = i>>16; 
	bp->wp[62] = i>>8; 
	bp->wp[63] = i; 
	bp->wp += 64; 
	qpass(f->in, bp); 
1993/1212    
} 
                 
1997/1210    
Block* 
etheriq(Ether* ether, Block* bp, int freebp) 
1993/0903    
{ 
1997/1210    
	Etherpkt *pkt; 
	ushort type; 
	int len; 
	Netfile **ep, *f, **fp, *fx; 
	Block *xbp; 
1993/0903    
                 
1997/1210    
	ether->inpackets++; 
1993/0903    
                 
1997/1210    
	pkt = (Etherpkt*)bp->rp; 
	len = BLEN(bp); 
	type = (pkt->type[0]<<8)|pkt->type[1]; 
	fx = 0; 
	ep = ðer->f[Ntypes]; 
1993/0904    
                 
1997/1210    
	/* check for valid multcast addresses */ 
	if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){ 
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ 
			if(freebp){ 
				freeb(bp); 
				bp = 0; 
1993/0904    
			} 
1997/1210    
			return bp; 
1993/0903    
		} 
1997/1210    
	} 
1993/0904    
                 
1997/1210    
	/* 
	 * Multiplex the packet to all the connections which want it. 
	 * If the packet is not to be used subsequently (freebp != 0), 
	 * attempt to simply pass it into one of the connections, thereby 
	 * saving a copy of the data (usual case hopefully). 
	 */ 
	for(fp = ether->f; fp < ep; fp++){ 
		if((f = *fp) && (f->type == type || f->type < 0)){ 
			if(f->type > -2){ 
				if(freebp && fx == 0) 
					fx = f; 
				else if(xbp = iallocb(len)){ 
					memmove(xbp->wp, pkt, len); 
					xbp->wp += len; 
					qpass(f->in, xbp); 
				} 
				else 
					ether->soverflows++; 
			} 
1993/0904    
			else 
1997/1210    
				etherrtrace(f, pkt, len); 
1993/0903    
		} 
1997/1210    
	} 
1993/0903    
                 
1997/1210    
	if(fx){ 
		qpass(fx->in, bp); 
		return 0; 
1993/0903    
	} 
1997/1210    
	if(freebp){ 
		freeb(bp); 
		return 0; 
	} 
1993/0903    
                 
1997/1210    
	return bp; 
1993/0903    
} 
                 
1997/1210    
static int 
etheroq(Ether* ether, Block* bp) 
1993/0906    
{ 
1997/1210    
	int len, loopback, s; 
	Etherpkt *pkt; 
1993/0906    
                 
1997/1210    
	ether->outpackets++; 
1993/0906    
                 
	/* 
1997/1210    
	 * Check if the packet has to be placed back onto the input queue, 
	 * i.e. if it's a loopback or broadcast packet or the interface is 
	 * in promiscuous mode. 
	 * If it's a loopback packet indicate to etheriq that the data isn't 
	 * needed and return, etheriq will pass-on or free the block. 
1993/0906    
	 */ 
1997/1210    
	pkt = (Etherpkt*)bp->rp; 
	len = BLEN(bp); 
	loopback = (memcmp(pkt->d, ether->addr, sizeof(pkt->d)) == 0); 
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){ 
		s = splhi(); 
		etheriq(ether, bp, loopback); 
		splx(s); 
1993/0906    
	} 
                 
1997/1210    
	if(!loopback){ 
		if(ether->dev && ether->dev->transmit){ 
			qbwrite(ether->oq, bp); 
			ether->dev->transmit(ether); 
		} 
		else{ 
			freeb(bp); 
			return 0; 
		} 
1993/0903    
	} 
                 
1997/1210    
	return len; 
1993/0903    
} 
                 
1997/1210    
static long 
1998/0319    
etherwrite(Chan* chan, void* buf, long n, vlong) 
1993/0903    
{ 
1997/1210    
	Ether *ether; 
	Block *bp; 
1993/0905    
                 
1997/1210    
	ether = etherxx[chan->dev]; 
	if(NETTYPE(chan->qid.path) != Ndataqid) 
		return netifwrite(ether, chan, buf, n); 
1993/0903    
                 
1997/1210    
	if(n > ETHERMAXTU) 
		error(Etoobig); 
	if(n < ETHERMINTU) 
		error(Etoosmall); 
1993/0903    
                 
1997/1210    
	bp = allocb(n); 
	if(waserror()){ 
		freeb(bp); 
		nexterror(); 
	} 
	memmove(bp->rp, buf, n); 
	memmove(bp->rp+Eaddrlen, ether->addr, Eaddrlen); 
	poperror(); 
	bp->wp += n; 
1993/0903    
                 
1997/1210    
	return etheroq(ether, bp); 
1993/0903    
} 
                 
1997/0327    
static long 
1997/1210    
etherbwrite(Chan* chan, Block* bp, ulong) 
1993/0903    
{ 
1997/1210    
	Ether *ether; 
	long n; 
1993/0903    
                 
1997/1210    
	n = BLEN(bp); 
	ether = etherxx[chan->dev]; 
	if(NETTYPE(chan->qid.path) != Ndataqid){ 
		n = netifwrite(ether, chan, bp->rp, n); 
		freeb(bp); 
1993/1202    
		return n; 
1993/0918    
	} 
                 
1997/1210    
	if(n > ETHERMAXTU){ 
		freeb(bp); 
		error(Ebadarg); 
1993/0903    
	} 
1997/1210    
	if(n < ETHERMINTU){ 
		freeb(bp); 
		error(Etoosmall); 
	} 
1993/0905    
                 
1997/1210    
	return etheroq(ether, bp); 
1995/0108    
} 
                 
1997/1210    
void 
etherreset(void) 
1993/0903    
{ 
1997/1210    
	Ether *ether; 
	int i, n, ctlrno; 
	char name[NAMELEN], buf[128]; 
1993/0903    
                 
1997/1210    
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ 
		if(ether == 0) 
			ether = malloc(sizeof(Ether)); 
		memset(ether, 0, sizeof(Ether)); 
		ether->ctlrno = ctlrno; 
		ether->tbdf = BUSUNKNOWN; 
		ether->mbps = 10; 
		if(isaconfig("ether", ctlrno, ether) == 0) 
			continue; 
		for(n = 0; endev[n]; n++){ 
			if(cistrcmp(endev[n]->name, ether->type)) 
				continue; 
			ether->dev = endev[n]; 
			for(i = 0; i < ether->nopt; i++){ 
				if(strncmp(ether->opt[i], "ea=", 3)) 
					continue; 
				if(parseether(ether->addr, ðer->opt[i][3]) == -1) 
					memset(ether->addr, 0, Eaddrlen); 
			}	 
			if(endev[n]->reset(ether)) 
				break; 
1993/0903    
                 
1997/1210    
			/* 
			 * IRQ2 doesn't really exist, it's used to gang the interrupt 
			 * controllers together. A device set to IRQ2 will appear on 
			 * the second interrupt controller as IRQ9. 
			 */ 
			if(ether->irq == 2) 
				ether->irq = 9; 
			intrenable(VectorPIC+ether->irq, ether->interrupt, ether, ether->tbdf); 
1993/0906    
                 
1997/1210    
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX", 
				ctlrno, ether->type, ether->mbps, ether->port); 
			if(ether->irq) 
1999/0629    
				i += sprint(buf+i, " irq %ld", ether->irq); 
1997/1210    
			if(ether->mem) 
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); 
			if(ether->size) 
				i += sprint(buf+i, " size 0x%luX", ether->size); 
			i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", 
				ether->addr[0], ether->addr[1], ether->addr[2], 
				ether->addr[3], ether->addr[4], ether->addr[5]); 
			sprint(buf+i, "\n"); 
			print(buf); 
1993/0906    
                 
1997/1210    
			snprint(name, sizeof(name), "ether%d", ctlrno); 
			if(ether->mbps == 100){ 
				netifinit(ether, name, Ntypes, 256*1024); 
				if(ether->oq == 0) 
					ether->oq = qopen(256*1024, 1, 0, 0); 
			} 
			else{ 
				netifinit(ether, name, Ntypes, 32*1024); 
				if(ether->oq == 0) 
					ether->oq = qopen(64*1024, 1, 0, 0); 
			} 
			if(ether->oq == 0) 
				panic("etherreset %s", name); 
1993/0906    
                 
1997/1210    
			ether->alen = Eaddrlen; 
			memset(ether->bcast, 0xFF, Eaddrlen); 
			ether->arg = ether; 
			ether->promiscuous = ether->dev->promiscuous; 
			ether->multicast = ether->dev->multicast; 
                 
			etherxx[ctlrno] = ether; 
			ether = 0; 
			break; 
		} 
1993/0906    
	} 
1997/1210    
	if(ether) 
		free(ether); 
1993/0903    
} 
1997/0327    
                 
int 
1997/1210    
parseether(uchar* to, char* from) 
1997/0327    
{ 
	char nip[4]; 
	char *p; 
	int i; 
                 
	p = from; 
	for(i = 0; i < 6; i++){ 
		if(*p == 0) 
			return -1; 
		nip[0] = *p++; 
		if(*p == 0) 
			return -1; 
		nip[1] = *p++; 
		nip[2] = 0; 
		to[i] = strtoul(nip, 0, 16); 
		if(*p == ':') 
			p++; 
	} 
	return 0; 
} 
                 
1997/1210    
#define POLY 0xedb88320 
                 
/* really slow 32 bit crc for ethers */ 
ulong 
ethercrc(uchar* p, int len) 
{ 
	int i, j; 
	ulong crc, b; 
                 
	crc = 0xffffffff; 
	for(i = 0; i < len; i++){ 
		b = *p++; 
		for(j = 0; j < 8; j++){ 
			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0); 
			b >>= 1; 
		} 
	} 
	return crc; 
} 
                 
1997/0327    
Dev etherdevtab = { 
1997/0408    
	'l', 
	"ether", 
                 
1997/0327    
	etherreset, 
	devinit, 
	etherattach, 
	devclone, 
	etherwalk, 
	etherstat, 
	etheropen, 
	ethercreate, 
	etherclose, 
	etherread, 
1997/1210    
	etherbread, 
1997/0327    
	etherwrite, 
1997/1210    
	etherbwrite, 
1997/0327    
	etherremove, 
	etherwstat, 
}; 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)