📄 ether82557.c
字号:
if(pbp != nil) etheriq(ether, pbp, 1); } else{ rfd->count = 0; rfd->field = 0; } /* * The ring tail pointer follows the head with with one * unused buffer in between to defeat hardware prefetch; * once the tail pointer has been bumped on to the next * and the new tail has the Suspend bit set, it can be * removed from the old tail buffer. * As a replacement for the current head buffer may have * been allocated above, ensure that the new tail points * to it (next and link). */ rfd = (Rfd*)ctlr->rfdtail->rp; ctlr->rfdtail = ctlr->rfdtail->next; ctlr->rfdtail->next = bp; ((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); ((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; coherence(); rfd->field &= ~RfdS; /* * Finally done with the current (possibly replaced) * head, move on to the next and maintain the sentinel * between tail and head. */ ctlr->rfdhead = bp->next; bp = ctlr->rfdhead; }}static voidinterrupt(Ureg*, void* arg){ Cb* cb; Ctlr *ctlr; Ether *ether; int status; ether = arg; ctlr = ether->ctlr; for(;;){ ilock(&ctlr->rlock); status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); iunlock(&ctlr->rlock); if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) break; /* * If the watchdog timer for the receiver lockup errata is running, * let it know the receiver is active. */ if(status & (StatFR|StatRNR)){ ilock(&ctlr->cblock); ctlr->tick = 0; iunlock(&ctlr->cblock); } if(status & StatFR){ receive(ether); status &= ~StatFR; } if(status & StatRNR){ command(ctlr, RUresume, 0); status &= ~StatRNR; } if(status & StatCNA){ ilock(&ctlr->cblock); cb = ctlr->cbtail; while(ctlr->cbq){ if(!(cb->status & CbC)) break; if(cb->bp){ freeb(cb->bp); cb->bp = nil; } if((cb->status & CbU) && ctlr->threshold < 0xE0) ctlr->threshold++; ctlr->cbq--; cb = cb->next; } ctlr->cbtail = cb; txstart(ether); iunlock(&ctlr->cblock); status &= ~StatCNA; } if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) panic("#l%d: status %uX\n", ether->ctlrno, status); }}static voidctlrinit(Ctlr* ctlr){ int i; Block *bp; Rfd *rfd; ulong link; /* * Create the Receive Frame Area (RFA) as a ring of allocated * buffers. * A sentinel buffer is maintained between the last buffer in * the ring (marked with RfdS) and the head buffer to defeat the * hardware prefetch of the next RFD and allow dynamic buffer * allocation. */ link = NullPointer; for(i = 0; i < Nrfd; i++){ bp = rfdalloc(link); if(ctlr->rfdhead == nil) ctlr->rfdtail = bp; bp->next = ctlr->rfdhead; ctlr->rfdhead = bp; link = PADDR(bp->rp); } ctlr->rfdtail->next = ctlr->rfdhead; rfd = (Rfd*)ctlr->rfdtail->rp; rfd->link = PADDR(ctlr->rfdhead->rp); rfd->field |= RfdS; ctlr->rfdhead = ctlr->rfdhead->next; /* * Create a ring of control blocks for the * transmit side. */ ilock(&ctlr->cblock); ctlr->cbr = malloc(ctlr->ncb*sizeof(Cb)); for(i = 0; i < ctlr->ncb; i++){ ctlr->cbr[i].status = CbC|CbOK; ctlr->cbr[i].command = CbS|CbNOP; ctlr->cbr[i].link = PADDR(&ctlr->cbr[NEXT(i, ctlr->ncb)].status); ctlr->cbr[i].next = &ctlr->cbr[NEXT(i, ctlr->ncb)]; } ctlr->cbhead = ctlr->cbr; ctlr->cbtail = ctlr->cbr; ctlr->cbq = 0; memmove(ctlr->configdata, configdata, sizeof(configdata)); ctlr->threshold = 80; ctlr->tick = 0; iunlock(&ctlr->cblock);}static intmiir(Ctlr* ctlr, int phyadd, int regadd){ int mcr, timo; lock(&ctlr->miilock); csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16)); mcr = 0; for(timo = 64; timo; timo--){ mcr = csr32r(ctlr, Mcr); if(mcr & MDIready) break; microdelay(1); } unlock(&ctlr->miilock); if(mcr & MDIready) return mcr & 0xFFFF; return -1;}static intmiiw(Ctlr* ctlr, int phyadd, int regadd, int data){ int mcr, timo; lock(&ctlr->miilock); csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF)); mcr = 0; for(timo = 64; timo; timo--){ mcr = csr32r(ctlr, Mcr); if(mcr & MDIready) break; microdelay(1); } unlock(&ctlr->miilock); if(mcr & MDIready) return 0; return -1;}static inthy93c46r(Ctlr* ctlr, int r){ int i, op, data; /* * Hyundai HY93C46 or equivalent serial EEPROM. * This sequence for reading a 16-bit register 'r' * in the EEPROM is taken straight from Section * 3.3.4.2 of the Intel 82557 User's Guide. */ csr16w(ctlr, Ecr, EEcs); op = EEstart|EEread; for(i = 2; i >= 0; i--){ data = (((op>>i) & 0x01)<<2)|EEcs; csr16w(ctlr, Ecr, data); csr16w(ctlr, Ecr, data|EEsk); microdelay(1); csr16w(ctlr, Ecr, data); microdelay(1); } for(i = EEaddrsz-1; i >= 0; i--){ data = (((r>>i) & 0x01)<<2)|EEcs; csr16w(ctlr, Ecr, data); csr16w(ctlr, Ecr, data|EEsk); delay(1); csr16w(ctlr, Ecr, data); microdelay(1); if(!(csr16r(ctlr, Ecr) & EEdo)) break; } data = 0; for(i = 15; i >= 0; i--){ csr16w(ctlr, Ecr, EEcs|EEsk); microdelay(1); if(csr16r(ctlr, Ecr) & EEdo) data |= (1<<i); csr16w(ctlr, Ecr, EEcs); microdelay(1); } csr16w(ctlr, Ecr, 0); return data;}typedef struct Adapter { int port; int irq; int tbdf;} Adapter;static Block* adapter;static voidi82557adapter(Block** bpp, int port, int irq, int tbdf){ Block *bp; Adapter *ap; bp = allocb(sizeof(Adapter)); ap = (Adapter*)bp->rp; ap->port = port; ap->irq = irq; ap->tbdf = tbdf; bp->next = *bpp; *bpp = bp;}static voidi82557pci(void){ Pcidev *p; int port; p = nil; while(p = pcimatch(p, 0x8086, 0x1229)){ /* * bar[0] is the memory-mapped register address (4KB), * bar[1] is the I/O port register address (32 bytes) and * bar[2] is for the flash ROM (1MB). */ port = p->mem[1].bar & ~0x01; if(ioalloc(port, p->mem[1].size, 0, "i82557pci") < 0){ print("i82557pci: port %d in use\n", port); continue; } i82557adapter(&adapter, port, p->intl, p->tbdf); pcisetbme(p); }}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 intscanphy(Ctlr* ctlr){ int i, oui, x; for(i = 0; i < 32; i++){ if((oui = miir(ctlr, i, 2)) == -1 || oui == 0 || oui == 0xFFFF) continue; oui <<= 6; x = miir(ctlr, i, 3); oui |= x>>10; //print("phy%d: oui %uX reg1 %uX\n", i, oui, miir(ctlr, i, 1)); ctlr->eeprom[6] = i; if(oui == 0xAA00) ctlr->eeprom[6] |= 0x07<<8; else if(oui == 0x80017){ if(x & 0x01) ctlr->eeprom[6] |= 0x0A<<8; else ctlr->eeprom[6] |= 0x04<<8; } return i; } return -1;}static intreset(Ether* ether){ int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, port, x; unsigned short sum; Block *bp, **bpp; Adapter *ap; uchar ea[Eaddrlen]; Ctlr *ctlr; static int scandone; if(scandone == 0){ i82557pci(); scandone = 1; } /* * Any adapter matches if no port is supplied, * otherwise the ports must match. */ port = 0; bpp = &adapter; for(bp = *bpp; bp; bp = bp->next){ ap = (Adapter*)bp->rp; if(ether->port == 0 || ether->port == ap->port){ port = ap->port; ether->irq = ap->irq; ether->tbdf = ap->tbdf; *bpp = bp->next; freeb(bp); break; } bpp = &bp->next; } if(port == 0) return -1; /* * Allocate a controller structure and start to initialise it. * Perform a software reset after which should ensure busmastering * is still enabled. The EtherExpress PRO/100B appears to leave * the PCI configuration alone (see the 'To do' list above) so punt * for now. * Load the RUB and CUB registers for linear addressing (0). */ ether->ctlr = malloc(sizeof(Ctlr)); ctlr = ether->ctlr; ctlr->port = port; ilock(&ctlr->rlock); csr32w(ctlr, Port, 0); delay(1); csr8w(ctlr, Interrupt, InterruptM); iunlock(&ctlr->rlock); command(ctlr, LoadRUB, 0); command(ctlr, LoadCUB, 0); command(ctlr, LoadDCA, PADDR(ctlr->dump)); /* * Initialise the receive frame, transmit ring and configuration areas. */ ctlr->ncb = Ncb; ctlrinit(ctlr); /* * Read the EEPROM. */ sum = 0; for(i = 0; i < 0x40; i++){ x = hy93c46r(ctlr, i); ctlr->eeprom[i] = x; sum += x; } if(sum != 0xBABA) print("#l%d: EEPROM checksum - 0x%4.4uX\n", ether->ctlrno, sum); /* * Eeprom[6] indicates whether there is a PHY and whether * it's not 10Mb-only, in which case use the given PHY address * to set any PHY specific options and determine the speed. * Unfortunately, sometimes the EEPROM is blank except for * the ether address and checksum; in this case look at the * controller type and if 0 scan for the first PHY and try to * use that. * If no PHY, assume 82503 (serial) operation. */ if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)) phyaddr = ctlr->eeprom[6] & 0x00FF; else if(!(ctlr->eeprom[5] & 0xFF00)) phyaddr = scanphy(ctlr); else phyaddr = -1; if(phyaddr >= 0){ /* * Resolve the highest common ability of the two * link partners. In descending order: * 0x0100 100BASE-TX Full Duplex * 0x0200 100BASE-T4 * 0x0080 100BASE-TX * 0x0040 10BASE-T Full Duplex * 0x0020 10BASE-T */ anar = miir(ctlr, phyaddr, 0x04); anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0; anar &= anlpar; bmcr = 0; if(anar & 0x380) bmcr = 0x2000; if(anar & 0x0140) bmcr |= 0x0100; switch((ctlr->eeprom[6]>>8) & 0x001F){ case 0x04: /* DP83840 */ case 0x0A: /* DP83840A */ /* * The DP83840[A] requires some tweaking for * reliable operation. * The manual says bit 10 should be unconditionally * set although it supposedly only affects full-duplex * operation (an & 0x0140). */ x = miir(ctlr, phyaddr, 0x17) & ~0x0520; x |= 0x0420; for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "congestioncontrol")) continue; x |= 0x0100; break; } miiw(ctlr, phyaddr, 0x17, x); /* * If the link partner can't autonegotiate, determine * the speed from elsewhere. */ if(anlpar == 0){ miir(ctlr, phyaddr, 0x01); bmsr = miir(ctlr, phyaddr, 0x01); x = miir(ctlr, phyaddr, 0x19); if((bmsr & 0x0004) && !(x & 0x0040)) bmcr = 0x2000; } break; case 0x07: /* Intel 82555 */ /* * Auto-negotiation may fail if the other end is * a DP83840A and the cable is short. */ miir(ctlr, phyaddr, 0x01); bmsr = miir(ctlr, phyaddr, 0x01); if((miir(ctlr, phyaddr, 0) & 0x1000) && !(bmsr & 0x0020)){ miiw(ctlr, phyaddr, 0x1A, 0x2010); x = miir(ctlr, phyaddr, 0); miiw(ctlr, phyaddr, 0, 0x0200|x); for(i = 0; i < 3000; i++){ delay(1); if(miir(ctlr, phyaddr, 0x01) & 0x0020) break; } miiw(ctlr, phyaddr, 0x1A, 0x2000); anar = miir(ctlr, phyaddr, 0x04); anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0; anar &= anlpar; bmcr = 0; if(anar & 0x380) bmcr = 0x2000; if(anar & 0x0140) bmcr |= 0x0100; } break; } /* * Force speed and duplex if no auto-negotiation. */ if(anlpar == 0){ medium = -1; for(i = 0; i < ether->nopt; i++){ for(k = 0; k < nelem(mediatable); k++){ if(cistrcmp(mediatable[k], ether->opt[i])) continue; medium = k; break; } switch(medium){ default: break; case 0x00: /* 10BASE-T */ case 0x01: /* 10BASE-2 */ case 0x02: /* 10BASE-5 */ bmcr &= ~(0x2000|0x0100); ctlr->configdata[19] &= ~0x40; break; case 0x03: /* 100BASE-TX */ case 0x06: /* 100BASE-T4 */ case 0x07: /* 100BASE-FX */ ctlr->configdata[19] &= ~0x40; bmcr |= 0x2000; break; case 0x04: /* 10BASE-TFD */ bmcr = (bmcr & ~0x2000)|0x0100; ctlr->configdata[19] |= 0x40; break; case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ bmcr |= 0x2000|0x0100; ctlr->configdata[19] |= 0x40; break; } } if(medium != -1) miiw(ctlr, phyaddr, 0x00, bmcr); } if(bmcr & 0x2000) ether->mbps = 100; ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; } else{ ctlr->configdata[8] = 0; ctlr->configdata[15] |= 0x80; } /* * Load the chip configuration and start it off. */ if(ether->oq == 0) ether->oq = qopen(256*1024, 1, 0, 0); configure(ether, 0); command(ctlr, CUstart, PADDR(&ctlr->cbr->status)); /* * 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 with the Individual Address Setup command. */ memset(ea, 0, Eaddrlen); if(memcmp(ea, ether->ea, Eaddrlen) == 0){ for(i = 0; i < Eaddrlen/2; i++){ x = ctlr->eeprom[i]; ether->ea[2*i] = x; ether->ea[2*i+1] = x>>8; } } ilock(&ctlr->cblock); ctlr->action = CbIAS; txstart(ether); iunlock(&ctlr->cblock); /* * Linkage to the generic ethernet driver. */ ether->port = port; ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt; ether->ifstat = ifstat; ether->promiscuous = promiscuous; ether->multicast = multicast; ether->arg = ether; return 0;}voidether82557link(void){ addethercard("i82557", reset);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -