Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/carrera/devether.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname carrera/devether.c 1993/0903
## diff -e /dev/null /n/fornaxdump/1993/0903/sys/src/brazil/carrera/devether.c
0a
#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"

/*
 *  ethernet address stored in prom
 */
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 */

	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)

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

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 */

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

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

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

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

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

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

#define RSUCC(i)	(((i)+1)&Rmask)
#define RPREV(i)	(((i)-1)&Rmask)
#define TSUCC(i)	(((i)+1)&Tmask)
#define TPREV(i)	(((i)-1)&Tmask)

/*
 *  a hardware packet buffer
 */
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;

struct Ether
{
	uchar	ea[6];

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

	Pbuf	*tbuf;		/* transmit buffers */
	Pbuf	*rbuf;		/* receive buffers */

	QLock	tlock;		/* lock for grabbing transmitter queue */
	Rendez	tr;		/* wait here for free xmit buffer */

	Netif;
} ether;


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

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

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

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

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

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

	if(ether.prom)
		edlc->rcmd = Renab | Rall;
	else
		edlc->rcmd = Renab | Rnormal;

	ether.rindex = edlc->rindex;
	ether.rtop = edlc->rtop = RPREV(ether.rindex);

	/* step 6: attach to ether */
	lxt->loopback = 0;
}

void
etherintr(void)
{
	EDLCdev *edlc = EPCEDLC;
	EPCmisc *misc = EPCMISC;
	Netfile *f, **fp;
	Pbuf *p;
	int x;
	ushort t;

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

		/* statistics */
		if(p->stat & (Rshort|Rdrbl|Rcrc|Rover)){
			if(p->stat & (Rdrbl|Rcrc))
				ether.crcs++;
			if(p->stat & Rover)
				ether.overflows++;
			if(p->stat & Rshort)
				ether.frames++;
		}
		if(p->stat & Rgood){
			x = (p->rlen[0]<<8) | p->rlen[1];
			t = (p->type[0]<<8) | p->type[1];
			for(fp = ether.f; fp < &ether.f[Ntypes]; fp++){
				f = *fp;
				if(f == 0)
					continue;
				if(f->type == t || f->type < 0)
					qproduce(f->in, p->d, x);
			}
		}

		/*
		 *  because of a chip bug, we have to reset if rtop
		 *  and rindex get too close.
		 */
		x = edlc->rtop - edlc->rindex;
		if(x < 0)
			x += Nrcv;
		if(x <= 64){
			etherhardreset();
		} else {
			edlc->rtop = ether.rindex;
			ether.rindex = RSUCC(ether.rindex);
		}
	}
	/* reenable holdoff and EPC interrupts */
	misc->clr = 0x10;
	misc->set = 0x10;
	epcenable(EIenet);
}

/*
 *  turn promiscuous mode on/off
 */
static void
promiscuous(void *arg, int on)
{
	EDLCdev *edlc = EPCEDLC;

	USED(arg);
	if(on)
		edlc->rcmd = Renab | Rall;
	else
		edlc->rcmd = Renab | Rnormal;
}

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

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

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

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

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

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

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

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

	edlc->rcmd = Renab | Rnormal;

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

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

void
etherinit(void)
{
}

Chan*
etherattach(char *spec)
{
	return devattach('l', spec);
}

Chan*
etherclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
etherwalk(Chan *c, char *name)
{
	return netifwalk(&ether, c, name);
}

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

void
ethercreate(Chan *c, char *name, int omode, ulong perm)
{
	USED(c, name, omode, perm);
}

void
etherclose(Chan *c)
{
	netifclose(&ether, c);
}

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

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

	USED(arg);
	ether.tindex = edlc->tindex;
	return TSUCC(ether.ttop) != ether.tindex;
}

long
etherwrite(Chan *c, void *buf, long n, ulong offset)
{
	Pbuf *p;
	EDLCdev *edlc = EPCEDLC;

	USED(offset);

	if(n > ETHERMAXTU)
		error(Ebadarg);

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

	/* we handle data */
	qlock(&ether.tlock);
	tsleep(&ether.tr, isoutbuf, edlc, 10000);
	if(!isoutbuf(edlc)){
		print("ether transmitter jammed\n");
	} else {
		p = &ether.tbuf[ether.ttop];
		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;
	}
	qunlock(&ether.tlock);
	return n;
}

void
etherremove(Chan *c)
{
	USED(c);
}

void
etherstat(Chan *c, char *dp)
{
	netifstat(&ether, c, dp);
}

void
etherwstat(Chan *c, char *dp)
{
	netifwstat(&ether, c, dp);
}
.
## diffname carrera/devether.c 1993/0904
## diff -e /n/fornaxdump/1993/0903/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/0904/sys/src/brazil/carrera/devether.c
461c
	netifwstat(ether[0], c, dp);
.
455c
	netifstat(ether[0], c, dp);
.
442c
	qunlock(&ctlr->tlock);
.
436,440c
		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);
.
429,430c
	}
	else {
		p =(Etherpkt*)ctlr->tb[ctlr->th];
.
425,427c
	qlock(&ctlr->tlock);
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000);
	if(!isoutbuf(ctlr)){
.
422c
		return netifwrite(ether[0], c, buf, n);
.
412,413c
	Etherpkt *p;
	TXpkt *txpkt;
	Ether *ctlr = ether[0];
.
404,406c
	return ctlr->tda[ctlr->th].status == Host;
.
402c
	Ether *ctlr = arg;
.
396c
	return netifread(ether[0], c, buf, n, offset);
.
390c
	netifclose(ether[0], c);
.
378c
	return netifopen(ether[0], c, omode);
.
372c
	return netifwalk(ether[0], c, name);
.
344,349c
	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];
.
337,341c
	memset(ctlr->ba, 0xFF, sizeof(ctlr->ba));
.
335c
	reset(ctlr);
.
332,333c
	ctlr = ether[0];
.
297,330c
	/*
	 * 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)); */
.
293,295c
	Ether *ctlr;
.
287c
		WR(rcr, reg&~Pro);
.
285c
		WR(rcr, reg|Pro);
.
283a

	reg = RD(rcr);
.
281c
	ushort reg;
.
269,272d
267a
		if(status & Br){
			print("sonic: bus retry occurred\n");
			status &= ~Br;
		}
	
		if(status & AllIntr)
			print("sonic %ux\n", status);
.
259,266c
		if(status & Lcd)
			status &= ~Lcd;
	
		/*
		 * Warnings that something is afoot.
		 */
		if(status & Hbl){
			print("sonic: cd heartbeat lost\n");
			status &= ~Hbl;
.
256,257c
		 * We get a 'load CAM done' interrupt
		 * after initialisation. Ignore it.
.
254a
	noinput:
.
253a
		status &= ~(Pktrx|Rde);
.
252a
			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];
.
243,251c

		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);
				}
.
234,241c
	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);
.
231,232c
	ctlr = ether[0];
.
229a
	Ether *ctlr;
	ulong status;
	TXpkt *txpkt;
	RXpkt *rxpkt;
	Etherpkt *p;
	Netfile *f, **fp;
.
224,227d
217,218c
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");
.
214,215c
	/*
	 * 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]));
.
209,212c
	WR(crda, LS16(ctlr->rda));
	WR(urda, MS16(ctlr->rda));
	WR(eobc, sizeof(ctlr->rb[0])/2 - 2);
.
206,207c
	ctlr->rda[Nrb-1].link |= Eol;
.
203,204c
	/*
	 * Terminate the receive descriptor ring
	 * and load the SONIC registers to describe the RDA.
.
200,201c
		ctlr->rra[i].ptr0 = ctlr->rda[i].ptr0 = LS16(ctlr->rb[i]);
		ctlr->rra[i].ptr1 = ctlr->rda[i].ptr1 = MS16(ctlr->rb[i]);
	}
.
193,198c
		ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]);
		ctlr->rda[i].owner = Interface;
.
188,191c
	/*
	 * 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;
.
184,186c
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);
.
179,182c
	int i;
.
177c
reset(Ether *ctlr)
.
172,175c
#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)

.
170a
Ether *ether[Nether];
.
169c
};
.
167a
	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 */

.
166a
	int	th;		/* first transmit buffer owned by host */	
	int	ti;		/* first transmit buffer owned by interface */
.
162,164d
157,160c
	Sonic	*sonic;		/* SONIC registers */
.
155a
	uchar	ba[6];
.
152a
/*
 * 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;
.
143,151c
	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;
.
139c
 * Receive Packet Descriptor.
.
133,136c
/*
 * 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;
.
118,130c
	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 */
.
115,116c
	Ptx	= 0x0001,	/* packet transmitted ok */
	Pintr	= 0x8000,	/* programmable interrupt */
.
107,113c
	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 */
.
105c
	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 */
.
94,103c
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 */
.
88,92c
	Nrb		= 16,		/* receive buffers */
	Ntb		= 8,		/* transmit buffers */
};
.
71,84c
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;
.
32,69c
#define RD(rn)		(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4))
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = v)
.
21,30c
#define SONICADDR	((Sonic*)Sonicbase)
.
13,19d
11c
 * National Semiconductor DP83932
 * Systems-Oriented Network Interface Controller
 * (SONIC)
.
## diffname carrera/devether.c 1993/0905
## diff -e /n/fornaxdump/1993/0904/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/0905/sys/src/brazil/carrera/devether.c
629a

iprint("tx done %d\n", n);

.
609d
607c

	if(!isoutbuf(ctlr))
.
596a
iprint("ether tx\n");

.
540a
	static int enable;

	if(enable == 0) {
		enable = 1;
		WR(cr, Rxen);
	}

.
533a
enab(void)
{
	WR(cr, Rxen);
}

void
.
516c

		if(PADDR(ether[0])+sizeof(Ether) > Ntranslation*BY2PG)
			panic("sonic: 16M io map");

		enetaddr(ether[0]->ea);
.
482c
			iprint("sonic #%lux\n", status);
.
477c
			iprint("sonic: bus retry occurred\n");
.
473c
			iprint("sonic: cd heartbeat lost\n");
.
414a
pxp(rxpkt);
.
413d
381a
print("s %lux\n", status);	
.
364a
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
.
361d
298d
294d
277a
iprint("eobc #%lux\n", RD(eobc));
.
268a
	ISquad(ctlr->rra);
	ISquad(ctlr->rda);
	ISquad(ctlr->rb);

.
258c
	for(i = 0; i < Nrb; i++) {
.
245c
	WR(dcr, 0x2423);	/* 5-19 Carrera manual */
iprint("eobc #%lux\n", RD(eobc));
.
237d
186c
typedef struct
{
.
180c
	Ntypes		= 8,
.
19a
#define ISquad(s)	if((ulong)s & 0x7) panic("sonoc: Quad alignment");
.
## diffname carrera/devether.c 1993/0906
## diff -e /n/fornaxdump/1993/0905/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/0906/sys/src/brazil/carrera/devether.c
694a
}

#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;
	}
.
674,675d
660a
		sonicswap(p, n);
.
654c
		p =(Pbuf*)ctlr->tb[ctlr->th];
.
638,639d
632c
	Pbuf *p;
.
581d
562,567d
541,543c
	if(ether[0] == 0) {
		ctlr = malloc(sizeof(Ether));
		ether[0] = ctlr;
		initbufs(ctlr);
.
538,539d
526a
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);
	}
}

.
506c
			print("sonic #%lux\n", status);
.
501c
			print("sonic: bus retry occurred\n");
.
497c
			print("sonic: cd heartbeat lost\n");
.
481c
			rxpkt = &c->rda[c->rh];
.
478,479c
			c->rda[PREV(c->rh, Nrb)].link &= ~Eol;
			c->rh = NEXT(c->rh, Nrb);
.
468c
				c->buffs++;
.
466c
				c->crcs++;
.
463c
				c->frames++;
.
448,460c
			if(rxpkt->status & Prx)
				sonicpkt(c, rxpkt, (Pbuf*)c->rb[c->rh]);
.
445,446d
440c
			c->inpackets++;
.
437,438c
		rxpkt = &c->rda[c->rh];
.
425,426c
				c->ti = NEXT(c->ti, Ntb);
				txpkt = &c->tda[c->ti];
.
422c
					c->oerrs++;
.
413c
			txpkt = &c->tda[c->ti];
.
405d
399c
	c = ether[0];
.
396,397d
390,392c
	Ether *c;
.
371,384c
	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);
	}
.
369c
sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p)
.
353a
	/*
	 * End the reset
	 * Load the Resource Descriptors and Cam contents
	 */
	WR(cr, 0);

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

.
351c
	WR(cdp, LS16(ctlr->cda));
.
345,349c
	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;
