enum { /* CSR9 - ROM and MII Management */
Scs = 0x00000001, /* serial ROM chip select */
Sclk = 0x00000002, /* serial ROM clock */
Sdi = 0x00000004, /* serial ROM data in */
Sdo = 0x00000008, /* serial ROM data out */
Ss = 0x00000800, /* serial ROM select */
Wr = 0x00002000, /* write */
Rd = 0x00004000, /* read */
Mdc = 0x00010000, /* MII management clock */
Mdo = 0x00020000, /* MII management write data */
Mii = 0x00040000, /* MII management operation mode (W) */
Mdi = 0x00080000, /* MII management data in */
};
enum { /* CSR12 - General-Purpose Port */
Gpc = 0x00000100, /* General Purpose Control */
};
typedef struct Des {
int status;
int control;
ulong addr;
Msgbuf* mb;
} Des;
enum { /* status */
Of = 0x00000001, /* Rx: OverFlow */
Ce = 0x00000002, /* Rx: CRC Error */
Db = 0x00000004, /* Rx: Dribbling Bit */
Re = 0x00000008, /* Rx: Report on MII Error */
Rw = 0x00000010, /* Rx: Receive Watchdog */
Ft = 0x00000020, /* Rx: Frame Type */
Cs = 0x00000040, /* Rx: Collision Seen */
Tl = 0x00000080, /* Rx: Frame too Long */
Ls = 0x00000100, /* Rx: Last deScriptor */
Fs = 0x00000200, /* Rx: First deScriptor */
Mf = 0x00000400, /* Rx: Multicast Frame */
Rf = 0x00000800, /* Rx: Runt Frame */
Dt = 0x00003000, /* Rx: Data Type (field) */
De = 0x00004000, /* Rx: Descriptor Error */
Fl = 0x3FFF0000, /* Rx: Frame Length (field) */
Ff = 0x40000000, /* Rx: Filtering Fail */
typedef struct Ctlr Ctlr;
typedef struct Ctlr {
int port;
Pcidev* pcidev;
Ctlr* next;
int active;
int id; /* (pcidev->did<<16)|pcidev->vid */
uchar srom[128];
uchar* sromea; /* MAC address */
uchar* leaf;
int sct; /* selected connection type */
int k; /* info block count */
uchar* infoblock[16];
int sctk; /* sct block index */
int curk; /* current block index */
uchar* type5block;
int phy[32]; /* logical to physical map */
int phyreset; /* reset bitmap */
int curphyad;
int fdx;
int ttm;
uchar fd; /* option */
int medium; /* option */
int csr6; /* CSR6 - operating mode */
int mask; /* CSR[57] - interrupt mask */
int mbps;
Lock lock;
Des* rdr; /* receive descriptor ring */
int nrdr; /* size of rdr */
int rdrx; /* index into rdr */
Lock tlock;
Des* tdr; /* transmit descriptor ring */
int ntdr; /* size of tdr */
int tdrh; /* host index into tdr */
int tdri; /* interface index into tdr */
int ntq; /* descriptors active */
int ntqmax;
Msgbuf* setupmb;
static void
interrupt(Ureg*, void* arg)
{
Ctlr *ctlr;
Ether *ether;
int len, status;
Des *des;
Msgbuf *mb, *rmb;
ether = arg;
ctlr = ether->ctlr;
while((status = csr32r(ctlr, 5)) & (Nis|Ais)){
/*
* Acknowledge the interrupts and mask-out
* the ones that are implicitly handled.
*/
csr32w(ctlr, 5, status);
status &= (ctlr->mask & ~(Nis|Ti));
ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
des = &ctlr->rdr[ctlr->rdrx];
}
status &= ~Ri;
}
/*
* Check the transmit side:
* check for Transmit Underflow and Adjust
* the threshold upwards;
* free any transmitted buffers and try to
* top-up the ring.
*/
if(status & Unf){
ctlr->unf++;
ilock(&ctlr->lock);
csr32w(ctlr, 6, ctlr->csr6 & ~St);
switch(ctlr->csr6 & Tr){
case Tr128:
len = Tr256;
break;
case Tr256:
len = Tr512;
break;
case Tr512:
len = Tr1024;
break;
default:
case Tr1024:
len = Sf;
break;
}
ctlr->csr6 = (ctlr->csr6 & ~Tr)|len;
csr32w(ctlr, 6, ctlr->csr6);
iunlock(&ctlr->lock);
csr32w(ctlr, 5, Tps);
status &= ~(Unf|Tps);
}
ilock(&ctlr->tlock);
while(ctlr->ntq){
des = &ctlr->tdr[ctlr->tdri];
if(des->status & Own)
break;
/*
* Clear any bits in the Status Register (CSR5) as
* the PNIC has a different reset value from a true 2114x.
*/
ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti;
csr32w(ctlr, 5, ctlr->mask);
csr32w(ctlr, 7, ctlr->mask);
ctlr->csr6 |= St;
csr32w(ctlr, 6, ctlr->csr6);
static int
miimdi(Ctlr* ctlr, int n)
{
int data, i;
/*
* Read n bits from the MII Management Register.
*/
data = 0;
for(i = n-1; i >= 0; i--){
if(csr32r(ctlr, 9) & Mdi)
data |= (1<<i);
csr9w(ctlr, Mii|Mdc);
csr9w(ctlr, Mii);
}
csr9w(ctlr, 0);
return data;
}
static void
miimdo(Ctlr* ctlr, int bits, int n)
{
int i, mdo;
/*
* Write n bits to the MII Management Register.
*/
for(i = n-1; i >= 0; i--){
if(bits & (1<<i))
mdo = Mdo;
else
mdo = 0;
csr9w(ctlr, mdo);
csr9w(ctlr, mdo|Mdc);
csr9w(ctlr, mdo);
}
}
static int
miir(Ctlr* ctlr, int phyad, int regad)
{
int data, i;
if(ctlr->id == Pnic){
i = 1000;
csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18));
do{
microdelay(1);
data = csr32r(ctlr, 20);
}while((data & 0x80000000) && --i);
if(i == 0)
return -1;
return data & 0xFFFF;
}
/*
* Preamble;
* ST+OP+PHYAD+REGAD;
* TA + 16 data bits.
*/
miimdo(ctlr, 0xFFFFFFFF, 32);
miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14);
data = miimdi(ctlr, 18);
if(data & 0x10000)
return -1;
return data & 0xFFFF;
}
static void
miiw(Ctlr* ctlr, int phyad, int regad, int data)
{
/*
* Preamble;
* ST+OP+PHYAD+REGAD+TA + 16 data bits;
* Z.
*/
miimdo(ctlr, 0xFFFFFFFF, 32);
data &= 0xFFFF;
data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16);
miimdo(ctlr, data, 32);
csr9w(ctlr, Mdc);
csr9w(ctlr, 0);
}
static int
sromr(Ctlr* ctlr, int r)
{
int i, op, data;
if(ctlr->id == Pnic){
i = 1000;
csr32w(ctlr, 19, 0x600|r);
do{
microdelay(1);
data = csr32r(ctlr, 19);
}while((data & 0x80000000) && --i);
return csr32r(ctlr, 9) & 0xFFFF;
}
/*
* This sequence for reading a 16-bit register 'r'
* in the EEPROM is taken straight from Section
* 7.4 of the 21140 Hardware Reference Manual.
*/
csr9w(ctlr, Rd|Ss);
csr9w(ctlr, Rd|Ss|Scs);
csr9w(ctlr, Rd|Ss|Sclk|Scs);
csr9w(ctlr, Rd|Ss);
op = 0x06;
for(i = 3-1; i >= 0; i--){
data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs;
csr9w(ctlr, data);
csr9w(ctlr, data|Sclk);
csr9w(ctlr, data);
}
for(i = 6-1; i >= 0; i--){
data = Rd|Ss|(((r>>i) & 0x01)<<2)|Scs;
csr9w(ctlr, data);
csr9w(ctlr, data|Sclk);
csr9w(ctlr, data);
}
data = 0;
for(i = 16-1; i >= 0; i--){
csr9w(ctlr, Rd|Ss|Sclk|Scs);
if(csr32r(ctlr, 9) & Sdo)
data |= (1<<i);
csr9w(ctlr, Rd|Ss|Scs);
}
csr9w(ctlr, 0);
return data & 0xFFFF;
}
static void
softreset(Ctlr* ctlr)
{
/*
* Soft-reset the controller and initialise bus mode.
* Delay should be >= 50 PCI cycles (2×S @ 25MHz).
*/
csr32w(ctlr, 0, Swr);
microdelay(10);
csr32w(ctlr, 0, Rml|Cal16);
delay(1);
}
static int
type5block(Ctlr* ctlr, uchar* block)
{
int csr15, i, len;
/*
* Reset or GPR sequence. Reset should be once only,
* before the GPR sequence.
* Note 'block' is not a pointer to the block head but
* a pointer to the data in the block starting at the
* reset length value so type5block can be used for the
* sequences contained in type 1 and type 3 blocks.
* The SROM docs state the 21140 type 5 block is the
* same as that for the 21143, but the two controllers
* use different registers and sequence-element lengths
* so the 21140 code here is a guess for a real type 5
* sequence.
*/
len = *block++;
if(ctlr->id != Tulip3){
for(i = 0; i < len; i++){
csr32w(ctlr, 12, *block);
block++;
}
return len;
}
static int
srom(Ctlr* ctlr)
{
int i, k, oui, phy, x;
uchar *p;
/*
* This is a partial decoding of the SROM format described in
* 'Digital Semiconductor 21X4 Serial ROM Format, Version 4.05,
* 2-Mar-98'. Only the 2114[03] are handled, support for other
* controllers can be added as needed.
*/
for(i = 0; i < sizeof(ctlr->srom)/2; i++){
x = sromr(ctlr, i);
ctlr->srom[2*i] = x;
ctlr->srom[2*i+1] = x>>8;
}
/*
* There are 2 SROM layouts:
* e.g. Digital EtherWORKS station address at offset 20;
* this complies with the 21140A SROM
* application note from Digital;
* e.g. SMC9332 station address at offset 0 followed by
* 2 additional bytes, repeated at offset
* 6; the 8 bytes are also repeated in
* reverse order at offset 8.
* To check which it is, read the SROM and check for the repeating
* patterns of the non-compliant cards; if that fails use the one at
* offset 20.
*/
ctlr->sromea = ctlr->srom;
for(i = 0; i < 8; i++){
x = ctlr->srom[i];
if(x != ctlr->srom[15-i] || x != ctlr->srom[16+i]){
ctlr->sromea = &ctlr->srom[20];
break;
}
}
/*
* Fake up the SROM for the PNIC.
* It looks like a 21140 with a PHY.
* The MAC address is byte-swapped in the orginal SROM data.
*/
if(ctlr->id == Pnic){
memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic));
for(i = 0; i < Easize; i += 2){
ctlr->srom[20+i] = ctlr->srom[i+1];
ctlr->srom[20+i+1] = ctlr->srom[i];
}
}
/*
* Next, try to find the info leaf in the SROM for media detection.
* If it's a non-conforming card try to match the vendor ethernet code
* and point p at a fake info leaf with compact 21140 entries.
*/
if(ctlr->sromea == ctlr->srom){
p = nil;
for(i = 0; leaf21140[i] != nil; i++){
if(memcmp(leaf21140[i], ctlr->sromea, 3) == 0){
p = &leaf21140[i][4];
break;
}
}
if(p == nil)
return -1;
}
else
p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]];
/*
* Set up the info needed for later media detection.
* For the 21140, set the general-purpose mask in CSR12.
* The info block entries are stored in order of increasing
* precedence, so detection will work backwards through the
* stored indexes into ctlr->srom.
* If an entry is found which matches the selected connection
* type, save the index. Otherwise, start at the last entry.
* If any MII entries are found (type 1 and 3 blocks), scan
* for PHYs.
*/
ctlr->leaf = p;
ctlr->sct = *p++;
ctlr->sct |= *p++<<8;
if(ctlr->id != Tulip3){
csr32w(ctlr, 12, Gpc|*p++);
delay(200);
}
ctlr->k = *p++;
if(ctlr->k >= nelem(ctlr->infoblock))
ctlr->k = nelem(ctlr->infoblock)-1;
ctlr->sctk = ctlr->k-1;
phy = 0;
for(k = 0; k < ctlr->k; k++){
ctlr->infoblock[k] = p;
/*
* The RAMIX PMC665 has a badly-coded SROM,
* hence the test for 21143 and type 3.
*/
if((*p & 0x80) || (ctlr->id == Tulip3 && *(p+1) == 3)){
*p |= 0x80;
if(*(p+1) == 1 || *(p+1) == 3)
phy = 1;
if(*(p+1) == 5)
ctlr->type5block = p;
p += (*p & ~0x80)+1;
}
else{
debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
p[0], p[1], p[2], p[3]);
if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
ctlr->sctk = k;
p += 4;
}
}
ctlr->curk = ctlr->sctk;
debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n",
ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy);
case Tulip3: /* 21143 */
/*
* Exit sleep mode.
*/
x = pcicfgr32(p, 0x40);
x &= ~0xc0000000;
pcicfgw32(p, 0x40, x);
/*FALLTHROUGH*/
case Pnic: /* PNIC */
case Pnic2: /* PNIC-II */
case Tulip0: /* 21140 */
break;
}
/*
* bar[0] is the I/O port register address and
* bar[1] is the memory-mapped register address.
*/
ctlr = ialloc(sizeof(Ctlr), 0);
ctlr->port = p->mem[0].bar & ~0x01;
ctlr->pcidev = p;
ctlr->id = (p->did<<16)|p->vid;
/*
* Some cards (e.g. ANA-6910FX) seem to need the Ps bit
* set or they don't always work right after a hardware
* reset.
*/
csr32w(ctlr, 6, Mbo|Ps);
softreset(ctlr);
if(srom(ctlr)){
//free(ctlr);
break;
}
switch(ctlr->id){
default:
break;
case Pnic: /* PNIC */
/*
* Turn off the jabber timer.
*/
csr32w(ctlr, 15, 0x00000001);
break;
}
/*
* 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 in the hardware.
*/
memset(ea, 0, Easize);
if(memcmp(ea, ether->ea, Easize) == 0)
memmove(ether->ea, ctlr->sromea, Easize);
/*
* Look for a medium override in case there's no autonegotiation
* (no MII) or the autonegotiation fails.
*/
for(i = 0; i < ether->nopt; i++){
if(cistrcmp(ether->opt[i], "FD") == 0){
ctlr->fd = 1;
continue;
}
for(x = 0; x < nelem(mediatable); x++){
debug("compare <%s> <%s>\n", mediatable[x],
ether->opt[i]);
if(cistrcmp(mediatable[x], ether->opt[i]))
continue;
ctlr->medium = x;