📄 etherigbe.c
字号:
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; if (ctlr == nil) return -1; /* * 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. * * The alpha needs the rest of this routine to run at splhi * or else the card interrupts and resets the processor. Don't know * why. Since the alpha isn't important any more, let's ignore that. */ csr32w(ctlr, Imc, ~0); csr32w(ctlr, Rctl, 0); csr32w(ctlr, Tctl, 0); delay(10); /* was 10 then 100 */ csr32w(ctlr, Ctrl, Devrst); delay(1); /* was 100 */ 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); /* was 100 */ 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);}intetherigbereset(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)){ /* ccru is a short in the FS kernel, thus the cast to uchar */ if(p->ccrb != 0x02 ||#ifdef FS (uchar)#endif 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; } /* cast for FS */ mem = (void *)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; } /* * from etherga620.c: * If PCI Write-and-Invalidate is enabled set the max write DMA * value to the host cache-line size (32 on Pentium or later). */ if(p->pcr & MemWrInv){ cls = pcicfgr8(p, PciCLS) * 4; if(cls != CACHELINESZ) pcicfgw8(p, PciCLS, CACHELINESZ/4); } cls = pcicfgr8(p, PciCLS); switch(cls){ default: print("igbe: unexpected CLS - %d bytes\n", cls*sizeof(long)); break; case 0x00: case 0xFF: /* alphapc 164lx returns 0 */ print("igbe: unusable PciCLS: %d, using %d longs\n", cls, CACHELINESZ/sizeof(long)); cls = CACHELINESZ/sizeof(long); pcicfgw8(p, PciCLS, cls); break; case 0x08: case 0x10: break; } ctlr = malloc(sizeof(Ctlr)); if (ctlr == nil) panic("ibgepci: no mem"); 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(etherigbereset(ctlr)){ free(ctlr); continue; } pcisetbme(p); if(igbectlrhead != nil) igbectlrtail->next = ctlr; else igbectlrhead = ctlr; igbectlrtail = ctlr; }}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;#ifndef FS edev->ifstat = igbeifstat; edev->ctl = igbectl; edev->arg = edev; edev->promiscuous = igbepromiscuous; edev->shutdown = igbeshutdown; edev->multicast = igbemulticast;#endif return 0;}#ifndef FSvoidetherigbebothlink(void){ addethercard("i82543", igbepnp); addethercard("igbe", igbepnp);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -