1d25bfb3bSDavid du Colombier /*
2d25bfb3bSDavid du Colombier * National Semiconductor DP83820
3d25bfb3bSDavid du Colombier * 10/100/1000 Mb/s Ethernet Network Interface Controller
4d25bfb3bSDavid du Colombier * (Gig-NIC).
5d25bfb3bSDavid du Colombier * Driver assumes little-endian and 32-bit host throughout.
6d25bfb3bSDavid du Colombier */
7d25bfb3bSDavid du Colombier #include "u.h"
8d25bfb3bSDavid du Colombier #include "../port/lib.h"
9d25bfb3bSDavid du Colombier #include "mem.h"
10d25bfb3bSDavid du Colombier #include "dat.h"
11d25bfb3bSDavid du Colombier #include "fns.h"
12d25bfb3bSDavid du Colombier #include "io.h"
13d25bfb3bSDavid du Colombier #include "../port/error.h"
14d25bfb3bSDavid du Colombier #include "../port/netif.h"
15d25bfb3bSDavid du Colombier
16d25bfb3bSDavid du Colombier #include "etherif.h"
17d25bfb3bSDavid du Colombier #include "ethermii.h"
18d25bfb3bSDavid du Colombier
19d25bfb3bSDavid du Colombier enum { /* Registers */
20d25bfb3bSDavid du Colombier Cr = 0x00, /* Command */
21d25bfb3bSDavid du Colombier Cfg = 0x04, /* Configuration and Media Status */
22d25bfb3bSDavid du Colombier Mear = 0x08, /* MII/EEPROM Access */
23d25bfb3bSDavid du Colombier Ptscr = 0x0C, /* PCI Test Control */
24d25bfb3bSDavid du Colombier Isr = 0x10, /* Interrupt Status */
25d25bfb3bSDavid du Colombier Imr = 0x14, /* Interrupt Mask */
26d25bfb3bSDavid du Colombier Ier = 0x18, /* Interrupt Enable */
27d25bfb3bSDavid du Colombier Ihr = 0x1C, /* Interrupt Holdoff */
28d25bfb3bSDavid du Colombier Txdp = 0x20, /* Transmit Descriptor Pointer */
29d25bfb3bSDavid du Colombier Txdphi = 0x24, /* Transmit Descriptor Pointer Hi */
30d25bfb3bSDavid du Colombier Txcfg = 0x28, /* Transmit Configuration */
31d25bfb3bSDavid du Colombier Gpior = 0x2C, /* General Purpose I/O Control */
32d25bfb3bSDavid du Colombier Rxdp = 0x30, /* Receive Descriptor Pointer */
33d25bfb3bSDavid du Colombier Rxdphi = 0x34, /* Receive Descriptor Pointer Hi */
34d25bfb3bSDavid du Colombier Rxcfg = 0x38, /* Receive Configuration */
35d25bfb3bSDavid du Colombier Pqcr = 0x3C, /* Priority Queueing Control */
36d25bfb3bSDavid du Colombier Wcsr = 0x40, /* Wake on LAN Control/Status */
37d25bfb3bSDavid du Colombier Pcr = 0x44, /* Pause Control/Status */
38d25bfb3bSDavid du Colombier Rfcr = 0x48, /* Receive Filter/Match Control */
39d25bfb3bSDavid du Colombier Rfdr = 0x4C, /* Receive Filter/Match Data */
40d25bfb3bSDavid du Colombier Brar = 0x50, /* Boot ROM Address */
41d25bfb3bSDavid du Colombier Brdr = 0x54, /* Boot ROM Data */
42d25bfb3bSDavid du Colombier Srr = 0x58, /* Silicon Revision */
43d25bfb3bSDavid du Colombier Mibc = 0x5C, /* MIB Control */
44d25bfb3bSDavid du Colombier Mibd = 0x60, /* MIB Data */
45d25bfb3bSDavid du Colombier Txdp1 = 0xA0, /* Txdp Priority 1 */
46d25bfb3bSDavid du Colombier Txdp2 = 0xA4, /* Txdp Priority 2 */
47d25bfb3bSDavid du Colombier Txdp3 = 0xA8, /* Txdp Priority 3 */
48d25bfb3bSDavid du Colombier Rxdp1 = 0xB0, /* Rxdp Priority 1 */
49d25bfb3bSDavid du Colombier Rxdp2 = 0xB4, /* Rxdp Priority 2 */
50d25bfb3bSDavid du Colombier Rxdp3 = 0xB8, /* Rxdp Priority 3 */
51d25bfb3bSDavid du Colombier Vrcr = 0xBC, /* VLAN/IP Receive Control */
52d25bfb3bSDavid du Colombier Vtcr = 0xC0, /* VLAN/IP Transmit Control */
53d25bfb3bSDavid du Colombier Vdr = 0xC4, /* VLAN Data */
54d25bfb3bSDavid du Colombier Ccsr = 0xCC, /* Clockrun Control/Status */
55d25bfb3bSDavid du Colombier Tbicr = 0xE0, /* TBI Control */
56d25bfb3bSDavid du Colombier Tbisr = 0xE4, /* TBI Status */
57d25bfb3bSDavid du Colombier Tanar = 0xE8, /* TBI ANAR */
58d25bfb3bSDavid du Colombier Tanlpar = 0xEC, /* TBI ANLPAR */
59d25bfb3bSDavid du Colombier Taner = 0xF0, /* TBI ANER */
60d25bfb3bSDavid du Colombier Tesr = 0xF4, /* TBI ESR */
61d25bfb3bSDavid du Colombier };
62d25bfb3bSDavid du Colombier
63d25bfb3bSDavid du Colombier enum { /* Cr */
64d25bfb3bSDavid du Colombier Txe = 0x00000001, /* Transmit Enable */
65d25bfb3bSDavid du Colombier Txd = 0x00000002, /* Transmit Disable */
66d25bfb3bSDavid du Colombier Rxe = 0x00000004, /* Receiver Enable */
67d25bfb3bSDavid du Colombier Rxd = 0x00000008, /* Receiver Disable */
68d25bfb3bSDavid du Colombier Txr = 0x00000010, /* Transmitter Reset */
69d25bfb3bSDavid du Colombier Rxr = 0x00000020, /* Receiver Reset */
70d25bfb3bSDavid du Colombier Swien = 0x00000080, /* Software Interrupt Enable */
71d25bfb3bSDavid du Colombier Rst = 0x00000100, /* Reset */
72d25bfb3bSDavid du Colombier TxpriSHFT = 9, /* Tx Priority Queue Select */
73d25bfb3bSDavid du Colombier TxpriMASK = 0x00001E00,
74d25bfb3bSDavid du Colombier RxpriSHFT = 13, /* Rx Priority Queue Select */
75d25bfb3bSDavid du Colombier RxpriMASK = 0x0001E000,
76d25bfb3bSDavid du Colombier };
77d25bfb3bSDavid du Colombier
78d25bfb3bSDavid du Colombier enum { /* Configuration and Media Status */
79d25bfb3bSDavid du Colombier Bem = 0x00000001, /* Big Endian Mode */
80d25bfb3bSDavid du Colombier Ext125 = 0x00000002, /* External 125MHz reference Select */
81d25bfb3bSDavid du Colombier Bromdis = 0x00000004, /* Disable Boot ROM interface */
82d25bfb3bSDavid du Colombier Pesel = 0x00000008, /* Parity Error Detection Action */
83d25bfb3bSDavid du Colombier Exd = 0x00000010, /* Excessive Deferral Abort */
84d25bfb3bSDavid du Colombier Pow = 0x00000020, /* Program Out of Window Timer */
85d25bfb3bSDavid du Colombier Sb = 0x00000040, /* Single Back-off */
86d25bfb3bSDavid du Colombier Reqalg = 0x00000080, /* PCI Bus Request Algorithm */
87d25bfb3bSDavid du Colombier Extstsen = 0x00000100, /* Extended Status Enable */
88d25bfb3bSDavid du Colombier Phydis = 0x00000200, /* Disable PHY */
89d25bfb3bSDavid du Colombier Phyrst = 0x00000400, /* Reset PHY */
90d25bfb3bSDavid du Colombier M64addren = 0x00000800, /* Master 64-bit Addressing Enable */
91d25bfb3bSDavid du Colombier Data64en = 0x00001000, /* 64-bit Data Enable */
92d25bfb3bSDavid du Colombier Pci64det = 0x00002000, /* PCI 64-bit Bus Detected */
93d25bfb3bSDavid du Colombier T64addren = 0x00004000, /* Target 64-bit Addressing Enable */
94d25bfb3bSDavid du Colombier Mwidis = 0x00008000, /* MWI Disable */
95d25bfb3bSDavid du Colombier Mrmdis = 0x00010000, /* MRM Disable */
96d25bfb3bSDavid du Colombier Tmrtest = 0x00020000, /* Timer Test Mode */
97d25bfb3bSDavid du Colombier Spdstsien = 0x00040000, /* PHY Spdsts Interrupt Enable */
98d25bfb3bSDavid du Colombier Lnkstsien = 0x00080000, /* PHY Lnksts Interrupt Enable */
99d25bfb3bSDavid du Colombier Dupstsien = 0x00100000, /* PHY Dupsts Interrupt Enable */
100d25bfb3bSDavid du Colombier Mode1000 = 0x00400000, /* 1000Mb/s Mode Control */
101d25bfb3bSDavid du Colombier Tbien = 0x01000000, /* Ten-Bit Interface Enable */
102d25bfb3bSDavid du Colombier Dupsts = 0x10000000, /* Full Duplex Status */
103d25bfb3bSDavid du Colombier Spdsts100 = 0x20000000, /* SPEED100 Input Pin Status */
104d25bfb3bSDavid du Colombier Spdsts1000 = 0x40000000, /* SPEED1000 Input Pin Status */
105d25bfb3bSDavid du Colombier Lnksts = 0x80000000, /* Link Status */
106d25bfb3bSDavid du Colombier };
107d25bfb3bSDavid du Colombier
108d25bfb3bSDavid du Colombier enum { /* MII/EEPROM Access */
109d25bfb3bSDavid du Colombier Eedi = 0x00000001, /* EEPROM Data In */
110d25bfb3bSDavid du Colombier Eedo = 0x00000002, /* EEPROM Data Out */
111d25bfb3bSDavid du Colombier Eeclk = 0x00000004, /* EEPROM Serial Clock */
112d25bfb3bSDavid du Colombier Eesel = 0x00000008, /* EEPROM Chip Select */
113d25bfb3bSDavid du Colombier Mdio = 0x00000010, /* MII Management Data */
114d25bfb3bSDavid du Colombier Mddir = 0x00000020, /* MII Management Direction */
115d25bfb3bSDavid du Colombier Mdc = 0x00000040, /* MII Management Clock */
116d25bfb3bSDavid du Colombier };
117d25bfb3bSDavid du Colombier
118d25bfb3bSDavid du Colombier enum { /* Interrupts */
119d25bfb3bSDavid du Colombier Rxok = 0x00000001, /* Rx OK */
120d25bfb3bSDavid du Colombier Rxdesc = 0x00000002, /* Rx Descriptor */
121d25bfb3bSDavid du Colombier Rxerr = 0x00000004, /* Rx Packet Error */
122d25bfb3bSDavid du Colombier Rxearly = 0x00000008, /* Rx Early Threshold */
123d25bfb3bSDavid du Colombier Rxidle = 0x00000010, /* Rx Idle */
124d25bfb3bSDavid du Colombier Rxorn = 0x00000020, /* Rx Overrun */
125d25bfb3bSDavid du Colombier Txok = 0x00000040, /* Tx Packet OK */
126d25bfb3bSDavid du Colombier Txdesc = 0x00000080, /* Tx Descriptor */
127d25bfb3bSDavid du Colombier Txerr = 0x00000100, /* Tx Packet Error */
128d25bfb3bSDavid du Colombier Txidle = 0x00000200, /* Tx Idle */
129d25bfb3bSDavid du Colombier Txurn = 0x00000400, /* Tx Underrun */
130d25bfb3bSDavid du Colombier Mib = 0x00000800, /* MIB Service */
131d25bfb3bSDavid du Colombier Swi = 0x00001000, /* Software Interrupt */
132d25bfb3bSDavid du Colombier Pme = 0x00002000, /* Power Management Event */
133d25bfb3bSDavid du Colombier Phy = 0x00004000, /* PHY Interrupt */
134d25bfb3bSDavid du Colombier Hibint = 0x00008000, /* High Bits Interrupt Set */
135d25bfb3bSDavid du Colombier Rxsovr = 0x00010000, /* Rx Status FIFO Overrun */
136d25bfb3bSDavid du Colombier Rtabt = 0x00020000, /* Received Target Abort */
137d25bfb3bSDavid du Colombier Rmabt = 0x00040000, /* Received Master Abort */
138d25bfb3bSDavid du Colombier Sserr = 0x00080000, /* Signalled System Error */
139d25bfb3bSDavid du Colombier Dperr = 0x00100000, /* Detected Parity Error */
140d25bfb3bSDavid du Colombier Rxrcmp = 0x00200000, /* Receive Reset Complete */
141d25bfb3bSDavid du Colombier Txrcmp = 0x00400000, /* Transmit Reset Complete */
142d25bfb3bSDavid du Colombier Rxdesc0 = 0x00800000, /* Rx Descriptor for Priority Queue 0 */
143d25bfb3bSDavid du Colombier Rxdesc1 = 0x01000000, /* Rx Descriptor for Priority Queue 1 */
144d25bfb3bSDavid du Colombier Rxdesc2 = 0x02000000, /* Rx Descriptor for Priority Queue 2 */
145d25bfb3bSDavid du Colombier Rxdesc3 = 0x04000000, /* Rx Descriptor for Priority Queue 3 */
146d25bfb3bSDavid du Colombier Txdesc0 = 0x08000000, /* Tx Descriptor for Priority Queue 0 */
147d25bfb3bSDavid du Colombier Txdesc1 = 0x10000000, /* Tx Descriptor for Priority Queue 1 */
148d25bfb3bSDavid du Colombier Txdesc2 = 0x20000000, /* Tx Descriptor for Priority Queue 2 */
149d25bfb3bSDavid du Colombier Txdesc3 = 0x40000000, /* Tx Descriptor for Priority Queue 3 */
150d25bfb3bSDavid du Colombier };
151d25bfb3bSDavid du Colombier
152d25bfb3bSDavid du Colombier enum { /* Interrupt Enable */
153d25bfb3bSDavid du Colombier Ien = 0x00000001, /* Interrupt Enable */
154d25bfb3bSDavid du Colombier };
155d25bfb3bSDavid du Colombier
156d25bfb3bSDavid du Colombier enum { /* Interrupt Holdoff */
157d25bfb3bSDavid du Colombier IhSHFT = 0, /* Interrupt Holdoff */
158d25bfb3bSDavid du Colombier IhMASK = 0x000000FF,
159d25bfb3bSDavid du Colombier Ihctl = 0x00000100, /* Interrupt Holdoff Control */
160d25bfb3bSDavid du Colombier };
161d25bfb3bSDavid du Colombier
162d25bfb3bSDavid du Colombier enum { /* Transmit Configuration */
163d25bfb3bSDavid du Colombier TxdrthSHFT = 0, /* Tx Drain Threshold */
164d25bfb3bSDavid du Colombier TxdrthMASK = 0x000000FF,
165d25bfb3bSDavid du Colombier FlthSHFT = 16, /* Tx Fill Threshold */
166d25bfb3bSDavid du Colombier FlthMASK = 0x0000FF00,
167d25bfb3bSDavid du Colombier Brstdis = 0x00080000, /* 1000Mb/s Burst Disable */
168d25bfb3bSDavid du Colombier MxdmaSHFT = 20, /* Max Size per Tx DMA Burst */
169d25bfb3bSDavid du Colombier MxdmaMASK = 0x00700000,
170d25bfb3bSDavid du Colombier Ecretryen = 0x00800000, /* Excessive Collision Retry Enable */
171d25bfb3bSDavid du Colombier Atp = 0x10000000, /* Automatic Transmit Padding */
172d25bfb3bSDavid du Colombier Mlb = 0x20000000, /* MAC Loopback */
173d25bfb3bSDavid du Colombier Hbi = 0x40000000, /* Heartbeat Ignore */
174d25bfb3bSDavid du Colombier Csi = 0x80000000, /* Carrier Sense Ignore */
175d25bfb3bSDavid du Colombier };
176d25bfb3bSDavid du Colombier
177d25bfb3bSDavid du Colombier enum { /* Receive Configuration */
178d25bfb3bSDavid du Colombier RxdrthSHFT = 1, /* Rx Drain Threshold */
179d25bfb3bSDavid du Colombier RxdrthMASK = 0x0000003E,
180d25bfb3bSDavid du Colombier Airl = 0x04000000, /* Accept In-Range Length Errored */
181d25bfb3bSDavid du Colombier Alp = 0x08000000, /* Accept Long Packets */
182d25bfb3bSDavid du Colombier Rxfd = 0x10000000, /* Receive Full Duplex */
183d25bfb3bSDavid du Colombier Stripcrc = 0x20000000, /* Strip CRC */
184d25bfb3bSDavid du Colombier Arp = 0x40000000, /* Accept Runt Packets */
185d25bfb3bSDavid du Colombier Aep = 0x80000000, /* Accept Errored Packets */
186d25bfb3bSDavid du Colombier };
187d25bfb3bSDavid du Colombier
188d25bfb3bSDavid du Colombier enum { /* Priority Queueing Control */
189d25bfb3bSDavid du Colombier Txpqen = 0x00000001, /* Transmit Priority Queuing Enable */
190d25bfb3bSDavid du Colombier Txfairen = 0x00000002, /* Transmit Fairness Enable */
191d25bfb3bSDavid du Colombier RxpqenSHFT = 2, /* Receive Priority Queue Enable */
192d25bfb3bSDavid du Colombier RxpqenMASK = 0x0000000C,
193d25bfb3bSDavid du Colombier };
194d25bfb3bSDavid du Colombier
195d25bfb3bSDavid du Colombier enum { /* Pause Control/Status */
196d25bfb3bSDavid du Colombier PscntSHFT = 0, /* Pause Counter Value */
197d25bfb3bSDavid du Colombier PscntMASK = 0x0000FFFF,
198d25bfb3bSDavid du Colombier Pstx = 0x00020000, /* Transmit Pause Frame */
199d25bfb3bSDavid du Colombier PsffloSHFT = 18, /* Rx Data FIFO Lo Threshold */
200d25bfb3bSDavid du Colombier PsffloMASK = 0x000C0000,
201d25bfb3bSDavid du Colombier PsffhiSHFT = 20, /* Rx Data FIFO Hi Threshold */
202d25bfb3bSDavid du Colombier PsffhiMASK = 0x00300000,
203d25bfb3bSDavid du Colombier PsstloSHFT = 22, /* Rx Stat FIFO Hi Threshold */
204d25bfb3bSDavid du Colombier PsstloMASK = 0x00C00000,
205d25bfb3bSDavid du Colombier PssthiSHFT = 24, /* Rx Stat FIFO Hi Threshold */
206d25bfb3bSDavid du Colombier PssthiMASK = 0x03000000,
207d25bfb3bSDavid du Colombier Psrcvd = 0x08000000, /* Pause Frame Received */
208d25bfb3bSDavid du Colombier Psact = 0x10000000, /* Pause Active */
209d25bfb3bSDavid du Colombier Psda = 0x20000000, /* Pause on Destination Address */
210d25bfb3bSDavid du Colombier Psmcast = 0x40000000, /* Pause on Multicast */
211d25bfb3bSDavid du Colombier Psen = 0x80000000, /* Pause Enable */
212d25bfb3bSDavid du Colombier };
213d25bfb3bSDavid du Colombier
214d25bfb3bSDavid du Colombier enum { /* Receive Filter/Match Control */
215d25bfb3bSDavid du Colombier RfaddrSHFT = 0, /* Extended Register Address */
216d25bfb3bSDavid du Colombier RfaddrMASK = 0x000003FF,
217d25bfb3bSDavid du Colombier Ulm = 0x00080000, /* U/L bit mask */
218d25bfb3bSDavid du Colombier Uhen = 0x00100000, /* Unicast Hash Enable */
219d25bfb3bSDavid du Colombier Mhen = 0x00200000, /* Multicast Hash Enable */
220d25bfb3bSDavid du Colombier Aarp = 0x00400000, /* Accept ARP Packets */
221d25bfb3bSDavid du Colombier ApatSHFT = 23, /* Accept on Pattern Match */
222d25bfb3bSDavid du Colombier ApatMASK = 0x07800000,
223d25bfb3bSDavid du Colombier Apm = 0x08000000, /* Accept on Perfect Match */
224d25bfb3bSDavid du Colombier Aau = 0x10000000, /* Accept All Unicast */
225d25bfb3bSDavid du Colombier Aam = 0x20000000, /* Accept All Multicast */
226d25bfb3bSDavid du Colombier Aab = 0x40000000, /* Accept All Broadcast */
227d25bfb3bSDavid du Colombier Rfen = 0x80000000, /* Rx Filter Enable */
228d25bfb3bSDavid du Colombier };
229d25bfb3bSDavid du Colombier
230d25bfb3bSDavid du Colombier enum { /* Receive Filter/Match Data */
231d25bfb3bSDavid du Colombier RfdataSHFT = 0, /* Receive Filter Data */
232d25bfb3bSDavid du Colombier RfdataMASK = 0x0000FFFF,
233d25bfb3bSDavid du Colombier BmaskSHFT = 16, /* Byte Mask */
234d25bfb3bSDavid du Colombier BmaskMASK = 0x00030000,
235d25bfb3bSDavid du Colombier };
236d25bfb3bSDavid du Colombier
237d25bfb3bSDavid du Colombier enum { /* MIB Control */
238d25bfb3bSDavid du Colombier Wrn = 0x00000001, /* Warning Test Indicator */
239d25bfb3bSDavid du Colombier Frz = 0x00000002, /* Freeze All Counters */
240d25bfb3bSDavid du Colombier Aclr = 0x00000004, /* Clear All Counters */
241d25bfb3bSDavid du Colombier Mibs = 0x00000008, /* MIB Counter Strobe */
242d25bfb3bSDavid du Colombier };
243d25bfb3bSDavid du Colombier
244d25bfb3bSDavid du Colombier enum { /* MIB Data */
245d25bfb3bSDavid du Colombier Nmibd = 11, /* Number of MIB Data Registers */
246d25bfb3bSDavid du Colombier };
247d25bfb3bSDavid du Colombier
248d25bfb3bSDavid du Colombier enum { /* VLAN/IP Receive Control */
249d25bfb3bSDavid du Colombier Vtden = 0x00000001, /* VLAN Tag Detection Enable */
250d25bfb3bSDavid du Colombier Vtren = 0x00000002, /* VLAN Tag Removal Enable */
251d25bfb3bSDavid du Colombier Dvtf = 0x00000004, /* Discard VLAN Tagged Frames */
252d25bfb3bSDavid du Colombier Dutf = 0x00000008, /* Discard Untagged Frames */
253d25bfb3bSDavid du Colombier Ipen = 0x00000010, /* IP Checksum Enable */
254d25bfb3bSDavid du Colombier Ripe = 0x00000020, /* Reject IP Checksum Errors */
255d25bfb3bSDavid du Colombier Rtcpe = 0x00000040, /* Reject TCP Checksum Errors */
256d25bfb3bSDavid du Colombier Rudpe = 0x00000080, /* Reject UDP Checksum Errors */
257d25bfb3bSDavid du Colombier };
258d25bfb3bSDavid du Colombier
259d25bfb3bSDavid du Colombier enum { /* VLAN/IP Transmit Control */
260d25bfb3bSDavid du Colombier Vgti = 0x00000001, /* VLAN Global Tag Insertion */
261d25bfb3bSDavid du Colombier Vppti = 0x00000002, /* VLAN Per-Packet Tag Insertion */
262d25bfb3bSDavid du Colombier Gchk = 0x00000004, /* Global Checksum Generation */
263d25bfb3bSDavid du Colombier Ppchk = 0x00000008, /* Per-Packet Checksum Generation */
264d25bfb3bSDavid du Colombier };
265d25bfb3bSDavid du Colombier
266d25bfb3bSDavid du Colombier enum { /* VLAN Data */
267d25bfb3bSDavid du Colombier VtypeSHFT = 0, /* VLAN Type Field */
268d25bfb3bSDavid du Colombier VtypeMASK = 0x0000FFFF,
269d25bfb3bSDavid du Colombier VtciSHFT = 16, /* VLAN Tag Control Information */
270d25bfb3bSDavid du Colombier VtciMASK = 0xFFFF0000,
271d25bfb3bSDavid du Colombier };
272d25bfb3bSDavid du Colombier
273d25bfb3bSDavid du Colombier enum { /* Clockrun Control/Status */
274d25bfb3bSDavid du Colombier Clkrunen = 0x00000001, /* CLKRUN Enable */
275d25bfb3bSDavid du Colombier Pmeen = 0x00000100, /* PME Enable */
276d25bfb3bSDavid du Colombier Pmests = 0x00008000, /* PME Status */
277d25bfb3bSDavid du Colombier };
278d25bfb3bSDavid du Colombier
279d25bfb3bSDavid du Colombier typedef struct {
280d25bfb3bSDavid du Colombier u32int link; /* Link to the next descriptor */
281d25bfb3bSDavid du Colombier u32int bufptr; /* pointer to data Buffer */
282d25bfb3bSDavid du Colombier int cmdsts; /* Command/Status */
283d25bfb3bSDavid du Colombier int extsts; /* optional Extended Status */
284d25bfb3bSDavid du Colombier
285d25bfb3bSDavid du Colombier Block* bp; /* Block containing bufptr */
286d25bfb3bSDavid du Colombier u32int unused; /* pad to 64-bit */
287d25bfb3bSDavid du Colombier } Desc;
288d25bfb3bSDavid du Colombier
289d25bfb3bSDavid du Colombier enum { /* Common cmdsts bits */
290d25bfb3bSDavid du Colombier SizeMASK = 0x0000FFFF, /* Descriptor Byte Count */
291d25bfb3bSDavid du Colombier SizeSHFT = 0,
292d25bfb3bSDavid du Colombier Ok = 0x08000000, /* Packet OK */
293d25bfb3bSDavid du Colombier Crc = 0x10000000, /* Suppress/Include CRC */
294d25bfb3bSDavid du Colombier Intr = 0x20000000, /* Interrupt on ownership transfer */
295d25bfb3bSDavid du Colombier More = 0x40000000, /* not last descriptor in a packet */
296d25bfb3bSDavid du Colombier Own = 0x80000000, /* Descriptor Ownership */
297d25bfb3bSDavid du Colombier };
298d25bfb3bSDavid du Colombier
299d25bfb3bSDavid du Colombier enum { /* Transmit cmdsts bits */
300d25bfb3bSDavid du Colombier CcntMASK = 0x000F0000, /* Collision Count */
301d25bfb3bSDavid du Colombier CcntSHFT = 16,
302d25bfb3bSDavid du Colombier Ec = 0x00100000, /* Excessive Collisions */
303d25bfb3bSDavid du Colombier Owc = 0x00200000, /* Out of Window Collision */
304d25bfb3bSDavid du Colombier Ed = 0x00400000, /* Excessive Deferral */
305d25bfb3bSDavid du Colombier Td = 0x00800000, /* Transmit Deferred */
306d25bfb3bSDavid du Colombier Crs = 0x01000000, /* Carrier Sense Lost */
307d25bfb3bSDavid du Colombier Tfu = 0x02000000, /* Transmit FIFO Underrun */
308d25bfb3bSDavid du Colombier Txa = 0x04000000, /* Transmit Abort */
309d25bfb3bSDavid du Colombier };
310d25bfb3bSDavid du Colombier
311d25bfb3bSDavid du Colombier enum { /* Receive cmdsts bits */
312d25bfb3bSDavid du Colombier Irl = 0x00010000, /* In-Range Length Error */
313d25bfb3bSDavid du Colombier Lbp = 0x00020000, /* Loopback Packet */
314d25bfb3bSDavid du Colombier Fae = 0x00040000, /* Frame Alignment Error */
315d25bfb3bSDavid du Colombier Crce = 0x00080000, /* CRC Error */
316d25bfb3bSDavid du Colombier Ise = 0x00100000, /* Invalid Symbol Error */
317d25bfb3bSDavid du Colombier Runt = 0x00200000, /* Runt Packet Received */
318d25bfb3bSDavid du Colombier Long = 0x00400000, /* Too Long Packet Received */
319d25bfb3bSDavid du Colombier DestMASK = 0x01800000, /* Destination Class */
320d25bfb3bSDavid du Colombier DestSHFT = 23,
321d25bfb3bSDavid du Colombier Rxo = 0x02000000, /* Receive Overrun */
322d25bfb3bSDavid du Colombier Rxa = 0x04000000, /* Receive Aborted */
323d25bfb3bSDavid du Colombier };
324d25bfb3bSDavid du Colombier
325d25bfb3bSDavid du Colombier enum { /* extsts bits */
326d25bfb3bSDavid du Colombier EvtciMASK = 0x0000FFFF, /* VLAN Tag Control Information */
327d25bfb3bSDavid du Colombier EvtciSHFT = 0,
328d25bfb3bSDavid du Colombier Vpkt = 0x00010000, /* VLAN Packet */
329d25bfb3bSDavid du Colombier Ippkt = 0x00020000, /* IP Packet */
330d25bfb3bSDavid du Colombier Iperr = 0x00040000, /* IP Checksum Error */
331d25bfb3bSDavid du Colombier Tcppkt = 0x00080000, /* TCP Packet */
332d25bfb3bSDavid du Colombier Tcperr = 0x00100000, /* TCP Checksum Error */
333d25bfb3bSDavid du Colombier Udppkt = 0x00200000, /* UDP Packet */
334d25bfb3bSDavid du Colombier Udperr = 0x00400000, /* UDP Checksum Error */
335d25bfb3bSDavid du Colombier };
336d25bfb3bSDavid du Colombier
337d25bfb3bSDavid du Colombier enum {
338d25bfb3bSDavid du Colombier Rbsz = ROUNDUP(sizeof(Etherpkt)+8, 8),
339588d0145SDavid du Colombier /* were 256, 4*Nrd & 64, but 52, 253 and 9 are ample. */
340588d0145SDavid du Colombier Nrd = 128,
341*cebd3b46SDavid du Colombier Nrb = 512,
342588d0145SDavid du Colombier Ntd = 32,
343d25bfb3bSDavid du Colombier };
344d25bfb3bSDavid du Colombier
345d25bfb3bSDavid du Colombier typedef struct Ctlr Ctlr;
346d25bfb3bSDavid du Colombier typedef struct Ctlr {
347d25bfb3bSDavid du Colombier int port;
348d25bfb3bSDavid du Colombier Pcidev* pcidev;
349d25bfb3bSDavid du Colombier Ctlr* next;
350d25bfb3bSDavid du Colombier int active;
351d25bfb3bSDavid du Colombier int id;
352d25bfb3bSDavid du Colombier
353d25bfb3bSDavid du Colombier int eepromsz; /* address size in bits */
354d25bfb3bSDavid du Colombier ushort* eeprom;
355d25bfb3bSDavid du Colombier
356d25bfb3bSDavid du Colombier int* nic;
357d25bfb3bSDavid du Colombier int cfg;
358d25bfb3bSDavid du Colombier int imr;
359d25bfb3bSDavid du Colombier
360d25bfb3bSDavid du Colombier QLock alock; /* attach */
361d25bfb3bSDavid du Colombier Lock ilock; /* init */
362d25bfb3bSDavid du Colombier void* alloc; /* base of per-Ctlr allocated data */
363d25bfb3bSDavid du Colombier
364d25bfb3bSDavid du Colombier Mii* mii;
365d25bfb3bSDavid du Colombier
366d25bfb3bSDavid du Colombier Lock rdlock; /* receive */
367d25bfb3bSDavid du Colombier Desc* rd;
368d25bfb3bSDavid du Colombier int nrd;
369d25bfb3bSDavid du Colombier int nrb;
370d25bfb3bSDavid du Colombier int rdx;
371d25bfb3bSDavid du Colombier int rxcfg;
372d25bfb3bSDavid du Colombier
373d25bfb3bSDavid du Colombier Lock tlock; /* transmit */
374d25bfb3bSDavid du Colombier Desc* td;
375d25bfb3bSDavid du Colombier int ntd;
376d25bfb3bSDavid du Colombier int tdh;
377d25bfb3bSDavid du Colombier int tdt;
378d25bfb3bSDavid du Colombier int ntq;
379d25bfb3bSDavid du Colombier int txcfg;
380d25bfb3bSDavid du Colombier
381d25bfb3bSDavid du Colombier int rxidle;
382d25bfb3bSDavid du Colombier
383d25bfb3bSDavid du Colombier uint mibd[Nmibd];
384d25bfb3bSDavid du Colombier
385d25bfb3bSDavid du Colombier int ec;
386d25bfb3bSDavid du Colombier int owc;
387d25bfb3bSDavid du Colombier int ed;
388d25bfb3bSDavid du Colombier int crs;
389d25bfb3bSDavid du Colombier int tfu;
390d25bfb3bSDavid du Colombier int txa;
391d25bfb3bSDavid du Colombier } Ctlr;
392d25bfb3bSDavid du Colombier
393d25bfb3bSDavid du Colombier #define csr32r(c, r) (*((c)->nic+((r)/4)))
394d25bfb3bSDavid du Colombier #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
395d25bfb3bSDavid du Colombier
396d25bfb3bSDavid du Colombier static Ctlr* dp83820ctlrhead;
397d25bfb3bSDavid du Colombier static Ctlr* dp83820ctlrtail;
398d25bfb3bSDavid du Colombier
399d25bfb3bSDavid du Colombier static Lock dp83820rblock; /* free receive Blocks */
400d25bfb3bSDavid du Colombier static Block* dp83820rbpool;
401d25bfb3bSDavid du Colombier
402d25bfb3bSDavid du Colombier static char* dp83820mibs[Nmibd] = {
403d25bfb3bSDavid du Colombier "RXErroredPkts",
404d25bfb3bSDavid du Colombier "RXFCSErrors",
405d25bfb3bSDavid du Colombier "RXMsdPktErrors",
406d25bfb3bSDavid du Colombier "RXFAErrors",
407d25bfb3bSDavid du Colombier "RXSymbolErrors",
408d25bfb3bSDavid du Colombier "RXFrameToLong",
409d25bfb3bSDavid du Colombier "RXIRLErrors",
410d25bfb3bSDavid du Colombier "RXBadOpcodes",
411d25bfb3bSDavid du Colombier "RXPauseFrames",
412d25bfb3bSDavid du Colombier "TXPauseFrames",
413d25bfb3bSDavid du Colombier "TXSQEErrors",
414d25bfb3bSDavid du Colombier };
415d25bfb3bSDavid du Colombier
416d25bfb3bSDavid du Colombier static int
mdior(Ctlr * ctlr,int n)417d25bfb3bSDavid du Colombier mdior(Ctlr* ctlr, int n)
418d25bfb3bSDavid du Colombier {
419d25bfb3bSDavid du Colombier int data, i, mear, r;
420d25bfb3bSDavid du Colombier
421d25bfb3bSDavid du Colombier mear = csr32r(ctlr, Mear);
422d25bfb3bSDavid du Colombier r = ~(Mdc|Mddir) & mear;
423d25bfb3bSDavid du Colombier data = 0;
424d25bfb3bSDavid du Colombier for(i = n-1; i >= 0; i--){
425d25bfb3bSDavid du Colombier if(csr32r(ctlr, Mear) & Mdio)
426d25bfb3bSDavid du Colombier data |= (1<<i);
427d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, Mdc|r);
428d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
429d25bfb3bSDavid du Colombier }
430d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, mear);
431d25bfb3bSDavid du Colombier
432d25bfb3bSDavid du Colombier return data;
433d25bfb3bSDavid du Colombier }
434d25bfb3bSDavid du Colombier
435d25bfb3bSDavid du Colombier static void
mdiow(Ctlr * ctlr,int bits,int n)436d25bfb3bSDavid du Colombier mdiow(Ctlr* ctlr, int bits, int n)
437d25bfb3bSDavid du Colombier {
438d25bfb3bSDavid du Colombier int i, mear, r;
439d25bfb3bSDavid du Colombier
440d25bfb3bSDavid du Colombier mear = csr32r(ctlr, Mear);
441d25bfb3bSDavid du Colombier r = Mddir|(~Mdc & mear);
442d25bfb3bSDavid du Colombier for(i = n-1; i >= 0; i--){
443d25bfb3bSDavid du Colombier if(bits & (1<<i))
444d25bfb3bSDavid du Colombier r |= Mdio;
445d25bfb3bSDavid du Colombier else
446d25bfb3bSDavid du Colombier r &= ~Mdio;
447d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
448d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, Mdc|r);
449d25bfb3bSDavid du Colombier }
450d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, mear);
451d25bfb3bSDavid du Colombier }
452d25bfb3bSDavid du Colombier
453d25bfb3bSDavid du Colombier static int
dp83820miimir(Mii * mii,int pa,int ra)454d25bfb3bSDavid du Colombier dp83820miimir(Mii* mii, int pa, int ra)
455d25bfb3bSDavid du Colombier {
456d25bfb3bSDavid du Colombier int data;
457d25bfb3bSDavid du Colombier Ctlr *ctlr;
458d25bfb3bSDavid du Colombier
459d25bfb3bSDavid du Colombier ctlr = mii->ctlr;
460d25bfb3bSDavid du Colombier
461d25bfb3bSDavid du Colombier /*
462d25bfb3bSDavid du Colombier * MII Management Interface Read.
463d25bfb3bSDavid du Colombier *
464d25bfb3bSDavid du Colombier * Preamble;
465d25bfb3bSDavid du Colombier * ST+OP+PA+RA;
466d25bfb3bSDavid du Colombier * LT + 16 data bits.
467d25bfb3bSDavid du Colombier */
468d25bfb3bSDavid du Colombier mdiow(ctlr, 0xFFFFFFFF, 32);
469d25bfb3bSDavid du Colombier mdiow(ctlr, 0x1800|(pa<<5)|ra, 14);
470d25bfb3bSDavid du Colombier data = mdior(ctlr, 18);
471d25bfb3bSDavid du Colombier
472d25bfb3bSDavid du Colombier if(data & 0x10000)
473d25bfb3bSDavid du Colombier return -1;
474d25bfb3bSDavid du Colombier
475d25bfb3bSDavid du Colombier return data & 0xFFFF;
476d25bfb3bSDavid du Colombier }
477d25bfb3bSDavid du Colombier
478d25bfb3bSDavid du Colombier static int
dp83820miimiw(Mii * mii,int pa,int ra,int data)479d25bfb3bSDavid du Colombier dp83820miimiw(Mii* mii, int pa, int ra, int data)
480d25bfb3bSDavid du Colombier {
481d25bfb3bSDavid du Colombier Ctlr *ctlr;
482d25bfb3bSDavid du Colombier
483d25bfb3bSDavid du Colombier ctlr = mii->ctlr;
484d25bfb3bSDavid du Colombier
485d25bfb3bSDavid du Colombier /*
486d25bfb3bSDavid du Colombier * MII Management Interface Write.
487d25bfb3bSDavid du Colombier *
488d25bfb3bSDavid du Colombier * Preamble;
489d25bfb3bSDavid du Colombier * ST+OP+PA+RA+LT + 16 data bits;
490d25bfb3bSDavid du Colombier * Z.
491d25bfb3bSDavid du Colombier */
492d25bfb3bSDavid du Colombier mdiow(ctlr, 0xFFFFFFFF, 32);
493d25bfb3bSDavid du Colombier data &= 0xFFFF;
494d25bfb3bSDavid du Colombier data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16);
495d25bfb3bSDavid du Colombier mdiow(ctlr, data, 32);
496d25bfb3bSDavid du Colombier
497d25bfb3bSDavid du Colombier return 0;
498d25bfb3bSDavid du Colombier }
499d25bfb3bSDavid du Colombier
500d25bfb3bSDavid du Colombier static Block *
dp83820rballoc(Desc * desc)501d25bfb3bSDavid du Colombier dp83820rballoc(Desc* desc)
502d25bfb3bSDavid du Colombier {
503d25bfb3bSDavid du Colombier Block *bp;
504d25bfb3bSDavid du Colombier
505d25bfb3bSDavid du Colombier if(desc->bp == nil){
506d25bfb3bSDavid du Colombier ilock(&dp83820rblock);
507d25bfb3bSDavid du Colombier if((bp = dp83820rbpool) == nil){
508d25bfb3bSDavid du Colombier iunlock(&dp83820rblock);
509d25bfb3bSDavid du Colombier desc->bp = nil;
510d25bfb3bSDavid du Colombier desc->cmdsts = Own;
511d25bfb3bSDavid du Colombier return nil;
512d25bfb3bSDavid du Colombier }
513d25bfb3bSDavid du Colombier dp83820rbpool = bp->next;
514d25bfb3bSDavid du Colombier bp->next = nil;
515b8a11165SDavid du Colombier _xinc(&bp->ref); /* prevent bp from being freed */
516d25bfb3bSDavid du Colombier iunlock(&dp83820rblock);
517d25bfb3bSDavid du Colombier
518d25bfb3bSDavid du Colombier desc->bufptr = PCIWADDR(bp->rp);
519d25bfb3bSDavid du Colombier desc->bp = bp;
520d25bfb3bSDavid du Colombier }
521d25bfb3bSDavid du Colombier else{
522d25bfb3bSDavid du Colombier bp = desc->bp;
523d25bfb3bSDavid du Colombier bp->rp = bp->lim - Rbsz;
524d25bfb3bSDavid du Colombier bp->wp = bp->rp;
525d25bfb3bSDavid du Colombier }
526d25bfb3bSDavid du Colombier
527d25bfb3bSDavid du Colombier coherence();
528d25bfb3bSDavid du Colombier desc->cmdsts = Intr|Rbsz;
529d25bfb3bSDavid du Colombier
530d25bfb3bSDavid du Colombier return bp;
531d25bfb3bSDavid du Colombier }
532d25bfb3bSDavid du Colombier
533d25bfb3bSDavid du Colombier static void
dp83820rbfree(Block * bp)534d25bfb3bSDavid du Colombier dp83820rbfree(Block *bp)
535d25bfb3bSDavid du Colombier {
536d25bfb3bSDavid du Colombier bp->rp = bp->lim - Rbsz;
537d25bfb3bSDavid du Colombier bp->wp = bp->rp;
538d25bfb3bSDavid du Colombier
539d25bfb3bSDavid du Colombier ilock(&dp83820rblock);
540d25bfb3bSDavid du Colombier bp->next = dp83820rbpool;
541d25bfb3bSDavid du Colombier dp83820rbpool = bp;
542d25bfb3bSDavid du Colombier iunlock(&dp83820rblock);
543d25bfb3bSDavid du Colombier }
544d25bfb3bSDavid du Colombier
545d25bfb3bSDavid du Colombier static void
dp83820halt(Ctlr * ctlr)546d25bfb3bSDavid du Colombier dp83820halt(Ctlr* ctlr)
547d25bfb3bSDavid du Colombier {
548d25bfb3bSDavid du Colombier int i, timeo;
549d25bfb3bSDavid du Colombier
550d25bfb3bSDavid du Colombier ilock(&ctlr->ilock);
551d25bfb3bSDavid du Colombier csr32w(ctlr, Imr, 0);
552d25bfb3bSDavid du Colombier csr32w(ctlr, Ier, 0);
553d25bfb3bSDavid du Colombier csr32w(ctlr, Cr, Rxd|Txd);
554d25bfb3bSDavid du Colombier for(timeo = 0; timeo < 1000; timeo++){
555d25bfb3bSDavid du Colombier if(!(csr32r(ctlr, Cr) & (Rxe|Txe)))
556d25bfb3bSDavid du Colombier break;
557d25bfb3bSDavid du Colombier microdelay(1);
558d25bfb3bSDavid du Colombier }
559d25bfb3bSDavid du Colombier csr32w(ctlr, Mibc, Frz);
560d25bfb3bSDavid du Colombier iunlock(&ctlr->ilock);
561d25bfb3bSDavid du Colombier
562d25bfb3bSDavid du Colombier if(ctlr->rd != nil){
563d25bfb3bSDavid du Colombier for(i = 0; i < ctlr->nrd; i++){
564d25bfb3bSDavid du Colombier if(ctlr->rd[i].bp == nil)
565d25bfb3bSDavid du Colombier continue;
566d25bfb3bSDavid du Colombier freeb(ctlr->rd[i].bp);
567d25bfb3bSDavid du Colombier ctlr->rd[i].bp = nil;
568d25bfb3bSDavid du Colombier }
569d25bfb3bSDavid du Colombier }
570d25bfb3bSDavid du Colombier if(ctlr->td != nil){
571d25bfb3bSDavid du Colombier for(i = 0; i < ctlr->ntd; i++){
572d25bfb3bSDavid du Colombier if(ctlr->td[i].bp == nil)
573d25bfb3bSDavid du Colombier continue;
574d25bfb3bSDavid du Colombier freeb(ctlr->td[i].bp);
575d25bfb3bSDavid du Colombier ctlr->td[i].bp = nil;
576d25bfb3bSDavid du Colombier }
577d25bfb3bSDavid du Colombier }
578d25bfb3bSDavid du Colombier }
579d25bfb3bSDavid du Colombier
580d25bfb3bSDavid du Colombier static void
dp83820cfg(Ctlr * ctlr)581d25bfb3bSDavid du Colombier dp83820cfg(Ctlr* ctlr)
582d25bfb3bSDavid du Colombier {
583d25bfb3bSDavid du Colombier int cfg;
584d25bfb3bSDavid du Colombier
585d25bfb3bSDavid du Colombier /*
586d25bfb3bSDavid du Colombier * Don't know how to deal with a TBI yet.
587d25bfb3bSDavid du Colombier */
588d25bfb3bSDavid du Colombier if(ctlr->mii == nil)
589d25bfb3bSDavid du Colombier return;
590d25bfb3bSDavid du Colombier
591d25bfb3bSDavid du Colombier /*
592d25bfb3bSDavid du Colombier * The polarity of these bits is at the mercy
593d25bfb3bSDavid du Colombier * of the board designer.
594d25bfb3bSDavid du Colombier * The correct answer for all speed and duplex questions
595d25bfb3bSDavid du Colombier * should be to query the phy.
596d25bfb3bSDavid du Colombier */
597d25bfb3bSDavid du Colombier cfg = csr32r(ctlr, Cfg);
598d25bfb3bSDavid du Colombier if(!(cfg & Dupsts)){
599d25bfb3bSDavid du Colombier ctlr->rxcfg |= Rxfd;
600d25bfb3bSDavid du Colombier ctlr->txcfg |= Csi|Hbi;
601d25bfb3bSDavid du Colombier iprint("83820: full duplex, ");
602d25bfb3bSDavid du Colombier }
603d25bfb3bSDavid du Colombier else{
604d25bfb3bSDavid du Colombier ctlr->rxcfg &= ~Rxfd;
605d25bfb3bSDavid du Colombier ctlr->txcfg &= ~(Csi|Hbi);
606d25bfb3bSDavid du Colombier iprint("83820: half duplex, ");
607d25bfb3bSDavid du Colombier }
608d25bfb3bSDavid du Colombier csr32w(ctlr, Rxcfg, ctlr->rxcfg);
609d25bfb3bSDavid du Colombier csr32w(ctlr, Txcfg, ctlr->txcfg);
610d25bfb3bSDavid du Colombier
611d25bfb3bSDavid du Colombier switch(cfg & (Spdsts1000|Spdsts100)){
612d25bfb3bSDavid du Colombier case Spdsts1000: /* 100Mbps */
613d25bfb3bSDavid du Colombier default: /* 10Mbps */
614d25bfb3bSDavid du Colombier ctlr->cfg &= ~Mode1000;
615d25bfb3bSDavid du Colombier if((cfg & (Spdsts1000|Spdsts100)) == Spdsts1000)
616d25bfb3bSDavid du Colombier iprint("100Mb/s\n");
617d25bfb3bSDavid du Colombier else
618d25bfb3bSDavid du Colombier iprint("10Mb/s\n");
619d25bfb3bSDavid du Colombier break;
620d25bfb3bSDavid du Colombier case Spdsts100: /* 1Gbps */
621d25bfb3bSDavid du Colombier ctlr->cfg |= Mode1000;
622d25bfb3bSDavid du Colombier iprint("1Gb/s\n");
623d25bfb3bSDavid du Colombier break;
624d25bfb3bSDavid du Colombier }
625d25bfb3bSDavid du Colombier csr32w(ctlr, Cfg, ctlr->cfg);
626d25bfb3bSDavid du Colombier }
627d25bfb3bSDavid du Colombier
628d25bfb3bSDavid du Colombier static void
dp83820init(Ether * edev)629d25bfb3bSDavid du Colombier dp83820init(Ether* edev)
630d25bfb3bSDavid du Colombier {
631d25bfb3bSDavid du Colombier int i;
632d25bfb3bSDavid du Colombier Ctlr *ctlr;
633d25bfb3bSDavid du Colombier Desc *desc;
634d25bfb3bSDavid du Colombier uchar *alloc;
635d25bfb3bSDavid du Colombier
636d25bfb3bSDavid du Colombier ctlr = edev->ctlr;
637d25bfb3bSDavid du Colombier
638d25bfb3bSDavid du Colombier dp83820halt(ctlr);
639d25bfb3bSDavid du Colombier
640d25bfb3bSDavid du Colombier /*
641d25bfb3bSDavid du Colombier * Receiver
642d25bfb3bSDavid du Colombier */
643d25bfb3bSDavid du Colombier alloc = (uchar*)ROUNDUP((ulong)ctlr->alloc, 8);
644d25bfb3bSDavid du Colombier ctlr->rd = (Desc*)alloc;
645d25bfb3bSDavid du Colombier alloc += ctlr->nrd*sizeof(Desc);
646d25bfb3bSDavid du Colombier memset(ctlr->rd, 0, ctlr->nrd*sizeof(Desc));
647d25bfb3bSDavid du Colombier ctlr->rdx = 0;
648d25bfb3bSDavid du Colombier for(i = 0; i < ctlr->nrd; i++){
649d25bfb3bSDavid du Colombier desc = &ctlr->rd[i];
650d25bfb3bSDavid du Colombier desc->link = PCIWADDR(&ctlr->rd[NEXT(i, ctlr->nrd)]);
651d25bfb3bSDavid du Colombier if(dp83820rballoc(desc) == nil)
652d25bfb3bSDavid du Colombier continue;
653d25bfb3bSDavid du Colombier }
654d25bfb3bSDavid du Colombier csr32w(ctlr, Rxdphi, 0);
655d25bfb3bSDavid du Colombier csr32w(ctlr, Rxdp, PCIWADDR(ctlr->rd));
656d25bfb3bSDavid du Colombier
657d25bfb3bSDavid du Colombier for(i = 0; i < Eaddrlen; i += 2){
658d25bfb3bSDavid du Colombier csr32w(ctlr, Rfcr, i);
659d25bfb3bSDavid du Colombier csr32w(ctlr, Rfdr, (edev->ea[i+1]<<8)|edev->ea[i]);
660d25bfb3bSDavid du Colombier }
661e183b1a6SDavid du Colombier csr32w(ctlr, Rfcr, Rfen|Aab|Aam|Apm);
662d25bfb3bSDavid du Colombier
663d25bfb3bSDavid du Colombier ctlr->rxcfg = Stripcrc|(((2*(ETHERMINTU+4))/8)<<RxdrthSHFT);
664d25bfb3bSDavid du Colombier ctlr->imr |= Rxorn|Rxidle|Rxearly|Rxdesc|Rxok;
665d25bfb3bSDavid du Colombier
666d25bfb3bSDavid du Colombier /*
667d25bfb3bSDavid du Colombier * Transmitter.
668d25bfb3bSDavid du Colombier */
669d25bfb3bSDavid du Colombier ctlr->td = (Desc*)alloc;
670d25bfb3bSDavid du Colombier memset(ctlr->td, 0, ctlr->ntd*sizeof(Desc));
671d25bfb3bSDavid du Colombier ctlr->tdh = ctlr->tdt = ctlr->ntq = 0;
672d25bfb3bSDavid du Colombier for(i = 0; i < ctlr->ntd; i++){
673d25bfb3bSDavid du Colombier desc = &ctlr->td[i];
674d25bfb3bSDavid du Colombier desc->link = PCIWADDR(&ctlr->td[NEXT(i, ctlr->ntd)]);
675d25bfb3bSDavid du Colombier }
676d25bfb3bSDavid du Colombier csr32w(ctlr, Txdphi, 0);
677d25bfb3bSDavid du Colombier csr32w(ctlr, Txdp, PCIWADDR(ctlr->td));
678d25bfb3bSDavid du Colombier
679d25bfb3bSDavid du Colombier ctlr->txcfg = Atp|(((2*(ETHERMINTU+4))/32)<<FlthSHFT)|((4096/32)<<TxdrthSHFT);
680d25bfb3bSDavid du Colombier ctlr->imr |= Txurn|Txidle|Txdesc|Txok;
681d25bfb3bSDavid du Colombier
682d25bfb3bSDavid du Colombier ilock(&ctlr->ilock);
683d25bfb3bSDavid du Colombier
684d25bfb3bSDavid du Colombier dp83820cfg(ctlr);
685d25bfb3bSDavid du Colombier
686d25bfb3bSDavid du Colombier csr32w(ctlr, Mibc, Aclr);
687d25bfb3bSDavid du Colombier ctlr->imr |= Mib;
688d25bfb3bSDavid du Colombier
689d25bfb3bSDavid du Colombier csr32w(ctlr, Imr, ctlr->imr);
690d25bfb3bSDavid du Colombier
691d25bfb3bSDavid du Colombier /* try coalescing adjacent interrupts; use hold-off interval of 100µs */
692d25bfb3bSDavid du Colombier csr32w(ctlr, Ihr, Ihctl|(1<<IhSHFT));
693d25bfb3bSDavid du Colombier
694d25bfb3bSDavid du Colombier csr32w(ctlr, Ier, Ien);
695d25bfb3bSDavid du Colombier csr32w(ctlr, Cr, Rxe|Txe);
696d25bfb3bSDavid du Colombier
697d25bfb3bSDavid du Colombier iunlock(&ctlr->ilock);
698d25bfb3bSDavid du Colombier }
699d25bfb3bSDavid du Colombier
700d25bfb3bSDavid du Colombier static void
dp83820attach(Ether * edev)701d25bfb3bSDavid du Colombier dp83820attach(Ether* edev)
702d25bfb3bSDavid du Colombier {
703d25bfb3bSDavid du Colombier Block *bp;
704d25bfb3bSDavid du Colombier Ctlr *ctlr;
705d25bfb3bSDavid du Colombier
706d25bfb3bSDavid du Colombier ctlr = edev->ctlr;
707d25bfb3bSDavid du Colombier qlock(&ctlr->alock);
708d25bfb3bSDavid du Colombier if(ctlr->alloc != nil){
709d25bfb3bSDavid du Colombier qunlock(&ctlr->alock);
710d25bfb3bSDavid du Colombier return;
711d25bfb3bSDavid du Colombier }
712d25bfb3bSDavid du Colombier
713d25bfb3bSDavid du Colombier if(waserror()){
714d25bfb3bSDavid du Colombier if(ctlr->mii != nil){
715d25bfb3bSDavid du Colombier free(ctlr->mii);
716d25bfb3bSDavid du Colombier ctlr->mii = nil;
717d25bfb3bSDavid du Colombier }
718d25bfb3bSDavid du Colombier if(ctlr->alloc != nil){
719d25bfb3bSDavid du Colombier free(ctlr->alloc);
720d25bfb3bSDavid du Colombier ctlr->alloc = nil;
721d25bfb3bSDavid du Colombier }
722d25bfb3bSDavid du Colombier qunlock(&ctlr->alock);
723d25bfb3bSDavid du Colombier nexterror();
724d25bfb3bSDavid du Colombier }
725d25bfb3bSDavid du Colombier
726d25bfb3bSDavid du Colombier if(!(ctlr->cfg & Tbien)){
727d25bfb3bSDavid du Colombier if((ctlr->mii = malloc(sizeof(Mii))) == nil)
728d25bfb3bSDavid du Colombier error(Enomem);
729d25bfb3bSDavid du Colombier ctlr->mii->ctlr = ctlr;
730d25bfb3bSDavid du Colombier ctlr->mii->mir = dp83820miimir;
731d25bfb3bSDavid du Colombier ctlr->mii->miw = dp83820miimiw;
732d25bfb3bSDavid du Colombier if(mii(ctlr->mii, ~0) == 0)
733d25bfb3bSDavid du Colombier error("no PHY");
734d25bfb3bSDavid du Colombier ctlr->cfg |= Dupstsien|Lnkstsien|Spdstsien;
735d25bfb3bSDavid du Colombier ctlr->imr |= Phy;
736d25bfb3bSDavid du Colombier }
737d25bfb3bSDavid du Colombier
738d25bfb3bSDavid du Colombier ctlr->nrd = Nrd;
739d25bfb3bSDavid du Colombier ctlr->nrb = Nrb;
740d25bfb3bSDavid du Colombier ctlr->ntd = Ntd;
741d25bfb3bSDavid du Colombier ctlr->alloc = mallocz((ctlr->nrd+ctlr->ntd)*sizeof(Desc) + 7, 0);
742d25bfb3bSDavid du Colombier if(ctlr->alloc == nil)
743d25bfb3bSDavid du Colombier error(Enomem);
744d25bfb3bSDavid du Colombier
745d25bfb3bSDavid du Colombier for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){
746d25bfb3bSDavid du Colombier if((bp = allocb(Rbsz)) == nil)
747d25bfb3bSDavid du Colombier break;
748d25bfb3bSDavid du Colombier bp->free = dp83820rbfree;
749d25bfb3bSDavid du Colombier dp83820rbfree(bp);
750d25bfb3bSDavid du Colombier }
751d25bfb3bSDavid du Colombier
752d25bfb3bSDavid du Colombier dp83820init(edev);
753d25bfb3bSDavid du Colombier
754d25bfb3bSDavid du Colombier qunlock(&ctlr->alock);
755d25bfb3bSDavid du Colombier poperror();
756d25bfb3bSDavid du Colombier }
757d25bfb3bSDavid du Colombier
758d25bfb3bSDavid du Colombier static void
dp83820transmit(Ether * edev)759d25bfb3bSDavid du Colombier dp83820transmit(Ether* edev)
760d25bfb3bSDavid du Colombier {
761d25bfb3bSDavid du Colombier Block *bp;
762d25bfb3bSDavid du Colombier Ctlr *ctlr;
763d25bfb3bSDavid du Colombier Desc *desc;
764d25bfb3bSDavid du Colombier int cmdsts, r, x;
765d25bfb3bSDavid du Colombier
766d25bfb3bSDavid du Colombier ctlr = edev->ctlr;
767d25bfb3bSDavid du Colombier
768d25bfb3bSDavid du Colombier ilock(&ctlr->tlock);
769d25bfb3bSDavid du Colombier
770d25bfb3bSDavid du Colombier bp = nil;
771d25bfb3bSDavid du Colombier for(x = ctlr->tdh; ctlr->ntq; x = NEXT(x, ctlr->ntd)){
772d25bfb3bSDavid du Colombier desc = &ctlr->td[x];
773d25bfb3bSDavid du Colombier if((cmdsts = desc->cmdsts) & Own)
774d25bfb3bSDavid du Colombier break;
775d25bfb3bSDavid du Colombier if(!(cmdsts & Ok)){
776d25bfb3bSDavid du Colombier if(cmdsts & Ec)
777d25bfb3bSDavid du Colombier ctlr->ec++;
778d25bfb3bSDavid du Colombier if(cmdsts & Owc)
779d25bfb3bSDavid du Colombier ctlr->owc++;
780d25bfb3bSDavid du Colombier if(cmdsts & Ed)
781d25bfb3bSDavid du Colombier ctlr->ed++;
782d25bfb3bSDavid du Colombier if(cmdsts & Crs)
783d25bfb3bSDavid du Colombier ctlr->crs++;
784d25bfb3bSDavid du Colombier if(cmdsts & Tfu)
785d25bfb3bSDavid du Colombier ctlr->tfu++;
786d25bfb3bSDavid du Colombier if(cmdsts & Txa)
787d25bfb3bSDavid du Colombier ctlr->txa++;
788d25bfb3bSDavid du Colombier edev->oerrs++;
789d25bfb3bSDavid du Colombier }
790d25bfb3bSDavid du Colombier desc->bp->next = bp;
791d25bfb3bSDavid du Colombier bp = desc->bp;
792d25bfb3bSDavid du Colombier desc->bp = nil;
793d25bfb3bSDavid du Colombier
794d25bfb3bSDavid du Colombier ctlr->ntq--;
795d25bfb3bSDavid du Colombier }
796d25bfb3bSDavid du Colombier ctlr->tdh = x;
797d25bfb3bSDavid du Colombier if(bp != nil)
798d25bfb3bSDavid du Colombier freeblist(bp);
799d25bfb3bSDavid du Colombier
800d25bfb3bSDavid du Colombier x = ctlr->tdt;
801d25bfb3bSDavid du Colombier while(ctlr->ntq < (ctlr->ntd-1)){
802d25bfb3bSDavid du Colombier if((bp = qget(edev->oq)) == nil)
803d25bfb3bSDavid du Colombier break;
804d25bfb3bSDavid du Colombier
805d25bfb3bSDavid du Colombier desc = &ctlr->td[x];
806d25bfb3bSDavid du Colombier desc->bufptr = PCIWADDR(bp->rp);
807d25bfb3bSDavid du Colombier desc->bp = bp;
808d25bfb3bSDavid du Colombier ctlr->ntq++;
809d25bfb3bSDavid du Colombier coherence();
810d25bfb3bSDavid du Colombier desc->cmdsts = Own|Intr|BLEN(bp);
811d25bfb3bSDavid du Colombier
812d25bfb3bSDavid du Colombier x = NEXT(x, ctlr->ntd);
813d25bfb3bSDavid du Colombier }
814d25bfb3bSDavid du Colombier if(x != ctlr->tdt){
815d25bfb3bSDavid du Colombier ctlr->tdt = x;
816d25bfb3bSDavid du Colombier r = csr32r(ctlr, Cr);
817d25bfb3bSDavid du Colombier csr32w(ctlr, Cr, Txe|r);
818d25bfb3bSDavid du Colombier }
819d25bfb3bSDavid du Colombier
820d25bfb3bSDavid du Colombier iunlock(&ctlr->tlock);
821d25bfb3bSDavid du Colombier }
822d25bfb3bSDavid du Colombier
823d25bfb3bSDavid du Colombier static void
dp83820interrupt(Ureg *,void * arg)824d25bfb3bSDavid du Colombier dp83820interrupt(Ureg*, void* arg)
825d25bfb3bSDavid du Colombier {
826d25bfb3bSDavid du Colombier Block *bp;
827d25bfb3bSDavid du Colombier Ctlr *ctlr;
828d25bfb3bSDavid du Colombier Desc *desc;
829d25bfb3bSDavid du Colombier Ether *edev;
830d25bfb3bSDavid du Colombier int cmdsts, i, isr, r, x;
831d25bfb3bSDavid du Colombier
832d25bfb3bSDavid du Colombier edev = arg;
833d25bfb3bSDavid du Colombier ctlr = edev->ctlr;
834d25bfb3bSDavid du Colombier
835d25bfb3bSDavid du Colombier for(isr = csr32r(ctlr, Isr); isr & ctlr->imr; isr = csr32r(ctlr, Isr)){
836d25bfb3bSDavid du Colombier if(isr & (Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok)){
837d25bfb3bSDavid du Colombier x = ctlr->rdx;
838d25bfb3bSDavid du Colombier desc = &ctlr->rd[x];
839d25bfb3bSDavid du Colombier while((cmdsts = desc->cmdsts) & Own){
840d25bfb3bSDavid du Colombier if((cmdsts & Ok) && desc->bp != nil){
841d25bfb3bSDavid du Colombier bp = desc->bp;
842d25bfb3bSDavid du Colombier desc->bp = nil;
843d25bfb3bSDavid du Colombier bp->wp += cmdsts & SizeMASK;
844d25bfb3bSDavid du Colombier etheriq(edev, bp, 1);
845d25bfb3bSDavid du Colombier }
84641dd6b47SDavid du Colombier else if(0 && !(cmdsts & Ok)){
84741dd6b47SDavid du Colombier iprint("dp83820: rx %8.8uX:", cmdsts);
84841dd6b47SDavid du Colombier bp = desc->bp;
84941dd6b47SDavid du Colombier for(i = 0; i < 20; i++)
85041dd6b47SDavid du Colombier iprint(" %2.2uX", bp->rp[i]);
85141dd6b47SDavid du Colombier iprint("\n");
85241dd6b47SDavid du Colombier }
853d25bfb3bSDavid du Colombier dp83820rballoc(desc);
854d25bfb3bSDavid du Colombier
855d25bfb3bSDavid du Colombier x = NEXT(x, ctlr->nrd);
856d25bfb3bSDavid du Colombier desc = &ctlr->rd[x];
857d25bfb3bSDavid du Colombier }
858d25bfb3bSDavid du Colombier ctlr->rdx = x;
859d25bfb3bSDavid du Colombier
860d25bfb3bSDavid du Colombier if(isr & Rxidle){
861d25bfb3bSDavid du Colombier r = csr32r(ctlr, Cr);
862d25bfb3bSDavid du Colombier csr32w(ctlr, Cr, Rxe|r);
863d25bfb3bSDavid du Colombier ctlr->rxidle++;
864d25bfb3bSDavid du Colombier }
865d25bfb3bSDavid du Colombier
866d25bfb3bSDavid du Colombier isr &= ~(Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok);
867d25bfb3bSDavid du Colombier }
868d25bfb3bSDavid du Colombier
869d25bfb3bSDavid du Colombier if(isr & Txurn){
870d25bfb3bSDavid du Colombier x = (ctlr->txcfg & TxdrthMASK)>>TxdrthSHFT;
871d25bfb3bSDavid du Colombier r = (ctlr->txcfg & FlthMASK)>>FlthSHFT;
872d25bfb3bSDavid du Colombier if(x < ((TxdrthMASK)>>TxdrthSHFT)
873d25bfb3bSDavid du Colombier && x < (2048/32 - r)){
874d25bfb3bSDavid du Colombier ctlr->txcfg &= ~TxdrthMASK;
875d25bfb3bSDavid du Colombier x++;
876d25bfb3bSDavid du Colombier ctlr->txcfg |= x<<TxdrthSHFT;
877d25bfb3bSDavid du Colombier csr32w(ctlr, Txcfg, ctlr->txcfg);
878d25bfb3bSDavid du Colombier }
879d25bfb3bSDavid du Colombier }
880d25bfb3bSDavid du Colombier
881d25bfb3bSDavid du Colombier if(isr & (Txurn|Txidle|Txdesc|Txok)){
882d25bfb3bSDavid du Colombier dp83820transmit(edev);
883d25bfb3bSDavid du Colombier isr &= ~(Txurn|Txidle|Txdesc|Txok);
884d25bfb3bSDavid du Colombier }
885d25bfb3bSDavid du Colombier
886d25bfb3bSDavid du Colombier if(isr & Mib){
887d25bfb3bSDavid du Colombier for(i = 0; i < Nmibd; i++){
888d25bfb3bSDavid du Colombier r = csr32r(ctlr, Mibd+(i*sizeof(int)));
889d25bfb3bSDavid du Colombier ctlr->mibd[i] += r & 0xFFFF;
890d25bfb3bSDavid du Colombier }
891d25bfb3bSDavid du Colombier isr &= ~Mib;
892d25bfb3bSDavid du Colombier }
893d25bfb3bSDavid du Colombier
894d25bfb3bSDavid du Colombier if((isr & Phy) && ctlr->mii != nil){
895d25bfb3bSDavid du Colombier ctlr->mii->mir(ctlr->mii, 1, Bmsr);
896d25bfb3bSDavid du Colombier print("phy: cfg %8.8uX bmsr %4.4uX\n",
897d25bfb3bSDavid du Colombier csr32r(ctlr, Cfg),
898d25bfb3bSDavid du Colombier ctlr->mii->mir(ctlr->mii, 1, Bmsr));
899d25bfb3bSDavid du Colombier dp83820cfg(ctlr);
900d25bfb3bSDavid du Colombier isr &= ~Phy;
901d25bfb3bSDavid du Colombier }
902d25bfb3bSDavid du Colombier if(isr)
903d25bfb3bSDavid du Colombier iprint("dp83820: isr %8.8uX\n", isr);
904d25bfb3bSDavid du Colombier }
905d25bfb3bSDavid du Colombier }
906d25bfb3bSDavid du Colombier
907d25bfb3bSDavid du Colombier static long
dp83820ifstat(Ether * edev,void * a,long n,ulong offset)908d25bfb3bSDavid du Colombier dp83820ifstat(Ether* edev, void* a, long n, ulong offset)
909d25bfb3bSDavid du Colombier {
910d25bfb3bSDavid du Colombier char *p;
911d25bfb3bSDavid du Colombier Ctlr *ctlr;
912d25bfb3bSDavid du Colombier int i, l, r;
913d25bfb3bSDavid du Colombier
914d25bfb3bSDavid du Colombier ctlr = edev->ctlr;
915d25bfb3bSDavid du Colombier
916d25bfb3bSDavid du Colombier edev->crcs = ctlr->mibd[Mibd+(1*sizeof(int))];
917d25bfb3bSDavid du Colombier edev->frames = ctlr->mibd[Mibd+(3*sizeof(int))];
918d25bfb3bSDavid du Colombier edev->buffs = ctlr->mibd[Mibd+(5*sizeof(int))];
919d25bfb3bSDavid du Colombier edev->overflows = ctlr->mibd[Mibd+(2*sizeof(int))];
920d25bfb3bSDavid du Colombier
921d25bfb3bSDavid du Colombier if(n == 0)
922d25bfb3bSDavid du Colombier return 0;
923d25bfb3bSDavid du Colombier
924d25bfb3bSDavid du Colombier p = malloc(READSTR);
925aa72973aSDavid du Colombier if(p == nil)
926aa72973aSDavid du Colombier error(Enomem);
927d25bfb3bSDavid du Colombier l = 0;
928d25bfb3bSDavid du Colombier for(i = 0; i < Nmibd; i++){
929d25bfb3bSDavid du Colombier r = csr32r(ctlr, Mibd+(i*sizeof(int)));
930d25bfb3bSDavid du Colombier ctlr->mibd[i] += r & 0xFFFF;
931d25bfb3bSDavid du Colombier if(ctlr->mibd[i] != 0 && dp83820mibs[i] != nil)
932d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "%s: %ud %ud\n",
933d25bfb3bSDavid du Colombier dp83820mibs[i], ctlr->mibd[i], r);
934d25bfb3bSDavid du Colombier }
935d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "rxidle %d\n", ctlr->rxidle);
936d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "ec %d\n", ctlr->ec);
937d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "owc %d\n", ctlr->owc);
938d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "ed %d\n", ctlr->ed);
939d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "crs %d\n", ctlr->crs);
940d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "tfu %d\n", ctlr->tfu);
941d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "txa %d\n", ctlr->txa);
942d25bfb3bSDavid du Colombier
943d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR, "rom:");
944d25bfb3bSDavid du Colombier for(i = 0; i < 0x10; i++){
945d25bfb3bSDavid du Colombier if(i && ((i & 0x07) == 0))
946d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "\n ");
947d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->eeprom[i]);
948d25bfb3bSDavid du Colombier }
949d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "\n");
950d25bfb3bSDavid du Colombier
951d25bfb3bSDavid du Colombier if(ctlr->mii != nil && ctlr->mii->curphy != nil){
952d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR, "phy:");
953d25bfb3bSDavid du Colombier for(i = 0; i < NMiiPhyr; i++){
954d25bfb3bSDavid du Colombier if(i && ((i & 0x07) == 0))
955d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, "\n ");
956d25bfb3bSDavid du Colombier r = miimir(ctlr->mii, i);
957d25bfb3bSDavid du Colombier l += snprint(p+l, READSTR-l, " %4.4uX", r);
958d25bfb3bSDavid du Colombier }
959d25bfb3bSDavid du Colombier snprint(p+l, READSTR-l, "\n");
960d25bfb3bSDavid du Colombier }
961d25bfb3bSDavid du Colombier
962d25bfb3bSDavid du Colombier n = readstr(offset, a, n, p);
963d25bfb3bSDavid du Colombier free(p);
964d25bfb3bSDavid du Colombier
965d25bfb3bSDavid du Colombier return n;
966d25bfb3bSDavid du Colombier }
967d25bfb3bSDavid du Colombier
968d25bfb3bSDavid du Colombier static void
dp83820promiscuous(void * arg,int on)969d25bfb3bSDavid du Colombier dp83820promiscuous(void* arg, int on)
970d25bfb3bSDavid du Colombier {
971d25bfb3bSDavid du Colombier USED(arg, on);
972d25bfb3bSDavid du Colombier }
973d25bfb3bSDavid du Colombier
974e183b1a6SDavid du Colombier /* multicast already on, don't need to do anything */
975e183b1a6SDavid du Colombier static void
dp83820multicast(void *,uchar *,int)976e183b1a6SDavid du Colombier dp83820multicast(void*, uchar*, int)
977e183b1a6SDavid du Colombier {
978e183b1a6SDavid du Colombier }
979e183b1a6SDavid du Colombier
980d25bfb3bSDavid du Colombier static int
dp83820detach(Ctlr * ctlr)981e1f2c6e8SDavid du Colombier dp83820detach(Ctlr* ctlr)
982e1f2c6e8SDavid du Colombier {
983e1f2c6e8SDavid du Colombier /*
984e1f2c6e8SDavid du Colombier * Soft reset the controller.
985e1f2c6e8SDavid du Colombier */
986e1f2c6e8SDavid du Colombier csr32w(ctlr, Cr, Rst);
987e1f2c6e8SDavid du Colombier delay(1);
988e1f2c6e8SDavid du Colombier while(csr32r(ctlr, Cr) & Rst)
989e1f2c6e8SDavid du Colombier delay(1);
990e1f2c6e8SDavid du Colombier return 0;
991e1f2c6e8SDavid du Colombier }
992e1f2c6e8SDavid du Colombier
993e1f2c6e8SDavid du Colombier static void
dp83820shutdown(Ether * ether)994e1f2c6e8SDavid du Colombier dp83820shutdown(Ether* ether)
995e1f2c6e8SDavid du Colombier {
996e1f2c6e8SDavid du Colombier print("dp83820shutdown\n");
997e1f2c6e8SDavid du Colombier dp83820detach(ether->ctlr);
998e1f2c6e8SDavid du Colombier }
999e1f2c6e8SDavid du Colombier
1000e1f2c6e8SDavid du Colombier static int
atc93c46r(Ctlr * ctlr,int address)1001d25bfb3bSDavid du Colombier atc93c46r(Ctlr* ctlr, int address)
1002d25bfb3bSDavid du Colombier {
1003d25bfb3bSDavid du Colombier int data, i, mear, r, size;
1004d25bfb3bSDavid du Colombier
1005d25bfb3bSDavid du Colombier /*
1006d25bfb3bSDavid du Colombier * Analog Technology, Inc. ATC93C46
1007d25bfb3bSDavid du Colombier * or equivalent serial EEPROM.
1008d25bfb3bSDavid du Colombier */
1009d25bfb3bSDavid du Colombier mear = csr32r(ctlr, Mear);
1010d25bfb3bSDavid du Colombier mear &= ~(Eesel|Eeclk|Eedo|Eedi);
1011d25bfb3bSDavid du Colombier r = Eesel|mear;
1012d25bfb3bSDavid du Colombier
1013d25bfb3bSDavid du Colombier reread:
1014d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
1015d25bfb3bSDavid du Colombier data = 0x06;
1016d25bfb3bSDavid du Colombier for(i = 3-1; i >= 0; i--){
1017d25bfb3bSDavid du Colombier if(data & (1<<i))
1018d25bfb3bSDavid du Colombier r |= Eedi;
1019d25bfb3bSDavid du Colombier else
1020d25bfb3bSDavid du Colombier r &= ~Eedi;
1021d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
1022d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, Eeclk|r);
1023d25bfb3bSDavid du Colombier microdelay(1);
1024d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
1025d25bfb3bSDavid du Colombier microdelay(1);
1026d25bfb3bSDavid du Colombier }
1027d25bfb3bSDavid du Colombier
1028d25bfb3bSDavid du Colombier /*
1029d25bfb3bSDavid du Colombier * First time through must work out the EEPROM size.
1030d25bfb3bSDavid du Colombier */
1031d25bfb3bSDavid du Colombier if((size = ctlr->eepromsz) == 0)
1032d25bfb3bSDavid du Colombier size = 8;
1033d25bfb3bSDavid du Colombier
1034d25bfb3bSDavid du Colombier for(size = size-1; size >= 0; size--){
1035d25bfb3bSDavid du Colombier if(address & (1<<size))
1036d25bfb3bSDavid du Colombier r |= Eedi;
1037d25bfb3bSDavid du Colombier else
1038d25bfb3bSDavid du Colombier r &= ~Eedi;
1039d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
1040d25bfb3bSDavid du Colombier microdelay(1);
1041d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, Eeclk|r);
1042d25bfb3bSDavid du Colombier microdelay(1);
1043d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
1044d25bfb3bSDavid du Colombier microdelay(1);
1045d25bfb3bSDavid du Colombier if(!(csr32r(ctlr, Mear) & Eedo))
1046d25bfb3bSDavid du Colombier break;
1047d25bfb3bSDavid du Colombier }
1048d25bfb3bSDavid du Colombier r &= ~Eedi;
1049d25bfb3bSDavid du Colombier
1050d25bfb3bSDavid du Colombier data = 0;
1051d25bfb3bSDavid du Colombier for(i = 16-1; i >= 0; i--){
1052d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, Eeclk|r);
1053d25bfb3bSDavid du Colombier microdelay(1);
1054d25bfb3bSDavid du Colombier if(csr32r(ctlr, Mear) & Eedo)
1055d25bfb3bSDavid du Colombier data |= (1<<i);
1056d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, r);
1057d25bfb3bSDavid du Colombier microdelay(1);
1058d25bfb3bSDavid du Colombier }
1059d25bfb3bSDavid du Colombier
1060d25bfb3bSDavid du Colombier csr32w(ctlr, Mear, mear);
1061d25bfb3bSDavid du Colombier
1062d25bfb3bSDavid du Colombier if(ctlr->eepromsz == 0){
1063d25bfb3bSDavid du Colombier ctlr->eepromsz = 8-size;
1064d25bfb3bSDavid du Colombier ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));
1065aa72973aSDavid du Colombier if(ctlr->eeprom == nil)
1066aa72973aSDavid du Colombier error(Enomem);
1067d25bfb3bSDavid du Colombier goto reread;
1068d25bfb3bSDavid du Colombier }
1069d25bfb3bSDavid du Colombier
1070d25bfb3bSDavid du Colombier return data;
1071d25bfb3bSDavid du Colombier }
1072d25bfb3bSDavid du Colombier
1073d25bfb3bSDavid du Colombier static int
dp83820reset(Ctlr * ctlr)1074d25bfb3bSDavid du Colombier dp83820reset(Ctlr* ctlr)
1075d25bfb3bSDavid du Colombier {
1076d25bfb3bSDavid du Colombier int i, r;
1077d25bfb3bSDavid du Colombier unsigned char sum;
1078d25bfb3bSDavid du Colombier
1079d25bfb3bSDavid du Colombier /*
1080d25bfb3bSDavid du Colombier * Soft reset the controller;
1081d25bfb3bSDavid du Colombier * read the EEPROM to get the initial settings
1082d25bfb3bSDavid du Colombier * of the Cfg and Gpior bits which should be cleared by
1083d25bfb3bSDavid du Colombier * the reset.
1084d25bfb3bSDavid du Colombier */
1085e1f2c6e8SDavid du Colombier dp83820detach(ctlr);
1086d25bfb3bSDavid du Colombier
1087d25bfb3bSDavid du Colombier atc93c46r(ctlr, 0);
1088e1f2c6e8SDavid du Colombier if(ctlr->eeprom == nil) {
1089e1f2c6e8SDavid du Colombier print("dp83820reset: no eeprom\n");
10904b348146SDavid du Colombier return -1;
1091e1f2c6e8SDavid du Colombier }
1092d25bfb3bSDavid du Colombier sum = 0;
1093d25bfb3bSDavid du Colombier for(i = 0; i < 0x0E; i++){
1094d25bfb3bSDavid du Colombier r = atc93c46r(ctlr, i);
1095d25bfb3bSDavid du Colombier ctlr->eeprom[i] = r;
1096d25bfb3bSDavid du Colombier sum += r;
1097d25bfb3bSDavid du Colombier sum += r>>8;
1098d25bfb3bSDavid du Colombier }
1099d25bfb3bSDavid du Colombier
1100d25bfb3bSDavid du Colombier if(sum != 0){
1101d25bfb3bSDavid du Colombier print("dp83820reset: bad EEPROM checksum\n");
1102d25bfb3bSDavid du Colombier return -1;
1103d25bfb3bSDavid du Colombier }
1104d25bfb3bSDavid du Colombier
1105d25bfb3bSDavid du Colombier #ifdef notdef
1106d25bfb3bSDavid du Colombier csr32w(ctlr, Gpior, ctlr->eeprom[4]);
1107d25bfb3bSDavid du Colombier
1108d25bfb3bSDavid du Colombier cfg = Extstsen|Exd;
1109d25bfb3bSDavid du Colombier r = csr32r(ctlr, Cfg);
1110d25bfb3bSDavid du Colombier if(ctlr->eeprom[5] & 0x0001)
1111d25bfb3bSDavid du Colombier cfg |= Ext125;
1112d25bfb3bSDavid du Colombier if(ctlr->eeprom[5] & 0x0002)
1113d25bfb3bSDavid du Colombier cfg |= M64addren;
1114d25bfb3bSDavid du Colombier if((ctlr->eeprom[5] & 0x0004) && (r & Pci64det))
1115d25bfb3bSDavid du Colombier cfg |= Data64en;
1116d25bfb3bSDavid du Colombier if(ctlr->eeprom[5] & 0x0008)
1117d25bfb3bSDavid du Colombier cfg |= T64addren;
1118d25bfb3bSDavid du Colombier if(!(pcicfgr16(ctlr->pcidev, PciPCR) & 0x10))
1119d25bfb3bSDavid du Colombier cfg |= Mwidis;
1120d25bfb3bSDavid du Colombier if(ctlr->eeprom[5] & 0x0020)
1121d25bfb3bSDavid du Colombier cfg |= Mrmdis;
1122d25bfb3bSDavid du Colombier if(ctlr->eeprom[5] & 0x0080)
1123d25bfb3bSDavid du Colombier cfg |= Mode1000;
1124d25bfb3bSDavid du Colombier if(ctlr->eeprom[5] & 0x0200)
1125d25bfb3bSDavid du Colombier cfg |= Tbien|Mode1000;
1126d25bfb3bSDavid du Colombier /*
1127d25bfb3bSDavid du Colombier * What about RO bits we might have destroyed with Rst?
1128d25bfb3bSDavid du Colombier * What about Exd, Tmrtest, Extstsen, Pintctl?
1129d25bfb3bSDavid du Colombier * Why does it think it has detected a 64-bit bus when
1130d25bfb3bSDavid du Colombier * it hasn't?
1131d25bfb3bSDavid du Colombier */
1132d25bfb3bSDavid du Colombier #else
1133d25bfb3bSDavid du Colombier // r = csr32r(ctlr, Cfg);
1134d25bfb3bSDavid du Colombier // r &= ~(Mode1000|T64addren|Data64en|M64addren);
1135d25bfb3bSDavid du Colombier // csr32w(ctlr, Cfg, r);
1136d25bfb3bSDavid du Colombier // csr32w(ctlr, Cfg, 0x2000);
1137d25bfb3bSDavid du Colombier #endif /* notdef */
1138d25bfb3bSDavid du Colombier ctlr->cfg = csr32r(ctlr, Cfg);
1139d25bfb3bSDavid du Colombier print("cfg %8.8uX pcicfg %8.8uX\n", ctlr->cfg, pcicfgr32(ctlr->pcidev, PciPCR));
1140d25bfb3bSDavid du Colombier ctlr->cfg &= ~(T64addren|Data64en|M64addren);
1141d25bfb3bSDavid du Colombier csr32w(ctlr, Cfg, ctlr->cfg);
1142d25bfb3bSDavid du Colombier csr32w(ctlr, Mibc, Aclr|Frz);
1143d25bfb3bSDavid du Colombier
1144d25bfb3bSDavid du Colombier return 0;
1145d25bfb3bSDavid du Colombier }
1146d25bfb3bSDavid du Colombier
1147d25bfb3bSDavid du Colombier static void
dp83820pci(void)1148d25bfb3bSDavid du Colombier dp83820pci(void)
1149d25bfb3bSDavid du Colombier {
11504de34a7eSDavid du Colombier void *mem;
1151d25bfb3bSDavid du Colombier Pcidev *p;
1152d25bfb3bSDavid du Colombier Ctlr *ctlr;
1153d25bfb3bSDavid du Colombier
1154d25bfb3bSDavid du Colombier p = nil;
1155d25bfb3bSDavid du Colombier while(p = pcimatch(p, 0, 0)){
1156e1f2c6e8SDavid du Colombier if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
1157d25bfb3bSDavid du Colombier continue;
1158d25bfb3bSDavid du Colombier
1159d25bfb3bSDavid du Colombier switch((p->did<<16)|p->vid){
1160d25bfb3bSDavid du Colombier default:
1161d25bfb3bSDavid du Colombier continue;
1162d25bfb3bSDavid du Colombier case (0x0022<<16)|0x100B: /* DP83820 (Gig-NIC) */
1163d25bfb3bSDavid du Colombier break;
1164d25bfb3bSDavid du Colombier }
1165d25bfb3bSDavid du Colombier
11664de34a7eSDavid du Colombier mem = vmap(p->mem[1].bar & ~0x0F, p->mem[1].size);
11674de34a7eSDavid du Colombier if(mem == 0){
1168d25bfb3bSDavid du Colombier print("DP83820: can't map %8.8luX\n", p->mem[1].bar);
1169d25bfb3bSDavid du Colombier continue;
1170d25bfb3bSDavid du Colombier }
1171d25bfb3bSDavid du Colombier
1172d25bfb3bSDavid du Colombier ctlr = malloc(sizeof(Ctlr));
1173aa72973aSDavid du Colombier if(ctlr == nil) {
1174aa72973aSDavid du Colombier vunmap(mem, p->mem[1].size);
1175aa72973aSDavid du Colombier error(Enomem);
1176aa72973aSDavid du Colombier }
11774de34a7eSDavid du Colombier ctlr->port = p->mem[1].bar & ~0x0F;
1178d25bfb3bSDavid du Colombier ctlr->pcidev = p;
1179d25bfb3bSDavid du Colombier ctlr->id = (p->did<<16)|p->vid;
1180d25bfb3bSDavid du Colombier
11814de34a7eSDavid du Colombier ctlr->nic = mem;
1182d25bfb3bSDavid du Colombier if(dp83820reset(ctlr)){
1183d25bfb3bSDavid du Colombier free(ctlr);
1184aa72973aSDavid du Colombier vunmap(mem, p->mem[1].size);
1185d25bfb3bSDavid du Colombier continue;
1186d25bfb3bSDavid du Colombier }
1187d25bfb3bSDavid du Colombier pcisetbme(p);
1188d25bfb3bSDavid du Colombier
1189d25bfb3bSDavid du Colombier if(dp83820ctlrhead != nil)
1190d25bfb3bSDavid du Colombier dp83820ctlrtail->next = ctlr;
1191d25bfb3bSDavid du Colombier else
1192d25bfb3bSDavid du Colombier dp83820ctlrhead = ctlr;
1193d25bfb3bSDavid du Colombier dp83820ctlrtail = ctlr;
1194d25bfb3bSDavid du Colombier }
1195d25bfb3bSDavid du Colombier }
1196d25bfb3bSDavid du Colombier
1197d25bfb3bSDavid du Colombier static int
dp83820pnp(Ether * edev)1198d25bfb3bSDavid du Colombier dp83820pnp(Ether* edev)
1199d25bfb3bSDavid du Colombier {
1200d25bfb3bSDavid du Colombier int i;
1201d25bfb3bSDavid du Colombier Ctlr *ctlr;
1202d25bfb3bSDavid du Colombier uchar ea[Eaddrlen];
1203d25bfb3bSDavid du Colombier
1204d25bfb3bSDavid du Colombier if(dp83820ctlrhead == nil)
1205d25bfb3bSDavid du Colombier dp83820pci();
1206d25bfb3bSDavid du Colombier
1207d25bfb3bSDavid du Colombier /*
1208d25bfb3bSDavid du Colombier * Any adapter matches if no edev->port is supplied,
1209d25bfb3bSDavid du Colombier * otherwise the ports must match.
1210d25bfb3bSDavid du Colombier */
1211d25bfb3bSDavid du Colombier for(ctlr = dp83820ctlrhead; ctlr != nil; ctlr = ctlr->next){
1212d25bfb3bSDavid du Colombier if(ctlr->active)
1213d25bfb3bSDavid du Colombier continue;
1214d25bfb3bSDavid du Colombier if(edev->port == 0 || edev->port == ctlr->port){
1215d25bfb3bSDavid du Colombier ctlr->active = 1;
1216d25bfb3bSDavid du Colombier break;
1217d25bfb3bSDavid du Colombier }
1218d25bfb3bSDavid du Colombier }
1219d25bfb3bSDavid du Colombier if(ctlr == nil)
1220d25bfb3bSDavid du Colombier return -1;
1221d25bfb3bSDavid du Colombier
1222d25bfb3bSDavid du Colombier edev->ctlr = ctlr;
1223d25bfb3bSDavid du Colombier edev->port = ctlr->port;
1224d25bfb3bSDavid du Colombier edev->irq = ctlr->pcidev->intl;
1225d25bfb3bSDavid du Colombier edev->tbdf = ctlr->pcidev->tbdf;
1226d25bfb3bSDavid du Colombier edev->mbps = 1000;
1227d25bfb3bSDavid du Colombier
1228d25bfb3bSDavid du Colombier /*
1229d25bfb3bSDavid du Colombier * Check if the adapter's station address is to be overridden.
1230d25bfb3bSDavid du Colombier * If not, read it from the EEPROM and set in ether->ea prior to
1231d25bfb3bSDavid du Colombier * loading the station address in the hardware.
1232d25bfb3bSDavid du Colombier */
1233d25bfb3bSDavid du Colombier memset(ea, 0, Eaddrlen);
1234e1f2c6e8SDavid du Colombier if(memcmp(ea, edev->ea, Eaddrlen) == 0)
1235d25bfb3bSDavid du Colombier for(i = 0; i < Eaddrlen/2; i++){
1236d25bfb3bSDavid du Colombier edev->ea[2*i] = ctlr->eeprom[0x0C-i];
1237d25bfb3bSDavid du Colombier edev->ea[2*i+1] = ctlr->eeprom[0x0C-i]>>8;
1238d25bfb3bSDavid du Colombier }
1239d25bfb3bSDavid du Colombier
1240d25bfb3bSDavid du Colombier edev->attach = dp83820attach;
1241d25bfb3bSDavid du Colombier edev->transmit = dp83820transmit;
1242d25bfb3bSDavid du Colombier edev->interrupt = dp83820interrupt;
1243d25bfb3bSDavid du Colombier edev->ifstat = dp83820ifstat;
1244d25bfb3bSDavid du Colombier
1245d25bfb3bSDavid du Colombier edev->arg = edev;
1246d25bfb3bSDavid du Colombier edev->promiscuous = dp83820promiscuous;
1247e183b1a6SDavid du Colombier edev->multicast = dp83820multicast;
1248e1f2c6e8SDavid du Colombier edev->shutdown = dp83820shutdown;
1249d25bfb3bSDavid du Colombier
1250d25bfb3bSDavid du Colombier return 0;
1251d25bfb3bSDavid du Colombier }
1252d25bfb3bSDavid du Colombier
1253d25bfb3bSDavid du Colombier void
etherdp83820link(void)1254d25bfb3bSDavid du Colombier etherdp83820link(void)
1255d25bfb3bSDavid du Colombier {
1256d25bfb3bSDavid du Colombier addethercard("DP83820", dp83820pnp);
1257d25bfb3bSDavid du Colombier }
1258