📄 ether82543gc.c
字号:
{ Ctlr *ctlr; Ether *edev; int icr; edev = arg; ctlr = edev->ctlr; while((icr = csr32r(ctlr, Icr) & ctlr->im) != 0){ /* * Link status changed. */ if(icr & (Lsc|Rxseq)) linkintr(ctlr); /* * Process recv buffers. */ gc82543recv(edev, icr); /* * Refill transmit ring and free packets. */ gc82543transmit(edev); }}static intgc82543init(Ether* edev){ int csr, i; Block *bp; Ctlr *ctlr; ctlr = edev->ctlr; /* * Allocate private buffer pool to use for receiving packets. */ ilock(&freelistlock); if (ctlr->freehead == nil){ for(i = 0; i < Nblocks; i++){ bp = iallocb(SBLOCKSIZE); if(bp != nil){ bp->next = freeShortHead; bp->free = freegc82543short; freeShortHead = bp; } else{ print("82543gc: no memory\n"); break; } } ctlr->freehead = &freeShortHead; } iunlock(&freelistlock); /* * 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). */ csr = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0]; csr32w(ctlr, Ral, csr); csr = 0x80000000|(edev->ea[5]<<8)|edev->ea[4]; csr32w(ctlr, Rah, csr); 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. */ for(i = 0; i < 128; i++) csr32w(ctlr, Mta+i*4, 0); gc82543txinit(ctlr); gc82543rxinit(ctlr); 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 */ if(lp != nil){ if(p != (lp+1) || loop != 7) return -1; lp = p; loop = 15; continue; } lp = p; loop = 7; 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(1); } if(loop >= 0) return -1; return r;}static intat93c46r(Ctlr* ctlr){ ushort sum; int addr, data; sum = 0; 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, "S ICc :DCc;", (0x02<<6)|addr) != 0) break; data = at93c46io(ctlr, "::COc;", 0); at93c46io(ctlr, "sic", 0); ctlr->eeprom[addr] = data; sum += data; } return sum;}static voidgc82543detach(Ctlr* ctlr){ /* * 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); while(csr32r(ctlr, Ctrl) & Devrst) ; csr32w(ctlr, Ctrlext, Eerst); while(csr32r(ctlr, Ctrlext) & Eerst) ; csr32w(ctlr, Imc, ~0); while(csr32r(ctlr, Icr)) ;}static voidgc82543checklink(Ctlr* ctlr){ int ctrl, status, rxcw; ctrl = csr32r(ctlr, Ctrl); status = csr32r(ctlr, Status); rxcw = csr32r(ctlr, Rxcw); if(!(status & Lu)){ if(!(ctrl & (Swdpin1|Slu)) && !(rxcw & Rxconfig)){ csr32w(ctlr, Txcw, ctlr->txcw & ~Ane); ctrl |= (Slu|Fd); if(ctlr->txcw & As) ctrl |= Rfce; if(ctlr->txcw & Ps) ctrl |= Tfce; csr32w(ctlr, Ctrl, ctrl); } } else if((ctrl & Slu) && (rxcw & Rxconfig)){ csr32w(ctlr, Txcw, ctlr->txcw); ctrl &= ~(Slu|Fd); csr32w(ctlr, Ctrl, ctrl); }}static voidgc82543shutdown(Ether* ether){ gc82543detach(ether->ctlr);}static intgc82543reset(Ctlr* ctlr){ int ctl; int te; /* * Read the EEPROM, validate the checksum * then get the device back to a power-on state. */ if(at93c46r(ctlr) != 0xBABA) return -1; gc82543detach(ctlr); te = ctlr->eeprom[Icw2]; if((te & 0x3000) == 0){ ctlr->fcrtl = 0x00002000; ctlr->fcrth = 0x00004000; ctlr->txcw = Ane|TxcwFd; } else if((te & 0x3000) == 0x2000){ ctlr->fcrtl = 0; ctlr->fcrth = 0; ctlr->txcw = Ane|TxcwFd|As; } else{ ctlr->fcrtl = 0x00002000; ctlr->fcrth = 0x00004000; ctlr->txcw = Ane|TxcwFd|As|Ps; } csr32w(ctlr, Txcw, ctlr->txcw); csr32w(ctlr, Ctrlext, (te & 0x00f0)<<4); csr32w(ctlr, Tctl, csr32r(ctlr, Tctl)|(64<<ColdSHIFT)); te = ctlr->eeprom[Icw1]; ctl = ((te & 0x01E0)<<17)|(te & 0x0010)<<3; csr32w(ctlr, Ctrl, ctl); delay(10); /* * 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); ctlr->im = Lsc; gc82543checklink(ctlr); return 0;}static voidgc82543watchdog(void* arg){ Ether *edev; Ctlr *ctlr; edev = arg; for(;;){ tsleep(&up->sleep, return0, 0, 1000); ctlr = edev->ctlr; if(ctlr == nil){ print("%s: exiting\n", up->text); pexit("disabled", 0); } gc82543checklink(ctlr); gc82543replenish(ctlr); }}static voidgc82543pci(void){ int cls; void *mem; Pcidev *p; Ctlr *ctlr; p = nil; while(p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x02 || p->ccru != 0) continue; switch((p->did<<16)|p->vid){ case (0x1000<<16)|0x8086: /* LSI L2A1157 (82542) */ case (0x1004<<16)|0x8086: /* Intel PRO/1000 T */ case (0x1008<<16)|0x8086: /* Intel PRO/1000 XT */ default: continue; case (0x1001<<16)|0x8086: /* Intel PRO/1000 F */ break; } mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size); if(mem == 0){ print("gc82543: can't map %8.8luX\n", p->mem[0].bar); continue; } cls = pcicfgr8(p, PciCLS); switch(cls){ case 0x00: case 0xFF: print("82543gc: unusable cache line size\n"); continue; case 0x08: break; default: print("82543gc: cache line size %d, expected 32\n", cls*4); } ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[0].bar & ~0x0F; ctlr->pcidev = p; ctlr->id = (p->did<<16)|p->vid; ctlr->nic = mem; if(gc82543reset(ctlr)){ free(ctlr); continue; } if(gc82543ctlrhead != nil) gc82543ctlrtail->next = ctlr; else gc82543ctlrhead = ctlr; gc82543ctlrtail = ctlr; }}static intgc82543pnp(Ether* edev){ int i; Ctlr *ctlr; uchar ea[Eaddrlen]; if(gc82543ctlrhead == nil) gc82543pci(); /* * Any adapter matches if no edev->port is supplied, * otherwise the ports must match. */ for(ctlr = gc82543ctlrhead; 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; /* * 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, edev->ea, Eaddrlen) == 0){ for(i = Ea; i < Eaddrlen/2; i++){ edev->ea[2*i] = ctlr->eeprom[i]; edev->ea[2*i+1] = ctlr->eeprom[i]>>8; } } gc82543init(edev); /* * Linkage to the generic ethernet driver. */ edev->attach = gc82543attach; edev->transmit = gc82543transmit; edev->interrupt = gc82543interrupt; edev->ifstat = gc82543ifstat; edev->shutdown = gc82543shutdown; edev->ctl = gc82543ctl; edev->arg = edev; edev->promiscuous = gc82543promiscuous; edev->multicast = gc82543multicast; return 0;}voidether82543gclink(void){ addethercard("82543GC", gc82543pnp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -