xref: /plan9/sys/src/9/pc/etherdp83820.c (revision cebd3b46303b6884206200c08c0d8b3fb8dc989e)
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