## diffname pc/ether82557.c 1996/0418
## diff -e /dev/null /n/fornaxdump/1996/0418/sys/src/brazil/pc/ether82557.c
0a
/*
* Intel 82557 Fast Ethernet PCI Bus LAN Controller
* as found on the Intel EtherExpress PRO/100B. This chip is full
* of smarts, unfortunately none of them are in the right place.
* To do:
* the PCI scanning code could be made common to other adapters;
* PCI code needs rewritten to handle byte, word, dword accesses
* and using the devno as a bus+dev+function triplet;
* stats.
*/
#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 {
Nrfd = 64, /* receive frame area */
NullPointer = 0xFFFFFFFF, /* 82557 NULL pointer */
};
enum { /* CSR */
Status = 0x00, /* byte or word (word includes Ack) */
Ack = 0x01, /* byte */
Command = 0x02, /* byte or word (word includes Interrupt) */
Interrupt = 0x03, /* byte */
Pointer = 0x04, /* dword */
Port = 0x08, /* dword */
Fcr = 0x0C, /* Flash control register */
Ecr = 0x0E, /* EEPROM control register */
Mcr = 0x10, /* MDI control register */
};
enum { /* Status */
RUidle = 0x0000,
RUsuspended = 0x0004,
RUnoresources = 0x0008,
RUready = 0x0010,
RUrbd = 0x0020, /* bit */
RUstatus = 0x003F, /* mask */
CUidle = 0x0000,
CUsuspended = 0x0040,
CUactive = 0x0080,
CUstatus = 0x00C0, /* mask */
StatSWI = 0x0400, /* SoftWare generated Interrupt */
StatMDI = 0x0800, /* MDI r/w done */
StatRNR = 0x1000, /* Receive unit Not Ready */
StatCNA = 0x2000, /* Command unit Not Active (Active->Idle) */
StatFR = 0x4000, /* Finished Receiving */
StatCX = 0x8000, /* Command eXecuted */
StatTNO = 0x8000, /* Transmit NOT OK */
};
enum { /* Command (byte) */
CUnop = 0x00,
CUstart = 0x10,
CUresume = 0x20,
LoadDCA = 0x40, /* Load Dump Counters Address */
DumpSC = 0x50, /* Dump Statistical Counters */
LoadCUB = 0x60, /* Load CU Base */
ResetSA = 0x70, /* Dump and Reset Statistical Counters */
RUstart = 0x01,
RUresume = 0x02,
RUabort = 0x04,
LoadHDS = 0x05, /* Load Header Data Size */
LoadRUB = 0x06, /* Load RU Base */
RBDresume = 0x07, /* Resume frame reception */
};
enum { /* Interrupt (byte) */
InterruptM = 0x01, /* interrupt Mask */
InterruptSI = 0x02, /* Software generated Interrupt */
};
enum { /* Ecr */
EEsk = 0x01, /* serial clock */
EEcs = 0x02, /* chip select */
EEdi = 0x04, /* serial data in */
EEdo = 0x08, /* serial data out */
EEstart = 0x04, /* start bit */
EEread = 0x02, /* read opcode */
EEaddrsz = 6, /* bits of address */
};
enum { /* Mcr */
MDIread = 0x08000000, /* read opcode */
MDIwrite = 0x04000000, /* write opcode */
MDIready = 0x10000000, /* ready bit */
MDIie = 0x20000000, /* interrupt enable */
};
typedef struct Rfd {
int field;
ulong link;
ulong rbd;
ushort count;
ushort size;
Etherpkt;
Block* bp;
} Rfd;
enum { /* field */
RfdCollision = 0x00000001,
RfdIA = 0x00000002, /* IA match */
RfdRxerr = 0x00000010, /* PHY character error */
RfdType = 0x00000020, /* Type frame */
RfdRunt = 0x00000080,
RfdOverrun = 0x00000100,
RfdBuffer = 0x00000200,
RfdAlignment = 0x00000400,
RfdCRC = 0x00000800,
RfdOK = 0x00002000, /* frame received OK */
RfdC = 0x00008000, /* reception Complete */
RfdSF = 0x00080000, /* Simplified or Flexible (1) Rfd */
RfdH = 0x00100000, /* Header RFD */
RfdI = 0x20000000, /* Interrupt after completion */
RfdS = 0x40000000, /* Suspend after completion */
RfdEL = 0x80000000, /* End of List */
};
enum { /* count */
RfdF = 0x00004000,
RfdEOF = 0x00008000,
};
typedef struct Cb {
int command;
ulong link;
uchar data[24]; /* CbIAS + CbConfigure */
} Cb;
typedef struct TxCB {
int command;
ulong link;
ulong tbd;
ushort count;
uchar threshold;
uchar number;
} TxCB;
enum { /* action command */
CbOK = 0x00002000, /* DMA completed OK */
CbC = 0x00008000, /* execution Complete */
CbNOP = 0x00000000,
CbIAS = 0x00010000, /* Indvidual Address Setup */
CbConfigure = 0x00020000,
CbMAS = 0x00030000, /* Multicast Address Setup */
CbTransmit = 0x00040000,
CbDump = 0x00060000,
CbDiagnose = 0x00070000,
CbCommand = 0x00070000, /* mask */
CbSF = 0x00080000, /* CbTransmit */
CbI = 0x20000000, /* Interrupt after completion */
CbS = 0x40000000, /* Suspend after completion */
CbEL = 0x80000000, /* End of List */
};
enum { /* CbTransmit count */
CbEOF = 0x00008000,
};
typedef struct Ctlr {
int port;
int ctlrno;
char* type;
uchar configdata[24];
Lock rlock;
Block* rfd[Nrfd];
int rfdl;
int rfdx;
Lock cbqlock;
Block* cbqhead;
Block* cbqtail;
int cbqbusy;
} Ctlr;
static uchar configdata[24] = {
0x16, /* byte count */
0x44, /* Rx/Tx FIFO limit */
0x00, /* adaptive IFS */
0x00,
0x04, /* Rx DMA maximum byte count */
0x84, /* Tx DMA maximum byte count */
0x33, /* late SCB, CNA interrupts */
0x01, /* discard short Rx frames */
0x00, /* 503/MII */
0x00,
0x2E, /* normal operation, NSAI */
0x00, /* linear priority */
0x60, /* inter-frame spacing */
0x00,
0xF2,
0x48, /* promiscuous mode off */
0x00,
0x40,
0xF2, /* transmit padding enable */
0x80, /* full duplex pin enable */
0x3F, /* no Multi IA */
0x05, /* no Multi Cast ALL */
};
#define csr8r(c, r) (inb((c)->port+(r)))
#define csr16r(c, r) (ins((c)->port+(r)))
#define csr32r(c, r) (inl((c)->port+(r)))
#define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
#define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
#define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l)))
static void
custart(Ctlr* ctlr)
{
if(ctlr->cbqhead == 0){
ctlr->cbqbusy = 0;
return;
}
ctlr->cbqbusy = 1;
csr32w(ctlr, Pointer, PADDR(ctlr->cbqhead->rp));
while(csr8r(ctlr, Command))
;
csr8w(ctlr, Command, CUstart);
}
static void
action(Ctlr* ctlr, Block* bp)
{
Cb *cb;
ilock(&ctlr->cbqlock);
cb = (Cb*)bp->rp;
cb->command |= CbEL;
if(ctlr->cbqhead){
ctlr->cbqtail->next = bp;
cb = (Cb*)ctlr->cbqtail->rp;
cb->link = PADDR(bp->rp);
cb->command &= ~CbEL;
}
else
ctlr->cbqhead = bp;
ctlr->cbqtail = bp;
if(ctlr->cbqbusy == 0)
custart(ctlr);
iunlock(&ctlr->cbqlock);
}
static void
attach(Ether* ether)
{
int status;
Ctlr *ctlr;
ctlr = ether->ctlr;
ilock(&ctlr->rlock);
status = csr16r(ctlr, Status);
if((status & RUstatus) == RUidle){
csr32w(ctlr, Pointer, PADDR(ctlr->rfd[ctlr->rfdx]->rp));
while(csr8r(ctlr, Command))
;
csr8w(ctlr, Command, RUstart);
}
iunlock(&ctlr->rlock);
}
static void
configure(void* arg, int promiscuous)
{
Ctlr *ctlr;
Block *bp;
Cb *cb;
ctlr = ((Ether*)arg)->ctlr;
bp = allocb(sizeof(Cb));
cb = (Cb*)bp->rp;
bp->wp += sizeof(Cb);
cb->command = CbConfigure;
cb->link = NullPointer;
memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata));
if(promiscuous)
cb->data[15] |= 0x01;
action(ctlr, bp);
}
static long
write(Ether* ether, void* buf, long n)
{
Block *bp;
TxCB *txcb;
bp = allocb(n+sizeof(TxCB));
txcb = (TxCB*)bp->wp;
bp->wp += sizeof(TxCB);
txcb->command = CbTransmit;
txcb->link = NullPointer;
txcb->tbd = NullPointer;
txcb->count = CbEOF|n;
txcb->threshold = 2;
txcb->number = 0;
memmove(bp->wp, buf, n);
memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen);
bp->wp += n;
action(ether->ctlr, bp);
ether->outpackets++;
return n;
}
static void
interrupt(Ureg*, void* arg)
{
Rfd *rfd;
Block *bp;
Ctlr *ctlr;
Ether *ether;
int status;
ether = arg;
ctlr = ether->ctlr;
for(;;){
status = csr16r(ctlr, Status);
csr8w(ctlr, Ack, (status>>8) & 0xFF);
if((status & (StatCX|StatFR|StatCNA|StatRNR)) == 0)
return;
if(status & StatFR){
bp = ctlr->rfd[ctlr->rfdx];
rfd = (Rfd*)bp->rp;
while(rfd->field & RfdC){
etherrloop(ether, rfd, rfd->count & 0x3FFF);
ether->inpackets++;
/*
* Reinitialise the frame for reception and bump
* the receive frame processing index;
* bump the sentinel index, mark the new sentinel
* and clear the old sentinel suspend bit;
* set bp and rfd for the next receive frame to
* process.
*/
rfd->field = 0;
rfd->count = 0;
ctlr->rfdx = NEXT(ctlr->rfdx, Nrfd);
rfd = (Rfd*)ctlr->rfd[ctlr->rfdl]->rp;
ctlr->rfdl = NEXT(ctlr->rfdl, Nrfd);
((Rfd*)ctlr->rfd[ctlr->rfdl]->rp)->field |= RfdS;
rfd->field &= ~RfdS;
bp = ctlr->rfd[ctlr->rfdx];
rfd = (Rfd*)bp->rp;
}
status &= ~StatFR;
}
if(status & StatRNR){
while(csr8r(ctlr, Command))
;
csr8w(ctlr, Command, RUresume);
status &= ~StatRNR;
}
if(status & StatCNA){
lock(&ctlr->cbqlock);
while(bp = ctlr->cbqhead){
if((((Cb*)bp->rp)->command & CbC) == 0)
break;
ctlr->cbqhead = bp->next;
freeb(bp);
}
custart(ctlr);
unlock(&ctlr->cbqlock);
status &= ~StatCNA;
}
if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))
panic("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status);
}
}
static void
ctlrinit(Ctlr* ctlr)
{
int i;
Block *bp;
Rfd *rfd;
ulong link;
link = NullPointer;
for(i = Nrfd-1; i >= 0; i--){
if(ctlr->rfd[i] == 0){
bp = allocb(sizeof(Rfd));
ctlr->rfd[i] = bp;
}
else
bp = ctlr->rfd[i];
rfd = (Rfd*)bp->rp;
rfd->field = 0;
rfd->link = link;
link = PADDR(rfd);
rfd->rbd = NullPointer;
rfd->count = 0;
rfd->size = sizeof(Etherpkt);
rfd->bp = bp;
}
((Rfd*)ctlr->rfd[Nrfd-1]->rp)->link = PADDR(ctlr->rfd[0]->rp);
ctlr->rfdl = 0;
((Rfd*)ctlr->rfd[0]->rp)->field |= RfdS;
ctlr->rfdx = 2;
memmove(ctlr->configdata, configdata, sizeof(configdata));
}
static int
dp83840r(Ctlr* ctlr, int phyadd, int regadd)
{
int mcr, timo;
/*
* DP83840
* 10/100Mb/s Ethernet Physical Layer.
*/
csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16));
mcr = 0;
for(timo = 10; timo; timo--){
mcr = csr32r(ctlr, Mcr);
if(mcr & MDIready)
break;
delay(1);
}
if(mcr & MDIready)
return mcr & 0xFFFF;
return -1;
}
static int
hy93c46r(Ctlr* ctlr, int r)
{
int i, op, data;
/*
* Hyundai HY93C46 or equivalent serial EEPROM.
* This sequence for reading a 16-bit register 'r'
* in the EEPROM is taken straight from Section
* 2.3.4.2 of the Intel 82557 User's Guide.
*/
csr16w(ctlr, Ecr, EEcs);
op = EEstart|EEread;
for(i = 2; i >= 0; i--){
data = (((op>>i) & 0x01)<<2)|EEcs;
csr16w(ctlr, Ecr, data);
csr16w(ctlr, Ecr, data|EEsk);
delay(1);
csr16w(ctlr, Ecr, data);
delay(1);
}
for(i = EEaddrsz-1; i >= 0; i--){
data = (((r>>i) & 0x01)<<2)|EEcs;
csr16w(ctlr, Ecr, data);
csr16w(ctlr, Ecr, data|EEsk);
delay(1);
csr16w(ctlr, Ecr, data);
delay(1);
if((csr16r(ctlr, Ecr) & EEdo) == 0)
break;
}
data = 0;
for(i = 15; i >= 0; i--){
csr16w(ctlr, Ecr, EEcs|EEsk);
delay(1);
if(csr16r(ctlr, Ecr) & EEdo)
data |= (1<<i);
csr16w(ctlr, Ecr, EEcs);
delay(1);
}
csr16w(ctlr, Ecr, 0);
return data;
}
typedef struct Adapter Adapter;
struct Adapter {
Adapter* next;
int port;
int irq;
int pcidevno;
};
static Adapter *adapter;
static int
i82557(Ether* ether, int* pcidevno)
{
PCIcfg pcicfg;
static int devno = 0;
int i, irq, port;
Adapter *ap;
for(;;){
pcicfg.vid = 0x8086;
pcicfg.did = 0x1229;
if((devno = pcimatch(0, devno, &pcicfg)) == -1)
break;
port = 0;
irq = 0;
for(i = 0; i < 6; i++){
if((pcicfg.baseaddr[i] & 0x03) != 0x01)
continue;
port = pcicfg.baseaddr[i] & ~0x01;
irq = pcicfg.irq;
if(ether->port == 0 || ether->port == port){
ether->irq = irq;
*pcidevno = devno-1;
return port;
}
}
if(port == 0)
continue;
ap = malloc(sizeof(Adapter));
ap->port = port;
ap->irq = irq;
ap->pcidevno = devno-1;
ap->next = adapter;
adapter = ap;
}
return 0;
}
static int
reset(Ether* ether)
{
int i, pcidevno, port, x;
Adapter *ap, **app;
uchar ea[Eaddrlen];
Ctlr *ctlr;
Block *bp;
Cb *cb;
/*
* Any adapter matches if no ether->port is supplied, otherwise the
* ports must match. First see if an adapter that fits the bill has
* already been found. If not, scan for another.
*/
port = 0;
pcidevno = -1;
for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){
if(ether->port == 0 || ether->port == ap->port){
ether->irq = ap->irq;
pcidevno = ap->pcidevno;
*app = ap->next;
free(ap);
break;
}
}
if(port == 0 && (port = i82557(ether, &pcidevno)) == 0)
return -1;
/*
* Allocate a controller structure and start to initialise it.
* Perform a software reset after which need to ensure busmastering
* is still enabled. The EtherExpress PRO/100B appears to leave
* the PCI configuration alone (see the 'To do' list above) so punt
* for now.
* Load the RUB and CUB registers for linear addressing (0).
*/
ether->ctlr = malloc(sizeof(Ctlr));
ctlr = ether->ctlr;
ctlr->ctlrno = ether->ctlrno;
ctlr->type = ether->type;
ctlr->port = port;
csr32w(ctlr, Port, 0);
delay(1);
pcicfgr(0, pcidevno, 0, 0x04, &x, 4);
if((x & 0x05) != 0x05)
print("PCI command = %uX\n", x);
csr32w(ctlr, Pointer, 0);
csr8w(ctlr, Command, LoadRUB);
while(csr8r(ctlr, Command))
;
csr8w(ctlr, Command, LoadCUB);
while(csr8r(ctlr, Command))
;
/*
* Initialise the action and receive frame areas.
*/
ctlrinit(ctlr);
/*
* Possibly need to configure the physical-layer chip here, but the
* EtherExpress PRO/100B appears to bring it up with a sensible default
* configuration. However, should check for the existence of the PHY
* and, if found, check whether to use 82503 (serial) or MII (nibble)
* mode. Verify the PHY is a National Semiconductor DP83840 by looking
* at the Organizationally Unique Identifier (OUI) in registers 2 and 3
* which should be 0x80017.
*/
for(i = 1; i < 32; i++){
if((x = dp83840r(ctlr, i, 2)) == 0xFFFF)
continue;
x <<= 6;
x |= dp83840r(ctlr, i, 3)>>10;
if(x != 0x80017)
continue;
x = dp83840r(ctlr, i, 0x1B);
if((x & 0x0200) == 0){
ctlr->configdata[8] = 1;
ctlr->configdata[15] |= 0x80;
}
break;
}
/*
* Load the chip configuration
*/
configure(ether, 0);
/*
* Check if the adapter's station address is to be overridden.
* If not, read it from the EEPROM and set in ether->ea prior to loading
* the station address with the Individual Address Setup command.
*/
memset(ea, 0, Eaddrlen);
if(memcmp(ea, ether->ea, Eaddrlen) == 0){
for(i = 0; i < Eaddrlen/2; i++){
x = hy93c46r(ctlr, i);
ether->ea[2*i] = x & 0xFF;
ether->ea[2*i+1] = (x>>8) & 0xFF;
}
}
bp = allocb(sizeof(Cb));
cb = (Cb*)bp->rp;
bp->wp += sizeof(Cb);
cb->command = CbIAS;
cb->link = NullPointer;
memmove(cb->data, ether->ea, Eaddrlen);
action(ctlr, bp);
/*
* Linkage to the generic ethernet driver.
*/
ether->port = port;
ether->attach = attach;
ether->write = write;
ether->interrupt = interrupt;
ether->promiscuous = configure;
ether->arg = ether;
return 0;
}
void
ether82557link(void)
{
addethercard("i82557", reset);
}
.
## diffname pc/ether82557.c 1996/0419
## diff -e /n/fornaxdump/1996/0418/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0419/sys/src/brazil/pc/ether82557.c
440,441d
111,112d
## diffname pc/ether82557.c 1996/0423
## diff -e /n/fornaxdump/1996/0419/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0423/sys/src/brazil/pc/ether82557.c
629c
* Initialise the receive frame and configuration areas.
.
626a
csr8w(ctlr, Command, LoadCUB);
.
624c
csr8w(ctlr, Command, LoadRUB);
.
620,621c
csr32w(ctlr, General, 0);
.
281c
csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp));
.
240c
csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp));
.
159c
CbIAS = 0x00010000, /* Individual Address Setup */
.
33c
General = 0x04, /* dword */
.
8a
* tidy/fix locking;
* optionally use memory-mapped registers;
.
## diffname pc/ether82557.c 1996/0601
## diff -e /n/fornaxdump/1996/0423/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0601/sys/src/brazil/pc/ether82557.c
655c
ctlr->configdata[15] &= ~0x80;
ether->mbps = 100;
.
217c
0xC8, /* promiscuous mode off */
.
## diffname pc/ether82557.c 1996/0607
## diff -e /n/fornaxdump/1996/0601/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0607/sys/src/brazil/pc/ether82557.c
697c
ether->promiscuous = promiscuous;
.
695a
ether->ifstat = ifstat;
.
688a
iunlock(&ctlr->rlock);
.
664c
bp = configure(ctlr, 0);
action(ctlr, bp);
.
641,642c
* at the Organizationally Unique Identifier (OUI) in registers 2 and
* 3 which should be 0x80017.
.
629a
while(csr8r(ctlr, Command))
;
csr32w(ctlr, General, PADDR(ctlr->dump));
csr8w(ctlr, Command, LoadDCA);
.
625a
.
624a
csr32w(ctlr, General, 0);
.
618,622d
614a
ilock(&ctlr->rlock);
.
413a
iunlock(&ctlr->rlock);
.
406d
398d
392a
print("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status);
.
363,364c
if(rfd->field & RfdOK){
etherrloop(ether, rfd, rfd->count & 0x3FFF);
ether->inpackets++;
}
else print("%s#%d: rfd->field %uX\n", ctlr->type, ctlr->ctlrno, rfd->field);
.
356,357c
if((status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) == 0)
break;
.
351a
ilock(&ctlr->rlock);
.
333c
ctlr = ether->ctlr;
ilock(&ctlr->rlock);
action(ctlr, bp);
iunlock(&ctlr->rlock);
.
314a
Ctlr *ctlr;
.
312a
ifstat(Ether* ether, void* a, long n, ulong offset)
{
Ctlr *ctlr;
char buf[512];
int len;
ctlr = ether->ctlr;
lock(&ctlr->dlock);
ctlr->dump[16] = 0;
ilock(&ctlr->rlock);
while(csr8r(ctlr, Command))
;
csr8w(ctlr, Command, DumpSC);
iunlock(&ctlr->rlock);
/*
* Wait for completion status, should be 0xA005.
*/
while(ctlr->dump[16] == 0)
;
ether->oerrs = ctlr->dump[1]+ctlr->dump[2]+ctlr->dump[3];
ether->crcs = ctlr->dump[10];
ether->frames = ctlr->dump[11];
ether->buffs = ctlr->dump[12]+ctlr->dump[15];
ether->overflows = ctlr->dump[13];
if(n == 0){
unlock(&ctlr->dlock);
return 0;
}
len = sprint(buf, "transmit good frames: %ld\n", ctlr->dump[0]);
len += sprint(buf+len, "transmit maximum collisions errors: %ld\n", ctlr->dump[1]);
len += sprint(buf+len, "transmit late collisions errors: %ld\n", ctlr->dump[2]);
len += sprint(buf+len, "transmit underrun errors: %ld\n", ctlr->dump[3]);
len += sprint(buf+len, "transmit lost carrier sense: %ld\n", ctlr->dump[4]);
len += sprint(buf+len, "transmit deferred: %ld\n", ctlr->dump[5]);
len += sprint(buf+len, "transmit single collisions: %ld\n", ctlr->dump[6]);
len += sprint(buf+len, "transmit multiple collisions: %ld\n", ctlr->dump[7]);
len += sprint(buf+len, "transmit total collisions: %ld\n", ctlr->dump[8]);
len += sprint(buf+len, "receive good frames: %ld\n", ctlr->dump[9]);
len += sprint(buf+len, "receive CRC errors: %ld\n", ctlr->dump[10]);
len += sprint(buf+len, "receive alignment errors: %ld\n", ctlr->dump[11]);
len += sprint(buf+len, "receive resource errors: %ld\n", ctlr->dump[12]);
len += sprint(buf+len, "receive overrun errors: %ld\n", ctlr->dump[13]);
len += sprint(buf+len, "receive collision detect errors: %ld\n", ctlr->dump[14]);
sprint(buf+len, "receive short frame errors: %ld\n", ctlr->dump[15]);
unlock(&ctlr->dlock);
return readstr(offset, a, n, buf);
}
static long
.
309a
iunlock(&ctlr->rlock);
.
308a
return bp;
}
static void
promiscuous(void* arg, int on)
{
Ctlr *ctlr;
Block *bp;
ctlr = ((Ether*)arg)->ctlr;
bp = configure(ctlr, on);
ilock(&ctlr->rlock);
.
298,299d
294d
291,292c
static Block*
configure(Ctlr* ctlr, int promiscuous)
.
285a
csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp));
.
283d
269,270d
253d
244a
csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp));
.
242d
197a
Lock dlock; /* dump statistical counters */
ulong dump[17];
.
194,195c
Block* cbqhead; /* transmit side */
.
190c
Block* rfd[Nrfd]; /* receive side */
.
188c
Lock rlock; /* registers */
.
144c
uchar data[24]; /* CbIAS + CbConfigure */
.
9,11c
* optionally use memory-mapped registers.
.
## diffname pc/ether82557.c 1996/0608
## diff -e /n/fornaxdump/1996/0607/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0608/sys/src/brazil/pc/ether82557.c
466d
437d
## diffname pc/ether82557.c 1996/0622
## diff -e /n/fornaxdump/1996/0608/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0622/sys/src/brazil/pc/ether82557.c
766c
iunlock(&ctlr->lock);
.
686c
ilock(&ctlr->lock);
.
669c
if(port == 0 && (port = i82557pci(ether, &pcidevno)) == 0)
.
603c
i82557pci(Ether* ether, int* pcidevno)
.
484c
iunlock(&ctlr->lock);
.
421c
ilock(&ctlr->lock);
.
402c
iunlock(&ctlr->lock);
.
400c
ilock(&ctlr->lock);
.
336c
iunlock(&ctlr->lock);
.
332c
ilock(&ctlr->lock);
.
318c
iunlock(&ctlr->lock);
.
316c
ilock(&ctlr->lock);
.
285c
iunlock(&ctlr->lock);
.
277c
ilock(&ctlr->lock);
.
196c
Lock dlock; /* dump statistical counters */
.
186c
Lock lock;
.
## diffname pc/ether82557.c 1996/0625
## diff -e /n/fornaxdump/1996/0622/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0625/sys/src/brazil/pc/ether82557.c
732c
}
else{
x = dp83840r(ctlr, i, 0x1B);
if((x & 0x0200) == 0){
ctlr->configdata[8] = 1;
ctlr->configdata[15] &= ~0x80;
}
.
728,729c
x = dp83840r(ctlr, i, 0x19);
if((x & 0x0040) == 0){
ether->mbps = 100;
.
8a
* auto-negotiation;
.
## diffname pc/ether82557.c 1997/0327
## diff -e /n/fornaxdump/1996/0625/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0327/sys/src/brazil/pc/ether82557.c
781c
ether->transmit = transmit;
.
774d
772c
action(ctlr, cb);
.
765,770c
cb = cballoc(ctlr, CbIAS);
.
760,761c
ether->ea[2*i] = x;
ether->ea[2*i+1] = x>>8;
.
757c
if(!memcmp(ea, ether->ea, Eaddrlen)){
.
748,749c
configure(ctlr, 0);
.
737c
if(!(x & 0x0200)){
.
730c
if(!(x & 0x0040)){
.
706d
704a
iunlock(&ctlr->rlock);
.
687,688c
ilock(&ctlr->rlock);
.
683,684d
670c
if(port == 0 && (port = i82557pci(ether)) == 0)
.
664,666c
ether->tbdf = ap->tbdf;
*bpp = bp->next;
freeb(bp);
.
662a
port = ap->port;
.
660,661c
bpp = &adapter;
for(bp = *bpp; bp; bp = bp->next){
ap = (Adapter*)bp->rp;
.
651d
647,648c
int i, port, x;
Block *bp, **bpp;
Adapter *ap;
.
633,638c
i82557adapter(&adapter, port, irq, p->tbdf);
.
630,631d
617,628c
bp->next = *bpp;
*bpp = bp;
}
static int
i82557pci(Ether* ether)
{
static Pcidev *p;
int irq, port;
while(p = pcimatch(p, 0x8086, 0x1229)){
/*
* bar[0] is the memory-mapped register address (4KB),
* bar[1] is the I/O port register address (32 bytes) and
* bar[2] is for the flash ROM (1MB).
*/
port = p->bar[1] & ~0x01;
irq = p->intl;
if(ether->port == 0 || ether->port == port){
ether->irq = irq;
ether->tbdf = p->tbdf;
return port;
.
611,615c
bp = allocb(sizeof(Adapter));
ap = (Adapter*)bp->rp;
ap->port = port;
ap->irq = irq;
ap->tbdf = tbdf;
.
606,608c
Block *bp;
.
603,604c
static void
i82557adapter(Block** bpp, int port, int irq, int tbdf)
.
594,601c
typedef struct Adapter {
int port;
int irq;
int tbdf;
} Adapter;
static Block* adapter;
.
575c
if(!(csr16r(ctlr, Ecr) & EEdo))
.
515,518d
513c
ctlr->rfdtail->next = ctlr->rfdhead;
rfd = (Rfd*)ctlr->rfdtail->rp;
rfd->link = PADDR(ctlr->rfdhead->rp);
rfd->field |= RfdS;
ctlr->rfdhead = ctlr->rfdhead->next;
.
497,511c
for(i = 0; i < Nrfd; i++){
bp = rfdalloc(link);
if(ctlr->rfdhead == nil)
ctlr->rfdtail = bp;
bp->next = ctlr->rfdhead;
ctlr->rfdhead = bp;
link = PADDR(bp->rp);
.
495a
/*
* Create the Receive Frame Area (RFA) as a ring of allocated
* buffers.
* A sentinel buffer is maintained between the last buffer in
* the ring (marked with RfdS) and the head buffer to defeat the
* hardware prefetch of the next RFD and allow dynamic buffer
* allocation.
*/
.
485d
483c
panic("#l%d: status %uX\n", ether->ctlrno, status);
.
477a
unlock(&ctlr->cbqlock);
.
474,475c
ctlr->cbqhead = cb->next;
if(cb->bp)
freeb(cb->bp);
cbfree(ctlr, cb);
.
471,472c
lock(&ctlr->cbqlock);
while(cb = ctlr->cbqhead){
if(!(cb->command & CbC))
.
465a
unlock(&ctlr->rlock);
.
462a
lock(&ctlr->rlock);
.
456c
/*
* Finally done with the current (possibly replaced)
* head, move on to the next and maintain the sentinel
* between tail and head.
*/
ctlr->rfdhead = bp->next;
bp = ctlr->rfdhead;
.
447,453c
rfd = (Rfd*)ctlr->rfdtail->rp;
ctlr->rfdtail = ctlr->rfdtail->next;
ctlr->rfdtail->next = bp;
((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp);
((Rfd*)ctlr->rfdtail->rp)->field |= RfdS;
.
440,445c
* The ring tail pointer follows the head with with one
* unused buffer in between to defeat hardware prefetch;
* once the tail pointer has been bumped on to the next
* and the new tail has the Suspend bit set, it can be
* removed from the old tail buffer.
* As a replacement for the current head buffer may have
* been allocated above, ensure that the new tail points
* to it (next and link).
.
437a
else{
rfd->field = 0;
rfd->count = 0;
}
.
434,436c
/*
* If it's an OK receive frame and a replacement buffer
* can be allocated then
* adjust the received buffer pointers for the
* actual data received;
* initialise the replacement buffer to point to
* the next in the ring;
* pass the received buffer on for disposal;
* initialise bp to point to the replacement.
* If not, just adjust the necessary fields for reuse.
*/
if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){
bp->rp += sizeof(Rfd)-sizeof(Etherpkt);
bp->wp = bp->rp + (rfd->count & 0x3FFF);
xbp->next = bp->next;
bp->next = 0;
etheriq(ether, bp, 1);
bp = xbp;
.
431c
bp = ctlr->rfdhead;
.
427c
if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)))
.
425a
unlock(&ctlr->rlock);
.
423a
lock(&ctlr->rlock);
.
422d
414c
Cb* cb;
Block *bp, *xbp;
.
407c
action(ctlr, cb);
.
405c
cb = cballoc(ctlr, CbSF|CbTransmit);
cb->bp = bp;
cb->tbd = PADDR(&cb->tba);
cb->count = 0;
cb->threshold = 2;
cb->number = 1;
cb->tba = PADDR(bp->rp);
cb->tbasz = BLEN(bp);
.
401,403d
389,399d
385,387c
bp = qget(ether->oq);
if(bp == nil)
return;
.
383c
Cb *cb;
.
378,379c
static void
transmit(Ether* ether)
.
337c
iunlock(&ctlr->rlock);
.
333c
ilock(&ctlr->rlock);
.
311,319c
configure(((Ether*)arg)->ctlr, on);
.
304,305c
action(ctlr, cb);
.
295,300c
cb = cballoc(ctlr, CbConfigure);
.
292d
289c
static void
.
286c
iunlock(&ctlr->rlock);
.
283c
csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp));
.
278c
ilock(&ctlr->rlock);
.
268a
iunlock(&ctlr->cbqlock);
.
267c
if(!ctlr->cbqbusy)
.
264,265c
ctlr->cbqhead = cb;
ctlr->cbqtail = cb;
.
258,261c
tail = ctlr->cbqtail;
tail->next = cb;
tail->link = PADDR(&cb->command);
tail->command &= ~CbEL;
.
256a
ilock(&ctlr->cbqlock);
.
254d
252c
Cb* tail;
.
250c
action(Ctlr* ctlr, Cb* cb)
.
246a
iunlock(&ctlr->rlock);
.
245c
csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command));
.
242a
ilock(&ctlr->rlock);
.
234a
cbfree(Ctlr* ctlr, Cb* cb)
{
ilock(&ctlr->cbplock);
cb->next = ctlr->cbpool;
ctlr->cbpool = cb;
iunlock(&ctlr->cbplock);
}
static void
.
233a
static Block*
rfdalloc(ulong link)
{
Block *bp;
Rfd *rfd;
if(bp = iallocb(sizeof(Rfd))){
rfd = (Rfd*)bp->rp;
rfd->field = 0;
rfd->link = link;
rfd->rbd = NullPointer;
rfd->count = 0;
rfd->size = sizeof(Etherpkt);
}
return bp;
}
static Cb*
cballoc(Ctlr* ctlr, int command)
{
Cb *cb;
ilock(&ctlr->cbplock);
if(cb = ctlr->cbpool){
ctlr->cbpool = cb->next;
iunlock(&ctlr->cbplock);
cb->next = 0;
cb->bp = 0;
}
else{
iunlock(&ctlr->cbplock);
cb = smalloc(sizeof(Cb));
}
cb->command = command;
cb->link = NullPointer;
return cb;
}
.
221c
0xF3, /* transmit padding enable */
.
206,209c
0x00, /* Rx DMA maximum byte count */
0x80, /* Tx DMA maximum byte count */
0x32, /* !late SCB, CNA interrupts */
0x03, /* discard short Rx frames */
.
203c
0x08, /* Rx/Tx FIFO limit */
.
196a
Lock cbplock; /* pool of free Cb's */
Cb* cbpool;
.
193,194c
Lock cbqlock; /* transmit side */
Cb* cbqhead;
Cb* cbqtail;
.
189,191c
Lock rfdlock; /* receive side */
Block* rfdhead;
Block* rfdtail;
int nrfd;
.
187c
Lock rlock; /* registers */
.
181,184d
168c
CbSF = 0x00080000, /* Flexible-mode CbTransmit */
.
154a
ulong tba;
ushort tbasz;
ushort pad;
};
};
} Cb;
.
149,153c
union {
uchar data[24]; /* CbIAS + CbConfigure */
struct {
ulong tbd;
ushort count;
uchar threshold;
uchar number;
.
146d
141,144c
Cb* next;
Block* bp;
.
139a
typedef struct Cb Cb;
.
111c
uchar data[sizeof(Etherpkt)];
.
7,8d
## diffname pc/ether82557.c 1997/0417
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0417/sys/src/brazil/pc/ether82557.c
420c
p = malloc(READSTR);
len = snprint(p, READSTR, "transmit good frames: %ld\n", dump[0]);
len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %ld\n", dump[1]);
len += snprint(p+len, READSTR-len, "transmit late collisions errors: %ld\n", dump[2]);
len += snprint(p+len, READSTR-len, "transmit underrun errors: %ld\n", dump[3]);
len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %ld\n", dump[4]);
len += snprint(p+len, READSTR-len, "transmit deferred: %ld\n", dump[5]);
len += snprint(p+len, READSTR-len, "transmit single collisions: %ld\n", dump[6]);
len += snprint(p+len, READSTR-len, "transmit multiple collisions: %ld\n", dump[7]);
len += snprint(p+len, READSTR-len, "transmit total collisions: %ld\n", dump[8]);
len += snprint(p+len, READSTR-len, "receive good frames: %ld\n", dump[9]);
len += snprint(p+len, READSTR-len, "receive CRC errors: %ld\n", dump[10]);
len += snprint(p+len, READSTR-len, "receive alignment errors: %ld\n", dump[11]);
len += snprint(p+len, READSTR-len, "receive resource errors: %ld\n", dump[12]);
len += snprint(p+len, READSTR-len, "receive overrun errors: %ld\n", dump[13]);
len += snprint(p+len, READSTR-len, "receive collision detect errors: %ld\n", dump[14]);
snprint(p+len, READSTR-len, "receive short frame errors: %ld\n", dump[15]);
n = readstr(offset, a, n, p);
free(p);
return n;
.
401,417c
memmove(dump, ctlr->dump, sizeof(dump));
.
375a
.
372a
Ctlr *ctlr;
ulong dump[17];
.
370,371c
char *p;
.
## diffname pc/ether82557.c 1997/0628
## diff -e /n/emeliedump/1997/0417/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0628/sys/src/brazil/pc/ether82557.c
7a
* full-duplex;
.
4c
* of smarts, unfortunately they're not all in the right place.
.
## diffname pc/ether82557.c 1997/0723
## diff -e /n/emeliedump/1997/0628/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0723/sys/src/brazil/pc/ether82557.c
804,805c
if(x != 0x80017 && x != 0xAA00)
print("#l%d: unrecognised PHY - OUI 0x%4.4uX\n", ether->ctlrno, x);
.
795,797c
* mode. Verify the PHY is a National Semiconductor DP83840 (OUI 0x80017)
* or an Intel 82555 (OUI 0xAA00) by looking at the Organizationally Unique
* Identifier (OUI) in registers 2 and 3.
.
751c
if(port == 0)
.
749a
bpp = &bp->next;
.
732a
if(scandone == 0){
i82557pci();
scandone = 1;
}
.
731a
static int scandone;
.
719,720d
709,717c
i82557adapter(&adapter, p->bar[1] & ~0x01, p->intl, p->tbdf);
.
702a
p = nil;
.
700,701c
Pcidev *p;
.
697,698c
static void
i82557pci(void)
.
8d
4c
* of smarts, unfortunately none of them are in the right place.
.
## diffname pc/ether82557.c 1997/0806
## diff -e /n/emeliedump/1997/0723/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0806/sys/src/brazil/pc/ether82557.c
830c
if(memcmp(ea, ether->ea, Eaddrlen) == 0){
.
778c
csr8w(ctlr, CommandR, LoadDCA);
.
775c
while(csr8r(ctlr, CommandR))
.
773c
csr8w(ctlr, CommandR, LoadCUB);
.
771c
while(csr8r(ctlr, CommandR))
.
769c
csr8w(ctlr, CommandR, LoadRUB);
.
766c
while(csr8r(ctlr, CommandR))
.
729,731c
* Any adapter matches if no port is supplied,
* otherwise the ports must match.
.
540c
csr8w(ctlr, CommandR, RUresume);
.
538c
while(csr8r(ctlr, CommandR))
.
383c
csr8w(ctlr, CommandR, DumpSC);
.
381c
while(csr8r(ctlr, CommandR))
.
344c
csr8w(ctlr, CommandR, RUstart);
.
341c
while(csr8r(ctlr, CommandR))
.
304c
csr8w(ctlr, CommandR, CUstart);
.
301c
while(csr8r(ctlr, CommandR))
.
30c
CommandR = 0x02, /* byte or word (word includes Interrupt) */
.
7a
* full-duplex;
.
4c
* of smarts, unfortunately they're not all in the right place.
.
## diffname pc/ether82557.c 1997/0807
## diff -e /n/emeliedump/1997/0806/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0807/sys/src/brazil/pc/ether82557.c
408,423c
len = snprint(p, READSTR, "transmit good frames: %lud\n", dump[0]);
len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %lud\n", dump[1]);
len += snprint(p+len, READSTR-len, "transmit late collisions errors: %lud\n", dump[2]);
len += snprint(p+len, READSTR-len, "transmit underrun errors: %lud\n", dump[3]);
len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %lud\n", dump[4]);
len += snprint(p+len, READSTR-len, "transmit deferred: %lud\n", dump[5]);
len += snprint(p+len, READSTR-len, "transmit single collisions: %lud\n", dump[6]);
len += snprint(p+len, READSTR-len, "transmit multiple collisions: %lud\n", dump[7]);
len += snprint(p+len, READSTR-len, "transmit total collisions: %lud\n", dump[8]);
len += snprint(p+len, READSTR-len, "receive good frames: %lud\n", dump[9]);
len += snprint(p+len, READSTR-len, "receive CRC errors: %lud\n", dump[10]);
len += snprint(p+len, READSTR-len, "receive alignment errors: %lud\n", dump[11]);
len += snprint(p+len, READSTR-len, "receive resource errors: %lud\n", dump[12]);
len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]);
len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]);
snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]);
.
## diffname pc/ether82557.c 1997/0823
## diff -e /n/emeliedump/1997/0807/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0823/sys/src/brazil/pc/ether82557.c
838,841c
ilock(&ctlr->cblock);
ctlr->action = CbIAS;
txstart(ether);
iunlock(&ctlr->cblock);
.
822c
if(ether->oq == 0)
ether->oq = qopen(256*1024, 1, 0, 0);
configure(ether, 0);
command(ctlr, CUstart, PADDR(&ctlr->cbr->status));
.
820c
* Load the chip configuration and start it off.
.
783a
ctlr->ncb = Ncb;
.
782c
* Initialise the receive frame, transmit ring and configuration areas.
.
780a
command(ctlr, LoadRUB, 0);
command(ctlr, LoadCUB, 0);
command(ctlr, LoadDCA, PADDR(ctlr->dump));
.
765,778d
752c
* Perform a software reset after which should ensure busmastering
.
721d
599a
ctlr->threshold = 8;
iunlock(&ctlr->cblock);
.
598a
/*
* Create a ring of control blocks for the
* transmit side.
*/
ilock(&ctlr->cblock);
ctlr->cbr = malloc(ctlr->ncb*sizeof(Cb));
for(i = 0; i < ctlr->ncb; i++){
ctlr->cbr[i].status = CbC|CbOK;
ctlr->cbr[i].command = CbS|CbNOP;
ctlr->cbr[i].link = PADDR(&ctlr->cbr[NEXT(i, ctlr->ncb)].status);
ctlr->cbr[i].next = &ctlr->cbr[NEXT(i, ctlr->ncb)];
}
ctlr->cbhead = ctlr->cbr;
ctlr->cbtail = ctlr->cbr;
ctlr->cbq = 0;
.
559a
txstart(ether);
unlock(&ctlr->cblock);
.
557,558c
ctlr->cbtail = cb;
.
555c
cb->bp = nil;
}
if((cb->status & CbU) && ctlr->threshold < 0xE0)
ctlr->threshold++;
ctlr->cbq--;
cb = cb->next;
.
552,553c
if(cb->bp){
.
548,550c
lock(&ctlr->cblock);
cb = ctlr->cbtail;
while(ctlr->cbq){
if(!(cb->status & CbC))
.
538,543c
command(ctlr, RUresume, 0);
.
453c
static void
transmit(Ether* ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
ilock(&ctlr->cblock);
txstart(ether);
iunlock(&ctlr->cblock);
.
444,451c
static void
promiscuous(void* arg, int on)
{
configure(arg, on);
}
.
442a
ilock(&ctlr->cblock);
if(promiscuous){
ctlr->configdata[6] |= 0x80; /* Save Bad Frames */
ctlr->configdata[6] &= ~0x40; /* !Discard Overrun Rx Frames */
ctlr->configdata[7] &= ~0x01; /* !Discard Short Rx Frames */
ctlr->configdata[15] |= 0x01; /* Promiscuous mode */
ctlr->configdata[18] &= ~0x01; /* (!Padding enable?), !stripping enable */
ctlr->configdata[21] |= 0x08; /* Multi Cast ALL */
}
else{
ctlr->configdata[6] &= ~0x80;
ctlr->configdata[7] |= 0x01;
ctlr->configdata[15] &= ~0x01;
ctlr->configdata[18] |= 0x01; /* 0x03? */
ctlr->configdata[21] &= ~0x08;
}
ctlr->action = CbConfigure;
txstart(ether);
iunlock(&ctlr->cblock);
}
.
441a
cb->command = CbS|CbSF|CbTransmit;
cb->tbd = PADDR(&cb->tba);
cb->count = 0;
cb->threshold = ctlr->threshold;
cb->number = 1;
cb->tba = PADDR(bp->rp);
cb->bp = bp;
cb->tbasz = BLEN(bp);
}
else if(ctlr->action == CbConfigure){
cb->command = CbS|CbConfigure;
memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata));
ctlr->action = 0;
}
else if(ctlr->action == CbIAS){
cb->command = CbS|CbIAS;
memmove(cb->data, ether->ea, Eaddrlen);
ctlr->action = 0;
}
else{
print("#l%d: action 0x%uX\n", ether->ctlrno, ctlr->action);
ctlr->action = 0;
break;
}
cb->status = 0;
ctlr->cbhead->command &= ~CbS;
ctlr->cbhead = cb;
ctlr->cbq++;
}
command(ctlr, CUresume, 0);
if(ctlr->cbq > ctlr->cbqmax)
ctlr->cbqmax = ctlr->cbq;
}
static void
configure(Ether* ether, int promiscuous)
{
Ctlr *ctlr;
.
438,440c
ctlr = ether->ctlr;
while(ctlr->cbq < (ctlr->ncb-1)){
cb = ctlr->cbhead->next;
if(ctlr->action == 0){
bp = qget(ether->oq);
if(bp == nil)
break;
.
432c
txstart(Ether* ether)
.
423c
len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]);
snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax);
ctlr->cbqmax = 0;
.
389a
ctlr->dump[16] = 0;
command(ctlr, DumpSC, 0);
.
388c
* Start the command then
* wait for completion status,
* should be 0xA005.
.
379,386d
350,367d
347c
unlock(&ctlr->slock);
.
339,345c
lock(&ctlr->slock);
if(ctlr->state == 0){
command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp));
ctlr->state = 1;
.
335d
284,332d
260,282d
241a
static void
command(Ctlr* ctlr, int c, int v)
{
ilock(&ctlr->rlock);
/*
* Only back-to-back CUresume can be done
* without waiting for any previous command to complete.
* This should be the common case.
*/
if(c == CUresume && ctlr->command == CUresume){
csr8w(ctlr, CommandR, c);
iunlock(&ctlr->rlock);
return;
}
while(csr8r(ctlr, CommandR))
;
switch(c){
case CUstart:
case LoadDCA:
case LoadCUB:
case RUstart:
case LoadHDS:
case LoadRUB:
csr32w(ctlr, General, v);
break;
/*
case CUnop:
case CUresume:
case DumpSC:
case ResetSA:
case RUresume:
case RUabort:
*/
default:
break;
}
csr8w(ctlr, CommandR, c);
ctlr->command = c;
iunlock(&ctlr->rlock);
}
.
201,204d
196,199c
Lock cblock; /* transmit side */
int action;
uchar configdata[24];
int threshold;
int ncb;
Cb* cbr;
Cb* cbhead;
Cb* cbtail;
int cbq;
int cbqmax;
.
191,192c
Block* rfdhead; /* receive side */
.
189a
int command; /* last command issued */
.
187d
185a
Lock slock; /* attach */
int state;
.
182c
CbEOF = 0x8000,
.
176,178c
CbI = 0x2000, /* Interrupt after completion */
CbS = 0x4000, /* Suspend after completion */
CbEL = 0x8000, /* End of List */
.
174c
CbSF = 0x0008, /* Flexible-mode CbTransmit */
.
165,172c
CbNOP = 0x0000,
CbIAS = 0x0001, /* Individual Address Setup */
CbConfigure = 0x0002,
CbMAS = 0x0003, /* Multicast Address Setup */
CbTransmit = 0x0004,
CbDump = 0x0006,
CbDiagnose = 0x0007,
CbCommand = 0x0007, /* mask */
.
162,163c
CbU = 0x1000, /* transmit underrun */
CbOK = 0x2000, /* DMA completed OK */
CbC = 0x8000, /* execution Complete */
.
158a
Block* bp;
Cb* next;
.
141,144c
ushort status;
ushort command;
.
135,136c
RfdF = 0x4000,
RfdEOF = 0x8000,
.
23a
Ncb = 64, /* maximum control blocks queued */
.
7,9c
* auto-negotiation, full-duplex;
* optionally use memory-mapped registers;
* detach for PCI reset problems (also towards loadable drivers).
.
## diffname pc/ether82557.c 1997/1011
## diff -e /n/emeliedump/1997/0823/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/1011/sys/src/brazil/pc/ether82557.c
760c
i82557adapter(&adapter, p->mem[1].bar & ~0x01, p->intl, p->tbdf);
.
263a
*/
.
258c
* Unfortunately there's a chip errata where back-to-back
* CUresumes can be lost, the fix is to always wait.
.
## diffname pc/ether82557.c 1998/0304
## diff -e /n/emeliedump/1997/1011/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0304/sys/src/brazil/pc/ether82557.c
878c
x = ctlr->eeprom[i];
.
860a
else{
ctlr->configdata[8] = 0;
ctlr->configdata[15] |= 0x80;
}
.
859c
ctlr->configdata[8] = 1;
ctlr->configdata[15] &= ~0x80;
.
857a
if(an & 0x0140)
x |= 0x0400;
miiw(ctlr, phyaddr, 0x17, x);
break;
.
849,856c
switch((ctlr->eeprom[6]>>8) & 0x001F){
case 0x04: /* DP83840 */
case 0x0A: /* DP83840A */
/*
* The DP83840[A] requires some tweaking for
* reliable operation.
*/
x = miir(ctlr, phyaddr, 0x17) & ~0x0520;
x |= 0x0020;
for(i = 0; i < ether->nopt; i++){
if(cistrcmp(ether->opt[i], "congestioncontrol"))
continue;
x |= 0x0100;
break;
.
846,847c
/*
* Eeprom[6] indicates whether there is a PHY and whether
* it's not 10Mb-only, in which case use the given PHY address
* to set any PHY specific options and determine the speed.
* If no PHY, assume 82503 (serial) operation.
*/
if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){
phyaddr = ctlr->eeprom[6] & 0x00FF;
/*
* Resolve the highest common ability of the two
* link partners. In descending order:
* 0x0100 100BASE-TX Full Duplex
* 0x0200 100BASE-T4
* 0x0080 100BASE-TX
* 0x0040 10BASE-T Full Duplex
* 0x0020 10BASE-T
*/
an = miir(ctlr, phyaddr, 0x04);
an &= miir(ctlr, phyaddr, 0x05) & 0x03E0;
if(an & 0x380)
.
838,844c
sum = 0;
for(i = 0; i < 0x40; i++){
x = hy93c46r(ctlr, i);
ctlr->eeprom[i] = x;
sum += x;
}
if(sum != 0xBABA)
print("#l%d: EEPROM checksum - 0x%4.4uX\n", ether->ctlrno, sum);
.
830,836c
* Read the EEPROM.
.
769c
int an, i, phyaddr, port, x;
unsigned short sum;
.
719c
microdelay(1);
.
715c
microdelay(1);
.
707c
microdelay(1);
.
698c
microdelay(1);
.
696c
microdelay(1);
.
688c
* 3.3.4.2 of the Intel 82557 User's Guide.
.
679a
miiw(Ctlr* ctlr, int phyadd, int regadd, int data)
{
int mcr, timo;
csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF));
mcr = 0;
for(timo = 64; timo; timo--){
mcr = csr32r(ctlr, Mcr);
if(mcr & MDIready)
break;
microdelay(1);
}
if(mcr & MDIready)
return 0;
return -1;
}
static int
.
670c
microdelay(1);
.
666c
for(timo = 64; timo; timo--){
.
660,663d
656c
miir(Ctlr* ctlr, int phyadd, int regadd)
.
650a
ctlr->tick = 0;
.
507a
/*
* If the watchdog timer for the receiver lockup errata is running,
* let it know the receiver is active.
*/
if(status & (StatFR|StatRNR))
ctlr->tick = 0;
.
458a
ctlr->configdata[6] |= 0x40;
.
424a
else if(ctlr->action == CbMAS){
cb->command = CbS|CbMAS;
memset(cb->data, 0, sizeof(cb->data));
ctlr->action = 0;
}
.
382,383c
if(ctlr->cbqmax > ctlr->cbqmaxhw)
ctlr->cbqmaxhw = ctlr->cbqmax;
len += snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax);
ctlr->cbqmax = 0;
snprint(p+len, READSTR-len, "threshold: %lud\n", ctlr->threshold);
.
325a
/*
* Start the watchdog timer for the receive lockup errata
* unless the EEPROM compatibility word indicates it may be
* omitted.
*/
if((ctlr->eeprom[0x03] & 0x0003) != 0x0003){
snprint(name, NAMELEN, "#l%dwatchdog", ether->ctlrno);
kproc(name, watchdog, ether);
}
.
319a
char name[NAMELEN];
.
316a
watchdog(void* arg)
{
Ether *ether;
Ctlr *ctlr;
static void txstart(Ether*);
ether = arg;
for(;;){
ctlr = ether->ctlr;
tsleep(&ctlr->timer, return0, 0, 4000);
/*
* Hmmm. This doesn't seem right. Currently
* the device can't be disabled but it may be in
* the future.
*/
ctlr = ether->ctlr;
if(ctlr == nil || ctlr->state == 0){
print("%s: exiting\n", up->text);
pexit("disabled", 0);
}
if(ctlr->tick++){
ilock(&ctlr->cblock);
ctlr->action = CbMAS;
txstart(ether);
iunlock(&ctlr->cblock);
}
}
}
static void
.
233c
0xC8, /* 503, promiscuous mode off */
.
210a
int cbqmaxhw;
.
193a
Rendez timer; /* watchdog timer for receive lockup errata */
int tick;
.
192a
ushort eeprom[0x40];
.
## diffname pc/ether82557.c 1998/0331
## diff -e /n/emeliedump/1998/0304/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0331/sys/src/brazil/pc/ether82557.c
656c
iunlock(&ctlr->cblock);
.
637c
ilock(&ctlr->cblock);
.
560c
iunlock(&ctlr->rlock);
.
557c
ilock(&ctlr->rlock);
.
## diffname pc/ether82557.c 1998/0507
## diff -e /n/emeliedump/1998/0331/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0507/sys/src/brazil/pc/ether82557.c
1012a
ether->multicast = multicast;
.
532a
multicast(void* arg, uchar *addr, int on)
{
USED(addr, on);
configure(arg, 1);
}
static void
.
## diffname pc/ether82557.c 1998/0511
## diff -e /n/emeliedump/1998/0507/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0511/sys/src/brazil/pc/ether82557.c
972a
case 0x07: /* Intel 82555 */
/*
* Auto-negotiation may fail if the other end is
* a DP83840A and the cable is short.
*/
miir(ctlr, phyaddr, 0x01);
bmsr = miir(ctlr, phyaddr, 0x01);
if((miir(ctlr, phyaddr, 0) & 0x1000) && !(bmsr & 0x0020)){
miiw(ctlr, phyaddr, 0x1A, 0x2010);
x = miir(ctlr, phyaddr, 0);
miiw(ctlr, phyaddr, 0, 0x0200|x);
for(i = 0; i < 3000; i++){
delay(1);
if(miir(ctlr, phyaddr, 0x01) & 0x0020)
break;
}
miiw(ctlr, phyaddr, 0x1A, 0x2000);
anar = miir(ctlr, phyaddr, 0x04);
anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;
anar &= anlpar;
bmcr = 0;
if(anar & 0x380)
bmcr = 0x2000;
if(anar & 0x0140)
bmcr |= 0x0100;
}
break;
}
/*
* Force speed and duplex if no auto-negotiation.
*/
if(anlpar == 0){
force = 0;
for(i = 0; i < ether->nopt; i++){
if(cistrcmp(ether->opt[i], "fullduplex") == 0){
force = 1;
bmcr |= 0x0100;
ctlr->configdata[19] |= 0x40;
}
else if(cistrcmp(ether->opt[i], "speed") == 0){
force = 1;
x = strtol(ðer->opt[i][6], 0, 0);
if(x == 10)
bmcr &= ~0x2000;
else if(x == 100)
bmcr |= 0x2000;
else
force = 0;
}
}
if(force)
miiw(ctlr, phyaddr, 0x00, bmcr);
.
971a
/*
* If the link partner can't autonegotiate, determine
* the speed from elsewhere.
*/
if(anlpar == 0){
miir(ctlr, phyaddr, 0x01);
bmsr = miir(ctlr, phyaddr, 0x01);
x = miir(ctlr, phyaddr, 0x19);
if((bmsr & 0x0004) && !(x & 0x0040))
bmcr = 0x2000;
}
.
969,970d
962c
x |= 0x0420;
.
959a
* The manual says bit 10 should be unconditionally
* set although it supposedly only affects full-duplex
* operation (an & 0x0140).
.
948,951c
anar = miir(ctlr, phyaddr, 0x04);
anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;
anar &= anlpar;
bmcr = 0;
if(anar & 0x380)
bmcr = 0x2000;
if(anar & 0x0140)
bmcr |= 0x0100;
.
857c
int anar, anlpar, bmcr, bmsr, force, i, phyaddr, port, x;
.
## diffname pc/ether82557.c 1998/0522
## diff -e /n/emeliedump/1998/0511/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0522/sys/src/brazil/pc/ether82557.c
623a
coherence();
.
595c
bp->rp += sizeof(Rfd)-sizeof(rfd->data);
.
515c
//ctlr->configdata[6] |= 0x40;
.
507c
//ctlr->configdata[6] &= ~0x40; /* !Discard Overrun Rx Frames */
.
487a
coherence();
.
111c
uchar data[1700];
.
## diffname pc/ether82557.c 1998/0825
## diff -e /n/emeliedump/1998/0522/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0825/sys/src/brazil/pc/ether82557.c
434c
snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold);
.
432c
len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax);
.
## diffname pc/ether82557.c 1998/0929
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0929/sys/src/brazil/pc/ether82557.c
1045c
if(medium != -1)
.
1034,1043d
1032a
break;
case 0x05: /* 100BASE-TXFD */
case 0x08: /* 100BASE-FXFD */
bmcr |= 0x2000|0x0100;
ctlr->configdata[19] |= 0x40;
break;
.
1029,1031c
for(k = 0; k < nelem(mediatable); k++){
if(cistrcmp(mediatable[k], ether->opt[i]))
continue;
medium = k;
break;
}
switch(medium){
default:
break;
case 0x00: /* 10BASE-T */
case 0x01: /* 10BASE-2 */
case 0x02: /* 10BASE-5 */
bmcr &= ~(0x2000|0x0100);
ctlr->configdata[19] &= ~0x40;
break;
case 0x03: /* 100BASE-TX */
case 0x06: /* 100BASE-T4 */
case 0x07: /* 100BASE-FX */
ctlr->configdata[19] &= ~0x40;
bmcr |= 0x2000;
break;
case 0x04: /* 10BASE-TFD */
bmcr = (bmcr & ~0x2000)|0x0100;
.
1027c
medium = -1;
.
859c
int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, port, x;
.
855a
static char* mediatable[9] = {
"10BASE-T", /* TP */
"10BASE-2", /* BNC */
"10BASE-5", /* AUI */
"100BASE-TX",
"10BASE-TFD",
"100BASE-TXFD",
"100BASE-T4",
"100BASE-FX",
"100BASE-FXFD",
};
.
761a
unlock(&ctlr->miilock);
.
753a
lock(&ctlr->miilock);
.
741a
unlock(&ctlr->miilock);
.
733a
lock(&ctlr->miilock);
.
435a
len += snprint(p+len, READSTR-len, "eeprom:");
for(i = 0; i < 0x40; i++){
if(i && ((i & 0x07) == 0))
len += snprint(p+len, READSTR-len, "\n ");
len += snprint(p+len, READSTR-len, " %4.4uX", ctlr->eeprom[i]);
}
if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){
phyaddr = ctlr->eeprom[6] & 0x00FF;
len += snprint(p+len, READSTR-len, "\nphy %2d:", phyaddr);
for(i = 0; i < 6; i++){
static int miir(Ctlr*, int, int);
len += snprint(p+len, READSTR-len, " %4.4uX",
miir(ctlr, phyaddr, i));
}
}
snprint(p+len, READSTR-len, "\n");
.
434c
len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold);
.
382c
int i, len, phyaddr;
.
194a
Lock miilock;
.
## diffname pc/ether82557.c 1998/0930
## diff -e /n/emeliedump/1998/0929/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0930/sys/src/brazil/pc/ether82557.c
602,657c
receive(ether);
.
577d
575a
Ctlr *ctlr;
int count;
Block *bp, *pbp, *xbp;
ctlr = ether->ctlr;
bp = ctlr->rfdhead;
for(rfd = (Rfd*)bp->rp; rfd->field & RfdC; rfd = (Rfd*)bp->rp){
/*
* If it's an OK receive frame
* 1) save the count
* 2) if it's small, try to allocate a block and copy
* the data, then adjust the necessary fields for reuse;
* 3) if it's big, try to allocate a new Rfd and if
* successful
* adjust the received buffer pointers for the
* actual data received;
* initialise the replacement buffer to point to
* the next in the ring;
* initialise bp to point to the replacement;
* 4) if there's a good packet, pass it on for disposal.
*/
if(rfd->field & RfdOK){
pbp = nil;
count = rfd->count & 0x3FFF;
if((count < ETHERMAXTU/4) && (pbp = iallocb(count))){
memmove(pbp->rp, bp->rp+sizeof(Rfd)-sizeof(rfd->data), count);
pbp->wp = pbp->rp + count;
rfd->count = 0;
rfd->field = 0;
}
else if(xbp = rfdalloc(rfd->link)){
bp->rp += sizeof(Rfd)-sizeof(rfd->data);
bp->wp = bp->rp + count;
xbp->next = bp->next;
bp->next = 0;
pbp = bp;
bp = xbp;
}
if(pbp != nil)
etheriq(ether, pbp, 1);
}
else{
rfd->count = 0;
rfd->field = 0;
}
/*
* The ring tail pointer follows the head with with one
* unused buffer in between to defeat hardware prefetch;
* once the tail pointer has been bumped on to the next
* and the new tail has the Suspend bit set, it can be
* removed from the old tail buffer.
* As a replacement for the current head buffer may have
* been allocated above, ensure that the new tail points
* to it (next and link).
*/
rfd = (Rfd*)ctlr->rfdtail->rp;
ctlr->rfdtail = ctlr->rfdtail->next;
ctlr->rfdtail->next = bp;
((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp);
((Rfd*)ctlr->rfdtail->rp)->field |= RfdS;
coherence();
rfd->field &= ~RfdS;
/*
* Finally done with the current (possibly replaced)
* head, move on to the next and maintain the sentinel
* between tail and head.
*/
ctlr->rfdhead = bp->next;
bp = ctlr->rfdhead;
}
}
static void
interrupt(Ureg*, void* arg)
{
.
573c
receive(Ether* ether)
.
## diffname pc/ether82557.c 1998/1024
## diff -e /n/emeliedump/1998/0930/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/1024/sys/src/brazil/pc/ether82557.c
1129a
if(bmcr & 0x2000)
ether->mbps = 100;
.
768c
ctlr->threshold = 80;
.
678a
iunlock(&ctlr->cblock);
}
.
677c
if(status & (StatFR|StatRNR)){
ilock(&ctlr->cblock);
.
351a
iunlock(&ctlr->cblock);
.
350d
347d
345a
ilock(&ctlr->cblock);
.
229c
// 0x80, /* Tx DMA maximum byte count */
0x00, /* Tx DMA maximum byte count */
.
## diffname pc/ether82557.c 1998/1126
## diff -e /n/emeliedump/1998/1024/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/1126/sys/src/brazil/pc/ether82557.c
972a
csr8w(ctlr, Interrupt, InterruptM);
.
364a
ilock(&ctlr->rlock);
csr8w(ctlr, Interrupt, 0);
iunlock(&ctlr->rlock);
.
## diffname pc/ether82557.c 1999/0314
## diff -e /n/emeliedump/1998/1126/sys/src/brazil/pc/ether82557.c /n/emeliedump/1999/0314/sys/src/brazil/pc/ether82557.c
908a
pcisetbme(p);
.
## diffname pc/ether82557.c 1999/0714
## diff -e /n/emeliedump/1999/0314/sys/src/brazil/pc/ether82557.c /n/emeliedump/1999/0714/sys/src/brazil/pc/ether82557.c
908c
port = p->mem[1].bar & ~0x01;
if(ioalloc(port, p->mem[1].size, 0, "i82557pci") < 0){
print("i82557pci: port %d in use\n", port);
continue;
}
i82557adapter(&adapter, port, p->intl, p->tbdf);
.
899a
int port;
.
## diffname pc/ether82557.c 2000/0317
## diff -e /n/emeliedump/1999/0714/sys/src/brazil/pc/ether82557.c /n/emeliedump/2000/0317/sys/src/9/pc/ether82557.c
1016c
else if(!(ctlr->eeprom[5] & 0xFF00))
phyaddr = scanphy(ctlr);
else
phyaddr = -1;
if(phyaddr >= 0){
.
1014c
if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000))
.
1011a
* Unfortunately, sometimes the EEPROM is blank except for
* the ether address and checksum; in this case look at the
* controller type and if 0 scan for the first PHY and try to
* use that.
.
931a
scanphy(Ctlr* ctlr)
{
int i, oui, x;
for(i = 0; i < 32; i++){
if((oui = miir(ctlr, i, 2)) == -1 || oui == 0 || oui == 0xFFFF)
continue;
oui <<= 6;
x = miir(ctlr, i, 3);
oui |= x>>10;
//print("phy%d: oui %uX reg1 %uX\n", i, oui, miir(ctlr, i, 1));
ctlr->eeprom[6] = i;
if(oui == 0xAA00)
ctlr->eeprom[6] |= 0x07<<8;
else if(oui == 0x80017){
if(x & 0x01)
ctlr->eeprom[6] |= 0x0A<<8;
else
ctlr->eeprom[6] |= 0x04<<8;
}
return i;
}
return -1;
}
static int
.
## diffname pc/ether82557.c 2000/0619
## diff -e /n/emeliedump/2000/0317/sys/src/9/pc/ether82557.c /n/emeliedump/2000/0619/sys/src/9/pc/ether82557.c
911c
print("i82557pci: port 0x%uX in use\n", port);
.
## diffname pc/ether82557.c 2001/0301
## diff -e /n/emeliedump/2000/0619/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0301/sys/src/9/pc/ether82557.c
1027c
for(i = 0; i < (1<<ctlr->eepromsz); i++){
.
1025a
hy93c46r(ctlr, 0);
.
1024a
* Do a dummy read first to get the size
* and allocate ctlr->eeprom.
.
869a
if(ctlr->eepromsz == 0){
ctlr->eepromsz = 8-size;
ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));
goto reread;
}
.
847,848c
/*
* First time through must work out the EEPROM size.
*/
if((size = ctlr->eepromsz) == 0)
size = 8;
for(size = size-1; size >= 0; size--){
data = (((r>>size) & 0x01)<<2)|EEcs;
.
835a
reread:
.
828c
int data, i, op, size;
.
443c
for(i = 0; i < (1<<ctlr->eepromsz); i++){
.
193c
int eepromsz; /* address size in bits */
ushort* eeprom;
.
93,94d
## diffname pc/ether82557.c 2001/0419
## diff -e /n/emeliedump/2001/0301/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0419/sys/src/9/pc/ether82557.c
1237d
1065a
break;
case 0x04: /* 82558 A-step */
case 0x05: /* 82558 B-step */
case 0x06: /* 82559 A-step */
case 0x07: /* 82559 B-step */
case 0x08: /* 82559 C-step */
case 0x09: /* 82559ER A-step */
phyaddr = scanphy(ctlr);
break;
}
.
1064a
switch(ctlr->pcidev->rid){
case 0x01: /* 82557 A-step */
case 0x02: /* 82557 B-step */
case 0x03: /* 82557 C-step */
default:
.
1062,1063d
1056,1057c
* controller type and if it's am 82558 or 82559 it has an
* embedded PHY so scan for that.
.
1015,1017c
ether->ctlr = ctlr;
ether->port = ctlr->port;
ether->irq = ctlr->pcidev->intl;
ether->tbdf = ctlr->pcidev->tbdf;
.
1008c
* Initialise the Ctlr structure.
.
1004c
if(ctlr == nil)
.
1002d
990,999c
for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
if(ctlr->active)
continue;
if(ether->port == 0 || ether->port == ctlr->port){
ctlr->active = 1;
.
987c
* Any adapter matches if no ether->port is supplied,
.
983,984d
981c
if(ctlrhead == nil)
.
979d
975,976d
973c
int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, x;
.
926c
ctlr = malloc(sizeof(Ctlr));
ctlr->port = port;
ctlr->pcidev = p;
if(ctlrhead != nil)
ctlrtail->next = ctlr;
else
ctlrhead = ctlr;
ctlrtail = ctlr;
.
922,923c
if(ioalloc(port, p->mem[1].size, 0, "i82557") < 0){
print("i82557: port 0x%uX in use\n", port);
.
912a
Pcidev *p;
Ctlr *ctlr;
.
911d
893,908d
885,891d
221a
static Ctlr* ctlrhead;
static Ctlr* ctlrtail;
.
190a
Pcidev* pcidev;
Ctlr* next;
int active;
.
185a
typedef struct Ctlr Ctlr;
.
## diffname pc/ether82557.c 2001/0424
## diff -e /n/emeliedump/2001/0419/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0424/sys/src/9/pc/ether82557.c
917,921c
/*
* this is backwards from what we really wanted to do
* but this keeps the numbering of ethernet cards
* consistent with 9load.
*/
ctlr->next = ctlrhead;
ctlrhead = ctlr;
.
228d
## diffname pc/ether82557.c 2001/0527
## diff -e /n/emeliedump/2001/0424/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0527/sys/src/9/pc/ether82557.c
383c
snprint(name, KNAMELEN, "#l%dwatchdog", ether->ctlrno);
.
366c
char name[KNAMELEN];
.
## diffname pc/ether82557.c 2001/0626
## diff -e /n/emeliedump/2001/0527/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0626/sys/src/9/pc/ether82557.c
916,922c
if(ctlrhead != nil)
ctlrtail->next = ctlr;
else
ctlrhead = ctlr;
ctlrtail = ctlr;
.
227a
static Ctlr* ctlrtail;
.
## diffname pc/ether82557.c 2001/1014
## diff -e /n/emeliedump/2001/0626/sys/src/9/pc/ether82557.c /n/emeliedump/2001/1014/sys/src/9/pc/ether82557.c
901c
while(p = pcimatch(p, 0x8086, 0)){
switch(p->did){
default:
continue;
case 0x1229: /* Intel 8255[789] */
case 0x1031: /* Intel 82562EM */
break;
}
.
## diffname pc/ether82557.c 2001/1016
## diff -e /n/emeliedump/2001/1014/sys/src/9/pc/ether82557.c /n/emeliedump/2001/1016/sys/src/9/pc/ether82557.c
906a
case 0x2449: /* Intel ????? */
.
## diffname pc/ether82557.c 2001/1017
## diff -e /n/emeliedump/2001/1016/sys/src/9/pc/ether82557.c /n/emeliedump/2001/1017/sys/src/9/pc/ether82557.c
907c
case 0x2449: /* Intel 82562ET */
.
904a
case 0x1209: /* INtel 82559ER */
.
## diffname pc/ether82557.c 2002/0109
## diff -e /n/emeliedump/2001/1017/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0109/sys/src/9/pc/ether82557.c
1249a
ether->shutdown = shutdown;
.
975a
static void
shutdown(Ether* ether)
{
Ctlr *ctlr = ether->ctlr;
print("ether82557 shutting down\n");
csr32w(ctlr, Port, 0);
delay(1);
csr8w(ctlr, Interrupt, InterruptM);
}
.
## diffname pc/ether82557.c 2002/0131
## diff -e /n/emeliedump/2002/0109/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0131/sys/src/9/pc/ether82557.c
905c
case 0x1209: /* Intel 82559ER */
.
## diffname pc/ether82557.c 2002/0711
## diff -e /n/emeliedump/2002/0131/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0711/sys/src/9/pc/ether82557.c
1232c
ether->oq = qopen(256*1024, Qmsg, 0, 0);
.
## diffname pc/ether82557.c 2002/0920
## diff -e /n/emeliedump/2002/0711/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0920/sys/src/9/pc/ether82557.c
282,283c
if(waitfordone(ctlr) < 0)
print("82557: lastcmd %x, cmd %x(%x) \n", ctlr->command, c, v);
.
269a
* on a 10 Mbs half-duplex connection, we seem to
* hang unless we do a nop before each command.
* This comes from a fix for a chip errata that jmk
* saw in a Linux driver.
*/
if(waitfordone(ctlr) < 0)
print("82557: lastcmd %x, cmd nop \n", ctlr->command);
csr8w(ctlr, CommandR, CUnop);
/*
.
263a
int
waitfordone(Ctlr *ctlr)
{
int loops;
/* fast wait, we usually get lucky */
for(loops = 0; loops < 100; loops++){
if(csr8r(ctlr, CommandR) == 0)
return 0;
}
/* slow wait */
for(loops = 0; loops < 1000; loops++){
if(csr8r(ctlr, CommandR) == 0)
return 0;
microdelay(1);
}
return -1;
}
.
## diffname pc/ether82557.c 2002/0921
## diff -e /n/emeliedump/2002/0920/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0921/sys/src/9/pc/ether82557.c
1256a
/*
* Workaround for some broken HUB chips when connected at 10Mb/s
* half-duplex.
* This is a band-aid, but as there's no dynamic auto-negotiation
* code at the moment, only deactivate the workaround code in txstart
* if the link is 100Mb/s.
*/
if(ether->mbps != 10)
ctlr->nop = 0;
.
955a
ctlr->nop = nop;
.
938a
nop = 1;
/*FALLTHROUGH*/
case 0x1209: /* Intel 82559ER */
case 0x1229: /* Intel 8255[789] */
.
935,936d
930a
nop = 0;
.
928a
int nop, port;
.
926d
554a
/*
* Workaround for some broken HUB chips
* when connected at 10Mb/s half-duplex.
*/
if(ctlr->nop){
command(ctlr, CUnop, 0);
microdelay(1);
}
.
472a
len += snprint(p+len, READSTR-len, "nop: %d\n", ctlr->nop);
.
312,313c
for(timeo = 0; timeo < 100; timeo++){
if(!csr8r(ctlr, CommandR))
break;
microdelay(1);
}
if(timeo >= 100){
ctlr->command = -1;
iunlock(&ctlr->rlock);
iprint("i82557: command 0x%uX %uX timeout\n", c, v);
return;
}
.
290,299d
286a
int timeo;
.
264,283d
212a
int nop;
.
## diffname pc/ether82557.c 2003/0407
## diff -e /n/emeliedump/2002/0921/sys/src/9/pc/ether82557.c /n/emeliedump/2003/0407/sys/src/9/pc/ether82557.c
352,353c
tsleep(&up->sleep, return0, 0, 4000);
.
201d
|