📄 etherigbe.c
字号:
* * Preamble; * ST+OP+PHYAD+REGAD; * TA + 16 data bits. */ i82543mdiow(ctlr, 0xFFFFFFFF, 32); i82543mdiow(ctlr, 0x1800|(pa<<5)|ra, 14); data = i82543mdior(ctlr, 18); if(data & 0x10000) return -1; return data & 0xFFFF;}static inti82543miimiw(Mii* mii, int pa, int ra, int data){ Ctlr *ctlr; ctlr = mii->ctlr; /* * MII Management Interface Write. * * Preamble; * ST+OP+PHYAD+REGAD+TA + 16 data bits; * Z. */ i82543mdiow(ctlr, 0xFFFFFFFF, 32); data &= 0xFFFF; data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16); i82543mdiow(ctlr, data, 32); return 0;}static intigbemiimir(Mii* mii, int pa, int ra){ Ctlr *ctlr; int mdic, timo; ctlr = mii->ctlr; csr32w(ctlr, Mdic, MDIrop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)); mdic = 0; for(timo = 64; timo; timo--){ mdic = csr32r(ctlr, Mdic); if(mdic & (MDIe|MDIready)) break; microdelay(1); } if((mdic & (MDIe|MDIready)) == MDIready) return mdic & 0xFFFF; return -1;}static intigbemiimiw(Mii* mii, int pa, int ra, int data){ Ctlr *ctlr; int mdic, timo; ctlr = mii->ctlr; data &= MDIdMASK; csr32w(ctlr, Mdic, MDIwop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)|data); mdic = 0; for(timo = 64; timo; timo--){ mdic = csr32r(ctlr, Mdic); if(mdic & (MDIe|MDIready)) break; microdelay(1); } if((mdic & (MDIe|MDIready)) == MDIready) return 0; return -1;}static intigbemii(Ctlr* ctlr){ MiiPhy *phy; int ctrl, p, r; r = csr32r(ctlr, Status); if(r & Tbimode) return -1; if((ctlr->mii = malloc(sizeof(Mii))) == nil) return -1; ctlr->mii->ctlr = ctlr; ctrl = csr32r(ctlr, Ctrl); ctrl |= Slu; switch(ctlr->id){ case i82543gc: ctrl |= Frcdplx|Frcspd; csr32w(ctlr, Ctrl, ctrl); /* * The reset pin direction (Mdro) should already * be set from the EEPROM load. * If it's not set this configuration is unexpected * so bail. */ r = csr32r(ctlr, Ctrlext); if(!(r & Mdro)) return -1; csr32w(ctlr, Ctrlext, r); delay(20); r = csr32r(ctlr, Ctrlext); r &= ~Mdr; csr32w(ctlr, Ctrlext, r); delay(20); r = csr32r(ctlr, Ctrlext); r |= Mdr; csr32w(ctlr, Ctrlext, r); delay(20); ctlr->mii->mir = i82543miimir; ctlr->mii->miw = i82543miimiw; break; case i82544ei: case i82547ei: case i82540em: case i82540eplp: case i82547gi: case i82541gi: case i82541gi2: case i82541pi: case i82545gmc: case i82546gb: case i82546eb: ctrl &= ~(Frcdplx|Frcspd); csr32w(ctlr, Ctrl, ctrl); ctlr->mii->mir = igbemiimir; ctlr->mii->miw = igbemiimiw; break; default: free(ctlr->mii); ctlr->mii = nil; return -1; } if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){ free(ctlr->mii); ctlr->mii = nil; return -1; } USED(phy); // print("oui %X phyno %d\n", phy->oui, phy->phyno); /* * 8254X-specific PHY registers not in 802.3: * 0x10 PHY specific control * 0x14 extended PHY specific control * Set appropriate values then reset the PHY to have * changes noted. */ switch(ctlr->id){ case i82547gi: case i82541gi: case i82541gi2: case i82541pi: case i82545gmc: case i82546gb: case i82546eb: break; default: r = miimir(ctlr->mii, 16); r |= 0x0800; /* assert CRS on Tx */ r |= 0x0060; /* auto-crossover all speeds */ r |= 0x0002; /* polarity reversal enabled */ miimiw(ctlr->mii, 16, r); r = miimir(ctlr->mii, 20); r |= 0x0070; /* +25MHz clock */ r &= ~0x0F00; r |= 0x0100; /* 1x downshift */ miimiw(ctlr->mii, 20, r); miireset(ctlr->mii); p = 0; if(ctlr->txcw & TxcwPs) p |= AnaP; if(ctlr->txcw & TxcwAs) p |= AnaAP; miiane(ctlr->mii, ~0, p, ~0); break; } return 0;}static intat93c46io(Ctlr* ctlr, char* op, int data){ char *lp, *p; int i, loop, eecd, r; eecd = csr32r(ctlr, Eecd); r = 0; loop = -1; lp = nil; for(p = op; *p != '\0'; p++){ switch(*p){ default: return -1; case ' ': continue; case ':': /* start of loop */ loop = strtol(p+1, &lp, 0)-1; lp--; if(p == lp) loop = 7; p = lp; continue; case ';': /* end of loop */ if(lp == nil) return -1; loop--; if(loop >= 0) p = lp; else lp = nil; continue; case 'C': /* assert clock */ eecd |= Sk; break; case 'c': /* deassert clock */ eecd &= ~Sk; break; case 'D': /* next bit in 'data' byte */ if(loop < 0) return -1; if(data & (1<<loop)) eecd |= Di; else eecd &= ~Di; break; case 'O': /* collect data output */ i = (csr32r(ctlr, Eecd) & Do) != 0; if(loop >= 0) r |= (i<<loop); else r = i; continue; case 'I': /* assert data input */ eecd |= Di; break; case 'i': /* deassert data input */ eecd &= ~Di; break; case 'S': /* enable chip select */ eecd |= Cs; break; case 's': /* disable chip select */ eecd &= ~Cs; break; } csr32w(ctlr, Eecd, eecd); microdelay(50); } if(loop >= 0) return -1; return r;}static intat93c46r(Ctlr* ctlr){ ushort sum; char rop[20]; int addr, areq, bits, data, eecd, i; eecd = csr32r(ctlr, Eecd); if(eecd & Spi){ print("igbe: SPI EEPROM access not implemented\n"); return 0; } if(eecd & (Eeszaddr|Eesz256)) bits = 8; else bits = 6; sum = 0; switch(ctlr->id){ default: areq = 0; break; case i82541gi: case i82547gi: case i82540em: case i82540eplp: case i82541pi: case i82541gi2: case i82545gmc: case i82546gb: case i82546eb: areq = 1; csr32w(ctlr, Eecd, eecd|Areq); for(i = 0; i < 1000; i++){ if((eecd = csr32r(ctlr, Eecd)) & Agnt) break; microdelay(5); } if(!(eecd & Agnt)){ print("igbe: not granted EEPROM access\n"); goto release; } break; } snprint(rop, sizeof(rop), "S :%dDCc;", bits+3); for(addr = 0; addr < 0x40; addr++){ /* * Read a word at address 'addr' from the Atmel AT93C46 * 3-Wire Serial EEPROM or compatible. The EEPROM access is * controlled by 4 bits in Eecd. See the AT93C46 datasheet * for protocol details. */ if(at93c46io(ctlr, rop, (0x06<<bits)|addr) != 0){ print("igbe: can't set EEPROM address 0x%2.2X\n", addr); goto release; } data = at93c46io(ctlr, ":16COc;", 0); at93c46io(ctlr, "sic", 0); ctlr->eeprom[addr] = data; sum += data; }release: if(areq) csr32w(ctlr, Eecd, eecd & ~Areq); return sum;}static intigbedetach(Ctlr* ctlr){ int r, timeo; /* * Perform a device reset to get the chip back to the * power-on state, followed by an EEPROM reset to read * the defaults for some internal registers. */ csr32w(ctlr, Imc, ~0); csr32w(ctlr, Rctl, 0); csr32w(ctlr, Tctl, 0); delay(10); csr32w(ctlr, Ctrl, Devrst); delay(1); for(timeo = 0; timeo < 1000; timeo++){ if(!(csr32r(ctlr, Ctrl) & Devrst)) break; delay(1); } if(csr32r(ctlr, Ctrl) & Devrst) return -1; r = csr32r(ctlr, Ctrlext); csr32w(ctlr, Ctrlext, r|Eerst); delay(1); for(timeo = 0; timeo < 1000; timeo++){ if(!(csr32r(ctlr, Ctrlext) & Eerst)) break; delay(1); } if(csr32r(ctlr, Ctrlext) & Eerst) return -1; switch(ctlr->id){ default: break; case i82540em: case i82540eplp: case i82541gi: case i82541pi: case i82547gi: case i82541gi2: case i82545gmc: case i82546gb: case i82546eb: r = csr32r(ctlr, Manc); r &= ~Arpen; csr32w(ctlr, Manc, r); break; } csr32w(ctlr, Imc, ~0); delay(1); for(timeo = 0; timeo < 1000; timeo++){ if(!csr32r(ctlr, Icr)) break; delay(1); } if(csr32r(ctlr, Icr)) return -1; return 0;}static voidigbeshutdown(Ether* ether){ igbedetach(ether->ctlr);}static intigbereset(Ctlr* ctlr){ int ctrl, i, pause, r, swdpio, txcw; if(igbedetach(ctlr)) return -1; /* * Read the EEPROM, validate the checksum * then get the device back to a power-on state. */ if((r = at93c46r(ctlr)) != 0xBABA){ print("igbe: bad EEPROM checksum - 0x%4.4uX\n", r); return -1; } /* * Snarf and set up the receive addresses. * There are 16 addresses. The first should be the MAC address. * The others are cleared and not marked valid (MS bit of Rah). */ if ((ctlr->id == i82546gb || ctlr->id == i82546eb) && BUSFNO(ctlr->pcidev->tbdf) == 1) ctlr->eeprom[Ea+2] += 0x100; // second interface for(i = Ea; i < Eaddrlen/2; i++){if(i == Ea && ctlr->id == i82541gi && ctlr->eeprom[i] == 0xFFFF) ctlr->eeprom[i] = 0xD000; ctlr->ra[2*i] = ctlr->eeprom[i]; ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8; } r = (ctlr->ra[3]<<24)|(ctlr->ra[2]<<16)|(ctlr->ra[1]<<8)|ctlr->ra[0]; csr32w(ctlr, Ral, r); r = 0x80000000|(ctlr->ra[5]<<8)|ctlr->ra[4]; csr32w(ctlr, Rah, r); for(i = 1; i < 16; i++){ csr32w(ctlr, Ral+i*8, 0); csr32w(ctlr, Rah+i*8, 0); } /* * Clear the Multicast Table Array. * It's a 4096 bit vector accessed as 128 32-bit registers. */ memset(ctlr->mta, 0, sizeof(ctlr->mta)); for(i = 0; i < 128; i++) csr32w(ctlr, Mta+i*4, 0); /* * Just in case the Eerst didn't load the defaults * (doesn't appear to fully on the 8243GC), do it manually. */ if (ctlr->id == i82543gc) { // 82543 txcw = csr32r(ctlr, Txcw); txcw &= ~(TxcwAne|TxcwPauseMASK|TxcwFd); ctrl = csr32r(ctlr, Ctrl); ctrl &= ~(SwdpioloMASK|Frcspd|Ilos|Lrst|Fd); if(ctlr->eeprom[Icw1] & 0x0400){ ctrl |= Fd; txcw |= TxcwFd; } if(ctlr->eeprom[Icw1] & 0x0200) ctrl |= Lrst; if(ctlr->eeprom[Icw1] & 0x0010) ctrl |= Ilos; if(ctlr->eeprom[Icw1] & 0x0800) ctrl |= Frcspd; swdpio = (ctlr->eeprom[Icw1] & 0x01E0)>>5; ctrl |= swdpio<<SwdpioloSHIFT; csr32w(ctlr, Ctrl, ctrl); ctrl = csr32r(ctlr, Ctrlext); ctrl &= ~(Ips|SwdpiohiMASK); swdpio = (ctlr->eeprom[Icw2] & 0x00F0)>>4; if(ctlr->eeprom[Icw1] & 0x1000) ctrl |= Ips; ctrl |= swdpio<<SwdpiohiSHIFT; csr32w(ctlr, Ctrlext, ctrl); if(ctlr->eeprom[Icw2] & 0x0800) txcw |= TxcwAne; pause = (ctlr->eeprom[Icw2] & 0x3000)>>12; txcw |= pause<<TxcwPauseSHIFT; switch(pause){ default: ctlr->fcrtl = 0x00002000; ctlr->fcrth = 0x00004000; txcw |= TxcwAs|TxcwPs; break; case 0: ctlr->fcrtl = 0x00002000; ctlr->fcrth = 0x00004000; break; case 2: ctlr->fcrtl = 0; ctlr->fcrth = 0; txcw |= TxcwAs; break; } ctlr->txcw = txcw; csr32w(ctlr, Txcw, txcw); } /* * Flow control - values from the datasheet. */ csr32w(ctlr, Fcal, 0x00C28001); csr32w(ctlr, Fcah, 0x00000100); csr32w(ctlr, Fct, 0x00008808); csr32w(ctlr, Fcttv, 0x00000100); csr32w(ctlr, Fcrtl, ctlr->fcrtl); csr32w(ctlr, Fcrth, ctlr->fcrth); if(!(csr32r(ctlr, Status) & Tbimode) && igbemii(ctlr) < 0) return -1; return 0;}static voidigbepci(void){ int cls; Pcidev *p; Ctlr *ctlr; void *mem; p = nil; while(p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x02 || p->ccru != 0) continue; switch((p->did<<16)|p->vid){ default: continue; case i82543gc: case i82544ei: case i82547ei: case i82540em: case i82540eplp: case i82541gi: case i82547gi: case i82541gi2: case i82541pi: case i82545gmc: case i82546gb: case i82546eb: break; } mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size); if(mem == nil){ print("igbe: can't map %8.8luX\n", p->mem[0].bar); continue; } cls = pcicfgr8(p, PciCLS); switch(cls){ default: print("igbe: unexpected CLS - %d\n", cls*4); break; case 0x00: case 0xFF: print("igbe: unusable CLS\n"); continue; case 0x08: case 0x10: break; } ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[0].bar & ~0x0F; ctlr->pcidev = p; ctlr->id = (p->did<<16)|p->vid; ctlr->cls = cls*4; ctlr->nic = mem; if(igbereset(ctlr)){ free(ctlr); vunmap(mem, p->mem[0].size); continue; } pcisetbme(p); if(igbectlrhead != nil) igbectlrtail->next = ctlr; else igbectlrhead = ctlr; igbectlrtail = ctlr; }}static intigbepnp(Ether* edev){ Ctlr *ctlr; if(igbectlrhead == nil) igbepci(); /* * Any adapter matches if no edev->port is supplied, * otherwise the ports must match. */ for(ctlr = igbectlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(edev->port == 0 || edev->port == ctlr->port){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; edev->ctlr = ctlr; edev->port = ctlr->port; edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; edev->mbps = 1000; memmove(edev->ea, ctlr->ra, Eaddrlen); /* * Linkage to the generic ethernet driver. */ edev->attach = igbeattach; edev->transmit = igbetransmit; edev->interrupt = igbeinterrupt; edev->ifstat = igbeifstat; edev->ctl = igbectl; edev->arg = edev; edev->promiscuous = igbepromiscuous; edev->shutdown = igbeshutdown; edev->multicast = igbemulticast; return 0;}voidetherigbelink(void){ addethercard("i82543", igbepnp); addethercard("igbe", igbepnp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -