1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132 |
- /*
- * Bootstrap driver for
- * Intel 82563, 82571, 82573, 82575
- * GbE PCI-Express Controllers.
- */
- #include "u.h"
- #include "lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "etherif.h"
- /* compatibility with cpu kernels */
- #define iallocb allocb
- #ifndef CACHELINESZ
- #define CACHELINESZ 32 /* pentium & later */
- #endif
- /* from pci.c */
- enum
- { /* command register pcidev->pcr */
- IOen = 1<<0,
- MEMen = 1<<1,
- MASen = 1<<2,
- MemWrInv = 1<<4,
- PErrEn = 1<<6,
- SErrEn = 1<<8,
- };
- /*
- * these are in the order they appear in the manual, not numeric order.
- * It was too hard to find them in the book. Ref 21489, rev 2.6
- */
- enum {
- /* General */
- Ctrl = 0x00000000, /* Device Control */
- Status = 0x00000008, /* Device Status */
- Eec = 0x00000010, /* EEPROM/Flash Control/Data */
- Eerd = 0x00000014, /* EEPROM Read */
- Ctrlext = 0x00000018, /* Extended Device Control */
- Fla = 0x0000001c, /* Flash Access */
- Mdic = 0x00000020, /* MDI Control */
- Seresctl = 0x00000024, /* Serdes ana */
- Fcal = 0x00000028, /* Flow Control Address Low */
- Fcah = 0x0000002C, /* Flow Control Address High */
- Fct = 0x00000030, /* Flow Control Type */
- Kumctrlsta = 0x00000034, /* MAC-PHY Interface */
- Vet = 0x00000038, /* VLAN EtherType */
- Fcttv = 0x00000170, /* Flow Control Transmit Timer Value */
- Txcw = 0x00000178, /* Transmit Configuration Word */
- Rxcw = 0x00000180, /* Receive Configuration Word */
- Ledctl = 0x00000E00, /* LED control */
- Pba = 0x00001000, /* Packet Buffer Allocation */
- Pbs = 0x00001008, /* Packet Buffer Size */
- /* Interrupt */
- Icr = 0x000000C0, /* Interrupt Cause Read */
- Ics = 0x000000C8, /* Interrupt Cause Set */
- Ims = 0x000000D0, /* Interrupt Mask Set/Read */
- Imc = 0x000000D8, /* Interrupt mask Clear */
- Iam = 0x000000E0, /* Interrupt acknowledge Auto Mask */
- /* Receive */
- Rctl = 0x00000100, /* Receive Control */
- Ert = 0x00002008, /* Early Receive Threshold (573[EVL] only) */
- Fcrtl = 0x00002160, /* Flow Control RX Threshold Low */
- Fcrth = 0x00002168, /* Flow Control Rx Threshold High */
- Psrctl = 0x00002170, /* Packet Split Receive Control */
- Rdbal = 0x00002800, /* Rdesc Base Address Low Queue 0 */
- Rdbah = 0x00002804, /* Rdesc Base Address High Queue 0 */
- Rdlen = 0x00002808, /* Receive Descriptor Length Queue 0 */
- Rdh = 0x00002810, /* Receive Descriptor Head Queue 0 */
- Rdt = 0x00002818, /* Receive Descriptor Tail Queue 0 */
- Rdtr = 0x00002820, /* Receive Descriptor Timer Ring */
- Rxdctl = 0x00002828, /* Receive Descriptor Control */
- Radv = 0x0000282C, /* Receive Interrupt Absolute Delay Timer */
- Rdbal1 = 0x00002900, /* Rdesc Base Address Low Queue 1 */
- Rdbah1 = 0x00002804, /* Rdesc Base Address High Queue 1 */
- Rdlen1 = 0x00002908, /* Receive Descriptor Length Queue 1 */
- Rdh1 = 0x00002910, /* Receive Descriptor Head Queue 1 */
- Rdt1 = 0x00002918, /* Receive Descriptor Tail Queue 1 */
- Rxdctl1 = 0x00002928, /* Receive Descriptor Control Queue 1 */
- Rsrpd = 0x00002c00, /* Receive Small Packet Detect */
- Raid = 0x00002c08, /* Receive ACK interrupt delay */
- Cpuvec = 0x00002c10, /* CPU Vector */
- Rxcsum = 0x00005000, /* Receive Checksum Control */
- Rfctl = 0x00005008, /* Receive Filter Control */
- Mta = 0x00005200, /* Multicast Table Array */
- Ral = 0x00005400, /* Receive Address Low */
- Rah = 0x00005404, /* Receive Address High */
- Vfta = 0x00005600, /* VLAN Filter Table Array */
- Mrqc = 0x00005818, /* Multiple Receive Queues Command */
- Rssim = 0x00005864, /* RSS Interrupt Mask */
- Rssir = 0x00005868, /* RSS Interrupt Request */
- Reta = 0x00005c00, /* Redirection Table */
- Rssrk = 0x00005c80, /* RSS Random Key */
- /* Transmit */
- Tctl = 0x00000400, /* Transmit Control */
- Tipg = 0x00000410, /* Transmit IPG */
- 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 */
- Tadv = 0x0000382C, /* Transmit Interrupt Absolute Delay Timer */
- Tarc0 = 0x00003840, /* Transmit Arbitration Counter Queue 0 */
- Tdbal1 = 0x00003900, /* Transmit Descriptor Base Low Queue 1 */
- Tdbah1 = 0x00003904, /* Transmit Descriptor Base High Queue 1 */
- Tdlen1 = 0x00003908, /* Transmit Descriptor Length Queue 1 */
- Tdh1 = 0x00003910, /* Transmit Descriptor Head Queue 1 */
- Tdt1 = 0x00003918, /* Transmit Descriptor Tail Queue 1 */
- Txdctl1 = 0x00003928, /* Transmit Descriptor Control 1 */
- Tarc1 = 0x00003940, /* Transmit Arbitration Counter Queue 1 */
- /* Statistics */
- 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,
- };
- enum { /* Ctrl */
- GIOmd = 1<<2, /* BIO master disable */
- Lrst = 1<<3, /* link reset */
- Slu = 1<<6, /* Set Link Up */
- SspeedMASK = 3<<8, /* Speed Selection */
- SspeedSHIFT = 8,
- Sspeed10 = 0x00000000, /* 10Mb/s */
- Sspeed100 = 0x00000100, /* 100Mb/s */
- Sspeed1000 = 0x00000200, /* 1000Mb/s */
- Frcspd = 1<<11, /* Force Speed */
- Frcdplx = 1<<12, /* Force Duplex */
- SwdpinsloMASK = 0x003C0000, /* Software Defined Pins - lo nibble */
- SwdpinsloSHIFT = 18,
- SwdpioloMASK = 0x03C00000, /* Software Defined Pins - I or O */
- SwdpioloSHIFT = 22,
- Devrst = 1<<26, /* Device Reset */
- Rfce = 1<<27, /* Receive Flow Control Enable */
- Tfce = 1<<28, /* Transmit Flow Control Enable */
- Vme = 1<<30, /* VLAN Mode Enable */
- Phy_rst = 1<<31, /* Phy Reset */
- };
- enum { /* Status */
- Lu = 1<<1, /* Link Up */
- Lanid = 3<<2, /* mask for Lan ID. */
- Txoff = 1<<4, /* Transmission Paused */
- Tbimode = 1<<5, /* TBI Mode Indication */
- SpeedMASK = 0x000000C0,
- Speed10 = 0x00000000, /* 10Mb/s */
- Speed100 = 0x00000040, /* 100Mb/s */
- Speed1000 = 0x00000080, /* 1000Mb/s */
- Phyra = 1<<10, /* PHY Reset Asserted */
- GIOme = 1<<19, /* GIO Master Enable Status */
- };
- enum { /* Ctrl and Status */
- Fd = 0x00000001, /* Full-Duplex */
- AsdvMASK = 0x00000300,
- Asdv10 = 0x00000000, /* 10Mb/s */
- Asdv100 = 0x00000100, /* 100Mb/s */
- Asdv1000 = 0x00000200, /* 1000Mb/s */
- };
- enum { /* Eec */
- Sk = 1<<0, /* Clock input to the EEPROM */
- Cs = 1<<1, /* Chip Select */
- Di = 1<<2, /* Data Input to the EEPROM */
- Do = 1<<3, /* Data Output from the EEPROM */
- Areq = 1<<6, /* EEPROM Access Request */
- Agnt = 1<<7, /* EEPROM Access Grant */
- };
- enum { /* Eerd */
- ee_start = 1<<0, /* Start Read */
- ee_done = 1<<1, /* Read done */
- ee_addr = 0xfff8<<2, /* Read address [15:2] */
- ee_data = 0xffff<<16, /* Read Data; Data returned from eeprom/nvm */
- };
- enum { /* Ctrlext */
- Asdchk = 1<<12, /* ASD Check */
- Eerst = 1<<13, /* EEPROM Reset */
- Spdbyps = 1<<15, /* Speed Select Bypass */
- };
- enum { /* EEPROM content offsets */
- Ea = 0x00, /* Ethernet Address */
- Cf = 0x03, /* Compatibility Field */
- 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,
- Ack = 0x00020000, /* receive ACK frame */
- };
- enum { /* Txcw */
- TxcwFd = 0x00000020, /* Full Duplex */
- TxcwHd = 0x00000040, /* Half Duplex */
- TxcwPauseMASK = 0x00000180, /* Pause */
- TxcwPauseSHIFT = 7,
- TxcwPs = 1<<TxcwPauseSHIFT, /* Pause Supported */
- TxcwAs = 2<<TxcwPauseSHIFT, /* Asymmetric FC desired */
- TxcwRfiMASK = 0x00003000, /* Remote Fault Indication */
- TxcwRfiSHIFT = 12,
- TxcwNpr = 0x00008000, /* Next Page Request */
- TxcwConfig = 0x40000000, /* Transmit Config Control */
- TxcwAne = 0x80000000, /* Auto-Negotiation Enable */
- };
- 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,
- Bsize1024 = 0x00010000,
- Bsize512 = 0x00020000,
- Bsize256 = 0x00030000,
- 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 */
- Mulr = 0x10000000, /* Allow multiple concurrent requests */
- 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, /* Writebacj Threshold */
- WthreshSHIFT = 16,
- Gran = 0x01000000, /* Granularity */
- Qenable = 0x02000000, /* Queue Enable (82575eb) */
- };
- enum { /* Rxcsum */
- PcssMASK = 0x000000FF, /* Packet Checksum Start */
- PcssSHIFT = 0,
- Ipofl = 0x00000100, /* IP Checksum Off-load Enable */
- Tuofl = 0x00000200, /* TCP/UDP Checksum Off-load Enable */
- };
- 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 */
- LenMASK = 0x000FFFFF, /* Data/Packet Length Field */
- LenSHIFT = 0,
- DtypeCD = 0x00000000, /* Data Type 'Context Descriptor' */
- DtypeDD = 0x00100000, /* Data Type 'Data Descriptor' */
- PtypeTCP = 0x01000000, /* TCP/UDP Packet Type (CD) */
- Teop = 0x01000000, /* End of Packet (DD) */
- PtypeIP = 0x02000000, /* IP Packet Type (CD) */
- Ifcs = 0x02000000, /* Insert FCS (DD) */
- Tse = 0x04000000, /* TCP Segmentation Enable */
- Rs = 0x08000000, /* Report Status */
- Rps = 0x10000000, /* Report Status Sent */
- Dext = 0x20000000, /* Descriptor Extension */
- 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,
- };
- typedef struct {
- ushort *reg;
- ulong *reg32;
- int sz;
- } Flash;
- enum {
- /* 16 and 32-bit flash registers for ich flash parts */
- Bfpr = 0x00/4, /* flash base 0:12; lim 16:28 */
- Fsts = 0x04/2, /* flash status; Hsfsts */
- Fctl = 0x06/2, /* flash control; Hsfctl */
- Faddr = 0x08/4, /* flash address to r/w */
- Fdata = 0x10/4, /* data @ address */
- /* status register */
- Fdone = 1<<0, /* flash cycle done */
- Fcerr = 1<<1, /* cycle error; write 1 to clear */
- Ael = 1<<2, /* direct access error log; 1 to clear */
- Scip = 1<<5, /* spi cycle in progress */
- Fvalid = 1<<14, /* flash descriptor valid */
- /* control register */
- Fgo = 1<<0, /* start cycle */
- Flcycle = 1<<1, /* two bits: r=0; w=2 */
- Fdbc = 1<<8, /* bytes to read; 5 bits */
- };
- enum {
- Nrdesc = 32, /* multiple of 8 */
- Ntdesc = 8, /* multiple of 8 */
- };
- enum {
- i82563,
- i82566,
- i82571,
- i82572,
- i82573,
- i82575,
- };
- static char *tname[] = {
- "i82563",
- "i82566",
- "i82571",
- "i82572",
- "i82573",
- "i82575",
- };
- #define Type tname[ctlr->type]
- typedef struct Ctlr Ctlr;
- struct Ctlr {
- int port;
- Pcidev *pcidev;
- Ctlr *next;
- int active;
- int cls;
- ushort eeprom[0x40];
- uchar ra[Eaddrlen]; /* receive address */
- int type;
- u32int* nic;
- Lock imlock;
- int im; /* interrupt mask */
- Lock slock;
- uint statistics[Nstatistics];
- Rdesc *rdba; /* receive descriptor base address */
- Block **rb; /* receive buffers */
- int rdh; /* receive descriptor head */
- int rdt; /* receive descriptor tail */
- Tdesc *tdba; /* transmit descriptor base address */
- Lock tdlock;
- Block **tb; /* transmit buffers */
- int tdh; /* transmit descriptor head */
- int tdt; /* transmit descriptor tail */
- int txcw;
- int fcrtl;
- int fcrth;
- /* bootstrap goo */
- Block *bqhead; /* transmission queue */
- Block *bqtail;
- };
- static Ctlr *ctlrhead;
- static Ctlr *ctlrtail;
- #define csr32r(c, r) (*((c)->nic+((r)/4)))
- #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
- static void
- i82563im(Ctlr* ctlr, int im)
- {
- ilock(&ctlr->imlock);
- ctlr->im |= im;
- csr32w(ctlr, Ims, ctlr->im);
- iunlock(&ctlr->imlock);
- }
- static void
- i82563attach(Ether* edev)
- {
- int ctl;
- Ctlr *ctlr;
- ctlr = edev->ctlr;
- i82563im(ctlr, 0);
- ctl = csr32r(ctlr, Rctl)|Ren;
- csr32w(ctlr, Rctl, ctl);
- ctl = csr32r(ctlr, Tctl)|Ten;
- csr32w(ctlr, Tctl, ctl);
- }
- static void
- txstart(Ether *edev)
- {
- int tdh, tdt;
- Ctlr *ctlr = edev->ctlr;
- Block *bp;
- Tdesc *tdesc;
- /*
- * Try to fill the ring back up, moving buffers from the transmit q.
- */
- tdh = PREV(ctlr->tdh, Ntdesc);
- for(tdt = ctlr->tdt; tdt != tdh; tdt = NEXT(tdt, Ntdesc)){
- /* pull off the head of the transmission queue */
- if((bp = ctlr->bqhead) == nil) /* was qget(edev->oq) */
- break;
- ctlr->bqhead = bp->next;
- if (ctlr->bqtail == bp)
- ctlr->bqtail = nil;
- /* set up a descriptor for it */
- tdesc = &ctlr->tdba[tdt];
- tdesc->addr[0] = PCIWADDR(bp->rp);
- tdesc->addr[1] = 0;
- tdesc->control = /* Ide | */ Rs | Ifcs | Teop | BLEN(bp);
- ctlr->tb[tdt] = bp;
- }
- ctlr->tdt = tdt;
- csr32w(ctlr, Tdt, tdt);
- i82563im(ctlr, Txdw);
- }
- static Block *
- fromringbuf(Ether *ether)
- {
- RingBuf *tb = ðer->tb[ether->ti];
- Block *bp = allocb(tb->len);
- memmove(bp->wp, tb->pkt, tb->len);
- memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen);
- bp->wp += tb->len;
- return bp;
- }
- static void
- i82563transmit(Ether* edev)
- {
- Block *bp;
- Ctlr *ctlr;
- Tdesc *tdesc;
- RingBuf *tb;
- int tdh;
- ctlr = edev->ctlr;
- ilock(&ctlr->tdlock);
- /*
- * Free any completed packets
- * - try to get the soft tdh to catch the tdt;
- * - if the packet had an underrun bump the threshold
- * - the Tu bit doesn't seem to ever be set, perhaps
- * because Rs mode is used?
- */
- tdh = ctlr->tdh;
- for(;;){
- tdesc = &ctlr->tdba[tdh];
- if(!(tdesc->status & Tdd))
- break;
- if(ctlr->tb[tdh] != nil){
- freeb(ctlr->tb[tdh]);
- ctlr->tb[tdh] = nil;
- }
- tdesc->status = 0;
- tdh = NEXT(tdh, Ntdesc);
- }
- ctlr->tdh = tdh;
- /* copy packets from the software RingBuf to the transmission q */
- while((tb = &edev->tb[edev->ti])->owner == Interface){
- bp = fromringbuf(edev);
- // print("#l%d: tx %d %E %E\n", edev->ctlrno, edev->ti, bp->rp,
- // bp->rp+6);
- if(ctlr->bqhead)
- ctlr->bqtail->next = bp;
- else
- ctlr->bqhead = bp;
- ctlr->bqtail = bp;
- txstart(edev); /* kick transmitter */
- tb->owner = Host; /* give descriptor back */
- edev->ti = NEXT(edev->ti, edev->ntb);
- }
- iunlock(&ctlr->tdlock);
- }
- static void
- i82563replenish(Ctlr* ctlr)
- {
- int rdt;
- Block *bp;
- Rdesc *rdesc;
- rdt = ctlr->rdt;
- while(NEXT(rdt, Nrdesc) != ctlr->rdh){
- rdesc = &ctlr->rdba[rdt];
- if(ctlr->rb[rdt] != nil){
- /* nothing to do */
- }
- else if((bp = iallocb(2048)) != nil){
- ctlr->rb[rdt] = bp;
- rdesc->addr[0] = PCIWADDR(bp->rp);
- rdesc->addr[1] = 0;
- }
- else
- break;
- rdesc->status = 0;
- rdt = NEXT(rdt, Nrdesc);
- }
- ctlr->rdt = rdt;
- csr32w(ctlr, Rdt, rdt);
- }
- static void
- toringbuf(Ether *ether, Block *bp)
- {
- RingBuf *rb = ðer->rb[ether->ri];
- if (rb->owner == Interface) {
- rb->len = BLEN(bp);
- memmove(rb->pkt, bp->rp, rb->len);
- rb->owner = Host;
- ether->ri = NEXT(ether->ri, ether->nrb);
- } else if (debug)
- print("#l%d: toringbuf: dropping packets @ ri %d\n",
- ether->ctlrno, ether->ri);
- }
- static void
- i82563interrupt(Ureg*, void* arg)
- {
- int icr, im, rdh, txdw = 0;
- Block *bp;
- Ctlr *ctlr;
- Ether *edev;
- Rdesc *rdesc;
- edev = arg;
- ctlr = edev->ctlr;
- ilock(&ctlr->imlock);
- csr32w(ctlr, Imc, ~0);
- im = ctlr->im;
- for(icr = csr32r(ctlr, Icr); icr & ctlr->im; icr = csr32r(ctlr, Icr)){
- if(icr & (Rxseq|Lsc)){
- /* should be more here */
- }
- rdh = ctlr->rdh;
- for (;;) {
- rdesc = &ctlr->rdba[rdh];
- if(!(rdesc->status & Rdd))
- break;
- if ((rdesc->status & Reop) && rdesc->errors == 0) {
- bp = ctlr->rb[rdh];
- if(0 && memcmp(bp->rp, broadcast, 6) != 0)
- print("#l%d: rx %d %E %E %d\n",
- edev->ctlrno, rdh, bp->rp,
- bp->rp+6, rdesc->length);
- ctlr->rb[rdh] = nil;
- bp->wp += rdesc->length;
- toringbuf(edev, bp);
- freeb(bp);
- } else if (rdesc->status & Reop && rdesc->errors)
- print("%s: input packet error 0x%ux\n",
- Type, rdesc->errors);
- rdesc->status = 0;
- rdh = NEXT(rdh, Nrdesc);
- }
- ctlr->rdh = rdh;
- if(icr & Rxdmt0)
- i82563replenish(ctlr);
- if(icr & Txdw){
- im &= ~Txdw;
- txdw++;
- }
- }
- ctlr->im = im;
- csr32w(ctlr, Ims, im);
- iunlock(&ctlr->imlock);
- if(txdw)
- i82563transmit(edev);
- }
- static void
- i82563init(Ether* edev)
- {
- Ctlr *ctlr;
- u32int r, rctl;
- ctlr = edev->ctlr;
- rctl = Dpf | Bsize2048 | Bam | RdtmsHALF;
- if(ctlr->type == i82575){
- /*
- * Setting Qenable in Rxdctl does not
- * appear to stick unless Ren is on.
- */
- csr32w(ctlr, Rctl, Ren|rctl);
- r = csr32r(ctlr, Rxdctl);
- r |= Qenable;
- csr32w(ctlr, Rxdctl, r);
- }
- csr32w(ctlr, Rctl, rctl);
- ctlr->rdba = mallocalign(Nrdesc*sizeof(Rdesc), 128, 0, 0);
- csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));
- csr32w(ctlr, Rdbah, 0);
- csr32w(ctlr, Rdlen, Nrdesc*sizeof(Rdesc));
- ctlr->rdh = 0;
- csr32w(ctlr, Rdh, ctlr->rdh);
- ctlr->rdt = 0;
- csr32w(ctlr, Rdt, ctlr->rdt);
- ctlr->rb = malloc(sizeof(Block*)*Nrdesc);
- i82563replenish(ctlr);
- csr32w(ctlr, Rdtr, 0);
- if(ctlr->type == i82573)
- csr32w(ctlr, Ert, 1024/8);
- if(ctlr->type == i82566)
- csr32w(ctlr, Pbs, 16);
- i82563im(ctlr, Rxt0 | Rxo | Rxdmt0 | Rxseq | Ack);
- csr32w(ctlr, Tctl, 0x0F<<CtSHIFT | Psp | 0x3f<<ColdSHIFT | Mulr);
- csr32w(ctlr, Tipg, 6<<20 | 8<<10 | 8);
- csr32w(ctlr, Tidv, 1);
- ctlr->tdba = mallocalign(Ntdesc*sizeof(Tdesc), 128, 0, 0);
- memset(ctlr->tdba, 0, Ntdesc*sizeof(Tdesc));
- csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
- csr32w(ctlr, Tdbah, 0);
- csr32w(ctlr, Tdlen, Ntdesc*sizeof(Tdesc));
- ctlr->tdh = 0;
- csr32w(ctlr, Tdh, ctlr->tdh);
- ctlr->tdt = 0;
- csr32w(ctlr, Tdt, ctlr->tdt);
- ctlr->tb = malloc(sizeof(Block*)*Ntdesc);
- r = csr32r(ctlr, Txdctl);
- r &= ~(WthreshMASK|PthreshSHIFT);
- r |= 4<<WthreshSHIFT | 4<<PthreshSHIFT;
- if(ctlr->type == i82575)
- r |= Qenable;
- csr32w(ctlr, Txdctl, r);
- csr32w(ctlr, Rxcsum, Tuofl | Ipofl | ETHERHDRSIZE<<PcssSHIFT);
- r = csr32r(ctlr, Tctl);
- r |= Ten;
- csr32w(ctlr, Tctl, r);
- }
- static ushort
- eeread(Ctlr* ctlr, int adr)
- {
- csr32w(ctlr, Eerd, ee_start | adr << 2);
- while ((csr32r(ctlr, Eerd) & ee_done) == 0)
- ;
- return csr32r(ctlr, Eerd) >> 16;
- }
- static int
- eeload(Ctlr* ctlr)
- {
- ushort sum;
- int data, adr;
- sum = 0;
- for (adr = 0; adr < 0x40; adr++) {
- data = eeread(ctlr, adr);
- ctlr->eeprom[adr] = data;
- sum += data;
- }
- return sum;
- }
- static void
- detach(Ctlr *ctlr)
- {
- int r;
- csr32w(ctlr, Imc, ~0);
- csr32w(ctlr, Rctl, 0);
- csr32w(ctlr, Tctl, 0);
- delay(10);
- r = csr32r(ctlr, Ctrl);
- if(ctlr->type == i82566)
- r |= Phy_rst;
- csr32w(ctlr, Ctrl, Devrst | r);
- /* apparently needed on multi-GHz processors to avoid infinite loops */
- delay(1);
- while(csr32r(ctlr, Ctrl) & Devrst)
- ;
- if(1 || ctlr->type != i82563){
- r = csr32r(ctlr, Ctrl);
- csr32w(ctlr, Ctrl, Slu | r);
- }
- csr32w(ctlr, Ctrlext, Eerst | csr32r(ctlr, Ctrlext));
- delay(1);
- while(csr32r(ctlr, Ctrlext) & Eerst)
- ;
- csr32w(ctlr, Imc, ~0);
- delay(1);
- while(csr32r(ctlr, Icr))
- ;
- }
- static void
- i82563detach(Ether *edev)
- {
- detach(edev->ctlr);
- }
- static void
- i82563shutdown(Ether* ether)
- {
- i82563detach(ether);
- }
- static int
- fcycle(Ctlr *, Flash *f)
- {
- ushort s, i;
- s = f->reg[Fsts];
- if((s&Fvalid) == 0)
- return -1;
- f->reg[Fsts] |= Fcerr | Ael;
- for(i = 0; i < 10; i++){
- if((s&Scip) == 0)
- return 0;
- delay(1);
- s = f->reg[Fsts];
- }
- return -1;
- }
- static int
- fread(Ctlr *c, Flash *f, int ladr)
- {
- ushort s;
- delay(1);
- if(fcycle(c, f) == -1)
- return -1;
- f->reg[Fsts] |= Fdone;
- f->reg32[Faddr] = ladr;
- /* setup flash control register */
- s = f->reg[Fctl];
- s &= ~(0x1f << 8);
- s |= (2-1) << 8; /* 2 bytes */
- s &= ~(2*Flcycle); /* read */
- f->reg[Fctl] = s | Fgo;
- while((f->reg[Fsts] & Fdone) == 0)
- ;
- if(f->reg[Fsts] & (Fcerr|Ael))
- return -1;
- return f->reg32[Fdata] & 0xffff;
- }
- static int
- fload(Ctlr *c)
- {
- ulong data, io, r, adr;
- ushort sum;
- Flash f;
- Pcidev *p;
- // io = c->pcidev->mem[1].bar & ~0x0f;
- // f.reg = vmap(io, c->pcidev->mem[1].size);
- // if(f.reg == nil)
- // return -1;
- p = c->pcidev;
- io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0);
- if(io == 0){
- print("i82566: can't map flash @ 0x%8.8lux\n", p->mem[1].bar);
- return -1;
- }
- f.reg = KADDR(io);
- f.reg32 = (ulong*)f.reg;
- f.sz = f.reg32[Bfpr];
- r = f.sz & 0x1fff;
- if(csr32r(c, Eec) & (1<<22))
- ++r;
- r <<= 12;
- sum = 0;
- for (adr = 0; adr < 0x40; adr++) {
- data = fread(c, &f, r + adr*2);
- if(data == -1)
- break;
- c->eeprom[adr] = data;
- sum += data;
- }
- // vunmap(f.reg, c->pcidev->mem[1].size);
- return sum;
- }
- static int
- i82563reset(Ctlr* ctlr)
- {
- int i, r;
- detach(ctlr);
- if(ctlr->type == i82566)
- r = fload(ctlr);
- else
- r = eeload(ctlr);
- if (r != 0 && r != 0xBABA){
- print("%s: bad EEPROM checksum - 0x%4.4ux\n", Type, r);
- return -1;
- }
- for(i = Ea; i < Eaddrlen/2; i++){
- ctlr->ra[2*i] = ctlr->eeprom[i];
- ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8;
- }
- r = (csr32r(ctlr, Status) & Lanid) >> 2;
- ctlr->ra[5] += r; /* ea ctlr[1] = ea ctlr[0]+1 */
- r = ctlr->ra[3]<<24 | ctlr->ra[2]<<16 | ctlr->ra[1]<<8 | ctlr->ra[0];
- csr32w(ctlr, Ral, r);
- r = 0x80000000 | ctlr->ra[5]<<8 | ctlr->ra[4];
- csr32w(ctlr, Rah, r);
- for(i = 1; i < 16; i++){
- csr32w(ctlr, Ral+i*8, 0);
- csr32w(ctlr, Rah+i*8, 0);
- }
- for(i = 0; i < 128; i++)
- csr32w(ctlr, Mta+i*4, 0);
- csr32w(ctlr, Fcal, 0x00C28001);
- csr32w(ctlr, Fcah, 0x00000100);
- csr32w(ctlr, Fct, 0x00008808);
- csr32w(ctlr, Fcttv, 0x00000100);
- csr32w(ctlr, Fcrtl, ctlr->fcrtl);
- csr32w(ctlr, Fcrth, ctlr->fcrth);
- ilock(&ctlr->imlock);
- csr32w(ctlr, Imc, ~0);
- ctlr->im = 0; /* was = Lsc, which hangs some controllers */
- csr32w(ctlr, Ims, ctlr->im);
- iunlock(&ctlr->imlock);
- return 0;
- }
- static void
- i82563pci(void)
- {
- int port, type, cls;
- Pcidev *p;
- Ctlr *ctlr;
- static int first = 1;
- if (first)
- first = 0;
- else
- return;
- p = nil;
- while(p = pcimatch(p, 0x8086, 0)){
- if(p->ccrb != 0x02 || p->ccru != 0)
- continue;
- //print("i82563pci: did %4.4#x\n", p->did);
- switch(p->did){
- case 0x1096:
- case 0x10ba:
- type = i82563;
- break;
- case 0x1049: /* mm */
- case 0x104a: /* dm */
- case 0x104d: /* v */
- case 0x10bd: /* dm */
- type = i82566;
- break;
- case 0x10a4:
- case 0x105e:
- type = i82571;
- break;
- case 0x10b9: /* sic, 82572 */
- type = i82572;
- break;
- case 0x108b: /* e */
- case 0x108c: /* e (iamt) */
- case 0x109a: /* l */
- type = i82573;
- break;
- case 0x10a7: /* 82575eb */
- type = i82575;
- break;
- default:
- continue;
- }
- port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
- if(port == 0){
- print("%s: can't map %d @ 0x%8.8lux\n", tname[type],
- p->mem[0].size, p->mem[0].bar);
- continue;
- }
- if(p->pcr & MemWrInv){
- cls = pcicfgr8(p, PciCLS) * 4;
- if(cls != CACHELINESZ)
- pcicfgw8(p, PciCLS, CACHELINESZ/4);
- }
- cls = pcicfgr8(p, PciCLS);
- switch(cls){
- default:
- print("%s: unexpected CLS - %d bytes\n",
- tname[type], cls*sizeof(long));
- break;
- case 0x00:
- case 0xFF:
- /* alphapc 164lx returns 0 */
- print("%s: unusable PciCLS: %d, using %d longs\n",
- tname[type], cls, CACHELINESZ/sizeof(long));
- cls = CACHELINESZ/sizeof(long);
- pcicfgw8(p, PciCLS, cls);
- break;
- case 0x08:
- case 0x10:
- break;
- }
- ctlr = malloc(sizeof(Ctlr));
- ctlr->port = port;
- ctlr->pcidev = p;
- ctlr->cls = cls*4;
- ctlr->type = type;
- ctlr->nic = KADDR(ctlr->port);
- if(i82563reset(ctlr)){
- free(ctlr);
- continue;
- }
- pcisetbme(p);
- if(ctlrhead != nil)
- ctlrtail->next = ctlr;
- else
- ctlrhead = ctlr;
- ctlrtail = ctlr;
- }
- }
- static uchar nilea[Eaddrlen];
- int
- i82563pnp(Ether* edev)
- {
- Ctlr *ctlr;
- if(ctlrhead == nil)
- i82563pci();
- /*
- * Any adapter matches if no edev->port is supplied,
- * otherwise the ports must match.
- */
- for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
- if(ctlr->active)
- continue;
- if(edev->port == 0 || edev->port == ctlr->port){
- ctlr->active = 1;
- break;
- }
- }
- if(ctlr == nil)
- return -1;
- edev->ctlr = ctlr;
- edev->port = ctlr->port;
- edev->irq = ctlr->pcidev->intl;
- edev->tbdf = ctlr->pcidev->tbdf;
- // edev->mbps = 1000;
- if(memcmp(edev->ea, nilea, Eaddrlen) == 0)
- memmove(edev->ea, ctlr->ra, Eaddrlen);
- i82563init(edev);
- /*
- * Linkage to the generic ethernet driver.
- */
- edev->attach = i82563attach;
- edev->transmit = i82563transmit;
- edev->interrupt = i82563interrupt;
- edev->detach = i82563detach;
- /*
- * with the current structure, there is no right place for this.
- * ideally, we recognize the interface, note it's down and move on.
- * currently either we can skip the interface or note it is down,
- * but not both.
- if((csr32r(ctlr, Status)&Lu) == 0){
- print("ether#%d: 82563 (%s): link down\n", edev->ctlrno, Type);
- return -1;
- }
- */
- return 0;
- }
|