📄 ether21140.c
字号:
return data & 0xFFFF;}static intsromr(Ctlr* ctlr, int r){ int i, op, data; /* * 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. */ srmiiw(ctlr, Rd|Ss); srmiiw(ctlr, Rd|Ss|Scs); srmiiw(ctlr, Rd|Ss|Sclk|Scs); srmiiw(ctlr, Rd|Ss); op = 0x06; for(i = 3-1; i >= 0; i--){ data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs; srmiiw(ctlr, data); srmiiw(ctlr, data|Sclk); srmiiw(ctlr, data); } for(i = 6-1; i >= 0; i--){ data = Rd|Ss|(((r>>i) & 0x01)<<2)|Scs; srmiiw(ctlr, data); srmiiw(ctlr, data|Sclk); srmiiw(ctlr, data); } data = 0; for(i = 16-1; i >= 0; i--){ srmiiw(ctlr, Rd|Ss|Sclk|Scs); if(csr32r(ctlr, 9) & Sdo) data |= (1<<i); srmiiw(ctlr, Rd|Ss|Scs); } srmiiw(ctlr, 0); return data & 0xFFFF;}static char* mediatable[] = { "10BASE-T", /* TP */ "10BASE-2", /* BNC */ "10BASE-5", /* AUI */ "100BASE-TX", "10BASE-TFD", "100BASE-TXFD", "100BASE-T4", "100BASE-FX", "100BASE-FXFD",};static uchar en1207[] = { /* Accton EN1207-COMBO */ 0x00, 0x00, 0xE8, /* [0] vendor ethernet code */ 0x00, /* [3] spare */ 0x00, 0x08, /* [4] connection (LSB, MSB = 0x0800) */ 0x1F, /* [6] general purpose control */ 2, /* [7] block count */ 0x03, /* [8] media code (100BASE-TX) */ 0x1B, /* [9] general purpose port data */ 0x6D, 0x00, /* [10] command (LSB, MSB = 0x006D) */ 0x00, /* [8] media code (10BASE-TX) */ 0x0B, /* [9] general purpose port data */ 0x9E, 0x00, /* [10] command (LSB, MSB = 0x009E) */ /* There is 10BASE-2 as well, but... */};static uchar ana6910fx[] = { /* Adaptec (Cogent) ANA-6910FX */ 0x00, 0x00, 0x92, /* [0] vendor ethernet code */ 0x00, /* [3] spare */ 0x00, 0x08, /* [4] connection (LSB, MSB = 0x0800) */ 0x3F, /* [6] general purpose control */ 1, /* [7] block count */ 0x07, /* [8] media code (100BASE-FX) */ 0x03, /* [9] general purpose port data */ 0x2D, 0x00 /* [10] command (LSB, MSB = 0x000D) */};static uchar smc9332[] = { /* SMC 9332 */ 0x00, 0x00, 0xC0, /* [0] vendor ethernet code */ 0x00, /* [3] spare */ 0x00, 0x08, /* [4] connection (LSB, MSB = 0x0800) */ 0x1F, /* [6] general purpose control */ 2, /* [7] block count */ 0x03, /* [8] media code (100BASE-TX) */ 0x09, /* [9] general purpose port data */ 0x6D, 0x00, /* [10] command (LSB, MSB = 0x006D) */ 0x00, /* [8] media code (10BASE-TX) */ 0x00, /* [9] general purpose port data */ 0x9E, 0x00, /* [10] command (LSB, MSB = 0x009E) */};static uchar* sromtable[] = { en1207, /* Accton EN1207-COMBO */ ana6910fx, /* Adaptec (Cogent) ANA-6910FX */ smc9332, /* SMC 9332 */ 0,};static voidsoftreset(Ctlr* ctlr){ csr32w(ctlr, 0, Swr); microdelay(10); csr32w(ctlr, 0, Rml|Cal16); delay(1);}static intmediadetect(Ctlr* ctlr, uchar* leaf, uchar csr12){ int csr6, m, polarity, sense, timeo; m = (leaf[3]<<8)|leaf[2]; csr6 = Sc|Mbo|Hbd|Ca|Sb|TrMODE; if(m & 0x0001) csr6 |= Ps; if(m & 0x0010) csr6 |= Ttm; if(m & 0x0020) csr6 |= Pcs; if(m & 0x0040) csr6 |= Scr; switch(leaf[0]){ default: if(!ctlr->fd) break; /*FALLTHROUGH*/ case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ csr6 |= Fd; break; } sense = 1<<((m & 0x000E)>>1); if(m & 0x0080) polarity = sense; else polarity = 0; csr32w(ctlr, 6, csr6); softreset(ctlr); csr32w(ctlr, 12, Gpc|csr12); delay(200); csr32w(ctlr, 12, leaf[1]); microdelay(10); csr32w(ctlr, 6, csr6); for(timeo = 0; timeo < 30; timeo++){ if((csr32r(ctlr, 12) & sense)^polarity){ DEBUG("timeo=%d CSR6=%uX CSR12=%uX m=%uX sense=%uX polarity=%uX\n", timeo, csr6, csr32r(ctlr, 12), m, sense, polarity); return csr6; } delay(100); } DEBUG("timeo=%d CSR6=%uX CSR12=%uX m=%uX sense=%uX polarity=%uX\n", timeo, csr6, csr32r(ctlr, 12), m, sense, polarity); return 0;}static voidscanphy(Ctlr* ctlr){ int index, number, oui; number = 0; for(index = 0; index < 32; index++){ if((oui = miir(ctlr, index, 2)) == -1 || oui == 0) continue; oui <<= 6; oui |= miir(ctlr, index, 3)>>10; DEBUG("phy%d: oui %uX reg1 %uX\n", index, oui, miir(ctlr, index, 1)); USED(oui); ctlr->phy[number] = index; }}static voidtype1(Ctlr* ctlr, uchar* block){ int anar, anlpar, phyad; scanphy(ctlr); /* * 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 */ phyad = ctlr->phy[block[2]]; anar = miir(ctlr, phyad, 0x04); anlpar = miir(ctlr, phyad, 0x05) & 0x03E0; anar &= anlpar;print("anar = %uX %uX %uX %uX\n", anar, anlpar, miir(ctlr, phyad, 0x00), miir(ctlr, phyad, 0x01)); ctlr->csr6 = Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; if(anar & 0x0100) ctlr->csr6 |= Fd; else if(anar & 0x0080) ; else if(anar & 0x0040) ctlr->csr6 |= Ttm|Fd; else ctlr->csr6 |= Ttm;}static intmedia(Ether* ether){ Ctlr *ctlr; uchar *p, *block; ushort m; int csr6, i, k, len, medium; ctlr = ether->ctlr; /* * If it's a non-conforming card try to match the vendor ethernet * code and point p at a fake SROM table entry. */ if(ctlr->sromea == ctlr->srom){ p = nil; for(i = 0; sromtable[i]; i++){ if(memcmp(sromtable[i], ctlr->sromea, 3) == 0){ p = &sromtable[i][4]; break; } } if(p == nil) return 0; } else p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]]; medium = -1; for(i = 0; i < ether->nopt; i++){ for(k = 0; k < nelem(mediatable); k++){ DEBUG("compare <%s> <%s>\n", mediatable[k], ether->opt[i]); if(cistrcmp(mediatable[k], ether->opt[i])) continue; medium = k; break; } switch(medium){ default: ctlr->fd = 0; break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ ctlr->fd = 1; break; } } m = (p[1]<<8)|p[0]; DEBUG("medium = %d, m = 0x%uX %uX %uX\n", medium, m, p[2], p[3]); for(block = &p[4], k = p[3]; k > 0; k--, block += len){ DEBUG("block %uX %uX %uX %uX\n", block[0], block[1], block[2], block[3]); if(block[0] & 0x80){ len = (block[0] & ~0x80)+1; if(block[1] == 1) type1(ctlr, block); continue; } else len = 4; if(medium >= 0 && block[0] != medium) continue; if(m != 0x0800 && block[0] != (m & 0xFF)) continue; /* * If full-duplex wasn't explicitly requested above, * don't attempt to to detect it. */ switch(block[0]){ default: break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ if(!ctlr->fd) continue; break; } csr6 = mediadetect(ctlr, block, p[2]); DEBUG("csr6 = %uX\n", csr6); if(csr6){ ctlr->csr6 = csr6; break; } } if(ctlr->csr6){ if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm)) return 10; else return 100; } return 0;}typedef struct Adapter { int port; int irq; int tbdf;} Adapter;static Block* adapter;static voiddec21140adapter(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; DEBUG("port 0x%luX intl 0x%luX tbdf 0x%luX\n", port, irq, tbdf); bp->next = *bpp; *bpp = bp;}static voiddec21140pci(void){ Pcidev *p; p = nil; while(p = pcimatch(p, VendorID, DeviceID)){ /* * bar[0] is the I/O port register address and * bar[1] is the memory-mapped register address. */ dec21140adapter(&adapter, p->mem[0].bar & ~0x01, p->intl, p->tbdf); pcisetbme(p); }}static voiddetach(Ether* ether){ softreset(ether->ctlr);}intether21140reset(Ether* ether){ int i, port, x; Block *bp, **bpp; Adapter *ap; Ctlr *ctlr; uchar ea[Eaddrlen*2]; static int scandone; if(scandone == 0){ dec21140pci(); scandone = 1; } /* * Any adapter matches if no ether->port is supplied, * otherwise the ports must match. */ port = 0; bpp = &adapter; for(bp = *bpp; bp; bp = bp->next){ ap = (Adapter*)bp->rp; if(ether->port == 0 || ether->port == ap->port){ port = ap->port; ether->irq = ap->irq; ether->tbdf = ap->tbdf; *bpp = bp->next; freeb(bp); break; } } if(port == 0) return -1; /* * Allocate a controller structure and start to initialise it. */ ether->ctlr = malloc(sizeof(Ctlr)); ctlr = ether->ctlr; ctlr->ctlrno = ether->ctlrno; ctlr->type = ether->type; ctlr->port = port; /* * Soft-reset the controller and initialise bus mode. * Delay should be >= 50 PCI cycles (2×S @ 25MHz). * 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); /* * 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. * * 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 16; * 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. */ 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; } 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; } } memset(ea, 0, Eaddrlen); if(memcmp(ea, ether->ea, Eaddrlen) == 0) memmove(ether->ea, ctlr->sromea, Eaddrlen); /* * Determine media. */ ctlr->mbps = media(ether); /* * Initialise descriptor rings, ethernet address. */ ctlr->nrdr = Nrde; ctlr->ntdr = Ntde; ctlrinit(ctlr, ether->ea); /* * Linkage to the generic ethernet driver. */ ether->port = port; ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt; ether->detach = detach; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -