/* * Realtek RTL8110S/8169S. * Mostly there. There are some magic register values used * which are not described in any datasheet or driver but seem * to be necessary. * Why is the Fovf descriptor bit set for every received packet? * Occasionally the hardware indicates an input TCP checksum error * although the higher-level software seems to check the packet OK? * No tuning has been done. Only tested on an RTL8110S, there * are slight differences between the chips in the series so some * tweaks may be needed. */#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h" typedef struct QLock { int r; } QLock;#define qlock(i) while(0)#define qunlock(i) while(0)#define iallocb allocbextern void mb386(void);#define coherence() mb386()#define iprint print#define mallocalign(n, a, o, s) ialloc((n), (a)) #include "etherif.h"#include "ethermii.h" enum { /* registers */ Idr0 = 0x00, /* MAC address */ Mar0 = 0x08, /* Multicast address */ Dtccr = 0x10, /* Dump Tally Counter Command */ Tnpds = 0x20, /* Transmit Normal Priority Descriptors */ Thpds = 0x28, /* Transmit High Priority Descriptors */ Flash = 0x30, /* Flash Memory Read/Write */ Erbcr = 0x34, /* Early Receive Byte Count */ Ersr = 0x36, /* Early Receive Status */ Cr = 0x37, /* Command Register */ Tppoll = 0x38, /* Transmit Priority Polling */ Imr = 0x3C, /* Interrupt Mask */ Isr = 0x3E, /* Interrupt Status */ Tcr = 0x40, /* Transmit Configuration */ Rcr = 0x44, /* Receive Configuration */ Tctr = 0x48, /* Timer Count */ Mpc = 0x4C, /* Missed Packet Counter */ Cr9346 = 0x50, /* 9346 Command Register */ Config0 = 0x51, /* Configuration Register 0 */ Config1 = 0x52, /* Configuration Register 1 */ Config2 = 0x53, /* Configuration Register 2 */ Config3 = 0x54, /* Configuration Register 3 */ Config4 = 0x55, /* Configuration Register 4 */ Config5 = 0x56, /* Configuration Register 5 */ Timerint = 0x58, /* Timer Interrupt */ Mulint = 0x5C, /* Multiple Interrupt Select */ Phyar = 0x60, /* PHY Access */ Tbicsr0 = 0x64, /* TBI Control and Status */ Tbianar = 0x68, /* TBI Auto-Negotiation Advertisment */ Tbilpar = 0x6A, /* TBI Auto-Negotiation Link Partner */ Phystatus = 0x6C, /* PHY Status */ Rms = 0xDA, /* Receive Packet Maximum Size */ Cplusc = 0xE0, /* C+ Command */ Rdsar = 0xE4, /* Receive Descriptor Start Address */ Mtps = 0xEC, /* Max. Transmit Packet Size */}; enum { /* Dtccr */ Cmd = 0x00000008, /* Command */}; enum { /* Cr */ Te = 0x04, /* Transmitter Enable */ Re = 0x08, /* Receiver Enable */ Rst = 0x10, /* Software Reset */}; enum { /* Tppoll */ Fswint = 0x01, /* Forced Software Interrupt */ Npq = 0x40, /* Normal Priority Queue polling */ Hpq = 0x80, /* High Priority Queue polling */}; enum { /* Imr/Isr */ Rok = 0x0001, /* Receive OK */ Rer = 0x0002, /* Receive Error */ Tok = 0x0004, /* Transmit OK */ Ter = 0x0008, /* Transmit Error */ Rdu = 0x0010, /* Receive Descriptor Unavailable */ Punlc = 0x0020, /* Packet Underrun or Link Change */ Fovw = 0x0040, /* Receive FIFO Overflow */ Tdu = 0x0080, /* Transmit Descriptor Unavailable */ Swint = 0x0100, /* Software Interrupt */ Timeout = 0x4000, /* Timer */ Serr = 0x8000, /* System Error */}; enum { /* Tcr */ MtxdmaSHIFT = 8, /* Max. DMA Burst Size */ MtxdmaMASK = 0x00000700, Mtxdmaunlimited = 0x00000700, Acrc = 0x00010000, /* Append CRC (not) */ Lbk0 = 0x00020000, /* Loopback Test 0 */ Lbk1 = 0x00040000, /* Loopback Test 1 */ Ifg2 = 0x00080000, /* Interframe Gap 2 */ HwveridSHIFT = 23, /* Hardware Version ID */ HwveridMASK = 0x7C800000, Ifg0 = 0x01000000, /* Interframe Gap 0 */ Ifg1 = 0x02000000, /* Interframe Gap 1 */}; enum { /* Rcr */ Aap = 0x00000001, /* Accept All Packets */ Apm = 0x00000002, /* Accept Physical Match */ Am = 0x00000004, /* Accept Multicast */ Ab = 0x00000008, /* Accept Broadcast */ Ar = 0x00000010, /* Accept Runt */ Aer = 0x00000020, /* Accept Error */ Sel9356 = 0x00000040, /* 9356 EEPROM used */ MrxdmaSHIFT = 8, /* Max. DMA Burst Size */ MrxdmaMASK = 0x00000700, Mrxdmaunlimited = 0x00000700, RxfthSHIFT = 13, /* Receive Buffer Length */ RxfthMASK = 0x0000E000, Rxfth256 = 0x00008000, Rxfthnone = 0x0000E000, Rer8 = 0x00010000, /* Accept Error Packets > 8 bytes */ MulERINT = 0x01000000, /* Multiple Early Interrupt Select */}; enum { /* Cr9346 */ Eedo = 0x01, /* */ Eedi = 0x02, /* */ Eesk = 0x04, /* */ Eecs = 0x08, /* */ Eem0 = 0x40, /* Operating Mode */ Eem1 = 0x80,}; enum { /* Phyar */ DataMASK = 0x0000FFFF, /* 16-bit GMII/MII Register Data */ DataSHIFT = 0, RegaddrMASK = 0x001F0000, /* 5-bit GMII/MII Register Address */ RegaddrSHIFT = 16, Flag = 0x80000000, /* */}; enum { /* Phystatus */ Fd = 0x01, /* Full Duplex */ Linksts = 0x02, /* Link Status */ Speed10 = 0x04, /* */ Speed100 = 0x08, /* */ Speed1000 = 0x10, /* */ Rxflow = 0x20, /* */ Txflow = 0x40, /* */ Entbi = 0x80, /* */}; enum { /* Cplusc */ Mulrw = 0x0008, /* PCI Multiple R/W Enable */ Dac = 0x0010, /* PCI Dual Address Cycle Enable */ Rxchksum = 0x0020, /* Receive Checksum Offload Enable */ Rxvlan = 0x0040, /* Receive VLAN De-tagging Enable */ Endian = 0x0200, /* Endian Mode */}; typedef struct D D; /* Transmit/Receive Descriptor */struct D { u32int control; u32int vlan; u32int addrlo; u32int addrhi;}; enum { /* Transmit Descriptor control */ TxflMASK = 0x0000FFFF, /* Transmit Frame Length */ TxflSHIFT = 0, Tcps = 0x00010000, /* TCP Checksum Offload */ Udpcs = 0x00020000, /* UDP Checksum Offload */ Ipcs = 0x00040000, /* IP Checksum Offload */ Lgsen = 0x08000000, /* Large Send */}; enum { /* Receive Descriptor control */ RxflMASK = 0x00003FFF, /* Receive Frame Length */ RxflSHIFT = 0, Tcpf = 0x00004000, /* TCP Checksum Failure */ Udpf = 0x00008000, /* UDP Checksum Failure */ Ipf = 0x00010000, /* IP Checksum Failure */ Pid0 = 0x00020000, /* Protocol ID0 */ Pid1 = 0x00040000, /* Protocol ID1 */ Crce = 0x00080000, /* CRC Error */ Runt = 0x00100000, /* Runt Packet */ Res = 0x00200000, /* Receive Error Summary */ Rwt = 0x00400000, /* Receive Watchdog Timer Expired */ Fovf = 0x00800000, /* FIFO Overflow */ Bovf = 0x01000000, /* Buffer Overflow */ Bar = 0x02000000, /* Broadcast Address Received */ Pam = 0x04000000, /* Physical Address Matched */ Mar = 0x08000000, /* Multicast Address Received */}; enum { /* General Descriptor control */ Ls = 0x10000000, /* Last Segment Descriptor */ Fs = 0x20000000, /* First Segment Descriptor */ Eor = 0x40000000, /* End of Descriptor Ring */ Own = 0x80000000, /* Ownership */}; /* */enum { /* Ring sizes (<= 1024) */ Ntd = 8, /* Transmit Ring */ Nrd = 32, /* Receive Ring */ Mps = ROUNDUP(ETHERMAXTU+4, 128),}; typedef struct Dtcc Dtcc;struct Dtcc { u64int txok; u64int rxok; u64int txer; u32int rxer; u16int misspkt; u16int fae; u32int tx1col; u32int txmcol; u64int rxokph; u64int rxokbrd; u32int rxokmu; u16int txabt; u16int txundrn;}; typedef struct Ctlr Ctlr;typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; uint id; QLock alock; /* attach */ Lock ilock; /* init */ int init; /* */ Mii* mii; Lock tlock; /* transmit */ D* td; /* descriptor ring */ Block** tb; /* transmit buffers */ int ntd; int tdh; /* head - producer index (host) */ int tdt; /* tail - consumer index (NIC) */ int ntdfree; int ntq; int mtps; /* Max. Transmit Packet Size */ Lock rlock; /* receive */ D* rd; /* descriptor ring */ void** rb; /* receive buffers */ int nrd; int rdh; /* head - producer index (NIC) */ int rdt; /* tail - consumer index (host) */ int nrdfree; int rcr; /* receive configuration register */ QLock slock; /* statistics */ Dtcc* dtcc; uint txdu; uint tcpf; uint udpf; uint ipf; uint fovf; uint ierrs; uint rer; uint rdu; uint punlc; uint fovw;} Ctlr; static Ctlr* ctlrhead;static Ctlr* ctlrtail; #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 intrtl8169miimir(Mii* mii, int pa, int ra){ uint r; int timeo; Ctlr *ctlr; if(pa != 1) return -1; ctlr = mii->ctlr; r = (ra<<16) & RegaddrMASK; csr32w(ctlr, Phyar, r); delay(1); for(timeo = 0; timeo < 2000; timeo++){ if((r = csr32r(ctlr, Phyar)) & Flag) break; microdelay(100); } if(!(r & Flag)) return -1; return (r & DataMASK)>>DataSHIFT;} static intrtl8169miimiw(Mii* mii, int pa, int ra, int data){ uint r; int timeo; Ctlr *ctlr; if(pa != 1) return -1; ctlr = mii->ctlr; r = Flag|((ra<<16) & RegaddrMASK)|((data<<DataSHIFT) & DataMASK); csr32w(ctlr, Phyar, r); delay(1); for(timeo = 0; timeo < 2000; timeo++){ if(!((r = csr32r(ctlr, Phyar)) & Flag)) break; microdelay(100); } if(r & Flag) return -1; return 0;} static intrtl8169mii(Ctlr* ctlr){ MiiPhy *phy; /* * Link management. */ if((ctlr->mii = malloc(sizeof(Mii))) == nil) return -1; ctlr->mii->mir = rtl8169miimir; ctlr->mii->miw = rtl8169miimiw; ctlr->mii->ctlr = ctlr; rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000); /* magic */ if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){ free(ctlr->mii); ctlr->mii = nil; return -1; } print("oui %X phyno %d\n", phy->oui, phy->phyno); miiane(ctlr->mii, ~0, ~0, ~0); return 0;} static intrtl8169reset(Ctlr* ctlr){ int timeo; /* * Soft reset the controller. */ csr8w(ctlr, Cr, Rst); for(timeo = 0; timeo < 1000; timeo++){ if(!(csr8r(ctlr, Cr) & Rst)) return 0; delay(1); } return -1;} static voidrtl8169detach(Ether* edev){ rtl8169reset(edev->ctlr);} static voidrtl8169halt(Ctlr* ctlr){ csr8w(ctlr, Cr, 0); csr16w(ctlr, Imr, 0); csr16w(ctlr, Isr, ~0);} static voidrtl8169replenish(Ctlr* ctlr){ D *d; int rdt; void *bp; rdt = ctlr->rdt; while(NEXT(rdt, ctlr->nrd) != ctlr->rdh){ d = &ctlr->rd[rdt]; if(ctlr->rb[rdt] == nil){ /* * simple allocation for now */ bp = malloc(Mps); ctlr->rb[rdt] = bp; d->addrlo = PCIWADDR(bp); d->addrhi = 0; } coherence(); d->control |= Own|Mps; rdt = NEXT(rdt, ctlr->nrd); ctlr->nrdfree++; } ctlr->rdt = rdt;} static voidrtl8169init(Ether* edev){ uint r; Ctlr *ctlr; ctlr = edev->ctlr; ilock(&ctlr->ilock); rtl8169halt(ctlr); /* * Setting Mulrw in Cplusc disables the Tx/Rx DMA burst settings * in Tcr/Rcr. */ csr16w(ctlr, Cplusc, (1<<14)|Rxchksum|Mulrw); /* magic (1<<14) */ /* * MAC Address. * Must put chip into config register write enable mode. */ csr8w(ctlr, Cr9346, Eem1|Eem0); r = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0]; csr32w(ctlr, Idr0, r); r = (edev->ea[5]<<8)|edev->ea[4]; csr32w(ctlr, Idr0+4, r); /* * Enable receiver/transmitter. * Need to do this first or some of the settings below * won't take. */ csr8w(ctlr, Cr, Te|Re); /* * Transmitter. * Mtps is in units of 128. */ memset(ctlr->td, 0, sizeof(D)*ctlr->ntd); ctlr->tdh = ctlr->tdt = 0; ctlr->td[ctlr->ntd-1].control = Eor; ctlr->mtps = HOWMANY(Mps, 128); /* * Receiver. */ memset(ctlr->rd, 0, sizeof(D)*ctlr->nrd); ctlr->rdh = ctlr->rdt = 0; ctlr->rd[ctlr->nrd-1].control = Eor; //for(i = 0; i < ctlr->nrd; i++){ // if((bp = ctlr->rb[i]) != nil){ // ctlr->rb[i] = nil; // freeb(bp); // } //} rtl8169replenish(ctlr); ctlr->rcr = Rxfth256|Mrxdmaunlimited|Ab|Apm; /* * Interrupts. * Disable Tdu|Tok for now, the transmit routine will tidy. * Tdu means the NIC ran out of descritors to send, so it * doesn't really need to ever be on. */Lines 1–500 of 847. Load more
/* * Realtek RTL8110S/8169S. * Mostly there. There are some magic register values used * which are not described in any datasheet or driver but seem * to be necessary. * Why is the Fovf descriptor bit set for every received packet? * Occasionally the hardware indicates an input TCP checksum error * although the higher-level software seems to check the packet OK? * No tuning has been done. Only tested on an RTL8110S, there * are slight differences between the chips in the series so some * tweaks may be needed. */ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" typedef struct QLock { int r; } QLock; #define qlock(i) while(0) #define qunlock(i) while(0) #define iallocb allocb extern void mb386(void); #define coherence() mb386() #define iprint print #define mallocalign(n, a, o, s) ialloc((n), (a)) #include "etherif.h" #include "ethermii.h" enum { /* registers */ Idr0 = 0x00, /* MAC address */ Mar0 = 0x08, /* Multicast address */ Dtccr = 0x10, /* Dump Tally Counter Command */ Tnpds = 0x20, /* Transmit Normal Priority Descriptors */ Thpds = 0x28, /* Transmit High Priority Descriptors */ Flash = 0x30, /* Flash Memory Read/Write */ Erbcr = 0x34, /* Early Receive Byte Count */ Ersr = 0x36, /* Early Receive Status */ Cr = 0x37, /* Command Register */ Tppoll = 0x38, /* Transmit Priority Polling */ Imr = 0x3C, /* Interrupt Mask */ Isr = 0x3E, /* Interrupt Status */ Tcr = 0x40, /* Transmit Configuration */ Rcr = 0x44, /* Receive Configuration */ Tctr = 0x48, /* Timer Count */ Mpc = 0x4C, /* Missed Packet Counter */ Cr9346 = 0x50, /* 9346 Command Register */ Config0 = 0x51, /* Configuration Register 0 */ Config1 = 0x52, /* Configuration Register 1 */ Config2 = 0x53, /* Configuration Register 2 */ Config3 = 0x54, /* Configuration Register 3 */ Config4 = 0x55, /* Configuration Register 4 */ Config5 = 0x56, /* Configuration Register 5 */ Timerint = 0x58, /* Timer Interrupt */ Mulint = 0x5C, /* Multiple Interrupt Select */ Phyar = 0x60, /* PHY Access */ Tbicsr0 = 0x64, /* TBI Control and Status */ Tbianar = 0x68, /* TBI Auto-Negotiation Advertisment */ Tbilpar = 0x6A, /* TBI Auto-Negotiation Link Partner */ Phystatus = 0x6C, /* PHY Status */ Rms = 0xDA, /* Receive Packet Maximum Size */ Cplusc = 0xE0, /* C+ Command */ Rdsar = 0xE4, /* Receive Descriptor Start Address */ Mtps = 0xEC, /* Max. Transmit Packet Size */ }; enum { /* Dtccr */ Cmd = 0x00000008, /* Command */ }; enum { /* Cr */ Te = 0x04, /* Transmitter Enable */ Re = 0x08, /* Receiver Enable */ Rst = 0x10, /* Software Reset */ }; enum { /* Tppoll */ Fswint = 0x01, /* Forced Software Interrupt */ Npq = 0x40, /* Normal Priority Queue polling */ Hpq = 0x80, /* High Priority Queue polling */ }; enum { /* Imr/Isr */ Rok = 0x0001, /* Receive OK */ Rer = 0x0002, /* Receive Error */ Tok = 0x0004, /* Transmit OK */ Ter = 0x0008, /* Transmit Error */ Rdu = 0x0010, /* Receive Descriptor Unavailable */ Punlc = 0x0020, /* Packet Underrun or Link Change */ Fovw = 0x0040, /* Receive FIFO Overflow */ Tdu = 0x0080, /* Transmit Descriptor Unavailable */ Swint = 0x0100, /* Software Interrupt */ Timeout = 0x4000, /* Timer */ Serr = 0x8000, /* System Error */ }; enum { /* Tcr */ MtxdmaSHIFT = 8, /* Max. DMA Burst Size */ MtxdmaMASK = 0x00000700, Mtxdmaunlimited = 0x00000700, Acrc = 0x00010000, /* Append CRC (not) */ Lbk0 = 0x00020000, /* Loopback Test 0 */ Lbk1 = 0x00040000, /* Loopback Test 1 */ Ifg2 = 0x00080000, /* Interframe Gap 2 */ HwveridSHIFT = 23, /* Hardware Version ID */ HwveridMASK = 0x7C800000, Ifg0 = 0x01000000, /* Interframe Gap 0 */ Ifg1 = 0x02000000, /* Interframe Gap 1 */ }; enum { /* Rcr */ Aap = 0x00000001, /* Accept All Packets */ Apm = 0x00000002, /* Accept Physical Match */ Am = 0x00000004, /* Accept Multicast */ Ab = 0x00000008, /* Accept Broadcast */ Ar = 0x00000010, /* Accept Runt */ Aer = 0x00000020, /* Accept Error */ Sel9356 = 0x00000040, /* 9356 EEPROM used */ MrxdmaSHIFT = 8, /* Max. DMA Burst Size */ MrxdmaMASK = 0x00000700, Mrxdmaunlimited = 0x00000700, RxfthSHIFT = 13, /* Receive Buffer Length */ RxfthMASK = 0x0000E000, Rxfth256 = 0x00008000, Rxfthnone = 0x0000E000, Rer8 = 0x00010000, /* Accept Error Packets > 8 bytes */ MulERINT = 0x01000000, /* Multiple Early Interrupt Select */ }; enum { /* Cr9346 */ Eedo = 0x01, /* */ Eedi = 0x02, /* */ Eesk = 0x04, /* */ Eecs = 0x08, /* */ Eem0 = 0x40, /* Operating Mode */ Eem1 = 0x80, }; enum { /* Phyar */ DataMASK = 0x0000FFFF, /* 16-bit GMII/MII Register Data */ DataSHIFT = 0, RegaddrMASK = 0x001F0000, /* 5-bit GMII/MII Register Address */ RegaddrSHIFT = 16, Flag = 0x80000000, /* */ }; enum { /* Phystatus */ Fd = 0x01, /* Full Duplex */ Linksts = 0x02, /* Link Status */ Speed10 = 0x04, /* */ Speed100 = 0x08, /* */ Speed1000 = 0x10, /* */ Rxflow = 0x20, /* */ Txflow = 0x40, /* */ Entbi = 0x80, /* */ }; enum { /* Cplusc */ Mulrw = 0x0008, /* PCI Multiple R/W Enable */ Dac = 0x0010, /* PCI Dual Address Cycle Enable */ Rxchksum = 0x0020, /* Receive Checksum Offload Enable */ Rxvlan = 0x0040, /* Receive VLAN De-tagging Enable */ Endian = 0x0200, /* Endian Mode */ }; typedef struct D D; /* Transmit/Receive Descriptor */ struct D { u32int control; u32int vlan; u32int addrlo; u32int addrhi; }; enum { /* Transmit Descriptor control */ TxflMASK = 0x0000FFFF, /* Transmit Frame Length */ TxflSHIFT = 0, Tcps = 0x00010000, /* TCP Checksum Offload */ Udpcs = 0x00020000, /* UDP Checksum Offload */ Ipcs = 0x00040000, /* IP Checksum Offload */ Lgsen = 0x08000000, /* Large Send */ }; enum { /* Receive Descriptor control */ RxflMASK = 0x00003FFF, /* Receive Frame Length */ RxflSHIFT = 0, Tcpf = 0x00004000, /* TCP Checksum Failure */ Udpf = 0x00008000, /* UDP Checksum Failure */ Ipf = 0x00010000, /* IP Checksum Failure */ Pid0 = 0x00020000, /* Protocol ID0 */ Pid1 = 0x00040000, /* Protocol ID1 */ Crce = 0x00080000, /* CRC Error */ Runt = 0x00100000, /* Runt Packet */ Res = 0x00200000, /* Receive Error Summary */ Rwt = 0x00400000, /* Receive Watchdog Timer Expired */ Fovf = 0x00800000, /* FIFO Overflow */ Bovf = 0x01000000, /* Buffer Overflow */ Bar = 0x02000000, /* Broadcast Address Received */ Pam = 0x04000000, /* Physical Address Matched */ Mar = 0x08000000, /* Multicast Address Received */ }; enum { /* General Descriptor control */ Ls = 0x10000000, /* Last Segment Descriptor */ Fs = 0x20000000, /* First Segment Descriptor */ Eor = 0x40000000, /* End of Descriptor Ring */ Own = 0x80000000, /* Ownership */ }; /* */ enum { /* Ring sizes (<= 1024) */ Ntd = 8, /* Transmit Ring */ Nrd = 32, /* Receive Ring */ Mps = ROUNDUP(ETHERMAXTU+4, 128), }; typedef struct Dtcc Dtcc; struct Dtcc { u64int txok; u64int rxok; u64int txer; u32int rxer; u16int misspkt; u16int fae; u32int tx1col; u32int txmcol; u64int rxokph; u64int rxokbrd; u32int rxokmu; u16int txabt; u16int txundrn; }; typedef struct Ctlr Ctlr; typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; uint id; QLock alock; /* attach */ Lock ilock; /* init */ int init; /* */ Mii* mii; Lock tlock; /* transmit */ D* td; /* descriptor ring */ Block** tb; /* transmit buffers */ int ntd; int tdh; /* head - producer index (host) */ int tdt; /* tail - consumer index (NIC) */ int ntdfree; int ntq; int mtps; /* Max. Transmit Packet Size */ Lock rlock; /* receive */ D* rd; /* descriptor ring */ void** rb; /* receive buffers */ int nrd; int rdh; /* head - producer index (NIC) */ int rdt; /* tail - consumer index (host) */ int nrdfree; int rcr; /* receive configuration register */ QLock slock; /* statistics */ Dtcc* dtcc; uint txdu; uint tcpf; uint udpf; uint ipf; uint fovf; uint ierrs; uint rer; uint rdu; uint punlc; uint fovw; } Ctlr; static Ctlr* ctlrhead; static Ctlr* ctlrtail; #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 int rtl8169miimir(Mii* mii, int pa, int ra) { uint r; int timeo; Ctlr *ctlr; if(pa != 1) return -1; ctlr = mii->ctlr; r = (ra<<16) & RegaddrMASK; csr32w(ctlr, Phyar, r); delay(1); for(timeo = 0; timeo < 2000; timeo++){ if((r = csr32r(ctlr, Phyar)) & Flag) break; microdelay(100); } if(!(r & Flag)) return -1; return (r & DataMASK)>>DataSHIFT; } static int rtl8169miimiw(Mii* mii, int pa, int ra, int data) { uint r; int timeo; Ctlr *ctlr; if(pa != 1) return -1; ctlr = mii->ctlr; r = Flag|((ra<<16) & RegaddrMASK)|((data<<DataSHIFT) & DataMASK); csr32w(ctlr, Phyar, r); delay(1); for(timeo = 0; timeo < 2000; timeo++){ if(!((r = csr32r(ctlr, Phyar)) & Flag)) break; microdelay(100); } if(r & Flag) return -1; return 0; } static int rtl8169mii(Ctlr* ctlr) { MiiPhy *phy; /* * Link management. */ if((ctlr->mii = malloc(sizeof(Mii))) == nil) return -1; ctlr->mii->mir = rtl8169miimir; ctlr->mii->miw = rtl8169miimiw; ctlr->mii->ctlr = ctlr; rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000); /* magic */ if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){ free(ctlr->mii); ctlr->mii = nil; return -1; } print("oui %X phyno %d\n", phy->oui, phy->phyno); miiane(ctlr->mii, ~0, ~0, ~0); return 0; } static int rtl8169reset(Ctlr* ctlr) { int timeo; /* * Soft reset the controller. */ csr8w(ctlr, Cr, Rst); for(timeo = 0; timeo < 1000; timeo++){ if(!(csr8r(ctlr, Cr) & Rst)) return 0; delay(1); } return -1; } static void rtl8169detach(Ether* edev) { rtl8169reset(edev->ctlr); } static void rtl8169halt(Ctlr* ctlr) { csr8w(ctlr, Cr, 0); csr16w(ctlr, Imr, 0); csr16w(ctlr, Isr, ~0); } static void rtl8169replenish(Ctlr* ctlr) { D *d; int rdt; void *bp; rdt = ctlr->rdt; while(NEXT(rdt, ctlr->nrd) != ctlr->rdh){ d = &ctlr->rd[rdt]; if(ctlr->rb[rdt] == nil){ /* * simple allocation for now */ bp = malloc(Mps); ctlr->rb[rdt] = bp; d->addrlo = PCIWADDR(bp); d->addrhi = 0; } coherence(); d->control |= Own|Mps; rdt = NEXT(rdt, ctlr->nrd); ctlr->nrdfree++; } ctlr->rdt = rdt; } static void rtl8169init(Ether* edev) { uint r; Ctlr *ctlr; ctlr = edev->ctlr; ilock(&ctlr->ilock); rtl8169halt(ctlr); /* * Setting Mulrw in Cplusc disables the Tx/Rx DMA burst settings * in Tcr/Rcr. */ csr16w(ctlr, Cplusc, (1<<14)|Rxchksum|Mulrw); /* magic (1<<14) */ /* * MAC Address. * Must put chip into config register write enable mode. */ csr8w(ctlr, Cr9346, Eem1|Eem0); r = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0]; csr32w(ctlr, Idr0, r); r = (edev->ea[5]<<8)|edev->ea[4]; csr32w(ctlr, Idr0+4, r); /* * Enable receiver/transmitter. * Need to do this first or some of the settings below * won't take. */ csr8w(ctlr, Cr, Te|Re); /* * Transmitter. * Mtps is in units of 128. */ memset(ctlr->td, 0, sizeof(D)*ctlr->ntd); ctlr->tdh = ctlr->tdt = 0; ctlr->td[ctlr->ntd-1].control = Eor; ctlr->mtps = HOWMANY(Mps, 128); /* * Receiver. */ memset(ctlr->rd, 0, sizeof(D)*ctlr->nrd); ctlr->rdh = ctlr->rdt = 0; ctlr->rd[ctlr->nrd-1].control = Eor; //for(i = 0; i < ctlr->nrd; i++){ // if((bp = ctlr->rb[i]) != nil){ // ctlr->rb[i] = nil; // freeb(bp); // } //} rtl8169replenish(ctlr); ctlr->rcr = Rxfth256|Mrxdmaunlimited|Ab|Apm; /* * Interrupts. * Disable Tdu|Tok for now, the transmit routine will tidy. * Tdu means the NIC ran out of descritors to send, so it * doesn't really need to ever be on. */