?? ether2114x.c
字號:
/* * Fail if * auto-negotiataion enabled but not complete; * no valid link established. */ bmcr = miir(ctlr, ctlr->curphyad, Bmcr); miir(ctlr, ctlr->curphyad, Bmsr); bmsr = miir(ctlr, ctlr->curphyad, Bmsr); debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr); if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004)) return 0; if(bmcr & 0x1000){ an = miir(ctlr, ctlr->curphyad, Anar); an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0; debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n", miir(ctlr, ctlr->curphyad, Anar), miir(ctlr, ctlr->curphyad, Anlpar), an); if(an & 0x0100) x = 0x4000; else if(an & 0x0080) x = 0x2000; else if(an & 0x0040) x = 0x1000; else if(an & 0x0020) x = 0x0800; else x = 0; } else if((bmcr & 0x2100) == 0x2100) x = 0x4000; else if(bmcr & 0x2000){ /* * If FD capable, force it if necessary. */ if((bmsr & 0x4000) && ctlr->fd){ miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100); x = 0x4000; } else x = 0x2000; } else if(bmcr & 0x0100) x = 0x1000; else x = 0x0800; csr6 = Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; if(ctlr->fdx & x) csr6 |= Fd; if(ctlr->ttm & x) csr6 |= Ttm; debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n", csr6, ctlr->csr6, csr32r(ctlr, 6)); if(csr6 != ctlr->csr6){ ctlr->csr6 = csr6; csr32w(ctlr, 6, csr6); } return 1;}static inttypephymode(Ctlr* ctlr, uchar* block, int wait){ uchar *p; int len, mc, nway, phyx, timeo; if(DEBUG){ int i; len = (block[0] & ~0x80)+1; for(i = 0; i < len; i++) debug("%2.2uX ", block[i]); debug("\n"); } if(block[1] == 1) len = 1; else if(block[1] == 3) len = 2; else return -1; /* * Snarf the media capabilities, nway advertisment, * FDX and TTM bitmaps. */ p = &block[5+len*block[3]+len*block[4+len*block[3]]]; mc = *p++; mc |= *p++<<8; nway = *p++; nway |= *p++<<8; ctlr->fdx = *p++; ctlr->fdx |= *p++<<8; ctlr->ttm = *p++; ctlr->ttm |= *p<<8; debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n", mc, nway, ctlr->fdx, ctlr->ttm); USED(mc); phyx = block[2]; ctlr->curphyad = ctlr->phy[phyx]; ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; //csr32w(ctlr, 6, ctlr->csr6); if(typephylink(ctlr, block)) return 0; if(!(ctlr->phyreset & (1<<phyx))){ debug("reset seq: len %d: ", block[3]); if(ctlr->type5block) type5block(ctlr, &ctlr->type5block[2]); else type5block(ctlr, &block[4+len*block[3]]); debug("\n"); ctlr->phyreset |= (1<<phyx); } /* * GPR sequence. */ debug("gpr seq: len %d: ", block[3]); type5block(ctlr, &block[3]); debug("\n"); ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; //csr32w(ctlr, 6, ctlr->csr6); if(typephylink(ctlr, block)) return 0; /* * Turn off auto-negotiation, set the auto-negotiation * advertisment register then start the auto-negotiation * process again. */ miiw(ctlr, ctlr->curphyad, Bmcr, 0); miiw(ctlr, ctlr->curphyad, Anar, nway|1); miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000); if(!wait) return 0; for(timeo = 0; timeo < 30; timeo++){ if(typephylink(ctlr, block)) return 0; delay(100); } return -1;}static inttype0link(Ctlr* ctlr, uchar* block){ int m, polarity, sense; m = (block[3]<<8)|block[2]; sense = 1<<((m & 0x000E)>>1); if(m & 0x0080) polarity = sense; else polarity = 0; return (csr32r(ctlr, 12) & sense)^polarity;}static inttype0mode(Ctlr* ctlr, uchar* block, int wait){ int csr6, m, timeo; csr6 = Sc|Mbo|Hbd|Ca|Sb|TrMODE;debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n", ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]); switch(block[0]){ default: break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ /* * Don't attempt full-duplex * unless explicitly requested. */ if(!ctlr->fd) return -1; csr6 |= Fd; break; } m = (block[3]<<8)|block[2]; if(m & 0x0001) csr6 |= Ps; if(m & 0x0010) csr6 |= Ttm; if(m & 0x0020) csr6 |= Pcs; if(m & 0x0040) csr6 |= Scr; csr32w(ctlr, 12, block[1]); microdelay(10); csr32w(ctlr, 6, csr6); ctlr->csr6 = csr6; if(!wait) return 0; for(timeo = 0; timeo < 30; timeo++){ if(type0link(ctlr, block)) return 0; delay(100); } return -1;}static intmediaxx(Ether* ether, int wait){ Ctlr* ctlr; uchar *block; ctlr = ether->ctlr; block = ctlr->infoblock[ctlr->curk]; if(block[0] & 0x80){ switch(block[1]){ default: return -1; case 0: if(ctlr->medium >= 0 && block[2] != ctlr->medium) return 0;/* need this test? */ if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[2]) return 0; if(type0mode(ctlr, block+2, wait)) return 0; break; case 1: if(typephymode(ctlr, block, wait)) return 0; break; case 3: if(typephymode(ctlr, block, wait)) return 0; break; } } else{ if(ctlr->medium >= 0 && block[0] != ctlr->medium) return 0;/* need this test? */if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[0]) return 0; if(type0mode(ctlr, block, wait)) return 0; } if(ctlr->csr6){ if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm)) return 10; return 100; } return 0;}static intmedia(Ether* ether, int wait){ Ctlr* ctlr; int k, mbps; ctlr = ether->ctlr; for(k = 0; k < ctlr->k; k++){ mbps = mediaxx(ether, wait); if(mbps > 0) return mbps; if(ctlr->curk == 0) ctlr->curk = ctlr->k-1; else ctlr->curk--; } return 0;}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",};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 */ 0x00, /* [8] media code (10BASE-TX) */ 0x0B, /* [9] general purpose port data */ 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */ 0x03, /* [8] media code (100BASE-TX) */ 0x1B, /* [9] general purpose port data */ 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */ /* 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 */ 0x00, /* [8] media code (10BASE-TX) */ 0x00, /* [9] general purpose port data */ 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */ 0x03, /* [8] media code (100BASE-TX) */ 0x09, /* [9] general purpose port data */ 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */};static uchar* leaf21140[] = { en1207, /* Accton EN1207-COMBO */ ana6910fx, /* Adaptec (Cogent) ANA-6910FX */ smc9332, /* SMC 9332 */ 0,};static intsrom(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; } } /* * 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->pcidev->did == 0x0009){ 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->pcidev->did == 0x0019 && *(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); if(phy){ x = 0; for(k = 0; k < nelem(ctlr->phy); k++){ if((oui = miir(ctlr, k, 2)) == -1 || oui == 0) continue; if(DEBUG){ oui = (oui & 0x3FF)<<6; oui |= miir(ctlr, k, 3)>>10; miir(ctlr, k, 1); debug("phy%d: index %d oui %uX reg1 %uX\n", x, k, oui, miir(ctlr, k, 1)); USED(oui); } ctlr->phy[x] = k; } } ctlr->fd = 0; ctlr->medium = -1; return 0;}static voiddec2114xpci(void){ Ctlr *ctlr; Pcidev *p; int x; p = nil; while(p = pcimatch(p, 0x1011, 0)){ switch(p->did){ default: continue; case 0x0019: /* 21143 */ /* * Exit sleep mode. */ x = pcicfgr32(p, 0x40); x &= ~0xc0000000; pcicfgw32(p, 0x40, x); /*FALLTHROUGH*/ case 0x0009: /* 21140 */ break; } /* * bar[0] is the I/O port register address and * bar[1] is the memory-mapped register address. */ ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[0].bar & ~0x01; ctlr->pcidev = p; debug("2114x: type 0x%4.4uX at port 0x%4.4uX\n", p->did, ctlr->port); /* * 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; } if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; }}static voiddetach(Ether* ether){ softreset(ether->ctlr);}intether2114xreset(Ether* ether){ Ctlr *ctlr; int i, x; uchar ea[Eaddrlen]; static int scandone; if(scandone == 0){ dec2114xpci(); scandone = 1; } /* * Any adapter matches if no ether->port is supplied, * otherwise the ports must match. */ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(ether->port == 0 || ether->port == ctlr->port){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; ether->ctlr = ctlr; ether->port = ctlr->port; ether->irq = ctlr->pcidev->intl; ether->tbdf = ctlr->pcidev->tbdf; /* * 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, Eaddrlen); if(memcmp(ea, ether->ea, Eaddrlen) == 0) memmove(ether->ea, ctlr->sromea, Eaddrlen); /* * 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; switch(ctlr->medium){ default: ctlr->fd = 0; break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ ctlr->fd = 1; break; } break; } } /* * Determine media. */ ctlr->mbps = media(ether, 1); /* * Initialise descriptor rings, ethernet address. */ ctlr->nrdr = Nrde; ctlr->ntdr = Ntde; pcisetbme(ctlr->pcidev); ctlrinit(ether); /* * Linkage to the generic ethernet driver. */ ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt; ether->detach = detach; return 0;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -