180ee5cbfSDavid du Colombier /*
280ee5cbfSDavid du Colombier * Intel RS-82543GC Gigabit Ethernet Controller
380ee5cbfSDavid du Colombier * as found on the Intel PRO/1000[FT] Server Adapter.
480ee5cbfSDavid du Colombier * The older non-[FT] cards use the 82542 (LSI L2A1157) chip; no attempt
580ee5cbfSDavid du Colombier * is made to handle the older chip although it should be possible.
680ee5cbfSDavid du Colombier * The datasheet is not very clear about running on a big-endian system
780ee5cbfSDavid du Colombier * and this driver assumes little-endian throughout.
880ee5cbfSDavid du Colombier * To do:
980ee5cbfSDavid du Colombier * GMII/MII
1080ee5cbfSDavid du Colombier * receive tuning
1180ee5cbfSDavid du Colombier * transmit tuning
1280ee5cbfSDavid du Colombier */
1380ee5cbfSDavid du Colombier #include "u.h"
1480ee5cbfSDavid du Colombier #include "../port/lib.h"
1580ee5cbfSDavid du Colombier #include "mem.h"
1680ee5cbfSDavid du Colombier #include "dat.h"
1780ee5cbfSDavid du Colombier #include "fns.h"
1880ee5cbfSDavid du Colombier #include "io.h"
1980ee5cbfSDavid du Colombier #include "../port/error.h"
2080ee5cbfSDavid du Colombier #include "../port/netif.h"
2180ee5cbfSDavid du Colombier
2280ee5cbfSDavid du Colombier #include "etherif.h"
2380ee5cbfSDavid du Colombier
2480ee5cbfSDavid du Colombier enum {
2580ee5cbfSDavid du Colombier Ctrl = 0x00000000, /* Device Control */
2680ee5cbfSDavid du Colombier Status = 0x00000008, /* Device Status */
2780ee5cbfSDavid du Colombier Eecd = 0x00000010, /* EEPROM/Flash Control/Data */
2880ee5cbfSDavid du Colombier Ctrlext = 0x00000018, /* Extended Device Control */
2980ee5cbfSDavid du Colombier Mdic = 0x00000020, /* MDI Control */
3080ee5cbfSDavid du Colombier Fcal = 0x00000028, /* Flow Control Address Low */
3180ee5cbfSDavid du Colombier Fcah = 0x0000002C, /* Flow Control Address High */
3280ee5cbfSDavid du Colombier Fct = 0x00000030, /* Flow Control Type */
3380ee5cbfSDavid du Colombier Icr = 0x000000C0, /* Interrupt Cause Read */
3480ee5cbfSDavid du Colombier Ics = 0x000000C8, /* Interrupt Cause Set */
3580ee5cbfSDavid du Colombier Ims = 0x000000D0, /* Interrupt Mask Set/Read */
3680ee5cbfSDavid du Colombier Imc = 0x000000D8, /* Interrupt mask Clear */
3780ee5cbfSDavid du Colombier Rctl = 0x00000100, /* Receive Control */
3880ee5cbfSDavid du Colombier Fcttv = 0x00000170, /* Flow Control Transmit Timer Value */
393ff48bf5SDavid du Colombier Txcw = 0x00000178, /* Transmit configuration word reg. */
403ff48bf5SDavid du Colombier Rxcw = 0x00000180, /* Receive configuration word reg. */
4180ee5cbfSDavid du Colombier Tctl = 0x00000400, /* Transmit Control */
4280ee5cbfSDavid du Colombier Tipg = 0x00000410, /* Transmit IPG */
4380ee5cbfSDavid du Colombier Tbt = 0x00000448, /* Transmit Burst Timer */
4480ee5cbfSDavid du Colombier Ait = 0x00000458, /* Adaptive IFS Throttle */
4580ee5cbfSDavid du Colombier Fcrtl = 0x00002160, /* Flow Control RX Threshold Low */
4680ee5cbfSDavid du Colombier Fcrth = 0x00002168, /* Flow Control Rx Threshold High */
473ff48bf5SDavid du Colombier Rdfh = 0x00002410, /* Receive data fifo head */
483ff48bf5SDavid du Colombier Rdft = 0x00002418, /* Receive data fifo tail */
493ff48bf5SDavid du Colombier Rdfhs = 0x00002420, /* Receive data fifo head saved */
503ff48bf5SDavid du Colombier Rdfts = 0x00002428, /* Receive data fifo tail saved */
513ff48bf5SDavid du Colombier Rdfpc = 0x00002430, /* Receive data fifo packet count */
5280ee5cbfSDavid du Colombier Rdbal = 0x00002800, /* Rdesc Base Address Low */
5380ee5cbfSDavid du Colombier Rdbah = 0x00002804, /* Rdesc Base Address High */
5480ee5cbfSDavid du Colombier Rdlen = 0x00002808, /* Receive Descriptor Length */
5580ee5cbfSDavid du Colombier Rdh = 0x00002810, /* Receive Descriptor Head */
5680ee5cbfSDavid du Colombier Rdt = 0x00002818, /* Receive Descriptor Tail */
5780ee5cbfSDavid du Colombier Rdtr = 0x00002820, /* Receive Descriptor Timer Ring */
5880ee5cbfSDavid du Colombier Rxdctl = 0x00002828, /* Receive Descriptor Control */
5980ee5cbfSDavid du Colombier Txdmac = 0x00003000, /* Transfer DMA Control */
6080ee5cbfSDavid du Colombier Ett = 0x00003008, /* Early Transmit Control */
613ff48bf5SDavid du Colombier Tdfh = 0x00003410, /* Transmit data fifo head */
623ff48bf5SDavid du Colombier Tdft = 0x00003418, /* Transmit data fifo tail */
633ff48bf5SDavid du Colombier Tdfhs = 0x00003420, /* Transmit data Fifo Head saved */
643ff48bf5SDavid du Colombier Tdfts = 0x00003428, /* Transmit data fifo tail saved */
653ff48bf5SDavid du Colombier Tdfpc = 0x00003430, /* Trasnmit data Fifo packet count */
6680ee5cbfSDavid du Colombier Tdbal = 0x00003800, /* Tdesc Base Address Low */
6780ee5cbfSDavid du Colombier Tdbah = 0x00003804, /* Tdesc Base Address High */
6880ee5cbfSDavid du Colombier Tdlen = 0x00003808, /* Transmit Descriptor Length */
6980ee5cbfSDavid du Colombier Tdh = 0x00003810, /* Transmit Descriptor Head */
7080ee5cbfSDavid du Colombier Tdt = 0x00003818, /* Transmit Descriptor Tail */
7180ee5cbfSDavid du Colombier Tidv = 0x00003820, /* Transmit Interrupt Delay Value */
7280ee5cbfSDavid du Colombier Txdctl = 0x00003828, /* Transmit Descriptor Control */
7380ee5cbfSDavid du Colombier
7480ee5cbfSDavid du Colombier Statistics = 0x00004000, /* Start of Statistics Area */
7580ee5cbfSDavid du Colombier Gorcl = 0x88/4, /* Good Octets Received Count */
7680ee5cbfSDavid du Colombier Gotcl = 0x90/4, /* Good Octets Transmitted Count */
7780ee5cbfSDavid du Colombier Torl = 0xC0/4, /* Total Octets Received */
7880ee5cbfSDavid du Colombier Totl = 0xC8/4, /* Total Octets Transmitted */
7980ee5cbfSDavid du Colombier Nstatistics = 64,
8080ee5cbfSDavid du Colombier
8180ee5cbfSDavid du Colombier Rxcsum = 0x00005000, /* Receive Checksum Control */
8280ee5cbfSDavid du Colombier Mta = 0x00005200, /* Multicast Table Array */
8380ee5cbfSDavid du Colombier Ral = 0x00005400, /* Receive Address Low */
8480ee5cbfSDavid du Colombier Rah = 0x00005404, /* Receive Address High */
8580ee5cbfSDavid du Colombier };
8680ee5cbfSDavid du Colombier
8780ee5cbfSDavid du Colombier enum { /* Ctrl */
8880ee5cbfSDavid du Colombier Bem = 0x00000002, /* Big Endian Mode */
8980ee5cbfSDavid du Colombier Prior = 0x00000004, /* Priority on the PCI bus */
9080ee5cbfSDavid du Colombier Lrst = 0x00000008, /* Link Reset */
9180ee5cbfSDavid du Colombier Asde = 0x00000020, /* Auto-Speed Detection Enable */
9280ee5cbfSDavid du Colombier Slu = 0x00000040, /* Set Link Up */
9380ee5cbfSDavid du Colombier Ilos = 0x00000080, /* Invert Loss of Signal (LOS) */
9480ee5cbfSDavid du Colombier Frcspd = 0x00000800, /* Force Speed */
9580ee5cbfSDavid du Colombier Frcdplx = 0x00001000, /* Force Duplex */
9680ee5cbfSDavid du Colombier Swdpinslo = 0x003C0000, /* Software Defined Pins - lo nibble */
973ff48bf5SDavid du Colombier Swdpin0 = 0x00040000,
983ff48bf5SDavid du Colombier Swdpin1 = 0x00080000,
993ff48bf5SDavid du Colombier Swdpin2 = 0x00100000,
1003ff48bf5SDavid du Colombier Swdpin3 = 0x00200000,
1013ff48bf5SDavid du Colombier Swdpiolo = 0x03C00000, /* Software Defined I/O Pins */
1023ff48bf5SDavid du Colombier Swdpio0 = 0x00400000,
1033ff48bf5SDavid du Colombier Swdpio1 = 0x00800000,
1043ff48bf5SDavid du Colombier Swdpio2 = 0x01000000,
1053ff48bf5SDavid du Colombier Swdpio3 = 0x02000000,
10680ee5cbfSDavid du Colombier Devrst = 0x04000000, /* Device Reset */
10780ee5cbfSDavid du Colombier Rfce = 0x08000000, /* Receive Flow Control Enable */
10880ee5cbfSDavid du Colombier Tfce = 0x10000000, /* Transmit Flow Control Enable */
10980ee5cbfSDavid du Colombier Vme = 0x40000000, /* VLAN Mode Enable */
11080ee5cbfSDavid du Colombier };
11180ee5cbfSDavid du Colombier
11280ee5cbfSDavid du Colombier enum { /* Status */
11380ee5cbfSDavid du Colombier Lu = 0x00000002, /* Link Up */
11480ee5cbfSDavid du Colombier Tckok = 0x00000004, /* Transmit clock is running */
11580ee5cbfSDavid du Colombier Rbcok = 0x00000008, /* Receive clock is running */
11680ee5cbfSDavid du Colombier Txoff = 0x00000010, /* Transmission Paused */
11780ee5cbfSDavid du Colombier Tbimode = 0x00000020, /* TBI Mode Indication */
11880ee5cbfSDavid du Colombier SpeedMASK = 0x000000C0,
11980ee5cbfSDavid du Colombier Speed10 = 0x00000000, /* 10Mb/s */
12080ee5cbfSDavid du Colombier Speed100 = 0x00000040, /* 100Mb/s */
12180ee5cbfSDavid du Colombier Speed1000 = 0x00000080, /* 1000Mb/s */
12280ee5cbfSDavid du Colombier Mtxckok = 0x00000400, /* MTX clock is running */
12380ee5cbfSDavid du Colombier Pci66 = 0x00000800, /* PCI Bus speed indication */
12480ee5cbfSDavid du Colombier Bus64 = 0x00001000, /* PCI Bus width indication */
12580ee5cbfSDavid du Colombier };
12680ee5cbfSDavid du Colombier
12780ee5cbfSDavid du Colombier enum { /* Ctrl and Status */
12880ee5cbfSDavid du Colombier Fd = 0x00000001, /* Full-Duplex */
12980ee5cbfSDavid du Colombier AsdvMASK = 0x00000300,
13080ee5cbfSDavid du Colombier Asdv10 = 0x00000000, /* 10Mb/s */
13180ee5cbfSDavid du Colombier Asdv100 = 0x00000100, /* 100Mb/s */
13280ee5cbfSDavid du Colombier Asdv1000 = 0x00000200, /* 1000Mb/s */
13380ee5cbfSDavid du Colombier };
13480ee5cbfSDavid du Colombier
13580ee5cbfSDavid du Colombier enum { /* Eecd */
13680ee5cbfSDavid du Colombier Sk = 0x00000001, /* Clock input to the EEPROM */
13780ee5cbfSDavid du Colombier Cs = 0x00000002, /* Chip Select */
13880ee5cbfSDavid du Colombier Di = 0x00000004, /* Data Input to the EEPROM */
13980ee5cbfSDavid du Colombier Do = 0x00000008, /* Data Output from the EEPROM */
14080ee5cbfSDavid du Colombier };
14180ee5cbfSDavid du Colombier
14280ee5cbfSDavid du Colombier enum { /* Ctrlext */
14380ee5cbfSDavid du Colombier Gpien = 0x0000000F, /* General Purpose Interrupt Enables */
14480ee5cbfSDavid du Colombier Swdpinshi = 0x000000F0, /* Software Defined Pins - hi nibble */
14580ee5cbfSDavid du Colombier Swdpiohi = 0x00000F00, /* Software Defined Pins - I or O */
14680ee5cbfSDavid du Colombier Asdchk = 0x00001000, /* ASD Check */
14780ee5cbfSDavid du Colombier Eerst = 0x00002000, /* EEPROM Reset */
14880ee5cbfSDavid du Colombier Ips = 0x00004000, /* Invert Power State */
14980ee5cbfSDavid du Colombier Spdbyps = 0x00008000, /* Speed Select Bypass */
15080ee5cbfSDavid du Colombier };
15180ee5cbfSDavid du Colombier
1523ff48bf5SDavid du Colombier enum { /* EEPROM content offsets */
1533ff48bf5SDavid du Colombier Ea = 0x00, /* Ethernet Address */
1543ff48bf5SDavid du Colombier Cf = 0x03, /* Compatibility Field */
1553ff48bf5SDavid du Colombier Pba = 0x08, /* Printed Board Assembly number */
1563ff48bf5SDavid du Colombier Icw1 = 0x0A, /* Initialization Control Word 1 */
1573ff48bf5SDavid du Colombier Sid = 0x0B, /* Subsystem ID */
1583ff48bf5SDavid du Colombier Svid = 0x0C, /* Subsystem Vendor ID */
1593ff48bf5SDavid du Colombier Did = 0x0D, /* Device ID */
1603ff48bf5SDavid du Colombier Vid = 0x0E, /* Vendor ID */
1613ff48bf5SDavid du Colombier Icw2 = 0x0F, /* Initialization Control Word 2 */
1623ff48bf5SDavid du Colombier };
1633ff48bf5SDavid du Colombier
16480ee5cbfSDavid du Colombier enum { /* Mdic */
16580ee5cbfSDavid du Colombier MDIdMASK = 0x0000FFFF, /* Data */
16680ee5cbfSDavid du Colombier MDIdSHIFT = 0,
16780ee5cbfSDavid du Colombier MDIrMASK = 0x001F0000, /* PHY Register Address */
16880ee5cbfSDavid du Colombier MDIrSHIFT = 16,
16980ee5cbfSDavid du Colombier MDIpMASK = 0x03E00000, /* PHY Address */
17080ee5cbfSDavid du Colombier MDIpSHIFT = 21,
17180ee5cbfSDavid du Colombier MDIwop = 0x04000000, /* Write Operation */
17280ee5cbfSDavid du Colombier MDIrop = 0x08000000, /* Read Operation */
17380ee5cbfSDavid du Colombier MDIready = 0x10000000, /* End of Transaction */
17480ee5cbfSDavid du Colombier MDIie = 0x20000000, /* Interrupt Enable */
17580ee5cbfSDavid du Colombier MDIe = 0x40000000, /* Error */
17680ee5cbfSDavid du Colombier };
17780ee5cbfSDavid du Colombier
17880ee5cbfSDavid du Colombier enum { /* Icr, Ics, Ims, Imc */
17980ee5cbfSDavid du Colombier Txdw = 0x00000001, /* Transmit Descriptor Written Back */
18080ee5cbfSDavid du Colombier Txqe = 0x00000002, /* Transmit Queue Empty */
18180ee5cbfSDavid du Colombier Lsc = 0x00000004, /* Link Status Change */
18280ee5cbfSDavid du Colombier Rxseq = 0x00000008, /* Receive Sequence Error */
18380ee5cbfSDavid du Colombier Rxdmt0 = 0x00000010, /* Rdesc Minimum Threshold Reached */
18480ee5cbfSDavid du Colombier Rxo = 0x00000040, /* Receiver Overrun */
18580ee5cbfSDavid du Colombier Rxt0 = 0x00000080, /* Receiver Timer Interrupt */
18680ee5cbfSDavid du Colombier Mdac = 0x00000200, /* MDIO Access Completed */
18780ee5cbfSDavid du Colombier Rxcfg = 0x00000400, /* Receiving /C/ ordered sets */
18880ee5cbfSDavid du Colombier Gpi0 = 0x00000800, /* General Purpose Interrupts */
18980ee5cbfSDavid du Colombier Gpi1 = 0x00001000,
19080ee5cbfSDavid du Colombier Gpi2 = 0x00002000,
19180ee5cbfSDavid du Colombier Gpi3 = 0x00004000,
19280ee5cbfSDavid du Colombier };
19380ee5cbfSDavid du Colombier
1943ff48bf5SDavid du Colombier enum { /* Txcw */
1953ff48bf5SDavid du Colombier Ane = 0x80000000, /* Autonegotiate enable */
1963ff48bf5SDavid du Colombier Np = 0x00008000, /* Next Page */
1973ff48bf5SDavid du Colombier As = 0x00000100, /* Asymmetric Flow control desired */
1983ff48bf5SDavid du Colombier Ps = 0x00000080, /* Pause supported */
1993ff48bf5SDavid du Colombier Hd = 0x00000040, /* Half duplex supported */
2003ff48bf5SDavid du Colombier TxcwFd = 0x00000020, /* Full Duplex supported */
2013ff48bf5SDavid du Colombier };
2023ff48bf5SDavid du Colombier
2033ff48bf5SDavid du Colombier enum { /* Rxcw */
2043ff48bf5SDavid du Colombier Rxword = 0x0000FFFF, /* Data from auto-negotiation process */
2053ff48bf5SDavid du Colombier Rxnocarrier = 0x04000000, /* Carrier Sense indication */
2063ff48bf5SDavid du Colombier Rxinvalid = 0x08000000, /* Invalid Symbol during configuration */
2073ff48bf5SDavid du Colombier Rxchange = 0x10000000, /* Change to the Rxword indication */
2083ff48bf5SDavid du Colombier Rxconfig = 0x20000000, /* /C/ order set reception indication */
2093ff48bf5SDavid du Colombier Rxsync = 0x40000000, /* Lost bit synchronization indication */
2103ff48bf5SDavid du Colombier Anc = 0x80000000, /* Auto Negotiation Complete */
2113ff48bf5SDavid du Colombier };
2123ff48bf5SDavid du Colombier
21380ee5cbfSDavid du Colombier enum { /* Rctl */
21480ee5cbfSDavid du Colombier Rrst = 0x00000001, /* Receiver Software Reset */
21580ee5cbfSDavid du Colombier Ren = 0x00000002, /* Receiver Enable */
21680ee5cbfSDavid du Colombier Sbp = 0x00000004, /* Store Bad Packets */
21780ee5cbfSDavid du Colombier Upe = 0x00000008, /* Unicast Promiscuous Enable */
21880ee5cbfSDavid du Colombier Mpe = 0x00000010, /* Multicast Promiscuous Enable */
21980ee5cbfSDavid du Colombier Lpe = 0x00000020, /* Long Packet Reception Enable */
22080ee5cbfSDavid du Colombier LbmMASK = 0x000000C0, /* Loopback Mode */
22180ee5cbfSDavid du Colombier LbmOFF = 0x00000000, /* No Loopback */
22280ee5cbfSDavid du Colombier LbmTBI = 0x00000040, /* TBI Loopback */
22380ee5cbfSDavid du Colombier LbmMII = 0x00000080, /* GMII/MII Loopback */
22480ee5cbfSDavid du Colombier LbmXCVR = 0x000000C0, /* Transceiver Loopback */
22580ee5cbfSDavid du Colombier RdtmsMASK = 0x00000300, /* Rdesc Minimum Threshold Size */
22680ee5cbfSDavid du Colombier RdtmsHALF = 0x00000000, /* Threshold is 1/2 Rdlen */
22780ee5cbfSDavid du Colombier RdtmsQUARTER = 0x00000100, /* Threshold is 1/4 Rdlen */
22880ee5cbfSDavid du Colombier RdtmsEIGHTH = 0x00000200, /* Threshold is 1/8 Rdlen */
22980ee5cbfSDavid du Colombier MoMASK = 0x00003000, /* Multicast Offset */
23080ee5cbfSDavid du Colombier Bam = 0x00008000, /* Broadcast Accept Mode */
23180ee5cbfSDavid du Colombier BsizeMASK = 0x00030000, /* Receive Buffer Size */
2323ff48bf5SDavid du Colombier Bsize2048 = 0x00000000, /* Bsex = 0 */
2333ff48bf5SDavid du Colombier Bsize1024 = 0x00010000, /* Bsex = 0 */
2343ff48bf5SDavid du Colombier Bsize512 = 0x00020000, /* Bsex = 0 */
2353ff48bf5SDavid du Colombier Bsize256 = 0x00030000, /* Bsex = 0 */
2363ff48bf5SDavid du Colombier Bsize16384 = 0x00010000, /* Bsex = 1 */
23780ee5cbfSDavid du Colombier Vfe = 0x00040000, /* VLAN Filter Enable */
23880ee5cbfSDavid du Colombier Cfien = 0x00080000, /* Canonical Form Indicator Enable */
23980ee5cbfSDavid du Colombier Cfi = 0x00100000, /* Canonical Form Indicator value */
24080ee5cbfSDavid du Colombier Dpf = 0x00400000, /* Discard Pause Frames */
24180ee5cbfSDavid du Colombier Pmcf = 0x00800000, /* Pass MAC Control Frames */
24280ee5cbfSDavid du Colombier Bsex = 0x02000000, /* Buffer Size Extension */
24380ee5cbfSDavid du Colombier Secrc = 0x04000000, /* Strip CRC from incoming packet */
24480ee5cbfSDavid du Colombier };
24580ee5cbfSDavid du Colombier
24680ee5cbfSDavid du Colombier enum { /* Tctl */
24780ee5cbfSDavid du Colombier Trst = 0x00000001, /* Transmitter Software Reset */
24880ee5cbfSDavid du Colombier Ten = 0x00000002, /* Transmit Enable */
24980ee5cbfSDavid du Colombier Psp = 0x00000008, /* Pad Short Packets */
25080ee5cbfSDavid du Colombier CtMASK = 0x00000FF0, /* Collision Threshold */
25180ee5cbfSDavid du Colombier CtSHIFT = 4,
25280ee5cbfSDavid du Colombier ColdMASK = 0x003FF000, /* Collision Distance */
25380ee5cbfSDavid du Colombier ColdSHIFT = 12,
25480ee5cbfSDavid du Colombier Swxoff = 0x00400000, /* Sofware XOFF Transmission */
25580ee5cbfSDavid du Colombier Pbe = 0x00800000, /* Packet Burst Enable */
25680ee5cbfSDavid du Colombier Rtlc = 0x01000000, /* Re-transmit on Late Collision */
25780ee5cbfSDavid du Colombier Nrtu = 0x02000000, /* No Re-transmit on Underrrun */
25880ee5cbfSDavid du Colombier };
25980ee5cbfSDavid du Colombier
26080ee5cbfSDavid du Colombier enum { /* [RT]xdctl */
26180ee5cbfSDavid du Colombier PthreshMASK = 0x0000003F, /* Prefetch Threshold */
26280ee5cbfSDavid du Colombier PthreshSHIFT = 0,
26380ee5cbfSDavid du Colombier HthreshMASK = 0x00003F00, /* Host Threshold */
26480ee5cbfSDavid du Colombier HthreshSHIFT = 8,
2653ff48bf5SDavid du Colombier WthreshMASK = 0x003F0000, /* Writeback Threshold */
26680ee5cbfSDavid du Colombier WthreshSHIFT = 16,
2673ff48bf5SDavid du Colombier Gran = 0x00000000, /* Granularity */
2683ff48bf5SDavid du Colombier RxGran = 0x01000000, /* Granularity */
26980ee5cbfSDavid du Colombier };
27080ee5cbfSDavid du Colombier
27180ee5cbfSDavid du Colombier enum { /* Rxcsum */
27280ee5cbfSDavid du Colombier PcssMASK = 0x000000FF, /* Packet Checksum Start */
27380ee5cbfSDavid du Colombier PcssSHIFT = 0,
27480ee5cbfSDavid du Colombier Ipofl = 0x00000100, /* IP Checksum Off-load Enable */
27580ee5cbfSDavid du Colombier Tuofl = 0x00000200, /* TCP/UDP Checksum Off-load Enable */
27680ee5cbfSDavid du Colombier };
27780ee5cbfSDavid du Colombier
2783ff48bf5SDavid du Colombier enum { /* Receive Delay Timer Ring */
2793ff48bf5SDavid du Colombier Fpd = 0x80000000, /* Flush partial Descriptor Block */
2803ff48bf5SDavid du Colombier };
2813ff48bf5SDavid du Colombier
28280ee5cbfSDavid du Colombier typedef struct Rdesc { /* Receive Descriptor */
28380ee5cbfSDavid du Colombier uint addr[2];
28480ee5cbfSDavid du Colombier ushort length;
28580ee5cbfSDavid du Colombier ushort checksum;
28680ee5cbfSDavid du Colombier uchar status;
28780ee5cbfSDavid du Colombier uchar errors;
28880ee5cbfSDavid du Colombier ushort special;
28980ee5cbfSDavid du Colombier } Rdesc;
29080ee5cbfSDavid du Colombier
29180ee5cbfSDavid du Colombier enum { /* Rdesc status */
29280ee5cbfSDavid du Colombier Rdd = 0x01, /* Descriptor Done */
29380ee5cbfSDavid du Colombier Reop = 0x02, /* End of Packet */
29480ee5cbfSDavid du Colombier Ixsm = 0x04, /* Ignore Checksum Indication */
29580ee5cbfSDavid du Colombier Vp = 0x08, /* Packet is 802.1Q (matched VET) */
29680ee5cbfSDavid du Colombier Tcpcs = 0x20, /* TCP Checksum Calculated on Packet */
29780ee5cbfSDavid du Colombier Ipcs = 0x40, /* IP Checksum Calculated on Packet */
29880ee5cbfSDavid du Colombier Pif = 0x80, /* Passed in-exact filter */
29980ee5cbfSDavid du Colombier };
30080ee5cbfSDavid du Colombier
30180ee5cbfSDavid du Colombier enum { /* Rdesc errors */
30280ee5cbfSDavid du Colombier Ce = 0x01, /* CRC Error or Alignment Error */
30380ee5cbfSDavid du Colombier Se = 0x02, /* Symbol Error */
30480ee5cbfSDavid du Colombier Seq = 0x04, /* Sequence Error */
30580ee5cbfSDavid du Colombier Cxe = 0x10, /* Carrier Extension Error */
30680ee5cbfSDavid du Colombier Tcpe = 0x20, /* TCP/UDP Checksum Error */
30780ee5cbfSDavid du Colombier Ipe = 0x40, /* IP Checksum Error */
30880ee5cbfSDavid du Colombier Rxe = 0x80, /* RX Data Error */
30980ee5cbfSDavid du Colombier };
31080ee5cbfSDavid du Colombier
31180ee5cbfSDavid du Colombier typedef struct Tdesc { /* Legacy+Normal Transmit Descriptor */
31280ee5cbfSDavid du Colombier uint addr[2];
31380ee5cbfSDavid du Colombier uint control; /* varies with descriptor type */
31480ee5cbfSDavid du Colombier uint status; /* varies with descriptor type */
31580ee5cbfSDavid du Colombier } Tdesc;
31680ee5cbfSDavid du Colombier
31780ee5cbfSDavid du Colombier enum { /* Tdesc control */
31880ee5cbfSDavid du Colombier CsoMASK = 0x00000F00, /* Checksum Offset */
31980ee5cbfSDavid du Colombier CsoSHIFT = 16,
32080ee5cbfSDavid du Colombier Teop = 0x01000000, /* End of Packet */
32180ee5cbfSDavid du Colombier Ifcs = 0x02000000, /* Insert FCS */
32280ee5cbfSDavid du Colombier Ic = 0x04000000, /* Insert Checksum (Dext == 0) */
32380ee5cbfSDavid du Colombier Tse = 0x04000000, /* TCP Segmentaion Enable (Dext == 1) */
32480ee5cbfSDavid du Colombier Rs = 0x08000000, /* Report Status */
32580ee5cbfSDavid du Colombier Rps = 0x10000000, /* Report Status Sent */
32680ee5cbfSDavid du Colombier Dext = 0x20000000, /* Extension (!legacy) */
32780ee5cbfSDavid du Colombier Vle = 0x40000000, /* VLAN Packet Enable */
32880ee5cbfSDavid du Colombier Ide = 0x80000000, /* Interrupt Delay Enable */
32980ee5cbfSDavid du Colombier };
33080ee5cbfSDavid du Colombier
33180ee5cbfSDavid du Colombier enum { /* Tdesc status */
33280ee5cbfSDavid du Colombier Tdd = 0x00000001, /* Descriptor Done */
33380ee5cbfSDavid du Colombier Ec = 0x00000002, /* Excess Collisions */
33480ee5cbfSDavid du Colombier Lc = 0x00000004, /* Late Collision */
33580ee5cbfSDavid du Colombier Tu = 0x00000008, /* Transmit Underrun */
33680ee5cbfSDavid du Colombier CssMASK = 0x0000FF00, /* Checksum Start Field */
33780ee5cbfSDavid du Colombier CssSHIFT = 8,
33880ee5cbfSDavid du Colombier };
33980ee5cbfSDavid du Colombier
34080ee5cbfSDavid du Colombier enum {
3413ff48bf5SDavid du Colombier Nrdesc = 256, /* multiple of 8 */
3426520663fSDavid du Colombier Ntdesc = 64, /* multiple of 8 */
3433ff48bf5SDavid du Colombier Nblocks = 4098, /* total number of blocks to use */
3443ff48bf5SDavid du Colombier
3453ff48bf5SDavid du Colombier SBLOCKSIZE = 2048,
3463ff48bf5SDavid du Colombier JBLOCKSIZE = 16384,
3473ff48bf5SDavid du Colombier
3483ff48bf5SDavid du Colombier NORMAL = 1,
3493ff48bf5SDavid du Colombier JUMBO = 2,
35080ee5cbfSDavid du Colombier };
35180ee5cbfSDavid du Colombier
35280ee5cbfSDavid du Colombier typedef struct Ctlr Ctlr;
35380ee5cbfSDavid du Colombier typedef struct Ctlr {
35480ee5cbfSDavid du Colombier int port;
35580ee5cbfSDavid du Colombier Pcidev* pcidev;
35680ee5cbfSDavid du Colombier Ctlr* next;
35780ee5cbfSDavid du Colombier int active;
3583ff48bf5SDavid du Colombier int started;
35980ee5cbfSDavid du Colombier int id;
36080ee5cbfSDavid du Colombier ushort eeprom[0x40];
36180ee5cbfSDavid du Colombier
36280ee5cbfSDavid du Colombier int* nic;
36380ee5cbfSDavid du Colombier int im; /* interrupt mask */
36480ee5cbfSDavid du Colombier
36580ee5cbfSDavid du Colombier Lock slock;
36680ee5cbfSDavid du Colombier uint statistics[Nstatistics];
36780ee5cbfSDavid du Colombier
3683ff48bf5SDavid du Colombier Lock rdlock;
36980ee5cbfSDavid du Colombier Rdesc* rdba; /* receive descriptor base address */
3703ff48bf5SDavid du Colombier Block* rb[Nrdesc]; /* receive buffers */
37180ee5cbfSDavid du Colombier int rdh; /* receive descriptor head */
37280ee5cbfSDavid du Colombier int rdt; /* receive descriptor tail */
3733ff48bf5SDavid du Colombier Block** freehead; /* points to long or short head */
37480ee5cbfSDavid du Colombier
37580ee5cbfSDavid du Colombier Lock tdlock;
3763ff48bf5SDavid du Colombier Tdesc* tdba; /* transmit descriptor base address */
3773ff48bf5SDavid du Colombier Block* tb[Ntdesc]; /* transmit buffers */
37880ee5cbfSDavid du Colombier int tdh; /* transmit descriptor head */
37980ee5cbfSDavid du Colombier int tdt; /* transmit descriptor tail */
3803ff48bf5SDavid du Colombier int txstalled; /* count of times unable to send */
3813ff48bf5SDavid du Colombier
3823ff48bf5SDavid du Colombier int txcw;
3833ff48bf5SDavid du Colombier int fcrtl;
3843ff48bf5SDavid du Colombier int fcrth;
3853ff48bf5SDavid du Colombier
3863ff48bf5SDavid du Colombier ulong multimask[128]; /* bit mask for multicast addresses */
38780ee5cbfSDavid du Colombier } Ctlr;
38880ee5cbfSDavid du Colombier
3893ff48bf5SDavid du Colombier static Ctlr* gc82543ctlrhead;
3903ff48bf5SDavid du Colombier static Ctlr* gc82543ctlrtail;
3913ff48bf5SDavid du Colombier
3923ff48bf5SDavid du Colombier static Lock freelistlock;
3933ff48bf5SDavid du Colombier static Block* freeShortHead;
3943ff48bf5SDavid du Colombier static Block* freeJumboHead;
39580ee5cbfSDavid du Colombier
39680ee5cbfSDavid du Colombier #define csr32r(c, r) (*((c)->nic+((r)/4)))
39780ee5cbfSDavid du Colombier #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
39880ee5cbfSDavid du Colombier
3993ff48bf5SDavid du Colombier static void gc82543watchdog(void* arg);
4003ff48bf5SDavid du Colombier
40180ee5cbfSDavid du Colombier static void
gc82543attach(Ether * edev)40280ee5cbfSDavid du Colombier gc82543attach(Ether* edev)
40380ee5cbfSDavid du Colombier {
40480ee5cbfSDavid du Colombier int ctl;
40580ee5cbfSDavid du Colombier Ctlr *ctlr;
4063ff48bf5SDavid du Colombier char name[KNAMELEN];
40780ee5cbfSDavid du Colombier
40880ee5cbfSDavid du Colombier /*
40980ee5cbfSDavid du Colombier * To do here:
41080ee5cbfSDavid du Colombier * one-time stuff;
41180ee5cbfSDavid du Colombier * adjust queue length depending on speed;
41280ee5cbfSDavid du Colombier * flow control.
41380ee5cbfSDavid du Colombier * more needed here...
41480ee5cbfSDavid du Colombier */
41580ee5cbfSDavid du Colombier ctlr = edev->ctlr;
4163ff48bf5SDavid du Colombier lock(&ctlr->slock);
4173ff48bf5SDavid du Colombier if(ctlr->started == 0){
4183ff48bf5SDavid du Colombier ctlr->started = 1;
4193ff48bf5SDavid du Colombier snprint(name, KNAMELEN, "#l%d82543", edev->ctlrno);
4203ff48bf5SDavid du Colombier kproc(name, gc82543watchdog, edev);
4213ff48bf5SDavid du Colombier }
4223ff48bf5SDavid du Colombier unlock(&ctlr->slock);
4233ff48bf5SDavid du Colombier
42480ee5cbfSDavid du Colombier ctl = csr32r(ctlr, Rctl)|Ren;
42580ee5cbfSDavid du Colombier csr32w(ctlr, Rctl, ctl);
42680ee5cbfSDavid du Colombier ctl = csr32r(ctlr, Tctl)|Ten;
42780ee5cbfSDavid du Colombier csr32w(ctlr, Tctl, ctl);
4283ff48bf5SDavid du Colombier
4293ff48bf5SDavid du Colombier csr32w(ctlr, Ims, ctlr->im);
43080ee5cbfSDavid du Colombier }
43180ee5cbfSDavid du Colombier
43280ee5cbfSDavid du Colombier static char* statistics[Nstatistics] = {
43380ee5cbfSDavid du Colombier "CRC Error",
43480ee5cbfSDavid du Colombier "Alignment Error",
43580ee5cbfSDavid du Colombier "Symbol Error",
43680ee5cbfSDavid du Colombier "RX Error",
43780ee5cbfSDavid du Colombier "Missed Packets",
43880ee5cbfSDavid du Colombier "Single Collision",
43980ee5cbfSDavid du Colombier "Excessive Collisions",
44080ee5cbfSDavid du Colombier "Multiple Collision",
44180ee5cbfSDavid du Colombier "Late Collisions",
44280ee5cbfSDavid du Colombier nil,
44380ee5cbfSDavid du Colombier "Collision",
44480ee5cbfSDavid du Colombier "Transmit Underrun",
44580ee5cbfSDavid du Colombier "Defer",
44680ee5cbfSDavid du Colombier "Transmit - No CRS",
44780ee5cbfSDavid du Colombier "Sequence Error",
44880ee5cbfSDavid du Colombier "Carrier Extension Error",
44980ee5cbfSDavid du Colombier "Receive Error Length",
45080ee5cbfSDavid du Colombier nil,
45180ee5cbfSDavid du Colombier "XON Received",
45280ee5cbfSDavid du Colombier "XON Transmitted",
45380ee5cbfSDavid du Colombier "XOFF Received",
45480ee5cbfSDavid du Colombier "XOFF Transmitted",
45580ee5cbfSDavid du Colombier "FC Received Unsupported",
45680ee5cbfSDavid du Colombier "Packets Received (64 Bytes)",
45780ee5cbfSDavid du Colombier "Packets Received (65-127 Bytes)",
45880ee5cbfSDavid du Colombier "Packets Received (128-255 Bytes)",
45980ee5cbfSDavid du Colombier "Packets Received (256-511 Bytes)",
46080ee5cbfSDavid du Colombier "Packets Received (512-1023 Bytes)",
46180ee5cbfSDavid du Colombier "Packets Received (1024-1522 Bytes)",
46280ee5cbfSDavid du Colombier "Good Packets Received",
46380ee5cbfSDavid du Colombier "Broadcast Packets Received",
46480ee5cbfSDavid du Colombier "Multicast Packets Received",
46580ee5cbfSDavid du Colombier "Good Packets Transmitted",
46680ee5cbfSDavid du Colombier nil,
46780ee5cbfSDavid du Colombier "Good Octets Received",
46880ee5cbfSDavid du Colombier nil,
46980ee5cbfSDavid du Colombier "Good Octets Transmitted",
47080ee5cbfSDavid du Colombier nil,
47180ee5cbfSDavid du Colombier nil,
47280ee5cbfSDavid du Colombier nil,
47380ee5cbfSDavid du Colombier "Receive No Buffers",
47480ee5cbfSDavid du Colombier "Receive Undersize",
47580ee5cbfSDavid du Colombier "Receive Fragment",
47680ee5cbfSDavid du Colombier "Receive Oversize",
47780ee5cbfSDavid du Colombier "Receive Jabber",
47880ee5cbfSDavid du Colombier nil,
47980ee5cbfSDavid du Colombier nil,
48080ee5cbfSDavid du Colombier nil,
48180ee5cbfSDavid du Colombier "Total Octets Received",
48280ee5cbfSDavid du Colombier nil,
48380ee5cbfSDavid du Colombier "Total Octets Transmitted",
48480ee5cbfSDavid du Colombier nil,
48580ee5cbfSDavid du Colombier "Total Packets Received",
48680ee5cbfSDavid du Colombier "Total Packets Transmitted",
48780ee5cbfSDavid du Colombier "Packets Transmitted (64 Bytes)",
48880ee5cbfSDavid du Colombier "Packets Transmitted (65-127 Bytes)",
48980ee5cbfSDavid du Colombier "Packets Transmitted (128-255 Bytes)",
49080ee5cbfSDavid du Colombier "Packets Transmitted (256-511 Bytes)",
49180ee5cbfSDavid du Colombier "Packets Transmitted (512-1023 Bytes)",
49280ee5cbfSDavid du Colombier "Packets Transmitted (1024-1522 Bytes)",
49380ee5cbfSDavid du Colombier "Multicast Packets Transmitted",
49480ee5cbfSDavid du Colombier "Broadcast Packets Transmitted",
49580ee5cbfSDavid du Colombier "TCP Segmentation Context Transmitted",
49680ee5cbfSDavid du Colombier "TCP Segmentation Context Fail",
49780ee5cbfSDavid du Colombier };
49880ee5cbfSDavid du Colombier
49980ee5cbfSDavid du Colombier static long
gc82543ifstat(Ether * edev,void * a,long n,ulong offset)50080ee5cbfSDavid du Colombier gc82543ifstat(Ether* edev, void* a, long n, ulong offset)
50180ee5cbfSDavid du Colombier {
50280ee5cbfSDavid du Colombier Ctlr *ctlr;
50380ee5cbfSDavid du Colombier char *p, *s;
50480ee5cbfSDavid du Colombier int i, l, r;
50580ee5cbfSDavid du Colombier uvlong tuvl, ruvl;
50680ee5cbfSDavid du Colombier
50780ee5cbfSDavid du Colombier ctlr = edev->ctlr;
5083ff48bf5SDavid du Colombier lock(&ctlr->slock);
50946136019SDavid du Colombier p = malloc(READSTR);
510aa72973aSDavid du Colombier if(p == nil) {
511aa72973aSDavid du Colombier unlock(&ctlr->slock);
512aa72973aSDavid du Colombier error(Enomem);
513aa72973aSDavid du Colombier }
51480ee5cbfSDavid du Colombier l = 0;
51580ee5cbfSDavid du Colombier for(i = 0; i < Nstatistics; i++){
51680ee5cbfSDavid du Colombier r = csr32r(ctlr, Statistics+i*4);
51780ee5cbfSDavid du Colombier if((s = statistics[i]) == nil)
51880ee5cbfSDavid du Colombier continue;
51980ee5cbfSDavid du Colombier switch(i){
52080ee5cbfSDavid du Colombier case Gorcl:
52180ee5cbfSDavid du Colombier case Gotcl:
52280ee5cbfSDavid du Colombier case Torl:
52380ee5cbfSDavid du Colombier case Totl:
52480ee5cbfSDavid du Colombier ruvl = r;
52580ee5cbfSDavid du Colombier ruvl += ((uvlong)csr32r(ctlr, Statistics+(i+1)*4))<<32;
52680ee5cbfSDavid du Colombier tuvl = ruvl;
52780ee5cbfSDavid du Colombier tuvl += ctlr->statistics[i];
52880ee5cbfSDavid du Colombier tuvl += ((uvlong)ctlr->statistics[i+1])<<32;
52980ee5cbfSDavid du Colombier if(tuvl == 0)
53080ee5cbfSDavid du Colombier continue;
53180ee5cbfSDavid du Colombier ctlr->statistics[i] = tuvl;
53280ee5cbfSDavid du Colombier ctlr->statistics[i+1] = tuvl>>32;
53346136019SDavid du Colombier l += snprint(p+l, READSTR-l, "%s: %llud %llud\n",
53480ee5cbfSDavid du Colombier s, tuvl, ruvl);
53580ee5cbfSDavid du Colombier i++;
53680ee5cbfSDavid du Colombier break;
53780ee5cbfSDavid du Colombier
53880ee5cbfSDavid du Colombier default:
53980ee5cbfSDavid du Colombier ctlr->statistics[i] += r;
54080ee5cbfSDavid du Colombier if(ctlr->statistics[i] == 0)
54180ee5cbfSDavid du Colombier continue;
54246136019SDavid du Colombier l += snprint(p+l, READSTR-l, "%s: %ud %ud\n",
54380ee5cbfSDavid du Colombier s, ctlr->statistics[i], r);
54480ee5cbfSDavid du Colombier break;
54580ee5cbfSDavid du Colombier }
54680ee5cbfSDavid du Colombier }
54780ee5cbfSDavid du Colombier
54846136019SDavid du Colombier l += snprint(p+l, READSTR-l, "eeprom:");
54980ee5cbfSDavid du Colombier for(i = 0; i < 0x40; i++){
55080ee5cbfSDavid du Colombier if(i && ((i & 0x07) == 0))
55146136019SDavid du Colombier l += snprint(p+l, READSTR-l, "\n ");
55246136019SDavid du Colombier l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->eeprom[i]);
55380ee5cbfSDavid du Colombier }
55480ee5cbfSDavid du Colombier
55546136019SDavid du Colombier snprint(p+l, READSTR-l, "\ntxstalled %d\n", ctlr->txstalled);
55680ee5cbfSDavid du Colombier n = readstr(offset, a, n, p);
55780ee5cbfSDavid du Colombier free(p);
5583ff48bf5SDavid du Colombier unlock(&ctlr->slock);
55980ee5cbfSDavid du Colombier
56080ee5cbfSDavid du Colombier return n;
56180ee5cbfSDavid du Colombier }
56280ee5cbfSDavid du Colombier
56380ee5cbfSDavid du Colombier static void
gc82543promiscuous(void * arg,int on)5643ff48bf5SDavid du Colombier gc82543promiscuous(void* arg, int on)
5653ff48bf5SDavid du Colombier {
5663ff48bf5SDavid du Colombier int rctl;
5673ff48bf5SDavid du Colombier Ctlr *ctlr;
5683ff48bf5SDavid du Colombier Ether *edev;
5693ff48bf5SDavid du Colombier
5703ff48bf5SDavid du Colombier edev = arg;
5713ff48bf5SDavid du Colombier ctlr = edev->ctlr;
5723ff48bf5SDavid du Colombier
5733ff48bf5SDavid du Colombier rctl = csr32r(ctlr, Rctl);
5743ff48bf5SDavid du Colombier rctl &= ~MoMASK; /* make sure we're using bits 47:36 */
5753ff48bf5SDavid du Colombier if(on)
5763ff48bf5SDavid du Colombier rctl |= Upe|Mpe;
5773ff48bf5SDavid du Colombier else
5783ff48bf5SDavid du Colombier rctl &= ~(Upe|Mpe);
5793ff48bf5SDavid du Colombier csr32w(ctlr, Rctl, rctl);
5803ff48bf5SDavid du Colombier }
5813ff48bf5SDavid du Colombier
5823ff48bf5SDavid du Colombier static void
gc82543multicast(void * arg,uchar * addr,int on)5833ff48bf5SDavid du Colombier gc82543multicast(void* arg, uchar* addr, int on)
5843ff48bf5SDavid du Colombier {
5853ff48bf5SDavid du Colombier int bit, x;
5863ff48bf5SDavid du Colombier Ctlr *ctlr;
5873ff48bf5SDavid du Colombier Ether *edev;
5883ff48bf5SDavid du Colombier
5893ff48bf5SDavid du Colombier edev = arg;
5903ff48bf5SDavid du Colombier ctlr = edev->ctlr;
5913ff48bf5SDavid du Colombier x = addr[5]>>1;
5923ff48bf5SDavid du Colombier bit = ((addr[5] & 1)<<4)|(addr[4]>>4);
5933ff48bf5SDavid du Colombier if(on)
5943ff48bf5SDavid du Colombier ctlr->multimask[x] |= 1<<bit;
5953ff48bf5SDavid du Colombier else
5963ff48bf5SDavid du Colombier ctlr->multimask[x] &= ~(1<<bit);
5973ff48bf5SDavid du Colombier
5983ff48bf5SDavid du Colombier csr32w(ctlr, Mta+x*4, ctlr->multimask[x]);
5993ff48bf5SDavid du Colombier }
6003ff48bf5SDavid du Colombier
6013ff48bf5SDavid du Colombier static long
gc82543ctl(Ether * edev,void * buf,long n)6023ff48bf5SDavid du Colombier gc82543ctl(Ether* edev, void* buf, long n)
6033ff48bf5SDavid du Colombier {
6043ff48bf5SDavid du Colombier Cmdbuf *cb;
6053ff48bf5SDavid du Colombier Ctlr *ctlr;
6063ff48bf5SDavid du Colombier int ctrl, i, r;
6073ff48bf5SDavid du Colombier
6083ff48bf5SDavid du Colombier ctlr = edev->ctlr;
6093ff48bf5SDavid du Colombier if(ctlr == nil)
6103ff48bf5SDavid du Colombier error(Enonexist);
6113ff48bf5SDavid du Colombier
6123ff48bf5SDavid du Colombier lock(&ctlr->slock);
6133ff48bf5SDavid du Colombier r = 0;
6143ff48bf5SDavid du Colombier cb = parsecmd(buf, n);
6153ff48bf5SDavid du Colombier if(cb->nf < 2)
6163ff48bf5SDavid du Colombier r = -1;
6173ff48bf5SDavid du Colombier else if(cistrcmp(cb->f[0], "auto") == 0){
6183ff48bf5SDavid du Colombier ctrl = csr32r(ctlr, Ctrl);
6193ff48bf5SDavid du Colombier if(cistrcmp(cb->f[1], "off") == 0){
6203ff48bf5SDavid du Colombier csr32w(ctlr, Txcw, ctlr->txcw & ~Ane);
6213ff48bf5SDavid du Colombier ctrl |= (Slu|Fd);
6223ff48bf5SDavid du Colombier if(ctlr->txcw & As)
6233ff48bf5SDavid du Colombier ctrl |= Rfce;
6243ff48bf5SDavid du Colombier if(ctlr->txcw & Ps)
6253ff48bf5SDavid du Colombier ctrl |= Tfce;
6263ff48bf5SDavid du Colombier csr32w(ctlr, Ctrl, ctrl);
6273ff48bf5SDavid du Colombier }
6283ff48bf5SDavid du Colombier else if(cistrcmp(cb->f[1], "on") == 0){
6293ff48bf5SDavid du Colombier csr32w(ctlr, Txcw, ctlr->txcw);
6303ff48bf5SDavid du Colombier ctrl &= ~(Slu|Fd);
6313ff48bf5SDavid du Colombier csr32w(ctlr, Ctrl, ctrl);
6323ff48bf5SDavid du Colombier }
6333ff48bf5SDavid du Colombier else
6343ff48bf5SDavid du Colombier r = -1;
6353ff48bf5SDavid du Colombier }
6363ff48bf5SDavid du Colombier else if(cistrcmp(cb->f[0], "clear") == 0){
6373ff48bf5SDavid du Colombier if(cistrcmp(cb->f[1], "stats") == 0){
6383ff48bf5SDavid du Colombier for(i = 0; i < Nstatistics; i++)
6393ff48bf5SDavid du Colombier ctlr->statistics[i] = 0;
6403ff48bf5SDavid du Colombier }
6413ff48bf5SDavid du Colombier else
6423ff48bf5SDavid du Colombier r = -1;
6433ff48bf5SDavid du Colombier }
6443ff48bf5SDavid du Colombier else
6453ff48bf5SDavid du Colombier r = -1;
6463ff48bf5SDavid du Colombier unlock(&ctlr->slock);
6473ff48bf5SDavid du Colombier
6483ff48bf5SDavid du Colombier free(cb);
6493ff48bf5SDavid du Colombier return (r == 0) ? n : r;
6503ff48bf5SDavid du Colombier }
6513ff48bf5SDavid du Colombier
6523ff48bf5SDavid du Colombier static void
gc82543txinit(Ctlr * ctlr)6533ff48bf5SDavid du Colombier gc82543txinit(Ctlr* ctlr)
6543ff48bf5SDavid du Colombier {
6553ff48bf5SDavid du Colombier int i;
6563ff48bf5SDavid du Colombier int tdsize;
6573ff48bf5SDavid du Colombier Block *bp, **bpp;
6583ff48bf5SDavid du Colombier
6593ff48bf5SDavid du Colombier tdsize = ROUND(Ntdesc*sizeof(Tdesc), 4096);
6603ff48bf5SDavid du Colombier
6613ff48bf5SDavid du Colombier if(ctlr->tdba == nil)
6623ff48bf5SDavid du Colombier ctlr->tdba = xspanalloc(tdsize, 32, 0);
6633ff48bf5SDavid du Colombier
6643ff48bf5SDavid du Colombier for(i = 0; i < Ntdesc; i++){
6653ff48bf5SDavid du Colombier bpp = &ctlr->tb[i];
6663ff48bf5SDavid du Colombier bp = *bpp;
6673ff48bf5SDavid du Colombier if(bp != nil){
6683ff48bf5SDavid du Colombier *bpp = nil;
6693ff48bf5SDavid du Colombier freeb(bp);
6703ff48bf5SDavid du Colombier }
6713ff48bf5SDavid du Colombier memset(&ctlr->tdba[i], 0, sizeof(Tdesc));
6723ff48bf5SDavid du Colombier }
6733ff48bf5SDavid du Colombier
6743ff48bf5SDavid du Colombier csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
6753ff48bf5SDavid du Colombier csr32w(ctlr, Tdbah, 0);
6763ff48bf5SDavid du Colombier csr32w(ctlr, Tdlen, Ntdesc*sizeof(Tdesc));
6773ff48bf5SDavid du Colombier
6783ff48bf5SDavid du Colombier /*
6793ff48bf5SDavid du Colombier * set the ring head and tail pointers.
6803ff48bf5SDavid du Colombier */
6813ff48bf5SDavid du Colombier ctlr->tdh = 0;
6823ff48bf5SDavid du Colombier csr32w(ctlr, Tdh, ctlr->tdh);
6833ff48bf5SDavid du Colombier ctlr->tdt = 0;
6843ff48bf5SDavid du Colombier csr32w(ctlr, Tdt, ctlr->tdt);
6853ff48bf5SDavid du Colombier
6863ff48bf5SDavid du Colombier csr32w(ctlr, Tipg, (6<<20)|(8<<10)|6);
6873ff48bf5SDavid du Colombier csr32w(ctlr, Tidv, 128);
6883ff48bf5SDavid du Colombier csr32w(ctlr, Ait, 0);
6893ff48bf5SDavid du Colombier csr32w(ctlr, Txdmac, 0);
6903ff48bf5SDavid du Colombier csr32w(ctlr, Txdctl, Gran|(4<<WthreshSHIFT)|(1<<HthreshSHIFT)|16);
6913ff48bf5SDavid du Colombier csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(6<<ColdSHIFT));
6923ff48bf5SDavid du Colombier
6933ff48bf5SDavid du Colombier ctlr->im |= Txdw;
6943ff48bf5SDavid du Colombier }
6953ff48bf5SDavid du Colombier
6963ff48bf5SDavid du Colombier static void
gc82543transmit(Ether * edev)69780ee5cbfSDavid du Colombier gc82543transmit(Ether* edev)
69880ee5cbfSDavid du Colombier {
6993ff48bf5SDavid du Colombier Block *bp, **bpp;
70080ee5cbfSDavid du Colombier Ctlr *ctlr;
70180ee5cbfSDavid du Colombier Tdesc *tdesc;
7023ff48bf5SDavid du Colombier int tdh, tdt, s;
70380ee5cbfSDavid du Colombier
70480ee5cbfSDavid du Colombier ctlr = edev->ctlr;
70580ee5cbfSDavid du Colombier
7063ff48bf5SDavid du Colombier ilock(&ctlr->tdlock);
70780ee5cbfSDavid du Colombier tdh = ctlr->tdh;
70880ee5cbfSDavid du Colombier for(;;){
7093ff48bf5SDavid du Colombier /*
7103ff48bf5SDavid du Colombier * Free any completed packets
7113ff48bf5SDavid du Colombier */
71280ee5cbfSDavid du Colombier tdesc = &ctlr->tdba[tdh];
71380ee5cbfSDavid du Colombier if(!(tdesc->status & Tdd))
71480ee5cbfSDavid du Colombier break;
7153ff48bf5SDavid du Colombier memset(tdesc, 0, sizeof(Tdesc));
7163ff48bf5SDavid du Colombier bpp = &ctlr->tb[tdh];
7173ff48bf5SDavid du Colombier bp = *bpp;
7183ff48bf5SDavid du Colombier if(bp != nil){
7193ff48bf5SDavid du Colombier *bpp = nil;
7203ff48bf5SDavid du Colombier freeb(bp);
72180ee5cbfSDavid du Colombier }
72280ee5cbfSDavid du Colombier tdh = NEXT(tdh, Ntdesc);
72380ee5cbfSDavid du Colombier }
72480ee5cbfSDavid du Colombier ctlr->tdh = tdh;
7253ff48bf5SDavid du Colombier s = csr32r(ctlr, Status);
72680ee5cbfSDavid du Colombier
72780ee5cbfSDavid du Colombier /*
7283ff48bf5SDavid du Colombier * Try to fill the ring back up
7293ff48bf5SDavid du Colombier * but only if link is up and transmission isn't paused.
73080ee5cbfSDavid du Colombier */
7313ff48bf5SDavid du Colombier if((s & (Txoff|Lu)) == Lu){
7323ff48bf5SDavid du Colombier tdt = ctlr->tdt;
7333ff48bf5SDavid du Colombier while(NEXT(tdt, Ntdesc) != tdh){
73480ee5cbfSDavid du Colombier if((bp = qget(edev->oq)) == nil)
73580ee5cbfSDavid du Colombier break;
73680ee5cbfSDavid du Colombier
73780ee5cbfSDavid du Colombier tdesc = &ctlr->tdba[tdt];
73880ee5cbfSDavid du Colombier tdesc->addr[0] = PCIWADDR(bp->rp);
73980ee5cbfSDavid du Colombier tdesc->control = Ide|Rs|Ifcs|Teop|BLEN(bp);
74080ee5cbfSDavid du Colombier ctlr->tb[tdt] = bp;
7413ff48bf5SDavid du Colombier tdt = NEXT(tdt, Ntdesc);
74280ee5cbfSDavid du Colombier }
7433ff48bf5SDavid du Colombier
7443ff48bf5SDavid du Colombier if(tdt != ctlr->tdt){
74580ee5cbfSDavid du Colombier ctlr->tdt = tdt;
74680ee5cbfSDavid du Colombier csr32w(ctlr, Tdt, tdt);
7473ff48bf5SDavid du Colombier }
7483ff48bf5SDavid du Colombier }
7493ff48bf5SDavid du Colombier else
7503ff48bf5SDavid du Colombier ctlr->txstalled++;
75180ee5cbfSDavid du Colombier
75280ee5cbfSDavid du Colombier iunlock(&ctlr->tdlock);
75380ee5cbfSDavid du Colombier }
75480ee5cbfSDavid du Colombier
7553ff48bf5SDavid du Colombier static Block *
gc82543allocb(Ctlr * ctlr)7563ff48bf5SDavid du Colombier gc82543allocb(Ctlr* ctlr)
7573ff48bf5SDavid du Colombier {
7583ff48bf5SDavid du Colombier Block *bp;
7593ff48bf5SDavid du Colombier
7603ff48bf5SDavid du Colombier ilock(&freelistlock);
7613ff48bf5SDavid du Colombier if((bp = *(ctlr->freehead)) != nil){
7623ff48bf5SDavid du Colombier *(ctlr->freehead) = bp->next;
7633ff48bf5SDavid du Colombier bp->next = nil;
764b8a11165SDavid du Colombier _xinc(&bp->ref); /* prevent bp from being freed */
7653ff48bf5SDavid du Colombier }
7663ff48bf5SDavid du Colombier iunlock(&freelistlock);
7673ff48bf5SDavid du Colombier return bp;
7683ff48bf5SDavid du Colombier }
7693ff48bf5SDavid du Colombier
77080ee5cbfSDavid du Colombier static void
gc82543replenish(Ctlr * ctlr)77180ee5cbfSDavid du Colombier gc82543replenish(Ctlr* ctlr)
77280ee5cbfSDavid du Colombier {
77380ee5cbfSDavid du Colombier int rdt;
77480ee5cbfSDavid du Colombier Block *bp;
77580ee5cbfSDavid du Colombier Rdesc *rdesc;
77680ee5cbfSDavid du Colombier
7773ff48bf5SDavid du Colombier ilock(&ctlr->rdlock);
77880ee5cbfSDavid du Colombier rdt = ctlr->rdt;
77980ee5cbfSDavid du Colombier while(NEXT(rdt, Nrdesc) != ctlr->rdh){
78080ee5cbfSDavid du Colombier rdesc = &ctlr->rdba[rdt];
7813ff48bf5SDavid du Colombier if(ctlr->rb[rdt] == nil){
7823ff48bf5SDavid du Colombier bp = gc82543allocb(ctlr);
7833ff48bf5SDavid du Colombier if(bp == nil){
7843ff48bf5SDavid du Colombier iprint("no available buffers\n");
7853ff48bf5SDavid du Colombier break;
7869a747e4fSDavid du Colombier }
78780ee5cbfSDavid du Colombier ctlr->rb[rdt] = bp;
78880ee5cbfSDavid du Colombier rdesc->addr[0] = PCIWADDR(bp->rp);
78980ee5cbfSDavid du Colombier rdesc->addr[1] = 0;
79080ee5cbfSDavid du Colombier }
7913ff48bf5SDavid du Colombier coherence();
79280ee5cbfSDavid du Colombier rdesc->status = 0;
79380ee5cbfSDavid du Colombier rdt = NEXT(rdt, Nrdesc);
79480ee5cbfSDavid du Colombier }
79580ee5cbfSDavid du Colombier ctlr->rdt = rdt;
79680ee5cbfSDavid du Colombier csr32w(ctlr, Rdt, rdt);
7973ff48bf5SDavid du Colombier iunlock(&ctlr->rdlock);
7983ff48bf5SDavid du Colombier }
7993ff48bf5SDavid du Colombier
8003ff48bf5SDavid du Colombier static void
gc82543rxinit(Ctlr * ctlr)8013ff48bf5SDavid du Colombier gc82543rxinit(Ctlr* ctlr)
8023ff48bf5SDavid du Colombier {
8033ff48bf5SDavid du Colombier int rdsize, i;
8043ff48bf5SDavid du Colombier
8053ff48bf5SDavid du Colombier csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF);
8063ff48bf5SDavid du Colombier
8073ff48bf5SDavid du Colombier /*
8083ff48bf5SDavid du Colombier * Allocate the descriptor ring and load its
8093ff48bf5SDavid du Colombier * address and length into the NIC.
8103ff48bf5SDavid du Colombier */
8113ff48bf5SDavid du Colombier rdsize = ROUND(Nrdesc*sizeof(Rdesc), 4096);
8123ff48bf5SDavid du Colombier if(ctlr->rdba == nil)
8133ff48bf5SDavid du Colombier ctlr->rdba = xspanalloc(rdsize, 32, 0);
8143ff48bf5SDavid du Colombier memset(ctlr->rdba, 0, rdsize);
8153ff48bf5SDavid du Colombier
8163ff48bf5SDavid du Colombier ctlr->rdh = 0;
8173ff48bf5SDavid du Colombier ctlr->rdt = 0;
8183ff48bf5SDavid du Colombier
8193ff48bf5SDavid du Colombier csr32w(ctlr, Rdtr, Fpd|64);
8203ff48bf5SDavid du Colombier csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));
8213ff48bf5SDavid du Colombier csr32w(ctlr, Rdbah, 0);
8223ff48bf5SDavid du Colombier csr32w(ctlr, Rdlen, Nrdesc*sizeof(Rdesc));
8233ff48bf5SDavid du Colombier csr32w(ctlr, Rdh, 0);
8243ff48bf5SDavid du Colombier csr32w(ctlr, Rdt, 0);
8253ff48bf5SDavid du Colombier for(i = 0; i < Nrdesc; i++){
8263ff48bf5SDavid du Colombier if(ctlr->rb[i] != nil){
8273ff48bf5SDavid du Colombier freeb(ctlr->rb[i]);
8283ff48bf5SDavid du Colombier ctlr->rb[i] = nil;
8293ff48bf5SDavid du Colombier }
8303ff48bf5SDavid du Colombier }
8313ff48bf5SDavid du Colombier gc82543replenish(ctlr);
8323ff48bf5SDavid du Colombier
8333ff48bf5SDavid du Colombier csr32w(ctlr, Rxdctl, RxGran|(8<<WthreshSHIFT)|(4<<HthreshSHIFT)|1);
8343ff48bf5SDavid du Colombier ctlr->im |= Rxt0|Rxo|Rxdmt0|Rxseq;
8353ff48bf5SDavid du Colombier }
8363ff48bf5SDavid du Colombier
8373ff48bf5SDavid du Colombier static void
gc82543recv(Ether * edev,int icr)8383ff48bf5SDavid du Colombier gc82543recv(Ether* edev, int icr)
8393ff48bf5SDavid du Colombier {
8403ff48bf5SDavid du Colombier Block *bp;
8413ff48bf5SDavid du Colombier Ctlr *ctlr;
8423ff48bf5SDavid du Colombier Rdesc *rdesc;
8433ff48bf5SDavid du Colombier int rdh;
8443ff48bf5SDavid du Colombier
8453ff48bf5SDavid du Colombier ctlr = edev->ctlr;
8463ff48bf5SDavid du Colombier
8473ff48bf5SDavid du Colombier rdh = ctlr->rdh;
8483ff48bf5SDavid du Colombier for(;;){
8493ff48bf5SDavid du Colombier rdesc = &ctlr->rdba[rdh];
8503ff48bf5SDavid du Colombier
8513ff48bf5SDavid du Colombier if(!(rdesc->status & Rdd))
8523ff48bf5SDavid du Colombier break;
8533ff48bf5SDavid du Colombier
8543ff48bf5SDavid du Colombier if((rdesc->status & Reop) && rdesc->errors == 0){
8553ff48bf5SDavid du Colombier bp = ctlr->rb[rdh];
8563ff48bf5SDavid du Colombier ctlr->rb[rdh] = nil;
8573ff48bf5SDavid du Colombier bp->wp += rdesc->length;
8583ff48bf5SDavid du Colombier bp->next = nil;
8593ff48bf5SDavid du Colombier etheriq(edev, bp, 1);
8603ff48bf5SDavid du Colombier }
8613ff48bf5SDavid du Colombier
8623ff48bf5SDavid du Colombier if(ctlr->rb[rdh] != nil){
8633ff48bf5SDavid du Colombier /* either non eop packet, or error */
8643ff48bf5SDavid du Colombier freeb(ctlr->rb[rdh]);
8653ff48bf5SDavid du Colombier ctlr->rb[rdh] = nil;
8663ff48bf5SDavid du Colombier }
8673ff48bf5SDavid du Colombier memset(rdesc, 0, sizeof(Rdesc));
8683ff48bf5SDavid du Colombier coherence();
8693ff48bf5SDavid du Colombier rdh = NEXT(rdh, Nrdesc);
8703ff48bf5SDavid du Colombier }
8713ff48bf5SDavid du Colombier ctlr->rdh = rdh;
8723ff48bf5SDavid du Colombier
8733ff48bf5SDavid du Colombier if(icr & Rxdmt0)
8743ff48bf5SDavid du Colombier gc82543replenish(ctlr);
8753ff48bf5SDavid du Colombier }
8763ff48bf5SDavid du Colombier
8773ff48bf5SDavid du Colombier static void
freegc82543short(Block * bp)8783ff48bf5SDavid du Colombier freegc82543short(Block *bp)
8793ff48bf5SDavid du Colombier {
8803ff48bf5SDavid du Colombier ilock(&freelistlock);
8813ff48bf5SDavid du Colombier /* reset read/write pointer to proper positions */
8823ff48bf5SDavid du Colombier bp->rp = bp->lim - ROUND(SBLOCKSIZE, BLOCKALIGN);
8833ff48bf5SDavid du Colombier bp->wp = bp->rp;
8843ff48bf5SDavid du Colombier bp->next = freeShortHead;
8853ff48bf5SDavid du Colombier freeShortHead = bp;
8863ff48bf5SDavid du Colombier iunlock(&freelistlock);
8873ff48bf5SDavid du Colombier }
8883ff48bf5SDavid du Colombier
8893ff48bf5SDavid du Colombier static void
freegc82532jumbo(Block * bp)8903ff48bf5SDavid du Colombier freegc82532jumbo(Block *bp)
8913ff48bf5SDavid du Colombier {
8923ff48bf5SDavid du Colombier ilock(&freelistlock);
8933ff48bf5SDavid du Colombier /* reset read/write pointer to proper positions */
8943ff48bf5SDavid du Colombier bp->rp = bp->lim - ROUND(JBLOCKSIZE, BLOCKALIGN);
8953ff48bf5SDavid du Colombier bp->wp = bp->rp;
8963ff48bf5SDavid du Colombier bp->next = freeJumboHead;
8973ff48bf5SDavid du Colombier freeJumboHead = bp;
8983ff48bf5SDavid du Colombier iunlock(&freelistlock);
8993ff48bf5SDavid du Colombier }
9003ff48bf5SDavid du Colombier
9013ff48bf5SDavid du Colombier static void
linkintr(Ctlr * ctlr)9023ff48bf5SDavid du Colombier linkintr(Ctlr* ctlr)
9033ff48bf5SDavid du Colombier {
9043ff48bf5SDavid du Colombier int ctrl;
9053ff48bf5SDavid du Colombier
9063ff48bf5SDavid du Colombier ctrl = csr32r(ctlr, Ctrl);
9073ff48bf5SDavid du Colombier
9083ff48bf5SDavid du Colombier if((ctrl & Swdpin1) ||
9093ff48bf5SDavid du Colombier ((csr32r(ctlr, Rxcw) & Rxconfig) && !(csr32r(ctlr, Txcw) & Ane))){
9103ff48bf5SDavid du Colombier csr32w(ctlr, Txcw, ctlr->txcw);
9113ff48bf5SDavid du Colombier ctrl &= ~(Slu|Fd|Frcdplx);
9123ff48bf5SDavid du Colombier csr32w(ctlr, Ctrl, ctrl);
9133ff48bf5SDavid du Colombier }
91480ee5cbfSDavid du Colombier }
91580ee5cbfSDavid du Colombier
91680ee5cbfSDavid du Colombier static void
gc82543interrupt(Ureg *,void * arg)91780ee5cbfSDavid du Colombier gc82543interrupt(Ureg*, void* arg)
91880ee5cbfSDavid du Colombier {
91980ee5cbfSDavid du Colombier Ctlr *ctlr;
92080ee5cbfSDavid du Colombier Ether *edev;
9213ff48bf5SDavid du Colombier int icr;
92280ee5cbfSDavid du Colombier
92380ee5cbfSDavid du Colombier edev = arg;
92480ee5cbfSDavid du Colombier ctlr = edev->ctlr;
92580ee5cbfSDavid du Colombier
9263ff48bf5SDavid du Colombier while((icr = csr32r(ctlr, Icr) & ctlr->im) != 0){
92780ee5cbfSDavid du Colombier /*
92880ee5cbfSDavid du Colombier * Link status changed.
92980ee5cbfSDavid du Colombier */
9303ff48bf5SDavid du Colombier if(icr & (Lsc|Rxseq))
9313ff48bf5SDavid du Colombier linkintr(ctlr);
93280ee5cbfSDavid du Colombier
93380ee5cbfSDavid du Colombier /*
9343ff48bf5SDavid du Colombier * Process recv buffers.
93580ee5cbfSDavid du Colombier */
9363ff48bf5SDavid du Colombier gc82543recv(edev, icr);
93780ee5cbfSDavid du Colombier
9383ff48bf5SDavid du Colombier /*
9393ff48bf5SDavid du Colombier * Refill transmit ring and free packets.
9403ff48bf5SDavid du Colombier */
94180ee5cbfSDavid du Colombier gc82543transmit(edev);
94280ee5cbfSDavid du Colombier }
94380ee5cbfSDavid du Colombier }
94480ee5cbfSDavid du Colombier
94580ee5cbfSDavid du Colombier static int
gc82543init(Ether * edev)94680ee5cbfSDavid du Colombier gc82543init(Ether* edev)
94780ee5cbfSDavid du Colombier {
94880ee5cbfSDavid du Colombier int csr, i;
9493ff48bf5SDavid du Colombier Block *bp;
95080ee5cbfSDavid du Colombier Ctlr *ctlr;
9513ff48bf5SDavid du Colombier
95280ee5cbfSDavid du Colombier ctlr = edev->ctlr;
95380ee5cbfSDavid du Colombier
95480ee5cbfSDavid du Colombier /*
9553ff48bf5SDavid du Colombier * Allocate private buffer pool to use for receiving packets.
9563ff48bf5SDavid du Colombier */
9573ff48bf5SDavid du Colombier ilock(&freelistlock);
9583ff48bf5SDavid du Colombier if (ctlr->freehead == nil){
9593ff48bf5SDavid du Colombier for(i = 0; i < Nblocks; i++){
9603ff48bf5SDavid du Colombier bp = iallocb(SBLOCKSIZE);
9613ff48bf5SDavid du Colombier if(bp != nil){
9623ff48bf5SDavid du Colombier bp->next = freeShortHead;
9633ff48bf5SDavid du Colombier bp->free = freegc82543short;
9643ff48bf5SDavid du Colombier freeShortHead = bp;
9653ff48bf5SDavid du Colombier }
9663ff48bf5SDavid du Colombier else{
9673ff48bf5SDavid du Colombier print("82543gc: no memory\n");
9683ff48bf5SDavid du Colombier break;
9693ff48bf5SDavid du Colombier }
9703ff48bf5SDavid du Colombier }
9713ff48bf5SDavid du Colombier ctlr->freehead = &freeShortHead;
9723ff48bf5SDavid du Colombier }
9733ff48bf5SDavid du Colombier iunlock(&freelistlock);
9743ff48bf5SDavid du Colombier
9753ff48bf5SDavid du Colombier /*
97680ee5cbfSDavid du Colombier * Set up the receive addresses.
97780ee5cbfSDavid du Colombier * There are 16 addresses. The first should be the MAC address.
97880ee5cbfSDavid du Colombier * The others are cleared and not marked valid (MS bit of Rah).
97980ee5cbfSDavid du Colombier */
98080ee5cbfSDavid du Colombier csr = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0];
98180ee5cbfSDavid du Colombier csr32w(ctlr, Ral, csr);
98280ee5cbfSDavid du Colombier csr = 0x80000000|(edev->ea[5]<<8)|edev->ea[4];
98380ee5cbfSDavid du Colombier csr32w(ctlr, Rah, csr);
98480ee5cbfSDavid du Colombier for(i = 1; i < 16; i++){
98580ee5cbfSDavid du Colombier csr32w(ctlr, Ral+i*8, 0);
98680ee5cbfSDavid du Colombier csr32w(ctlr, Rah+i*8, 0);
98780ee5cbfSDavid du Colombier }
98880ee5cbfSDavid du Colombier
98980ee5cbfSDavid du Colombier /*
99080ee5cbfSDavid du Colombier * Clear the Multicast Table Array.
99180ee5cbfSDavid du Colombier * It's a 4096 bit vector accessed as 128 32-bit registers.
99280ee5cbfSDavid du Colombier */
99380ee5cbfSDavid du Colombier for(i = 0; i < 128; i++)
99480ee5cbfSDavid du Colombier csr32w(ctlr, Mta+i*4, 0);
99580ee5cbfSDavid du Colombier
9963ff48bf5SDavid du Colombier gc82543txinit(ctlr);
9973ff48bf5SDavid du Colombier gc82543rxinit(ctlr);
99880ee5cbfSDavid du Colombier
99980ee5cbfSDavid du Colombier return 0;
100080ee5cbfSDavid du Colombier }
100180ee5cbfSDavid du Colombier
100280ee5cbfSDavid du Colombier static int
at93c46io(Ctlr * ctlr,char * op,int data)100380ee5cbfSDavid du Colombier at93c46io(Ctlr* ctlr, char* op, int data)
100480ee5cbfSDavid du Colombier {
100580ee5cbfSDavid du Colombier char *lp, *p;
100680ee5cbfSDavid du Colombier int i, loop, eecd, r;
100780ee5cbfSDavid du Colombier
100880ee5cbfSDavid du Colombier eecd = csr32r(ctlr, Eecd);
100980ee5cbfSDavid du Colombier
101080ee5cbfSDavid du Colombier r = 0;
101180ee5cbfSDavid du Colombier loop = -1;
101280ee5cbfSDavid du Colombier lp = nil;
101380ee5cbfSDavid du Colombier for(p = op; *p != '\0'; p++){
101480ee5cbfSDavid du Colombier switch(*p){
101580ee5cbfSDavid du Colombier default:
101680ee5cbfSDavid du Colombier return -1;
101780ee5cbfSDavid du Colombier case ' ':
101880ee5cbfSDavid du Colombier continue;
101980ee5cbfSDavid du Colombier case ':': /* start of loop */
102080ee5cbfSDavid du Colombier if(lp != nil){
102180ee5cbfSDavid du Colombier if(p != (lp+1) || loop != 7)
102280ee5cbfSDavid du Colombier return -1;
102380ee5cbfSDavid du Colombier lp = p;
102480ee5cbfSDavid du Colombier loop = 15;
102580ee5cbfSDavid du Colombier continue;
102680ee5cbfSDavid du Colombier }
102780ee5cbfSDavid du Colombier lp = p;
102880ee5cbfSDavid du Colombier loop = 7;
102980ee5cbfSDavid du Colombier continue;
103080ee5cbfSDavid du Colombier case ';': /* end of loop */
103180ee5cbfSDavid du Colombier if(lp == nil)
103280ee5cbfSDavid du Colombier return -1;
103380ee5cbfSDavid du Colombier loop--;
103480ee5cbfSDavid du Colombier if(loop >= 0)
103580ee5cbfSDavid du Colombier p = lp;
103680ee5cbfSDavid du Colombier else
103780ee5cbfSDavid du Colombier lp = nil;
103880ee5cbfSDavid du Colombier continue;
103980ee5cbfSDavid du Colombier case 'C': /* assert clock */
104080ee5cbfSDavid du Colombier eecd |= Sk;
104180ee5cbfSDavid du Colombier break;
104280ee5cbfSDavid du Colombier case 'c': /* deassert clock */
104380ee5cbfSDavid du Colombier eecd &= ~Sk;
104480ee5cbfSDavid du Colombier break;
104580ee5cbfSDavid du Colombier case 'D': /* next bit in 'data' byte */
104680ee5cbfSDavid du Colombier if(loop < 0)
104780ee5cbfSDavid du Colombier return -1;
104880ee5cbfSDavid du Colombier if(data & (1<<loop))
104980ee5cbfSDavid du Colombier eecd |= Di;
105080ee5cbfSDavid du Colombier else
105180ee5cbfSDavid du Colombier eecd &= ~Di;
105280ee5cbfSDavid du Colombier break;
105380ee5cbfSDavid du Colombier case 'O': /* collect data output */
105480ee5cbfSDavid du Colombier i = (csr32r(ctlr, Eecd) & Do) != 0;
105580ee5cbfSDavid du Colombier if(loop >= 0)
105680ee5cbfSDavid du Colombier r |= (i<<loop);
105780ee5cbfSDavid du Colombier else
105880ee5cbfSDavid du Colombier r = i;
105980ee5cbfSDavid du Colombier continue;
106080ee5cbfSDavid du Colombier case 'I': /* assert data input */
106180ee5cbfSDavid du Colombier eecd |= Di;
106280ee5cbfSDavid du Colombier break;
106380ee5cbfSDavid du Colombier case 'i': /* deassert data input */
106480ee5cbfSDavid du Colombier eecd &= ~Di;
106580ee5cbfSDavid du Colombier break;
106680ee5cbfSDavid du Colombier case 'S': /* enable chip select */
106780ee5cbfSDavid du Colombier eecd |= Cs;
106880ee5cbfSDavid du Colombier break;
106980ee5cbfSDavid du Colombier case 's': /* disable chip select */
107080ee5cbfSDavid du Colombier eecd &= ~Cs;
107180ee5cbfSDavid du Colombier break;
107280ee5cbfSDavid du Colombier }
107380ee5cbfSDavid du Colombier csr32w(ctlr, Eecd, eecd);
107480ee5cbfSDavid du Colombier microdelay(1);
107580ee5cbfSDavid du Colombier }
107680ee5cbfSDavid du Colombier if(loop >= 0)
107780ee5cbfSDavid du Colombier return -1;
107880ee5cbfSDavid du Colombier return r;
107980ee5cbfSDavid du Colombier }
108080ee5cbfSDavid du Colombier
108180ee5cbfSDavid du Colombier static int
at93c46r(Ctlr * ctlr)108280ee5cbfSDavid du Colombier at93c46r(Ctlr* ctlr)
108380ee5cbfSDavid du Colombier {
108480ee5cbfSDavid du Colombier ushort sum;
108580ee5cbfSDavid du Colombier int addr, data;
108680ee5cbfSDavid du Colombier
108780ee5cbfSDavid du Colombier sum = 0;
108880ee5cbfSDavid du Colombier for(addr = 0; addr < 0x40; addr++){
108980ee5cbfSDavid du Colombier /*
109080ee5cbfSDavid du Colombier * Read a word at address 'addr' from the Atmel AT93C46
109180ee5cbfSDavid du Colombier * 3-Wire Serial EEPROM or compatible. The EEPROM access is
109280ee5cbfSDavid du Colombier * controlled by 4 bits in Eecd. See the AT93C46 datasheet
109380ee5cbfSDavid du Colombier * for protocol details.
109480ee5cbfSDavid du Colombier */
109580ee5cbfSDavid du Colombier if(at93c46io(ctlr, "S ICc :DCc;", (0x02<<6)|addr) != 0)
109680ee5cbfSDavid du Colombier break;
109780ee5cbfSDavid du Colombier data = at93c46io(ctlr, "::COc;", 0);
109880ee5cbfSDavid du Colombier at93c46io(ctlr, "sic", 0);
109980ee5cbfSDavid du Colombier ctlr->eeprom[addr] = data;
110080ee5cbfSDavid du Colombier sum += data;
110180ee5cbfSDavid du Colombier }
110280ee5cbfSDavid du Colombier
110380ee5cbfSDavid du Colombier return sum;
110480ee5cbfSDavid du Colombier }
110580ee5cbfSDavid du Colombier
110680ee5cbfSDavid du Colombier static void
gc82543detach(Ctlr * ctlr)110780ee5cbfSDavid du Colombier gc82543detach(Ctlr* ctlr)
110880ee5cbfSDavid du Colombier {
110980ee5cbfSDavid du Colombier /*
111080ee5cbfSDavid du Colombier * Perform a device reset to get the chip back to the
111180ee5cbfSDavid du Colombier * power-on state, followed by an EEPROM reset to read
111280ee5cbfSDavid du Colombier * the defaults for some internal registers.
111380ee5cbfSDavid du Colombier */
11143ff48bf5SDavid du Colombier csr32w(ctlr, Imc, ~0);
11153ff48bf5SDavid du Colombier csr32w(ctlr, Rctl, 0);
11163ff48bf5SDavid du Colombier csr32w(ctlr, Tctl, 0);
11173ff48bf5SDavid du Colombier
11183ff48bf5SDavid du Colombier delay(10);
11193ff48bf5SDavid du Colombier
112080ee5cbfSDavid du Colombier csr32w(ctlr, Ctrl, Devrst);
112180ee5cbfSDavid du Colombier while(csr32r(ctlr, Ctrl) & Devrst)
112280ee5cbfSDavid du Colombier ;
112380ee5cbfSDavid du Colombier
112480ee5cbfSDavid du Colombier csr32w(ctlr, Ctrlext, Eerst);
112580ee5cbfSDavid du Colombier while(csr32r(ctlr, Ctrlext) & Eerst)
112680ee5cbfSDavid du Colombier ;
11273ff48bf5SDavid du Colombier
11283ff48bf5SDavid du Colombier csr32w(ctlr, Imc, ~0);
11293ff48bf5SDavid du Colombier while(csr32r(ctlr, Icr))
11303ff48bf5SDavid du Colombier ;
11313ff48bf5SDavid du Colombier }
11323ff48bf5SDavid du Colombier
11333ff48bf5SDavid du Colombier static void
gc82543checklink(Ctlr * ctlr)11343ff48bf5SDavid du Colombier gc82543checklink(Ctlr* ctlr)
11353ff48bf5SDavid du Colombier {
11363ff48bf5SDavid du Colombier int ctrl, status, rxcw;
11373ff48bf5SDavid du Colombier
11383ff48bf5SDavid du Colombier ctrl = csr32r(ctlr, Ctrl);
11393ff48bf5SDavid du Colombier status = csr32r(ctlr, Status);
11403ff48bf5SDavid du Colombier rxcw = csr32r(ctlr, Rxcw);
11413ff48bf5SDavid du Colombier
11423ff48bf5SDavid du Colombier if(!(status & Lu)){
11433ff48bf5SDavid du Colombier if(!(ctrl & (Swdpin1|Slu)) && !(rxcw & Rxconfig)){
11443ff48bf5SDavid du Colombier csr32w(ctlr, Txcw, ctlr->txcw & ~Ane);
11453ff48bf5SDavid du Colombier ctrl |= (Slu|Fd);
11463ff48bf5SDavid du Colombier if(ctlr->txcw & As)
11473ff48bf5SDavid du Colombier ctrl |= Rfce;
11483ff48bf5SDavid du Colombier if(ctlr->txcw & Ps)
11493ff48bf5SDavid du Colombier ctrl |= Tfce;
11503ff48bf5SDavid du Colombier csr32w(ctlr, Ctrl, ctrl);
11513ff48bf5SDavid du Colombier }
11523ff48bf5SDavid du Colombier }
11533ff48bf5SDavid du Colombier else if((ctrl & Slu) && (rxcw & Rxconfig)){
11543ff48bf5SDavid du Colombier csr32w(ctlr, Txcw, ctlr->txcw);
11553ff48bf5SDavid du Colombier ctrl &= ~(Slu|Fd);
11563ff48bf5SDavid du Colombier csr32w(ctlr, Ctrl, ctrl);
11573ff48bf5SDavid du Colombier }
115880ee5cbfSDavid du Colombier }
115980ee5cbfSDavid du Colombier
11609a747e4fSDavid du Colombier static void
gc82543shutdown(Ether * ether)11619a747e4fSDavid du Colombier gc82543shutdown(Ether* ether)
11629a747e4fSDavid du Colombier {
11639a747e4fSDavid du Colombier gc82543detach(ether->ctlr);
11649a747e4fSDavid du Colombier }
11659a747e4fSDavid du Colombier
116680ee5cbfSDavid du Colombier static int
gc82543reset(Ctlr * ctlr)116780ee5cbfSDavid du Colombier gc82543reset(Ctlr* ctlr)
116880ee5cbfSDavid du Colombier {
11693ff48bf5SDavid du Colombier int ctl;
11703ff48bf5SDavid du Colombier int te;
11713ff48bf5SDavid du Colombier
117280ee5cbfSDavid du Colombier /*
117380ee5cbfSDavid du Colombier * Read the EEPROM, validate the checksum
117480ee5cbfSDavid du Colombier * then get the device back to a power-on state.
117580ee5cbfSDavid du Colombier */
117680ee5cbfSDavid du Colombier if(at93c46r(ctlr) != 0xBABA)
117780ee5cbfSDavid du Colombier return -1;
11783ff48bf5SDavid du Colombier
117980ee5cbfSDavid du Colombier gc82543detach(ctlr);
118080ee5cbfSDavid du Colombier
11813ff48bf5SDavid du Colombier te = ctlr->eeprom[Icw2];
11823ff48bf5SDavid du Colombier if((te & 0x3000) == 0){
11833ff48bf5SDavid du Colombier ctlr->fcrtl = 0x00002000;
11843ff48bf5SDavid du Colombier ctlr->fcrth = 0x00004000;
11853ff48bf5SDavid du Colombier ctlr->txcw = Ane|TxcwFd;
11863ff48bf5SDavid du Colombier }
11873ff48bf5SDavid du Colombier else if((te & 0x3000) == 0x2000){
11883ff48bf5SDavid du Colombier ctlr->fcrtl = 0;
11893ff48bf5SDavid du Colombier ctlr->fcrth = 0;
11903ff48bf5SDavid du Colombier ctlr->txcw = Ane|TxcwFd|As;
11913ff48bf5SDavid du Colombier }
11923ff48bf5SDavid du Colombier else{
11933ff48bf5SDavid du Colombier ctlr->fcrtl = 0x00002000;
11943ff48bf5SDavid du Colombier ctlr->fcrth = 0x00004000;
11953ff48bf5SDavid du Colombier ctlr->txcw = Ane|TxcwFd|As|Ps;
11963ff48bf5SDavid du Colombier }
11973ff48bf5SDavid du Colombier
11983ff48bf5SDavid du Colombier csr32w(ctlr, Txcw, ctlr->txcw);
11993ff48bf5SDavid du Colombier
12003ff48bf5SDavid du Colombier csr32w(ctlr, Ctrlext, (te & 0x00f0)<<4);
12013ff48bf5SDavid du Colombier
12023ff48bf5SDavid du Colombier csr32w(ctlr, Tctl, csr32r(ctlr, Tctl)|(64<<ColdSHIFT));
12033ff48bf5SDavid du Colombier
12043ff48bf5SDavid du Colombier te = ctlr->eeprom[Icw1];
12053ff48bf5SDavid du Colombier ctl = ((te & 0x01E0)<<17)|(te & 0x0010)<<3;
12063ff48bf5SDavid du Colombier csr32w(ctlr, Ctrl, ctl);
12073ff48bf5SDavid du Colombier
12083ff48bf5SDavid du Colombier delay(10);
12093ff48bf5SDavid du Colombier
121080ee5cbfSDavid du Colombier /*
121180ee5cbfSDavid du Colombier * Flow control - values from the datasheet.
121280ee5cbfSDavid du Colombier */
121380ee5cbfSDavid du Colombier csr32w(ctlr, Fcal, 0x00C28001);
121480ee5cbfSDavid du Colombier csr32w(ctlr, Fcah, 0x00000100);
121580ee5cbfSDavid du Colombier csr32w(ctlr, Fct, 0x00008808);
121680ee5cbfSDavid du Colombier csr32w(ctlr, Fcttv, 0x00000100);
121780ee5cbfSDavid du Colombier
12183ff48bf5SDavid du Colombier csr32w(ctlr, Fcrtl, ctlr->fcrtl);
12193ff48bf5SDavid du Colombier csr32w(ctlr, Fcrth, ctlr->fcrth);
122080ee5cbfSDavid du Colombier
122180ee5cbfSDavid du Colombier ctlr->im = Lsc;
12223ff48bf5SDavid du Colombier gc82543checklink(ctlr);
122380ee5cbfSDavid du Colombier
122480ee5cbfSDavid du Colombier return 0;
122580ee5cbfSDavid du Colombier }
122680ee5cbfSDavid du Colombier
122780ee5cbfSDavid du Colombier static void
gc82543watchdog(void * arg)12283ff48bf5SDavid du Colombier gc82543watchdog(void* arg)
12293ff48bf5SDavid du Colombier {
12303ff48bf5SDavid du Colombier Ether *edev;
12313ff48bf5SDavid du Colombier Ctlr *ctlr;
12323ff48bf5SDavid du Colombier
12333ff48bf5SDavid du Colombier edev = arg;
12343ff48bf5SDavid du Colombier for(;;){
1235dc5a79c1SDavid du Colombier tsleep(&up->sleep, return0, 0, 1000);
12363ff48bf5SDavid du Colombier
12373ff48bf5SDavid du Colombier ctlr = edev->ctlr;
12383ff48bf5SDavid du Colombier if(ctlr == nil){
12393ff48bf5SDavid du Colombier print("%s: exiting\n", up->text);
12403ff48bf5SDavid du Colombier pexit("disabled", 0);
12413ff48bf5SDavid du Colombier }
12423ff48bf5SDavid du Colombier
12433ff48bf5SDavid du Colombier gc82543checklink(ctlr);
12443ff48bf5SDavid du Colombier gc82543replenish(ctlr);
12453ff48bf5SDavid du Colombier }
12463ff48bf5SDavid du Colombier }
12473ff48bf5SDavid du Colombier
12483ff48bf5SDavid du Colombier static void
gc82543pci(void)124980ee5cbfSDavid du Colombier gc82543pci(void)
125080ee5cbfSDavid du Colombier {
12514de34a7eSDavid du Colombier int cls;
12524de34a7eSDavid du Colombier void *mem;
125380ee5cbfSDavid du Colombier Pcidev *p;
125480ee5cbfSDavid du Colombier Ctlr *ctlr;
125580ee5cbfSDavid du Colombier
125680ee5cbfSDavid du Colombier p = nil;
125780ee5cbfSDavid du Colombier while(p = pcimatch(p, 0, 0)){
125880ee5cbfSDavid du Colombier if(p->ccrb != 0x02 || p->ccru != 0)
125980ee5cbfSDavid du Colombier continue;
126080ee5cbfSDavid du Colombier
126180ee5cbfSDavid du Colombier switch((p->did<<16)|p->vid){
126280ee5cbfSDavid du Colombier case (0x1000<<16)|0x8086: /* LSI L2A1157 (82542) */
1263dc5a79c1SDavid du Colombier case (0x1004<<16)|0x8086: /* Intel PRO/1000 T */
1264dc5a79c1SDavid du Colombier case (0x1008<<16)|0x8086: /* Intel PRO/1000 XT */
126580ee5cbfSDavid du Colombier default:
126680ee5cbfSDavid du Colombier continue;
126780ee5cbfSDavid du Colombier case (0x1001<<16)|0x8086: /* Intel PRO/1000 F */
126880ee5cbfSDavid du Colombier break;
126980ee5cbfSDavid du Colombier }
127080ee5cbfSDavid du Colombier
12714de34a7eSDavid du Colombier mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
12724de34a7eSDavid du Colombier if(mem == 0){
127380ee5cbfSDavid du Colombier print("gc82543: can't map %8.8luX\n", p->mem[0].bar);
127480ee5cbfSDavid du Colombier continue;
127580ee5cbfSDavid du Colombier }
12763ff48bf5SDavid du Colombier cls = pcicfgr8(p, PciCLS);
12773ff48bf5SDavid du Colombier switch(cls){
12783ff48bf5SDavid du Colombier default:
1279*0591a7c1SDavid du Colombier print("82543gc: p->cls %#ux, setting to 0x10\n", p->cls);
1280*0591a7c1SDavid du Colombier p->cls = 0x10;
1281*0591a7c1SDavid du Colombier pcicfgw8(p, PciCLS, p->cls);
1282*0591a7c1SDavid du Colombier break;
1283*0591a7c1SDavid du Colombier case 0x08:
1284*0591a7c1SDavid du Colombier case 0x10:
1285*0591a7c1SDavid du Colombier break;
12863ff48bf5SDavid du Colombier }
128780ee5cbfSDavid du Colombier ctlr = malloc(sizeof(Ctlr));
1288aa72973aSDavid du Colombier if(ctlr == nil)
1289aa72973aSDavid du Colombier error(Enomem);
12904de34a7eSDavid du Colombier ctlr->port = p->mem[0].bar & ~0x0F;
129180ee5cbfSDavid du Colombier ctlr->pcidev = p;
129280ee5cbfSDavid du Colombier ctlr->id = (p->did<<16)|p->vid;
12934de34a7eSDavid du Colombier ctlr->nic = mem;
12943ff48bf5SDavid du Colombier
129580ee5cbfSDavid du Colombier if(gc82543reset(ctlr)){
129680ee5cbfSDavid du Colombier free(ctlr);
129780ee5cbfSDavid du Colombier continue;
129880ee5cbfSDavid du Colombier }
129980ee5cbfSDavid du Colombier
13003ff48bf5SDavid du Colombier if(gc82543ctlrhead != nil)
13013ff48bf5SDavid du Colombier gc82543ctlrtail->next = ctlr;
130280ee5cbfSDavid du Colombier else
13033ff48bf5SDavid du Colombier gc82543ctlrhead = ctlr;
13043ff48bf5SDavid du Colombier gc82543ctlrtail = ctlr;
130580ee5cbfSDavid du Colombier }
130680ee5cbfSDavid du Colombier }
130780ee5cbfSDavid du Colombier
130880ee5cbfSDavid du Colombier static int
gc82543pnp(Ether * edev)130980ee5cbfSDavid du Colombier gc82543pnp(Ether* edev)
131080ee5cbfSDavid du Colombier {
131180ee5cbfSDavid du Colombier int i;
131280ee5cbfSDavid du Colombier Ctlr *ctlr;
131380ee5cbfSDavid du Colombier uchar ea[Eaddrlen];
131480ee5cbfSDavid du Colombier
13153ff48bf5SDavid du Colombier if(gc82543ctlrhead == nil)
131680ee5cbfSDavid du Colombier gc82543pci();
131780ee5cbfSDavid du Colombier
131880ee5cbfSDavid du Colombier /*
131980ee5cbfSDavid du Colombier * Any adapter matches if no edev->port is supplied,
132080ee5cbfSDavid du Colombier * otherwise the ports must match.
132180ee5cbfSDavid du Colombier */
13223ff48bf5SDavid du Colombier for(ctlr = gc82543ctlrhead; ctlr != nil; ctlr = ctlr->next){
132380ee5cbfSDavid du Colombier if(ctlr->active)
132480ee5cbfSDavid du Colombier continue;
132580ee5cbfSDavid du Colombier if(edev->port == 0 || edev->port == ctlr->port){
132680ee5cbfSDavid du Colombier ctlr->active = 1;
132780ee5cbfSDavid du Colombier break;
132880ee5cbfSDavid du Colombier }
132980ee5cbfSDavid du Colombier }
133080ee5cbfSDavid du Colombier if(ctlr == nil)
133180ee5cbfSDavid du Colombier return -1;
133280ee5cbfSDavid du Colombier
133380ee5cbfSDavid du Colombier edev->ctlr = ctlr;
133480ee5cbfSDavid du Colombier edev->port = ctlr->port;
133580ee5cbfSDavid du Colombier edev->irq = ctlr->pcidev->intl;
133680ee5cbfSDavid du Colombier edev->tbdf = ctlr->pcidev->tbdf;
133780ee5cbfSDavid du Colombier edev->mbps = 1000;
133880ee5cbfSDavid du Colombier
133980ee5cbfSDavid du Colombier /*
134080ee5cbfSDavid du Colombier * Check if the adapter's station address is to be overridden.
134180ee5cbfSDavid du Colombier * If not, read it from the EEPROM and set in ether->ea prior to
134280ee5cbfSDavid du Colombier * loading the station address in the hardware.
134380ee5cbfSDavid du Colombier */
134480ee5cbfSDavid du Colombier memset(ea, 0, Eaddrlen);
134580ee5cbfSDavid du Colombier if(memcmp(ea, edev->ea, Eaddrlen) == 0){
13463ff48bf5SDavid du Colombier for(i = Ea; i < Eaddrlen/2; i++){
134780ee5cbfSDavid du Colombier edev->ea[2*i] = ctlr->eeprom[i];
134880ee5cbfSDavid du Colombier edev->ea[2*i+1] = ctlr->eeprom[i]>>8;
134980ee5cbfSDavid du Colombier }
135080ee5cbfSDavid du Colombier }
135180ee5cbfSDavid du Colombier gc82543init(edev);
135280ee5cbfSDavid du Colombier
135380ee5cbfSDavid du Colombier /*
135480ee5cbfSDavid du Colombier * Linkage to the generic ethernet driver.
135580ee5cbfSDavid du Colombier */
135680ee5cbfSDavid du Colombier edev->attach = gc82543attach;
135780ee5cbfSDavid du Colombier edev->transmit = gc82543transmit;
135880ee5cbfSDavid du Colombier edev->interrupt = gc82543interrupt;
135980ee5cbfSDavid du Colombier edev->ifstat = gc82543ifstat;
13609a747e4fSDavid du Colombier edev->shutdown = gc82543shutdown;
13613ff48bf5SDavid du Colombier edev->ctl = gc82543ctl;
136280ee5cbfSDavid du Colombier edev->arg = edev;
13633ff48bf5SDavid du Colombier edev->promiscuous = gc82543promiscuous;
13643ff48bf5SDavid du Colombier edev->multicast = gc82543multicast;
136580ee5cbfSDavid du Colombier
136680ee5cbfSDavid du Colombier return 0;
136780ee5cbfSDavid du Colombier }
136880ee5cbfSDavid du Colombier
136980ee5cbfSDavid du Colombier void
ether82543gclink(void)137080ee5cbfSDavid du Colombier ether82543gclink(void)
137180ee5cbfSDavid du Colombier {
137280ee5cbfSDavid du Colombier addethercard("82543GC", gc82543pnp);
137380ee5cbfSDavid du Colombier }
1374