/* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full * of smarts, unfortunately none of them are in the right place. * To do: * the PCI scanning code could be made common to other adapters; * PCI code needs rewritten to handle byte, word, dword accesses * and using the devno as a bus+dev+function triplet. */#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h" #include "etherif.h" enum { Nrfd = 4, /* receive frame area */ NullPointer = 0xFFFFFFFF, /* 82557 NULL pointer */}; enum { /* CSR */ Status = 0x00, /* byte or word (word includes Ack) */ Ack = 0x01, /* byte */ CommandR = 0x02, /* byte or word (word includes Interrupt) */ Interrupt = 0x03, /* byte */ Pointer = 0x04, /* dword */ Port = 0x08, /* dword */ Fcr = 0x0C, /* Flash control register */ Ecr = 0x0E, /* EEPROM control register */ Mcr = 0x10, /* MDI control register */}; enum { /* Status */ RUidle = 0x0000, RUsuspended = 0x0004, RUnoresources = 0x0008, RUready = 0x0010, RUrbd = 0x0020, /* bit */ RUstatus = 0x003F, /* mask */ CUidle = 0x0000, CUsuspended = 0x0040, CUactive = 0x0080, CUstatus = 0x00C0, /* mask */ StatSWI = 0x0400, /* SoftWare generated Interrupt */ StatMDI = 0x0800, /* MDI r/w done */ StatRNR = 0x1000, /* Receive unit Not Ready */ StatCNA = 0x2000, /* Command unit Not Active (Active->Idle) */ StatFR = 0x4000, /* Finished Receiving */ StatCX = 0x8000, /* Command eXecuted */ StatTNO = 0x8000, /* Transmit NOT OK */}; enum { /* Command (byte) */ CUnop = 0x00, CUstart = 0x10, CUresume = 0x20, LoadDCA = 0x40, /* Load Dump Counters Address */ DumpSC = 0x50, /* Dump Statistical Counters */ LoadCUB = 0x60, /* Load CU Base */ ResetSA = 0x70, /* Dump and Reset Statistical Counters */ RUstart = 0x01, RUresume = 0x02, RUabort = 0x04, LoadHDS = 0x05, /* Load Header Data Size */ LoadRUB = 0x06, /* Load RU Base */ RBDresume = 0x07, /* Resume frame reception */}; enum { /* Interrupt (byte) */ InterruptM = 0x01, /* interrupt Mask */ InterruptSI = 0x02, /* Software generated Interrupt */}; enum { /* Ecr */ EEsk = 0x01, /* serial clock */ EEcs = 0x02, /* chip select */ EEdi = 0x04, /* serial data in */ EEdo = 0x08, /* serial data out */ EEstart = 0x04, /* start bit */ EEread = 0x02, /* read opcode */}; enum { /* Mcr */ MDIread = 0x08000000, /* read opcode */ MDIwrite = 0x04000000, /* write opcode */ MDIready = 0x10000000, /* ready bit */ MDIie = 0x20000000, /* interrupt enable */}; typedef struct Rfd { int field; ulong link; ulong rbd; ushort count; ushort size; Etherpkt;} Rfd; enum { /* field */ RfdCollision = 0x00000001, RfdIA = 0x00000002, /* IA match */ RfdRxerr = 0x00000010, /* PHY character error */ RfdType = 0x00000020, /* Type frame */ RfdRunt = 0x00000080, RfdOverrun = 0x00000100, RfdBuffer = 0x00000200, RfdAlignment = 0x00000400, RfdCRC = 0x00000800, RfdOK = 0x00002000, /* frame received OK */ RfdC = 0x00008000, /* reception Complete */ RfdSF = 0x00080000, /* Simplified or Flexible (1) Rfd */ RfdH = 0x00100000, /* Header RFD */ RfdI = 0x20000000, /* Interrupt after completion */ RfdS = 0x40000000, /* Suspend after completion */ RfdEL = 0x80000000, /* End of List */}; enum { /* count */ RfdF = 0x00004000, RfdEOF = 0x00008000,}; typedef struct Cb { int command; ulong link; uchar data[24]; /* CbIAS + CbConfigure */} Cb; typedef struct TxCB { int command; ulong link; ulong tbd; ushort count; uchar threshold; uchar number;} TxCB; enum { /* action command */ CbOK = 0x00002000, /* DMA completed OK */ CbC = 0x00008000, /* execution Complete */ CbNOP = 0x00000000, CbIAS = 0x00010000, /* Indvidual Address Setup */ CbConfigure = 0x00020000, CbMAS = 0x00030000, /* Multicast Address Setup */ CbTransmit = 0x00040000, CbDump = 0x00060000, CbDiagnose = 0x00070000, CbCommand = 0x00070000, /* mask */ CbSF = 0x00080000, /* CbTransmit */ CbI = 0x20000000, /* Interrupt after completion */ CbS = 0x40000000, /* Suspend after completion */ CbEL = 0x80000000, /* End of List */}; enum { /* CbTransmit count */ CbEOF = 0x00008000,}; typedef struct Ctlr Ctlr;typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; int eepromsz; /* address size in bits */ ushort* eeprom; int ctlrno; char* type; uchar configdata[24]; Rfd rfd[Nrfd]; int rfdl; int rfdx; Block* cbqhead; Block* cbqtail; int cbqbusy;} Ctlr; static Ctlr* ctlrhead;static Ctlr* ctlrtail; static uchar configdata[24] = { 0x16, /* byte count */ 0x44, /* Rx/Tx FIFO limit */ 0x00, /* adaptive IFS */ 0x00, 0x04, /* Rx DMA maximum byte count */ 0x84, /* Tx DMA maximum byte count */ 0x33, /* late SCB, CNA interrupts */ 0x01, /* discard short Rx frames */ 0x00, /* 503/MII */ 0x00, 0x2E, /* normal operation, NSAI */ 0x00, /* linear priority */ 0x60, /* inter-frame spacing */ 0x00, 0xF2, 0x48, /* promiscuous mode off */ 0x00, 0x40, 0xF2, /* transmit padding enable */ 0x80, /* full duplex pin enable */ 0x3F, /* no Multi IA */ 0x05, /* no Multi Cast ALL */}; #define csr8r(c, r) (inb((c)->port+(r)))#define csr16r(c, r) (ins((c)->port+(r)))#define csr32r(c, r) (inl((c)->port+(r)))#define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))#define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))#define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l))) static voidcustart(Ctlr* ctlr){ if(ctlr->cbqhead == 0){ ctlr->cbqbusy = 0; return; } ctlr->cbqbusy = 1; csr32w(ctlr, Pointer, PADDR(ctlr->cbqhead->rp)); while(csr8r(ctlr, CommandR)) ; csr8w(ctlr, CommandR, CUstart);} static voidaction(Ctlr* ctlr, Block* bp){ Cb *cb; cb = (Cb*)bp->rp; cb->command |= CbEL; if(ctlr->cbqhead){ ctlr->cbqtail->next = bp; cb = (Cb*)ctlr->cbqtail->rp; cb->link = PADDR(bp->rp); cb->command &= ~CbEL; } else ctlr->cbqhead = bp; ctlr->cbqtail = bp; if(ctlr->cbqbusy == 0) custart(ctlr);} static voidattach(Ether* ether){ int status; Ctlr *ctlr; ctlr = ether->ctlr; status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ csr32w(ctlr, Pointer, PADDR(&ctlr->rfd[ctlr->rfdx])); while(csr8r(ctlr, CommandR)) ; csr8w(ctlr, CommandR, RUstart); }} static voidconfigure(void* arg, int promiscuous){ Ctlr *ctlr; Block *bp; Cb *cb; ctlr = ((Ether*)arg)->ctlr; bp = allocb(sizeof(Cb)); cb = (Cb*)bp->rp; bp->wp += sizeof(Cb); cb->command = CbConfigure; cb->link = NullPointer; memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); if(promiscuous) cb->data[15] |= 0x01; action(ctlr, bp);} static voidtransmit(Ether* ether){ Block *bp; TxCB *txcb; RingBuf *tb; for(tb = ðer->tb[ether->ti]; tb->owner == Interface; tb = ðer->tb[ether->ti]){ bp = allocb(tb->len+sizeof(TxCB)); txcb = (TxCB*)bp->wp; bp->wp += sizeof(TxCB); txcb->command = CbTransmit; txcb->link = NullPointer; txcb->tbd = NullPointer; txcb->count = CbEOF|tb->len; txcb->threshold = 2; txcb->number = 0; memmove(bp->wp, tb->pkt, tb->len); memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += tb->len; action(ether->ctlr, bp); tb->owner = Host; ether->ti = NEXT(ether->ti, ether->ntb); }} static voidinterrupt(Ureg*, void* arg){ Rfd *rfd; Block *bp; Ctlr *ctlr; Ether *ether; int status; RingBuf *rb; ether = arg; ctlr = ether->ctlr; for(;;){ status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); if((status & (StatCX|StatFR|StatCNA|StatRNR)) == 0) return; if(status & StatFR){ rfd = &ctlr->rfd[ctlr->rfdx]; while(rfd->field & RfdC){ rb = ðer->rb[ether->ri]; if(rb->owner == Interface){ rb->owner = Host; rb->len = rfd->count & 0x3FFF; memmove(rb->pkt, rfd->d, rfd->count & 0x3FFF); ether->ri = NEXT(ether->ri, ether->nrb); } /* * Reinitialise the frame for reception and bump * the receive frame processing index; * bump the sentinel index, mark the new sentinel * and clear the old sentinel suspend bit; * set bp and rfd for the next receive frame to * process. */ rfd->field = 0; rfd->count = 0; ctlr->rfdx = NEXT(ctlr->rfdx, Nrfd); rfd = &ctlr->rfd[ctlr->rfdl]; ctlr->rfdl = NEXT(ctlr->rfdl, Nrfd); ctlr->rfd[ctlr->rfdl].field |= RfdS; rfd->field &= ~RfdS; rfd = &ctlr->rfd[ctlr->rfdx]; } status &= ~StatFR; } if(status & StatRNR){ while(csr8r(ctlr, CommandR)) ; csr8w(ctlr, CommandR, RUresume); status &= ~StatRNR; } if(status & StatCNA){ while(bp = ctlr->cbqhead){ if((((Cb*)bp->rp)->command & CbC) == 0) break; ctlr->cbqhead = bp->next; freeb(bp); } custart(ctlr); status &= ~StatCNA; } if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) panic("%s#%d: status %uX", ctlr->type, ctlr->ctlrno, status); }} static voidctlrinit(Ctlr* ctlr){ int i; Rfd *rfd; ulong link; link = NullPointer; for(i = Nrfd-1; i >= 0; i--){ rfd = &ctlr->rfd[i]; rfd->field = 0; rfd->link = link; link = PADDR(rfd); rfd->rbd = NullPointer; rfd->count = 0; rfd->size = sizeof(Etherpkt); } ctlr->rfd[Nrfd-1].link = PADDR(&ctlr->rfd[0]); ctlr->rfdl = 0; ctlr->rfd[0].field |= RfdS; ctlr->rfdx = 2; memmove(ctlr->configdata, configdata, sizeof(configdata));} static intmiir(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);Lines 1–500 of 885. Load more
/* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full * of smarts, unfortunately none of them are in the right place. * To do: * the PCI scanning code could be made common to other adapters; * PCI code needs rewritten to handle byte, word, dword accesses * and using the devno as a bus+dev+function triplet. */ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "etherif.h" enum { Nrfd = 4, /* receive frame area */ NullPointer = 0xFFFFFFFF, /* 82557 NULL pointer */ }; enum { /* CSR */ Status = 0x00, /* byte or word (word includes Ack) */ Ack = 0x01, /* byte */ CommandR = 0x02, /* byte or word (word includes Interrupt) */ Interrupt = 0x03, /* byte */ Pointer = 0x04, /* dword */ Port = 0x08, /* dword */ Fcr = 0x0C, /* Flash control register */ Ecr = 0x0E, /* EEPROM control register */ Mcr = 0x10, /* MDI control register */ }; enum { /* Status */ RUidle = 0x0000, RUsuspended = 0x0004, RUnoresources = 0x0008, RUready = 0x0010, RUrbd = 0x0020, /* bit */ RUstatus = 0x003F, /* mask */ CUidle = 0x0000, CUsuspended = 0x0040, CUactive = 0x0080, CUstatus = 0x00C0, /* mask */ StatSWI = 0x0400, /* SoftWare generated Interrupt */ StatMDI = 0x0800, /* MDI r/w done */ StatRNR = 0x1000, /* Receive unit Not Ready */ StatCNA = 0x2000, /* Command unit Not Active (Active->Idle) */ StatFR = 0x4000, /* Finished Receiving */ StatCX = 0x8000, /* Command eXecuted */ StatTNO = 0x8000, /* Transmit NOT OK */ }; enum { /* Command (byte) */ CUnop = 0x00, CUstart = 0x10, CUresume = 0x20, LoadDCA = 0x40, /* Load Dump Counters Address */ DumpSC = 0x50, /* Dump Statistical Counters */ LoadCUB = 0x60, /* Load CU Base */ ResetSA = 0x70, /* Dump and Reset Statistical Counters */ RUstart = 0x01, RUresume = 0x02, RUabort = 0x04, LoadHDS = 0x05, /* Load Header Data Size */ LoadRUB = 0x06, /* Load RU Base */ RBDresume = 0x07, /* Resume frame reception */ }; enum { /* Interrupt (byte) */ InterruptM = 0x01, /* interrupt Mask */ InterruptSI = 0x02, /* Software generated Interrupt */ }; enum { /* Ecr */ EEsk = 0x01, /* serial clock */ EEcs = 0x02, /* chip select */ EEdi = 0x04, /* serial data in */ EEdo = 0x08, /* serial data out */ EEstart = 0x04, /* start bit */ EEread = 0x02, /* read opcode */ }; enum { /* Mcr */ MDIread = 0x08000000, /* read opcode */ MDIwrite = 0x04000000, /* write opcode */ MDIready = 0x10000000, /* ready bit */ MDIie = 0x20000000, /* interrupt enable */ }; typedef struct Rfd { int field; ulong link; ulong rbd; ushort count; ushort size; Etherpkt; } Rfd; enum { /* field */ RfdCollision = 0x00000001, RfdIA = 0x00000002, /* IA match */ RfdRxerr = 0x00000010, /* PHY character error */ RfdType = 0x00000020, /* Type frame */ RfdRunt = 0x00000080, RfdOverrun = 0x00000100, RfdBuffer = 0x00000200, RfdAlignment = 0x00000400, RfdCRC = 0x00000800, RfdOK = 0x00002000, /* frame received OK */ RfdC = 0x00008000, /* reception Complete */ RfdSF = 0x00080000, /* Simplified or Flexible (1) Rfd */ RfdH = 0x00100000, /* Header RFD */ RfdI = 0x20000000, /* Interrupt after completion */ RfdS = 0x40000000, /* Suspend after completion */ RfdEL = 0x80000000, /* End of List */ }; enum { /* count */ RfdF = 0x00004000, RfdEOF = 0x00008000, }; typedef struct Cb { int command; ulong link; uchar data[24]; /* CbIAS + CbConfigure */ } Cb; typedef struct TxCB { int command; ulong link; ulong tbd; ushort count; uchar threshold; uchar number; } TxCB; enum { /* action command */ CbOK = 0x00002000, /* DMA completed OK */ CbC = 0x00008000, /* execution Complete */ CbNOP = 0x00000000, CbIAS = 0x00010000, /* Indvidual Address Setup */ CbConfigure = 0x00020000, CbMAS = 0x00030000, /* Multicast Address Setup */ CbTransmit = 0x00040000, CbDump = 0x00060000, CbDiagnose = 0x00070000, CbCommand = 0x00070000, /* mask */ CbSF = 0x00080000, /* CbTransmit */ CbI = 0x20000000, /* Interrupt after completion */ CbS = 0x40000000, /* Suspend after completion */ CbEL = 0x80000000, /* End of List */ }; enum { /* CbTransmit count */ CbEOF = 0x00008000, }; typedef struct Ctlr Ctlr; typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; int eepromsz; /* address size in bits */ ushort* eeprom; int ctlrno; char* type; uchar configdata[24]; Rfd rfd[Nrfd]; int rfdl; int rfdx; Block* cbqhead; Block* cbqtail; int cbqbusy; } Ctlr; static Ctlr* ctlrhead; static Ctlr* ctlrtail; static uchar configdata[24] = { 0x16, /* byte count */ 0x44, /* Rx/Tx FIFO limit */ 0x00, /* adaptive IFS */ 0x00, 0x04, /* Rx DMA maximum byte count */ 0x84, /* Tx DMA maximum byte count */ 0x33, /* late SCB, CNA interrupts */ 0x01, /* discard short Rx frames */ 0x00, /* 503/MII */ 0x00, 0x2E, /* normal operation, NSAI */ 0x00, /* linear priority */ 0x60, /* inter-frame spacing */ 0x00, 0xF2, 0x48, /* promiscuous mode off */ 0x00, 0x40, 0xF2, /* transmit padding enable */ 0x80, /* full duplex pin enable */ 0x3F, /* no Multi IA */ 0x05, /* no Multi Cast ALL */ }; #define csr8r(c, r) (inb((c)->port+(r))) #define csr16r(c, r) (ins((c)->port+(r))) #define csr32r(c, r) (inl((c)->port+(r))) #define csr8w(c, r, b) (outb((c)->port+(r), (int)(b))) #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w))) #define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l))) static void custart(Ctlr* ctlr) { if(ctlr->cbqhead == 0){ ctlr->cbqbusy = 0; return; } ctlr->cbqbusy = 1; csr32w(ctlr, Pointer, PADDR(ctlr->cbqhead->rp)); while(csr8r(ctlr, CommandR)) ; csr8w(ctlr, CommandR, CUstart); } static void action(Ctlr* ctlr, Block* bp) { Cb *cb; cb = (Cb*)bp->rp; cb->command |= CbEL; if(ctlr->cbqhead){ ctlr->cbqtail->next = bp; cb = (Cb*)ctlr->cbqtail->rp; cb->link = PADDR(bp->rp); cb->command &= ~CbEL; } else ctlr->cbqhead = bp; ctlr->cbqtail = bp; if(ctlr->cbqbusy == 0) custart(ctlr); } static void attach(Ether* ether) { int status; Ctlr *ctlr; ctlr = ether->ctlr; status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ csr32w(ctlr, Pointer, PADDR(&ctlr->rfd[ctlr->rfdx])); while(csr8r(ctlr, CommandR)) ; csr8w(ctlr, CommandR, RUstart); } } static void configure(void* arg, int promiscuous) { Ctlr *ctlr; Block *bp; Cb *cb; ctlr = ((Ether*)arg)->ctlr; bp = allocb(sizeof(Cb)); cb = (Cb*)bp->rp; bp->wp += sizeof(Cb); cb->command = CbConfigure; cb->link = NullPointer; memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); if(promiscuous) cb->data[15] |= 0x01; action(ctlr, bp); } static void transmit(Ether* ether) { Block *bp; TxCB *txcb; RingBuf *tb; for(tb = ðer->tb[ether->ti]; tb->owner == Interface; tb = ðer->tb[ether->ti]){ bp = allocb(tb->len+sizeof(TxCB)); txcb = (TxCB*)bp->wp; bp->wp += sizeof(TxCB); txcb->command = CbTransmit; txcb->link = NullPointer; txcb->tbd = NullPointer; txcb->count = CbEOF|tb->len; txcb->threshold = 2; txcb->number = 0; memmove(bp->wp, tb->pkt, tb->len); memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += tb->len; action(ether->ctlr, bp); tb->owner = Host; ether->ti = NEXT(ether->ti, ether->ntb); } } static void interrupt(Ureg*, void* arg) { Rfd *rfd; Block *bp; Ctlr *ctlr; Ether *ether; int status; RingBuf *rb; ether = arg; ctlr = ether->ctlr; for(;;){ status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); if((status & (StatCX|StatFR|StatCNA|StatRNR)) == 0) return; if(status & StatFR){ rfd = &ctlr->rfd[ctlr->rfdx]; while(rfd->field & RfdC){ rb = ðer->rb[ether->ri]; if(rb->owner == Interface){ rb->owner = Host; rb->len = rfd->count & 0x3FFF; memmove(rb->pkt, rfd->d, rfd->count & 0x3FFF); ether->ri = NEXT(ether->ri, ether->nrb); } /* * Reinitialise the frame for reception and bump * the receive frame processing index; * bump the sentinel index, mark the new sentinel * and clear the old sentinel suspend bit; * set bp and rfd for the next receive frame to * process. */ rfd->field = 0; rfd->count = 0; ctlr->rfdx = NEXT(ctlr->rfdx, Nrfd); rfd = &ctlr->rfd[ctlr->rfdl]; ctlr->rfdl = NEXT(ctlr->rfdl, Nrfd); ctlr->rfd[ctlr->rfdl].field |= RfdS; rfd->field &= ~RfdS; rfd = &ctlr->rfd[ctlr->rfdx]; } status &= ~StatFR; } if(status & StatRNR){ while(csr8r(ctlr, CommandR)) ; csr8w(ctlr, CommandR, RUresume); status &= ~StatRNR; } if(status & StatCNA){ while(bp = ctlr->cbqhead){ if((((Cb*)bp->rp)->command & CbC) == 0) break; ctlr->cbqhead = bp->next; freeb(bp); } custart(ctlr); status &= ~StatCNA; } if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) panic("%s#%d: status %uX", ctlr->type, ctlr->ctlrno, status); } } static void ctlrinit(Ctlr* ctlr) { int i; Rfd *rfd; ulong link; link = NullPointer; for(i = Nrfd-1; i >= 0; i--){ rfd = &ctlr->rfd[i]; rfd->field = 0; rfd->link = link; link = PADDR(rfd); rfd->rbd = NullPointer; rfd->count = 0; rfd->size = sizeof(Etherpkt); } ctlr->rfd[Nrfd-1].link = PADDR(&ctlr->rfd[0]); ctlr->rfdl = 0; ctlr->rfd[0].field |= RfdS; ctlr->rfdx = 2; memmove(ctlr->configdata, configdata, sizeof(configdata)); } static int 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 int miiw(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 int hy93c46r(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);