891 lines · 19.1 KB · C
RawDownload
/* * FCCn ethernet */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "imm.h"#include "../port/error.h"#include "../port/netif.h" #include "etherif.h"#include "../ppc/ethermii.h" #define DBG 1 enum {	Nrdre		= 128,			/* receive descriptor ring entries */	Ntdre		= 128,			/* transmit descriptor ring entries */ 	Rbsize		= ETHERMAXTU+4,		/* ring buffer size (+4 for CRC) */	Bufsize		= Rbsize+CACHELINESZ,	/* extra room for alignment */}; enum { 	/* ether-specific Rx BD bits */	RxMiss=		SBIT(7),	RxeLG=		SBIT(10),	RxeNO=		SBIT(11),	RxeSH=		SBIT(12),	RxeCR=		SBIT(13),	RxeOV=		SBIT(14),	RxeCL=		SBIT(15),	RxError=	(RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL),	/* various error flags */ 	/* ether-specific Tx BD bits */	TxPad=		SBIT(1),	/* pad short frames */	TxTC=		SBIT(5),	/* transmit CRC */	TxeDEF=		SBIT(6),	TxeHB=		SBIT(7),	TxeLC=		SBIT(8),	TxeRL=		SBIT(9),	TxeUN=		SBIT(14),	TxeCSL=		SBIT(15), 	/* psmr */	CRCE=		BIT(24),	/* Ethernet CRC */	FCE=		BIT(10),	/* flow control */	PRO=		BIT(9),		/* promiscuous mode */	FDE=		BIT(5),		/* full duplex ethernet */	LPB=		BIT(3),		/* local protect bit */ 	/* gfmr */	ENET=		0xc,		/* ethernet mode */	ENT=		BIT(27),	ENR=		BIT(26),	TCI=		BIT(2), 	/* FCC function code register */	GBL=		0x20,	BO=		0x18,	EB=		0x10,		/* Motorola byte order */	TC2=		0x04,	DTB=		0x02,	BDB=		0x01, 	/* FCC Event/Mask bits */	GRA=		SBIT(8),	RXC=		SBIT(9),	TXC=		SBIT(10),	TXE=		SBIT(11),	RXF=		SBIT(12),	BSY=		SBIT(13),	TXB=		SBIT(14),	RXB=		SBIT(15),}; enum {		/* Mcr */	MDIread	=	0x60020000,	/* read opcode */	MDIwrite =	0x50020000,	/* write opcode */}; typedef struct Etherparam Etherparam;struct Etherparam {/*0x00*/	FCCparam;/*0x3c*/	ulong	stat_buf;/*0x40*/	ulong	cam_ptr;/*0x44*/	ulong	cmask;/*0x48*/	ulong	cpres;/*0x4c*/	ulong	crcec;/*0x50*/	ulong	alec;/*0x54*/	ulong	disfc;/*0x58*/	ushort	retlim;/*0x5a*/	ushort	retcnt;/*0x5c*/	ushort	p_per;/*0x5e*/	ushort	boff_cnt;/*0x60*/	ulong	gaddr[2];/*0x68*/	ushort	tfcstat;/*0x6a*/	ushort	tfclen;/*0x6c*/	ulong	tfcptr;/*0x70*/	ushort	mflr;/*0x72*/	ushort	paddr[3];/*0x78*/	ushort	ibd_cnt;/*0x7a*/	ushort	ibd_start;/*0x7c*/	ushort	ibd_end;/*0x7e*/	ushort	tx_len;/*0x80*/	uchar	ibd_base[32];/*0xa0*/	ulong	iaddr[2];/*0xa8*/	ushort	minflr;/*0xaa*/	ushort	taddr[3];/*0xb0*/	ushort	padptr;/*0xb2*/	ushort	Rsvdb2;/*0xb4*/	ushort	cf_range;/*0xb6*/	ushort	max_b;/*0xb8*/	ushort	maxd1;/*0xba*/	ushort	maxd2;/*0xbc*/	ushort	maxd;/*0xbe*/	ushort	dma_cnt;/*0xc0*/	ulong	octc;/*0xc4*/	ulong	colc;/*0xc8*/	ulong	broc;/*0xcc*/	ulong	mulc;/*0xd0*/	ulong	uspc;/*0xd4*/	ulong	frgc;/*0xd8*/	ulong	ospc;/*0xdc*/	ulong	jbrc;/*0xe0*/	ulong	p64c;/*0xe4*/	ulong	p65c;/*0xe8*/	ulong	p128c;/*0xec*/	ulong	p256c;/*0xf0*/	ulong	p512c;/*0xf4*/	ulong	p1024c;/*0xf8*/	ulong	cam_buf;/*0xfc*/	ulong	Rsvdfc;/*0x100*/}; typedef struct Ctlr Ctlr;struct Ctlr {	Lock;	int	fccid;	int	port;	ulong	pmdio;	ulong	pmdck;	int	init;	int	active;	int	duplex;		/* 1 == full */	FCC*	fcc; 	Ring;	Block*	rcvbufs[Nrdre];	Mii*	mii;	Timer; 	ulong	interrupts;	/* statistics */	ulong	deferred;	ulong	heartbeat;	ulong	latecoll;	ulong	retrylim;	ulong	underrun;	ulong	overrun;	ulong	carrierlost;	ulong	retrycount;}; static	int	fccirq[] = {0x20, 0x21, 0x22};static	int	fccid[] = {FCC1ID, FCC2ID, FCC3ID}; #ifdef DBGulong fccrhisto[16];ulong fccthisto[16];ulong fccrthisto[16];ulong fcctrhisto[16];ulong ehisto[0x80];#endif static int fccmiimir(Mii*, int, int);static int fccmiimiw(Mii*, int, int, int);static void fccltimer(Ureg*, Timer*); static voidattach(Ether *ether){	Ctlr *ctlr; 	ctlr = ether->ctlr;	ilock(ctlr);	ctlr->active = 1;	ctlr->fcc->gfmr |= ENR|ENT;	iunlock(ctlr);	ctlr->tmode = Tperiodic;	ctlr->tf = fccltimer;	ctlr->ta = ether;	ctlr->tns = 5000000000LL;	/* 5 seconds */	timeradd(ctlr);} static voidclosed(Ether *ether){	Ctlr *ctlr; 	ctlr = ether->ctlr;	ilock(ctlr);	ctlr->active = 0;	ctlr->fcc->gfmr &= ~(ENR|ENT);	iunlock(ctlr);	print("Ether closed\n");} static voidpromiscuous(void* arg, int on){	Ether *ether;	Ctlr *ctlr; 	ether = (Ether*)arg;	ctlr = ether->ctlr; 	ilock(ctlr);	if(on || ether->nmaddr)		ctlr->fcc->fpsmr |= PRO;	else		ctlr->fcc->fpsmr &= ~PRO;	iunlock(ctlr);} static voidmulticast(void* arg, uchar *addr, int on){	Ether *ether;	Ctlr *ctlr; 	USED(addr, on);	/* if on, could SetGroupAddress; if !on, it's hard */ 	ether = (Ether*)arg;	ctlr = ether->ctlr; 	ilock(ctlr);	if(ether->prom || ether->nmaddr)		ctlr->fcc->fpsmr |= PRO;	else		ctlr->fcc->fpsmr &= ~PRO;	iunlock(ctlr);} static voidtxstart(Ether *ether){	int len;	Ctlr *ctlr;	Block *b;	BD *dre; 	ctlr = ether->ctlr;	if(ctlr->init)		return;	while(ctlr->ntq < Ntdre-1){		b = qget(ether->oq);		if(b == 0)			break; 		dre = &ctlr->tdr[ctlr->tdrh];		dczap(dre, sizeof(BD));		if(dre->status & BDReady)			panic("ether: txstart"); 		/*		 * Give ownership of the descriptor to the chip, increment the		 * software ring descriptor pointer and tell the chip to poll.		 */		len = BLEN(b);		if(ctlr->txb[ctlr->tdrh] != nil)			panic("fcc/ether: txstart");		ctlr->txb[ctlr->tdrh] = b;		if((ulong)b->rp&1)			panic("fcc/ether: txstart align");	/* TO DO: ensure alignment */		dre->addr = PADDR(b->rp);		dre->length = len;		dcflush(b->rp, len);		dcflush(dre, sizeof(BD));		dre->status = (dre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC;		dcflush(dre, sizeof(BD));/*		ctlr->fcc->ftodr = 1<<15;	/* transmit now; Don't do this according to errata */		ctlr->ntq++;		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);	}} static voidtransmit(Ether* ether){	Ctlr *ctlr; 	ctlr = ether->ctlr;	ilock(ctlr);	txstart(ether);	iunlock(ctlr);} static voidinterrupt(Ureg*, void *arg){	int len, status, rcvd, xmtd, restart;	ushort events;	Ctlr *ctlr;	BD *dre;	Block *b, *nb;	Ether *ether = arg; 	ctlr = ether->ctlr;	if(!ctlr->active)		return;	/* not ours */ 	/*	 * Acknowledge all interrupts and whine about those that shouldn't	 * happen.	 */	events = ctlr->fcc->fcce;	ctlr->fcc->fcce = events;		/* clear events */ #ifdef DBG	ehisto[events & 0x7f]++;#endif 	ctlr->interrupts++; 	if(events & BSY)		ctlr->overrun++;	if(events & TXE)		ether->oerrs++; #ifdef DBG	rcvd = xmtd = 0;#endif	/*	 * Receiver interrupt: run round the descriptor ring logging	 * errors and passing valid receive data up to the higher levels	 * until we encounter a descriptor still owned by the chip.	 */	if(events & RXF){		dre = &ctlr->rdr[ctlr->rdrx];		dczap(dre, sizeof(BD));		while(((status = dre->status) & BDEmpty) == 0){			rcvd++;			if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){				if(status & (RxeLG|RxeSH))					ether->buffs++;				if(status & RxeNO)					ether->frames++;				if(status & RxeCR)					ether->crcs++;				if(status & RxeOV)					ether->overflows++;				print("eth rx: %ux\n", status);			}else{				/*				 * We have a packet. Read it in.				 */				len = dre->length-4;				b = ctlr->rcvbufs[ctlr->rdrx];				assert(dre->addr == PADDR(b->rp));				dczap(b->rp, len);				if(nb = iallocb(Bufsize)){					b->wp += len;					etheriq(ether, b, 1);					b = nb;					b->rp = (uchar*)(((ulong)b->rp + CACHELINESZ-1) & ~(CACHELINESZ-1));					b->wp = b->rp;					ctlr->rcvbufs[ctlr->rdrx] = b;					ctlr->rdr[ctlr->rdrx].addr = PADDR(b->wp);				}else					ether->soverflows++;			} 			/*			 * Finished with this descriptor, reinitialise it,			 * give it back to the chip, then on to the next...			 */			dre->length = 0;			dre->status = (status & BDWrap) | BDEmpty | BDInt;			dcflush(dre, sizeof(BD)); 			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);			dre = &ctlr->rdr[ctlr->rdrx];			dczap(dre, sizeof(BD));		}	} 	/*	 * Transmitter interrupt: handle anything queued for a free descriptor.	 */	if(events & (TXB|TXE)){		ilock(ctlr);		restart = 0;		while(ctlr->ntq){			dre = &ctlr->tdr[ctlr->tdri];			dczap(dre, sizeof(BD));			status = dre->status;			if(status & BDReady)				break;			if(status & TxeDEF)				ctlr->deferred++;			if(status & TxeHB)				ctlr->heartbeat++;			if(status & TxeLC)				ctlr->latecoll++;			if(status & TxeRL)				ctlr->retrylim++;			if(status & TxeUN)				ctlr->underrun++;			if(status & TxeCSL)				ctlr->carrierlost++;			if(status & (TxeLC|TxeRL|TxeUN))				restart = 1;			ctlr->retrycount += (status>>2)&0xF;			b = ctlr->txb[ctlr->tdri];			if(b == nil)				panic("fcce/interrupt: bufp");			ctlr->txb[ctlr->tdri] = nil;			freeb(b);			ctlr->ntq--;			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);			xmtd++;		} 		if(restart){			ctlr->fcc->gfmr &= ~ENT;			delay(10);			ctlr->fcc->gfmr |= ENT;			cpmop(RestartTx, ctlr->fccid, 0xc);		}		txstart(ether);		iunlock(ctlr);	}#ifdef DBG	if(rcvd >= nelem(fccrhisto))		rcvd = nelem(fccrhisto) - 1;	if(xmtd >= nelem(fccthisto))		xmtd = nelem(fccthisto) - 1;	if(rcvd)		fcctrhisto[xmtd]++;	else		fccthisto[xmtd]++;	if(xmtd)		fccrthisto[rcvd]++;	else		fccrhisto[rcvd]++;#endif} static longifstat(Ether* ether, void* a, long n, ulong offset){	char *p;	int len, i, r;	Ctlr *ctlr;	MiiPhy *phy; 	if(n == 0)		return 0; 	ctlr = ether->ctlr; 	p = malloc(2*READSTR);	len = snprint(p, 2*READSTR, "interrupts: %lud\n", ctlr->interrupts);	len += snprint(p+len, 2*READSTR-len, "carrierlost: %lud\n", ctlr->carrierlost);	len += snprint(p+len, 2*READSTR-len, "heartbeat: %lud\n", ctlr->heartbeat);	len += snprint(p+len, 2*READSTR-len, "retrylimit: %lud\n", ctlr->retrylim);	len += snprint(p+len, 2*READSTR-len, "retrycount: %lud\n", ctlr->retrycount);	len += snprint(p+len, 2*READSTR-len, "latecollisions: %lud\n", ctlr->latecoll);	len += snprint(p+len, 2*READSTR-len, "rxoverruns: %lud\n", ctlr->overrun);	len += snprint(p+len, 2*READSTR-len, "txunderruns: %lud\n", ctlr->underrun);	len += snprint(p+len, 2*READSTR-len, "framesdeferred: %lud\n", ctlr->deferred);	miistatus(ctlr->mii);	phy = ctlr->mii->curphy;	len += snprint(p+len, 2*READSTR-len, "phy: link=%d, tfc=%d, rfc=%d, speed=%d, fd=%d\n",		phy->link, phy->tfc, phy->rfc, phy->speed, phy->fd); #ifdef DBG	if(ctlr->mii != nil && ctlr->mii->curphy != nil){		len += snprint(p+len, 2*READSTR, "phy:   ");		for(i = 0; i < NMiiPhyr; i++){			if(i && ((i & 0x07) == 0))				len += snprint(p+len, 2*READSTR-len, "\n       ");			r = miimir(ctlr->mii, i);			len += snprint(p+len, 2*READSTR-len, " %4.4uX", r);		}		snprint(p+len, 2*READSTR-len, "\n");	}#endif	snprint(p+len, 2*READSTR-len, "\n"); 	n = readstr(offset, a, n, p);	free(p); 

Lines 1–500 of 891.