📄 ether2114x.c
字号:
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 */ nil,};/* * Copied to ctlr->srom at offset 20. */static uchar leafpnic[] = { 0x00, 0x00, 0x00, 0x00, /* MAC address */ 0x00, 0x00, 0x00, /* controller 0 device number */ 0x1E, 0x00, /* controller 0 info leaf offset */ 0x00, /* reserved */ 0x00, 0x08, /* selected connection type */ 0x00, /* general purpose control */ 0x01, /* block count */ 0x8C, /* format indicator and count */ 0x01, /* block type */ 0x00, /* PHY number */ 0x00, /* GPR sequence length */ 0x00, /* reset sequence length */ 0x00, 0x78, /* media capabilities */ 0xE0, 0x01, /* Nway advertisment */ 0x00, 0x50, /* FDX bitmap */ 0x00, 0x18, /* TTM bitmap */};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; } } /* * 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); 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, 0, 0)){ if(p->ccru != ((0x02<<8)|0x00)) continue; switch((p->did<<16)|p->vid){ default: continue; 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; } if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; }}intether21140reset(Ether* ether){ Ctlr *ctlr; int i, x; uchar ea[Easize]; 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, 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; 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; } } ether->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; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -