#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-
-#include "etherif.h"
+#include "../port/etherif.h"
enum {
Lognrdre = 6,
ulong addr;
ulong md1; /* status|bcnt */
ulong md2; /* rcc|rpc|mcnt */
- Block* bp;
+ ulong aux;
};
+
enum { /* md1 */
Enp = 0x01000000, /* end of packet */
Stp = 0x02000000, /* start of packet */
int init; /* initialisation in progress */
Iblock iblock;
+ Block** rb;
Dre* rdr; /* receive descriptor ring */
int rdrx;
+ Block** tb;
Dre* tdr; /* transmit descriptor ring */
int tdrh; /* host index into tdr */
int tdri; /* interface index into tdr */
if(n == 0)
return 0;
- p = malloc(READSTR);
+ p = smalloc(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);
static void
ringinit(Ctlr* ctlr)
{
+ Block *bp;
Dre *dre;
+ int i;
/*
* Initialise the receive and transmit buffer rings.
*
* This routine is protected by ctlr->init.
*/
+ if(ctlr->rb == nil)
+ ctlr->rb = malloc(Nrdre*sizeof(Block*));
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);
- if(dre->bp == nil)
- panic("can't allocate ethernet receive ring\n");
- dre->addr = PADDR(dre->bp->rp);
+ for(i=0; i<Nrdre; i++){
+ bp = iallocb(Rbsize);
+ if(bp == nil)
+ panic("can't allocate ethernet receive ring");
+ ctlr->rb[i] = bp;
+ dre = &ctlr->rdr[i];
+ dre->addr = PADDR(bp->rp);
dre->md2 = 0;
dre->md1 = Own|(-Rbsize & 0xFFFF);
+ dre->aux = 0;
}
}
ctlr->rdrx = 0;
+ if(ctlr->tb == nil)
+ ctlr->tb = malloc(Ntdre*sizeof(Block*));
if(ctlr->tdr == 0)
ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
ctlr->iow(ctlr, Rap, 15);
x = ctlr->ior(ctlr, Rdp) & ~Prom;
- if(on)
+ if(on || ether->nmaddr > 0)
x |= Prom;
ctlr->iow(ctlr, Rdp, x);
ctlr->iow(ctlr, Rap, 0);
static void
multicast(void* arg, uchar*, int)
{
- promiscuous(arg, 1);
+ Ether *ether = arg;
+ promiscuous(arg, ether->prom);
}
static void
Ctlr *ctlr;
Block *bp;
Dre *dre;
+ int i;
ctlr = ether->ctlr;
* There's no need to pad to ETHERMINTU
* here as ApadXmt is set in CSR4.
*/
- dre = &ctlr->tdr[ctlr->tdrh];
- dre->bp = bp;
+ i = ctlr->tdrh;
+ if(ctlr->tb[i] != nil)
+ break;
+ dre = &ctlr->tdr[i];
+ ctlr->tb[i] = bp;
dre->addr = PADDR(bp->rp);
dre->md2 = 0;
dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
{
Ctlr *ctlr;
Ether *ether;
- int csr0, len;
+ int csr0, len, i;
Dre *dre;
- Block *bp;
+ Block *bp, *bb;
ether = arg;
ctlr = ether->ctlr;
* until a descriptor is encountered still owned by the chip.
*/
if(csr0 & Rint){
- dre = &ctlr->rdr[ctlr->rdrx];
+ ilock(ctlr);
+ i = ctlr->rdrx;
+ dre = &ctlr->rdr[i];
while(!(dre->md1 & Own)){
if(dre->md1 & RxErr){
if(dre->md1 & RxBuff)
ctlr->fram++;
}
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;
+ bb = ctlr->rb[i];
+ ctlr->rb[i] = bp;
+ if(bb != nil){
+ len = (dre->md2 & 0x0FFF)-4;
+ bb->wp = bb->rp+len;
+ etheriq(ether, bb);
+ }
dre->addr = PADDR(bp->rp);
}
dre->md2 = 0;
dre->md1 = Own|(-Rbsize & 0xFFFF);
- ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
- dre = &ctlr->rdr[ctlr->rdrx];
+ i = ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
+ dre = &ctlr->rdr[i];
}
+ iunlock(ctlr);
}
/*
* Transmitter interrupt: wakeup anyone waiting for a free descriptor.
*/
if(csr0 & Tint){
- lock(ctlr);
+ ilock(ctlr);
while(ctlr->ntq){
- dre = &ctlr->tdr[ctlr->tdri];
+ i = ctlr->tdri;
+ dre = &ctlr->tdr[i];
if(dre->md1 & Own)
break;
ctlr->txbuff++;
ether->oerrs++;
}
-
- freeb(dre->bp);
+ bp = ctlr->tb[i];
+ if(bp != nil){
+ ctlr->tb[i] = nil;
+ freeb(bp);
+ }
ctlr->ntq--;
ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
}
txstart(ether);
- unlock(ctlr);
+ iunlock(ctlr);
}
goto intrloop;
}
continue;
}
ctlr = malloc(sizeof(Ctlr));
+ if(ctlr == nil){
+ print("amd79c970: can't allocate memory\n");
+ iofree(port);
+ continue;
+ }
ctlr->port = p->mem[0].bar & ~0x01;
ctlr->pcidev = p;
ether->port = ctlr->port;
ether->irq = ctlr->pcidev->intl;
ether->tbdf = ctlr->pcidev->tbdf;
- pcisetbme(ctlr->pcidev);
ilock(ctlr);
ctlr->init = 1;
+ pcienable(ctlr->pcidev);
+ pcisetbme(ctlr->pcidev);
io32r(ctlr, Sreset);
io16r(ctlr, Sreset);
switch(x&0xFFFFFFF){
case 0x2420003: /* PCnet/PCI 79C970 */
case 0x2621003: /* PCnet/PCI II 79C970A */
+ ether->mbps = 10;
+ break;
case 0x2625003: /* PCnet-FAST III 79C973 */
+ ether->mbps = 100;
break;
default:
print("#l%d: unknown PCnet card version 0x%.7ux\n",
ether->ea[5] = x>>8;
}
+ /* VMware */
+ x = ether->ea[0]<<16 | ether->ea[1]<<8 | ether->ea[2];
+ switch(x){
+ case 0x0569:
+ case 0x0C29:
+ case 0x5056:
+ ether->mbps = 1000;
+ }
+
/*
* Start to fill in the initialisation block
* (must be DWORD aligned).
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->arg = ether;
ether->multicast = multicast;
// ether->shutdown = shutdown;
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
+
return 0;
}