.
342,343d
301,304d
292,293d
283,284c
	WR(eobc, Rxbuf/2 - 2);
.
273d
270a
	/*
	 * Check the important resources are QUAD aligned
	 */
.
267,268c
		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);
.
264c
		ctlr->rda[i].link =  LS16(&ctlr->rda[NEXT(i, Nrb)]);
.
261,262c
		wus(&ctlr->rra[i].wc0, lolen);
		wus(&ctlr->rra[i].wc1, hilen);
.
259a

	lolen = (Rxbuf/2) & 0xFFFF;
	hilen = ((Rxbuf/2)>>16) & 0xFFFF;

.
257c
	 * thus the size of the receive buffers must be sizeof(Pbuf)+4.
.
247,248d
243c
	 * Setup the descriptor and buffer area.
.
237a
	ushort lolen, hilen, loadr, hiadr;
.
234a
wus(ushort *a, ushort v)
{
	a[0] = v;
	a[-1] = v;
}

static void
.
233a
void sonicswap(void*, int);

.
223a
	uchar	*rb[Nrb];	/* receive buffer area */
	uchar	*tb[Ntb];	/* transmit buffer area */

.
217,222c
	RXrsc	*rra;		/* receive resource area */
	RXpkt	*rda;		/* receive descriptor area */
	TXpkt	*tda;		/* transmit descriptor area */
	Cam	*cda;		/* CAM descriptor area */
.
207,208d
189,198c
	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 */
.
157,172c
	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 */
.
136,149c
	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 */
.
121,128c
	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;
.
113a

	Rxbuf	= sizeof(Pbuf)+4,
	Txbuf	= sizeof(Pbuf),
.
35c
	ulong	crba0;		/* DO NOT WRITE THESE */
	ulong	crba1;
	ulong	rbwc0;
	ulong	rbwc1;
.
21a
typedef struct Pbuf Pbuf;
struct Pbuf
{
	uchar	d[6];
	uchar	s[6];
	uchar	type[2];
	uchar	data[1500];
	uchar	crc[4];
};

.
19,20c
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = (v))
#define ISquad(s)	if((ulong)s & 0x7) panic("sonic: Quad alignment");
.
## diffname carrera/devether.c 1993/0918
## diff -e /n/fornaxdump/1993/0906/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/0918/sys/src/brazil/carrera/devether.c
725a
	poperror();
.
701a
	if(waserror()) {
		qunlock(&ctlr->tlock);
		nexterror();
	}

.
464a
			wakeup(&c->tr);
.
## diffname carrera/devether.c 1993/1202
## diff -e /n/fornaxdump/1993/0918/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1202/sys/src/brazil/carrera/devether.c
701a
	if(etherloop(buf, n))
		return n;

.
684a
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 < &ether.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;
}

.
## diffname carrera/devether.c 1993/1208
## diff -e /n/fornaxdump/1993/1202/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1208/sys/src/brazil/carrera/devether.c
698c
	for(fp = ether[0]->f; fp < &ether[0]->f[Ntypes]; fp++) {
.
693c
	if(different && memcmp(p->d, ether[0]->bcast, sizeof(p->d)))
.
## diffname carrera/devether.c 1993/1211
## diff -e /n/fornaxdump/1993/1208/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1211/sys/src/brazil/carrera/devether.c
745a
		reset(ctlr);
		WR(cr, Rxen);
	}
.
744c
	if(!isoutbuf(ctlr)) {
.
742c
	tsleep(&ctlr->tr, isoutbuf, ctlr, 1000);
.
## diffname carrera/devether.c 1993/1212
## diff -e /n/fornaxdump/1993/1211/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1212/sys/src/brazil/carrera/devether.c
750c
		p = (Pbuf*)ctlr->tb[ctlr->th];
.
744,748c
	if(!isoutbuf(ctlr))
		print("ether transmitter jammed cr #%lux\n", RD(cr));
.
742c
	tsleep(&ctlr->tr, isoutbuf, ctlr, 10000);
.
731a
	if(n > ETHERMAXTU)
		error(Ebadarg);

.
725,727d
678,685d
517c
		 * Warnings that something is atoe.
.
465c
			if(isoutbuf(c))
				wakeup(&c->tr);
.
427a
static int
isoutbuf(void *arg)
{
	Ether *ctlr = arg;

	return ctlr->tda[ctlr->th].status == Host;
}

.
78c
	Ntb		= 16,		/* transmit buffers */
.
## diffname carrera/devether.c 1993/1217
## diff -e /n/fornaxdump/1993/1212/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1217/sys/src/brazil/carrera/devether.c
597a
	if(mem >= base+64*1024)
		panic("sonic init");
.
565a
	base = mem;
.
563c
	uchar *mem, *base;
.
534a
			for(;;);
.
533c
			WR(cr, 0);
			iprint("sonic: bus retry occurred\n");
.
77,78c
	Nrb		= 8,		/* receive buffers */
	Ntb		= 8,		/* transmit buffers */
.
18,19c
#define RD(rn)		(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4))
#define WR(rn, v)	(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v))
.
## diffname carrera/devether.c 1993/1218
## diff -e /n/fornaxdump/1993/1217/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1218/sys/src/brazil/carrera/devether.c
536d
533,534c
			print("sonic: bus retry occurred\n");
.
253a
sncdly(void)
{
	int i, j, *pj;

	pj = &j;
	for(i = 0; i < 200; i++)
		*pj++;
}

static void
.
77c
	Nrb		= 16,		/* receive buffers */
.
18,19c
#define RD(rn)		(sncdly(), *(ulong*)((ulong)&SONICADDR->rn^4))
#define WR(rn, v)	(sncdly(), *(ulong*)((ulong)&SONICADDR->rn^4) = (v))
.
## diffname carrera/devether.c 1993/1219
## diff -e /n/fornaxdump/1993/1218/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1219/sys/src/brazil/carrera/devether.c
624d
466c
		if(status & (Txdn|Txer)) {
.
460a
		/* Clear the interrupt cause */
.
254,263d
18,19c
#define RD(rn)		(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4))
#define WR(rn, v)	(delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v))
.
## diffname carrera/devether.c 1993/1231
## diff -e /n/fornaxdump/1993/1219/sys/src/brazil/carrera/devether.c /n/fornaxdump/1993/1231/sys/src/brazil/carrera/devether.c
589d
584,587d
566c
	mem = xspanalloc(64*1024, 8, 64*1024);
.
## diffname carrera/devether.c 1994/0107
## diff -e /n/fornaxdump/1993/1231/sys/src/brazil/carrera/devether.c /n/fornaxdump/1994/0107/sys/src/brazil/carrera/devether.c
760c
		s = &ctlr->tda[PREV(ctlr->th, Ntb)].link;
		wus(s, *s & ~Eol);
.
758c
		wus(&txpkt->link, txpkt->link|Eol);
.
735a
	ctlr->outpackets++;
.
718a
	ushort *s;
.
539a
		}
.
538c
		if(status & AllIntr) {
			WR(isr, status);
.
533,536d
525,531d
523c
		if(status & Lcd) {
			WR(isr, Lcd);
.
515a
		WR(isr, status & (Pktrx|Rde));
.
511c
			s = &c->rda[PREV(c->rh, Nrb)].link;
			wus(s, *s & ~Eol);
.
509c
			wus(&rxpkt->link,  rxpkt->link|Eol);
.
502a
			rxpkt->status  = 0;
.
472a
			WR(isr, status & (Txdn|Txer));
.
451,452c
		/*
		 * 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;
		}
.
439a
	ushort *s;
.
400c
	WR(rcr, Brd);
.
385,386d
382d
273a
	WR(cr, 0);
.
## diffname carrera/devether.c 1994/0524
## diff -e /n/fornaxdump/1994/0107/sys/src/brazil/carrera/devether.c /n/fornaxdump/1994/0524/sys/src/brazil/carrera/devether.c
573c
	/* Put the ethernet buffers in the same place
	 * as the bootrom
	 */
	mem = (void*)(KZERO|0x2000);
.
## diffname carrera/devether.c 1995/0108
## diff -e /n/fornaxdump/1994/0524/sys/src/brazil/carrera/devether.c /n/fornaxdump/1995/0108/sys/src/brazil/carrera/devether.c
781a
}

long
etherbwrite(Chan *c, Block *bp, ulong offset)
{
	return devbwrite(c, bp, offset);
.
693a
Block*
etherbread(Chan *c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

.
## diffname carrera/devether.c 1995/0114
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/carrera/devether.c /n/fornaxdump/1995/0114/sys/src/brazil/carrera/devether.c
770d
747a
	p = buf;
	memmove(p->s, ctlr->ea, sizeof(ctlr->ea));

.
713c
	for(fp = ctlr->f; fp < &ctlr->f[Ntypes]; fp++) {
.
707,708c
	different = memcmp(p->d, ctlr->ea, sizeof(ctlr->ea));
	if(different && memcmp(p->d, ctlr->bcast, sizeof(p->d)))
.
705a
	Ether *ctlr = ether[0];
.
## diffname carrera/devether.c 1995/0520
## diff -e /n/fornaxdump/1995/0114/sys/src/brazil/carrera/devether.c /n/fornaxdump/1995/0520/sys/src/brazil/carrera/devether.c
654a
	if(*spec && strcmp(spec, "0") != 0)
		error(Eio);
.
## diffname carrera/devether.c 1997/0327
## diff -e /n/fornaxdump/1995/0520/sys/src/brazil/carrera/devether.c /n/emeliedump/1997/0327/sys/src/brazil/carrera/devether.c
836a

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,
};
.
821c
static void
.
813c
static void
.
807c
static void
.
795,801c
static void
.
734c
static long
.
696,701d
684c
static void
.
678c
static void
.
672c
static Chan*
.
660,666c
static int
.
641,646c
static Chan*
.
633c
	netifinit(ether[0], "ether0", Ntypes, 32*1024);
.
609c
static void
.
403c
static void
.
251c
static void sonicswap(void*, int);
.
244c
static Ether *ether[Nether];
.
## diffname carrera/devether.c 1997/0408
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/carrera/devether.c /n/emeliedump/1997/0408/sys/src/brazil/carrera/devether.c
838a
	'l',
	"ether",

.
## diffname carrera/devether.c 1997/1210
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/carrera/devether.c /n/emeliedump/1997/1210/sys/src/brazil/carrera/devether.c
854c
	etherbwrite,
.
852c
	etherbread,
.
837a
#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;
}

.
816c
parseether(uchar* to, char* from)
.
812a
	if(ether)
		free(ether);
.
803,811c
			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;
		}
.
798,801c
			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);
.
796c
			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);
.
790,794c
			/*
			 * 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);
.
784,788c
	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, &ether->opt[i][3]) == -1)
					memset(ether->addr, 0, Eaddrlen);
			}	
			if(endev[n]->reset(ether))
				break;
.
781,782c
	Ether *ether;
	int i, n, ctlrno;
	char name[NAMELEN], buf[128];
.
778,779c
void
etherreset(void)
.
775c
	return etheroq(ether, bp);
.
772,773c
	if(n < ETHERMINTU){
		freeb(bp);
		error(Etoosmall);
	}
.
748,770c
	if(n > ETHERMAXTU){
		freeb(bp);
		error(Ebadarg);
.
740,745d
725,738c
	n = BLEN(bp);
	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid){
		n = netifwrite(ether, chan, bp->rp, n);
		freeb(bp);
.
720,723c
	Ether *ether;
	long n;
.
718c
etherbwrite(Chan* chan, Block* bp, ulong)
.
673,716d
667,670c
	return etheroq(ether, bp);
.
661,665c
	bp = allocb(n);
	if(waserror()){
		freeb(bp);
		nexterror();
	}
	memmove(bp->rp, buf, n);
	memmove(bp->rp+Eaddrlen, ether->addr, Eaddrlen);
	poperror();
	bp->wp += n;
.
655,659c
	if(n > ETHERMAXTU)
		error(Etoobig);
	if(n < ETHERMINTU)
		error(Etoosmall);
.
646,653c
	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid)
		return netifwrite(ether, chan, buf, n);
.
644c
	Ether *ether;
	Block *bp;
.
641,642c
static long
etherwrite(Chan* chan, void* buf, long n, ulong)
.
628,638c
	return len;
.
626d
609,624c
	if(!loopback){
		if(ether->dev && ether->dev->transmit){
			qbwrite(ether->oq, bp);
			ether->dev->transmit(ether);
		}
		else{
			freeb(bp);
			return 0;
		}
.
600,607d
583,598c
	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);
.
581c
	 * 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.
.
573,578c
	ether->outpackets++;
.
570,571c
	int len, loopback, s;
	Etherpkt *pkt;
.
567,568c
static int
etheroq(Ether* ether, Block* bp)
.
550,564c
	return bp;
.
548c
	if(freebp){
		freeb(bp);
		return 0;
	}
.
533,546c
	if(fx){
		qpass(fx->in, bp);
		return 0;
.
530,531c
	}
.
507,528c
				etherrtrace(f, pkt, len);
.
490,505c
	/*
	 * 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++;
			}
.
488a
	}
.
484,487c
			return bp;
.
450,482c
	/* 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;
.
445,448c
	pkt = (Etherpkt*)bp->rp;
	len = BLEN(bp);
	type = (pkt->type[0]<<8)|pkt->type[1];
	fx = 0;
	ep = &ether->f[Ntypes];
.
443c
	ether->inpackets++;
.
437,441c
	Etherpkt *pkt;
	ushort type;
	int len;
	Netfile **ep, *f, **fp, *fx;
	Block *xbp;
.
434,435c
Block*
etheriq(Ether* ether, Block* bp, int freebp)
.
431c
	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);
.
429c
	int i, n;
	Block *bp;
.
426,427c
static void
etherrtrace(Netfile* f, Etherpkt* pkt, int len)
.
406,423c
	netifwstat(etherxx[chan->dev], chan, dp);
.
404c
etherwstat(Chan* chan, char* dp)
.
263,400d
261c
etherremove(Chan*)
.
256,257c
	return netifbread(etherxx[chan->dev], chan, n, offset);
.
233,254c
static Block*
etherbread(Chan* chan, long n, ulong offset)
.
230,231c
	return netifread(ether, chan, buf, n, offset);
}
.
225,228c
	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);
	}
.
222,223c
	Ether *ether;
.
219,220c
static long
etherread(Chan* chan, void* buf, long n, ulong offset)
.
206,217c
	netifclose(etherxx[chan->dev], chan);
}
.
192,204c
static void
etherclose(Chan* chan)
.
174,190c
}
.
169,172c
static void
ethercreate(Chan*, char*, int, ulong)
.
152,167c
	return netifopen(etherxx[chan->dev], chan, omode);
}
.
147,150c
static Chan*
etheropen(Chan* chan, int omode)
.
137,145c
	netifstat(etherxx[chan->dev], chan, dp);
}
.
93,135c
static void
etherstat(Chan* chan, char* dp)
.
83,91c
	return netifwalk(etherxx[chan->dev], chan, name);
}
.
81c
static int
etherwalk(Chan* chan, char* name)
.
75,79c
	chan = devattach('l', spec);
	chan->dev = ctlrno;
	if(etherxx[ctlrno]->dev && etherxx[ctlrno]->dev->attach)
		etherxx[ctlrno]->dev->attach(etherxx[ctlrno]);
	return chan;
}
.
32,73c
	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);
.
25,30c
	ulong ctlrno;
	char *p;
	Chan *chan;
.
18,23c
Chan*
etherattach(char* spec)
.
16c
static Ether *etherxx[MaxEther];
.
10,14c
#include "etherif.h"
.
1,8c
#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"
.
## diffname carrera/devether.c 1998/0319
## diff -e /n/emeliedump/1997/1210/sys/src/brazil/carrera/devether.c /n/emeliedump/1998/0319/sys/src/brazil/carrera/devether.c
234c
etherwrite(Chan* chan, void* buf, long n, vlong)
.
70a
	ulong offset = off;
.
68c
etherread(Chan* chan, void* buf, long n, vlong off)
.
## diffname carrera/devether.c 1999/0629
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/carrera/devether.c /n/emeliedump/1999/0629/sys/src/brazil/carrera/devether.c
329c
				i += sprint(buf+i, " irq %ld", ether->irq);
.
## diffname carrera/devether.c 2000/0713
## diff -e /n/emeliedump/1999/0629/sys/src/brazil/carrera/devether.c /n/emeliedump/2000/0713/sys/src/9/carrera/devether.c
117,118c
	bp = iallocb(64);
	if(bp == nil)
.
113,114c
	if(len > 58)
		n = 58;
.
## diffname carrera/devether.c 2001/0527 # deleted
## diff -e /n/emeliedump/2000/0713/sys/src/9/carrera/devether.c /n/emeliedump/2001/0527/sys/src/9/carrera/devether.c
1,431d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.