| /* | 
 |  * Copyright 2008-2014 | 
 |  * erik quanstrom | 
 |  * | 
 |  * This software is provided `as-is,' without any express or implied | 
 |  * warranty.  In no event will the author be held liable for any damages | 
 |  * arising from the use of this software. | 
 |  * | 
 |  * Permission is granted to anyone to use this software for any purpose, | 
 |  * including commercial applications, and to alter it and redistribute it | 
 |  * freely, subject to the following restrictions: | 
 |  * | 
 |  * 1.  The origin of this software must not be misrepresented; you must | 
 |  * not claim that you wrote the original software.  If you use this | 
 |  * software in a product, an acknowledgment in the product documentation | 
 |  * would be appreciated but is not required. | 
 |  * | 
 |  * 2.  Altered source versions must be plainly marked as such, and must | 
 |  * not be misrepresented as being the original software. | 
 |  * | 
 |  * 3.  This notice may not be removed or altered from any source | 
 |  * distribution. | 
 |  */ | 
 | /* This code has been modified by UC Berkeley and Google to work in Akaros. */ | 
 | /* | 
 |  * Intel Gigabit Ethernet PCI-Express Controllers. | 
 |  *	8256[367], 8257[1-79], 21[078] | 
 |  * Pretty basic, does not use many of the chip smarts. | 
 |  * The interrupt mitigation tuning for each chip variant | 
 |  * is probably different. The reset/initialisation | 
 |  * sequence needs straightened out. Doubt the PHY code | 
 |  * for the 82575eb is right. | 
 |  * | 
 |  * on the assumption that allowing jumbo packets makes the controller | 
 |  * much slower (as is true of the 82579), never allow jumbos. | 
 |  */ | 
 | #include <assert.h> | 
 | #include <cpio.h> | 
 | #include <error.h> | 
 | #include <kmalloc.h> | 
 | #include <kref.h> | 
 | #include <net/ip.h> | 
 | #include <pmap.h> | 
 | #include <slab.h> | 
 | #include <smp.h> | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 |  | 
 | #define now() TK2MS(MACHP(0)->ticks) | 
 |  | 
 | /* | 
 |  * 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 = 0x0000,       /* Device Control */ | 
 | 	Status = 0x0008,     /* Device Status */ | 
 | 	Eec = 0x0010,        /* EEPROM/Flash Control/Data */ | 
 | 	Fextnvm6 = 0x0010,   /* Future Extended NVM 6 */ | 
 | 	Eerd = 0x0014,       /* EEPROM Read */ | 
 | 	Ctrlext = 0x0018,    /* Extended Device Control */ | 
 | 	Fla = 0x001c,        /* Flash Access */ | 
 | 	Mdic = 0x0020,       /* MDI Control */ | 
 | 	Seresctl = 0x0024,   /* Serdes ana */ | 
 | 	Fcal = 0x0028,       /* Flow Control Address Low */ | 
 | 	Fcah = 0x002C,       /* Flow Control Address High */ | 
 | 	Fct = 0x0030,        /* Flow Control Type */ | 
 | 	Kumctrlsta = 0x0034, /* MAC-PHY Interface */ | 
 | 	Vet = 0x0038,        /* VLAN EtherType */ | 
 | 	Fcttv = 0x0170,      /* Flow Control Transmit Timer Value */ | 
 | 	Txcw = 0x0178,       /* Transmit Configuration Word */ | 
 | 	Rxcw = 0x0180,       /* Receive Configuration Word */ | 
 | 	Ledctl = 0x0E00,     /* LED control */ | 
 | 	Pba = 0x1000,        /* Packet Buffer Allocation */ | 
 | 	Pbs = 0x1008,        /* Packet Buffer Size */ | 
 |  | 
 | 	/* Interrupt */ | 
 | 	Icr = 0x00C0, /* Interrupt Cause Read */ | 
 | 	Itr = 0x00c4, /* Interrupt Throttling Rate */ | 
 | 	Ics = 0x00C8, /* Interrupt Cause Set */ | 
 | 	Ims = 0x00D0, /* Interrupt Mask Set/Read */ | 
 | 	Imc = 0x00D8, /* Interrupt mask Clear */ | 
 | 	Iam = 0x00E0, /* Interrupt acknowledge Auto Mask */ | 
 |  | 
 | 	/* Receive */ | 
 | 	Rctl = 0x0100,    /* Control */ | 
 | 	Ert = 0x2008,     /* Early Receive Threshold (573[EVL], 579 only) */ | 
 | 	Fcrtl = 0x2160,   /* Flow Control RX Threshold Low */ | 
 | 	Fcrth = 0x2168,   /* Flow Control Rx Threshold High */ | 
 | 	Psrctl = 0x2170,  /* Packet Split Receive Control */ | 
 | 	Rdbal = 0x2800,   /* Rdesc Base Address Low Queue 0 */ | 
 | 	Rdbah = 0x2804,   /* Rdesc Base Address High Queue 0 */ | 
 | 	Rdlen = 0x2808,   /* Descriptor Length Queue 0 */ | 
 | 	Srrctl = 0x280c,  /* split and replication rx control (82575) */ | 
 | 	Rdh = 0x2810,     /* Descriptor Head Queue 0 */ | 
 | 	Rdt = 0x2818,     /* Descriptor Tail Queue 0 */ | 
 | 	Rdtr = 0x2820,    /* Descriptor Timer Ring */ | 
 | 	Rxdctl = 0x2828,  /* Descriptor Control */ | 
 | 	Radv = 0x282C,    /* Interrupt Absolute Delay Timer */ | 
 | 	Rdbal1 = 0x2900,  /* Rdesc Base Address Low Queue 1 */ | 
 | 	Rdbah1 = 0x2804,  /* Rdesc Base Address High Queue 1 */ | 
 | 	Rdlen1 = 0x2908,  /* Descriptor Length Queue 1 */ | 
 | 	Rdh1 = 0x2910,    /* Descriptor Head Queue 1 */ | 
 | 	Rdt1 = 0x2918,    /* Descriptor Tail Queue 1 */ | 
 | 	Rxdctl1 = 0x2928, /* Descriptor Control Queue 1 */ | 
 | 	Rsrpd = 0x2c00,   /* Small Packet Detect */ | 
 | 	Raid = 0x2c08,    /* ACK interrupt delay */ | 
 | 	Cpuvec = 0x2c10,  /* CPU Vector */ | 
 | 	Rxcsum = 0x5000,  /* Checksum Control */ | 
 | 	Rmpl = 0x5004,    /* rx maximum packet length (82575) */ | 
 | 	Rfctl = 0x5008,   /* Filter Control */ | 
 | 	Mta = 0x5200,     /* Multicast Table Array */ | 
 | 	Ral = 0x5400,     /* Receive Address Low */ | 
 | 	Rah = 0x5404,     /* Receive Address High */ | 
 | 	Vfta = 0x5600,    /* VLAN Filter Table Array */ | 
 | 	Mrqc = 0x5818,    /* Multiple Receive Queues Command */ | 
 | 	Rssim = 0x5864,   /* RSS Interrupt Mask */ | 
 | 	Rssir = 0x5868,   /* RSS Interrupt Request */ | 
 | 	Reta = 0x5c00,    /* Redirection Table */ | 
 | 	Rssrk = 0x5c80,   /* RSS Random Key */ | 
 |  | 
 | 	/* Transmit */ | 
 | 	Tctl = 0x0400, /* Transmit Control */ | 
 | 	Tipg = 0x0410, /* Transmit IPG */ | 
 | 	Tkabgtxd = | 
 | 	    0x3004,      /* glci afe band gap transmit ref data, or something */ | 
 | 	Tdbal = 0x3800,  /* Tdesc Base Address Low */ | 
 | 	Tdbah = 0x3804,  /* Tdesc Base Address High */ | 
 | 	Tdlen = 0x3808,  /* Descriptor Length */ | 
 | 	Tdh = 0x3810,    /* Descriptor Head */ | 
 | 	Tdt = 0x3818,    /* Descriptor Tail */ | 
 | 	Tidv = 0x3820,   /* Interrupt Delay Value */ | 
 | 	Txdctl = 0x3828, /* Descriptor Control */ | 
 | 	Tadv = 0x382C,   /* Interrupt Absolute Delay Timer */ | 
 | 	Tarc0 = 0x3840,  /* Arbitration Counter Queue 0 */ | 
 | 	Tdbal1 = 0x3900, /* Descriptor Base Low Queue 1 */ | 
 | 	Tdbah1 = 0x3904, /* Descriptor Base High Queue 1 */ | 
 | 	Tdlen1 = 0x3908, /* Descriptor Length Queue 1 */ | 
 | 	Tdh1 = 0x3910,   /* Descriptor Head Queue 1 */ | 
 | 	Tdt1 = 0x3918,   /* Descriptor Tail Queue 1 */ | 
 | 	Txdctl1 = 0x3928, /* Descriptor Control 1 */ | 
 | 	Tarc1 = 0x3940,   /* Arbitration Counter Queue 1 */ | 
 |  | 
 | 	/* Statistics */ | 
 | 	Statistics = 0x4000, /* 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 = 0x124 / 4, | 
 | }; | 
 |  | 
 | 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 */ | 
 |        Phyrst = 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 */ | 
 |        Phyra = 1 << 10,  /* PHY Reset Asserted */ | 
 |        GIOme = 1 << 19,  /* GIO Master Enable Status */ | 
 | }; | 
 |  | 
 | enum { | 
 | 	/* Eec */ | 
 | 	Nvpres = 1 << 8,   /* nvram present */ | 
 | 	Autord = 1 << 9,   /* autoread complete */ | 
 | 	Sec1val = 1 << 22, /* sector 1 valid (!sec0) */ | 
 | }; | 
 |  | 
 | enum {                   /* Eerd */ | 
 |        EEstart = 1 << 0, /* Start Read */ | 
 |        EEdone = 1 << 1,  /* Read done */ | 
 | }; | 
 |  | 
 | enum {                    /* Ctrlext */ | 
 |        Asdchk = 1 << 12,  /* ASD Check */ | 
 |        Eerst = 1 << 13,   /* EEPROM Reset */ | 
 |        Spdbyps = 1 << 15, /* Speed Select Bypass */ | 
 | }; | 
 |  | 
 | /* | 
 |  * TODO(dcross): 'Ea' is 0 elsewhere. Investigate and possibly correct. | 
 |  */ | 
 | enum {               /* EEPROM content offsets */ | 
 |        OldEa = 0x00, /* Old Ethernet address */ | 
 |        Ea = 0x01,    /* 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 {                 /* phy interface registers */ | 
 |        Phyctl = 0,     /* phy ctl */ | 
 |        Physsr = 17,    /* phy secondary status */ | 
 |        Phyier = 18,    /* 82573 phy interrupt enable */ | 
 |        Phyisr = 19,    /* 82563 phy interrupt status */ | 
 |        Phylhr = 19,    /* 8257[12] link health */ | 
 |        Phyier218 = 24, /* 218 (phy79?) phy interrupt enable */ | 
 |        Phyisr218 = 25, /* 218 (phy79?) phy interrupt status */ | 
 |        Phystat = 26,   /* 82580 (phy79?) phy status */ | 
 |        Phypage = 31,   /* page number */ | 
 |  | 
 |        Rtlink = 1 << 10, /* realtime link status */ | 
 |        Phyan = 1 << 11,  /* phy has auto-negotiated */ | 
 |  | 
 |        /* Phyctl bits */ | 
 |        Ran = 1 << 9,  /* restart auto-negotiation */ | 
 |        Ean = 1 << 12, /* enable auto-negotiation */ | 
 |  | 
 |        /* 82573 Phyier interrupt enable bits */ | 
 |        Lscie = 1 << 10, /* link status changed */ | 
 |        Ancie = 1 << 11, /* auto-negotiation complete */ | 
 |        Spdie = 1 << 14, /* speed changed */ | 
 |        Panie = 1 << 15, /* phy auto-negotiation error */ | 
 |  | 
 |        /* Phylhr/Phyisr bits */ | 
 |        Anf = 1 << 6,  /* lhr: auto-negotiation fault */ | 
 |        Ane = 1 << 15, /* isr: auto-negotiation error */ | 
 |  | 
 |        /* 82580 Phystat bits */ | 
 |        Ans = 3 << 14, /* 82580 autoneg. status */ | 
 |        Link = 1 << 6, /* 82580 link */ | 
 |  | 
 |        /* 218 Phystat bits */ | 
 |        Anfs = 3 << 13,   /* fault status */ | 
 |        Ans218 = 1 << 12, /* autoneg complete */ | 
 |  | 
 |        /* 218 Phyier218 interrupt enable bits */ | 
 |        Spdie218 = 1 << 1, /* speed changed */ | 
 |        Lscie218 = 1 << 2, /* link status changed */ | 
 |        Ancie218 = 1 << 8, /* auto-negotiation changed */ | 
 | }; | 
 |  | 
 | 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 */ | 
 |        Bsize16384 = 0x00010000,   /* Bsex = 1 */ | 
 |        Bsize8192 = 0x00020000,    /* Bsex = 1 */ | 
 |        Bsize2048 = 0x00000000, | 
 |        Bsize1024 = 0x00010000, | 
 |        Bsize512 = 0x00020000, | 
 |        Bsize256 = 0x00030000, | 
 |        BsizeFlex = 0x08000000, /* Flexible Bsize in 1KB increments */ | 
 |        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 { /* Srrctl */ | 
 |        Dropen = 1 << 31, | 
 | }; | 
 |  | 
 | 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, /* Writeback Threshold */ | 
 |        WthreshSHIFT = 16, | 
 |        Gran = 0x01000000,    /* Granularity (descriptors, not cls) */ | 
 |        Qenable = 0x02000000, /* Queue Enable (82575) */ | 
 | }; | 
 |  | 
 | enum {                    /* Rxcsum */ | 
 |        PcssMASK = 0x00FF, /* Packet Checksum Start */ | 
 |        PcssSHIFT = 0, | 
 |        Ipofl = 0x0100, /* IP Checksum Off-load Enable */ | 
 |        Tuofl = 0x0200, /* TCP/UDP Checksum Off-load Enable */ | 
 | }; | 
 |  | 
 | enum {                     /* Receive Delay Timer Ring */ | 
 |        DelayMASK = 0xFFFF, /* delay timer in 1.024nS increments */ | 
 |        DelaySHIFT = 0, | 
 |        Fpd = 0x80000000, /* Flush partial Descriptor Block */ | 
 | }; | 
 |  | 
 | struct rd { /* Receive Descriptor */ | 
 | 	uint32_t addr[2]; | 
 | 	uint16_t length; | 
 | 	uint16_t checksum; | 
 | 	uint8_t status; | 
 | 	uint8_t errors; | 
 | 	uint16_t special; | 
 | }; | 
 |  | 
 | enum {               /* Rd 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 {              /* Rd 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 */ | 
 | }; | 
 |  | 
 | struct td {               /* Transmit Descriptor */ | 
 | 	uint32_t addr[2]; /* Data */ | 
 | 	uint32_t control; | 
 | 	uint32_t status; | 
 | }; | 
 |  | 
 | 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 = 0x0001,     /* Descriptor Done */ | 
 |        Ec = 0x0002,      /* Excess Collisions */ | 
 |        Lc = 0x0004,      /* Late Collision */ | 
 |        Tu = 0x0008,      /* Transmit Underrun */ | 
 |        CssMASK = 0xFF00, /* Checksum Start Field */ | 
 |        CssSHIFT = 8, | 
 | }; | 
 |  | 
 | struct flash { | 
 | 	uint16_t *reg; | 
 | 	uint32_t *reg32; | 
 | 	uint16_t base; | 
 | 	uint16_t lim; | 
 | }; | 
 |  | 
 | 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 */ | 
 | }; | 
 |  | 
 | /* | 
 |  * the kumeran interface is mac-to-phy for external gigabit ethernet on | 
 |  * intel's esb2 ich8 (io controller hub), it carries mii bits.  can be used | 
 |  * to reset the phy.  intel proprietary, see "kumeran specification". | 
 |  */ | 
 | enum { I217inbandctlpage = 770, /* phy page */ | 
 |        I217inbandctlreg = 18,   /* phy register */ | 
 |        I217inbandctllnkststxtmoutmask = 0x3F00, | 
 |        I217inbandctllnkststxtmoutshift = 8, | 
 |  | 
 |        Fextnvm6reqpllclk = 0x100, | 
 |        Fextnvm6enak1entrycond = 0x200, /* extend K1 entry latency */ | 
 |  | 
 |        Nvmk1cfg = 0x1B,   /* NVM K1 Config Word */ | 
 |        Nvmk1enable = 0x1, /* NVM Enable K1 bit */ | 
 |  | 
 |        Kumctrlstaoff = 0x1F0000, | 
 |        Kumctrlstaoffshift = 16, | 
 |        Kumctrlstaren = 0x200000, | 
 |        Kumctrlstak1cfg = 0x7, | 
 |        Kumctrlstak1enable = 0x2, | 
 | }; | 
 |  | 
 | enum { | 
 | 	/* | 
 | 	 * these were 512, 1024 & 64, but 52, 253 & 9 are usually ample; | 
 | 	 * however cpu servers and terminals can need more receive buffers | 
 | 	 * due to bursts of traffic. | 
 | 	 * | 
 | 	 * Tdlen and Rdlen have to be multiples of 128.  Rd and Td are both | 
 | 	 * 16 bytes long, so Nrd and Ntd must be multiples of 8. | 
 | 	 */ | 
 | 	Ntd = 32,  /* power of two >= 8 */ | 
 | 	Nrd = 128, /* power of two >= 8 */ | 
 | 	Rbalign = 16, | 
 | 	Slop = 32, /* for vlan headers, crcs, etc. */ | 
 | }; | 
 |  | 
 | enum { Iany = -1, | 
 |        i82563, | 
 |        i82566, | 
 |        i82567, | 
 |        i82567m, | 
 |        i82571, | 
 |        i82572, | 
 |        i82573, | 
 |        i82574, | 
 |        i82575, | 
 |        i82576, | 
 |        i82577, | 
 |        i82577m, | 
 |        i82578, | 
 |        i82578m, | 
 |        i82579, | 
 |        i82580, | 
 |        i82583, | 
 |        i210, | 
 |        i217, | 
 |        i218, | 
 |        i350, | 
 |        Nctlrtype, | 
 | }; | 
 |  | 
 | enum { Fload = 1 << 0, | 
 |        Fert = 1 << 1, | 
 |        F75 = 1 << 2, | 
 |        Fpba = 1 << 3, | 
 |        Fflashea = 1 << 4, | 
 |        F79phy = 1 << 5, | 
 |        Fnofct = 1 << 6, | 
 | }; | 
 |  | 
 | struct ctlrtype { | 
 | 	int type; | 
 | 	int mtu; | 
 | 	int phyno; | 
 | 	char *name; | 
 | 	int flag; | 
 | }; | 
 |  | 
 | static struct ctlrtype ctlrtab[Nctlrtype] = { | 
 |     {i82563, 9014, 1, "i82563", Fpba}, | 
 |     {i82566, 1514, 1, "i82566", Fload}, | 
 |     {i82567, 9234, 1, "i82567", Fload}, | 
 |     {i82567m, 1514, 1, "i82567m", 0}, | 
 |     {i82571, 9234, 1, "i82571", Fpba}, | 
 |     {i82572, 9234, 1, "i82572", Fpba}, | 
 |     {i82573, 8192, 1, "i82573", Fert}, /* terrible perf above 8k */ | 
 |     {i82574, 9018, 1, "i82574", 0}, | 
 |     {i82575, 9728, 1, "i82575", F75 | Fflashea}, | 
 |     {i82576, 9728, 1, "i82576", F75}, | 
 |     {i82577, 4096, 2, "i82577", Fload | Fert}, | 
 |     {i82577m, 1514, 2, "i82577", Fload | Fert}, | 
 |     {i82578, 4096, 2, "i82578", Fload | Fert}, | 
 |     {i82578m, 1514, 2, "i82578", Fload | Fert}, | 
 |     {i82579, 9018, 2, "i82579", Fload | Fert | F79phy | Fnofct}, | 
 |     {i82580, 9728, 1, "i82580", F75 | F79phy}, | 
 |     {i82583, 1514, 1, "i82583", 0}, | 
 |     {i210, 9728, 1, "i210", F75 | Fnofct | Fert}, | 
 |     {i217, 9728, 1, "i217", F79phy | Fnofct | Fload | Fert}, | 
 |     {i350, 9728, 1, "i350", F75 | F79phy | Fnofct}, | 
 | }; | 
 |  | 
 | struct ctlr { | 
 | 	struct pci_device *pcidev; | 
 | 	struct ctlr *next; | 
 | 	struct ether *edev; | 
 | 	int active; | 
 | 	int type; | 
 | 	uint16_t eeprom[0x40]; | 
 |  | 
 | 	qlock_t alock; /* attach */ | 
 | 	void *alloc; | 
 | 	unsigned int rbsz; | 
 | 	int attached; | 
 |  | 
 | 	int *nic; | 
 | 	spinlock_t imlock; | 
 | 	int im; /* interrupt mask */ | 
 |  | 
 | 	struct rendez lrendez; | 
 | 	int lim; | 
 | 	int phynum; | 
 | 	int didk1fix; | 
 |  | 
 | 	qlock_t slock; | 
 | 	unsigned int statistics[Nstatistics]; | 
 | 	unsigned int lsleep; | 
 | 	unsigned int lintr; | 
 | 	unsigned int rsleep; | 
 | 	unsigned int rintr; | 
 | 	unsigned int txdw; | 
 | 	unsigned int tintr; | 
 | 	unsigned int ixsm; | 
 | 	unsigned int ipcs; | 
 | 	unsigned int tcpcs; | 
 | 	unsigned int speeds[4]; | 
 |  | 
 | 	uint8_t ra[Eaddrlen]; /* receive address */ | 
 | 	uint32_t mta[128];    /* multicast table array */ | 
 |  | 
 | 	struct rendez rrendez; | 
 | 	int rim; | 
 | 	int rdfree;        /* rx descriptors awaiting packets */ | 
 | 	struct rd *rdba;   /* receive descriptor base address */ | 
 | 	struct block **rb; /* receive buffers */ | 
 | 	unsigned int rdh;  /* receive descriptor head */ | 
 | 	unsigned int rdt;  /* receive descriptor tail */ | 
 | 	int rdtr;          /* receive delay timer ring value */ | 
 | 	int radv;          /* receive interrupt absolute delay timer */ | 
 |  | 
 | 	struct rendez trendez; | 
 | 	qlock_t tlock; | 
 | 	struct td *tdba;   /* transmit descriptor base address */ | 
 | 	struct block **tb; /* transmit buffers */ | 
 | 	int tdh;           /* transmit descriptor head */ | 
 | 	int tdt;           /* transmit descriptor tail */ | 
 |  | 
 | 	int fcrtl; | 
 | 	int fcrth; | 
 |  | 
 | 	unsigned int pbs; /* packet buffer size */ | 
 | 	unsigned int pba; /* packet buffer allocation */ | 
 | }; | 
 |  | 
 | static inline uint32_t csr32r(struct ctlr *c, uintptr_t reg) | 
 | { | 
 | 	return read_mmreg32((uintptr_t)(c->nic + (reg / 4))); | 
 | } | 
 |  | 
 | static inline void csr32w(struct ctlr *c, uintptr_t reg, uint32_t val) | 
 | { | 
 | 	write_mmreg32((uintptr_t)(c->nic + (reg / 4)), val); | 
 | } | 
 |  | 
 | static struct ctlr *i82563ctlrhead; | 
 | static struct ctlr *i82563ctlrtail; | 
 |  | 
 | static int speedtab[] = {10, 100, 1000, 0}; | 
 |  | 
 | static char *statistics[] = { | 
 |     "CRC Error", | 
 |     "Alignment Error", | 
 |     "Symbol Error", | 
 |     "RX Error", | 
 |     "Missed Packets", | 
 |     "Single Collision", | 
 |     "Excessive Collisions", | 
 |     "Multiple Collision", | 
 |     "Late Collisions", | 
 |     NULL, | 
 |     "Collision", | 
 |     "Transmit Underrun", | 
 |     "Defer", | 
 |     "Transmit - No CRS", | 
 |     "Sequence Error", | 
 |     "Carrier Extension Error", | 
 |     "Receive Error Length", | 
 |     NULL, | 
 |     "XON Received", | 
 |     "XON Transmitted", | 
 |     "XOFF Received", | 
 |     "XOFF Transmitted", | 
 |     "FC Received Unsupported", | 
 |     "Packets Received (64 Bytes)", | 
 |     "Packets Received (65-127 Bytes)", | 
 |     "Packets Received (128-255 Bytes)", | 
 |     "Packets Received (256-511 Bytes)", | 
 |     "Packets Received (512-1023 Bytes)", | 
 |     "Packets Received (1024-mtu Bytes)", | 
 |     "Good Packets Received", | 
 |     "Broadcast Packets Received", | 
 |     "Multicast Packets Received", | 
 |     "Good Packets Transmitted", | 
 |     NULL, | 
 |     "Good Octets Received", | 
 |     NULL, | 
 |     "Good Octets Transmitted", | 
 |     NULL, | 
 |     NULL, | 
 |     NULL, | 
 |     "Receive No Buffers", | 
 |     "Receive Undersize", | 
 |     "Receive Fragment", | 
 |     "Receive Oversize", | 
 |     "Receive Jabber", | 
 |     "Management Packets Rx", | 
 |     "Management Packets Drop", | 
 |     "Management Packets Tx", | 
 |     "Total Octets Received", | 
 |     NULL, | 
 |     "Total Octets Transmitted", | 
 |     NULL, | 
 |     "Total Packets Received", | 
 |     "Total Packets Transmitted", | 
 |     "Packets Transmitted (64 Bytes)", | 
 |     "Packets Transmitted (65-127 Bytes)", | 
 |     "Packets Transmitted (128-255 Bytes)", | 
 |     "Packets Transmitted (256-511 Bytes)", | 
 |     "Packets Transmitted (512-1023 Bytes)", | 
 |     "Packets Transmitted (1024-mtu Bytes)", | 
 |     "Multicast Packets Transmitted", | 
 |     "Broadcast Packets Transmitted", | 
 |     "TCP Segmentation Context Transmitted", | 
 |     "TCP Segmentation Context Fail", | 
 |     "Interrupt Assertion", | 
 |     "Interrupt Rx Pkt Timer", | 
 |     "Interrupt Rx Abs Timer", | 
 |     "Interrupt Tx Pkt Timer", | 
 |     "Interrupt Tx Abs Timer", | 
 |     "Interrupt Tx Queue Empty", | 
 |     "Interrupt Tx Desc Low", | 
 |     "Interrupt Rx Min", | 
 |     "Interrupt Rx Overrun", | 
 | }; | 
 |  | 
 | static char *cname(struct ctlr *c) | 
 | { | 
 | 	return ctlrtab[c->type].name; | 
 | } | 
 |  | 
 | static int i82563reset(struct ctlr *); | 
 |  | 
 | static long i82563ifstat(struct ether *edev, void *a, long n, uint32_t offset) | 
 | { | 
 | 	struct ctlr *ctlr; | 
 | 	char *s, *p, *e, *stat; | 
 | 	int i, r; | 
 | 	uint64_t tuvl, ruvl; | 
 |  | 
 | 	ctlr = edev->ctlr; | 
 | 	qlock(&ctlr->slock); | 
 | 	p = s = kzmalloc(READSTR, 0); | 
 | 	if (p == NULL) { | 
 | 		qunlock(&ctlr->slock); | 
 | 		error(ENOMEM, "kzmalloc did not panic"); | 
 | 	} | 
 | 	e = p + READSTR; | 
 |  | 
 | 	for (i = 0; i < Nstatistics; i++) { | 
 | 		r = csr32r(ctlr, Statistics + i * 4); | 
 | 		stat = statistics[i]; | 
 | 		if (stat == NULL) | 
 | 			continue; | 
 | 		switch (i) { | 
 | 		case Gorcl: | 
 | 		case Gotcl: | 
 | 		case Torl: | 
 | 		case Totl: | 
 | 			ruvl = r; | 
 | 			ruvl += (uint64_t)csr32r(ctlr, Statistics + (i + 1) * 4) | 
 | 			        << 32; | 
 | 			tuvl = ruvl; | 
 | 			tuvl += ctlr->statistics[i]; | 
 | 			tuvl += (uint64_t)ctlr->statistics[i + 1] << 32; | 
 | 			if (tuvl == 0) | 
 | 				continue; | 
 | 			ctlr->statistics[i] = tuvl; | 
 | 			ctlr->statistics[i + 1] = tuvl >> 32; | 
 | 			p = seprintf(p, e, "%s: %llud %llud\n", stat, tuvl, | 
 | 			             ruvl); | 
 | 			i++; | 
 | 			break; | 
 |  | 
 | 		default: | 
 | 			ctlr->statistics[i] += r; | 
 | 			if (ctlr->statistics[i] == 0) | 
 | 				continue; | 
 | 			p = seprintf(p, e, "%s: %ud %ud\n", stat, | 
 | 			             ctlr->statistics[i], r); | 
 | 			break; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	p = seprintf(p, e, "lintr: %ud %ud\n", ctlr->lintr, ctlr->lsleep); | 
 | 	p = seprintf(p, e, "rintr: %ud %ud\n", ctlr->rintr, ctlr->rsleep); | 
 | 	p = seprintf(p, e, "tintr: %ud %ud\n", ctlr->tintr, ctlr->txdw); | 
 | 	p = seprintf(p, e, "ixcs: %ud %ud %ud\n", ctlr->ixsm, ctlr->ipcs, | 
 | 	             ctlr->tcpcs); | 
 | 	p = seprintf(p, e, "ctrl: %.8ux\n", csr32r(ctlr, Ctrl)); | 
 | 	p = seprintf(p, e, "ctrlext: %.8ux\n", csr32r(ctlr, Ctrlext)); | 
 | 	p = seprintf(p, e, "status: %.8ux\n", csr32r(ctlr, Status)); | 
 | 	p = seprintf(p, e, "txcw: %.8ux\n", csr32r(ctlr, Txcw)); | 
 | 	p = seprintf(p, e, "txdctl: %.8ux\n", csr32r(ctlr, Txdctl)); | 
 | 	p = seprintf(p, e, "pbs: %dKB\n", ctlr->pbs); | 
 | 	p = seprintf(p, e, "pba: %#.8ux\n", ctlr->pba); | 
 |  | 
 | 	p = seprintf(p, e, "speeds: 10:%ud 100:%ud 1000:%ud ?:%ud\n", | 
 | 	             ctlr->speeds[0], ctlr->speeds[1], ctlr->speeds[2], | 
 | 	             ctlr->speeds[3]); | 
 | 	p = seprintf(p, e, "type: %s\n", cname(ctlr)); | 
 |  | 
 | 	//  p = seprintf(p, e, "eeprom:"); | 
 | 	//  for(i = 0; i < 0x40; i++){ | 
 | 	//      if(i && ((i & 7) == 0)) | 
 | 	//          p = seprintf(p, e, "\n       "); | 
 | 	//      p = seprintf(p, e, " %4.4ux", ctlr->eeprom[i]); | 
 | 	//  } | 
 | 	//  p = seprintf(p, e, "\n"); | 
 |  | 
 | 	n = readstr(offset, a, n, s); | 
 | 	kfree(s); | 
 | 	qunlock(&ctlr->slock); | 
 |  | 
 | 	return n; | 
 | } | 
 |  | 
 | enum { CMrdtr, | 
 |        CMradv, | 
 |        CMpause, | 
 |        CMan, | 
 | }; | 
 |  | 
 | static struct cmdtab i82563ctlmsg[] = { | 
 |     {CMrdtr, "rdtr", 2}, | 
 |     {CMradv, "radv", 2}, | 
 |     {CMpause, "pause", 1}, | 
 |     {CMan, "an", 1}, | 
 | }; | 
 |  | 
 | static long i82563ctl(struct ether *edev, void *buf, size_t n) | 
 | { | 
 | 	ERRSTACK(1); | 
 | 	char *p; | 
 | 	uint32_t v; | 
 | 	struct ctlr *ctlr; | 
 | 	struct cmdbuf *cb; | 
 | 	struct cmdtab *ct; | 
 |  | 
 | 	ctlr = edev->ctlr; | 
 | 	if (ctlr == NULL) | 
 | 		error(ENODEV, "i82563ctl: NULL controller"); | 
 |  | 
 | 	cb = parsecmd(buf, n); | 
 | 	if (waserror()) { | 
 | 		kfree(cb); | 
 | 		nexterror(); | 
 | 	} | 
 |  | 
 | 	ct = lookupcmd(cb, i82563ctlmsg, ARRAY_SIZE(i82563ctlmsg)); | 
 | 	switch (ct->index) { | 
 | 	case CMrdtr: | 
 | 		v = strtoul(cb->f[1], &p, 0); | 
 | 		if (*p || v > 0xffff) | 
 | 			error(EINVAL, ERROR_FIXME); | 
 | 		ctlr->rdtr = v; | 
 | 		csr32w(ctlr, Rdtr, v); | 
 | 		break; | 
 | 	case CMradv: | 
 | 		v = strtoul(cb->f[1], &p, 0); | 
 | 		if (*p || v > 0xffff) | 
 | 			error(EINVAL, ERROR_FIXME); | 
 | 		ctlr->radv = v; | 
 | 		csr32w(ctlr, Radv, v); | 
 | 		break; | 
 | 	case CMpause: | 
 | 		csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) ^ (Rfce | Tfce)); | 
 | 		break; | 
 | 	case CMan: | 
 | 		csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) | Lrst | Phyrst); | 
 | 		break; | 
 | 	} | 
 | 	kfree(cb); | 
 | 	poperror(); | 
 |  | 
 | 	return n; | 
 | } | 
 |  | 
 | static void i82563promiscuous(void *arg, int on) | 
 | { | 
 | 	int rctl; | 
 | 	struct ctlr *ctlr; | 
 | 	struct ether *edev; | 
 |  | 
 | 	edev = arg; | 
 | 	ctlr = edev->ctlr; | 
 |  | 
 | 	rctl = csr32r(ctlr, Rctl) & ~MoMASK; | 
 | 	if (on) | 
 | 		rctl |= Upe | Mpe; | 
 | 	else | 
 | 		rctl &= ~(Upe | Mpe); | 
 | 	csr32w(ctlr, Rctl, rctl); | 
 | } | 
 |  | 
 | /* | 
 |  * Returns the number of bits of mac address used in multicast hash, | 
 |  * thus the number of longs of ctlr->mta (2^(bits-5)). | 
 |  * This must be right for multicast (thus ipv6) to work reliably. | 
 |  * | 
 |  * The default multicast hash for mta is based on 12 bits of MAC address; | 
 |  * the rightmost bit is a function of Rctl's Multicast Offset: 0=>36, | 
 |  * 1=>35, 2=>34, 3=>32.  Exceptions include the 578, 579, 217, 218, 219; | 
 |  * they use only 10 bits, ignoring the rightmost 2 of the 12. | 
 |  */ | 
 | static int mcastbits(struct ctlr *ctlr) | 
 | { | 
 | 	switch (ctlr->type) { | 
 | 	/* | 
 | 	 * openbsd says all `ich8' versions (ich8, ich9, ich10, pch, | 
 | 	 * pch2 and pch_lpt) have 32 longs (use 10 bits of mac address | 
 | 	 * for hash). | 
 | 	 */ | 
 | 	case i82566: | 
 | 	case i82567: | 
 | 		//	case i82578: | 
 | 	case i82579: | 
 | 	case i217: | 
 | 	case i218: | 
 | 		//	case i219: | 
 | 		return 10; /* 32 longs */ | 
 | 	case i82563: | 
 | 	case i82571: | 
 | 	case i82572: | 
 | 	case i82573: | 
 | 	case i82574: | 
 | 		//	case i82575: | 
 | 		//	case i82583: | 
 | 	case i210:         /* includes i211 */ | 
 | 		return 12; /* 128 longs */ | 
 | 	default: | 
 | 		printk("82563: unsure of multicast bits in mac addresses; " | 
 | 		       "enabling promiscuous multicast reception\n"); | 
 | 		csr32w(ctlr, Rctl, csr32r(ctlr, Rctl) | Mpe); | 
 | 		return 10; /* be conservative (for mta size) */ | 
 | 	} | 
 | } | 
 |  | 
 | static int mcbitstolongs(int nmcbits) | 
 | { | 
 | 	return 1 << (nmcbits - 5); /* 2^5 = 32 */ | 
 | } | 
 |  | 
 | static void i82563multicast(void *arg, uint8_t *addr, int on) | 
 | { | 
 | 	uint32_t nbits, tblsz, hash, word, bit; | 
 | 	struct ctlr *ctlr; | 
 | 	struct ether *edev; | 
 |  | 
 | 	edev = arg; | 
 | 	ctlr = edev->ctlr; | 
 |  | 
 | 	nbits = mcastbits(ctlr); | 
 | 	tblsz = mcbitstolongs(nbits); | 
 | 	/* assume multicast offset in Rctl is 0 (we clear it above) */ | 
 | 	hash = addr[5] << 4 | addr[4] >> 4; /* bits 47:36 of mac */ | 
 | 	if (nbits == 10) | 
 | 		hash >>= 2; /* discard 37:36 of mac */ | 
 | 	word = (hash / 32) & (tblsz - 1); | 
 | 	bit = 1UL << (hash % 32); | 
 | 	/* | 
 | 	 * multiple ether addresses can hash to the same filter bit, | 
 | 	 * so it's never safe to clear a filter bit. | 
 | 	 * if we want to clear filter bits, we need to keep track of | 
 | 	 * all the multicast addresses in use, clear all the filter bits, | 
 | 	 * then set the ones corresponding to in-use addresses. | 
 | 	 */ | 
 | 	if (on) | 
 | 		ctlr->mta[word] |= bit; | 
 | 	//	else | 
 | 	//		ctlr->mta[word] &= ~bit; | 
 | 	csr32w(ctlr, Mta + word * 4, ctlr->mta[word]); | 
 | } | 
 |  | 
 | static void i82563im(struct ctlr *ctlr, int im) | 
 | { | 
 | 	spin_lock_irqsave(&ctlr->imlock); | 
 | 	ctlr->im |= im; | 
 | 	csr32w(ctlr, Ims, ctlr->im); | 
 | 	spin_unlock_irqsave(&ctlr->imlock); | 
 | } | 
 |  | 
 | static void i82563txinit(struct ctlr *ctlr) | 
 | { | 
 | 	int i, r, tctl; | 
 | 	struct block *bp; | 
 |  | 
 | 	/* | 
 | 	 * TODO(dcross): Figure out how to integrate this table driven | 
 | 	 * code into the stanza below. | 
 | 	 */ | 
 | 	tctl = 0x0F << Ctshift | Psp; | 
 | 	if (0) { | 
 | 		if ((ctlrtab[ctlr->type].flag & F75) == 0) | 
 | 			tctl |= (66 << ColdSHIFT | Mulr); | 
 | 	} | 
 | 	switch (ctlr->type) { | 
 | 	case i210: | 
 | 		break; | 
 | 	default: | 
 | 		tctl |= Mulr; | 
 | 		/* fall through */ | 
 | 	case i217: | 
 | 	case i218: | 
 | 		tctl |= 66 << ColdSHIFT; | 
 | 		break; | 
 | 	} | 
 | 	csr32w(ctlr, Tctl, tctl); | 
 | 	csr32w(ctlr, Tipg, 6 << 20 | 8 << 10 | 8); /* yb sez: 0x702008 */ | 
 | 	for (i = 0; i < Ntd; i++) { | 
 | 		bp = ctlr->tb[i]; | 
 | 		if (bp != NULL) { | 
 | 			ctlr->tb[i] = NULL; | 
 | 			freeb(bp); | 
 | 		} | 
 | 	} | 
 | 	memset(ctlr->tdba, 0, Ntd * sizeof(struct td)); | 
 | 	csr32w(ctlr, Tdbal, paddr_low32(ctlr->tdba)); | 
 | 	csr32w(ctlr, Tdbah, paddr_high32(ctlr->tdba)); | 
 | 	csr32w(ctlr, Tdlen, Ntd * sizeof(struct td)); | 
 | 	ctlr->tdh = PREV_RING(0, Ntd); | 
 | 	csr32w(ctlr, Tdh, 0); | 
 | 	ctlr->tdt = 0; | 
 | 	csr32w(ctlr, Tdt, 0); | 
 | 	csr32w(ctlr, Tidv, 0); /* don't coalesce interrupts */ | 
 | 	csr32w(ctlr, Tadv, 0); | 
 | 	r = csr32r(ctlr, Txdctl) & ~(WthreshMASK | PthreshMASK); | 
 | 	r |= 4 << WthreshSHIFT | 4 << PthreshSHIFT; | 
 | 	if (ctlrtab[ctlr->type].flag & F75) | 
 | 		r |= Qenable; | 
 | 	csr32w(ctlr, Txdctl, r); | 
 | 	csr32w(ctlr, Tctl, csr32r(ctlr, Tctl) | Ten); | 
 | } | 
 |  | 
 | static int i82563cleanup(struct ctlr *ctlr) | 
 | { | 
 | 	struct block *bp; | 
 | 	int tdh, n; | 
 |  | 
 | 	tdh = ctlr->tdh; | 
 | 	while (ctlr->tdba[n = NEXT_RING(tdh, Ntd)].status & Tdd) { | 
 | 		tdh = n; | 
 | 		bp = ctlr->tb[tdh]; | 
 | 		if (bp != NULL) { | 
 | 			ctlr->tb[tdh] = NULL; | 
 | 			freeb(bp); | 
 | 		} else | 
 | 			iprint("82563 tx underrun!\n"); | 
 | 		ctlr->tdba[tdh].status = 0; | 
 | 	} | 
 | 	return ctlr->tdh = tdh; | 
 | } | 
 |  | 
 | static void i82563transmit(struct ether *edev) | 
 | { | 
 | 	struct td *td; | 
 | 	struct block *bp; | 
 | 	struct ctlr *ctlr; | 
 | 	int tdh, tdt; | 
 |  | 
 | 	ctlr = edev->ctlr; | 
 | 	qlock(&ctlr->tlock); | 
 |  | 
 | 	/* | 
 | 	 * Free any completed packets | 
 | 	 */ | 
 | 	tdh = i82563cleanup(ctlr); | 
 |  | 
 | 	/* if link down on 218, don't try since we need k1fix to run first */ | 
 | 	if (!edev->link && ctlr->type == i218 && !ctlr->didk1fix) { | 
 | 		qunlock(&ctlr->tlock); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Try to fill the ring back up. | 
 | 	 */ | 
 | 	tdt = ctlr->tdt; | 
 | 	for (;;) { | 
 | 		if (NEXT_RING(tdt, Ntd) == tdh) { /* ring full? */ | 
 | 			ctlr->txdw++; | 
 | 			i82563im(ctlr, Txdw); | 
 | 			break; | 
 | 		} | 
 | 		bp = qget(edev->oq); | 
 | 		if (bp == NULL) | 
 | 			break; | 
 | 		td = &ctlr->tdba[tdt]; | 
 | 		td->addr[0] = paddr_low32(bp->rp); | 
 | 		td->addr[1] = paddr_high32(bp->rp); | 
 | 		td->control = Ide | Rs | Ifcs | Teop | BLEN(bp); | 
 | 		ctlr->tb[tdt] = bp; | 
 | 		tdt = NEXT_RING(tdt, Ntd); | 
 | 	} | 
 | 	if (ctlr->tdt != tdt) { | 
 | 		ctlr->tdt = tdt; | 
 | 		wmb_f(); | 
 | 		csr32w(ctlr, Tdt, tdt); | 
 | 	} | 
 | 	/* else may not be any new ones, but could be some still in flight */ | 
 | 	qunlock(&ctlr->tlock); | 
 | } | 
 |  | 
 | static void i82563replenish(struct ctlr *ctlr) | 
 | { | 
 | 	struct rd *rd; | 
 | 	int rdt; | 
 | 	struct block *bp; | 
 |  | 
 | 	rdt = ctlr->rdt; | 
 | 	while (NEXT_RING(rdt, Nrd) != ctlr->rdh) { | 
 | 		rd = &ctlr->rdba[rdt]; | 
 | 		if (ctlr->rb[rdt] != NULL) { | 
 | 			printd("#l%d: 82563: rx overrun\n", ctlr->edev->ctlrno); | 
 | 			break; | 
 | 		} | 
 | 		bp = block_alloc(ctlr->rbsz + Slop + Rbalign, MEM_ATOMIC); | 
 | 		if (bp == NULL) { | 
 | 			warn_once("OOM, trying to survive"); | 
 | 			break; | 
 | 		} | 
 | 		ctlr->rb[rdt] = bp; | 
 | 		rd->addr[0] = paddr_low32(bp->rp); | 
 | 		rd->addr[1] = paddr_high32(bp->rp); | 
 | 		rd->status = 0; | 
 | 		ctlr->rdfree++; | 
 | 		rdt = NEXT_RING(rdt, Nrd); | 
 | 	} | 
 | 	if (ctlr->rdt != rdt) { | 
 | 		ctlr->rdt = rdt; | 
 | 		wmb_f(); | 
 | 		csr32w(ctlr, Rdt, rdt); | 
 | 	} | 
 | } | 
 |  | 
 | static void i82563rxinit(struct ctlr *ctlr) | 
 | { | 
 | 	struct block *bp; | 
 | 	int i, r, rctl, type; | 
 |  | 
 | 	type = ctlr->type; | 
 |  | 
 | 	if (ctlr->rbsz <= 2048) | 
 | 		csr32w(ctlr, Rctl, Dpf | Bsize2048 | Bam | RdtmsHALF); | 
 | 	else { | 
 | 		i = ctlr->rbsz / 1024; | 
 | 		if (ctlr->rbsz % 1024) | 
 | 			i++; | 
 | 		if (ctlrtab[ctlr->type].flag & F75) { | 
 | 			csr32w(ctlr, Rctl, | 
 | 			       Lpe | Dpf | Bsize2048 | Bam | RdtmsHALF | Secrc); | 
 | 			if (ctlr->type != i82575) | 
 | 				i |= (Nrd / 2 >> 4) << 20; /* RdmsHalf */ | 
 | 			csr32w(ctlr, Srrctl, i | Dropen); | 
 | 			csr32w(ctlr, Rmpl, ctlr->rbsz); | 
 | 			// csr32w(ctlr, Drxmxod, 0x7ff); | 
 | 		} else | 
 | 			csr32w(ctlr, Rctl, | 
 | 			       Lpe | Dpf | BsizeFlex * i | Bam | RdtmsHALF | | 
 | 			           Secrc); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * TODO(dcross): Reconcile this with latest above code block. | 
 | 	 */ | 
 | 	if (0) { | 
 | 		rctl = Dpf | Bsize2048 | Bam | RdtmsHALF; | 
 | 		if (type == i82575 || type == i82576 || type == i210) { | 
 | 			/* | 
 | 			 * Setting Qenable in Rxdctl does not | 
 | 			 * appear to stick unless Ren is on. | 
 | 			 */ | 
 | 			csr32w(ctlr, Rctl, Ren | rctl); | 
 | 			csr32w(ctlr, Rxdctl, csr32r(ctlr, Rxdctl) | Qenable); | 
 | 		} | 
 | 		csr32w(ctlr, Rctl, rctl); | 
 | 	} | 
 |  | 
 | 	if (ctlrtab[ctlr->type].flag & Fert) | 
 | 		csr32w(ctlr, Ert, 1024 / 8); /* early rx threshold */ | 
 |  | 
 | 	csr32w(ctlr, Rdbal, paddr_low32(ctlr->rdba)); | 
 | 	csr32w(ctlr, Rdbah, paddr_high32(ctlr->rdba)); | 
 | 	csr32w(ctlr, Rdlen, Nrd * sizeof(struct rd)); | 
 | 	ctlr->rdh = ctlr->rdt = 0; | 
 | 	csr32w(ctlr, Rdh, 0); | 
 | 	csr32w(ctlr, Rdt, 0); | 
 |  | 
 | 	/* to hell with interrupt moderation, we want low latency */ | 
 | 	csr32w(ctlr, Rdtr, 0); | 
 | 	csr32w(ctlr, Radv, 0); | 
 |  | 
 | 	for (i = 0; i < Nrd; i++) { | 
 | 		bp = ctlr->rb[i]; | 
 | 		if (bp != NULL) { | 
 | 			ctlr->rb[i] = NULL; | 
 | 			freeb(bp); | 
 | 		} | 
 | 	} | 
 | 	i82563replenish(ctlr); | 
 |  | 
 | 	if (type == i82575 || type == i82576 || type == i210) { | 
 | 		/* | 
 | 		 * See comment above for Qenable. | 
 | 		 * Could shuffle the code? | 
 | 		 */ | 
 | 		r = csr32r(ctlr, Rxdctl) & ~(WthreshMASK | PthreshMASK); | 
 | 		csr32w(ctlr, Rxdctl, r | 2 << WthreshSHIFT | 2 << PthreshSHIFT); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Don't enable checksum offload.  In practice, it interferes with | 
 | 	 * tftp booting on at least the 82575. | 
 | 	 */ | 
 | 	csr32w(ctlr, Rxcsum, 0); | 
 | } | 
 |  | 
 | static int i82563rim(void *ctlr) | 
 | { | 
 | 	return ((struct ctlr *)ctlr)->rim != 0; | 
 | } | 
 |  | 
 | /* | 
 |  * With no errors and the Ixsm bit set, | 
 |  * the descriptor status Tpcs and Ipcs bits give | 
 |  * an indication of whether the checksums were | 
 |  * calculated and valid. | 
 |  * | 
 |  * Must be called with rd->errors == 0. | 
 |  */ | 
 | static void ckcksums(struct ctlr *ctlr, struct rd *rd, struct block *bp) | 
 | { | 
 | 	if (0) { | 
 | 		if (rd->status & Ixsm) | 
 | 			return; | 
 | 		ctlr->ixsm++; | 
 | 		if (rd->status & Ipcs) { | 
 | 			/* | 
 | 			 * IP checksum calculated (and valid as errors == 0). | 
 | 			 */ | 
 | 			ctlr->ipcs++; | 
 | 			bp->flag |= Bipck; | 
 | 		} | 
 | 		if (rd->status & Tcpcs) { | 
 | 			/* | 
 | 			 * TCP/UDP checksum calculated (and valid as errors == | 
 | 			 * 0). | 
 | 			 */ | 
 | 			ctlr->tcpcs++; | 
 | 			bp->flag |= Btcpck | Budpck; | 
 | 		} | 
 | 		bp->flag |= Bpktck; | 
 | 	} | 
 | } | 
 |  | 
 | static void i82563rproc(void *arg) | 
 | { | 
 | 	struct rd *rd; | 
 | 	struct block *bp; | 
 | 	struct ctlr *ctlr; | 
 | 	int rdh, rim, passed; | 
 | 	struct ether *edev; | 
 |  | 
 | 	edev = arg; | 
 | 	ctlr = edev->ctlr; | 
 | 	i82563rxinit(ctlr); | 
 | 	csr32w(ctlr, Rctl, csr32r(ctlr, Rctl) | Ren); | 
 |  | 
 | 	/* | 
 | 	 * TODO(dcross): Work references to ctlrtab into this code. | 
 | 	 */ | 
 | 	if (ctlr->type == i210) | 
 | 		csr32w(ctlr, Rxdctl, csr32r(ctlr, Rxdctl) | Qenable); | 
 |  | 
 | 	for (;;) { | 
 | 		i82563replenish(ctlr); | 
 | 		i82563im(ctlr, Rxt0 | Rxo | Rxdmt0 | Rxseq | Ack); | 
 | 		ctlr->rsleep++; | 
 | 		rendez_sleep(&ctlr->rrendez, i82563rim, ctlr); | 
 |  | 
 | 		rdh = ctlr->rdh; | 
 | 		passed = 0; | 
 | 		for (;;) { | 
 | 			rim = ctlr->rim; | 
 | 			ctlr->rim = 0; | 
 | 			rd = &ctlr->rdba[rdh]; | 
 | 			if (!(rd->status & Rdd)) | 
 | 				break; | 
 |  | 
 | 			/* | 
 | 			 * Accept eop packets with no errors. | 
 | 			 */ | 
 | 			bp = ctlr->rb[rdh]; | 
 | 			if ((rd->status & Reop) && rd->errors == 0) { | 
 | 				bp->wp += rd->length; | 
 | 				bp->lim = bp->wp; /* lie like a dog. */ | 
 | 				if (0) | 
 | 					ckcksums(ctlr, rd, bp); | 
 | 				etheriq(edev, bp, 1); /* pass pkt upstream */ | 
 | 				passed++; | 
 | 			} else { | 
 | 				if (rd->status & Reop && rd->errors) | 
 | 					printd("%s: input packet error %#ux\n", | 
 | 					       tname[ctlr->type], rd->errors); | 
 | 				freeb(bp); | 
 | 			} | 
 | 			ctlr->rb[rdh] = NULL; | 
 |  | 
 | 			/* rd needs to be replenished to accept another pkt */ | 
 | 			rd->status = 0; | 
 | 			ctlr->rdfree--; | 
 | 			ctlr->rdh = rdh = NEXT_RING(rdh, Nrd); | 
 | 			/* | 
 | 			 * if number of rds ready for packets is too low, | 
 | 			 * set up the unready ones. | 
 | 			 */ | 
 | 			if (ctlr->rdfree <= Nrd - 32 || (rim & Rxdmt0)) | 
 | 				i82563replenish(ctlr); | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static int i82563lim(void *ctlr) | 
 | { | 
 | 	return ((struct ctlr *)ctlr)->lim != 0; | 
 | } | 
 |  | 
 | static int phynum(struct ctlr *ctlr) | 
 | { | 
 | 	if (ctlr->phynum < 0) | 
 | 		switch (ctlr->type) { | 
 | 		case i82577: | 
 | 			//      case i82578:            /* not yet implemented | 
 | 			//      */ | 
 | 		case i82579: | 
 | 		case i217: | 
 | 		case i218: | 
 | 			ctlr->phynum = 2; /* pcie phy */ | 
 | 			break; | 
 | 		default: | 
 | 			ctlr->phynum = 1; /* gbe phy */ | 
 | 			break; | 
 | 		} | 
 | 	return ctlr->phynum; | 
 | } | 
 |  | 
 | static unsigned int phyread(struct ctlr *ctlr, int reg) | 
 | { | 
 | 	unsigned int phy, i; | 
 |  | 
 | 	if (reg >= 32) | 
 | 		iprint("phyread: reg %d >= 32\n", reg); | 
 | 	csr32w(ctlr, Mdic, | 
 | 	       MDIrop | phynum(ctlr) << MDIpSHIFT | reg << MDIrSHIFT); | 
 | 	phy = 0; | 
 | 	for (i = 0; i < 64; i++) { | 
 | 		phy = csr32r(ctlr, Mdic); | 
 | 		if (phy & (MDIe | MDIready)) | 
 | 			break; | 
 | 		udelay(1); | 
 | 	} | 
 | 	if ((phy & (MDIe | MDIready)) != MDIready) | 
 | 		return ~0; | 
 | 	return phy & 0xffff; | 
 | } | 
 |  | 
 | static unsigned int phywrite(struct ctlr *ctlr, int reg, uint16_t val) | 
 | { | 
 | 	unsigned int phy, i; | 
 |  | 
 | 	if (reg >= 32) | 
 | 		iprint("phyread: reg %d >= 32\n", reg); | 
 | 	csr32w(ctlr, Mdic, | 
 | 	       MDIwop | phynum(ctlr) << MDIpSHIFT | reg << MDIrSHIFT | val); | 
 | 	phy = 0; | 
 | 	for (i = 0; i < 64; i++) { | 
 | 		phy = csr32r(ctlr, Mdic); | 
 | 		if (phy & (MDIe | MDIready)) | 
 | 			break; | 
 | 		udelay(1); | 
 | 	} | 
 | 	if ((phy & (MDIe | MDIready)) != MDIready) | 
 | 		return ~0; | 
 | 	return 0; | 
 | } | 
 |  | 
 | static uint32_t kmrnread(struct ctlr *ctlr, uint32_t reg_addr) | 
 | { | 
 | 	/* write register address */ | 
 | 	csr32w(ctlr, Kumctrlsta, | 
 | 	       ((reg_addr << Kumctrlstaoffshift) & Kumctrlstaoff) | | 
 | 	           Kumctrlstaren); | 
 | 	udelay(2); | 
 | 	/* read data */ | 
 | 	return csr32r(ctlr, Kumctrlsta); | 
 | } | 
 |  | 
 | static void kmrnwrite(struct ctlr *ctlr, uint32_t reg_addr, uint16_t data) | 
 | { | 
 | 	csr32w(ctlr, Kumctrlsta, | 
 | 	       ((reg_addr << Kumctrlstaoffshift) & Kumctrlstaoff) | data); | 
 | 	udelay(2); | 
 | } | 
 |  | 
 | /* | 
 |  * this is essentially black magic.  we blindly follow the incantations | 
 |  * prescribed by the god Intel: | 
 |  * | 
 |  * On ESB2, the MAC-to-PHY (Kumeran) interface must be configured after | 
 |  * link is up before any traffic is sent. | 
 |  * | 
 |  * workaround DMA unit hang on I218 | 
 |  * | 
 |  * At 1Gbps link speed, one of the MAC's internal clocks can be stopped | 
 |  * for up to 4us when entering K1 (a power mode of the MAC-PHY | 
 |  * interconnect).  If the MAC is waiting for completion indications for 2 | 
 |  * DMA write requests into Host memory (e.g.  descriptor writeback or Rx | 
 |  * packet writing) and the indications occur while the clock is stopped, | 
 |  * both indications will be missed by the MAC, causing the MAC to wait | 
 |  * for the completion indications and be unable to generate further DMA | 
 |  * write requests.  This results in an apparent hardware hang. | 
 |  * | 
 |  * Work-around the bug by disabling the de-assertion of the clock request | 
 |  * when 1Gbps link is acquired (K1 must be disabled while doing this). | 
 |  * Also, set appropriate Tx re-transmission timeouts for 10 and 100-half | 
 |  * link speeds to avoid Tx hangs. | 
 |  */ | 
 | static void k1fix(struct ctlr *ctlr) | 
 | { | 
 | 	int txtmout; /* units of 10µs */ | 
 | 	uint32_t fextnvm6, status; | 
 | 	uint16_t reg; | 
 | 	struct ether *edev; | 
 |  | 
 | 	edev = ctlr->edev; | 
 | 	fextnvm6 = csr32r(ctlr, Fextnvm6); | 
 | 	status = csr32r(ctlr, Status); | 
 | 	/* status speed bits are different on 217/8 than earlier ctlrs */ | 
 | 	if (edev->link && status & (Sspeed1000 >> 2)) { | 
 | 		reg = kmrnread(ctlr, Kumctrlstak1cfg); | 
 | 		kmrnwrite(ctlr, Kumctrlstak1cfg, reg & ~Kumctrlstak1enable); | 
 | 		udelay(10); | 
 | 		csr32w(ctlr, Fextnvm6, fextnvm6 | Fextnvm6reqpllclk); | 
 | 		kmrnwrite(ctlr, Kumctrlstak1cfg, reg); | 
 | 		ctlr->didk1fix = 1; | 
 | 		return; | 
 | 	} | 
 | 	/* else uncommon cases */ | 
 |  | 
 | 	fextnvm6 &= ~Fextnvm6reqpllclk; | 
 | 	/* | 
 | 	 * 217 manual claims not to have Frcdplx bit in status; | 
 | 	 * 218 manual just omits the non-phy registers. | 
 | 	 */ | 
 | 	if (!edev->link || (status & (Sspeed100 >> 2 | Frcdplx)) == | 
 | 	                       (Sspeed100 >> 2 | Frcdplx)) { | 
 | 		csr32w(ctlr, Fextnvm6, fextnvm6); | 
 | 		ctlr->didk1fix = 1; | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	/* access other page via phy addr 1 reg 31, then access reg 16-30 */ | 
 | 	phywrite(ctlr, Phypage, I217inbandctlpage << 5); | 
 | 	reg = phyread(ctlr, I217inbandctlreg) & ~I217inbandctllnkststxtmoutmask; | 
 | 	if (status & (Sspeed100 >> 2)) { /* 100Mb/s half-duplex? */ | 
 | 		txtmout = 5; | 
 | 		fextnvm6 &= ~Fextnvm6enak1entrycond; | 
 | 	} else { /* 10Mb/s */ | 
 | 		txtmout = 50; | 
 | 		fextnvm6 |= Fextnvm6enak1entrycond; | 
 | 	} | 
 | 	phywrite(ctlr, I217inbandctlreg, | 
 | 	         reg | txtmout << I217inbandctllnkststxtmoutshift); | 
 | 	csr32w(ctlr, Fextnvm6, fextnvm6); | 
 | 	phywrite(ctlr, Phypage, 0 << 5); /* reset page to usual 0 */ | 
 | 	ctlr->didk1fix = 1; | 
 | } | 
 |  | 
 | /* | 
 |  * watch for changes of link state | 
 |  */ | 
 | static void i82563lproc(void *v) | 
 | { | 
 | 	unsigned int phy, sp, a, phy79, prevlink; | 
 | 	struct ctlr *ctlr; | 
 | 	struct ether *edev; | 
 |  | 
 | 	edev = v; | 
 | 	ctlr = edev->ctlr; | 
 | 	phy79 = 0; | 
 | 	switch (ctlr->type) { | 
 | 	case i82579: | 
 | 	case i82580: | 
 | 	case i217: | 
 | 	case i218: | 
 | 	case i350: | 
 | 		phy79 = 1; | 
 | 		break; | 
 | 	} | 
 | 	/* | 
 | 	 * TODO(dcross): Extract PHY number from ctlrtab. | 
 | 	 */ | 
 | 	if (ctlr->type == i82573 && phyread(ctlr, Phyier) != ~0) { | 
 | 		phy = phyread(ctlr, Phyier); | 
 | 		phywrite(ctlr, Phyier, phy | Lscie | Ancie | Spdie | Panie); | 
 | 	} else if (phy79 && phyread(ctlr, Phyier218) != ~0) { | 
 | 		phy = phyread(ctlr, Phyier218); | 
 | 		phywrite(ctlr, Phyier218, phy | Lscie218 | Ancie218 | Spdie218); | 
 | 	} | 
 | 	prevlink = 0; | 
 | 	for (;;) { | 
 | 		a = 0; | 
 | 		phy = phyread(ctlr, phy79 ? Phystat : Physsr); | 
 | 		if (phy == ~0) | 
 | 			goto next; | 
 | 		if (phy79) { | 
 | 			sp = (phy >> 8) & 3; | 
 | 			// a = phy & (ctlr->type == i218? Anfs: Ans); | 
 | 			a = phy & Anfs; | 
 | 		} else { | 
 | 			sp = (phy >> 14) & 3; | 
 | 			switch (ctlr->type) { | 
 | 			case i82563: | 
 | 			case i210: | 
 | 				a = phyread(ctlr, Phyisr) & Ane; /* a-n error */ | 
 | 				break; | 
 | 			case i82571: | 
 | 			case i82572: | 
 | 			case i82575: | 
 | 			case i82576: | 
 | 				a = phyread(ctlr, Phylhr) & Anf; /* a-n fault */ | 
 | 				sp = (sp - 1) & 3; | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 		if (a) /* enable & restart autoneg */ /* enable & restart | 
 | 		                                         autoneg */ | 
 | 			phywrite(ctlr, Phyctl, | 
 | 			         phyread(ctlr, Phyctl) | Ran | Ean); | 
 | 		edev->link = (phy & (phy79 ? Link : Rtlink)) != 0; | 
 | 		if (edev->link) { | 
 | 			ctlr->speeds[sp]++; | 
 | 			if (speedtab[sp]) | 
 | 				edev->mbps = speedtab[sp]; | 
 | 			if (prevlink == 0 && ctlr->type == i218) | 
 | 				k1fix(ctlr); /* link newly up: kludge away */ | 
 | 			netif_carrier_on(edev); | 
 | 		} else | 
 | 			ctlr->didk1fix = 0; /* force fix at next link up */ | 
 | 		prevlink = edev->link; | 
 | 	next: | 
 | 		ctlr->lim = 0; | 
 | 		i82563im(ctlr, Lsc); | 
 | 		ctlr->lsleep++; | 
 | 		rendez_sleep(&ctlr->lrendez, i82563lim, ctlr); | 
 | 	} | 
 | } | 
 |  | 
 | static int return0(void *unused_void_p) | 
 | { | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void i82563tproc(void *v) | 
 | { | 
 | 	struct ether *edev; | 
 | 	struct ctlr *ctlr; | 
 |  | 
 | 	edev = v; | 
 | 	ctlr = edev->ctlr; | 
 | 	for (;;) { | 
 | 		rendez_sleep(&ctlr->trendez, return0, 0); | 
 | 		i82563transmit(edev); | 
 | 	} | 
 | } | 
 |  | 
 | /* | 
 |  * controller is buggered; shock it back to life. | 
 |  */ | 
 | static void restart(struct ctlr *ctlr) | 
 | { | 
 | 	if (0) { | 
 | 		static spinlock_t rstlock; | 
 |  | 
 | 		qlock(&ctlr->tlock); | 
 | 		spin_lock_irqsave(&rstlock); | 
 | 		iprint("#l%d: resetting...", ctlr->edev->ctlrno); | 
 | 		i82563reset(ctlr); | 
 | 		/* [rt]xinit reset the ring indices */ | 
 | 		i82563txinit(ctlr); | 
 | 		i82563rxinit(ctlr); | 
 | 		csr32w(ctlr, Rctl, csr32r(ctlr, Rctl) | Ren); | 
 | 		spin_unlock_irqsave(&rstlock); | 
 | 		qunlock(&ctlr->tlock); | 
 | 		iprint("reset\n"); | 
 | 	} | 
 | } | 
 |  | 
 | static void freemem(struct ctlr *ctlr) | 
 | { | 
 | 	kfree(ctlr->tb); | 
 | 	ctlr->tb = NULL; | 
 | 	kfree(ctlr->rb); | 
 | 	ctlr->rb = NULL; | 
 | 	kfree(ctlr->tdba); | 
 | 	ctlr->tdba = NULL; | 
 | 	kfree(ctlr->rdba); | 
 | 	ctlr->rdba = NULL; | 
 | } | 
 |  | 
 | static void i82563attach(struct ether *edev) | 
 | { | 
 | 	ERRSTACK(2); | 
 | 	int i; | 
 | 	struct block *bp; | 
 | 	struct ctlr *ctlr; | 
 | 	char *lname, *rname, *tname; | 
 |  | 
 | 	ctlr = edev->ctlr; | 
 | 	qlock(&ctlr->alock); | 
 |  | 
 | 	if (ctlr->attached) { | 
 | 		qunlock(&ctlr->alock); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	if (waserror()) { | 
 | 		freemem(ctlr); | 
 | 		qunlock(&ctlr->alock); | 
 | 		nexterror(); | 
 | 	} | 
 |  | 
 | 	ctlr->alloc = kzmalloc( | 
 | 	    Nrd * sizeof(struct rd) + Ntd * sizeof(struct td) + 255, MEM_WAIT); | 
 | 	if (ctlr->alloc == NULL) { | 
 | 		qunlock(&ctlr->alock); | 
 | 		error(ENOMEM, "i82563attach: error allocating rx/tx rings"); | 
 | 	} | 
 | 	ctlr->rdba = (struct rd *)ROUNDUP((uintptr_t)ctlr->alloc, 256); | 
 | 	ctlr->tdba = (struct td *)(ctlr->rdba + Nrd); | 
 | 	ctlr->rb = kzmalloc(Nrd * sizeof(struct block *), 0); | 
 | 	ctlr->tb = kzmalloc(Ntd * sizeof(struct block *), 0); | 
 | 	if (ctlr->rb == NULL || ctlr->tb == NULL) { | 
 | 		qunlock(&ctlr->alock); | 
 | 		error(ENOMEM, "i82563attach: error allocating rx/tx buffers"); | 
 | 	} | 
 |  | 
 | 	ctlr->edev = edev; /* point back to Ether* */ | 
 | 	ctlr->attached = 1; | 
 |  | 
 | 	lname = kzmalloc(KNAMELEN, MEM_WAIT); | 
 | 	snprintf(lname, KNAMELEN, "#l%dl", edev->ctlrno); | 
 | 	ktask(lname, i82563lproc, edev); | 
 |  | 
 | 	rname = kzmalloc(KNAMELEN, MEM_WAIT); | 
 | 	snprintf(rname, KNAMELEN, "#l%dr", edev->ctlrno); | 
 | 	ktask(rname, i82563rproc, edev); | 
 |  | 
 | 	tname = kzmalloc(KNAMELEN, MEM_WAIT); | 
 | 	snprintf(tname, KNAMELEN, "#l%dt", edev->ctlrno); | 
 | 	ktask(tname, i82563tproc, edev); | 
 |  | 
 | 	i82563txinit(ctlr); | 
 |  | 
 | 	qunlock(&ctlr->alock); | 
 | 	poperror(); | 
 | } | 
 |  | 
 | static void i82563interrupt(struct hw_trapframe *unused_hw_trapframe, void *arg) | 
 | { | 
 | 	struct ctlr *ctlr; | 
 | 	struct ether *edev; | 
 | 	int icr, im, i, loops; | 
 |  | 
 | 	edev = arg; | 
 | 	ctlr = edev->ctlr; | 
 | 	spin_lock_irqsave(&ctlr->imlock); | 
 | 	csr32w(ctlr, Imc, ~0); | 
 | 	im = ctlr->im; | 
 | 	loops = 0; | 
 | 	i = Nrd; /* don't livelock */ | 
 | 	for (icr = csr32r(ctlr, Icr); icr & ctlr->im && i-- > 0; | 
 | 	     icr = csr32r(ctlr, Icr)) { | 
 | 		loops++; | 
 | 		if (icr & Lsc) { | 
 | 			im &= ~Lsc; | 
 | 			ctlr->lim = icr & Lsc; | 
 | 			rendez_wakeup(&ctlr->lrendez); | 
 | 			ctlr->lintr++; | 
 | 		} | 
 | 		if (icr & (Rxt0 | Rxo | Rxdmt0 | Rxseq | Ack)) { | 
 | 			ctlr->rim = icr & (Rxt0 | Rxo | Rxdmt0 | Rxseq | Ack); | 
 | 			im &= ~(Rxt0 | Rxo | Rxdmt0 | Rxseq | Ack); | 
 | 			rendez_wakeup(&ctlr->rrendez); | 
 | 			ctlr->rintr++; | 
 | 		} | 
 | 		if (icr & Txdw) { | 
 | 			im &= ~Txdw; | 
 | 			ctlr->tintr++; | 
 | 			rendez_wakeup(&ctlr->trendez); | 
 | 		} | 
 | 	} | 
 | 	ctlr->im = im; | 
 | 	csr32w(ctlr, Ims, im); | 
 | 	spin_unlock_irqsave(&ctlr->imlock); | 
 | } | 
 |  | 
 | /* assume misrouted interrupts and check all controllers */ | 
 | static void i82575interrupt(struct hw_trapframe *unused_hw_trapframe, | 
 |                             void *unused_arg) | 
 | { | 
 | 	struct ctlr *ctlr; | 
 |  | 
 | 	for (ctlr = i82563ctlrhead; ctlr != NULL && ctlr->edev != NULL; | 
 | 	     ctlr = ctlr->next) | 
 | 		i82563interrupt(NULL, ctlr->edev); | 
 | } | 
 |  | 
 | static int i82563detach0(struct ctlr *ctlr) | 
 | { | 
 | 	int r, timeo; | 
 |  | 
 | 	/* | 
 | 	 * Perform a device reset to get the chip back to the | 
 | 	 * power-on state, followed by an EEPROM reset to read | 
 | 	 * the defaults for some internal registers. | 
 | 	 */ | 
 | 	csr32w(ctlr, Imc, ~0); | 
 | 	csr32w(ctlr, Rctl, 0); | 
 | 	csr32w(ctlr, Tctl, 0); | 
 |  | 
 | 	udelay(1000 * 1000); | 
 |  | 
 | 	/* | 
 | 	 * Balance Rx/Tx packet buffer. | 
 | 	 * No need to set PBA register unless using jumbo, defaults to 32KB | 
 | 	 * for receive. If it is changed, then have to do a MAC reset, | 
 | 	 * and need to do that at the the right time as it will wipe stuff. | 
 | 	 * | 
 | 	 * TODO(dcross): reconcile the following code with the above commentary. | 
 | 	 */ | 
 | 	if (0) { | 
 | 		if (ctlr->rbsz > 8192 && ctlrtab[ctlr->type].flag & Fpba) { | 
 | 			ctlr->pba = csr32r(ctlr, Pba); | 
 | 			r = ctlr->pba >> 16; | 
 | 			r += ctlr->pba & 0xffff; | 
 | 			r >>= 1; | 
 | 			csr32w(ctlr, Pba, r); | 
 | 		} else if (ctlr->type == i82573 && ctlr->rbsz > 1514) | 
 | 			csr32w(ctlr, Pba, 14); | 
 | 	} | 
 | 	ctlr->pba = csr32r(ctlr, Pba); | 
 |  | 
 | 	/* set packet buffer size if present.  no effect until soft reset. */ | 
 | 	switch (ctlr->type) { | 
 | 	case i82566: | 
 | 	case i82567: | 
 | 	case i217: | 
 | 		ctlr->pbs = 16; /* in KB */ | 
 | 		csr32w(ctlr, Pbs, ctlr->pbs); | 
 | 		break; | 
 | 	case i218: | 
 | 		// after pxe or 9fat boot, pba is always 0xe0012 on i218 => 32K | 
 | 		ctlr->pbs = (ctlr->pba >> 16) + (uint16_t)ctlr->pba; | 
 | 		csr32w(ctlr, Pbs, ctlr->pbs); | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	r = csr32r(ctlr, Ctrl); | 
 | 	if (ctlr->type == i82566 || ctlr->type == i82567 || | 
 | 	    ctlr->type == i82579) | 
 | 		r |= Phyrst; | 
 | 	csr32w(ctlr, Ctrl, Devrst | r); | 
 | 	udelay(1000); | 
 | 	for (timeo = 0; timeo < 1000; timeo++) { | 
 | 		if (!(csr32r(ctlr, Ctrl) & Devrst)) | 
 | 			break; | 
 | 		udelay(1000); | 
 | 	} | 
 | 	if (csr32r(ctlr, Ctrl) & Devrst) | 
 | 		return -1; | 
 |  | 
 | 	r = csr32r(ctlr, Ctrlext); | 
 | 	csr32w(ctlr, Ctrlext, r | Eerst); | 
 | 	udelay(1000); | 
 | 	for (timeo = 0; timeo < 1000; timeo++) { | 
 | 		if (!(csr32r(ctlr, Ctrlext) & Eerst)) | 
 | 			break; | 
 | 		udelay(1000); | 
 | 	} | 
 | 	if (csr32r(ctlr, Ctrlext) & Eerst) | 
 | 		return -1; | 
 |  | 
 | 	csr32w(ctlr, Imc, ~0); | 
 | 	udelay(1000); | 
 | 	for (timeo = 0; timeo < 1000; timeo++) { | 
 | 		if (!csr32r(ctlr, Icr)) | 
 | 			break; | 
 | 		udelay(1000); | 
 | 	} | 
 | 	if (csr32r(ctlr, Icr)) | 
 | 		return -1; | 
 |  | 
 | 	csr32w(ctlr, Ctrl, Slu | csr32r(ctlr, Ctrl)); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int i82563detach(struct ctlr *ctlr) | 
 | { | 
 | 	int r; | 
 | 	static spinlock_t detlck; | 
 |  | 
 | 	spin_lock_irqsave(&detlck); | 
 | 	r = i82563detach0(ctlr); | 
 | 	spin_unlock_irqsave(&detlck); | 
 | 	return r; | 
 | } | 
 |  | 
 | static void i82563shutdown(struct ether *ether) | 
 | { | 
 | 	i82563detach(ether->ctlr); | 
 | } | 
 |  | 
 | static uint16_t eeread(struct ctlr *ctlr, int adr) | 
 | { | 
 | 	uint32_t n; | 
 |  | 
 | 	csr32w(ctlr, Eerd, EEstart | adr << 2); | 
 | 	n = 1000000; | 
 | 	while (n > 0 && (csr32r(ctlr, Eerd) & EEdone) == 0) | 
 | 		n--; | 
 | 	if (n == 0) | 
 | 		panic("i82563: eeread stuck"); | 
 | 	return csr32r(ctlr, Eerd) >> 16; | 
 | } | 
 |  | 
 | /* load eeprom into ctlr */ | 
 | static int eeload(struct ctlr *ctlr) | 
 | { | 
 | 	uint16_t 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 int fcycle(struct ctlr *unused_ctlr_p, struct flash *f) | 
 | { | 
 | 	uint16_t 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) /* spi cycle done? */ | 
 | 			return 0; | 
 | 		udelay(1000); | 
 | 		s = f->reg[Fsts]; | 
 | 	} | 
 | 	return -1; | 
 | } | 
 |  | 
 | static int fread(struct ctlr *ctlr, struct flash *f, int ladr) | 
 | { | 
 | 	uint16_t s; | 
 | 	uint32_t n; | 
 |  | 
 | 	udelay(1000); | 
 | 	if (fcycle(ctlr, f) == -1) | 
 | 		return -1; | 
 | 	f->reg[Fsts] |= Fdone; | 
 | 	f->reg32[Faddr] = ladr; | 
 |  | 
 | 	/* setup flash control register */ | 
 | 	s = f->reg[Fctl] & ~(0x1f << 8); | 
 | 	s |= (2 - 1) << 8;   /* 2 bytes */ | 
 | 	s &= ~(2 * Flcycle); /* read */ | 
 | 	f->reg[Fctl] = s | Fgo; | 
 |  | 
 | 	n = 1000000; | 
 | 	while (n > 0 && (f->reg[Fsts] & Fdone) == 0) | 
 | 		n--; | 
 | 	if (n == 0) | 
 | 		panic("i82563: fread stuck"); | 
 | 	if (f->reg[Fsts] & (Fcerr | Ael)) | 
 | 		return -1; | 
 | 	return f->reg32[Fdata] & 0xffff; | 
 | } | 
 |  | 
 | /* load flash into ctlr */ | 
 | static int fload(struct ctlr *ctlr) | 
 | { | 
 | 	uint32_t data, r, adr; | 
 | 	uint16_t sum; | 
 | 	struct pci_device *pcidev = ctlr->pcidev; | 
 | 	struct flash f; | 
 |  | 
 | 	f.reg = pci_get_mmio_bar_kva(pcidev, 1); | 
 | 	if (f.reg == NULL) | 
 | 		return -1; | 
 | 	f.reg32 = (void *)f.reg; | 
 | 	f.base = f.reg32[Bfpr] & 0x1fff; | 
 | 	f.lim = (f.reg32[Bfpr] >> 16) & 0x1fff; | 
 | 	if (csr32r(ctlr, Eec) & Sec1val) | 
 | 		f.base += (f.lim + 1 - f.base) >> 1; | 
 | 	r = f.base << 12; | 
 |  | 
 | 	sum = 0; | 
 | 	for (adr = 0; adr < 0x40; adr++) { | 
 | 		data = fread(ctlr, &f, r + adr * 2); | 
 | 		if (data == -1) | 
 | 			break; | 
 | 		ctlr->eeprom[adr] = data; | 
 | 		sum += data; | 
 | 	} | 
 | 	return sum; | 
 | } | 
 |  | 
 | static int i82563reset(struct ctlr *ctlr) | 
 | { | 
 | 	int i, r, type; | 
 |  | 
 | 	/* | 
 | 	 * TODO(dcross): Integrate ctlrtab references into this code. | 
 | 	 */ | 
 | 	if (i82563detach(ctlr)) { | 
 | 		iprint("82563 reset: detach failed\n"); | 
 | 		return -1; | 
 | 	} | 
 | 	type = ctlr->type; | 
 | 	if (ctlr->ra[Eaddrlen - 1] != 0) | 
 | 		goto macset; | 
 | 	switch (type) { | 
 | 	case i82566: | 
 | 	case i82567: | 
 | 	case i82577: | 
 | 		//  case i82578:            /* not yet implemented */ | 
 | 	case i82579: | 
 | 	case i217: | 
 | 	case i218: | 
 | 		r = fload(ctlr); | 
 | 		break; | 
 | 	default: | 
 | 		r = eeload(ctlr); | 
 | 		break; | 
 | 	} | 
 | 	if (r != 0 && r != 0xBABA) { | 
 | 		printd("%s: bad EEPROM checksum - %#.4ux\n", tname[type], r); | 
 | 		// return -1; | 
 | 	} | 
 |  | 
 | 	/* set mac addr */ | 
 | 	for (i = 0; i < Eaddrlen / 2; i++) { | 
 | 		ctlr->ra[2 * i] = ctlr->eeprom[Ea + i]; | 
 | 		ctlr->ra[2 * i + 1] = ctlr->eeprom[Ea + i] >> 8; | 
 | 	} | 
 | 	/* ea ctlr[1] = ea ctlr[0]+1 */ | 
 | 	ctlr->ra[5] += (csr32r(ctlr, Status) & Lanid) >> 2; | 
 | 	/* | 
 | 	 * zero other mac addresses.` | 
 | 	 * AV bits should be zeroed by master reset & there may only be 11 | 
 | 	 * other registers on e.g., the i217. | 
 | 	 */ | 
 | 	for (i = 1; i < 12; i++) { /* `12' used to be `16' here */ | 
 | 		csr32w(ctlr, Ral + i * 8, 0); | 
 | 		csr32w(ctlr, Rah + i * 8, 0); | 
 | 	} | 
 | 	memset(ctlr->mta, 0, sizeof(ctlr->mta)); | 
 | macset: | 
 | 	/* low mac addr */ | 
 | 	csr32w(ctlr, Ral, | 
 | 	       ctlr->ra[3] << 24 | ctlr->ra[2] << 16 | ctlr->ra[1] << 8 | | 
 | 	           ctlr->ra[0]); | 
 | 	/* address valid | high mac addr */ | 
 | 	csr32w(ctlr, Rah, 0x80000000 | ctlr->ra[5] << 8 | ctlr->ra[4]); | 
 |  | 
 | 	/* populate multicast table */ | 
 | 	for (i = 0; i < mcbitstolongs(mcastbits(ctlr)); i++) | 
 | 		csr32w(ctlr, Mta + i * 4, ctlr->mta[i]); | 
 |  | 
 | 	/* | 
 | 	 * Does autonegotiation affect this manual setting? | 
 | 	 * The correct values here should depend on the PBA value | 
 | 	 * and maximum frame length, no? | 
 | 	 */ | 
 | 	/* fixed flow control ethernet address 0x0180c2000001 */ | 
 | 	csr32w(ctlr, Fcal, 0x00C28001); | 
 | 	csr32w(ctlr, Fcah, 0x0100); | 
 | 	if (type != i82579 && type != i210 && type != i217 && type != i218) | 
 | 		/* flow control type, dictated by Intel */ | 
 | 		csr32w(ctlr, Fct, 0x8808); | 
 | 	csr32w(ctlr, Fcttv, 0x0100); /* for XOFF frame */ | 
 | 	// ctlr->fcrtl = 0x00002000;        /* rcv low water mark: 8KB */ | 
 | 	/* rcv high water mark: 16KB, < rcv buffer in PBA & RXA */ | 
 | 	// ctlr->fcrth = 0x00004000; | 
 | 	ctlr->fcrtl = ctlr->fcrth = 0; | 
 | 	csr32w(ctlr, Fcrtl, ctlr->fcrtl); | 
 | 	csr32w(ctlr, Fcrth, ctlr->fcrth); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void i82563pci(void) | 
 | { | 
 | 	int type; | 
 | 	void *mem; | 
 | 	struct pci_device *p; | 
 | 	struct ctlr *ctlr; | 
 |  | 
 | 	p = NULL; | 
 | 	STAILQ_FOREACH (p, &pci_devices, all_dev) { | 
 | 		if (p->ven_id != 0x8086) | 
 | 			continue; | 
 | 		switch (p->dev_id) { | 
 | 		default: | 
 | 			continue; | 
 | 		case 0x1096: | 
 | 		case 0x10ba: | 
 | 		case 0x1098: /* serdes; not seen */ | 
 | 		case 0x10bb: /* serdes */ | 
 | 			type = i82563; | 
 | 			break; | 
 | 		case 0x1049: /* mm */ | 
 | 		case 0x104a: /* dm */ | 
 | 		case 0x104b: /* dc */ | 
 | 		case 0x104d: /* mc */ | 
 | 		case 0x10bd: /* dm */ | 
 | 		case 0x294c: /* dc-2 */ | 
 | 			type = i82566; | 
 | 			break; | 
 | 		case 0x10de: /* lm-3 */ | 
 | 		case 0x10df: /* lf ich10 */ | 
 | 		case 0x10e5: /* lm ich9 */ | 
 | 		case 0x10f5: /* lm-2 */ | 
 | 			type = i82567; | 
 | 			break; | 
 | 		case 0x10bf: /* lf ich9m */ | 
 | 		case 0x10cb: /* v ich9m */ | 
 | 		case 0x10cd: /* lf ich10 */ | 
 | 		case 0x10ce: /* v ich10 */ | 
 | 		case 0x10cc: /* lm ich10 */ | 
 | 			type = i82567m; | 
 | 			break; | 
 | 		case 0x105e: /* eb */ | 
 | 		case 0x105f: /* eb */ | 
 | 		case 0x1060: /* eb */ | 
 | 		case 0x10a4: /* eb */ | 
 | 		case 0x10a5: /* eb  fiber */ | 
 | 		case 0x10bc: /* eb */ | 
 | 		case 0x10d9: /* eb serdes */ | 
 | 		case 0x10da: /* eb serdes “ophir” */ | 
 | 			type = i82571; | 
 | 			break; | 
 | 		case 0x107d: /* eb copper */ | 
 | 		case 0x107e: /* ei fiber */ | 
 | 		case 0x107f: /* ei */ | 
 | 		case 0x10b9: /* sic, 82572gi */ | 
 | 			type = i82572; | 
 | 			break; | 
 | 		case 0x108b: /*  v */ | 
 | 		case 0x108c: /*  e (iamt) */ | 
 | 		case 0x109a: /*  l */ | 
 | 			type = i82573; | 
 | 			break; | 
 | 		case 0x10d3: /* l */ | 
 | 			type = i82574; | 
 | 			break; | 
 | 		case 0x10a7: /* 82575eb: one of a pair of controllers */ | 
 | 		case 0x10a9: /* fiber/serdes */ | 
 | 			type = i82575; | 
 | 			break; | 
 | 		case 0x10c9: /* 82576 copper */ | 
 | 		case 0x10e6: /* 82576 fiber */ | 
 | 		case 0x10e7: /* 82576 serdes */ | 
 | 		case 0x150d: /* backplane */ | 
 | 			type = i82576; | 
 | 			break; | 
 | 		case 0x10ea: /* 82577lm */ | 
 | 			type = i82577; | 
 | 			break; | 
 | 		case 0x10eb: /* lm “calpella” */ | 
 | 			type = i82577m; | 
 | 			break; | 
 | 		case 0x1502: /* 82579lm */ | 
 | 		case 0x1503: /* 82579v */ | 
 | 			type = i82579; | 
 | 			break; | 
 | 		case 0x10f0: /* dm “king's creek” */ | 
 | 			type = i82578m; | 
 | 			break; | 
 | 		case 0x150e: /* “barton hills” */ | 
 | 		case 0x150f: /* fiber */ | 
 | 		case 0x1510: /* backplane */ | 
 | 		case 0x1511: /* sfp */ | 
 | 		case 0x1516: | 
 | 			type = i82580; | 
 | 			break; | 
 | 		case 0x1506: /* v */ | 
 | 			type = i82583; | 
 | 			break; | 
 | 		case 0x1533: /* i210-t1 */ | 
 | 		case 0x1534: /* i210 */ | 
 | 		case 0x1536: /* i210-fiber */ | 
 | 		case 0x1537: /* i210-backplane */ | 
 | 		case 0x1538: | 
 | 		case 0x1539: /* i211 */ | 
 | 		case 0x157b: /* i210 */ | 
 | 		case 0x157c: /* i210 */ | 
 | 			type = i210; | 
 | 			break; | 
 | 		case 0x153a: /* i217-lm */ | 
 | 		case 0x153b: /* i217-v */ | 
 | 			type = i217; | 
 | 			break; | 
 | 		case 0x15a0: /* i218-lm */ | 
 | 		case 0x15a1: /* i218-v */ | 
 | 		case 0x15a2: /* i218-lm */ | 
 | 		case 0x15a3: /* i218-v */ | 
 | 			type = i218; | 
 | 			break; | 
 | 		case 0x151f: /* “powerville” eeprom-less */ | 
 | 		case 0x1521: /* copper */ | 
 | 		case 0x1522: /* fiber */ | 
 | 		case 0x1523: /* serdes */ | 
 | 		case 0x1524: /* sgmii */ | 
 | 			type = i350; | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		mem = pci_get_mmio_bar_kva(p, 0); | 
 | 		if (mem == NULL) { | 
 | 			printd("%s: can't map bar 0!\n", tname[type]); | 
 | 			continue; | 
 | 		} | 
 | 		ctlr = kzmalloc(sizeof(struct ctlr), 0); | 
 | 		if (ctlr == NULL) | 
 | 			error(ENOMEM, "i82563pci: alloc for ctlr failed"); | 
 | 		ctlr->rbsz = ctlrtab[type].mtu; | 
 | 		ctlr->pcidev = p; | 
 | 		ctlr->type = type; | 
 | 		ctlr->nic = mem; | 
 | 		ctlr->phynum = -1; /* not yet known */ | 
 |  | 
 | 		qlock_init(&ctlr->alock); | 
 | 		spinlock_init_irqsave(&ctlr->imlock); | 
 | 		rendez_init(&ctlr->lrendez); | 
 | 		qlock_init(&ctlr->slock); | 
 | 		rendez_init(&ctlr->rrendez); | 
 | 		rendez_init(&ctlr->trendez); | 
 | 		qlock_init(&ctlr->tlock); | 
 |  | 
 | 		pci_set_bus_master(p); | 
 | 		if (i82563reset(ctlr)) { | 
 | 			kfree(ctlr); | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		if (i82563ctlrhead != NULL) | 
 | 			i82563ctlrtail->next = ctlr; | 
 | 		else | 
 | 			i82563ctlrhead = ctlr; | 
 | 		i82563ctlrtail = ctlr; | 
 | 	} | 
 | } | 
 |  | 
 | static int pnp(struct ether *edev, int type) | 
 | { | 
 | 	struct ctlr *ctlr; | 
 | 	static int done; | 
 |  | 
 | 	if (!done) { | 
 | 		i82563pci(); | 
 | 		done = 1; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Any adapter matches if no edev->port is supplied, | 
 | 	 * otherwise the ports must match.  Using the 'NIC', which is BAR0's | 
 | 	 * unique KVA, for identification. | 
 | 	 */ | 
 | 	for (ctlr = i82563ctlrhead; ctlr != NULL; ctlr = ctlr->next) { | 
 | 		if (ctlr->active) | 
 | 			continue; | 
 | 		if (type != Iany && ctlr->type != type) | 
 | 			continue; | 
 | 		if (edev->port == 0 || edev->port == (uintptr_t)ctlr->nic) { | 
 | 			ctlr->active = 1; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if (ctlr == NULL) | 
 | 		return -1; | 
 |  | 
 | 	edev->ctlr = ctlr; | 
 | 	strlcpy(edev->drv_name, "i82563", KNAMELEN); | 
 | 	ctlr->edev = edev; /* point back to Ether* */ | 
 | 	edev->port = (uintptr_t)ctlr->nic; | 
 | 	edev->irq = ctlr->pcidev->irqline; | 
 | 	edev->tbdf = pci_to_tbdf(ctlr->pcidev); | 
 | 	edev->mbps = 1000; | 
 | 	edev->max_mtu = ctlr->rbsz - ETHERHDRSIZE; | 
 | 	edev->mtu = edev->mtu; | 
 | 	memmove(edev->ea, ctlr->ra, Eaddrlen); | 
 | 	/* Jim or whoever have this turned on already.  We might be capable of | 
 | 	 * other features. */ | 
 | 	edev->feat = NETF_RXCSUM; | 
 |  | 
 | 	/* | 
 | 	 * Linkage to the generic ethernet driver. | 
 | 	 */ | 
 | 	edev->attach = i82563attach; | 
 | 	edev->transmit = i82563transmit; | 
 | 	edev->ifstat = i82563ifstat; | 
 | 	edev->ctl = i82563ctl; | 
 |  | 
 | 	edev->arg = edev; | 
 | 	edev->promiscuous = i82563promiscuous; | 
 | 	edev->shutdown = i82563shutdown; | 
 | 	edev->multicast = i82563multicast; | 
 |  | 
 | 	register_irq(edev->irq, | 
 | 	             ctlr->type == i82575 ? i82575interrupt : i82563interrupt, | 
 | 	             edev, edev->tbdf); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int anypnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, Iany); | 
 | } | 
 |  | 
 | static int i82563pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i82563); | 
 | } | 
 |  | 
 | static int i82566pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i82566); | 
 | } | 
 |  | 
 | static int i82571pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i82571); | 
 | } | 
 |  | 
 | static int i82572pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i82572); | 
 | } | 
 |  | 
 | static int i82573pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i82573); | 
 | } | 
 |  | 
 | static int i82575pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i82575); | 
 | } | 
 |  | 
 | static int i82579pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i82579); | 
 | } | 
 |  | 
 | static int i210pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i210); | 
 | } | 
 |  | 
 | static int i217pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i217); | 
 | } | 
 |  | 
 | static int i218pnp(struct ether *e) | 
 | { | 
 | 	return pnp(e, i218); | 
 | } | 
 |  | 
 | static void __init ether82563link(void) | 
 | { | 
 | 	/* recognise lots of model numbers for debugging assistance */ | 
 | 	addethercard("i82563", i82563pnp); | 
 | 	addethercard("i82566", i82566pnp); | 
 | 	addethercard("i82571", i82571pnp); | 
 | 	addethercard("i82572", i82572pnp); | 
 | 	addethercard("i82573", i82573pnp); | 
 | 	addethercard("i82575", i82575pnp); | 
 | 	addethercard("i82579", i82579pnp); | 
 | 	addethercard("i210", i210pnp); | 
 | 	addethercard("i217", i217pnp); | 
 | 	addethercard("i218", i218pnp); | 
 | 	addethercard("igbepcie", anypnp); | 
 | } | 
 | init_func_3(ether82563link); |