📄 ether82543gc.c
字号:
/* * Intel RS-82543GC Gigabit Ethernet Controller * as found on the Intel PRO/1000[FT] Server Adapter. * The older non-[FT] cards use the 82542 (LSI L2A1157) chip; no attempt * is made to handle the older chip although it should be possible. * The datasheet is not very clear about running on a big-endian system * and this driver assumes little-endian throughout. * To do: * GMII/MII * receive tuning * transmit tuning */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "../port/netif.h"#include "etherif.h"enum { Ctrl = 0x00000000, /* Device Control */ Status = 0x00000008, /* Device Status */ Eecd = 0x00000010, /* EEPROM/Flash Control/Data */ Ctrlext = 0x00000018, /* Extended Device Control */ Mdic = 0x00000020, /* MDI Control */ Fcal = 0x00000028, /* Flow Control Address Low */ Fcah = 0x0000002C, /* Flow Control Address High */ Fct = 0x00000030, /* Flow Control Type */ Icr = 0x000000C0, /* Interrupt Cause Read */ Ics = 0x000000C8, /* Interrupt Cause Set */ Ims = 0x000000D0, /* Interrupt Mask Set/Read */ Imc = 0x000000D8, /* Interrupt mask Clear */ Rctl = 0x00000100, /* Receive Control */ Fcttv = 0x00000170, /* Flow Control Transmit Timer Value */ Txcw = 0x00000178, /* Transmit configuration word reg. */ Rxcw = 0x00000180, /* Receive configuration word reg. */ Tctl = 0x00000400, /* Transmit Control */ Tipg = 0x00000410, /* Transmit IPG */ Tbt = 0x00000448, /* Transmit Burst Timer */ Ait = 0x00000458, /* Adaptive IFS Throttle */ Fcrtl = 0x00002160, /* Flow Control RX Threshold Low */ Fcrth = 0x00002168, /* Flow Control Rx Threshold High */ Rdfh = 0x00002410, /* Receive data fifo head */ Rdft = 0x00002418, /* Receive data fifo tail */ Rdfhs = 0x00002420, /* Receive data fifo head saved */ Rdfts = 0x00002428, /* Receive data fifo tail saved */ Rdfpc = 0x00002430, /* Receive data fifo packet count */ Rdbal = 0x00002800, /* Rdesc Base Address Low */ Rdbah = 0x00002804, /* Rdesc Base Address High */ Rdlen = 0x00002808, /* Receive Descriptor Length */ Rdh = 0x00002810, /* Receive Descriptor Head */ Rdt = 0x00002818, /* Receive Descriptor Tail */ Rdtr = 0x00002820, /* Receive Descriptor Timer Ring */ Rxdctl = 0x00002828, /* Receive Descriptor Control */ Txdmac = 0x00003000, /* Transfer DMA Control */ Ett = 0x00003008, /* Early Transmit Control */ Tdfh = 0x00003410, /* Transmit data fifo head */ Tdft = 0x00003418, /* Transmit data fifo tail */ Tdfhs = 0x00003420, /* Transmit data Fifo Head saved */ Tdfts = 0x00003428, /* Transmit data fifo tail saved */ Tdfpc = 0x00003430, /* Trasnmit data Fifo packet count */ Tdbal = 0x00003800, /* Tdesc Base Address Low */ Tdbah = 0x00003804, /* Tdesc Base Address High */ Tdlen = 0x00003808, /* Transmit Descriptor Length */ Tdh = 0x00003810, /* Transmit Descriptor Head */ Tdt = 0x00003818, /* Transmit Descriptor Tail */ Tidv = 0x00003820, /* Transmit Interrupt Delay Value */ Txdctl = 0x00003828, /* Transmit Descriptor Control */ Statistics = 0x00004000, /* Start of Statistics Area */ Gorcl = 0x88/4, /* Good Octets Received Count */ Gotcl = 0x90/4, /* Good Octets Transmitted Count */ Torl = 0xC0/4, /* Total Octets Received */ Totl = 0xC8/4, /* Total Octets Transmitted */ Nstatistics = 64, Rxcsum = 0x00005000, /* Receive Checksum Control */ Mta = 0x00005200, /* Multicast Table Array */ Ral = 0x00005400, /* Receive Address Low */ Rah = 0x00005404, /* Receive Address High */};enum { /* Ctrl */ Bem = 0x00000002, /* Big Endian Mode */ Prior = 0x00000004, /* Priority on the PCI bus */ Lrst = 0x00000008, /* Link Reset */ Asde = 0x00000020, /* Auto-Speed Detection Enable */ Slu = 0x00000040, /* Set Link Up */ Ilos = 0x00000080, /* Invert Loss of Signal (LOS) */ Frcspd = 0x00000800, /* Force Speed */ Frcdplx = 0x00001000, /* Force Duplex */ Swdpinslo = 0x003C0000, /* Software Defined Pins - lo nibble */ Swdpin0 = 0x00040000, Swdpin1 = 0x00080000, Swdpin2 = 0x00100000, Swdpin3 = 0x00200000, Swdpiolo = 0x03C00000, /* Software Defined I/O Pins */ Swdpio0 = 0x00400000, Swdpio1 = 0x00800000, Swdpio2 = 0x01000000, Swdpio3 = 0x02000000, Devrst = 0x04000000, /* Device Reset */ Rfce = 0x08000000, /* Receive Flow Control Enable */ Tfce = 0x10000000, /* Transmit Flow Control Enable */ Vme = 0x40000000, /* VLAN Mode Enable */};enum { /* Status */ Lu = 0x00000002, /* Link Up */ Tckok = 0x00000004, /* Transmit clock is running */ Rbcok = 0x00000008, /* Receive clock is running */ Txoff = 0x00000010, /* Transmission Paused */ Tbimode = 0x00000020, /* TBI Mode Indication */ SpeedMASK = 0x000000C0, Speed10 = 0x00000000, /* 10Mb/s */ Speed100 = 0x00000040, /* 100Mb/s */ Speed1000 = 0x00000080, /* 1000Mb/s */ Mtxckok = 0x00000400, /* MTX clock is running */ Pci66 = 0x00000800, /* PCI Bus speed indication */ Bus64 = 0x00001000, /* PCI Bus width indication */};enum { /* Ctrl and Status */ Fd = 0x00000001, /* Full-Duplex */ AsdvMASK = 0x00000300, Asdv10 = 0x00000000, /* 10Mb/s */ Asdv100 = 0x00000100, /* 100Mb/s */ Asdv1000 = 0x00000200, /* 1000Mb/s */};enum { /* Eecd */ Sk = 0x00000001, /* Clock input to the EEPROM */ Cs = 0x00000002, /* Chip Select */ Di = 0x00000004, /* Data Input to the EEPROM */ Do = 0x00000008, /* Data Output from the EEPROM */};enum { /* Ctrlext */ Gpien = 0x0000000F, /* General Purpose Interrupt Enables */ Swdpinshi = 0x000000F0, /* Software Defined Pins - hi nibble */ Swdpiohi = 0x00000F00, /* Software Defined Pins - I or O */ Asdchk = 0x00001000, /* ASD Check */ Eerst = 0x00002000, /* EEPROM Reset */ Ips = 0x00004000, /* Invert Power State */ Spdbyps = 0x00008000, /* Speed Select Bypass */};enum { /* EEPROM content offsets */ Ea = 0x00, /* Ethernet Address */ Cf = 0x03, /* Compatibility Field */ Pba = 0x08, /* Printed Board Assembly number */ Icw1 = 0x0A, /* Initialization Control Word 1 */ Sid = 0x0B, /* Subsystem ID */ Svid = 0x0C, /* Subsystem Vendor ID */ Did = 0x0D, /* Device ID */ Vid = 0x0E, /* Vendor ID */ Icw2 = 0x0F, /* Initialization Control Word 2 */};enum { /* Mdic */ MDIdMASK = 0x0000FFFF, /* Data */ MDIdSHIFT = 0, MDIrMASK = 0x001F0000, /* PHY Register Address */ MDIrSHIFT = 16, MDIpMASK = 0x03E00000, /* PHY Address */ MDIpSHIFT = 21, MDIwop = 0x04000000, /* Write Operation */ MDIrop = 0x08000000, /* Read Operation */ MDIready = 0x10000000, /* End of Transaction */ MDIie = 0x20000000, /* Interrupt Enable */ MDIe = 0x40000000, /* Error */};enum { /* Icr, Ics, Ims, Imc */ Txdw = 0x00000001, /* Transmit Descriptor Written Back */ Txqe = 0x00000002, /* Transmit Queue Empty */ Lsc = 0x00000004, /* Link Status Change */ Rxseq = 0x00000008, /* Receive Sequence Error */ Rxdmt0 = 0x00000010, /* Rdesc Minimum Threshold Reached */ Rxo = 0x00000040, /* Receiver Overrun */ Rxt0 = 0x00000080, /* Receiver Timer Interrupt */ Mdac = 0x00000200, /* MDIO Access Completed */ Rxcfg = 0x00000400, /* Receiving /C/ ordered sets */ Gpi0 = 0x00000800, /* General Purpose Interrupts */ Gpi1 = 0x00001000, Gpi2 = 0x00002000, Gpi3 = 0x00004000,};enum { /* Txcw */ Ane = 0x80000000, /* Autonegotiate enable */ Np = 0x00008000, /* Next Page */ As = 0x00000100, /* Asymmetric Flow control desired */ Ps = 0x00000080, /* Pause supported */ Hd = 0x00000040, /* Half duplex supported */ TxcwFd = 0x00000020, /* Full Duplex supported */};enum { /* Rxcw */ Rxword = 0x0000FFFF, /* Data from auto-negotiation process */ Rxnocarrier = 0x04000000, /* Carrier Sense indication */ Rxinvalid = 0x08000000, /* Invalid Symbol during configuration */ Rxchange = 0x10000000, /* Change to the Rxword indication */ Rxconfig = 0x20000000, /* /C/ order set reception indication */ Rxsync = 0x40000000, /* Lost bit synchronization indication */ Anc = 0x80000000, /* Auto Negotiation Complete */};enum { /* Rctl */ Rrst = 0x00000001, /* Receiver Software Reset */ Ren = 0x00000002, /* Receiver Enable */ Sbp = 0x00000004, /* Store Bad Packets */ Upe = 0x00000008, /* Unicast Promiscuous Enable */ Mpe = 0x00000010, /* Multicast Promiscuous Enable */ Lpe = 0x00000020, /* Long Packet Reception Enable */ LbmMASK = 0x000000C0, /* Loopback Mode */ LbmOFF = 0x00000000, /* No Loopback */ LbmTBI = 0x00000040, /* TBI Loopback */ LbmMII = 0x00000080, /* GMII/MII Loopback */ LbmXCVR = 0x000000C0, /* Transceiver Loopback */ RdtmsMASK = 0x00000300, /* Rdesc Minimum Threshold Size */ RdtmsHALF = 0x00000000, /* Threshold is 1/2 Rdlen */ RdtmsQUARTER = 0x00000100, /* Threshold is 1/4 Rdlen */ RdtmsEIGHTH = 0x00000200, /* Threshold is 1/8 Rdlen */ MoMASK = 0x00003000, /* Multicast Offset */ Bam = 0x00008000, /* Broadcast Accept Mode */ BsizeMASK = 0x00030000, /* Receive Buffer Size */ Bsize2048 = 0x00000000, /* Bsex = 0 */ Bsize1024 = 0x00010000, /* Bsex = 0 */ Bsize512 = 0x00020000, /* Bsex = 0 */ Bsize256 = 0x00030000, /* Bsex = 0 */ Bsize16384 = 0x00010000, /* Bsex = 1 */ Vfe = 0x00040000, /* VLAN Filter Enable */ Cfien = 0x00080000, /* Canonical Form Indicator Enable */ Cfi = 0x00100000, /* Canonical Form Indicator value */ Dpf = 0x00400000, /* Discard Pause Frames */ Pmcf = 0x00800000, /* Pass MAC Control Frames */ Bsex = 0x02000000, /* Buffer Size Extension */ Secrc = 0x04000000, /* Strip CRC from incoming packet */};enum { /* Tctl */ Trst = 0x00000001, /* Transmitter Software Reset */ Ten = 0x00000002, /* Transmit Enable */ Psp = 0x00000008, /* Pad Short Packets */ CtMASK = 0x00000FF0, /* Collision Threshold */ CtSHIFT = 4, ColdMASK = 0x003FF000, /* Collision Distance */ ColdSHIFT = 12, Swxoff = 0x00400000, /* Sofware XOFF Transmission */ Pbe = 0x00800000, /* Packet Burst Enable */ Rtlc = 0x01000000, /* Re-transmit on Late Collision */ Nrtu = 0x02000000, /* No Re-transmit on Underrrun */};enum { /* [RT]xdctl */ PthreshMASK = 0x0000003F, /* Prefetch Threshold */ PthreshSHIFT = 0, HthreshMASK = 0x00003F00, /* Host Threshold */ HthreshSHIFT = 8, WthreshMASK = 0x003F0000, /* Writeback Threshold */ WthreshSHIFT = 16, Gran = 0x00000000, /* Granularity */ RxGran = 0x01000000, /* Granularity */};enum { /* Rxcsum */ PcssMASK = 0x000000FF, /* Packet Checksum Start */ PcssSHIFT = 0, Ipofl = 0x00000100, /* IP Checksum Off-load Enable */ Tuofl = 0x00000200, /* TCP/UDP Checksum Off-load Enable */};enum { /* Receive Delay Timer Ring */ Fpd = 0x80000000, /* Flush partial Descriptor Block */};typedef struct Rdesc { /* Receive Descriptor */ uint addr[2]; ushort length; ushort checksum; uchar status; uchar errors; ushort special;} Rdesc;enum { /* Rdesc status */ Rdd = 0x01, /* Descriptor Done */ Reop = 0x02, /* End of Packet */ Ixsm = 0x04, /* Ignore Checksum Indication */ Vp = 0x08, /* Packet is 802.1Q (matched VET) */ Tcpcs = 0x20, /* TCP Checksum Calculated on Packet */ Ipcs = 0x40, /* IP Checksum Calculated on Packet */ Pif = 0x80, /* Passed in-exact filter */};enum { /* Rdesc errors */ Ce = 0x01, /* CRC Error or Alignment Error */ Se = 0x02, /* Symbol Error */ Seq = 0x04, /* Sequence Error */ Cxe = 0x10, /* Carrier Extension Error */ Tcpe = 0x20, /* TCP/UDP Checksum Error */ Ipe = 0x40, /* IP Checksum Error */ Rxe = 0x80, /* RX Data Error */};typedef struct Tdesc { /* Legacy+Normal Transmit Descriptor */ uint addr[2]; uint control; /* varies with descriptor type */ uint status; /* varies with descriptor type */} Tdesc;enum { /* Tdesc control */ CsoMASK = 0x00000F00, /* Checksum Offset */ CsoSHIFT = 16, Teop = 0x01000000, /* End of Packet */ Ifcs = 0x02000000, /* Insert FCS */ Ic = 0x04000000, /* Insert Checksum (Dext == 0) */ Tse = 0x04000000, /* TCP Segmentaion Enable (Dext == 1) */ Rs = 0x08000000, /* Report Status */ Rps = 0x10000000, /* Report Status Sent */ Dext = 0x20000000, /* Extension (!legacy) */ Vle = 0x40000000, /* VLAN Packet Enable */ Ide = 0x80000000, /* Interrupt Delay Enable */};enum { /* Tdesc status */ Tdd = 0x00000001, /* Descriptor Done */ Ec = 0x00000002, /* Excess Collisions */ Lc = 0x00000004, /* Late Collision */ Tu = 0x00000008, /* Transmit Underrun */ CssMASK = 0x0000FF00, /* Checksum Start Field */ CssSHIFT = 8,};enum { Nrdesc = 256, /* multiple of 8 */ Ntdesc = 256, /* multiple of 8 */ Nblocks = 4098, /* total number of blocks to use */ SBLOCKSIZE = 2048, JBLOCKSIZE = 16384, NORMAL = 1, JUMBO = 2,};typedef struct Ctlr Ctlr;typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; int started; int id; ushort eeprom[0x40]; int* nic; int im; /* interrupt mask */ Lock slock; uint statistics[Nstatistics]; Lock rdlock; Rdesc* rdba; /* receive descriptor base address */ Block* rb[Nrdesc]; /* receive buffers */ int rdh; /* receive descriptor head */ int rdt; /* receive descriptor tail */ Block** freehead; /* points to long or short head */ Lock tdlock; Tdesc* tdba; /* transmit descriptor base address */ Block* tb[Ntdesc]; /* transmit buffers */ int tdh; /* transmit descriptor head */ int tdt; /* transmit descriptor tail */ int txstalled; /* count of times unable to send */ int txcw; int fcrtl; int fcrth; ulong multimask[128]; /* bit mask for multicast addresses */} Ctlr;static Ctlr* gc82543ctlrhead;static Ctlr* gc82543ctlrtail;static Lock freelistlock;static Block* freeShortHead;static Block* freeJumboHead;#define csr32r(c, r) (*((c)->nic+((r)/4)))#define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))static void gc82543watchdog(void* arg);static voidgc82543attach(Ether* edev){ int ctl; Ctlr *ctlr; char name[KNAMELEN]; /* * To do here: * one-time stuff; * adjust queue length depending on speed; * flow control. * more needed here... */ ctlr = edev->ctlr; lock(&ctlr->slock); if(ctlr->started == 0){ ctlr->started = 1; snprint(name, KNAMELEN, "#l%d82543", edev->ctlrno); kproc(name, gc82543watchdog, edev); } unlock(&ctlr->slock); ctl = csr32r(ctlr, Rctl)|Ren; csr32w(ctlr, Rctl, ctl); ctl = csr32r(ctlr, Tctl)|Ten; csr32w(ctlr, Tctl, ctl); csr32w(ctlr, Ims, ctlr->im);}static char* statistics[Nstatistics] = { "CRC Error", "Alignment Error", "Symbol Error", "RX Error", "Missed Packets", "Single Collision", "Excessive Collisions", "Multiple Collision", "Late Collisions", nil, "Collision", "Transmit Underrun", "Defer", "Transmit - No CRS", "Sequence Error", "Carrier Extension Error", "Receive Error Length", nil, "XON Received", "XON Transmitted", "XOFF Received", "XOFF Transmitted", "FC Received Unsupported", "Packets Received (64 Bytes)",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -