Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/pc/ether79c970.c

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


## diffname pc/ether79c970.c 1995/0721
## diff -e /dev/null /n/fornaxdump/1995/0721/sys/src/brazil/pc/ether79c970.c
0a
/*
 * AM79C970
 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
 * To do:
 *	only issue transmit interrupt if necessary?
 *	dynamically increase rings as necessary?
 *	use Block's as receive buffers?
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "etherif.h"

enum {
	Lognrdre	= 6,
	Nrdre		= (1<<Lognrdre),	/* receive descriptor ring entries */
	Logntdre	= 4,
	Ntdre		= (1<<Logntdre),	/* transmit descriptor ring entries */

	Rbsize		= ETHERMAXTU+4,		/* ring buffer size (+4 for CRC) */
};

enum {						/* DWIO I/O resource map */
	Aprom		= 0x0000,		/* physical address */
	Rdp		= 0x0010,		/* register data port */
	Rap		= 0x0014,		/* register address port */
	Sreset		= 0x0018,		/* software reset */
	Bdp		= 0x001C,		/* bus configuration register data port */
};

enum {						/* CSR0 */
	Init		= 0x0001,		/* begin initialisation */
	Strt		= 0x0002,		/* enable chip */
	Stop		= 0x0004,		/* disable chip */
	Tdmd		= 0x0008,		/* transmit demand */
	Txon		= 0x0010,		/* transmitter on */
	Rxon		= 0x0020,		/* receiver on */
	Iena		= 0x0040,		/* interrupt enable */
	Intr		= 0x0080,		/* interrupt flag */
	Idon		= 0x0100,		/* initialisation done */
	Tint		= 0x0200,		/* transmit interrupt */
	Rint		= 0x0400,		/* receive interrupt */
	Merr		= 0x0800,		/* memory error */
	Miss		= 0x1000,		/* missed frame */
	Cerr		= 0x2000,		/* collision */
	Babl		= 0x4000,		/* transmitter timeout */
	Err		= 0x8000,		/* Babl|Cerr|Miss|Merr */
};
	
enum {						/* CSR3 */
	Bswp		= 0x0004,		/* byte swap */
	Emba		= 0x0008,		/* enable modified back-off algorithm */
	Dxmt2pd		= 0x0010,		/* disable transmit two part deferral */
	Lappen		= 0x0020,		/* look-ahead packet processing enable */
	Idonm		= 0x0100,		/* initialisation done mask */
	Tintm		= 0x0200,		/* transmit interrupt mask */
	Rintm		= 0x0400,		/* receive interrupt mask */
	Merrm		= 0x0800,		/* memory error mask */
	Missm		= 0x1000,		/* missed frame mask */
	Bablm		= 0x4000,		/* babl mask */
};

enum {						/* CSR4 */
	ApadXmt		= 0x0800,		/* auto pad transmit */
};

enum {						/* CSR15 */
	Prom		= 0x8000,		/* promiscuous mode */
};

typedef struct {				/* Initialisation Block */
	ushort	mode;
	uchar	rlen;				/* upper 4 bits */
	uchar	tlen;				/* upper 4 bits */
	uchar	padr[6];
	uchar	res[2];
	uchar	ladr[8];
	ulong	rdra;
	ulong	tdra;
} Iblock;

typedef struct {				/* receive descriptor ring entry */
	ulong	rbadr;
	ulong	rmd1;				/* status|bcnt */
	ulong	rmd2;				/* rcc|rpc|mcnt */
	ulong	rmd3;				/* reserved */
} Rdre;

typedef struct {				/* transmit descriptor ring entry */
	ulong	tbadr;
	ulong	tmd1;				/* status|bcnt */
	ulong	tmd2;				/* errors */
	ulong	tmd3;				/* reserved */
} Tdre;

enum {						/* [RT]dre status bits */
	Enp		= 0x01000000,		/* end of packet */
	Stp		= 0x02000000,		/* start of packet */
	RxBuff		= 0x04000000,		/* buffer error */
	TxDef		= 0x04000000,		/* deferred */
	RxCrc		= 0x08000000,		/* CRC error */
	TxOne		= 0x08000000,		/* one retry needed */
	RxOflo		= 0x10000000,		/* overflow error */
	TxMore		= 0x10000000,		/* more than one retry needed */
	Fram		= 0x20000000,		/* framing error */
	RxErr		= 0x40000000,		/* Fram|Oflo|Crc|RxBuff */
	TxErr		= 0x40000000,		/* Uflo|Lcol|Lcar|Rtry */
	Own		= 0x80000000,
};

typedef struct {
	Lock	raplock;			/* registers other than CSR0 */

	Iblock	iblock;

	Rdre*	rdr;				/* receive descriptor ring */
	void*	rrb;				/* receive ring buffers */
	int	rdrx;				/* index into rdr */

	Rendez	trendez;			/* wait here for free tdre */
	Tdre*	tdr;				/* transmit descriptor ring */
	void*	trb;				/* transmit ring buffers */
	int	tdrx;				/* index into tdr */
} Ctlr;

static void
attach(Ether* ether)
{
	int port;

	port = ether->port;
	outl(port+Rdp, Iena|Strt);
}

static void
ringinit(Ctlr* ctlr)
{
	int i, x;

	/*
	 * Initialise the receive and transmit buffer rings. The ring
	 * entries must be aligned on 16-byte boundaries.
	 */
	if(ctlr->rdr == 0)
		ctlr->rdr = xspanalloc(Nrdre*sizeof(Rdre), 0x10, 0);
	if(ctlr->rrb == 0)
		ctlr->rrb = xalloc(Nrdre*Rbsize);
	x = PADDR(ctlr->rrb);
	for(i = 0; i < Nrdre; i++){
		ctlr->rdr[i].rbadr = x;
		x += Rbsize;
		ctlr->rdr[i].rmd1 = Own|(-Rbsize & 0xFFFF);
	}
	ctlr->rdrx = 0;

	if(ctlr->tdr == 0)
		ctlr->tdr = xspanalloc(Ntdre*sizeof(Tdre), 0x10, 0);
	if(ctlr->trb == 0)
		ctlr->trb = xalloc(Ntdre*Rbsize);
	x = PADDR(ctlr->trb);
	for(i = 0; i < Ntdre; i++){
		ctlr->tdr[i].tbadr = x;
		x += Rbsize;
	}
	ctlr->tdrx = 0;
}

static void
promiscuous(void* arg, int on)
{
	Ether *ether;
	int port, x;
	Ctlr *ctlr;

	ether = arg;
	port = ether->port;
	ctlr = ether->ctlr;

	/*
	 * Put the chip into promiscuous mode. First we must wait until
	 * anyone transmitting is done, then we can stop the chip and put
	 * it in promiscuous mode. Restarting is made harder by the chip
	 * reloading the transmit and receive descriptor pointers with their
	 * base addresses when Strt is set (unlike the older Lance chip),
	 * so the rings must be re-initialised.
	 */
	qlock(&ether->tlock);

	ilock(&ctlr->raplock);
	outl(port+Rdp, Stop);

	outl(port+Rap, 15);
	x = inl(port+Rdp) & ~Prom;
	if(on)
		x |= Prom;
	outl(port+Rdp, x);
	outl(port+Rap, 0);

	ringinit(ctlr);
	outl(port+Rdp, Iena|Strt);
	iunlock(&ctlr->raplock);

	qunlock(&ether->tlock);
}

static int
owntdre(void* arg)
{
	return (((Tdre*)arg)->tmd1 & Own) == 0;
}

static long
write(Ether* ether, void* buf, long n)
{
	int port;
	Ctlr *ctlr;
	Tdre *tdre;
	Etherpkt *pkt;

	port = ether->port;
	ctlr = ether->ctlr;

	/*
	 * Wait for a transmit ring descriptor (and hence a buffer) to become
	 * free. If none become free after a reasonable period, give up.
	 */
	tdre = &ctlr->tdr[ctlr->tdrx];
	tsleep(&ctlr->trendez, owntdre, tdre, 100);
	if(owntdre(tdre) == 0)
		return 0;

	/*
	 * Copy the packet to the transmit buffer and fill in our
	 * source ethernet address. There's no need to pad to ETHERMINTU
	 * here as we set ApadXmit in CSR4.
	 */
	pkt = KADDR(tdre->tbadr);
	memmove(pkt->d, buf, n);
	memmove(pkt->s, ether->ea, sizeof(pkt->s));

	/*
	 * Give ownership of the descriptor to the chip, increment the
	 * software ring descriptor pointer and tell the chip to poll.
	 */
	tdre->tmd2 = 0;
	tdre->tmd1 = Own|Stp|Enp|(-n & 0xFFFF);
	ctlr->tdrx = NEXT(ctlr->tdrx, Ntdre);
	outl(port+Rdp, Iena|Tdmd);

	ether->outpackets++;
	return n;
}

static void
interrupt(Ureg*, void* arg)
{
	Ether *ether;
	int port, csr0, status;
	Ctlr *ctlr;
	Rdre *rdre;
	Etherpkt *pkt;

	ether = arg;
	port = ether->port;
	ctlr = ether->ctlr;

	/*
	 * Acknowledge all interrupts and whine about those that shouldn't
	 * happen.
	 */
	csr0 = inl(port+Rdp);
	outl(port+Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
	if(csr0 & (Babl|Miss|Merr))
		print("AMD70C970#%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);

	/*
	 * 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(csr0 & Rint){
		rdre = &ctlr->rdr[ctlr->rdrx];
		while(((status = rdre->rmd1) & Own) == 0){
			if(status & RxErr){
				if(status & RxBuff)
					ether->buffs++;
				if(status & RxCrc)
					ether->crcs++;
				if(status & RxOflo)
					ether->overflows++;
			}
			else{
				ether->inpackets++;
				pkt = KADDR(rdre->rbadr);
				etherrloop(ether, pkt, (rdre->rmd2 & 0x0FFF)-4);
			}

			/*
			 * Finished with this descriptor, reinitialise it,
			 * give it back to the chip, then on to the next...
			 */
			rdre->rmd2 = 0;
			rdre->rmd1 = Own|(-Rbsize & 0xFFFF);

			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
			rdre = &ctlr->rdr[ctlr->rdrx];
		}
	}

	/*
	 * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
	 */
	if(csr0 & Tint)
		wakeup(&ctlr->trendez);
}

typedef struct Adapter Adapter;
struct Adapter {
	Adapter*	next;
	int		port;
	PCIcfg*		pcicfg;
};
static Adapter *adapter;

static PCIcfg*
amd79c90(Ether* ether)
{
	PCIcfg *pcicfg;
	static int devno = 0;
	int port;
	Adapter *ap;

	pcicfg = malloc(sizeof(PCIcfg));
	for(;;){
		pcicfg->vid = 0x1022;
		pcicfg->did = 0x2000;
		if((devno = pcimatch(0, devno, pcicfg)) == -1)
			break;

		port = pcicfg->baseaddr[0] & ~0x01;
		if(ether->port == 0 || ether->port == port)
			return pcicfg;

		ap = malloc(sizeof(Adapter));
		ap->pcicfg = pcicfg;
		ap->port = port;
		ap->next = adapter;
		adapter = ap;

		pcicfg = malloc(sizeof(PCIcfg));
	}
	free(pcicfg);

	return 0;
}

static int
reset(Ether* ether)
{
	int port, x;
	PCIcfg *pcicfg;
	Adapter *ap, **app;
	uchar ea[Eaddrlen];
	Ctlr *ctlr;

	/*
	 * Any adapter matches if no ether->port is supplied, otherwise the
	 * ports must match. First see if we've already found an adapter that fits
	 * the bill. If not then scan for another.
	 */
	port = 0;
	pcicfg = 0;
	for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){
		if(ether->port == 0 || ether->port == ap->port){
			port = ap->port;
			pcicfg = ap->pcicfg;
			*app = ap->next;
			free(ap);
			break;
		}
	}
	if(port == 0 && (pcicfg = amd79c90(ether))){
		port = pcicfg->baseaddr[0] & ~0x01;
		ether->irq = pcicfg->irq;
	}
	if(port == 0)
		return -1;

	if(pcicfg)
		free(pcicfg);

	/*
	 * How can we tell what mode we're in at this point - if we're in WORD
	 * mode then the only 32-bit access we are allowed to make is a write to
	 * the RDP, which forces the chip to DWORD mode; if we're in DWORD mode
	 * then we're not allowed to make any non-DWORD accesses?
	 * Assuming we do a DWORD write to the RDP, how can we tell what we're
	 * about to overwrite as we can't reliably access the RAP?
	 *
	 * Force DWORD mode by writing to RDP, doing a reset then writing to RDP
	 * again; at least we know what state we're in now. The value of RAP after
	 * a reset is 0, so the second DWORD write will be to CSR0.
	 * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
	 * Set the auto pad transmit in CSR4.
	 */
	outl(port+Rdp, 0x00);
	inl(port+Sreset);
	outl(port+Rdp, Stop);

	outl(port+Rap, 20);
	outl(port+Bdp, 0x0002);

	outl(port+Rap, 4);
	x = inl(port+Rdp) & 0xFFFF;
	outl(port+Rdp, ApadXmt|x);

	outl(port+Rap, 0);

	/*
	 * Check if we are going to override the adapter's station address.
	 * If not, read it from the I/O-space and set in ether->ea prior to loading the
	 * station address in the initialisation block.
	 */
	memset(ea, 0, Eaddrlen);
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
		x = inl(port+Aprom);
		ether->ea[0] = x & 0xFF;
		ether->ea[1] = (x>>8) & 0xFF;
		ether->ea[2] = (x>>16) & 0xFF;
		ether->ea[3] = (x>>24) & 0xFF;
		x = inl(port+Aprom+4);
		ether->ea[4] = x & 0xFF;
		ether->ea[5] = (x>>8) & 0xFF;
	}

	/*
	 * Allocate a controller structure and start to fill in the
	 * initialisation block (must be DWORD aligned).
	 */
	ether->ctlr = malloc(sizeof(Ctlr));
	ctlr = ether->ctlr;

	ctlr->iblock.rlen = Lognrdre<<4;
	ctlr->iblock.tlen = Logntdre<<4;
	memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));

	ringinit(ctlr);
	ctlr->iblock.rdra = PADDR(ctlr->rdr);
	ctlr->iblock.tdra = PADDR(ctlr->tdr);

	/*
	 * Point the chip at the initialisation block and tell it to go.
	 * Mask the Idon interrupt and poll for completion. Strt and interrupt
	 * enables will be set later when we're ready to attach to the network.
	 */
	x = PADDR(&ctlr->iblock);
	outl(port+Rap, 1);
	outl(port+Rdp, x & 0xFFFF);
	outl(port+Rap, 2);
	outl(port+Rdp, (x>>16) & 0xFFFF);
	outl(port+Rap, 3);
	outl(port+Rdp, Idonm);
	outl(port+Rap, 0);
	outl(port+Rdp, Init);

	while((inl(port+Rdp) & Idon) == 0)
		;
	outl(port+Rdp, Idon|Stop);
	
	ether->port = port;
	ether->attach = attach;
	ether->write = write;
	ether->interrupt = interrupt;

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

	return 0;
}

void
ether79c970link(void)
{
	addethercard("AMD79C970",  reset);
}
.
## diffname pc/ether79c970.c 1995/0817
## diff -e /n/fornaxdump/1995/0721/sys/src/brazil/pc/ether79c970.c /n/fornaxdump/1995/0817/sys/src/brazil/pc/ether79c970.c
23c
	Logntdre	= 5,
.
21c
	Lognrdre	= 7,
.
## diffname pc/ether79c970.c 1996/0607
## diff -e /n/fornaxdump/1995/0817/sys/src/brazil/pc/ether79c970.c /n/fornaxdump/1996/0607/sys/src/brazil/pc/ether79c970.c
460c
	 * enables will be set later when attaching to the network.
.
426c
	 * Check if the adapter's station address is to be over-ridden.
.
407,408c
	 * again. The value of RAP after a reset is 0, so the second DWORD write
	 * will be to CSR0.
.
399,404c
	 * How to tell what mode the chip is in at this point - if it's in WORD
	 * mode then the only 32-bit access allowedis a write to the RDP, which
	 * forces the chip to DWORD mode; if it's in DWORD mode then only DWORD
	 * accesses are allowed?
	 * Assuming a DWORD write is done to the RDP, what will be overwritten as
	 * the RAP can't reliably be accessed?
.
395,397d
388,392c
	if(port == 0 && (port = amd79c90(ether)) == 0)
.
382c
			ether->irq = ap->irq;
.
378d
367d
358d
355,356d
352a
		ap->irq = irq;
.
351d
346,348c
		port = pcicfg.baseaddr[0] & ~0x01;
		irq = pcicfg.irq;
		if(ether->port == 0 || ether->port == port){
			ether->irq = irq;
			return port;
		}
.
341,343c
		pcicfg.vid = 0x1022;
		pcicfg.did = 0x2000;
		if((devno = pcimatch(0, devno, &pcicfg)) == -1)
.
339d
336c
	int irq, port;
.
334c
	PCIcfg pcicfg;
.
331c
static int
.
327c
	int		irq;
.
241c
	 * here as ApadXmit is set in CSR4.
.
239c
	 * Copy the packet to the transmit buffer and fill in the
.
4a
 *	bag the tsleep in write, buffer them up;
 *	loop in interrupt routine until all done;
.
## diffname pc/ether79c970.c 1996/0608
## diff -e /n/fornaxdump/1996/0607/sys/src/brazil/pc/ether79c970.c /n/fornaxdump/1996/0608/sys/src/brazil/pc/ether79c970.c
374,375c
	 * ports must match. First see if an adapter that fits the bill has
	 * already been found. If not then scan for another.
.
287c
	 * until a descriptor is encountered still owned by the chip.
.
188,189c
	 * Put the chip into promiscuous mode. First must wait until
	 * anyone transmitting is done, then stop the chip and put
.
## diffname pc/ether79c970.c 1997/0327
## diff -e /n/fornaxdump/1996/0608/sys/src/brazil/pc/ether79c970.c /n/emeliedump/1997/0327/sys/src/brazil/pc/ether79c970.c
474a
	ether->promiscuous = promiscuous;
.
473d
471a
	ether->ifstat = ifstat;
.
470c
	ether->transmit = transmit;
.
466,467c
	csr32w(ctlr, Rdp, Idon|Stop);
	ctlr->init = 0;
	iunlock(ctlr);

	/*
	 * Linkage to the generic ethernet driver.
	 */
.
464c
	while(!(csr32r(ctlr, Rdp) & Idon))
.
455,462c
	csr32w(ctlr, Rap, 1);
	csr32w(ctlr, Rdp, x & 0xFFFF);
	csr32w(ctlr, Rap, 2);
	csr32w(ctlr, Rdp, (x>>16) & 0xFFFF);
	csr32w(ctlr, Rap, 3);
	csr32w(ctlr, Rdp, Idon);
	csr32w(ctlr, Rap, 0);
	csr32w(ctlr, Rdp, Init);
.
438,440d
435,436c
	 * Start to fill in the initialisation block
	 * (must be DWORD aligned).
.
423,431c
	if(!memcmp(ea, ether->ea, Eaddrlen)){
		x = csr32r(ctlr, Aprom);
		ether->ea[0] = x;
		ether->ea[1] = x>>8;
		ether->ea[2] = x>>16;
		ether->ea[3] = x>>24;
		x = csr32r(ctlr, Aprom+4);
		ether->ea[4] = x;
		ether->ea[5] = x>>8;
.
415c
	csr32w(ctlr, Rap, 0);
.
411,413c
	csr32w(ctlr, Rap, 4);
	x = csr32r(ctlr, Rdp) & 0xFFFF;
	csr32w(ctlr, Rdp, ApadXmt|x);
.
408,409c
	csr32w(ctlr, Rap, 20);
	csr32w(ctlr, Bdp, 0x0002);
.
404,406c
	csr32w(ctlr, Rdp, 0x00);
	csr32r(ctlr, Sreset);
	csr32w(ctlr, Rdp, Stop);
.
392c
	 * mode then the only 32-bit access allowed is a write to the RDP, which
.
390a
	 * Allocate a controller structure and start to initialise it.
	 */
	ether->ctlr = malloc(sizeof(Ctlr));
	ctlr = ether->ctlr;
	ilock(ctlr);
	ctlr->init = 1;
	ctlr->port = port;

	/*
.
382,383c
			ether->tbdf = ap->tbdf;
			*bpp = bp->next;
			freeb(bp);
.
378c
	bpp = &adapter;
	for(bp = *bpp; bp; bp = bp->next){
		ap = (Adapter*)bp->rp;
.
375c
	 * already been found. If not, scan for another.
.
368c
	Block *bp, **bpp;
	Adapter *ap;
.
354,358c
		amd79c970adapter(&adapter, port, irq, p->tbdf);
.
350a
			ether->tbdf = p->tbdf;
.
341,348c
	while(p = pcimatch(p, 0x1022, 0x2000)){
		port = p->bar[0] & ~0x01;
		irq = p->intl;
.
339d
336,337c
	static Pcidev *p;
.
332a
static void
amd79c970adapter(Block** bpp, int port, int irq, int tbdf)
{
	Block *bp;
	Adapter *ap;

	bp = allocb(sizeof(Adapter));
	ap = (Adapter*)bp->rp;
	ap->port = port;
	ap->irq = irq;
	ap->tbdf = tbdf;

	bp->next = *bpp;
	*bpp = bp;
}

.
325,331c
typedef struct Adapter {
	int	port;
	int	irq;
	int	tbdf;
} Adapter;
static Block* adapter;
.
321,322c
	if(csr0 & Tint){
		lock(ctlr);
		while(ctlr->ntq){
			dre = &ctlr->tdr[ctlr->tdri];
			if(dre->md1 & Own)
				break;
	
			if(dre->md1 & TxErr){
				if(dre->md2 & Rtry)
					ctlr->rtry++;
				if(dre->md2 & Lcar)
					ctlr->lcar++;
				if(dre->md2 & Lcol)
					ctlr->lcol++;
				if(dre->md2 & Uflo)
					ctlr->uflo++;
				if(dre->md2 & TxBuff)
					ctlr->txbuff++;
				ether->oerrs++;
			}
	
			freeb(dre->bp);
	
			ctlr->ntq--;
			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
		}
		txstart(ether);
		unlock(ctlr);
	}
	goto intrloop;
.
314c
			dre = &ctlr->rdr[ctlr->rdrx];
.
310,311c
			dre->md2 = 0;
			dre->md1 = Own|(-Rbsize & 0xFFFF);
.
300,303c
			else if(bp = iallocb(Rbsize)){
				len = (dre->md2 & 0x0FFF)-4;
				dre->bp->wp = dre->bp->rp+len;
				etheriq(ether, dre->bp, 1);
				dre->bp = bp;
				dre->addr = PADDR(bp->rp);
.
290,298c
		dre = &ctlr->rdr[ctlr->rdrx];
		while(!(dre->md1 & Own)){
			if(dre->md1 & RxErr){
				if(dre->md1 & RxBuff)
					ctlr->rxbuff++;
				if(dre->md1 & Crc)
					ctlr->crc++;
				if(dre->md1 & Oflo)
					ctlr->oflo++;
				if(dre->md1 & Fram)
					ctlr->fram++;
.
282c
		print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
	if(!(csr0 & (Rint|Tint)))
		return;
.
279,280c
intrloop:
	csr0 = csr32r(ctlr, Rdp) & 0xFFFF;
	csr32w(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
.
272d
268,269c
	Ether *ether;
	int csr0, len;
	Dre *dre;
	Block *bp;
.
265,266d
258,259c
static void
transmit(Ether* ether)
{
	Ctlr *ctlr;

	ctlr = ether->ctlr;
	ilock(ctlr);
	txstart(ether);
	iunlock(ctlr);
.
249,256c
		/*
		 * Give ownership of the descriptor to the chip,
		 * increment the software ring descriptor pointer
		 * and tell the chip to poll.
		 * There's no need to pad to ETHERMINTU
		 * here as ApadXmit is set in CSR4.
		 */
		dre = &ctlr->tdr[ctlr->tdrh];
		dre->bp = bp;
		dre->addr = PADDR(bp->rp);
		dre->md2 = 0;
		dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
		ctlr->ntq++;
		csr32w(ctlr, Rdp, Iena|Tdmd);
		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
	}
}
.
240,247c
	while(ctlr->ntq < (Ntdre-1)){
		bp = qget(ether->oq);
		if(bp == nil)
			break;
.
231,238c
	if(ctlr->init)
		return;
.
228d
225,226c
	Block *bp;
	Dre *dre;
.
217,223d
214,215c
static void
txstart(Ether* ether)
.
211c
	ilock(ctlr);
	ctlr->init = 0;
	csr32w(ctlr, Rdp, Iena|Strt);
	iunlock(ctlr);
.
208,209d
204,205c
	csr32w(ctlr, Rdp, x);
	csr32w(ctlr, Rap, 0);
.
200,201c
	csr32w(ctlr, Rdp, Stop);

	csr32w(ctlr, Rap, 15);
	x = csr32r(ctlr, Rdp) & ~Prom;
.
197,198c
	while(ctlr->ntq)
		;
.
195c
	ilock(ctlr);
	if(ctlr->init){
		iunlock(ctlr);
		return;
	}
	ctlr->init = 1;
	iunlock(ctlr);
.
184d
180c
	int x;
.
165,173c
		ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
	memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
	ctlr->tdrh = ctlr->tdri = 0;
.
152,160c
	if(ctlr->rdr == 0){
		ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0);
		for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){
			dre->bp = iallocb(Rbsize);
			dre->addr = PADDR(dre->bp->rp);
			dre->md2 = 0;
			dre->md1 = Own|(-Rbsize & 0xFFFF);
		}
.
149,150c
	 * Initialise the receive and transmit buffer rings.
	 * The ring entries must be aligned on 16-byte boundaries.
	 *
	 * This routine is protected by ctlr->init.
.
146c
	Dre *dre;
.
142a
static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
	Ctlr *ctlr;
	char buf[512];
	int len;

	ctlr = ether->ctlr;

	ether->crcs = ctlr->crc;
	ether->frames = ctlr->fram;
	ether->buffs = ctlr->rxbuff+ctlr->txbuff;
	ether->overflows = ctlr->oflo;

	if(n == 0)
		return 0;

	len = sprint(buf, "Rxbuff: %ld\n", ctlr->rxbuff);
	len += sprint(buf+len, "Crc: %ld\n", ctlr->crc);
	len += sprint(buf+len, "Oflo: %ld\n", ctlr->oflo);
	len += sprint(buf+len, "Fram: %ld\n", ctlr->fram);
	len += sprint(buf+len, "Rtry: %ld\n", ctlr->rtry);
	len += sprint(buf+len, "Lcar: %ld\n", ctlr->lcar);
	len += sprint(buf+len, "Lcol: %ld\n", ctlr->lcol);
	len += sprint(buf+len, "Uflo: %ld\n", ctlr->uflo);
	sprint(buf+len, "Txbuff: %ld\n", ctlr->txbuff);

	return readstr(offset, a, n, buf);
}

