📄 ether82557.c
字号:
miir(Ctlr* ctlr, int phyadd, int regadd){ int mcr, timo; 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); } if(mcr & MDIready) return mcr & 0xFFFF; return -1;}static intmiiw(Ctlr* ctlr, int phyadd, int regadd, int data){ int mcr, timo; 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); } if(mcr & MDIready) return 0; return -1;}static inthy93c46r(Ctlr* ctlr, int r){ int data, i, op, size; /* * 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. */reread: 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); } /* * First time through must work out the EEPROM size. */ if((size = ctlr->eepromsz) == 0) size = 8; for(size = size-1; size >= 0; size--){ data = (((r>>size) & 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); if(ctlr->eepromsz == 0){ ctlr->eepromsz = 8-size; ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort)); goto reread; } return data;}static voidi82557pci(void){ Pcidev *p; Ctlr *ctlr; p = nil; while(p = pcimatch(p, 0x8086, 0)){ switch(p->did){ default: continue; case 0x1031: /* Intel 82562EM */ case 0x1050: /* Intel 82562EZ */ case 0x1039: /* Intel 82801BD PRO/100 VE */ case 0x103A: /* Intel 82562 PRO/100 VE */ case 0x1064: /* Intel 82562 PRO/100 VE */ case 0x2449: /* Intel 82562ET */ case 0x1209: /* Intel 82559ER */ case 0x1229: /* Intel 8255[789] */ case 0x1030: /* Intel 82559 InBusiness 10/100 */ break; } /* * 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). */ ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[1].bar & ~0x01; ctlr->pcidev = p; if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; pcisetbme(p); }}static voiddetach(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; csr32w(ctlr, Port, 0); delay(1); while(csr8r(ctlr, CommandR)) ;}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)); 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;}inti82557reset(Ether* ether){ int anar, anlpar, bmcr, bmsr, force, i, phyaddr, x; unsigned short sum; Block *bp; uchar ea[Eaddrlen]; Ctlr *ctlr; Cb *cb; if(ctlrhead == nil) i82557pci(); /* * 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; /* * Initialise the Ctlr structure. * Perform a software reset after which need to 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 = ctlr; ether->port = ctlr->port; ether->irq = ctlr->pcidev->intl; ether->tbdf = ctlr->pcidev->tbdf; ctlr->ctlrno = ether->ctlrno; ctlr->type = ether->type; csr32w(ctlr, Port, 0); delay(1); while(csr8r(ctlr, CommandR)) ; csr32w(ctlr, Pointer, 0); csr8w(ctlr, CommandR, LoadRUB); while(csr8r(ctlr, CommandR)) ; csr8w(ctlr, CommandR, LoadCUB); /* * Initialise the action and receive frame areas. */ ctlrinit(ctlr); /* * Read the EEPROM. * Do a dummy read first to get the size * and allocate ctlr->eeprom. */ hy93c46r(ctlr, 0); sum = 0; for(i = 0; i < (1<<ctlr->eepromsz); 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 it's am 82558 or 82559 it has an * embedded PHY so scan for that. * If no PHY, assume 82503 (serial) operation. */ if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)) phyaddr = ctlr->eeprom[6] & 0x00FF; else switch(ctlr->pcidev->rid){ case 0x01: /* 82557 A-step */ case 0x02: /* 82557 B-step */ case 0x03: /* 82557 C-step */ default: phyaddr = -1; break; case 0x04: /* 82558 A-step */ case 0x05: /* 82558 B-step */ case 0x06: /* 82559 A-step */ case 0x07: /* 82559 B-step */ case 0x08: /* 82559 C-step */ case 0x09: /* 82559ER A-step */ phyaddr = scanphy(ctlr); break; } 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. */ 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){ force = 0; for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "fullduplex") == 0){ force = 1; bmcr |= 0x0100; ctlr->configdata[19] |= 0x40; } else if(cistrcmp(ether->opt[i], "speed") == 0){ force = 1; x = strtol(ðer->opt[i][6], 0, 0); if(x == 10) bmcr &= ~0x2000; else if(x == 100) bmcr |= 0x2000; else force = 0; } } if(force) miiw(ctlr, phyaddr, 0x00, bmcr); } ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; } else{ ctlr->configdata[8] = 0; ctlr->configdata[15] |= 0x80; } /* * Load the chip configuration */ configure(ether, 0); /* * 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 & 0xFF; ether->ea[2*i+1] = (x>>8) & 0xFF; } } bp = allocb(sizeof(Cb)); cb = (Cb*)bp->rp; bp->wp += sizeof(Cb); cb->command = CbIAS; cb->link = NullPointer; memmove(cb->data, ether->ea, Eaddrlen); action(ctlr, bp); /* * Linkage to the generic ethernet driver. */ ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt; ether->detach = detach; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -