147ad9175SDavid du Colombier /*
208cb4641SDavid du Colombier * Intel Gigabit Ethernet PCI-Express Controllers.
39b7bf7dfSDavid du Colombier * 8256[36], 8257[1-79]
408cb4641SDavid du Colombier * Pretty basic, does not use many of the chip smarts.
508cb4641SDavid du Colombier * The interrupt mitigation tuning for each chip variant
608cb4641SDavid du Colombier * is probably different. The reset/initialisation
791157df7SDavid du Colombier * sequence needs straightened out. Doubt the PHY code
808cb4641SDavid du Colombier * for the 82575eb is right.
947ad9175SDavid du Colombier */
1047ad9175SDavid du Colombier #include "u.h"
1147ad9175SDavid du Colombier #include "../port/lib.h"
1247ad9175SDavid du Colombier #include "mem.h"
1347ad9175SDavid du Colombier #include "dat.h"
1447ad9175SDavid du Colombier #include "fns.h"
1547ad9175SDavid du Colombier #include "io.h"
1647ad9175SDavid du Colombier #include "../port/error.h"
1747ad9175SDavid du Colombier #include "../port/netif.h"
1847ad9175SDavid du Colombier
1947ad9175SDavid du Colombier #include "etherif.h"
2047ad9175SDavid du Colombier
2147ad9175SDavid du Colombier /*
2247ad9175SDavid du Colombier * these are in the order they appear in the manual, not numeric order.
2347ad9175SDavid du Colombier * It was too hard to find them in the book. Ref 21489, rev 2.6
2447ad9175SDavid du Colombier */
2547ad9175SDavid du Colombier
2647ad9175SDavid du Colombier enum {
2747ad9175SDavid du Colombier /* General */
2847ad9175SDavid du Colombier
2937a6523bSDavid du Colombier Ctrl = 0x0000, /* Device Control */
3037a6523bSDavid du Colombier Status = 0x0008, /* Device Status */
3137a6523bSDavid du Colombier Eec = 0x0010, /* EEPROM/Flash Control/Data */
3237a6523bSDavid du Colombier Eerd = 0x0014, /* EEPROM Read */
3337a6523bSDavid du Colombier Ctrlext = 0x0018, /* Extended Device Control */
3437a6523bSDavid du Colombier Fla = 0x001c, /* Flash Access */
3537a6523bSDavid du Colombier Mdic = 0x0020, /* MDI Control */
3637a6523bSDavid du Colombier Seresctl = 0x0024, /* Serdes ana */
3737a6523bSDavid du Colombier Fcal = 0x0028, /* Flow Control Address Low */
3837a6523bSDavid du Colombier Fcah = 0x002C, /* Flow Control Address High */
3937a6523bSDavid du Colombier Fct = 0x0030, /* Flow Control Type */
4008cb4641SDavid du Colombier Kumctrlsta = 0x0034, /* MAC-PHY Interface */
4137a6523bSDavid du Colombier Vet = 0x0038, /* VLAN EtherType */
4237a6523bSDavid du Colombier Fcttv = 0x0170, /* Flow Control Transmit Timer Value */
4337a6523bSDavid du Colombier Txcw = 0x0178, /* Transmit Configuration Word */
4437a6523bSDavid du Colombier Rxcw = 0x0180, /* Receive Configuration Word */
4537a6523bSDavid du Colombier Ledctl = 0x0E00, /* LED control */
4637a6523bSDavid du Colombier Pba = 0x1000, /* Packet Buffer Allocation */
4737a6523bSDavid du Colombier Pbs = 0x1008, /* Packet Buffer Size */
4847ad9175SDavid du Colombier
4947ad9175SDavid du Colombier /* Interrupt */
5047ad9175SDavid du Colombier
5137a6523bSDavid du Colombier Icr = 0x00C0, /* Interrupt Cause Read */
5237a6523bSDavid du Colombier Itr = 0x00c4, /* Interrupt Throttling Rate */
5337a6523bSDavid du Colombier Ics = 0x00C8, /* Interrupt Cause Set */
5437a6523bSDavid du Colombier Ims = 0x00D0, /* Interrupt Mask Set/Read */
5537a6523bSDavid du Colombier Imc = 0x00D8, /* Interrupt mask Clear */
5637a6523bSDavid du Colombier Iam = 0x00E0, /* Interrupt acknowledge Auto Mask */
5747ad9175SDavid du Colombier
5847ad9175SDavid du Colombier /* Receive */
5947ad9175SDavid du Colombier
6037a6523bSDavid du Colombier Rctl = 0x0100, /* Control */
619b7bf7dfSDavid du Colombier Ert = 0x2008, /* Early Receive Threshold (573[EVL], 579 only) */
6237a6523bSDavid du Colombier Fcrtl = 0x2160, /* Flow Control RX Threshold Low */
6337a6523bSDavid du Colombier Fcrth = 0x2168, /* Flow Control Rx Threshold High */
6437a6523bSDavid du Colombier Psrctl = 0x2170, /* Packet Split Receive Control */
6537a6523bSDavid du Colombier Rdbal = 0x2800, /* Rdesc Base Address Low Queue 0 */
6637a6523bSDavid du Colombier Rdbah = 0x2804, /* Rdesc Base Address High Queue 0 */
6737a6523bSDavid du Colombier Rdlen = 0x2808, /* Descriptor Length Queue 0 */
6837a6523bSDavid du Colombier Rdh = 0x2810, /* Descriptor Head Queue 0 */
6937a6523bSDavid du Colombier Rdt = 0x2818, /* Descriptor Tail Queue 0 */
7037a6523bSDavid du Colombier Rdtr = 0x2820, /* Descriptor Timer Ring */
7137a6523bSDavid du Colombier Rxdctl = 0x2828, /* Descriptor Control */
7237a6523bSDavid du Colombier Radv = 0x282C, /* Interrupt Absolute Delay Timer */
7337a6523bSDavid du Colombier Rdbal1 = 0x2900, /* Rdesc Base Address Low Queue 1 */
7437a6523bSDavid du Colombier Rdbah1 = 0x2804, /* Rdesc Base Address High Queue 1 */
7537a6523bSDavid du Colombier Rdlen1 = 0x2908, /* Descriptor Length Queue 1 */
7637a6523bSDavid du Colombier Rdh1 = 0x2910, /* Descriptor Head Queue 1 */
7737a6523bSDavid du Colombier Rdt1 = 0x2918, /* Descriptor Tail Queue 1 */
7837a6523bSDavid du Colombier Rxdctl1 = 0x2928, /* Descriptor Control Queue 1 */
7937a6523bSDavid du Colombier Rsrpd = 0x2c00, /* Small Packet Detect */
8037a6523bSDavid du Colombier Raid = 0x2c08, /* ACK interrupt delay */
8137a6523bSDavid du Colombier Cpuvec = 0x2c10, /* CPU Vector */
8237a6523bSDavid du Colombier Rxcsum = 0x5000, /* Checksum Control */
8337a6523bSDavid du Colombier Rfctl = 0x5008, /* Filter Control */
8437a6523bSDavid du Colombier Mta = 0x5200, /* Multicast Table Array */
8537a6523bSDavid du Colombier Ral = 0x5400, /* Receive Address Low */
8637a6523bSDavid du Colombier Rah = 0x5404, /* Receive Address High */
8737a6523bSDavid du Colombier Vfta = 0x5600, /* VLAN Filter Table Array */
8837a6523bSDavid du Colombier Mrqc = 0x5818, /* Multiple Receive Queues Command */
8937a6523bSDavid du Colombier Rssim = 0x5864, /* RSS Interrupt Mask */
9037a6523bSDavid du Colombier Rssir = 0x5868, /* RSS Interrupt Request */
9137a6523bSDavid du Colombier Reta = 0x5c00, /* Redirection Table */
9237a6523bSDavid du Colombier Rssrk = 0x5c80, /* RSS Random Key */
9347ad9175SDavid du Colombier
9447ad9175SDavid du Colombier /* Transmit */
9547ad9175SDavid du Colombier
9637a6523bSDavid du Colombier Tctl = 0x0400, /* Transmit Control */
9737a6523bSDavid du Colombier Tipg = 0x0410, /* Transmit IPG */
9837a6523bSDavid du Colombier Tkabgtxd = 0x3004, /* glci afe band gap transmit ref data, or something */
9937a6523bSDavid du Colombier Tdbal = 0x3800, /* Tdesc Base Address Low */
10037a6523bSDavid du Colombier Tdbah = 0x3804, /* Tdesc Base Address High */
10137a6523bSDavid du Colombier Tdlen = 0x3808, /* Descriptor Length */
10237a6523bSDavid du Colombier Tdh = 0x3810, /* Descriptor Head */
10337a6523bSDavid du Colombier Tdt = 0x3818, /* Descriptor Tail */
10437a6523bSDavid du Colombier Tidv = 0x3820, /* Interrupt Delay Value */
10537a6523bSDavid du Colombier Txdctl = 0x3828, /* Descriptor Control */
10637a6523bSDavid du Colombier Tadv = 0x382C, /* Interrupt Absolute Delay Timer */
10737a6523bSDavid du Colombier Tarc0 = 0x3840, /* Arbitration Counter Queue 0 */
10837a6523bSDavid du Colombier Tdbal1 = 0x3900, /* Descriptor Base Low Queue 1 */
10937a6523bSDavid du Colombier Tdbah1 = 0x3904, /* Descriptor Base High Queue 1 */
11037a6523bSDavid du Colombier Tdlen1 = 0x3908, /* Descriptor Length Queue 1 */
11137a6523bSDavid du Colombier Tdh1 = 0x3910, /* Descriptor Head Queue 1 */
11237a6523bSDavid du Colombier Tdt1 = 0x3918, /* Descriptor Tail Queue 1 */
11337a6523bSDavid du Colombier Txdctl1 = 0x3928, /* Descriptor Control 1 */
11437a6523bSDavid du Colombier Tarc1 = 0x3940, /* Arbitration Counter Queue 1 */
11547ad9175SDavid du Colombier
11647ad9175SDavid du Colombier /* Statistics */
11747ad9175SDavid du Colombier
11837a6523bSDavid du Colombier Statistics = 0x4000, /* Start of Statistics Area */
11947ad9175SDavid du Colombier Gorcl = 0x88/4, /* Good Octets Received Count */
12047ad9175SDavid du Colombier Gotcl = 0x90/4, /* Good Octets Transmitted Count */
12147ad9175SDavid du Colombier Torl = 0xC0/4, /* Total Octets Received */
12247ad9175SDavid du Colombier Totl = 0xC8/4, /* Total Octets Transmitted */
12337a6523bSDavid du Colombier Nstatistics = 0x124/4,
12447ad9175SDavid du Colombier };
12547ad9175SDavid du Colombier
12647ad9175SDavid du Colombier enum { /* Ctrl */
12737a6523bSDavid du Colombier GIOmd = 1<<2, /* BIO master disable */
12837a6523bSDavid du Colombier Lrst = 1<<3, /* link reset */
12937a6523bSDavid du Colombier Slu = 1<<6, /* Set Link Up */
13037a6523bSDavid du Colombier SspeedMASK = 3<<8, /* Speed Selection */
13147ad9175SDavid du Colombier SspeedSHIFT = 8,
1320343ea0dSDavid du Colombier Sspeed10 = 0x00000000, /* 10Mb/s */
1330343ea0dSDavid du Colombier Sspeed100 = 0x00000100, /* 100Mb/s */
1340343ea0dSDavid du Colombier Sspeed1000 = 0x00000200, /* 1000Mb/s */
13537a6523bSDavid du Colombier Frcspd = 1<<11, /* Force Speed */
13637a6523bSDavid du Colombier Frcdplx = 1<<12, /* Force Duplex */
13747ad9175SDavid du Colombier SwdpinsloMASK = 0x003C0000, /* Software Defined Pins - lo nibble */
13847ad9175SDavid du Colombier SwdpinsloSHIFT = 18,
13947ad9175SDavid du Colombier SwdpioloMASK = 0x03C00000, /* Software Defined Pins - I or O */
14047ad9175SDavid du Colombier SwdpioloSHIFT = 22,
14137a6523bSDavid du Colombier Devrst = 1<<26, /* Device Reset */
14237a6523bSDavid du Colombier Rfce = 1<<27, /* Receive Flow Control Enable */
14337a6523bSDavid du Colombier Tfce = 1<<28, /* Transmit Flow Control Enable */
14437a6523bSDavid du Colombier Vme = 1<<30, /* VLAN Mode Enable */
14537a6523bSDavid du Colombier Phyrst = 1<<31, /* Phy Reset */
14647ad9175SDavid du Colombier };
14747ad9175SDavid du Colombier
14847ad9175SDavid du Colombier enum { /* Status */
14937a6523bSDavid du Colombier Lu = 1<<1, /* Link Up */
15022f9ff60SDavid du Colombier Lanid = 3<<2, /* mask for Lan ID. */
15137a6523bSDavid du Colombier Txoff = 1<<4, /* Transmission Paused */
15237a6523bSDavid du Colombier Tbimode = 1<<5, /* TBI Mode Indication */
15337a6523bSDavid du Colombier Phyra = 1<<10, /* PHY Reset Asserted */
15437a6523bSDavid du Colombier GIOme = 1<<19, /* GIO Master Enable Status */
15547ad9175SDavid du Colombier };
15647ad9175SDavid du Colombier
15747ad9175SDavid du Colombier enum { /* Eerd */
1580343ea0dSDavid du Colombier EEstart = 1<<0, /* Start Read */
1590343ea0dSDavid du Colombier EEdone = 1<<1, /* Read done */
16047ad9175SDavid du Colombier };
16147ad9175SDavid du Colombier
16247ad9175SDavid du Colombier enum { /* Ctrlext */
16337a6523bSDavid du Colombier Asdchk = 1<<12, /* ASD Check */
16437a6523bSDavid du Colombier Eerst = 1<<13, /* EEPROM Reset */
16537a6523bSDavid du Colombier Spdbyps = 1<<15, /* Speed Select Bypass */
16647ad9175SDavid du Colombier };
16747ad9175SDavid du Colombier
16847ad9175SDavid du Colombier enum { /* EEPROM content offsets */
16947ad9175SDavid du Colombier Ea = 0x00, /* Ethernet Address */
17047ad9175SDavid du Colombier Cf = 0x03, /* Compatibility Field */
17147ad9175SDavid du Colombier Icw1 = 0x0A, /* Initialization Control Word 1 */
17247ad9175SDavid du Colombier Sid = 0x0B, /* Subsystem ID */
17347ad9175SDavid du Colombier Svid = 0x0C, /* Subsystem Vendor ID */
17447ad9175SDavid du Colombier Did = 0x0D, /* Device ID */
17547ad9175SDavid du Colombier Vid = 0x0E, /* Vendor ID */
17647ad9175SDavid du Colombier Icw2 = 0x0F, /* Initialization Control Word 2 */
17747ad9175SDavid du Colombier };
17847ad9175SDavid du Colombier
17947ad9175SDavid du Colombier enum { /* Mdic */
1800343ea0dSDavid du Colombier MDIdMASK = 0x0000FFFF, /* Data */
18147ad9175SDavid du Colombier MDIdSHIFT = 0,
18247ad9175SDavid du Colombier MDIrMASK = 0x001F0000, /* PHY Register Address */
18347ad9175SDavid du Colombier MDIrSHIFT = 16,
18447ad9175SDavid du Colombier MDIpMASK = 0x03E00000, /* PHY Address */
18547ad9175SDavid du Colombier MDIpSHIFT = 21,
18647ad9175SDavid du Colombier MDIwop = 0x04000000, /* Write Operation */
18747ad9175SDavid du Colombier MDIrop = 0x08000000, /* Read Operation */
18847ad9175SDavid du Colombier MDIready = 0x10000000, /* End of Transaction */
18947ad9175SDavid du Colombier MDIie = 0x20000000, /* Interrupt Enable */
19047ad9175SDavid du Colombier MDIe = 0x40000000, /* Error */
19147ad9175SDavid du Colombier };
19247ad9175SDavid du Colombier
19331748cd5SDavid du Colombier enum { /* phy interface registers */
19431748cd5SDavid du Colombier Phyctl = 0, /* phy ctl */
19531748cd5SDavid du Colombier Physsr = 17, /* phy secondary status */
19631748cd5SDavid du Colombier Phyier = 18, /* 82573 phy interrupt enable */
19731748cd5SDavid du Colombier Phyisr = 19, /* 82563 phy interrupt status */
19831748cd5SDavid du Colombier Phylhr = 19, /* 8257[12] link health */
19931748cd5SDavid du Colombier
20037a6523bSDavid du Colombier Rtlink = 1<<10, /* realtime link status */
20131748cd5SDavid du Colombier Phyan = 1<<11, /* phy has auto-negotiated */
20231748cd5SDavid du Colombier
20331748cd5SDavid du Colombier /* Phyctl bits */
20431748cd5SDavid du Colombier Ran = 1<<9, /* restart auto-negotiation */
20531748cd5SDavid du Colombier Ean = 1<<12, /* enable auto-negotiation */
20631748cd5SDavid du Colombier
20731748cd5SDavid du Colombier /* 82573 Phyier bits */
20831748cd5SDavid du Colombier Lscie = 1<<10, /* link status changed ie */
20931748cd5SDavid du Colombier Ancie = 1<<11, /* auto-negotiation complete ie */
21031748cd5SDavid du Colombier Spdie = 1<<14, /* speed changed ie */
21131748cd5SDavid du Colombier Panie = 1<<15, /* phy auto-negotiation error ie */
21231748cd5SDavid du Colombier
21331748cd5SDavid du Colombier /* Phylhr/Phyisr bits */
21431748cd5SDavid du Colombier Anf = 1<<6, /* lhr: auto-negotiation fault */
21531748cd5SDavid du Colombier Ane = 1<<15, /* isr: auto-negotiation error */
21637a6523bSDavid du Colombier };
21737a6523bSDavid du Colombier
21847ad9175SDavid du Colombier enum { /* Icr, Ics, Ims, Imc */
2190343ea0dSDavid du Colombier Txdw = 0x00000001, /* Transmit Descriptor Written Back */
2200343ea0dSDavid du Colombier Txqe = 0x00000002, /* Transmit Queue Empty */
2210343ea0dSDavid du Colombier Lsc = 0x00000004, /* Link Status Change */
2220343ea0dSDavid du Colombier Rxseq = 0x00000008, /* Receive Sequence Error */
2230343ea0dSDavid du Colombier Rxdmt0 = 0x00000010, /* Rdesc Minimum Threshold Reached */
2240343ea0dSDavid du Colombier Rxo = 0x00000040, /* Receiver Overrun */
2250343ea0dSDavid du Colombier Rxt0 = 0x00000080, /* Receiver Timer Interrupt */
2260343ea0dSDavid du Colombier Mdac = 0x00000200, /* MDIO Access Completed */
2270343ea0dSDavid du Colombier Rxcfg = 0x00000400, /* Receiving /C/ ordered sets */
2280343ea0dSDavid du Colombier Gpi0 = 0x00000800, /* General Purpose Interrupts */
2290343ea0dSDavid du Colombier Gpi1 = 0x00001000,
2300343ea0dSDavid du Colombier Gpi2 = 0x00002000,
2310343ea0dSDavid du Colombier Gpi3 = 0x00004000,
23237a6523bSDavid du Colombier Ack = 0x00020000, /* Receive ACK frame */
23347ad9175SDavid du Colombier };
23447ad9175SDavid du Colombier
23547ad9175SDavid du Colombier enum { /* Txcw */
2360343ea0dSDavid du Colombier TxcwFd = 0x00000020, /* Full Duplex */
2370343ea0dSDavid du Colombier TxcwHd = 0x00000040, /* Half Duplex */
2380343ea0dSDavid du Colombier TxcwPauseMASK = 0x00000180, /* Pause */
23947ad9175SDavid du Colombier TxcwPauseSHIFT = 7,
24037a6523bSDavid du Colombier TxcwPs = 1<<TxcwPauseSHIFT, /* Pause Supported */
24137a6523bSDavid du Colombier TxcwAs = 2<<TxcwPauseSHIFT, /* Asymmetric FC desired */
2420343ea0dSDavid du Colombier TxcwRfiMASK = 0x00003000, /* Remote Fault Indication */
24347ad9175SDavid du Colombier TxcwRfiSHIFT = 12,
2440343ea0dSDavid du Colombier TxcwNpr = 0x00008000, /* Next Page Request */
24508cb4641SDavid du Colombier TxcwConfig = 0x40000000, /* Transmit Config Control */
24647ad9175SDavid du Colombier TxcwAne = 0x80000000, /* Auto-Negotiation Enable */
24747ad9175SDavid du Colombier };
24847ad9175SDavid du Colombier
24947ad9175SDavid du Colombier enum { /* Rctl */
2500343ea0dSDavid du Colombier Rrst = 0x00000001, /* Receiver Software Reset */
2510343ea0dSDavid du Colombier Ren = 0x00000002, /* Receiver Enable */
2520343ea0dSDavid du Colombier Sbp = 0x00000004, /* Store Bad Packets */
2530343ea0dSDavid du Colombier Upe = 0x00000008, /* Unicast Promiscuous Enable */
2540343ea0dSDavid du Colombier Mpe = 0x00000010, /* Multicast Promiscuous Enable */
2550343ea0dSDavid du Colombier Lpe = 0x00000020, /* Long Packet Reception Enable */
2560343ea0dSDavid du Colombier LbmMASK = 0x000000C0, /* Loopback Mode */
2570343ea0dSDavid du Colombier LbmOFF = 0x00000000, /* No Loopback */
2580343ea0dSDavid du Colombier LbmTBI = 0x00000040, /* TBI Loopback */
2590343ea0dSDavid du Colombier LbmMII = 0x00000080, /* GMII/MII Loopback */
2600343ea0dSDavid du Colombier LbmXCVR = 0x000000C0, /* Transceiver Loopback */
2610343ea0dSDavid du Colombier RdtmsMASK = 0x00000300, /* Rdesc Minimum Threshold Size */
2620343ea0dSDavid du Colombier RdtmsHALF = 0x00000000, /* Threshold is 1/2 Rdlen */
2630343ea0dSDavid du Colombier RdtmsQUARTER = 0x00000100, /* Threshold is 1/4 Rdlen */
2640343ea0dSDavid du Colombier RdtmsEIGHTH = 0x00000200, /* Threshold is 1/8 Rdlen */
2650343ea0dSDavid du Colombier MoMASK = 0x00003000, /* Multicast Offset */
2660343ea0dSDavid du Colombier Bam = 0x00008000, /* Broadcast Accept Mode */
26747ad9175SDavid du Colombier BsizeMASK = 0x00030000, /* Receive Buffer Size */
26837a6523bSDavid du Colombier Bsize16384 = 0x00010000, /* Bsex = 1 */
26947ad9175SDavid du Colombier Bsize8192 = 0x00020000, /* Bsex = 1 */
2700343ea0dSDavid du Colombier Bsize2048 = 0x00000000,
27147ad9175SDavid du Colombier Bsize1024 = 0x00010000,
27247ad9175SDavid du Colombier Bsize512 = 0x00020000,
27347ad9175SDavid du Colombier Bsize256 = 0x00030000,
27408cb4641SDavid du Colombier BsizeFlex = 0x08000000, /* Flexible Bsize in 1KB increments */
27547ad9175SDavid du Colombier Vfe = 0x00040000, /* VLAN Filter Enable */
27647ad9175SDavid du Colombier Cfien = 0x00080000, /* Canonical Form Indicator Enable */
27747ad9175SDavid du Colombier Cfi = 0x00100000, /* Canonical Form Indicator value */
27847ad9175SDavid du Colombier Dpf = 0x00400000, /* Discard Pause Frames */
27947ad9175SDavid du Colombier Pmcf = 0x00800000, /* Pass MAC Control Frames */
28047ad9175SDavid du Colombier Bsex = 0x02000000, /* Buffer Size Extension */
28147ad9175SDavid du Colombier Secrc = 0x04000000, /* Strip CRC from incoming packet */
28247ad9175SDavid du Colombier };
28347ad9175SDavid du Colombier
28447ad9175SDavid du Colombier enum { /* Tctl */
2850343ea0dSDavid du Colombier Trst = 0x00000001, /* Transmitter Software Reset */
2860343ea0dSDavid du Colombier Ten = 0x00000002, /* Transmit Enable */
2870343ea0dSDavid du Colombier Psp = 0x00000008, /* Pad Short Packets */
28837a6523bSDavid du Colombier Mulr = 0x10000000, /* Allow multiple concurrent requests */
2890343ea0dSDavid du Colombier CtMASK = 0x00000FF0, /* Collision Threshold */
29047ad9175SDavid du Colombier CtSHIFT = 4,
29147ad9175SDavid du Colombier ColdMASK = 0x003FF000, /* Collision Distance */
29247ad9175SDavid du Colombier ColdSHIFT = 12,
29347ad9175SDavid du Colombier Swxoff = 0x00400000, /* Sofware XOFF Transmission */
29447ad9175SDavid du Colombier Pbe = 0x00800000, /* Packet Burst Enable */
29547ad9175SDavid du Colombier Rtlc = 0x01000000, /* Re-transmit on Late Collision */
29647ad9175SDavid du Colombier Nrtu = 0x02000000, /* No Re-transmit on Underrrun */
29747ad9175SDavid du Colombier };
29847ad9175SDavid du Colombier
29947ad9175SDavid du Colombier enum { /* [RT]xdctl */
3000343ea0dSDavid du Colombier PthreshMASK = 0x0000003F, /* Prefetch Threshold */
30147ad9175SDavid du Colombier PthreshSHIFT = 0,
3020343ea0dSDavid du Colombier HthreshMASK = 0x00003F00, /* Host Threshold */
30347ad9175SDavid du Colombier HthreshSHIFT = 8,
30437a6523bSDavid du Colombier WthreshMASK = 0x003F0000, /* Writeback Threshold */
30547ad9175SDavid du Colombier WthreshSHIFT = 16,
30647ad9175SDavid du Colombier Gran = 0x01000000, /* Granularity */
30708cb4641SDavid du Colombier Qenable = 0x02000000, /* Queue Enable (82575) */
30847ad9175SDavid du Colombier };
30947ad9175SDavid du Colombier
31047ad9175SDavid du Colombier enum { /* Rxcsum */
31137a6523bSDavid du Colombier PcssMASK = 0x00FF, /* Packet Checksum Start */
31247ad9175SDavid du Colombier PcssSHIFT = 0,
31337a6523bSDavid du Colombier Ipofl = 0x0100, /* IP Checksum Off-load Enable */
31437a6523bSDavid du Colombier Tuofl = 0x0200, /* TCP/UDP Checksum Off-load Enable */
31547ad9175SDavid du Colombier };
31647ad9175SDavid du Colombier
31747ad9175SDavid du Colombier enum { /* Receive Delay Timer Ring */
31837a6523bSDavid du Colombier DelayMASK = 0xFFFF, /* delay timer in 1.024nS increments */
31947ad9175SDavid du Colombier DelaySHIFT = 0,
32047ad9175SDavid du Colombier Fpd = 0x80000000, /* Flush partial Descriptor Block */
32147ad9175SDavid du Colombier };
32247ad9175SDavid du Colombier
323c02f0a41SDavid du Colombier typedef struct Ctlr Ctlr;
324c02f0a41SDavid du Colombier typedef struct Rd Rd;
325c02f0a41SDavid du Colombier typedef struct Td Td;
326c02f0a41SDavid du Colombier
327c02f0a41SDavid du Colombier struct Rd { /* Receive Descriptor */
32808cb4641SDavid du Colombier u32int addr[2];
32908cb4641SDavid du Colombier u16int length;
33008cb4641SDavid du Colombier u16int checksum;
33108cb4641SDavid du Colombier u8int status;
33208cb4641SDavid du Colombier u8int errors;
33308cb4641SDavid du Colombier u16int special;
334c02f0a41SDavid du Colombier };
33547ad9175SDavid du Colombier
33647ad9175SDavid du Colombier enum { /* Rd status */
33747ad9175SDavid du Colombier Rdd = 0x01, /* Descriptor Done */
33847ad9175SDavid du Colombier Reop = 0x02, /* End of Packet */
33947ad9175SDavid du Colombier Ixsm = 0x04, /* Ignore Checksum Indication */
34047ad9175SDavid du Colombier Vp = 0x08, /* Packet is 802.1Q (matched VET) */
34147ad9175SDavid du Colombier Tcpcs = 0x20, /* TCP Checksum Calculated on Packet */
34247ad9175SDavid du Colombier Ipcs = 0x40, /* IP Checksum Calculated on Packet */
34347ad9175SDavid du Colombier Pif = 0x80, /* Passed in-exact filter */
34447ad9175SDavid du Colombier };
34547ad9175SDavid du Colombier
34647ad9175SDavid du Colombier enum { /* Rd errors */
34747ad9175SDavid du Colombier Ce = 0x01, /* CRC Error or Alignment Error */
34847ad9175SDavid du Colombier Se = 0x02, /* Symbol Error */
34947ad9175SDavid du Colombier Seq = 0x04, /* Sequence Error */
35047ad9175SDavid du Colombier Cxe = 0x10, /* Carrier Extension Error */
35147ad9175SDavid du Colombier Tcpe = 0x20, /* TCP/UDP Checksum Error */
35247ad9175SDavid du Colombier Ipe = 0x40, /* IP Checksum Error */
35347ad9175SDavid du Colombier Rxe = 0x80, /* RX Data Error */
35447ad9175SDavid du Colombier };
35547ad9175SDavid du Colombier
356c02f0a41SDavid du Colombier struct Td { /* Transmit Descriptor */
35708cb4641SDavid du Colombier u32int addr[2]; /* Data */
35808cb4641SDavid du Colombier u32int control;
35908cb4641SDavid du Colombier u32int status;
360c02f0a41SDavid du Colombier };
36147ad9175SDavid du Colombier
36247ad9175SDavid du Colombier enum { /* Tdesc control */
36347ad9175SDavid du Colombier LenMASK = 0x000FFFFF, /* Data/Packet Length Field */
36447ad9175SDavid du Colombier LenSHIFT = 0,
3650343ea0dSDavid du Colombier DtypeCD = 0x00000000, /* Data Type 'Context Descriptor' */
36647ad9175SDavid du Colombier DtypeDD = 0x00100000, /* Data Type 'Data Descriptor' */
36747ad9175SDavid du Colombier PtypeTCP = 0x01000000, /* TCP/UDP Packet Type (CD) */
36847ad9175SDavid du Colombier Teop = 0x01000000, /* End of Packet (DD) */
36947ad9175SDavid du Colombier PtypeIP = 0x02000000, /* IP Packet Type (CD) */
37047ad9175SDavid du Colombier Ifcs = 0x02000000, /* Insert FCS (DD) */
37147ad9175SDavid du Colombier Tse = 0x04000000, /* TCP Segmentation Enable */
37247ad9175SDavid du Colombier Rs = 0x08000000, /* Report Status */
37347ad9175SDavid du Colombier Rps = 0x10000000, /* Report Status Sent */
37447ad9175SDavid du Colombier Dext = 0x20000000, /* Descriptor Extension */
37547ad9175SDavid du Colombier Vle = 0x40000000, /* VLAN Packet Enable */
37647ad9175SDavid du Colombier Ide = 0x80000000, /* Interrupt Delay Enable */
37747ad9175SDavid du Colombier };
37847ad9175SDavid du Colombier
37947ad9175SDavid du Colombier enum { /* Tdesc status */
38037a6523bSDavid du Colombier Tdd = 0x0001, /* Descriptor Done */
38137a6523bSDavid du Colombier Ec = 0x0002, /* Excess Collisions */
38237a6523bSDavid du Colombier Lc = 0x0004, /* Late Collision */
38337a6523bSDavid du Colombier Tu = 0x0008, /* Transmit Underrun */
38437a6523bSDavid du Colombier CssMASK = 0xFF00, /* Checksum Start Field */
38547ad9175SDavid du Colombier CssSHIFT = 8,
38647ad9175SDavid du Colombier };
38747ad9175SDavid du Colombier
38891b330d9SDavid du Colombier typedef struct {
38908cb4641SDavid du Colombier u16int *reg;
39008cb4641SDavid du Colombier u32int *reg32;
3918c242bd4SDavid du Colombier u16int base;
3928c242bd4SDavid du Colombier u16int lim;
39391b330d9SDavid du Colombier } Flash;
39491b330d9SDavid du Colombier
39591b330d9SDavid du Colombier enum {
39691b330d9SDavid du Colombier /* 16 and 32-bit flash registers for ich flash parts */
39791b330d9SDavid du Colombier Bfpr = 0x00/4, /* flash base 0:12; lim 16:28 */
3983bf825d6SDavid du Colombier Fsts = 0x04/2, /* flash status; Hsfsts */
3993bf825d6SDavid du Colombier Fctl = 0x06/2, /* flash control; Hsfctl */
40091b330d9SDavid du Colombier Faddr = 0x08/4, /* flash address to r/w */
40191b330d9SDavid du Colombier Fdata = 0x10/4, /* data @ address */
40291b330d9SDavid du Colombier
40391b330d9SDavid du Colombier /* status register */
40491b330d9SDavid du Colombier Fdone = 1<<0, /* flash cycle done */
40591b330d9SDavid du Colombier Fcerr = 1<<1, /* cycle error; write 1 to clear */
40691b330d9SDavid du Colombier Ael = 1<<2, /* direct access error log; 1 to clear */
40791b330d9SDavid du Colombier Scip = 1<<5, /* spi cycle in progress */
40891b330d9SDavid du Colombier Fvalid = 1<<14, /* flash descriptor valid */
40991b330d9SDavid du Colombier
41091b330d9SDavid du Colombier /* control register */
41191b330d9SDavid du Colombier Fgo = 1<<0, /* start cycle */
41291b330d9SDavid du Colombier Flcycle = 1<<1, /* two bits: r=0; w=2 */
41391b330d9SDavid du Colombier Fdbc = 1<<8, /* bytes to read; 5 bits */
41491b330d9SDavid du Colombier };
41591b330d9SDavid du Colombier
41647ad9175SDavid du Colombier enum {
417588d0145SDavid du Colombier /* were 512, 1024 & 64, but 52, 253 and 9 are ample. */
418588d0145SDavid du Colombier Nrd = 128, /* power of two */
419*cebd3b46SDavid du Colombier Nrb = 512, /* private receive buffers per Ctlr */
420588d0145SDavid du Colombier Ntd = 32, /* power of two */
42147ad9175SDavid du Colombier };
42247ad9175SDavid du Colombier
42337a6523bSDavid du Colombier enum {
42491b330d9SDavid du Colombier Iany,
42537a6523bSDavid du Colombier i82563,
42637a6523bSDavid du Colombier i82566,
427e4ac449cSDavid du Colombier i82567,
42837a6523bSDavid du Colombier i82571,
42937a6523bSDavid du Colombier i82572,
43037a6523bSDavid du Colombier i82573,
43188bfb1f3SDavid du Colombier i82574,
43208cb4641SDavid du Colombier i82575,
433c39c2eb3SDavid du Colombier i82576,
434d8cd2beaSDavid du Colombier i82577,
4359b7bf7dfSDavid du Colombier i82579,
43637a6523bSDavid du Colombier };
43737a6523bSDavid du Colombier
43837a6523bSDavid du Colombier static int rbtab[] = {
43991b330d9SDavid du Colombier 0,
44037a6523bSDavid du Colombier 9014,
441a587111cSDavid du Colombier ETHERMAXTU,
442a587111cSDavid du Colombier ETHERMAXTU,
44337a6523bSDavid du Colombier 9234,
44437a6523bSDavid du Colombier 9234,
44537a6523bSDavid du Colombier 8192, /* terrible performance above 8k */
446a587111cSDavid du Colombier ETHERMAXTU,
447a587111cSDavid du Colombier ETHERMAXTU,
448a587111cSDavid du Colombier ETHERMAXTU,
449a587111cSDavid du Colombier ETHERMAXTU,
4509b7bf7dfSDavid du Colombier 9018,
45137a6523bSDavid du Colombier };
45237a6523bSDavid du Colombier
45337a6523bSDavid du Colombier static char *tname[] = {
45491b330d9SDavid du Colombier "any",
45537a6523bSDavid du Colombier "i82563",
45637a6523bSDavid du Colombier "i82566",
457e4ac449cSDavid du Colombier "i82567",
45837a6523bSDavid du Colombier "i82571",
45937a6523bSDavid du Colombier "i82572",
46037a6523bSDavid du Colombier "i82573",
46188bfb1f3SDavid du Colombier "i82574",
46208cb4641SDavid du Colombier "i82575",
463c39c2eb3SDavid du Colombier "i82576",
464d8cd2beaSDavid du Colombier "i82577",
4659b7bf7dfSDavid du Colombier "i82579",
46637a6523bSDavid du Colombier };
46737a6523bSDavid du Colombier
46847ad9175SDavid du Colombier struct Ctlr {
46947ad9175SDavid du Colombier int port;
47047ad9175SDavid du Colombier Pcidev *pcidev;
47147ad9175SDavid du Colombier Ctlr *next;
47246136019SDavid du Colombier Ether *edev;
47347ad9175SDavid du Colombier int active;
47437a6523bSDavid du Colombier int type;
47547ad9175SDavid du Colombier ushort eeprom[0x40];
47647ad9175SDavid du Colombier
47747ad9175SDavid du Colombier QLock alock; /* attach */
47808cb4641SDavid du Colombier int attached;
47947ad9175SDavid du Colombier int nrd;
48047ad9175SDavid du Colombier int ntd;
4816083aa43SDavid du Colombier int nrb; /* # rcv bufs this Ctlr has in the pool */
4820343ea0dSDavid du Colombier unsigned rbsz; /* unsigned for % and / by 1024 */
48347ad9175SDavid du Colombier
48447ad9175SDavid du Colombier int *nic;
48547ad9175SDavid du Colombier Lock imlock;
48647ad9175SDavid du Colombier int im; /* interrupt mask */
48747ad9175SDavid du Colombier
48847ad9175SDavid du Colombier Rendez lrendez;
48947ad9175SDavid du Colombier int lim;
49047ad9175SDavid du Colombier
491217e9e83SDavid du Colombier Watermark wmrb;
492217e9e83SDavid du Colombier Watermark wmrd;
493217e9e83SDavid du Colombier Watermark wmtd;
494217e9e83SDavid du Colombier
49547ad9175SDavid du Colombier QLock slock;
49647ad9175SDavid du Colombier uint statistics[Nstatistics];
49747ad9175SDavid du Colombier uint lsleep;
49847ad9175SDavid du Colombier uint lintr;
49947ad9175SDavid du Colombier uint rsleep;
50047ad9175SDavid du Colombier uint rintr;
50147ad9175SDavid du Colombier uint txdw;
50247ad9175SDavid du Colombier uint tintr;
50347ad9175SDavid du Colombier uint ixsm;
50447ad9175SDavid du Colombier uint ipcs;
50547ad9175SDavid du Colombier uint tcpcs;
50637a6523bSDavid du Colombier uint speeds[4];
50747ad9175SDavid du Colombier
50847ad9175SDavid du Colombier uchar ra[Eaddrlen]; /* receive address */
50947ad9175SDavid du Colombier ulong mta[128]; /* multicast table array */
51047ad9175SDavid du Colombier
51147ad9175SDavid du Colombier Rendez rrendez;
51247ad9175SDavid du Colombier int rim;
513c02f0a41SDavid du Colombier int rdfree; /* rx descriptors awaiting packets */
51447ad9175SDavid du Colombier Rd *rdba; /* receive descriptor base address */
51547ad9175SDavid du Colombier Block **rb; /* receive buffers */
51647ad9175SDavid du Colombier int rdh; /* receive descriptor head */
51747ad9175SDavid du Colombier int rdt; /* receive descriptor tail */
51847ad9175SDavid du Colombier int rdtr; /* receive delay timer ring value */
51947ad9175SDavid du Colombier int radv; /* receive interrupt absolute delay timer */
52047ad9175SDavid du Colombier
52137a6523bSDavid du Colombier Rendez trendez;
52237a6523bSDavid du Colombier QLock tlock;
52347ad9175SDavid du Colombier Td *tdba; /* transmit descriptor base address */
52447ad9175SDavid du Colombier Block **tb; /* transmit buffers */
52547ad9175SDavid du Colombier int tdh; /* transmit descriptor head */
52647ad9175SDavid du Colombier int tdt; /* transmit descriptor tail */
52747ad9175SDavid du Colombier
52847ad9175SDavid du Colombier int fcrtl;
52947ad9175SDavid du Colombier int fcrth;
53047ad9175SDavid du Colombier
53137a6523bSDavid du Colombier uint pba; /* packet buffer allocation */
53247ad9175SDavid du Colombier };
53347ad9175SDavid du Colombier
53447ad9175SDavid du Colombier #define csr32r(c, r) (*((c)->nic+((r)/4)))
53547ad9175SDavid du Colombier #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
53647ad9175SDavid du Colombier
53747ad9175SDavid du Colombier static Ctlr* i82563ctlrhead;
53847ad9175SDavid du Colombier static Ctlr* i82563ctlrtail;
53947ad9175SDavid du Colombier
54047ad9175SDavid du Colombier static Lock i82563rblock; /* free receive Blocks */
54147ad9175SDavid du Colombier static Block* i82563rbpool;
5426083aa43SDavid du Colombier static int nrbfull; /* # of rcv Blocks with data awaiting processing */
54347ad9175SDavid du Colombier
54437a6523bSDavid du Colombier static char* statistics[] = {
54547ad9175SDavid du Colombier "CRC Error",
54647ad9175SDavid du Colombier "Alignment Error",
54747ad9175SDavid du Colombier "Symbol Error",
54847ad9175SDavid du Colombier "RX Error",
54947ad9175SDavid du Colombier "Missed Packets",
55047ad9175SDavid du Colombier "Single Collision",
55147ad9175SDavid du Colombier "Excessive Collisions",
55247ad9175SDavid du Colombier "Multiple Collision",
55347ad9175SDavid du Colombier "Late Collisions",
55447ad9175SDavid du Colombier nil,
55547ad9175SDavid du Colombier "Collision",
55647ad9175SDavid du Colombier "Transmit Underrun",
55747ad9175SDavid du Colombier "Defer",
55847ad9175SDavid du Colombier "Transmit - No CRS",
55947ad9175SDavid du Colombier "Sequence Error",
56047ad9175SDavid du Colombier "Carrier Extension Error",
56147ad9175SDavid du Colombier "Receive Error Length",
56247ad9175SDavid du Colombier nil,
56347ad9175SDavid du Colombier "XON Received",
56447ad9175SDavid du Colombier "XON Transmitted",
56547ad9175SDavid du Colombier "XOFF Received",
56647ad9175SDavid du Colombier "XOFF Transmitted",
56747ad9175SDavid du Colombier "FC Received Unsupported",
56847ad9175SDavid du Colombier "Packets Received (64 Bytes)",
56947ad9175SDavid du Colombier "Packets Received (65-127 Bytes)",
57047ad9175SDavid du Colombier "Packets Received (128-255 Bytes)",
57147ad9175SDavid du Colombier "Packets Received (256-511 Bytes)",
57247ad9175SDavid du Colombier "Packets Received (512-1023 Bytes)",
57337a6523bSDavid du Colombier "Packets Received (1024-mtu Bytes)",
57447ad9175SDavid du Colombier "Good Packets Received",
57547ad9175SDavid du Colombier "Broadcast Packets Received",
57647ad9175SDavid du Colombier "Multicast Packets Received",
57747ad9175SDavid du Colombier "Good Packets Transmitted",
57847ad9175SDavid du Colombier nil,
57947ad9175SDavid du Colombier "Good Octets Received",
58047ad9175SDavid du Colombier nil,
58147ad9175SDavid du Colombier "Good Octets Transmitted",
58247ad9175SDavid du Colombier nil,
58347ad9175SDavid du Colombier nil,
58447ad9175SDavid du Colombier nil,
58547ad9175SDavid du Colombier "Receive No Buffers",
58647ad9175SDavid du Colombier "Receive Undersize",
58747ad9175SDavid du Colombier "Receive Fragment",
58847ad9175SDavid du Colombier "Receive Oversize",
58947ad9175SDavid du Colombier "Receive Jabber",
59037a6523bSDavid du Colombier "Management Packets Rx",
59137a6523bSDavid du Colombier "Management Packets Drop",
59237a6523bSDavid du Colombier "Management Packets Tx",
59347ad9175SDavid du Colombier "Total Octets Received",
59447ad9175SDavid du Colombier nil,
59547ad9175SDavid du Colombier "Total Octets Transmitted",
59647ad9175SDavid du Colombier nil,
59747ad9175SDavid du Colombier "Total Packets Received",
59847ad9175SDavid du Colombier "Total Packets Transmitted",
59947ad9175SDavid du Colombier "Packets Transmitted (64 Bytes)",
60047ad9175SDavid du Colombier "Packets Transmitted (65-127 Bytes)",
60147ad9175SDavid du Colombier "Packets Transmitted (128-255 Bytes)",
60247ad9175SDavid du Colombier "Packets Transmitted (256-511 Bytes)",
60347ad9175SDavid du Colombier "Packets Transmitted (512-1023 Bytes)",
60437a6523bSDavid du Colombier "Packets Transmitted (1024-mtu Bytes)",
60547ad9175SDavid du Colombier "Multicast Packets Transmitted",
60647ad9175SDavid du Colombier "Broadcast Packets Transmitted",
60747ad9175SDavid du Colombier "TCP Segmentation Context Transmitted",
60847ad9175SDavid du Colombier "TCP Segmentation Context Fail",
60937a6523bSDavid du Colombier "Interrupt Assertion",
61037a6523bSDavid du Colombier "Interrupt Rx Pkt Timer",
61137a6523bSDavid du Colombier "Interrupt Rx Abs Timer",
61237a6523bSDavid du Colombier "Interrupt Tx Pkt Timer",
61337a6523bSDavid du Colombier "Interrupt Tx Abs Timer",
61437a6523bSDavid du Colombier "Interrupt Tx Queue Empty",
61537a6523bSDavid du Colombier "Interrupt Tx Desc Low",
61637a6523bSDavid du Colombier "Interrupt Rx Min",
61737a6523bSDavid du Colombier "Interrupt Rx Overrun",
61847ad9175SDavid du Colombier };
61947ad9175SDavid du Colombier
62047ad9175SDavid du Colombier static long
i82563ifstat(Ether * edev,void * a,long n,ulong offset)62147ad9175SDavid du Colombier i82563ifstat(Ether* edev, void* a, long n, ulong offset)
62247ad9175SDavid du Colombier {
62347ad9175SDavid du Colombier Ctlr *ctlr;
62437a6523bSDavid du Colombier char *s, *p, *e, *stat;
62537a6523bSDavid du Colombier int i, r;
62647ad9175SDavid du Colombier uvlong tuvl, ruvl;
62747ad9175SDavid du Colombier
62847ad9175SDavid du Colombier ctlr = edev->ctlr;
62947ad9175SDavid du Colombier qlock(&ctlr->slock);
63046136019SDavid du Colombier p = s = malloc(READSTR);
631aa72973aSDavid du Colombier if(p == nil) {
632aa72973aSDavid du Colombier qunlock(&ctlr->slock);
633aa72973aSDavid du Colombier error(Enomem);
634aa72973aSDavid du Colombier }
63546136019SDavid du Colombier e = p + READSTR;
63637a6523bSDavid du Colombier
63747ad9175SDavid du Colombier for(i = 0; i < Nstatistics; i++){
63847ad9175SDavid du Colombier r = csr32r(ctlr, Statistics + i*4);
63937a6523bSDavid du Colombier if((stat = statistics[i]) == nil)
64047ad9175SDavid du Colombier continue;
64147ad9175SDavid du Colombier switch(i){
64247ad9175SDavid du Colombier case Gorcl:
64347ad9175SDavid du Colombier case Gotcl:
64447ad9175SDavid du Colombier case Torl:
64547ad9175SDavid du Colombier case Totl:
64647ad9175SDavid du Colombier ruvl = r;
64737a6523bSDavid du Colombier ruvl += (uvlong)csr32r(ctlr, Statistics+(i+1)*4) << 32;
64847ad9175SDavid du Colombier tuvl = ruvl;
64947ad9175SDavid du Colombier tuvl += ctlr->statistics[i];
65037a6523bSDavid du Colombier tuvl += (uvlong)ctlr->statistics[i+1] << 32;
65147ad9175SDavid du Colombier if(tuvl == 0)
65247ad9175SDavid du Colombier continue;
65347ad9175SDavid du Colombier ctlr->statistics[i] = tuvl;
65447ad9175SDavid du Colombier ctlr->statistics[i+1] = tuvl >> 32;
65537a6523bSDavid du Colombier p = seprint(p, e, "%s: %llud %llud\n", stat, tuvl, ruvl);
65647ad9175SDavid du Colombier i++;
65747ad9175SDavid du Colombier break;
65847ad9175SDavid du Colombier
65947ad9175SDavid du Colombier default:
66047ad9175SDavid du Colombier ctlr->statistics[i] += r;
66147ad9175SDavid du Colombier if(ctlr->statistics[i] == 0)
66247ad9175SDavid du Colombier continue;
66337a6523bSDavid du Colombier p = seprint(p, e, "%s: %ud %ud\n", stat,
66437a6523bSDavid du Colombier ctlr->statistics[i], r);
66547ad9175SDavid du Colombier break;
66647ad9175SDavid du Colombier }
66747ad9175SDavid du Colombier }
66847ad9175SDavid du Colombier
66937a6523bSDavid du Colombier p = seprint(p, e, "lintr: %ud %ud\n", ctlr->lintr, ctlr->lsleep);
67037a6523bSDavid du Colombier p = seprint(p, e, "rintr: %ud %ud\n", ctlr->rintr, ctlr->rsleep);
67137a6523bSDavid du Colombier p = seprint(p, e, "tintr: %ud %ud\n", ctlr->tintr, ctlr->txdw);
67237a6523bSDavid du Colombier p = seprint(p, e, "ixcs: %ud %ud %ud\n", ctlr->ixsm, ctlr->ipcs, ctlr->tcpcs);
67337a6523bSDavid du Colombier p = seprint(p, e, "rdtr: %ud\n", ctlr->rdtr);
67437a6523bSDavid du Colombier p = seprint(p, e, "radv: %ud\n", ctlr->radv);
67537a6523bSDavid du Colombier p = seprint(p, e, "ctrl: %.8ux\n", csr32r(ctlr, Ctrl));
67637a6523bSDavid du Colombier p = seprint(p, e, "ctrlext: %.8ux\n", csr32r(ctlr, Ctrlext));
67737a6523bSDavid du Colombier p = seprint(p, e, "status: %.8ux\n", csr32r(ctlr, Status));
67837a6523bSDavid du Colombier p = seprint(p, e, "txcw: %.8ux\n", csr32r(ctlr, Txcw));
67937a6523bSDavid du Colombier p = seprint(p, e, "txdctl: %.8ux\n", csr32r(ctlr, Txdctl));
68037a6523bSDavid du Colombier p = seprint(p, e, "pba: %.8ux\n", ctlr->pba);
68147ad9175SDavid du Colombier
68237a6523bSDavid du Colombier p = seprint(p, e, "speeds: 10:%ud 100:%ud 1000:%ud ?:%ud\n",
68337a6523bSDavid du Colombier ctlr->speeds[0], ctlr->speeds[1], ctlr->speeds[2], ctlr->speeds[3]);
68491b330d9SDavid du Colombier p = seprint(p, e, "type: %s\n", tname[ctlr->type]);
6856083aa43SDavid du Colombier p = seprint(p, e, "nrbfull (rcv blocks outstanding): %d\n", nrbfull);
68637a6523bSDavid du Colombier
68737a6523bSDavid du Colombier // p = seprint(p, e, "eeprom:");
68837a6523bSDavid du Colombier // for(i = 0; i < 0x40; i++){
68937a6523bSDavid du Colombier // if(i && ((i & 7) == 0))
69037a6523bSDavid du Colombier // p = seprint(p, e, "\n ");
69137a6523bSDavid du Colombier // p = seprint(p, e, " %4.4ux", ctlr->eeprom[i]);
69237a6523bSDavid du Colombier // }
69337a6523bSDavid du Colombier // p = seprint(p, e, "\n");
69437a6523bSDavid du Colombier
695217e9e83SDavid du Colombier p = seprintmark(p, e, &ctlr->wmrb);
696217e9e83SDavid du Colombier p = seprintmark(p, e, &ctlr->wmrd);
697217e9e83SDavid du Colombier p = seprintmark(p, e, &ctlr->wmtd);
698217e9e83SDavid du Colombier
69937a6523bSDavid du Colombier USED(p);
70037a6523bSDavid du Colombier n = readstr(offset, a, n, s);
70137a6523bSDavid du Colombier free(s);
70247ad9175SDavid du Colombier qunlock(&ctlr->slock);
70347ad9175SDavid du Colombier
70447ad9175SDavid du Colombier return n;
70547ad9175SDavid du Colombier }
70647ad9175SDavid du Colombier
70747ad9175SDavid du Colombier enum {
70847ad9175SDavid du Colombier CMrdtr,
70947ad9175SDavid du Colombier CMradv,
71047ad9175SDavid du Colombier };
71147ad9175SDavid du Colombier
71247ad9175SDavid du Colombier static Cmdtab i82563ctlmsg[] = {
71347ad9175SDavid du Colombier CMrdtr, "rdtr", 2,
71447ad9175SDavid du Colombier CMradv, "radv", 2,
71547ad9175SDavid du Colombier };
71647ad9175SDavid du Colombier
71747ad9175SDavid du Colombier static long
i82563ctl(Ether * edev,void * buf,long n)71847ad9175SDavid du Colombier i82563ctl(Ether* edev, void* buf, long n)
71947ad9175SDavid du Colombier {
72031748cd5SDavid du Colombier ulong v;
72147ad9175SDavid du Colombier char *p;
72247ad9175SDavid du Colombier Ctlr *ctlr;
72347ad9175SDavid du Colombier Cmdbuf *cb;
72447ad9175SDavid du Colombier Cmdtab *ct;
72547ad9175SDavid du Colombier
72647ad9175SDavid du Colombier if((ctlr = edev->ctlr) == nil)
72747ad9175SDavid du Colombier error(Enonexist);
72847ad9175SDavid du Colombier
72947ad9175SDavid du Colombier cb = parsecmd(buf, n);
73047ad9175SDavid du Colombier if(waserror()){
73147ad9175SDavid du Colombier free(cb);
73247ad9175SDavid du Colombier nexterror();
73347ad9175SDavid du Colombier }
73447ad9175SDavid du Colombier
73547ad9175SDavid du Colombier ct = lookupcmd(cb, i82563ctlmsg, nelem(i82563ctlmsg));
73647ad9175SDavid du Colombier switch(ct->index){
73747ad9175SDavid du Colombier case CMrdtr:
73831748cd5SDavid du Colombier v = strtoul(cb->f[1], &p, 0);
73931748cd5SDavid du Colombier if(p == cb->f[1] || v > 0xFFFF)
74047ad9175SDavid du Colombier error(Ebadarg);
74147ad9175SDavid du Colombier ctlr->rdtr = v;
74237a6523bSDavid du Colombier csr32w(ctlr, Rdtr, v);
74347ad9175SDavid du Colombier break;
74447ad9175SDavid du Colombier case CMradv:
74531748cd5SDavid du Colombier v = strtoul(cb->f[1], &p, 0);
74631748cd5SDavid du Colombier if(p == cb->f[1] || v > 0xFFFF)
74747ad9175SDavid du Colombier error(Ebadarg);
74847ad9175SDavid du Colombier ctlr->radv = v;
74947ad9175SDavid du Colombier csr32w(ctlr, Radv, v);
75047ad9175SDavid du Colombier }
75147ad9175SDavid du Colombier free(cb);
75247ad9175SDavid du Colombier poperror();
75347ad9175SDavid du Colombier
75447ad9175SDavid du Colombier return n;
75547ad9175SDavid du Colombier }
75647ad9175SDavid du Colombier
75747ad9175SDavid du Colombier static void
i82563promiscuous(void * arg,int on)75847ad9175SDavid du Colombier i82563promiscuous(void* arg, int on)
75947ad9175SDavid du Colombier {
76047ad9175SDavid du Colombier int rctl;
76147ad9175SDavid du Colombier Ctlr *ctlr;
76247ad9175SDavid du Colombier Ether *edev;
76347ad9175SDavid du Colombier
76447ad9175SDavid du Colombier edev = arg;
76547ad9175SDavid du Colombier ctlr = edev->ctlr;
76647ad9175SDavid du Colombier
76747ad9175SDavid du Colombier rctl = csr32r(ctlr, Rctl);
76847ad9175SDavid du Colombier rctl &= ~MoMASK;
76947ad9175SDavid du Colombier if(on)
77047ad9175SDavid du Colombier rctl |= Upe|Mpe;
77147ad9175SDavid du Colombier else
77247ad9175SDavid du Colombier rctl &= ~(Upe|Mpe);
77347ad9175SDavid du Colombier csr32w(ctlr, Rctl, rctl);
77447ad9175SDavid du Colombier }
77547ad9175SDavid du Colombier
77647ad9175SDavid du Colombier static void
i82563multicast(void * arg,uchar * addr,int on)77747ad9175SDavid du Colombier i82563multicast(void* arg, uchar* addr, int on)
77847ad9175SDavid du Colombier {
77947ad9175SDavid du Colombier int bit, x;
78047ad9175SDavid du Colombier Ctlr *ctlr;
78147ad9175SDavid du Colombier Ether *edev;
78247ad9175SDavid du Colombier
78347ad9175SDavid du Colombier edev = arg;
78447ad9175SDavid du Colombier ctlr = edev->ctlr;
78547ad9175SDavid du Colombier
78647ad9175SDavid du Colombier x = addr[5]>>1;
787e4ac449cSDavid du Colombier if(ctlr->type == i82566 || ctlr->type == i82567)
78837a6523bSDavid du Colombier x &= 31;
78947ad9175SDavid du Colombier bit = ((addr[5] & 1)<<4)|(addr[4]>>4);
7903bf825d6SDavid du Colombier /*
7913bf825d6SDavid du Colombier * multiple ether addresses can hash to the same filter bit,
7923bf825d6SDavid du Colombier * so it's never safe to clear a filter bit.
7933bf825d6SDavid du Colombier * if we want to clear filter bits, we need to keep track of
7943bf825d6SDavid du Colombier * all the multicast addresses in use, clear all the filter bits,
7953bf825d6SDavid du Colombier * then set the ones corresponding to in-use addresses.
7963bf825d6SDavid du Colombier */
79747ad9175SDavid du Colombier if(on)
79847ad9175SDavid du Colombier ctlr->mta[x] |= 1<<bit;
7993bf825d6SDavid du Colombier // else
8003bf825d6SDavid du Colombier // ctlr->mta[x] &= ~(1<<bit);
80147ad9175SDavid du Colombier
80247ad9175SDavid du Colombier csr32w(ctlr, Mta+x*4, ctlr->mta[x]);
80347ad9175SDavid du Colombier }
80447ad9175SDavid du Colombier
80547ad9175SDavid du Colombier static Block*
i82563rballoc(void)80647ad9175SDavid du Colombier i82563rballoc(void)
80747ad9175SDavid du Colombier {
80847ad9175SDavid du Colombier Block *bp;
80947ad9175SDavid du Colombier
81047ad9175SDavid du Colombier ilock(&i82563rblock);
81147ad9175SDavid du Colombier if((bp = i82563rbpool) != nil){
81247ad9175SDavid du Colombier i82563rbpool = bp->next;
81347ad9175SDavid du Colombier bp->next = nil;
81408cb4641SDavid du Colombier _xinc(&bp->ref); /* prevent bp from being freed */
81547ad9175SDavid du Colombier }
81647ad9175SDavid du Colombier iunlock(&i82563rblock);
81747ad9175SDavid du Colombier
81847ad9175SDavid du Colombier return bp;
81947ad9175SDavid du Colombier }
82047ad9175SDavid du Colombier
82147ad9175SDavid du Colombier static void
i82563rbfree(Block * b)82237a6523bSDavid du Colombier i82563rbfree(Block* b)
82347ad9175SDavid du Colombier {
82437a6523bSDavid du Colombier b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base);
825bfb6eab9SDavid du Colombier b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
82647ad9175SDavid du Colombier ilock(&i82563rblock);
82737a6523bSDavid du Colombier b->next = i82563rbpool;
82837a6523bSDavid du Colombier i82563rbpool = b;
8296083aa43SDavid du Colombier nrbfull--;
83047ad9175SDavid du Colombier iunlock(&i82563rblock);
83147ad9175SDavid du Colombier }
83247ad9175SDavid du Colombier
83347ad9175SDavid du Colombier static void
i82563im(Ctlr * ctlr,int im)83447ad9175SDavid du Colombier i82563im(Ctlr* ctlr, int im)
83547ad9175SDavid du Colombier {
83647ad9175SDavid du Colombier ilock(&ctlr->imlock);
83747ad9175SDavid du Colombier ctlr->im |= im;
83847ad9175SDavid du Colombier csr32w(ctlr, Ims, ctlr->im);
83947ad9175SDavid du Colombier iunlock(&ctlr->imlock);
84047ad9175SDavid du Colombier }
84147ad9175SDavid du Colombier
84247ad9175SDavid du Colombier static void
i82563txinit(Ctlr * ctlr)84347ad9175SDavid du Colombier i82563txinit(Ctlr* ctlr)
84447ad9175SDavid du Colombier {
84547ad9175SDavid du Colombier int i, r;
84647ad9175SDavid du Colombier Block *bp;
84747ad9175SDavid du Colombier
84837a6523bSDavid du Colombier csr32w(ctlr, Tctl, 0x0F<<CtSHIFT | Psp | 66<<ColdSHIFT | Mulr);
84937a6523bSDavid du Colombier csr32w(ctlr, Tipg, 6<<20 | 8<<10 | 8); /* yb sez: 0x702008 */
85047ad9175SDavid du Colombier csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
85147ad9175SDavid du Colombier csr32w(ctlr, Tdbah, 0);
85247ad9175SDavid du Colombier csr32w(ctlr, Tdlen, ctlr->ntd * sizeof(Td));
85347ad9175SDavid du Colombier ctlr->tdh = PREV(0, ctlr->ntd);
85447ad9175SDavid du Colombier csr32w(ctlr, Tdh, 0);
85547ad9175SDavid du Colombier ctlr->tdt = 0;
85647ad9175SDavid du Colombier csr32w(ctlr, Tdt, 0);
85747ad9175SDavid du Colombier for(i = 0; i < ctlr->ntd; i++){
85847ad9175SDavid du Colombier if((bp = ctlr->tb[i]) != nil){
85947ad9175SDavid du Colombier ctlr->tb[i] = nil;
86047ad9175SDavid du Colombier freeb(bp);
86147ad9175SDavid du Colombier }
86247ad9175SDavid du Colombier memset(&ctlr->tdba[i], 0, sizeof(Td));
86347ad9175SDavid du Colombier }
86447ad9175SDavid du Colombier csr32w(ctlr, Tidv, 128);
86547ad9175SDavid du Colombier r = csr32r(ctlr, Txdctl);
866c39c2eb3SDavid du Colombier r &= ~(WthreshMASK|PthreshMASK);
86737a6523bSDavid du Colombier r |= 4<<WthreshSHIFT | 4<<PthreshSHIFT;
868c39c2eb3SDavid du Colombier if(ctlr->type == i82575 || ctlr->type == i82576)
86908cb4641SDavid du Colombier r |= Qenable;
87047ad9175SDavid du Colombier csr32w(ctlr, Tadv, 64);
87147ad9175SDavid du Colombier csr32w(ctlr, Txdctl, r);
87247ad9175SDavid du Colombier r = csr32r(ctlr, Tctl);
87347ad9175SDavid du Colombier r |= Ten;
87447ad9175SDavid du Colombier csr32w(ctlr, Tctl, r);
87537a6523bSDavid du Colombier // if(ctlr->type == i82671)
87637a6523bSDavid du Colombier // csr32w(ctlr, Tarc0, csr32r(ctlr, Tarc0) | 7<<24); /* yb sez? */
87737a6523bSDavid du Colombier }
87837a6523bSDavid du Colombier
87937a6523bSDavid du Colombier #define Next(x, m) (((x)+1) & (m))
88037a6523bSDavid du Colombier
88137a6523bSDavid du Colombier static int
i82563cleanup(Ctlr * ctlr)882217e9e83SDavid du Colombier i82563cleanup(Ctlr *ctlr)
88337a6523bSDavid du Colombier {
88437a6523bSDavid du Colombier Block *b;
88537a6523bSDavid du Colombier int tdh, m, n;
88637a6523bSDavid du Colombier
887217e9e83SDavid du Colombier tdh = ctlr->tdh;
888217e9e83SDavid du Colombier m = ctlr->ntd-1;
889217e9e83SDavid du Colombier while(ctlr->tdba[n = Next(tdh, m)].status & Tdd){
89037a6523bSDavid du Colombier tdh = n;
891217e9e83SDavid du Colombier if((b = ctlr->tb[tdh]) != nil){
892217e9e83SDavid du Colombier ctlr->tb[tdh] = nil;
89337a6523bSDavid du Colombier freeb(b);
89437a6523bSDavid du Colombier }else
89537a6523bSDavid du Colombier iprint("82563 tx underrun!\n");
896217e9e83SDavid du Colombier ctlr->tdba[tdh].status = 0;
89737a6523bSDavid du Colombier }
89837a6523bSDavid du Colombier
899217e9e83SDavid du Colombier return ctlr->tdh = tdh;
90047ad9175SDavid du Colombier }
90147ad9175SDavid du Colombier
90247ad9175SDavid du Colombier static void
i82563transmit(Ether * edev)90347ad9175SDavid du Colombier i82563transmit(Ether* edev)
90447ad9175SDavid du Colombier {
90547ad9175SDavid du Colombier Td *td;
90647ad9175SDavid du Colombier Block *bp;
90747ad9175SDavid du Colombier Ctlr *ctlr;
90837a6523bSDavid du Colombier int tdh, tdt, m;
90947ad9175SDavid du Colombier
91047ad9175SDavid du Colombier ctlr = edev->ctlr;
91147ad9175SDavid du Colombier
91237a6523bSDavid du Colombier qlock(&ctlr->tlock);
91347ad9175SDavid du Colombier
91447ad9175SDavid du Colombier /*
91547ad9175SDavid du Colombier * Free any completed packets
91647ad9175SDavid du Colombier */
91737a6523bSDavid du Colombier tdh = i82563cleanup(ctlr);
91847ad9175SDavid du Colombier
91947ad9175SDavid du Colombier /*
92047ad9175SDavid du Colombier * Try to fill the ring back up.
92147ad9175SDavid du Colombier */
92247ad9175SDavid du Colombier tdt = ctlr->tdt;
92337a6523bSDavid du Colombier m = ctlr->ntd-1;
92437a6523bSDavid du Colombier for(;;){
92537a6523bSDavid du Colombier if(Next(tdt, m) == tdh){
92647ad9175SDavid du Colombier ctlr->txdw++;
92747ad9175SDavid du Colombier i82563im(ctlr, Txdw);
92847ad9175SDavid du Colombier break;
92947ad9175SDavid du Colombier }
93037a6523bSDavid du Colombier if((bp = qget(edev->oq)) == nil)
93137a6523bSDavid du Colombier break;
93237a6523bSDavid du Colombier td = &ctlr->tdba[tdt];
93337a6523bSDavid du Colombier td->addr[0] = PCIWADDR(bp->rp);
93437a6523bSDavid du Colombier td->control = Ide|Rs|Ifcs|Teop|BLEN(bp);
93537a6523bSDavid du Colombier ctlr->tb[tdt] = bp;
936217e9e83SDavid du Colombier /* note size of queue of tds awaiting transmission */
937217e9e83SDavid du Colombier notemark(&ctlr->wmtd, (tdt + Ntd - tdh) % Ntd);
93837a6523bSDavid du Colombier tdt = Next(tdt, m);
93947ad9175SDavid du Colombier }
94037a6523bSDavid du Colombier if(ctlr->tdt != tdt){
94137a6523bSDavid du Colombier ctlr->tdt = tdt;
94247ad9175SDavid du Colombier csr32w(ctlr, Tdt, tdt);
94337a6523bSDavid du Colombier }
94437a6523bSDavid du Colombier qunlock(&ctlr->tlock);
94547ad9175SDavid du Colombier }
94647ad9175SDavid du Colombier
94747ad9175SDavid du Colombier static void
i82563replenish(Ctlr * ctlr)94847ad9175SDavid du Colombier i82563replenish(Ctlr* ctlr)
94947ad9175SDavid du Colombier {
95047ad9175SDavid du Colombier Rd *rd;
95137a6523bSDavid du Colombier int rdt, m;
95247ad9175SDavid du Colombier Block *bp;
95347ad9175SDavid du Colombier
95447ad9175SDavid du Colombier rdt = ctlr->rdt;
95537a6523bSDavid du Colombier m = ctlr->nrd-1;
95637a6523bSDavid du Colombier while(Next(rdt, m) != ctlr->rdh){
95747ad9175SDavid du Colombier rd = &ctlr->rdba[rdt];
95837a6523bSDavid du Colombier if(ctlr->rb[rdt] != nil){
9596083aa43SDavid du Colombier print("#l%d: 82563: rx overrun\n", ctlr->edev->ctlrno);
96037a6523bSDavid du Colombier break;
96137a6523bSDavid du Colombier }
96247ad9175SDavid du Colombier bp = i82563rballoc();
9636083aa43SDavid du Colombier if(bp == nil)
9646083aa43SDavid du Colombier /*
9656083aa43SDavid du Colombier * this almost never gets better. likely there's a bug
9666083aa43SDavid du Colombier * elsewhere in the kernel that is failing to free a
9676083aa43SDavid du Colombier * receive Block.
9686083aa43SDavid du Colombier */
9696083aa43SDavid du Colombier panic("#l%d: 82563: all %d rx buffers in use, nrbfull %d",
9706083aa43SDavid du Colombier ctlr->edev->ctlrno, ctlr->nrb, nrbfull);
97147ad9175SDavid du Colombier ctlr->rb[rdt] = bp;
97247ad9175SDavid du Colombier rd->addr[0] = PCIWADDR(bp->rp);
97337a6523bSDavid du Colombier // rd->addr[1] = 0;
97447ad9175SDavid du Colombier rd->status = 0;
97547ad9175SDavid du Colombier ctlr->rdfree++;
97637a6523bSDavid du Colombier rdt = Next(rdt, m);
97747ad9175SDavid du Colombier }
97847ad9175SDavid du Colombier ctlr->rdt = rdt;
97947ad9175SDavid du Colombier csr32w(ctlr, Rdt, rdt);
98047ad9175SDavid du Colombier }
98147ad9175SDavid du Colombier
98247ad9175SDavid du Colombier static void
i82563rxinit(Ctlr * ctlr)98347ad9175SDavid du Colombier i82563rxinit(Ctlr* ctlr)
98447ad9175SDavid du Colombier {
98547ad9175SDavid du Colombier Block *bp;
98608cb4641SDavid du Colombier int i, r, rctl;
98747ad9175SDavid du Colombier
98837a6523bSDavid du Colombier if(ctlr->rbsz <= 2048)
98908cb4641SDavid du Colombier rctl = Dpf|Bsize2048|Bam|RdtmsHALF;
99037a6523bSDavid du Colombier else if(ctlr->rbsz <= 8192)
99108cb4641SDavid du Colombier rctl = Lpe|Dpf|Bsize8192|Bsex|Bam|RdtmsHALF|Secrc;
99237a6523bSDavid du Colombier else if(ctlr->rbsz <= 12*1024){
99337a6523bSDavid du Colombier i = ctlr->rbsz / 1024;
99437a6523bSDavid du Colombier if(ctlr->rbsz % 1024)
99537a6523bSDavid du Colombier i++;
99608cb4641SDavid du Colombier rctl = Lpe|Dpf|BsizeFlex*i|Bam|RdtmsHALF|Secrc;
99708cb4641SDavid du Colombier }
99808cb4641SDavid du Colombier else
99908cb4641SDavid du Colombier rctl = Lpe|Dpf|Bsize16384|Bsex|Bam|RdtmsHALF|Secrc;
100008cb4641SDavid du Colombier
1001c39c2eb3SDavid du Colombier if(ctlr->type == i82575 || ctlr->type == i82576){
100208cb4641SDavid du Colombier /*
100308cb4641SDavid du Colombier * Setting Qenable in Rxdctl does not
100408cb4641SDavid du Colombier * appear to stick unless Ren is on.
100508cb4641SDavid du Colombier */
100608cb4641SDavid du Colombier csr32w(ctlr, Rctl, Ren|rctl);
100708cb4641SDavid du Colombier r = csr32r(ctlr, Rxdctl);
100808cb4641SDavid du Colombier r |= Qenable;
100908cb4641SDavid du Colombier csr32w(ctlr, Rxdctl, r);
101008cb4641SDavid du Colombier }
101108cb4641SDavid du Colombier csr32w(ctlr, Rctl, rctl);
101237a6523bSDavid du Colombier
10139b7bf7dfSDavid du Colombier if(ctlr->type == i82573 || ctlr->type == i82577 || ctlr->type == i82579)
101437a6523bSDavid du Colombier csr32w(ctlr, Ert, 1024/8);
10150343ea0dSDavid du Colombier
1016e4ac449cSDavid du Colombier if(ctlr->type == i82566 || ctlr->type == i82567)
101737a6523bSDavid du Colombier csr32w(ctlr, Pbs, 16);
101847ad9175SDavid du Colombier
101947ad9175SDavid du Colombier csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));
102047ad9175SDavid du Colombier csr32w(ctlr, Rdbah, 0);
102147ad9175SDavid du Colombier csr32w(ctlr, Rdlen, ctlr->nrd * sizeof(Rd));
102247ad9175SDavid du Colombier ctlr->rdh = 0;
102347ad9175SDavid du Colombier csr32w(ctlr, Rdh, 0);
102447ad9175SDavid du Colombier ctlr->rdt = 0;
102547ad9175SDavid du Colombier csr32w(ctlr, Rdt, 0);
10266f746b77SDavid du Colombier /* to hell with interrupt moderation, we've got fast cpus */
10276f746b77SDavid du Colombier // ctlr->rdtr = 25; /* µs units? */
10286f746b77SDavid du Colombier // ctlr->radv = 500; /* µs units? */
102991157df7SDavid du Colombier ctlr->radv = ctlr->rdtr = 0;
103037a6523bSDavid du Colombier csr32w(ctlr, Rdtr, ctlr->rdtr);
103137a6523bSDavid du Colombier csr32w(ctlr, Radv, ctlr->radv);
103247ad9175SDavid du Colombier
103308cb4641SDavid du Colombier for(i = 0; i < ctlr->nrd; i++){
103447ad9175SDavid du Colombier if((bp = ctlr->rb[i]) != nil){
103547ad9175SDavid du Colombier ctlr->rb[i] = nil;
103647ad9175SDavid du Colombier freeb(bp);
103747ad9175SDavid du Colombier }
103808cb4641SDavid du Colombier }
103947ad9175SDavid du Colombier i82563replenish(ctlr);
104008cb4641SDavid du Colombier
1041c39c2eb3SDavid du Colombier if(ctlr->type != i82575 || ctlr->type == i82576){
104208cb4641SDavid du Colombier /*
104308cb4641SDavid du Colombier * See comment above for Qenable.
104408cb4641SDavid du Colombier * Could shuffle the code?
104508cb4641SDavid du Colombier */
104608cb4641SDavid du Colombier r = csr32r(ctlr, Rxdctl);
1047c39c2eb3SDavid du Colombier r &= ~(WthreshMASK|PthreshMASK);
104808cb4641SDavid du Colombier r |= (2<<WthreshSHIFT)|(2<<PthreshSHIFT);
104908cb4641SDavid du Colombier csr32w(ctlr, Rxdctl, r);
105008cb4641SDavid du Colombier }
105147ad9175SDavid du Colombier
105247ad9175SDavid du Colombier /*
10536f746b77SDavid du Colombier * Don't enable checksum offload. In practice, it interferes with
10546f746b77SDavid du Colombier * tftp booting on at least the 82575.
105547ad9175SDavid du Colombier */
10566f746b77SDavid du Colombier // csr32w(ctlr, Rxcsum, Tuofl | Ipofl | ETHERHDRSIZE<<PcssSHIFT);
10576f746b77SDavid du Colombier csr32w(ctlr, Rxcsum, 0);
105847ad9175SDavid du Colombier }
105947ad9175SDavid du Colombier
106047ad9175SDavid du Colombier static int
i82563rim(void * ctlr)106147ad9175SDavid du Colombier i82563rim(void* ctlr)
106247ad9175SDavid du Colombier {
106347ad9175SDavid du Colombier return ((Ctlr*)ctlr)->rim != 0;
106447ad9175SDavid du Colombier }
106547ad9175SDavid du Colombier
106647ad9175SDavid du Colombier static void
i82563rproc(void * arg)106747ad9175SDavid du Colombier i82563rproc(void* arg)
106847ad9175SDavid du Colombier {
106947ad9175SDavid du Colombier Rd *rd;
107047ad9175SDavid du Colombier Block *bp;
107147ad9175SDavid du Colombier Ctlr *ctlr;
1072217e9e83SDavid du Colombier int r, m, rdh, rim, passed;
107347ad9175SDavid du Colombier Ether *edev;
107447ad9175SDavid du Colombier
107547ad9175SDavid du Colombier edev = arg;
107647ad9175SDavid du Colombier ctlr = edev->ctlr;
107747ad9175SDavid du Colombier
107847ad9175SDavid du Colombier i82563rxinit(ctlr);
107947ad9175SDavid du Colombier r = csr32r(ctlr, Rctl);
108047ad9175SDavid du Colombier r |= Ren;
108147ad9175SDavid du Colombier csr32w(ctlr, Rctl, r);
108237a6523bSDavid du Colombier m = ctlr->nrd-1;
108347ad9175SDavid du Colombier
108447ad9175SDavid du Colombier for(;;){
10856083aa43SDavid du Colombier i82563replenish(ctlr);
108637a6523bSDavid du Colombier i82563im(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq|Ack);
108747ad9175SDavid du Colombier ctlr->rsleep++;
108847ad9175SDavid du Colombier sleep(&ctlr->rrendez, i82563rim, ctlr);
108947ad9175SDavid du Colombier
109047ad9175SDavid du Colombier rdh = ctlr->rdh;
1091217e9e83SDavid du Colombier passed = 0;
109247ad9175SDavid du Colombier for(;;){
109347ad9175SDavid du Colombier rim = ctlr->rim;
109447ad9175SDavid du Colombier ctlr->rim = 0;
10956083aa43SDavid du Colombier rd = &ctlr->rdba[rdh];
109647ad9175SDavid du Colombier if(!(rd->status & Rdd))
109747ad9175SDavid du Colombier break;
109847ad9175SDavid du Colombier
109947ad9175SDavid du Colombier /*
110047ad9175SDavid du Colombier * Accept eop packets with no errors.
110147ad9175SDavid du Colombier * With no errors and the Ixsm bit set,
110247ad9175SDavid du Colombier * the descriptor status Tpcs and Ipcs bits give
110347ad9175SDavid du Colombier * an indication of whether the checksums were
110447ad9175SDavid du Colombier * calculated and valid.
110547ad9175SDavid du Colombier */
110631748cd5SDavid du Colombier bp = ctlr->rb[rdh];
110747ad9175SDavid du Colombier if((rd->status & Reop) && rd->errors == 0){
110847ad9175SDavid du Colombier bp->wp += rd->length;
11090343ea0dSDavid du Colombier bp->lim = bp->wp; /* lie like a dog. */
111047ad9175SDavid du Colombier if(!(rd->status & Ixsm)){
111147ad9175SDavid du Colombier ctlr->ixsm++;
111247ad9175SDavid du Colombier if(rd->status & Ipcs){
111347ad9175SDavid du Colombier /*
111447ad9175SDavid du Colombier * IP checksum calculated
111547ad9175SDavid du Colombier * (and valid as errors == 0).
111647ad9175SDavid du Colombier */
111747ad9175SDavid du Colombier ctlr->ipcs++;
111847ad9175SDavid du Colombier bp->flag |= Bipck;
111947ad9175SDavid du Colombier }
112047ad9175SDavid du Colombier if(rd->status & Tcpcs){
112147ad9175SDavid du Colombier /*
112247ad9175SDavid du Colombier * TCP/UDP checksum calculated
112347ad9175SDavid du Colombier * (and valid as errors == 0).
112447ad9175SDavid du Colombier */
112547ad9175SDavid du Colombier ctlr->tcpcs++;
112647ad9175SDavid du Colombier bp->flag |= Btcpck|Budpck;
112747ad9175SDavid du Colombier }
112847ad9175SDavid du Colombier bp->checksum = rd->checksum;
112947ad9175SDavid du Colombier bp->flag |= Bpktck;
113047ad9175SDavid du Colombier }
11316083aa43SDavid du Colombier ilock(&i82563rblock);
11326083aa43SDavid du Colombier nrbfull++;
11336083aa43SDavid du Colombier iunlock(&i82563rblock);
1134217e9e83SDavid du Colombier notemark(&ctlr->wmrb, nrbfull);
113547ad9175SDavid du Colombier etheriq(edev, bp, 1);
1136217e9e83SDavid du Colombier passed++;
113759f7772cSDavid du Colombier } else {
113859f7772cSDavid du Colombier if (rd->status & Reop && rd->errors)
11396f746b77SDavid du Colombier print("%s: input packet error %#ux\n",
11406f746b77SDavid du Colombier tname[ctlr->type], rd->errors);
114147ad9175SDavid du Colombier freeb(bp);
114259f7772cSDavid du Colombier }
114347ad9175SDavid du Colombier ctlr->rb[rdh] = nil;
114431748cd5SDavid du Colombier
1145c02f0a41SDavid du Colombier /* rd needs to be replenished to accept another pkt */
114637a6523bSDavid du Colombier rd->status = 0;
114747ad9175SDavid du Colombier ctlr->rdfree--;
114837a6523bSDavid du Colombier ctlr->rdh = rdh = Next(rdh, m);
1149c02f0a41SDavid du Colombier /*
1150c02f0a41SDavid du Colombier * if number of rds ready for packets is too low,
1151c02f0a41SDavid du Colombier * set up the unready ones.
1152c02f0a41SDavid du Colombier */
1153c02f0a41SDavid du Colombier if(ctlr->rdfree <= ctlr->nrd - 32 || (rim & Rxdmt0))
115447ad9175SDavid du Colombier i82563replenish(ctlr);
115547ad9175SDavid du Colombier }
1156217e9e83SDavid du Colombier /* note how many rds had full buffers */
1157217e9e83SDavid du Colombier notemark(&ctlr->wmrd, passed);
115847ad9175SDavid du Colombier }
115947ad9175SDavid du Colombier }
116047ad9175SDavid du Colombier
116137a6523bSDavid du Colombier static int
i82563lim(void * ctlr)1162217e9e83SDavid du Colombier i82563lim(void* ctlr)
116337a6523bSDavid du Colombier {
1164217e9e83SDavid du Colombier return ((Ctlr*)ctlr)->lim != 0;
116537a6523bSDavid du Colombier }
116637a6523bSDavid du Colombier
116737a6523bSDavid du Colombier static int speedtab[] = {
116837a6523bSDavid du Colombier 10, 100, 1000, 0
116937a6523bSDavid du Colombier };
117037a6523bSDavid du Colombier
117137a6523bSDavid du Colombier static uint
phyread(Ctlr * ctlr,int reg)1172217e9e83SDavid du Colombier phyread(Ctlr *ctlr, int reg)
117337a6523bSDavid du Colombier {
117437a6523bSDavid du Colombier uint phy, i;
117537a6523bSDavid du Colombier
1176217e9e83SDavid du Colombier csr32w(ctlr, Mdic, MDIrop | 1<<MDIpSHIFT | reg<<MDIrSHIFT);
117737a6523bSDavid du Colombier phy = 0;
117837a6523bSDavid du Colombier for(i = 0; i < 64; i++){
1179217e9e83SDavid du Colombier phy = csr32r(ctlr, Mdic);
118037a6523bSDavid du Colombier if(phy & (MDIe|MDIready))
118137a6523bSDavid du Colombier break;
118237a6523bSDavid du Colombier microdelay(1);
118337a6523bSDavid du Colombier }
118437a6523bSDavid du Colombier if((phy & (MDIe|MDIready)) != MDIready)
118537a6523bSDavid du Colombier return ~0;
11860343ea0dSDavid du Colombier return phy & 0xffff;
118737a6523bSDavid du Colombier }
118837a6523bSDavid du Colombier
118937a6523bSDavid du Colombier static uint
phywrite(Ctlr * ctlr,int reg,ushort val)1190217e9e83SDavid du Colombier phywrite(Ctlr *ctlr, int reg, ushort val)
119137a6523bSDavid du Colombier {
119237a6523bSDavid du Colombier uint phy, i;
119337a6523bSDavid du Colombier
1194217e9e83SDavid du Colombier csr32w(ctlr, Mdic, MDIwop | 1<<MDIpSHIFT | reg<<MDIrSHIFT | val);
119537a6523bSDavid du Colombier phy = 0;
119637a6523bSDavid du Colombier for(i = 0; i < 64; i++){
1197217e9e83SDavid du Colombier phy = csr32r(ctlr, Mdic);
119837a6523bSDavid du Colombier if(phy & (MDIe|MDIready))
119937a6523bSDavid du Colombier break;
120037a6523bSDavid du Colombier microdelay(1);
120137a6523bSDavid du Colombier }
120237a6523bSDavid du Colombier if((phy & (MDIe|MDIready)) != MDIready)
120337a6523bSDavid du Colombier return ~0;
120437a6523bSDavid du Colombier return 0;
120537a6523bSDavid du Colombier }
120637a6523bSDavid du Colombier
120731748cd5SDavid du Colombier /*
120831748cd5SDavid du Colombier * watch for changes of link state
120931748cd5SDavid du Colombier */
121037a6523bSDavid du Colombier static void
i82563lproc(void * v)121137a6523bSDavid du Colombier i82563lproc(void *v)
121237a6523bSDavid du Colombier {
121331748cd5SDavid du Colombier uint phy, i, a;
1214217e9e83SDavid du Colombier Ctlr *ctlr;
121531748cd5SDavid du Colombier Ether *e;
121637a6523bSDavid du Colombier
121737a6523bSDavid du Colombier e = v;
1218217e9e83SDavid du Colombier ctlr = e->ctlr;
121937a6523bSDavid du Colombier
1220217e9e83SDavid du Colombier if(ctlr->type == i82573 && (phy = phyread(ctlr, Phyier)) != ~0)
1221217e9e83SDavid du Colombier phywrite(ctlr, Phyier, phy | Lscie | Ancie | Spdie | Panie);
122237a6523bSDavid du Colombier for(;;){
1223217e9e83SDavid du Colombier phy = phyread(ctlr, Physsr);
122437a6523bSDavid du Colombier if(phy == ~0)
122537a6523bSDavid du Colombier goto next;
122637a6523bSDavid du Colombier i = (phy>>14) & 3;
122737a6523bSDavid du Colombier
1228217e9e83SDavid du Colombier switch(ctlr->type){
122937a6523bSDavid du Colombier case i82563:
1230217e9e83SDavid du Colombier a = phyread(ctlr, Phyisr) & Ane;
123137a6523bSDavid du Colombier break;
123237a6523bSDavid du Colombier case i82571:
123337a6523bSDavid du Colombier case i82572:
1234d8cd2beaSDavid du Colombier case i82575:
1235d8cd2beaSDavid du Colombier case i82576:
1236217e9e83SDavid du Colombier a = phyread(ctlr, Phylhr) & Anf;
123737a6523bSDavid du Colombier i = (i-1) & 3;
123837a6523bSDavid du Colombier break;
123931748cd5SDavid du Colombier default:
124031748cd5SDavid du Colombier a = 0;
124131748cd5SDavid du Colombier break;
124237a6523bSDavid du Colombier }
124331748cd5SDavid du Colombier if(a)
1244217e9e83SDavid du Colombier phywrite(ctlr, Phyctl, phyread(ctlr, Phyctl) | Ran | Ean);
124531748cd5SDavid du Colombier e->link = (phy & Rtlink) != 0;
124631748cd5SDavid du Colombier if(e->link){
1247217e9e83SDavid du Colombier ctlr->speeds[i]++;
12486f746b77SDavid du Colombier if (speedtab[i])
124937a6523bSDavid du Colombier e->mbps = speedtab[i];
125031748cd5SDavid du Colombier }
125137a6523bSDavid du Colombier next:
1252217e9e83SDavid du Colombier ctlr->lim = 0;
1253217e9e83SDavid du Colombier i82563im(ctlr, Lsc);
1254217e9e83SDavid du Colombier ctlr->lsleep++;
1255217e9e83SDavid du Colombier sleep(&ctlr->lrendez, i82563lim, ctlr);
125637a6523bSDavid du Colombier }
125737a6523bSDavid du Colombier }
125837a6523bSDavid du Colombier
125937a6523bSDavid du Colombier static void
i82563tproc(void * v)126037a6523bSDavid du Colombier i82563tproc(void *v)
126137a6523bSDavid du Colombier {
126237a6523bSDavid du Colombier Ether *e;
1263217e9e83SDavid du Colombier Ctlr *ctlr;
126437a6523bSDavid du Colombier
126537a6523bSDavid du Colombier e = v;
1266217e9e83SDavid du Colombier ctlr = e->ctlr;
126737a6523bSDavid du Colombier for(;;){
1268217e9e83SDavid du Colombier sleep(&ctlr->trendez, return0, 0);
126937a6523bSDavid du Colombier i82563transmit(e);
127037a6523bSDavid du Colombier }
127137a6523bSDavid du Colombier }
127237a6523bSDavid du Colombier
127347ad9175SDavid du Colombier static void
i82563attach(Ether * edev)127447ad9175SDavid du Colombier i82563attach(Ether* edev)
127547ad9175SDavid du Colombier {
127637a6523bSDavid du Colombier Block *bp;
127747ad9175SDavid du Colombier Ctlr *ctlr;
127847ad9175SDavid du Colombier char name[KNAMELEN];
127947ad9175SDavid du Colombier
128047ad9175SDavid du Colombier ctlr = edev->ctlr;
128147ad9175SDavid du Colombier qlock(&ctlr->alock);
128208cb4641SDavid du Colombier if(ctlr->attached){
128347ad9175SDavid du Colombier qunlock(&ctlr->alock);
128447ad9175SDavid du Colombier return;
128547ad9175SDavid du Colombier }
128647ad9175SDavid du Colombier
128737a6523bSDavid du Colombier ctlr->nrd = Nrd;
128837a6523bSDavid du Colombier ctlr->ntd = Ntd;
128947ad9175SDavid du Colombier
129047ad9175SDavid du Colombier if(waserror()){
129191157df7SDavid du Colombier while(ctlr->nrb > 0){
129247ad9175SDavid du Colombier bp = i82563rballoc();
129347ad9175SDavid du Colombier bp->free = nil;
129447ad9175SDavid du Colombier freeb(bp);
129591157df7SDavid du Colombier ctlr->nrb--;
129647ad9175SDavid du Colombier }
129747ad9175SDavid du Colombier free(ctlr->tb);
1298bfb6eab9SDavid du Colombier ctlr->tb = nil;
129991157df7SDavid du Colombier free(ctlr->rb);
130047ad9175SDavid du Colombier ctlr->rb = nil;
130108cb4641SDavid du Colombier free(ctlr->tdba);
1302bfb6eab9SDavid du Colombier ctlr->tdba = nil;
130391157df7SDavid du Colombier free(ctlr->rdba);
130408cb4641SDavid du Colombier ctlr->rdba = nil;
130547ad9175SDavid du Colombier qunlock(&ctlr->alock);
130647ad9175SDavid du Colombier nexterror();
130747ad9175SDavid du Colombier }
130847ad9175SDavid du Colombier
1309bfb6eab9SDavid du Colombier if((ctlr->rdba = mallocalign(ctlr->nrd*sizeof(Rd), 128, 0, 0)) == nil ||
1310bfb6eab9SDavid du Colombier (ctlr->tdba = mallocalign(ctlr->ntd*sizeof(Td), 128, 0, 0)) == nil ||
1311bfb6eab9SDavid du Colombier (ctlr->rb = malloc(ctlr->nrd*sizeof(Block*))) == nil ||
1312bfb6eab9SDavid du Colombier (ctlr->tb = malloc(ctlr->ntd*sizeof(Block*))) == nil)
131308cb4641SDavid du Colombier error(Enomem);
131408cb4641SDavid du Colombier
131537a6523bSDavid du Colombier for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){
131637a6523bSDavid du Colombier if((bp = allocb(ctlr->rbsz + BY2PG)) == nil)
13176fbfa2f3SDavid du Colombier error(Enomem);
131847ad9175SDavid du Colombier bp->free = i82563rbfree;
131947ad9175SDavid du Colombier freeb(bp);
132047ad9175SDavid du Colombier }
13216083aa43SDavid du Colombier nrbfull = 0;
132237a6523bSDavid du Colombier
132330ce352cSDavid du Colombier ctlr->edev = edev; /* point back to Ether* */
132408cb4641SDavid du Colombier ctlr->attached = 1;
1325217e9e83SDavid du Colombier initmark(&ctlr->wmrb, Nrb, "rcv bufs unprocessed");
1326217e9e83SDavid du Colombier initmark(&ctlr->wmrd, Nrd-1, "rcv descrs processed at once");
1327217e9e83SDavid du Colombier initmark(&ctlr->wmtd, Ntd-1, "xmit descr queue len");
132808cb4641SDavid du Colombier
13290343ea0dSDavid du Colombier snprint(name, sizeof name, "#l%dl", edev->ctlrno);
133037a6523bSDavid du Colombier kproc(name, i82563lproc, edev);
133147ad9175SDavid du Colombier
13320343ea0dSDavid du Colombier snprint(name, sizeof name, "#l%dr", edev->ctlrno);
133347ad9175SDavid du Colombier kproc(name, i82563rproc, edev);
133447ad9175SDavid du Colombier
13350343ea0dSDavid du Colombier snprint(name, sizeof name, "#l%dt", edev->ctlrno);
133637a6523bSDavid du Colombier kproc(name, i82563tproc, edev);
133737a6523bSDavid du Colombier
133847ad9175SDavid du Colombier i82563txinit(ctlr);
133947ad9175SDavid du Colombier
134047ad9175SDavid du Colombier qunlock(&ctlr->alock);
134147ad9175SDavid du Colombier poperror();
134247ad9175SDavid du Colombier }
134347ad9175SDavid du Colombier
134447ad9175SDavid du Colombier static void
i82563interrupt(Ureg *,void * arg)134547ad9175SDavid du Colombier i82563interrupt(Ureg*, void* arg)
134647ad9175SDavid du Colombier {
134747ad9175SDavid du Colombier Ctlr *ctlr;
134847ad9175SDavid du Colombier Ether *edev;
13496fbfa2f3SDavid du Colombier int icr, im, i;
135047ad9175SDavid du Colombier
135147ad9175SDavid du Colombier edev = arg;
135247ad9175SDavid du Colombier ctlr = edev->ctlr;
135347ad9175SDavid du Colombier
135447ad9175SDavid du Colombier ilock(&ctlr->imlock);
135547ad9175SDavid du Colombier csr32w(ctlr, Imc, ~0);
135647ad9175SDavid du Colombier im = ctlr->im;
13576083aa43SDavid du Colombier i = Nrd; /* don't livelock */
13586fbfa2f3SDavid du Colombier for(icr = csr32r(ctlr, Icr); icr & ctlr->im && i-- > 0;
13596fbfa2f3SDavid du Colombier icr = csr32r(ctlr, Icr)){
136047ad9175SDavid du Colombier if(icr & Lsc){
136147ad9175SDavid du Colombier im &= ~Lsc;
136247ad9175SDavid du Colombier ctlr->lim = icr & Lsc;
136347ad9175SDavid du Colombier wakeup(&ctlr->lrendez);
136447ad9175SDavid du Colombier ctlr->lintr++;
136547ad9175SDavid du Colombier }
136637a6523bSDavid du Colombier if(icr & (Rxt0|Rxo|Rxdmt0|Rxseq|Ack)){
136737a6523bSDavid du Colombier ctlr->rim = icr & (Rxt0|Rxo|Rxdmt0|Rxseq|Ack);
136837a6523bSDavid du Colombier im &= ~(Rxt0|Rxo|Rxdmt0|Rxseq|Ack);
136947ad9175SDavid du Colombier wakeup(&ctlr->rrendez);
137047ad9175SDavid du Colombier ctlr->rintr++;
137147ad9175SDavid du Colombier }
137247ad9175SDavid du Colombier if(icr & Txdw){
137347ad9175SDavid du Colombier im &= ~Txdw;
137447ad9175SDavid du Colombier ctlr->tintr++;
137537a6523bSDavid du Colombier wakeup(&ctlr->trendez);
137647ad9175SDavid du Colombier }
137747ad9175SDavid du Colombier }
137847ad9175SDavid du Colombier ctlr->im = im;
137947ad9175SDavid du Colombier csr32w(ctlr, Ims, im);
138047ad9175SDavid du Colombier iunlock(&ctlr->imlock);
138147ad9175SDavid du Colombier }
138247ad9175SDavid du Colombier
13836f746b77SDavid du Colombier /* assume misrouted interrupts and check all controllers */
13846f746b77SDavid du Colombier static void
i82575interrupt(Ureg *,void *)13856f746b77SDavid du Colombier i82575interrupt(Ureg*, void *)
13866f746b77SDavid du Colombier {
13876f746b77SDavid du Colombier Ctlr *ctlr;
13886f746b77SDavid du Colombier
138930ce352cSDavid du Colombier for (ctlr = i82563ctlrhead; ctlr != nil && ctlr->edev != nil;
139030ce352cSDavid du Colombier ctlr = ctlr->next)
13916f746b77SDavid du Colombier i82563interrupt(nil, ctlr->edev);
13926f746b77SDavid du Colombier }
13936f746b77SDavid du Colombier
139447ad9175SDavid du Colombier static int
i82563detach0(Ctlr * ctlr)13958ccc32efSDavid du Colombier i82563detach0(Ctlr* ctlr)
139647ad9175SDavid du Colombier {
139747ad9175SDavid du Colombier int r, timeo;
139847ad9175SDavid du Colombier
139947ad9175SDavid du Colombier /*
140047ad9175SDavid du Colombier * Perform a device reset to get the chip back to the
140147ad9175SDavid du Colombier * power-on state, followed by an EEPROM reset to read
140247ad9175SDavid du Colombier * the defaults for some internal registers.
140347ad9175SDavid du Colombier */
140447ad9175SDavid du Colombier csr32w(ctlr, Imc, ~0);
140547ad9175SDavid du Colombier csr32w(ctlr, Rctl, 0);
140647ad9175SDavid du Colombier csr32w(ctlr, Tctl, 0);
140747ad9175SDavid du Colombier
140847ad9175SDavid du Colombier delay(10);
140947ad9175SDavid du Colombier
141037a6523bSDavid du Colombier r = csr32r(ctlr, Ctrl);
14119b7bf7dfSDavid du Colombier if(ctlr->type == i82566 || ctlr->type == i82567 || ctlr->type == i82579)
141237a6523bSDavid du Colombier r |= Phyrst;
141337a6523bSDavid du Colombier csr32w(ctlr, Ctrl, Devrst | r);
141447ad9175SDavid du Colombier delay(1);
141547ad9175SDavid du Colombier for(timeo = 0; timeo < 1000; timeo++){
141647ad9175SDavid du Colombier if(!(csr32r(ctlr, Ctrl) & Devrst))
141747ad9175SDavid du Colombier break;
141847ad9175SDavid du Colombier delay(1);
141947ad9175SDavid du Colombier }
142047ad9175SDavid du Colombier if(csr32r(ctlr, Ctrl) & Devrst)
142147ad9175SDavid du Colombier return -1;
142237a6523bSDavid du Colombier
142347ad9175SDavid du Colombier r = csr32r(ctlr, Ctrlext);
142447ad9175SDavid du Colombier csr32w(ctlr, Ctrlext, r|Eerst);
142547ad9175SDavid du Colombier delay(1);
142647ad9175SDavid du Colombier for(timeo = 0; timeo < 1000; timeo++){
142747ad9175SDavid du Colombier if(!(csr32r(ctlr, Ctrlext) & Eerst))
142847ad9175SDavid du Colombier break;
142947ad9175SDavid du Colombier delay(1);
143047ad9175SDavid du Colombier }
143147ad9175SDavid du Colombier if(csr32r(ctlr, Ctrlext) & Eerst)
143247ad9175SDavid du Colombier return -1;
143347ad9175SDavid du Colombier
143447ad9175SDavid du Colombier csr32w(ctlr, Imc, ~0);
143547ad9175SDavid du Colombier delay(1);
143647ad9175SDavid du Colombier for(timeo = 0; timeo < 1000; timeo++){
143747ad9175SDavid du Colombier if(!csr32r(ctlr, Icr))
143847ad9175SDavid du Colombier break;
143947ad9175SDavid du Colombier delay(1);
144047ad9175SDavid du Colombier }
144147ad9175SDavid du Colombier if(csr32r(ctlr, Icr))
144247ad9175SDavid du Colombier return -1;
144347ad9175SDavid du Colombier
144408cb4641SDavid du Colombier /*
144508cb4641SDavid du Colombier * Balance Rx/Tx packet buffer.
144608cb4641SDavid du Colombier * No need to set PBA register unless using jumbo, defaults to 32KB
144708cb4641SDavid du Colombier * for receive. If it is changed, then have to do a MAC reset,
144808cb4641SDavid du Colombier * and need to do that at the the right time as it will wipe stuff.
144908cb4641SDavid du Colombier */
145008cb4641SDavid du Colombier if(ctlr->rbsz > 8192 && (ctlr->type == i82563 || ctlr->type == i82571 ||
145108cb4641SDavid du Colombier ctlr->type == i82572)){
145208cb4641SDavid du Colombier ctlr->pba = csr32r(ctlr, Pba);
145308cb4641SDavid du Colombier r = ctlr->pba >> 16;
145408cb4641SDavid du Colombier r += ctlr->pba & 0xffff;
145508cb4641SDavid du Colombier r >>= 1;
145608cb4641SDavid du Colombier csr32w(ctlr, Pba, r);
1457a587111cSDavid du Colombier } else if(ctlr->type == i82573 && ctlr->rbsz > ETHERMAXTU)
145808cb4641SDavid du Colombier csr32w(ctlr, Pba, 14);
145908cb4641SDavid du Colombier ctlr->pba = csr32r(ctlr, Pba);
146008cb4641SDavid du Colombier
146108cb4641SDavid du Colombier r = csr32r(ctlr, Ctrl);
146208cb4641SDavid du Colombier csr32w(ctlr, Ctrl, Slu|r);
146308cb4641SDavid du Colombier
146447ad9175SDavid du Colombier return 0;
146547ad9175SDavid du Colombier }
146647ad9175SDavid du Colombier
14678ccc32efSDavid du Colombier static int
i82563detach(Ctlr * ctlr)14688ccc32efSDavid du Colombier i82563detach(Ctlr* ctlr)
14698ccc32efSDavid du Colombier {
14708ccc32efSDavid du Colombier int r;
14718ccc32efSDavid du Colombier static Lock detlck;
14728ccc32efSDavid du Colombier
14738ccc32efSDavid du Colombier ilock(&detlck);
14748ccc32efSDavid du Colombier r = i82563detach0(ctlr);
14758ccc32efSDavid du Colombier iunlock(&detlck);
14768ccc32efSDavid du Colombier return r;
14778ccc32efSDavid du Colombier }
14788ccc32efSDavid du Colombier
147947ad9175SDavid du Colombier static void
i82563shutdown(Ether * ether)148047ad9175SDavid du Colombier i82563shutdown(Ether* ether)
148147ad9175SDavid du Colombier {
148247ad9175SDavid du Colombier i82563detach(ether->ctlr);
148347ad9175SDavid du Colombier }
148447ad9175SDavid du Colombier
148547ad9175SDavid du Colombier static ushort
eeread(Ctlr * ctlr,int adr)148647ad9175SDavid du Colombier eeread(Ctlr *ctlr, int adr)
148747ad9175SDavid du Colombier {
14888ccc32efSDavid du Colombier ulong n;
14898ccc32efSDavid du Colombier
14900343ea0dSDavid du Colombier csr32w(ctlr, Eerd, EEstart | adr << 2);
14918ccc32efSDavid du Colombier for (n = 1000000; (csr32r(ctlr, Eerd) & EEdone) == 0 && n-- > 0; )
149247ad9175SDavid du Colombier ;
14938ccc32efSDavid du Colombier if (n == 0)
14948ccc32efSDavid du Colombier panic("i82563: eeread stuck");
149547ad9175SDavid du Colombier return csr32r(ctlr, Eerd) >> 16;
149647ad9175SDavid du Colombier }
149747ad9175SDavid du Colombier
149847ad9175SDavid du Colombier static int
eeload(Ctlr * ctlr)149947ad9175SDavid du Colombier eeload(Ctlr *ctlr)
150047ad9175SDavid du Colombier {
150147ad9175SDavid du Colombier ushort sum;
150247ad9175SDavid du Colombier int data, adr;
150347ad9175SDavid du Colombier
150447ad9175SDavid du Colombier sum = 0;
150547ad9175SDavid du Colombier for (adr = 0; adr < 0x40; adr++) {
150647ad9175SDavid du Colombier data = eeread(ctlr, adr);
150747ad9175SDavid du Colombier ctlr->eeprom[adr] = data;
150847ad9175SDavid du Colombier sum += data;
150947ad9175SDavid du Colombier }
151047ad9175SDavid du Colombier return sum;
151147ad9175SDavid du Colombier }
151247ad9175SDavid du Colombier
151347ad9175SDavid du Colombier static int
fcycle(Ctlr *,Flash * f)151491b330d9SDavid du Colombier fcycle(Ctlr *, Flash *f)
151591b330d9SDavid du Colombier {
151691b330d9SDavid du Colombier ushort s, i;
151791b330d9SDavid du Colombier
151891b330d9SDavid du Colombier s = f->reg[Fsts];
151991b330d9SDavid du Colombier if((s&Fvalid) == 0)
152091b330d9SDavid du Colombier return -1;
152191b330d9SDavid du Colombier f->reg[Fsts] |= Fcerr | Ael;
152291b330d9SDavid du Colombier for(i = 0; i < 10; i++){
152391b330d9SDavid du Colombier if((s&Scip) == 0)
152491b330d9SDavid du Colombier return 0;
152591b330d9SDavid du Colombier delay(1);
152691b330d9SDavid du Colombier s = f->reg[Fsts];
152791b330d9SDavid du Colombier }
152891b330d9SDavid du Colombier return -1;
152991b330d9SDavid du Colombier }
153091b330d9SDavid du Colombier
153191b330d9SDavid du Colombier static int
fread(Ctlr * ctlr,Flash * f,int ladr)1532217e9e83SDavid du Colombier fread(Ctlr *ctlr, Flash *f, int ladr)
153391b330d9SDavid du Colombier {
153491b330d9SDavid du Colombier ushort s;
15358ccc32efSDavid du Colombier ulong n;
153691b330d9SDavid du Colombier
153791b330d9SDavid du Colombier delay(1);
1538217e9e83SDavid du Colombier if(fcycle(ctlr, f) == -1)
153991b330d9SDavid du Colombier return -1;
154091b330d9SDavid du Colombier f->reg[Fsts] |= Fdone;
154191b330d9SDavid du Colombier f->reg32[Faddr] = ladr;
154291b330d9SDavid du Colombier
154391b330d9SDavid du Colombier /* setup flash control register */
154491b330d9SDavid du Colombier s = f->reg[Fctl];
154591b330d9SDavid du Colombier s &= ~(0x1f << 8);
154691b330d9SDavid du Colombier s |= (2-1) << 8; /* 2 bytes */
154791b330d9SDavid du Colombier s &= ~(2*Flcycle); /* read */
154891b330d9SDavid du Colombier f->reg[Fctl] = s | Fgo;
154991b330d9SDavid du Colombier
15508ccc32efSDavid du Colombier for (n = 1000000; (f->reg[Fsts] & Fdone) == 0 && n-- > 0; )
155191b330d9SDavid du Colombier ;
15528ccc32efSDavid du Colombier if (n == 0)
15538ccc32efSDavid du Colombier panic("i82563: fread stuck");
155491b330d9SDavid du Colombier if(f->reg[Fsts] & (Fcerr|Ael))
155591b330d9SDavid du Colombier return -1;
155691b330d9SDavid du Colombier return f->reg32[Fdata] & 0xffff;
155791b330d9SDavid du Colombier }
155891b330d9SDavid du Colombier
155991b330d9SDavid du Colombier static int
fload(Ctlr * ctlr)1560217e9e83SDavid du Colombier fload(Ctlr *ctlr)
156191b330d9SDavid du Colombier {
156291b330d9SDavid du Colombier ulong data, io, r, adr;
156391b330d9SDavid du Colombier ushort sum;
156491b330d9SDavid du Colombier Flash f;
156591b330d9SDavid du Colombier
1566217e9e83SDavid du Colombier io = ctlr->pcidev->mem[1].bar & ~0x0f;
1567217e9e83SDavid du Colombier f.reg = vmap(io, ctlr->pcidev->mem[1].size);
156891b330d9SDavid du Colombier if(f.reg == nil)
156991b330d9SDavid du Colombier return -1;
157008cb4641SDavid du Colombier f.reg32 = (void*)f.reg;
15718c242bd4SDavid du Colombier f.base = f.reg32[Bfpr] & FMASK(0, 13);
15728c242bd4SDavid du Colombier f.lim = (f.reg32[Bfpr]>>16) & FMASK(0, 13);
1573217e9e83SDavid du Colombier if(csr32r(ctlr, Eec) & (1<<22))
15748c242bd4SDavid du Colombier f.base += (f.lim + 1 - f.base) >> 1;
15758c242bd4SDavid du Colombier r = f.base << 12;
157691b330d9SDavid du Colombier
157791b330d9SDavid du Colombier sum = 0;
157891b330d9SDavid du Colombier for (adr = 0; adr < 0x40; adr++) {
1579217e9e83SDavid du Colombier data = fread(ctlr, &f, r + adr*2);
158091b330d9SDavid du Colombier if(data == -1)
158191b330d9SDavid du Colombier break;
1582217e9e83SDavid du Colombier ctlr->eeprom[adr] = data;
158391b330d9SDavid du Colombier sum += data;
158491b330d9SDavid du Colombier }
1585217e9e83SDavid du Colombier vunmap(f.reg, ctlr->pcidev->mem[1].size);
158691b330d9SDavid du Colombier return sum;
158791b330d9SDavid du Colombier }
158891b330d9SDavid du Colombier
158991b330d9SDavid du Colombier static int
i82563reset(Ctlr * ctlr)159047ad9175SDavid du Colombier i82563reset(Ctlr *ctlr)
159147ad9175SDavid du Colombier {
159247ad9175SDavid du Colombier int i, r;
159347ad9175SDavid du Colombier
159447ad9175SDavid du Colombier if(i82563detach(ctlr))
159547ad9175SDavid du Colombier return -1;
15969b7bf7dfSDavid du Colombier if(ctlr->type == i82566 || ctlr->type == i82567 ||
15979b7bf7dfSDavid du Colombier ctlr->type == i82577 || ctlr->type == i82579)
159891b330d9SDavid du Colombier r = fload(ctlr);
159991b330d9SDavid du Colombier else
160047ad9175SDavid du Colombier r = eeload(ctlr);
160147ad9175SDavid du Colombier if (r != 0 && r != 0xBABA){
160291b330d9SDavid du Colombier print("%s: bad EEPROM checksum - %#.4ux\n",
160391b330d9SDavid du Colombier tname[ctlr->type], r);
160447ad9175SDavid du Colombier return -1;
160547ad9175SDavid du Colombier }
160647ad9175SDavid du Colombier
160731748cd5SDavid du Colombier for(i = 0; i < Eaddrlen/2; i++){
160831748cd5SDavid du Colombier ctlr->ra[2*i] = ctlr->eeprom[Ea+i];
160931748cd5SDavid du Colombier ctlr->ra[2*i+1] = ctlr->eeprom[Ea+i] >> 8;
161047ad9175SDavid du Colombier }
161122f9ff60SDavid du Colombier r = (csr32r(ctlr, Status) & Lanid) >> 2;
161222f9ff60SDavid du Colombier ctlr->ra[5] += r; /* ea ctlr[1] = ea ctlr[0]+1 */
161322f9ff60SDavid du Colombier
161437a6523bSDavid du Colombier r = ctlr->ra[3]<<24 | ctlr->ra[2]<<16 | ctlr->ra[1]<<8 | ctlr->ra[0];
161547ad9175SDavid du Colombier csr32w(ctlr, Ral, r);
161637a6523bSDavid du Colombier r = 0x80000000 | ctlr->ra[5]<<8 | ctlr->ra[4];
161747ad9175SDavid du Colombier csr32w(ctlr, Rah, r);
161847ad9175SDavid du Colombier for(i = 1; i < 16; i++){
161947ad9175SDavid du Colombier csr32w(ctlr, Ral+i*8, 0);
162047ad9175SDavid du Colombier csr32w(ctlr, Rah+i*8, 0);
162147ad9175SDavid du Colombier }
162247ad9175SDavid du Colombier memset(ctlr->mta, 0, sizeof(ctlr->mta));
162347ad9175SDavid du Colombier for(i = 0; i < 128; i++)
162447ad9175SDavid du Colombier csr32w(ctlr, Mta + i*4, 0);
162508cb4641SDavid du Colombier
162608cb4641SDavid du Colombier /*
162708cb4641SDavid du Colombier * Does autonegotiation affect this manual setting?
162808cb4641SDavid du Colombier * The correct values here should depend on the PBA value
162908cb4641SDavid du Colombier * and maximum frame length, no?
163008cb4641SDavid du Colombier * ctlr->fcrt[lh] are never set, so default to 0.
163108cb4641SDavid du Colombier */
163247ad9175SDavid du Colombier csr32w(ctlr, Fcal, 0x00C28001);
163337a6523bSDavid du Colombier csr32w(ctlr, Fcah, 0x0100);
16349b7bf7dfSDavid du Colombier if(ctlr->type != i82579)
163537a6523bSDavid du Colombier csr32w(ctlr, Fct, 0x8808);
163637a6523bSDavid du Colombier csr32w(ctlr, Fcttv, 0x0100);
163708cb4641SDavid du Colombier
163846136019SDavid du Colombier ctlr->fcrtl = ctlr->fcrth = 0;
163946136019SDavid du Colombier // ctlr->fcrtl = 0x00002000;
164046136019SDavid du Colombier // ctlr->fcrth = 0x00004000;
164147ad9175SDavid du Colombier csr32w(ctlr, Fcrtl, ctlr->fcrtl);
164247ad9175SDavid du Colombier csr32w(ctlr, Fcrth, ctlr->fcrth);
164337a6523bSDavid du Colombier
164447ad9175SDavid du Colombier return 0;
164547ad9175SDavid du Colombier }
164647ad9175SDavid du Colombier
164747ad9175SDavid du Colombier static void
i82563pci(void)164847ad9175SDavid du Colombier i82563pci(void)
164947ad9175SDavid du Colombier {
16500343ea0dSDavid du Colombier int type;
165147ad9175SDavid du Colombier ulong io;
165247ad9175SDavid du Colombier void *mem;
165337a6523bSDavid du Colombier Pcidev *p;
165437a6523bSDavid du Colombier Ctlr *ctlr;
165547ad9175SDavid du Colombier
165647ad9175SDavid du Colombier p = nil;
165737a6523bSDavid du Colombier while(p = pcimatch(p, 0x8086, 0)){
165837a6523bSDavid du Colombier switch(p->did){
165937a6523bSDavid du Colombier default:
166047ad9175SDavid du Colombier continue;
166137a6523bSDavid du Colombier case 0x1096:
166237a6523bSDavid du Colombier case 0x10ba:
166337a6523bSDavid du Colombier type = i82563;
166437a6523bSDavid du Colombier break;
166537a6523bSDavid du Colombier case 0x1049: /* mm */
166637a6523bSDavid du Colombier case 0x104a: /* dm */
1667f881a1ebSDavid du Colombier case 0x104b: /* dc */
1668f881a1ebSDavid du Colombier case 0x104d: /* mc */
166931748cd5SDavid du Colombier case 0x10bd: /* dm */
1670f881a1ebSDavid du Colombier case 0x294c: /* dc-2 */
167137a6523bSDavid du Colombier type = i82566;
167237a6523bSDavid du Colombier break;
1673e4ac449cSDavid du Colombier case 0x10cd: /* lf */
1674f881a1ebSDavid du Colombier case 0x10ce: /* v-2 */
1675f881a1ebSDavid du Colombier case 0x10de: /* lm-3 */
1676f881a1ebSDavid du Colombier case 0x10f5: /* lm-2 */
1677e4ac449cSDavid du Colombier type = i82567;
1678e4ac449cSDavid du Colombier break;
167937a6523bSDavid du Colombier case 0x10a4:
168037a6523bSDavid du Colombier case 0x105e:
168137a6523bSDavid du Colombier type = i82571;
168237a6523bSDavid du Colombier break;
16834faf3cb1SDavid du Colombier case 0x107d: /* eb copper */
16844faf3cb1SDavid du Colombier case 0x107e: /* ei fiber */
16854faf3cb1SDavid du Colombier case 0x107f: /* ei */
1686f881a1ebSDavid du Colombier case 0x10b9: /* sic, 82572gi */
168737a6523bSDavid du Colombier type = i82572;
168837a6523bSDavid du Colombier break;
1689f881a1ebSDavid du Colombier case 0x108b: /* v */
169037a6523bSDavid du Colombier case 0x108c: /* e (iamt) */
169137a6523bSDavid du Colombier case 0x109a: /* l */
169237a6523bSDavid du Colombier type = i82573;
169337a6523bSDavid du Colombier break;
169488bfb1f3SDavid du Colombier case 0x10d3: /* l */
169588bfb1f3SDavid du Colombier type = i82574;
169688bfb1f3SDavid du Colombier break;
16976f746b77SDavid du Colombier case 0x10a7: /* 82575eb: one of a pair of controllers */
169808cb4641SDavid du Colombier type = i82575;
169908cb4641SDavid du Colombier break;
1700c39c2eb3SDavid du Colombier case 0x10c9: /* 82576 copper */
1701c39c2eb3SDavid du Colombier case 0x10e6: /* 82576 fiber */
1702c39c2eb3SDavid du Colombier case 0x10e7: /* 82576 serdes */
1703c39c2eb3SDavid du Colombier type = i82576;
1704c39c2eb3SDavid du Colombier break;
1705d8cd2beaSDavid du Colombier case 0x10ea: /* 82577lm */
1706d8cd2beaSDavid du Colombier type = i82577;
1707d8cd2beaSDavid du Colombier break;
17089b7bf7dfSDavid du Colombier case 0x1502: /* 82579lm */
17099b7bf7dfSDavid du Colombier case 0x1503: /* 82579v */
17109b7bf7dfSDavid du Colombier type = i82579;
17119b7bf7dfSDavid du Colombier break;
171237a6523bSDavid du Colombier }
171347ad9175SDavid du Colombier
171447ad9175SDavid du Colombier io = p->mem[0].bar & ~0x0F;
171547ad9175SDavid du Colombier mem = vmap(io, p->mem[0].size);
171647ad9175SDavid du Colombier if(mem == nil){
171731748cd5SDavid du Colombier print("%s: can't map %.8lux\n", tname[type], io);
171847ad9175SDavid du Colombier continue;
171947ad9175SDavid du Colombier }
172047ad9175SDavid du Colombier ctlr = malloc(sizeof(Ctlr));
1721aa72973aSDavid du Colombier if(ctlr == nil) {
1722aa72973aSDavid du Colombier vunmap(mem, p->mem[0].size);
1723aa72973aSDavid du Colombier error(Enomem);
1724aa72973aSDavid du Colombier }
172547ad9175SDavid du Colombier ctlr->port = io;
172647ad9175SDavid du Colombier ctlr->pcidev = p;
172737a6523bSDavid du Colombier ctlr->type = type;
1728a587111cSDavid du Colombier /*
1729a587111cSDavid du Colombier * on the assumption that allowing jumbo packets makes
1730a587111cSDavid du Colombier * the controller much slower (as is true of the 82579),
1731a587111cSDavid du Colombier * never allow jumbos.
1732a587111cSDavid du Colombier */
1733a587111cSDavid du Colombier // ctlr->rbsz = rbtab[type];
1734a587111cSDavid du Colombier ctlr->rbsz = ETHERMAXTU;
173547ad9175SDavid du Colombier ctlr->nic = mem;
173647ad9175SDavid du Colombier
173747ad9175SDavid du Colombier if(i82563reset(ctlr)){
173831748cd5SDavid du Colombier vunmap(mem, p->mem[0].size);
173947ad9175SDavid du Colombier free(ctlr);
174047ad9175SDavid du Colombier continue;
174147ad9175SDavid du Colombier }
174247ad9175SDavid du Colombier pcisetbme(p);
174347ad9175SDavid du Colombier
174447ad9175SDavid du Colombier if(i82563ctlrhead != nil)
174547ad9175SDavid du Colombier i82563ctlrtail->next = ctlr;
174647ad9175SDavid du Colombier else
174747ad9175SDavid du Colombier i82563ctlrhead = ctlr;
174847ad9175SDavid du Colombier i82563ctlrtail = ctlr;
174947ad9175SDavid du Colombier }
175047ad9175SDavid du Colombier }
175147ad9175SDavid du Colombier
175247ad9175SDavid du Colombier static int
pnp(Ether * edev,int type)175337a6523bSDavid du Colombier pnp(Ether* edev, int type)
175447ad9175SDavid du Colombier {
175547ad9175SDavid du Colombier Ctlr *ctlr;
175691b330d9SDavid du Colombier static int done;
175747ad9175SDavid du Colombier
175891b330d9SDavid du Colombier if(!done) {
175947ad9175SDavid du Colombier i82563pci();
176091b330d9SDavid du Colombier done = 1;
176191b330d9SDavid du Colombier }
176247ad9175SDavid du Colombier
176347ad9175SDavid du Colombier /*
176447ad9175SDavid du Colombier * Any adapter matches if no edev->port is supplied,
176547ad9175SDavid du Colombier * otherwise the ports must match.
176647ad9175SDavid du Colombier */
176737a6523bSDavid du Colombier for(ctlr = i82563ctlrhead; ctlr != nil; ctlr = ctlr->next){
176847ad9175SDavid du Colombier if(ctlr->active)
176947ad9175SDavid du Colombier continue;
177091b330d9SDavid du Colombier if(type != Iany && ctlr->type != type)
177137a6523bSDavid du Colombier continue;
177237a6523bSDavid du Colombier if(edev->port == 0 || edev->port == ctlr->port){
177347ad9175SDavid du Colombier ctlr->active = 1;
177447ad9175SDavid du Colombier break;
177547ad9175SDavid du Colombier }
177637a6523bSDavid du Colombier }
177747ad9175SDavid du Colombier if(ctlr == nil)
177847ad9175SDavid du Colombier return -1;
177947ad9175SDavid du Colombier
178047ad9175SDavid du Colombier edev->ctlr = ctlr;
17816f746b77SDavid du Colombier ctlr->edev = edev; /* point back to Ether* */
178247ad9175SDavid du Colombier edev->port = ctlr->port;
178347ad9175SDavid du Colombier edev->irq = ctlr->pcidev->intl;
178447ad9175SDavid du Colombier edev->tbdf = ctlr->pcidev->tbdf;
178547ad9175SDavid du Colombier edev->mbps = 1000;
178637a6523bSDavid du Colombier edev->maxmtu = ctlr->rbsz;
178747ad9175SDavid du Colombier memmove(edev->ea, ctlr->ra, Eaddrlen);
178847ad9175SDavid du Colombier
178947ad9175SDavid du Colombier /*
179047ad9175SDavid du Colombier * Linkage to the generic ethernet driver.
179147ad9175SDavid du Colombier */
179247ad9175SDavid du Colombier edev->attach = i82563attach;
179347ad9175SDavid du Colombier edev->transmit = i82563transmit;
17946f746b77SDavid du Colombier edev->interrupt = (ctlr->type == i82575?
17956f746b77SDavid du Colombier i82575interrupt: i82563interrupt);
179647ad9175SDavid du Colombier edev->ifstat = i82563ifstat;
179747ad9175SDavid du Colombier edev->ctl = i82563ctl;
179847ad9175SDavid du Colombier
179947ad9175SDavid du Colombier edev->arg = edev;
180047ad9175SDavid du Colombier edev->promiscuous = i82563promiscuous;
180147ad9175SDavid du Colombier edev->shutdown = i82563shutdown;
180247ad9175SDavid du Colombier edev->multicast = i82563multicast;
180347ad9175SDavid du Colombier
180447ad9175SDavid du Colombier return 0;
180547ad9175SDavid du Colombier }
180647ad9175SDavid du Colombier
180737a6523bSDavid du Colombier static int
anypnp(Ether * e)180837a6523bSDavid du Colombier anypnp(Ether *e)
180937a6523bSDavid du Colombier {
181091b330d9SDavid du Colombier return pnp(e, Iany);
181137a6523bSDavid du Colombier }
181237a6523bSDavid du Colombier
181337a6523bSDavid du Colombier static int
i82563pnp(Ether * e)181437a6523bSDavid du Colombier i82563pnp(Ether *e)
181537a6523bSDavid du Colombier {
181637a6523bSDavid du Colombier return pnp(e, i82563);
181737a6523bSDavid du Colombier }
181837a6523bSDavid du Colombier
181937a6523bSDavid du Colombier static int
i82566pnp(Ether * e)182037a6523bSDavid du Colombier i82566pnp(Ether *e)
182137a6523bSDavid du Colombier {
182237a6523bSDavid du Colombier return pnp(e, i82566);
182337a6523bSDavid du Colombier }
182437a6523bSDavid du Colombier
182537a6523bSDavid du Colombier static int
i82571pnp(Ether * e)182637a6523bSDavid du Colombier i82571pnp(Ether *e)
182737a6523bSDavid du Colombier {
182837a6523bSDavid du Colombier return pnp(e, i82571);
182937a6523bSDavid du Colombier }
183037a6523bSDavid du Colombier
183137a6523bSDavid du Colombier static int
i82572pnp(Ether * e)183237a6523bSDavid du Colombier i82572pnp(Ether *e)
183337a6523bSDavid du Colombier {
183437a6523bSDavid du Colombier return pnp(e, i82572);
183537a6523bSDavid du Colombier }
183637a6523bSDavid du Colombier
183737a6523bSDavid du Colombier static int
i82573pnp(Ether * e)183837a6523bSDavid du Colombier i82573pnp(Ether *e)
183937a6523bSDavid du Colombier {
184037a6523bSDavid du Colombier return pnp(e, i82573);
184137a6523bSDavid du Colombier }
184237a6523bSDavid du Colombier
184308cb4641SDavid du Colombier static int
i82575pnp(Ether * e)184408cb4641SDavid du Colombier i82575pnp(Ether *e)
184508cb4641SDavid du Colombier {
184608cb4641SDavid du Colombier return pnp(e, i82575);
184708cb4641SDavid du Colombier }
184808cb4641SDavid du Colombier
18499b7bf7dfSDavid du Colombier static int
i82579pnp(Ether * e)18509b7bf7dfSDavid du Colombier i82579pnp(Ether *e)
18519b7bf7dfSDavid du Colombier {
18529b7bf7dfSDavid du Colombier return pnp(e, i82579);
18539b7bf7dfSDavid du Colombier }
18549b7bf7dfSDavid du Colombier
185547ad9175SDavid du Colombier void
ether82563link(void)185647ad9175SDavid du Colombier ether82563link(void)
185747ad9175SDavid du Colombier {
185837a6523bSDavid du Colombier /* recognise lots of model numbers for debugging assistance */
185947ad9175SDavid du Colombier addethercard("i82563", i82563pnp);
186037a6523bSDavid du Colombier addethercard("i82566", i82566pnp);
186137a6523bSDavid du Colombier addethercard("i82571", i82571pnp);
186237a6523bSDavid du Colombier addethercard("i82572", i82572pnp);
186337a6523bSDavid du Colombier addethercard("i82573", i82573pnp);
186408cb4641SDavid du Colombier addethercard("i82575", i82575pnp);
18659b7bf7dfSDavid du Colombier addethercard("i82579", i82579pnp);
18660343ea0dSDavid du Colombier addethercard("igbepcie", anypnp);
186747ad9175SDavid du Colombier }
1868