.
139,140c
	ctlr = ether->ctlr;

	ilock(ctlr);
	if(ctlr->init){
		iunlock(ctlr);
		return;
	}
	csr32w(ctlr, Rdp, Iena|Strt);
	iunlock(ctlr);
.
137c
	Ctlr *ctlr;
.
133a
#define csr32r(c, r)	(inl((c)->port+(r)))
#define csr32w(c, r, l)	(outl((c)->port+(r), (ulong)(l)))

.
128,131c
	Dre*	tdr;			/* transmit descriptor ring */
	int	tdrh;			/* host index into tdr */
	int	tdri;			/* interface index into tdr */
	int	ntq;			/* descriptors active */

	ulong	rxbuff;			/* receive statistics */
	ulong	crc;
	ulong	oflo;
	ulong	fram;

	ulong	rtry;			/* transmit statistics */
	ulong	lcar;
	ulong	lcol;
	ulong	uflo;
	ulong	txbuff;
.
124,126c
	Dre*	rdr;			/* receive descriptor ring */
	int	rdrx;
.
121a
typedef struct Ctlr {
	Lock;
	int	port;

	int	init;			/* initialisation in progress */
.
119,120c
enum {					/* md2 */
	Rtry		= 0x04000000,	/* failed after repeated retries */
	Lcar		= 0x08000000,	/* loss of carrier */
	Lcol		= 0x10000000,	/* late collision */
	Uflo		= 0x40000000,	/* underflow error */
	TxBuff		= 0x80000000,	/* buffer error */
};
.
97,115c
enum {					/* md1 */
	Enp		= 0x01000000,	/* end of packet */
	Stp		= 0x02000000,	/* start of packet */
	RxBuff		= 0x04000000,	/* buffer error */
	Def		= 0x04000000,	/* deferred */
	Crc		= 0x08000000,	/* CRC error */
	One		= 0x08000000,	/* one retry needed */
	Oflo		= 0x10000000,	/* overflow error */
	More		= 0x10000000,	/* more than one retry needed */
	Fram		= 0x20000000,	/* framing error */
	RxErr		= 0x40000000,	/* Fram|Oflo|Crc|RxBuff */
	TxErr		= 0x40000000,	/* Uflo|Lcol|Lcar|Rtry */
.
90,95c
typedef struct {			/* descriptor ring entry */
	ulong	addr;
	ulong	md1;			/* status|bcnt */
	ulong	md2;			/* rcc|rpc|mcnt */
	Block*	bp;
} Dre;
.
81,82c
	uchar	rlen;			/* upper 4 bits */
	uchar	tlen;			/* upper 4 bits */
.
79c
typedef struct {			/* Initialisation Block */
.
75,76c
enum {					/* CSR15 */
	Prom		= 0x8000,	/* promiscuous mode */
.
71,72c
enum {					/* CSR4 */
	ApadXmt		= 0x0800,	/* auto pad transmit */
.
58,68c
enum {					/* CSR3 */
	Bswp		= 0x0004,	/* byte swap */
	Emba		= 0x0008,	/* enable modified back-off algorithm */
	Dxmt2pd		= 0x0010,	/* disable transmit two part deferral */
	Lappen		= 0x0020,	/* look-ahead packet processing enable */
.
39,55c
enum {					/* CSR0 */
	Init		= 0x0001,	/* begin initialisation */
	Strt		= 0x0002,	/* enable chip */
	Stop		= 0x0004,	/* disable chip */
	Tdmd		= 0x0008,	/* transmit demand */
	Txon		= 0x0010,	/* transmitter on */
	Rxon		= 0x0020,	/* receiver on */
	Iena		= 0x0040,	/* interrupt enable */
	Intr		= 0x0080,	/* interrupt flag */
	Idon		= 0x0100,	/* initialisation done */
	Tint		= 0x0200,	/* transmit interrupt */
	Rint		= 0x0400,	/* receive interrupt */
	Merr		= 0x0800,	/* memory error */
	Miss		= 0x1000,	/* missed frame */
	Cerr		= 0x2000,	/* collision */
	Babl		= 0x4000,	/* transmitter timeout */
	Err		= 0x8000,	/* Babl|Cerr|Miss|Merr */
.
31,36c
enum {					/* DWIO I/O resource map */
	Aprom		= 0x0000,	/* physical address */
	Rdp		= 0x0010,	/* register data port */
	Rap		= 0x0014,	/* register address port */
	Sreset		= 0x0018,	/* software reset */
	Bdp		= 0x001C,	/* bus configuration register data port */
.
28c
	Rbsize		= ETHERMAXTU+4,	/* ring buffer size (+4 for CRC) */
.
23,26c
	Lognrdre	= 6,
	Nrdre		= (1<<Lognrdre),/* receive descriptor ring entries */
	Logntdre	= 4,
	Ntdre		= (1<<Logntdre),/* transmit descriptor ring entries */
.
5,9c
 *	finish this rewrite
.
## diffname pc/ether79c970.c 1997/0417
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/ether79c970.c /n/emeliedump/1997/0417/sys/src/brazil/pc/ether79c970.c
183c
	n = readstr(offset, a, n, p);
	free(p);

	return n;
.
173,181c
	p = malloc(READSTR);
	len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff);
	len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc);
	len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo);
	len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram);
	len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry);
	len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar);
	len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol);
	len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo);
	snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
.
161a
	Ctlr *ctlr;
.
159,160c
	char *p;
.
## diffname pc/ether79c970.c 1997/0723
## diff -e /n/emeliedump/1997/0417/sys/src/brazil/pc/ether79c970.c /n/emeliedump/1997/0723/sys/src/brazil/pc/ether79c970.c
476a
		bpp = &bp->next;
.
## diffname pc/ether79c970.c 1997/1011
## diff -e /n/emeliedump/1997/0723/sys/src/brazil/pc/ether79c970.c /n/emeliedump/1997/1011/sys/src/brazil/pc/ether79c970.c
479c
	if(port == 0)
.
461,463c
	 * Any adapter matches if no port is supplied,
	 * otherwise the ports must match.
.
459a
	if(scandone == 0){
		amd79c970pci();
		scandone = 1;
	}

.
458a
	static int scandone;
.
436,448c
	p = nil;
	while(p = pcimatch(p, 0x1022, 0x2000))
		amd79c970adapter(&adapter, p->mem[0].bar & ~0x01, p->intl, p->tbdf);
.
433,434c
	Pcidev *p;
.
430,431c
static void
amd79c970pci(void)
.
## diffname pc/ether79c970.c 1999/0112
## diff -e /n/emeliedump/1997/1011/sys/src/brazil/pc/ether79c970.c /n/emeliedump/1999/0112/sys/src/brazil/pc/ether79c970.c
329,330c
	if(csr0 & Merr)
		ctlr->merr++;
	if(csr0 & Miss)
		ctlr->miss++;
	if(csr0 & Babl)
		ctlr->babl++;
	//if(csr0 & (Babl|Miss|Merr))
	//	print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
.
182c
	len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
	len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr);
	len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss);
	snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl);
.
134a

	ulong	merr;			/* bobf is such a whiner */
	ulong	miss;
	ulong	babl;
.
## diffname pc/ether79c970.c 1999/0314
## diff -e /n/emeliedump/1999/0112/sys/src/brazil/pc/ether79c970.c /n/emeliedump/1999/0314/sys/src/brazil/pc/ether79c970.c
450a
		pcisetbme(p);
	}
.
449c
	while(p = pcimatch(p, 0x1022, 0x2000)){
.
## diffname pc/ether79c970.c 1999/0714
## diff -e /n/emeliedump/1999/0314/sys/src/brazil/pc/ether79c970.c /n/emeliedump/1999/0714/sys/src/brazil/pc/ether79c970.c
450c
		port = p->mem[0].bar & ~0x01;
		if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
			print("amd79c970: port %d in use\n", port);
			continue;
		}
		amd79c970adapter(&adapter, port, p->intl, p->tbdf);
.
446a
	int port;
.
## diffname pc/ether79c970.c 2000/0619
## diff -e /n/emeliedump/1999/0714/sys/src/brazil/pc/ether79c970.c /n/emeliedump/2000/0619/sys/src/9/pc/ether79c970.c
453c
			print("amd79c970: port 0x%uX in use\n", port);
.
## diffname pc/ether79c970.c 2001/0504
## diff -e /n/emeliedump/2000/0619/sys/src/9/pc/ether79c970.c /n/emeliedump/2001/0504/sys/src/9/pc/ether79c970.c
433c
	bp = iallocb(sizeof(Adapter));
	if(bp == nil)
		return;
.
## diffname pc/ether79c970.c 2001/0527
## diff -e /n/emeliedump/2001/0504/sys/src/9/pc/ether79c970.c /n/emeliedump/2001/0527/sys/src/9/pc/ether79c970.c
458c
		if(amd79c970adapter(&adapter, port, p->intl, p->tbdf)){
			iofree(port);
			continue;
		}
.
442a

	return 0;
.
435c
		return -1;
.
433c
	bp = allocb(sizeof(Adapter));
.
427c
static int
.
211a
			if(dre->bp == nil)
				panic("can't allocate ethernet receive ring\n");
.
## diffname pc/ether79c970.c 2001/0712
## diff -e /n/emeliedump/2001/0527/sys/src/9/pc/ether79c970.c /n/emeliedump/2001/0712/sys/src/9/pc/ether79c970.c
595d
513d
509,510c
	ether->ctlr = ctlr;
	ether->port = ctlr->port;
	ether->irq = ctlr->pcidev->intl;
	ether->tbdf = ctlr->pcidev->tbdf;
	pcisetbme(ctlr->pcidev);
.
503c
	if(ctlr == nil)
.
501d
489,498c
	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
		if(ctlr->active)
			continue;
		if(ether->port == 0 || ether->port == ctlr->port){
			ctlr->active = 1;
.
482,483d
480c
	if(ctlrhead == nil)
.
478d
473,475c
	int x;
.
462,466c
		ctlr = malloc(sizeof(Ctlr));
		ctlr->port = p->mem[0].bar & ~0x01;
		ctlr->pcidev = p;

		if(ctlrhead != nil)
			ctlrtail->next = ctlr;
		else
			ctlrhead = ctlr;
		ctlrtail = ctlr;
.
453a
	Ctlr *ctlr;
	Pcidev *p;
.
452d
422,448d
140a
static Ctlr* ctlrhead;
static Ctlr* ctlrtail;

.
112a
	Pcidev*	pcidev;
	Ctlr*	next;
	int	active;
.
109a
typedef struct Ctlr Ctlr;
.
## diffname pc/ether79c970.c 2001/0822
## diff -e /n/emeliedump/2001/0712/sys/src/9/pc/ether79c970.c /n/emeliedump/2001/0822/sys/src/9/pc/ether79c970.c
564c

	/*
	 * We used to set CSR0 to Idon|Stop here, and then
	 * in attach change it to Iena|Strt.  Apparently the simulated
	 * 79C970 in VMware never enables after a write of Idon|Stop,
	 * so we enable the device here now.
	 */
	ctlr->iow(ctlr, Rdp, Iena|Strt);
.
562c
	while(!(ctlr->ior(ctlr, Rdp) & Idon))
.
553,560c
	ctlr->iow(ctlr, Rap, 1);
	ctlr->iow(ctlr, Rdp, x & 0xFFFF);
	ctlr->iow(ctlr, Rap, 2);
	ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
	ctlr->iow(ctlr, Rap, 3);
	ctlr->iow(ctlr, Rdp, Idon);
	ctlr->iow(ctlr, Rap, 0);
	ctlr->iow(ctlr, Rdp, Init);
.
528,530c
		if(ctlr->ior == io16r)
			x = ctlr->ior(ctlr, Aprom+2);
		else
			x >>= 16;
		ether->ea[2] = x;
		ether->ea[3] = x>>8;
		x = ctlr->ior(ctlr, Aprom+4);
.
525c
		x = ctlr->ior(ctlr, Aprom);
.
519,521c
	 * Check if the adapter's station address is to be overridden.
	 * If not, read it from the I/O-space and set in ether->ea prior to
	 * loading the station address in the initialisation block.
.
516,517d
512,514c
	ctlr->iow(ctlr, Rap, 0);
.
509,510c
	ctlr->iow(ctlr, Rap, 4);
	x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
	ctlr->iow(ctlr, Rdp, ApadXmt|x);
.
505,507c
	ctlr->iow(ctlr, Rap, 20);
	ctlr->iow(ctlr, Bdp, 0x0002);
.
492,501d
490a
	io32r(ctlr, Sreset);
	io16r(ctlr, Sreset);

	if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
		ctlr->ior = io16r;
		ctlr->iow = io16w;
	}else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
		ctlr->ior = io32r;
		ctlr->iow = io32w;
	}else{
		print("#l%d: card doesn't talk right\n", ether->ctlrno);
		iunlock(ctlr);
		return -1;
	}

	ctlr->iow(ctlr, Rap, 88);
	x = ctlr->ior(ctlr, Rdp);
	ctlr->iow(ctlr, Rap, 89);
	x |= ctlr->ior(ctlr, Rdp)<<16;

	switch(x&0xFFFFFFF){
	case 0x2420003:	/* PCnet/PCI 79C970 */
	case 0x2621003:	/* PCnet/PCI II 79C970A */
		break;
	default:
		print("#l%d: unknown PCnet card version %.7ux\n",
			ether->ctlrno, x&0xFFFFFFF);
		iunlock(ctlr);
		return -1;
	}

.
343,344c
	csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
	ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
.
310c
		ctlr->iow(ctlr, Rdp, Iena|Tdmd);
.
302c
		 * here as ApadXmt is set in CSR4.
.
276c
	ctlr->iow(ctlr, Rdp, Iena|Strt);
.
269,270c
	ctlr->iow(ctlr, Rdp, x);
	ctlr->iow(ctlr, Rap, 0);
.
265,266c
	ctlr->iow(ctlr, Rap, 15);
	x = ctlr->ior(ctlr, Rdp) & ~Prom;
.
263c
	ctlr->iow(ctlr, Rdp, Stop);
.
166a
static void
attach(Ether*)
{
}

.
158,164c
static void
io32w(Ctlr *c, int r, int v)
{
	outl(c->port+r, v);
.
156c
static int
io32r(Ctlr *c, int r)
{
	return inl(c->port+r);
}
.
154c
	if(r >= Rdp)
		r = (r-Rdp)/2+Rdp;
	outs(c->port+r, v);
}
.
152c
io16w(Ctlr *c, int r, int v)
.
148,149c
/*
 * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above.
 * To get to 16-bit offsets, scale down with 0x10 staying the same.
 */
static int
io16r(Ctlr *c, int r)
{
	if(r >= Rdp)
		r = (r-Rdp)/2+Rdp;
	return ins(c->port+r);
}
.
144a
	int	(*ior)(Ctlr*, int);
	void	(*iow)(Ctlr*, int, int);
};

.
143d
111c
struct Ctlr {
.
2c
 * AMD79C970
.
## diffname pc/ether79c970.c 2001/1015
## diff -e /n/emeliedump/2001/0822/sys/src/9/pc/ether79c970.c /n/emeliedump/2001/1015/sys/src/9/pc/ether79c970.c
503a
	if(ioalloc(ctlr->port, 0x20, 0, "ether79c970") < 0)
		return -1;

.
## diffname pc/ether79c970.c 2002/0404
## diff -e /n/emeliedump/2001/1015/sys/src/9/pc/ether79c970.c /n/emeliedump/2002/0404/sys/src/9/pc/ether79c970.c
540a
			ether->ctlrno, x&0xFFFFFFF);
iprint("#l%d: unknown PCnet card version %.7ux\n",
.
525a
iprint("#l%d: card doesn't talk right\n", ether->ctlrno);
.
504,506d

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.