## 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(ðer->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(ðer->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
|