xref: /onnv-gate/usr/src/grub/grub-0.97/netboot/via-rhine.c (revision 8044:b3af80bbf173)
1*8044SWilliam.Kucharski@Sun.COM /* rhine.c:Fast Ethernet driver for Linux. */
2*8044SWilliam.Kucharski@Sun.COM /*
3*8044SWilliam.Kucharski@Sun.COM 	Adapted 09-jan-2000 by Paolo Marini (paolom@prisma-eng.it)
4*8044SWilliam.Kucharski@Sun.COM 
5*8044SWilliam.Kucharski@Sun.COM         originally written by Donald Becker.
6*8044SWilliam.Kucharski@Sun.COM 
7*8044SWilliam.Kucharski@Sun.COM 	This software may be used and distributed according to the terms
8*8044SWilliam.Kucharski@Sun.COM 	of the GNU Public License (GPL), incorporated herein by reference.
9*8044SWilliam.Kucharski@Sun.COM 	Drivers derived from this code also fall under the GPL and must retain
10*8044SWilliam.Kucharski@Sun.COM 	this authorship and copyright notice.
11*8044SWilliam.Kucharski@Sun.COM 
12*8044SWilliam.Kucharski@Sun.COM 	Under no circumstances are the authors responsible for
13*8044SWilliam.Kucharski@Sun.COM 	the proper functioning of this software, nor do the authors assume any
14*8044SWilliam.Kucharski@Sun.COM 	responsibility for damages incurred with its use.
15*8044SWilliam.Kucharski@Sun.COM 
16*8044SWilliam.Kucharski@Sun.COM 	This driver is designed for the VIA VT86C100A Rhine-II PCI Fast Ethernet
17*8044SWilliam.Kucharski@Sun.COM 	controller.
18*8044SWilliam.Kucharski@Sun.COM 
19*8044SWilliam.Kucharski@Sun.COM */
20*8044SWilliam.Kucharski@Sun.COM 
21*8044SWilliam.Kucharski@Sun.COM static const char *version = "rhine.c v1.0.1 2003-02-06\n";
22*8044SWilliam.Kucharski@Sun.COM 
23*8044SWilliam.Kucharski@Sun.COM /* A few user-configurable values. */
24*8044SWilliam.Kucharski@Sun.COM 
25*8044SWilliam.Kucharski@Sun.COM /* Size of the in-memory receive ring. */
26*8044SWilliam.Kucharski@Sun.COM #define RX_BUF_LEN_IDX	3	/* 0==8K, 1==16K, 2==32K, 3==64K */
27*8044SWilliam.Kucharski@Sun.COM #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
28*8044SWilliam.Kucharski@Sun.COM 
29*8044SWilliam.Kucharski@Sun.COM /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
30*8044SWilliam.Kucharski@Sun.COM #define TX_BUF_SIZE	1536
31*8044SWilliam.Kucharski@Sun.COM #define RX_BUF_SIZE	1536
32*8044SWilliam.Kucharski@Sun.COM 
33*8044SWilliam.Kucharski@Sun.COM /* PCI Tuning Parameters
34*8044SWilliam.Kucharski@Sun.COM    Threshold is bytes transferred to chip before transmission starts. */
35*8044SWilliam.Kucharski@Sun.COM #define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
36*8044SWilliam.Kucharski@Sun.COM 
37*8044SWilliam.Kucharski@Sun.COM /* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
38*8044SWilliam.Kucharski@Sun.COM #define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
39*8044SWilliam.Kucharski@Sun.COM #define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
40*8044SWilliam.Kucharski@Sun.COM #define TX_DMA_BURST	4
41*8044SWilliam.Kucharski@Sun.COM 
42*8044SWilliam.Kucharski@Sun.COM /* Operational parameters that usually are not changed. */
43*8044SWilliam.Kucharski@Sun.COM /* Time in jiffies before concluding the transmitter is hung. */
44*8044SWilliam.Kucharski@Sun.COM #define TX_TIMEOUT  ((2000*HZ)/1000)
45*8044SWilliam.Kucharski@Sun.COM 
46*8044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
47*8044SWilliam.Kucharski@Sun.COM #include "nic.h"
48*8044SWilliam.Kucharski@Sun.COM #include "pci.h"
49*8044SWilliam.Kucharski@Sun.COM 
50*8044SWilliam.Kucharski@Sun.COM /* define all ioaddr */
51*8044SWilliam.Kucharski@Sun.COM 
52*8044SWilliam.Kucharski@Sun.COM #define byPAR0				ioaddr
53*8044SWilliam.Kucharski@Sun.COM #define byRCR				ioaddr + 6
54*8044SWilliam.Kucharski@Sun.COM #define byTCR				ioaddr + 7
55*8044SWilliam.Kucharski@Sun.COM #define byCR0				ioaddr + 8
56*8044SWilliam.Kucharski@Sun.COM #define byCR1				ioaddr + 9
57*8044SWilliam.Kucharski@Sun.COM #define byISR0				ioaddr + 0x0c
58*8044SWilliam.Kucharski@Sun.COM #define byISR1				ioaddr + 0x0d
59*8044SWilliam.Kucharski@Sun.COM #define byIMR0				ioaddr + 0x0e
60*8044SWilliam.Kucharski@Sun.COM #define byIMR1				ioaddr + 0x0f
61*8044SWilliam.Kucharski@Sun.COM #define byMAR0				ioaddr + 0x10
62*8044SWilliam.Kucharski@Sun.COM #define byMAR1				ioaddr + 0x11
63*8044SWilliam.Kucharski@Sun.COM #define byMAR2				ioaddr + 0x12
64*8044SWilliam.Kucharski@Sun.COM #define byMAR3				ioaddr + 0x13
65*8044SWilliam.Kucharski@Sun.COM #define byMAR4				ioaddr + 0x14
66*8044SWilliam.Kucharski@Sun.COM #define byMAR5				ioaddr + 0x15
67*8044SWilliam.Kucharski@Sun.COM #define byMAR6				ioaddr + 0x16
68*8044SWilliam.Kucharski@Sun.COM #define byMAR7				ioaddr + 0x17
69*8044SWilliam.Kucharski@Sun.COM #define dwCurrentRxDescAddr		ioaddr + 0x18
70*8044SWilliam.Kucharski@Sun.COM #define dwCurrentTxDescAddr		ioaddr + 0x1c
71*8044SWilliam.Kucharski@Sun.COM #define dwCurrentRDSE0			ioaddr + 0x20
72*8044SWilliam.Kucharski@Sun.COM #define dwCurrentRDSE1			ioaddr + 0x24
73*8044SWilliam.Kucharski@Sun.COM #define dwCurrentRDSE2			ioaddr + 0x28
74*8044SWilliam.Kucharski@Sun.COM #define dwCurrentRDSE3			ioaddr + 0x2c
75*8044SWilliam.Kucharski@Sun.COM #define dwNextRDSE0			ioaddr + 0x30
76*8044SWilliam.Kucharski@Sun.COM #define dwNextRDSE1			ioaddr + 0x34
77*8044SWilliam.Kucharski@Sun.COM #define dwNextRDSE2			ioaddr + 0x38
78*8044SWilliam.Kucharski@Sun.COM #define dwNextRDSE3			ioaddr + 0x3c
79*8044SWilliam.Kucharski@Sun.COM #define dwCurrentTDSE0			ioaddr + 0x40
80*8044SWilliam.Kucharski@Sun.COM #define dwCurrentTDSE1			ioaddr + 0x44
81*8044SWilliam.Kucharski@Sun.COM #define dwCurrentTDSE2			ioaddr + 0x48
82*8044SWilliam.Kucharski@Sun.COM #define dwCurrentTDSE3			ioaddr + 0x4c
83*8044SWilliam.Kucharski@Sun.COM #define dwNextTDSE0			ioaddr + 0x50
84*8044SWilliam.Kucharski@Sun.COM #define dwNextTDSE1			ioaddr + 0x54
85*8044SWilliam.Kucharski@Sun.COM #define dwNextTDSE2			ioaddr + 0x58
86*8044SWilliam.Kucharski@Sun.COM #define dwNextTDSE3			ioaddr + 0x5c
87*8044SWilliam.Kucharski@Sun.COM #define dwCurrRxDMAPtr			ioaddr + 0x60
88*8044SWilliam.Kucharski@Sun.COM #define dwCurrTxDMAPtr			ioaddr + 0x64
89*8044SWilliam.Kucharski@Sun.COM #define byMPHY				ioaddr + 0x6c
90*8044SWilliam.Kucharski@Sun.COM #define byMIISR				ioaddr + 0x6d
91*8044SWilliam.Kucharski@Sun.COM #define byBCR0				ioaddr + 0x6e
92*8044SWilliam.Kucharski@Sun.COM #define byBCR1				ioaddr + 0x6f
93*8044SWilliam.Kucharski@Sun.COM #define byMIICR				ioaddr + 0x70
94*8044SWilliam.Kucharski@Sun.COM #define byMIIAD				ioaddr + 0x71
95*8044SWilliam.Kucharski@Sun.COM #define wMIIDATA			ioaddr + 0x72
96*8044SWilliam.Kucharski@Sun.COM #define byEECSR				ioaddr + 0x74
97*8044SWilliam.Kucharski@Sun.COM #define byTEST				ioaddr + 0x75
98*8044SWilliam.Kucharski@Sun.COM #define byGPIO				ioaddr + 0x76
99*8044SWilliam.Kucharski@Sun.COM #define byCFGA				ioaddr + 0x78
100*8044SWilliam.Kucharski@Sun.COM #define byCFGB				ioaddr + 0x79
101*8044SWilliam.Kucharski@Sun.COM #define byCFGC				ioaddr + 0x7a
102*8044SWilliam.Kucharski@Sun.COM #define byCFGD				ioaddr + 0x7b
103*8044SWilliam.Kucharski@Sun.COM #define wTallyCntMPA			ioaddr + 0x7c
104*8044SWilliam.Kucharski@Sun.COM #define wTallyCntCRC			ioaddr + 0x7d
105*8044SWilliam.Kucharski@Sun.COM #define bySTICKHW			ioaddr + 0x83
106*8044SWilliam.Kucharski@Sun.COM #define byWOLcrClr			ioaddr + 0xA4
107*8044SWilliam.Kucharski@Sun.COM #define byWOLcgClr			ioaddr + 0xA7
108*8044SWilliam.Kucharski@Sun.COM #define byPwrcsrClr			ioaddr + 0xAC
109*8044SWilliam.Kucharski@Sun.COM 
110*8044SWilliam.Kucharski@Sun.COM /*---------------------  Exioaddr Definitions -------------------------*/
111*8044SWilliam.Kucharski@Sun.COM 
112*8044SWilliam.Kucharski@Sun.COM /*
113*8044SWilliam.Kucharski@Sun.COM  * Bits in the RCR register
114*8044SWilliam.Kucharski@Sun.COM  */
115*8044SWilliam.Kucharski@Sun.COM 
116*8044SWilliam.Kucharski@Sun.COM #define RCR_RRFT2		0x80
117*8044SWilliam.Kucharski@Sun.COM #define RCR_RRFT1		0x40
118*8044SWilliam.Kucharski@Sun.COM #define RCR_RRFT0		0x20
119*8044SWilliam.Kucharski@Sun.COM #define RCR_PROM		0x10
120*8044SWilliam.Kucharski@Sun.COM #define RCR_AB			0x08
121*8044SWilliam.Kucharski@Sun.COM #define RCR_AM			0x04
122*8044SWilliam.Kucharski@Sun.COM #define RCR_AR			0x02
123*8044SWilliam.Kucharski@Sun.COM #define RCR_SEP			0x01
124*8044SWilliam.Kucharski@Sun.COM 
125*8044SWilliam.Kucharski@Sun.COM /*
126*8044SWilliam.Kucharski@Sun.COM  * Bits in the TCR register
127*8044SWilliam.Kucharski@Sun.COM  */
128*8044SWilliam.Kucharski@Sun.COM 
129*8044SWilliam.Kucharski@Sun.COM #define TCR_RTSF		0x80
130*8044SWilliam.Kucharski@Sun.COM #define TCR_RTFT1		0x40
131*8044SWilliam.Kucharski@Sun.COM #define TCR_RTFT0		0x20
132*8044SWilliam.Kucharski@Sun.COM #define TCR_OFSET		0x08
133*8044SWilliam.Kucharski@Sun.COM #define TCR_LB1			0x04	/* loopback[1] */
134*8044SWilliam.Kucharski@Sun.COM #define TCR_LB0			0x02	/* loopback[0] */
135*8044SWilliam.Kucharski@Sun.COM 
136*8044SWilliam.Kucharski@Sun.COM /*
137*8044SWilliam.Kucharski@Sun.COM  * Bits in the CR0 register
138*8044SWilliam.Kucharski@Sun.COM  */
139*8044SWilliam.Kucharski@Sun.COM 
140*8044SWilliam.Kucharski@Sun.COM #define CR0_RDMD		0x40	/* rx descriptor polling demand */
141*8044SWilliam.Kucharski@Sun.COM #define CR0_TDMD		0x20	/* tx descriptor polling demand */
142*8044SWilliam.Kucharski@Sun.COM #define CR0_TXON		0x10
143*8044SWilliam.Kucharski@Sun.COM #define CR0_RXON		0x08
144*8044SWilliam.Kucharski@Sun.COM #define CR0_STOP		0x04	/* stop NIC, default = 1 */
145*8044SWilliam.Kucharski@Sun.COM #define CR0_STRT		0x02	/* start NIC */
146*8044SWilliam.Kucharski@Sun.COM #define CR0_INIT		0x01	/* start init process */
147*8044SWilliam.Kucharski@Sun.COM 
148*8044SWilliam.Kucharski@Sun.COM 
149*8044SWilliam.Kucharski@Sun.COM /*
150*8044SWilliam.Kucharski@Sun.COM  * Bits in the CR1 register
151*8044SWilliam.Kucharski@Sun.COM  */
152*8044SWilliam.Kucharski@Sun.COM 
153*8044SWilliam.Kucharski@Sun.COM #define CR1_SFRST		0x80	/* software reset */
154*8044SWilliam.Kucharski@Sun.COM #define CR1_RDMD1		0x40	/* RDMD1 */
155*8044SWilliam.Kucharski@Sun.COM #define CR1_TDMD1		0x20	/* TDMD1 */
156*8044SWilliam.Kucharski@Sun.COM #define CR1_KEYPAG		0x10	/* turn on par/key */
157*8044SWilliam.Kucharski@Sun.COM #define CR1_DPOLL		0x08	/* disable rx/tx auto polling */
158*8044SWilliam.Kucharski@Sun.COM #define CR1_FDX			0x04	/* full duplex mode */
159*8044SWilliam.Kucharski@Sun.COM #define CR1_ETEN		0x02	/* early tx mode */
160*8044SWilliam.Kucharski@Sun.COM #define CR1_EREN		0x01	/* early rx mode */
161*8044SWilliam.Kucharski@Sun.COM 
162*8044SWilliam.Kucharski@Sun.COM /*
163*8044SWilliam.Kucharski@Sun.COM  * Bits in the CR register
164*8044SWilliam.Kucharski@Sun.COM  */
165*8044SWilliam.Kucharski@Sun.COM 
166*8044SWilliam.Kucharski@Sun.COM #define CR_RDMD			0x0040	/* rx descriptor polling demand */
167*8044SWilliam.Kucharski@Sun.COM #define CR_TDMD			0x0020	/* tx descriptor polling demand */
168*8044SWilliam.Kucharski@Sun.COM #define CR_TXON			0x0010
169*8044SWilliam.Kucharski@Sun.COM #define CR_RXON			0x0008
170*8044SWilliam.Kucharski@Sun.COM #define CR_STOP			0x0004	/* stop NIC, default = 1 */
171*8044SWilliam.Kucharski@Sun.COM #define CR_STRT			0x0002	/* start NIC */
172*8044SWilliam.Kucharski@Sun.COM #define CR_INIT			0x0001	/* start init process */
173*8044SWilliam.Kucharski@Sun.COM #define CR_SFRST		0x8000	/* software reset */
174*8044SWilliam.Kucharski@Sun.COM #define CR_RDMD1		0x4000	/* RDMD1 */
175*8044SWilliam.Kucharski@Sun.COM #define CR_TDMD1		0x2000	/* TDMD1 */
176*8044SWilliam.Kucharski@Sun.COM #define CR_KEYPAG		0x1000	/* turn on par/key */
177*8044SWilliam.Kucharski@Sun.COM #define CR_DPOLL		0x0800	/* disable rx/tx auto polling */
178*8044SWilliam.Kucharski@Sun.COM #define CR_FDX			0x0400	/* full duplex mode */
179*8044SWilliam.Kucharski@Sun.COM #define CR_ETEN			0x0200	/* early tx mode */
180*8044SWilliam.Kucharski@Sun.COM #define CR_EREN			0x0100	/* early rx mode */
181*8044SWilliam.Kucharski@Sun.COM 
182*8044SWilliam.Kucharski@Sun.COM /*
183*8044SWilliam.Kucharski@Sun.COM  * Bits in the IMR0 register
184*8044SWilliam.Kucharski@Sun.COM  */
185*8044SWilliam.Kucharski@Sun.COM 
186*8044SWilliam.Kucharski@Sun.COM #define IMR0_CNTM		0x80
187*8044SWilliam.Kucharski@Sun.COM #define IMR0_BEM		0x40
188*8044SWilliam.Kucharski@Sun.COM #define IMR0_RUM		0x20
189*8044SWilliam.Kucharski@Sun.COM #define IMR0_TUM		0x10
190*8044SWilliam.Kucharski@Sun.COM #define IMR0_TXEM		0x08
191*8044SWilliam.Kucharski@Sun.COM #define IMR0_RXEM		0x04
192*8044SWilliam.Kucharski@Sun.COM #define IMR0_PTXM		0x02
193*8044SWilliam.Kucharski@Sun.COM #define IMR0_PRXM		0x01
194*8044SWilliam.Kucharski@Sun.COM 
195*8044SWilliam.Kucharski@Sun.COM /* define imrshadow */
196*8044SWilliam.Kucharski@Sun.COM 
197*8044SWilliam.Kucharski@Sun.COM #define IMRShadow		0x5AFF
198*8044SWilliam.Kucharski@Sun.COM 
199*8044SWilliam.Kucharski@Sun.COM /*
200*8044SWilliam.Kucharski@Sun.COM  * Bits in the IMR1 register
201*8044SWilliam.Kucharski@Sun.COM  */
202*8044SWilliam.Kucharski@Sun.COM 
203*8044SWilliam.Kucharski@Sun.COM #define IMR1_INITM		0x80
204*8044SWilliam.Kucharski@Sun.COM #define IMR1_SRCM		0x40
205*8044SWilliam.Kucharski@Sun.COM #define IMR1_NBFM		0x10
206*8044SWilliam.Kucharski@Sun.COM #define IMR1_PRAIM		0x08
207*8044SWilliam.Kucharski@Sun.COM #define IMR1_RES0M		0x04
208*8044SWilliam.Kucharski@Sun.COM #define IMR1_ETM		0x02
209*8044SWilliam.Kucharski@Sun.COM #define IMR1_ERM		0x01
210*8044SWilliam.Kucharski@Sun.COM 
211*8044SWilliam.Kucharski@Sun.COM /*
212*8044SWilliam.Kucharski@Sun.COM  * Bits in the ISR register
213*8044SWilliam.Kucharski@Sun.COM  */
214*8044SWilliam.Kucharski@Sun.COM 
215*8044SWilliam.Kucharski@Sun.COM #define ISR_INITI		0x8000
216*8044SWilliam.Kucharski@Sun.COM #define ISR_SRCI		0x4000
217*8044SWilliam.Kucharski@Sun.COM #define ISR_ABTI		0x2000
218*8044SWilliam.Kucharski@Sun.COM #define ISR_NORBF		0x1000
219*8044SWilliam.Kucharski@Sun.COM #define ISR_PKTRA		0x0800
220*8044SWilliam.Kucharski@Sun.COM #define ISR_RES0		0x0400
221*8044SWilliam.Kucharski@Sun.COM #define ISR_ETI			0x0200
222*8044SWilliam.Kucharski@Sun.COM #define ISR_ERI			0x0100
223*8044SWilliam.Kucharski@Sun.COM #define ISR_CNT			0x0080
224*8044SWilliam.Kucharski@Sun.COM #define ISR_BE			0x0040
225*8044SWilliam.Kucharski@Sun.COM #define ISR_RU			0x0020
226*8044SWilliam.Kucharski@Sun.COM #define ISR_TU			0x0010
227*8044SWilliam.Kucharski@Sun.COM #define ISR_TXE			0x0008
228*8044SWilliam.Kucharski@Sun.COM #define ISR_RXE			0x0004
229*8044SWilliam.Kucharski@Sun.COM #define ISR_PTX			0x0002
230*8044SWilliam.Kucharski@Sun.COM #define ISR_PRX			0x0001
231*8044SWilliam.Kucharski@Sun.COM 
232*8044SWilliam.Kucharski@Sun.COM /*
233*8044SWilliam.Kucharski@Sun.COM  * Bits in the ISR0 register
234*8044SWilliam.Kucharski@Sun.COM  */
235*8044SWilliam.Kucharski@Sun.COM 
236*8044SWilliam.Kucharski@Sun.COM #define ISR0_CNT		0x80
237*8044SWilliam.Kucharski@Sun.COM #define ISR0_BE			0x40
238*8044SWilliam.Kucharski@Sun.COM #define ISR0_RU			0x20
239*8044SWilliam.Kucharski@Sun.COM #define ISR0_TU			0x10
240*8044SWilliam.Kucharski@Sun.COM #define ISR0_TXE		0x08
241*8044SWilliam.Kucharski@Sun.COM #define ISR0_RXE		0x04
242*8044SWilliam.Kucharski@Sun.COM #define ISR0_PTX		0x02
243*8044SWilliam.Kucharski@Sun.COM #define ISR0_PRX		0x01
244*8044SWilliam.Kucharski@Sun.COM 
245*8044SWilliam.Kucharski@Sun.COM /*
246*8044SWilliam.Kucharski@Sun.COM  * Bits in the ISR1 register
247*8044SWilliam.Kucharski@Sun.COM  */
248*8044SWilliam.Kucharski@Sun.COM 
249*8044SWilliam.Kucharski@Sun.COM #define ISR1_INITI		0x80
250*8044SWilliam.Kucharski@Sun.COM #define ISR1_SRCI		0x40
251*8044SWilliam.Kucharski@Sun.COM #define ISR1_NORBF		0x10
252*8044SWilliam.Kucharski@Sun.COM #define ISR1_PKTRA		0x08
253*8044SWilliam.Kucharski@Sun.COM #define ISR1_ETI		0x02
254*8044SWilliam.Kucharski@Sun.COM #define ISR1_ERI		0x01
255*8044SWilliam.Kucharski@Sun.COM 
256*8044SWilliam.Kucharski@Sun.COM /* ISR ABNORMAL CONDITION */
257*8044SWilliam.Kucharski@Sun.COM 
258*8044SWilliam.Kucharski@Sun.COM #define ISR_ABNORMAL ISR_BE+ISR_RU+ISR_TU+ISR_CNT+ISR_NORBF+ISR_PKTRA
259*8044SWilliam.Kucharski@Sun.COM 
260*8044SWilliam.Kucharski@Sun.COM /*
261*8044SWilliam.Kucharski@Sun.COM  * Bits in the MIISR register
262*8044SWilliam.Kucharski@Sun.COM  */
263*8044SWilliam.Kucharski@Sun.COM 
264*8044SWilliam.Kucharski@Sun.COM #define MIISR_MIIERR		0x08
265*8044SWilliam.Kucharski@Sun.COM #define MIISR_MRERR		0x04
266*8044SWilliam.Kucharski@Sun.COM #define MIISR_LNKFL		0x02
267*8044SWilliam.Kucharski@Sun.COM #define MIISR_SPEED		0x01
268*8044SWilliam.Kucharski@Sun.COM 
269*8044SWilliam.Kucharski@Sun.COM /*
270*8044SWilliam.Kucharski@Sun.COM  * Bits in the MIICR register
271*8044SWilliam.Kucharski@Sun.COM  */
272*8044SWilliam.Kucharski@Sun.COM 
273*8044SWilliam.Kucharski@Sun.COM #define MIICR_MAUTO		0x80
274*8044SWilliam.Kucharski@Sun.COM #define MIICR_RCMD		0x40
275*8044SWilliam.Kucharski@Sun.COM #define MIICR_WCMD		0x20
276*8044SWilliam.Kucharski@Sun.COM #define MIICR_MDPM		0x10
277*8044SWilliam.Kucharski@Sun.COM #define MIICR_MOUT		0x08
278*8044SWilliam.Kucharski@Sun.COM #define MIICR_MDO		0x04
279*8044SWilliam.Kucharski@Sun.COM #define MIICR_MDI		0x02
280*8044SWilliam.Kucharski@Sun.COM #define MIICR_MDC		0x01
281*8044SWilliam.Kucharski@Sun.COM 
282*8044SWilliam.Kucharski@Sun.COM /*
283*8044SWilliam.Kucharski@Sun.COM  * Bits in the EECSR register
284*8044SWilliam.Kucharski@Sun.COM  */
285*8044SWilliam.Kucharski@Sun.COM 
286*8044SWilliam.Kucharski@Sun.COM #define EECSR_EEPR		0x80	/* eeprom programed status, 73h means programed */
287*8044SWilliam.Kucharski@Sun.COM #define EECSR_EMBP		0x40	/* eeprom embeded programming */
288*8044SWilliam.Kucharski@Sun.COM #define EECSR_AUTOLD		0x20	/* eeprom content reload */
289*8044SWilliam.Kucharski@Sun.COM #define EECSR_DPM		0x10	/* eeprom direct programming */
290*8044SWilliam.Kucharski@Sun.COM #define EECSR_CS		0x08	/* eeprom CS pin */
291*8044SWilliam.Kucharski@Sun.COM #define EECSR_SK		0x04	/* eeprom SK pin */
292*8044SWilliam.Kucharski@Sun.COM #define EECSR_DI		0x02	/* eeprom DI pin */
293*8044SWilliam.Kucharski@Sun.COM #define EECSR_DO		0x01	/* eeprom DO pin */
294*8044SWilliam.Kucharski@Sun.COM 
295*8044SWilliam.Kucharski@Sun.COM /*
296*8044SWilliam.Kucharski@Sun.COM  * Bits in the BCR0 register
297*8044SWilliam.Kucharski@Sun.COM  */
298*8044SWilliam.Kucharski@Sun.COM 
299*8044SWilliam.Kucharski@Sun.COM #define BCR0_CRFT2		0x20
300*8044SWilliam.Kucharski@Sun.COM #define BCR0_CRFT1		0x10
301*8044SWilliam.Kucharski@Sun.COM #define BCR0_CRFT0		0x08
302*8044SWilliam.Kucharski@Sun.COM #define BCR0_DMAL2		0x04
303*8044SWilliam.Kucharski@Sun.COM #define BCR0_DMAL1		0x02
304*8044SWilliam.Kucharski@Sun.COM #define BCR0_DMAL0		0x01
305*8044SWilliam.Kucharski@Sun.COM 
306*8044SWilliam.Kucharski@Sun.COM /*
307*8044SWilliam.Kucharski@Sun.COM  * Bits in the BCR1 register
308*8044SWilliam.Kucharski@Sun.COM  */
309*8044SWilliam.Kucharski@Sun.COM 
310*8044SWilliam.Kucharski@Sun.COM #define BCR1_CTSF		0x20
311*8044SWilliam.Kucharski@Sun.COM #define BCR1_CTFT1		0x10
312*8044SWilliam.Kucharski@Sun.COM #define BCR1_CTFT0		0x08
313*8044SWilliam.Kucharski@Sun.COM #define BCR1_POT2		0x04
314*8044SWilliam.Kucharski@Sun.COM #define BCR1_POT1		0x02
315*8044SWilliam.Kucharski@Sun.COM #define BCR1_POT0		0x01
316*8044SWilliam.Kucharski@Sun.COM 
317*8044SWilliam.Kucharski@Sun.COM /*
318*8044SWilliam.Kucharski@Sun.COM  * Bits in the CFGA register
319*8044SWilliam.Kucharski@Sun.COM  */
320*8044SWilliam.Kucharski@Sun.COM 
321*8044SWilliam.Kucharski@Sun.COM #define CFGA_EELOAD		0x80	/* enable eeprom embeded and direct programming */
322*8044SWilliam.Kucharski@Sun.COM #define CFGA_JUMPER		0x40
323*8044SWilliam.Kucharski@Sun.COM #define CFGA_MTGPIO		0x08
324*8044SWilliam.Kucharski@Sun.COM #define CFGA_T10EN		0x02
325*8044SWilliam.Kucharski@Sun.COM #define CFGA_AUTO		0x01
326*8044SWilliam.Kucharski@Sun.COM 
327*8044SWilliam.Kucharski@Sun.COM /*
328*8044SWilliam.Kucharski@Sun.COM  * Bits in the CFGB register
329*8044SWilliam.Kucharski@Sun.COM  */
330*8044SWilliam.Kucharski@Sun.COM 
331*8044SWilliam.Kucharski@Sun.COM #define CFGB_PD			0x80
332*8044SWilliam.Kucharski@Sun.COM #define CFGB_POLEN		0x02
333*8044SWilliam.Kucharski@Sun.COM #define CFGB_LNKEN		0x01
334*8044SWilliam.Kucharski@Sun.COM 
335*8044SWilliam.Kucharski@Sun.COM /*
336*8044SWilliam.Kucharski@Sun.COM  * Bits in the CFGC register
337*8044SWilliam.Kucharski@Sun.COM  */
338*8044SWilliam.Kucharski@Sun.COM 
339*8044SWilliam.Kucharski@Sun.COM #define CFGC_M10TIO		0x80
340*8044SWilliam.Kucharski@Sun.COM #define CFGC_M10POL		0x40
341*8044SWilliam.Kucharski@Sun.COM #define CFGC_PHY1		0x20
342*8044SWilliam.Kucharski@Sun.COM #define CFGC_PHY0		0x10
343*8044SWilliam.Kucharski@Sun.COM #define CFGC_BTSEL		0x08
344*8044SWilliam.Kucharski@Sun.COM #define CFGC_BPS2		0x04	/* bootrom select[2] */
345*8044SWilliam.Kucharski@Sun.COM #define CFGC_BPS1		0x02	/* bootrom select[1] */
346*8044SWilliam.Kucharski@Sun.COM #define CFGC_BPS0		0x01	/* bootrom select[0] */
347*8044SWilliam.Kucharski@Sun.COM 
348*8044SWilliam.Kucharski@Sun.COM /*
349*8044SWilliam.Kucharski@Sun.COM  * Bits in the CFGD register
350*8044SWilliam.Kucharski@Sun.COM  */
351*8044SWilliam.Kucharski@Sun.COM 
352*8044SWilliam.Kucharski@Sun.COM #define CFGD_GPIOEN		0x80
353*8044SWilliam.Kucharski@Sun.COM #define CFGD_DIAG		0x40
354*8044SWilliam.Kucharski@Sun.COM #define CFGD_MAGIC		0x10
355*8044SWilliam.Kucharski@Sun.COM #define CFGD_CFDX		0x04
356*8044SWilliam.Kucharski@Sun.COM #define CFGD_CEREN		0x02
357*8044SWilliam.Kucharski@Sun.COM #define CFGD_CETEN		0x01
358*8044SWilliam.Kucharski@Sun.COM 
359*8044SWilliam.Kucharski@Sun.COM /* Bits in RSR */
360*8044SWilliam.Kucharski@Sun.COM #define RSR_RERR		0x00000001
361*8044SWilliam.Kucharski@Sun.COM #define RSR_CRC			0x00000002
362*8044SWilliam.Kucharski@Sun.COM #define RSR_FAE			0x00000004
363*8044SWilliam.Kucharski@Sun.COM #define RSR_FOV			0x00000008
364*8044SWilliam.Kucharski@Sun.COM #define RSR_LONG		0x00000010
365*8044SWilliam.Kucharski@Sun.COM #define RSR_RUNT		0x00000020
366*8044SWilliam.Kucharski@Sun.COM #define RSR_SERR		0x00000040
367*8044SWilliam.Kucharski@Sun.COM #define RSR_BUFF		0x00000080
368*8044SWilliam.Kucharski@Sun.COM #define RSR_EDP			0x00000100
369*8044SWilliam.Kucharski@Sun.COM #define RSR_STP			0x00000200
370*8044SWilliam.Kucharski@Sun.COM #define RSR_CHN			0x00000400
371*8044SWilliam.Kucharski@Sun.COM #define RSR_PHY			0x00000800
372*8044SWilliam.Kucharski@Sun.COM #define RSR_BAR			0x00001000
373*8044SWilliam.Kucharski@Sun.COM #define RSR_MAR			0x00002000
374*8044SWilliam.Kucharski@Sun.COM #define RSR_RXOK		0x00008000
375*8044SWilliam.Kucharski@Sun.COM #define RSR_ABNORMAL		RSR_RERR+RSR_LONG+RSR_RUNT
376*8044SWilliam.Kucharski@Sun.COM 
377*8044SWilliam.Kucharski@Sun.COM /* Bits in TSR */
378*8044SWilliam.Kucharski@Sun.COM #define TSR_NCR0		0x00000001
379*8044SWilliam.Kucharski@Sun.COM #define TSR_NCR1		0x00000002
380*8044SWilliam.Kucharski@Sun.COM #define TSR_NCR2		0x00000004
381*8044SWilliam.Kucharski@Sun.COM #define TSR_NCR3		0x00000008
382*8044SWilliam.Kucharski@Sun.COM #define TSR_COLS		0x00000010
383*8044SWilliam.Kucharski@Sun.COM #define TSR_CDH			0x00000080
384*8044SWilliam.Kucharski@Sun.COM #define TSR_ABT			0x00000100
385*8044SWilliam.Kucharski@Sun.COM #define TSR_OWC			0x00000200
386*8044SWilliam.Kucharski@Sun.COM #define TSR_CRS			0x00000400
387*8044SWilliam.Kucharski@Sun.COM #define TSR_UDF			0x00000800
388*8044SWilliam.Kucharski@Sun.COM #define TSR_TBUFF		0x00001000
389*8044SWilliam.Kucharski@Sun.COM #define TSR_SERR		0x00002000
390*8044SWilliam.Kucharski@Sun.COM #define TSR_JAB			0x00004000
391*8044SWilliam.Kucharski@Sun.COM #define TSR_TERR		0x00008000
392*8044SWilliam.Kucharski@Sun.COM #define TSR_ABNORMAL		TSR_TERR+TSR_OWC+TSR_ABT+TSR_JAB+TSR_CRS
393*8044SWilliam.Kucharski@Sun.COM #define TSR_OWN_BIT		0x80000000
394*8044SWilliam.Kucharski@Sun.COM 
395*8044SWilliam.Kucharski@Sun.COM #define CB_DELAY_LOOP_WAIT	10	/* 10ms */
396*8044SWilliam.Kucharski@Sun.COM /* enabled mask value of irq */
397*8044SWilliam.Kucharski@Sun.COM 
398*8044SWilliam.Kucharski@Sun.COM #define W_IMR_MASK_VALUE	0x1BFF	/* initial value of IMR */
399*8044SWilliam.Kucharski@Sun.COM 
400*8044SWilliam.Kucharski@Sun.COM /* Ethernet address filter type */
401*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_DIRECTED	0x0001	/* obsolete, directed address is always accepted */
402*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_MULTICAST	0x0002
403*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_ALL_MULTICAST	0x0004
404*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_BROADCAST	0x0008
405*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_PROMISCUOUS	0x0020
406*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_LONG		0x2000
407*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_RUNT		0x4000
408*8044SWilliam.Kucharski@Sun.COM #define PKT_TYPE_ERROR		0x8000	/* accept error packets, e.g. CRC error */
409*8044SWilliam.Kucharski@Sun.COM 
410*8044SWilliam.Kucharski@Sun.COM /* Loopback mode */
411*8044SWilliam.Kucharski@Sun.COM 
412*8044SWilliam.Kucharski@Sun.COM #define NIC_LB_NONE		0x00
413*8044SWilliam.Kucharski@Sun.COM #define NIC_LB_INTERNAL		0x01
414*8044SWilliam.Kucharski@Sun.COM #define NIC_LB_PHY		0x02	/* MII or Internal-10BaseT loopback */
415*8044SWilliam.Kucharski@Sun.COM 
416*8044SWilliam.Kucharski@Sun.COM #define TX_RING_SIZE		2
417*8044SWilliam.Kucharski@Sun.COM #define RX_RING_SIZE		2
418*8044SWilliam.Kucharski@Sun.COM #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
419*8044SWilliam.Kucharski@Sun.COM 
420*8044SWilliam.Kucharski@Sun.COM /* Transmit and receive descriptors definition */
421*8044SWilliam.Kucharski@Sun.COM 
422*8044SWilliam.Kucharski@Sun.COM struct rhine_tx_desc
423*8044SWilliam.Kucharski@Sun.COM {
424*8044SWilliam.Kucharski@Sun.COM     union VTC_tx_status_tag
425*8044SWilliam.Kucharski@Sun.COM     {
426*8044SWilliam.Kucharski@Sun.COM 	struct
427*8044SWilliam.Kucharski@Sun.COM 	{
428*8044SWilliam.Kucharski@Sun.COM 	    unsigned long ncro:1;
429*8044SWilliam.Kucharski@Sun.COM 	    unsigned long ncr1:1;
430*8044SWilliam.Kucharski@Sun.COM 	    unsigned long ncr2:1;
431*8044SWilliam.Kucharski@Sun.COM 	    unsigned long ncr3:1;
432*8044SWilliam.Kucharski@Sun.COM 	    unsigned long cols:1;
433*8044SWilliam.Kucharski@Sun.COM 	    unsigned long reserve_1:2;
434*8044SWilliam.Kucharski@Sun.COM 	    unsigned long cdh:1;
435*8044SWilliam.Kucharski@Sun.COM 	    unsigned long abt:1;
436*8044SWilliam.Kucharski@Sun.COM 	    unsigned long owc:1;
437*8044SWilliam.Kucharski@Sun.COM 	    unsigned long crs:1;
438*8044SWilliam.Kucharski@Sun.COM 	    unsigned long udf:1;
439*8044SWilliam.Kucharski@Sun.COM 	    unsigned long tbuff:1;
440*8044SWilliam.Kucharski@Sun.COM 	    unsigned long serr:1;
441*8044SWilliam.Kucharski@Sun.COM 	    unsigned long jab:1;
442*8044SWilliam.Kucharski@Sun.COM 	    unsigned long terr:1;
443*8044SWilliam.Kucharski@Sun.COM 	    unsigned long reserve_2:15;
444*8044SWilliam.Kucharski@Sun.COM 	    unsigned long own_bit:1;
445*8044SWilliam.Kucharski@Sun.COM 	}
446*8044SWilliam.Kucharski@Sun.COM 	bits;
447*8044SWilliam.Kucharski@Sun.COM 	unsigned long lw;
448*8044SWilliam.Kucharski@Sun.COM     }
449*8044SWilliam.Kucharski@Sun.COM     tx_status;
450*8044SWilliam.Kucharski@Sun.COM 
451*8044SWilliam.Kucharski@Sun.COM     union VTC_tx_ctrl_tag
452*8044SWilliam.Kucharski@Sun.COM     {
453*8044SWilliam.Kucharski@Sun.COM 	struct
454*8044SWilliam.Kucharski@Sun.COM 	{
455*8044SWilliam.Kucharski@Sun.COM 	    unsigned long tx_buf_size:11;
456*8044SWilliam.Kucharski@Sun.COM 	    unsigned long extend_tx_buf_size:4;
457*8044SWilliam.Kucharski@Sun.COM 	    unsigned long chn:1;
458*8044SWilliam.Kucharski@Sun.COM 	    unsigned long crc:1;
459*8044SWilliam.Kucharski@Sun.COM 	    unsigned long reserve_1:4;
460*8044SWilliam.Kucharski@Sun.COM 	    unsigned long stp:1;
461*8044SWilliam.Kucharski@Sun.COM 	    unsigned long edp:1;
462*8044SWilliam.Kucharski@Sun.COM 	    unsigned long ic:1;
463*8044SWilliam.Kucharski@Sun.COM 	    unsigned long reserve_2:8;
464*8044SWilliam.Kucharski@Sun.COM 	}
465*8044SWilliam.Kucharski@Sun.COM 	bits;
466*8044SWilliam.Kucharski@Sun.COM 	unsigned long lw;
467*8044SWilliam.Kucharski@Sun.COM     }
468*8044SWilliam.Kucharski@Sun.COM     tx_ctrl;
469*8044SWilliam.Kucharski@Sun.COM 
470*8044SWilliam.Kucharski@Sun.COM     unsigned long buf_addr_1:32;
471*8044SWilliam.Kucharski@Sun.COM     unsigned long buf_addr_2:32;
472*8044SWilliam.Kucharski@Sun.COM 
473*8044SWilliam.Kucharski@Sun.COM };
474*8044SWilliam.Kucharski@Sun.COM 
475*8044SWilliam.Kucharski@Sun.COM struct rhine_rx_desc
476*8044SWilliam.Kucharski@Sun.COM {
477*8044SWilliam.Kucharski@Sun.COM     union VTC_rx_status_tag
478*8044SWilliam.Kucharski@Sun.COM     {
479*8044SWilliam.Kucharski@Sun.COM 	struct
480*8044SWilliam.Kucharski@Sun.COM 	{
481*8044SWilliam.Kucharski@Sun.COM 	    unsigned long rerr:1;
482*8044SWilliam.Kucharski@Sun.COM 	    unsigned long crc_error:1;
483*8044SWilliam.Kucharski@Sun.COM 	    unsigned long fae:1;
484*8044SWilliam.Kucharski@Sun.COM 	    unsigned long fov:1;
485*8044SWilliam.Kucharski@Sun.COM 	    unsigned long toolong:1;
486*8044SWilliam.Kucharski@Sun.COM 	    unsigned long runt:1;
487*8044SWilliam.Kucharski@Sun.COM 	    unsigned long serr:1;
488*8044SWilliam.Kucharski@Sun.COM 	    unsigned long buff:1;
489*8044SWilliam.Kucharski@Sun.COM 	    unsigned long edp:1;
490*8044SWilliam.Kucharski@Sun.COM 	    unsigned long stp:1;
491*8044SWilliam.Kucharski@Sun.COM 	    unsigned long chn:1;
492*8044SWilliam.Kucharski@Sun.COM 	    unsigned long phy:1;
493*8044SWilliam.Kucharski@Sun.COM 	    unsigned long bar:1;
494*8044SWilliam.Kucharski@Sun.COM 	    unsigned long mar:1;
495*8044SWilliam.Kucharski@Sun.COM 	    unsigned long reserve_1:1;
496*8044SWilliam.Kucharski@Sun.COM 	    unsigned long rxok:1;
497*8044SWilliam.Kucharski@Sun.COM 	    unsigned long frame_length:11;
498*8044SWilliam.Kucharski@Sun.COM 	    unsigned long reverve_2:4;
499*8044SWilliam.Kucharski@Sun.COM 	    unsigned long own_bit:1;
500*8044SWilliam.Kucharski@Sun.COM 	}
501*8044SWilliam.Kucharski@Sun.COM 	bits;
502*8044SWilliam.Kucharski@Sun.COM 	unsigned long lw;
503*8044SWilliam.Kucharski@Sun.COM     }
504*8044SWilliam.Kucharski@Sun.COM     rx_status;
505*8044SWilliam.Kucharski@Sun.COM 
506*8044SWilliam.Kucharski@Sun.COM     union VTC_rx_ctrl_tag
507*8044SWilliam.Kucharski@Sun.COM     {
508*8044SWilliam.Kucharski@Sun.COM 	struct
509*8044SWilliam.Kucharski@Sun.COM 	{
510*8044SWilliam.Kucharski@Sun.COM 	    unsigned long rx_buf_size:11;
511*8044SWilliam.Kucharski@Sun.COM 	    unsigned long extend_rx_buf_size:4;
512*8044SWilliam.Kucharski@Sun.COM 	    unsigned long reserved_1:17;
513*8044SWilliam.Kucharski@Sun.COM 	}
514*8044SWilliam.Kucharski@Sun.COM 	bits;
515*8044SWilliam.Kucharski@Sun.COM 	unsigned long lw;
516*8044SWilliam.Kucharski@Sun.COM     }
517*8044SWilliam.Kucharski@Sun.COM     rx_ctrl;
518*8044SWilliam.Kucharski@Sun.COM 
519*8044SWilliam.Kucharski@Sun.COM     unsigned long buf_addr_1:32;
520*8044SWilliam.Kucharski@Sun.COM     unsigned long buf_addr_2:32;
521*8044SWilliam.Kucharski@Sun.COM 
522*8044SWilliam.Kucharski@Sun.COM };
523*8044SWilliam.Kucharski@Sun.COM 
524*8044SWilliam.Kucharski@Sun.COM 
525*8044SWilliam.Kucharski@Sun.COM /* The I/O extent. */
526*8044SWilliam.Kucharski@Sun.COM #define rhine_TOTAL_SIZE 0x80
527*8044SWilliam.Kucharski@Sun.COM 
528*8044SWilliam.Kucharski@Sun.COM #ifdef	HAVE_DEVLIST
529*8044SWilliam.Kucharski@Sun.COM struct netdev_entry rhine_drv =
530*8044SWilliam.Kucharski@Sun.COM     { "rhine", rhine_probe, rhine_TOTAL_SIZE, NULL };
531*8044SWilliam.Kucharski@Sun.COM #endif
532*8044SWilliam.Kucharski@Sun.COM 
533*8044SWilliam.Kucharski@Sun.COM static int rhine_debug = 1;
534*8044SWilliam.Kucharski@Sun.COM 
535*8044SWilliam.Kucharski@Sun.COM /*
536*8044SWilliam.Kucharski@Sun.COM 				Theory of Operation
537*8044SWilliam.Kucharski@Sun.COM 
538*8044SWilliam.Kucharski@Sun.COM I. Board Compatibility
539*8044SWilliam.Kucharski@Sun.COM 
540*8044SWilliam.Kucharski@Sun.COM This driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet
541*8044SWilliam.Kucharski@Sun.COM controller.
542*8044SWilliam.Kucharski@Sun.COM 
543*8044SWilliam.Kucharski@Sun.COM II. Board-specific settings
544*8044SWilliam.Kucharski@Sun.COM 
545*8044SWilliam.Kucharski@Sun.COM Boards with this chip are functional only in a bus-master PCI slot.
546*8044SWilliam.Kucharski@Sun.COM 
547*8044SWilliam.Kucharski@Sun.COM Many operational settings are loaded from the EEPROM to the Config word at
548*8044SWilliam.Kucharski@Sun.COM offset 0x78.  This driver assumes that they are correct.
549*8044SWilliam.Kucharski@Sun.COM If this driver is compiled to use PCI memory space operations the EEPROM
550*8044SWilliam.Kucharski@Sun.COM must be configured to enable memory ops.
551*8044SWilliam.Kucharski@Sun.COM 
552*8044SWilliam.Kucharski@Sun.COM III. Driver operation
553*8044SWilliam.Kucharski@Sun.COM 
554*8044SWilliam.Kucharski@Sun.COM IIIa. Ring buffers
555*8044SWilliam.Kucharski@Sun.COM 
556*8044SWilliam.Kucharski@Sun.COM This driver uses two statically allocated fixed-size descriptor lists
557*8044SWilliam.Kucharski@Sun.COM formed into rings by a branch from the final descriptor to the beginning of
558*8044SWilliam.Kucharski@Sun.COM the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
559*8044SWilliam.Kucharski@Sun.COM 
560*8044SWilliam.Kucharski@Sun.COM IIIb/c. Transmit/Receive Structure
561*8044SWilliam.Kucharski@Sun.COM 
562*8044SWilliam.Kucharski@Sun.COM This driver attempts to use a zero-copy receive and transmit scheme.
563*8044SWilliam.Kucharski@Sun.COM 
564*8044SWilliam.Kucharski@Sun.COM Alas, all data buffers are required to start on a 32 bit boundary, so
565*8044SWilliam.Kucharski@Sun.COM the driver must often copy transmit packets into bounce buffers.
566*8044SWilliam.Kucharski@Sun.COM 
567*8044SWilliam.Kucharski@Sun.COM The driver allocates full frame size skbuffs for the Rx ring buffers at
568*8044SWilliam.Kucharski@Sun.COM open() time and passes the skb->data field to the chip as receive data
569*8044SWilliam.Kucharski@Sun.COM buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
570*8044SWilliam.Kucharski@Sun.COM a fresh skbuff is allocated and the frame is copied to the new skbuff.
571*8044SWilliam.Kucharski@Sun.COM When the incoming frame is larger, the skbuff is passed directly up the
572*8044SWilliam.Kucharski@Sun.COM protocol stack.  Buffers consumed this way are replaced by newly allocated
573*8044SWilliam.Kucharski@Sun.COM skbuffs in the last phase of netdev_rx().
574*8044SWilliam.Kucharski@Sun.COM 
575*8044SWilliam.Kucharski@Sun.COM The RX_COPYBREAK value is chosen to trade-off the memory wasted by
576*8044SWilliam.Kucharski@Sun.COM using a full-sized skbuff for small frames vs. the copying costs of larger
577*8044SWilliam.Kucharski@Sun.COM frames.  New boards are typically used in generously configured machines
578*8044SWilliam.Kucharski@Sun.COM and the underfilled buffers have negligible impact compared to the benefit of
579*8044SWilliam.Kucharski@Sun.COM a single allocation size, so the default value of zero results in never
580*8044SWilliam.Kucharski@Sun.COM copying packets.  When copying is done, the cost is usually mitigated by using
581*8044SWilliam.Kucharski@Sun.COM a combined copy/checksum routine.  Copying also preloads the cache, which is
582*8044SWilliam.Kucharski@Sun.COM most useful with small frames.
583*8044SWilliam.Kucharski@Sun.COM 
584*8044SWilliam.Kucharski@Sun.COM Since the VIA chips are only able to transfer data to buffers on 32 bit
585*8044SWilliam.Kucharski@Sun.COM boundaries, the the IP header at offset 14 in an ethernet frame isn't
586*8044SWilliam.Kucharski@Sun.COM longword aligned for further processing.  Copying these unaligned buffers
587*8044SWilliam.Kucharski@Sun.COM has the beneficial effect of 16-byte aligning the IP header.
588*8044SWilliam.Kucharski@Sun.COM 
589*8044SWilliam.Kucharski@Sun.COM IIId. Synchronization
590*8044SWilliam.Kucharski@Sun.COM 
591*8044SWilliam.Kucharski@Sun.COM The driver runs as two independent, single-threaded flows of control.  One
592*8044SWilliam.Kucharski@Sun.COM is the send-packet routine, which enforces single-threaded use by the
593*8044SWilliam.Kucharski@Sun.COM dev->tbusy flag.  The other thread is the interrupt handler, which is single
594*8044SWilliam.Kucharski@Sun.COM threaded by the hardware and interrupt handling software.
595*8044SWilliam.Kucharski@Sun.COM 
596*8044SWilliam.Kucharski@Sun.COM The send packet thread has partial control over the Tx ring and 'dev->tbusy'
597*8044SWilliam.Kucharski@Sun.COM flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
598*8044SWilliam.Kucharski@Sun.COM queue slot is empty, it clears the tbusy flag when finished otherwise it sets
599*8044SWilliam.Kucharski@Sun.COM the 'lp->tx_full' flag.
600*8044SWilliam.Kucharski@Sun.COM 
601*8044SWilliam.Kucharski@Sun.COM The interrupt handler has exclusive control over the Rx ring and records stats
602*8044SWilliam.Kucharski@Sun.COM from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
603*8044SWilliam.Kucharski@Sun.COM empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
604*8044SWilliam.Kucharski@Sun.COM clears both the tx_full and tbusy flags.
605*8044SWilliam.Kucharski@Sun.COM 
606*8044SWilliam.Kucharski@Sun.COM IV. Notes
607*8044SWilliam.Kucharski@Sun.COM 
608*8044SWilliam.Kucharski@Sun.COM IVb. References
609*8044SWilliam.Kucharski@Sun.COM 
610*8044SWilliam.Kucharski@Sun.COM Preliminary VT86C100A manual from http://www.via.com.tw/
611*8044SWilliam.Kucharski@Sun.COM http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
612*8044SWilliam.Kucharski@Sun.COM http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
613*8044SWilliam.Kucharski@Sun.COM 
614*8044SWilliam.Kucharski@Sun.COM IVc. Errata
615*8044SWilliam.Kucharski@Sun.COM 
616*8044SWilliam.Kucharski@Sun.COM The VT86C100A manual is not reliable information.
617*8044SWilliam.Kucharski@Sun.COM The chip does not handle unaligned transmit or receive buffers, resulting
618*8044SWilliam.Kucharski@Sun.COM in significant performance degradation for bounce buffer copies on transmit
619*8044SWilliam.Kucharski@Sun.COM and unaligned IP headers on receive.
620*8044SWilliam.Kucharski@Sun.COM The chip does not pad to minimum transmit length.
621*8044SWilliam.Kucharski@Sun.COM 
622*8044SWilliam.Kucharski@Sun.COM */
623*8044SWilliam.Kucharski@Sun.COM 
624*8044SWilliam.Kucharski@Sun.COM /* The rest of these values should never change. */
625*8044SWilliam.Kucharski@Sun.COM #define NUM_TX_DESC	2	/* Number of Tx descriptor registers. */
626*8044SWilliam.Kucharski@Sun.COM 
627*8044SWilliam.Kucharski@Sun.COM static struct rhine_private
628*8044SWilliam.Kucharski@Sun.COM {
629*8044SWilliam.Kucharski@Sun.COM     char devname[8];		/* Used only for kernel debugging. */
630*8044SWilliam.Kucharski@Sun.COM     const char *product_name;
631*8044SWilliam.Kucharski@Sun.COM     struct rhine_rx_desc *rx_ring;
632*8044SWilliam.Kucharski@Sun.COM     struct rhine_tx_desc *tx_ring;
633*8044SWilliam.Kucharski@Sun.COM     char *rx_buffs[RX_RING_SIZE];
634*8044SWilliam.Kucharski@Sun.COM     char *tx_buffs[TX_RING_SIZE];
635*8044SWilliam.Kucharski@Sun.COM 
636*8044SWilliam.Kucharski@Sun.COM     /* temporary Rx buffers. */
637*8044SWilliam.Kucharski@Sun.COM 
638*8044SWilliam.Kucharski@Sun.COM     int chip_id;
639*8044SWilliam.Kucharski@Sun.COM     int chip_revision;
640*8044SWilliam.Kucharski@Sun.COM     unsigned short ioaddr;
641*8044SWilliam.Kucharski@Sun.COM     unsigned int cur_rx, cur_tx;	/* The next free and used entries */
642*8044SWilliam.Kucharski@Sun.COM     unsigned int dirty_rx, dirty_tx;
643*8044SWilliam.Kucharski@Sun.COM     /* The saved address of a sent-in-place packet/buffer, for skfree(). */
644*8044SWilliam.Kucharski@Sun.COM     struct sk_buff *tx_skbuff[TX_RING_SIZE];
645*8044SWilliam.Kucharski@Sun.COM     unsigned char mc_filter[8];	/* Current multicast filter. */
646*8044SWilliam.Kucharski@Sun.COM     char phys[4];		/* MII device addresses. */
647*8044SWilliam.Kucharski@Sun.COM     unsigned int tx_full:1;	/* The Tx queue is full. */
648*8044SWilliam.Kucharski@Sun.COM     unsigned int full_duplex:1;	/* Full-duplex operation requested. */
649*8044SWilliam.Kucharski@Sun.COM     unsigned int default_port:4;	/* Last dev->if_port value. */
650*8044SWilliam.Kucharski@Sun.COM     unsigned int media2:4;	/* Secondary monitored media port. */
651*8044SWilliam.Kucharski@Sun.COM     unsigned int medialock:1;	/* Don't sense media type. */
652*8044SWilliam.Kucharski@Sun.COM     unsigned int mediasense:1;	/* Media sensing in progress. */
653*8044SWilliam.Kucharski@Sun.COM }
654*8044SWilliam.Kucharski@Sun.COM rhine;
655*8044SWilliam.Kucharski@Sun.COM 
656*8044SWilliam.Kucharski@Sun.COM static void rhine_probe1 (struct nic *nic, int ioaddr,
657*8044SWilliam.Kucharski@Sun.COM 				 int chip_id, int options);
658*8044SWilliam.Kucharski@Sun.COM static int QueryAuto (int);
659*8044SWilliam.Kucharski@Sun.COM static int ReadMII (int byMIIIndex, int);
660*8044SWilliam.Kucharski@Sun.COM static void WriteMII (char, char, char, int);
661*8044SWilliam.Kucharski@Sun.COM static void MIIDelay (void);
662*8044SWilliam.Kucharski@Sun.COM static void rhine_init_ring (struct nic *dev);
663*8044SWilliam.Kucharski@Sun.COM static void rhine_disable (struct dev *dev);
664*8044SWilliam.Kucharski@Sun.COM static void rhine_reset (struct nic *nic);
665*8044SWilliam.Kucharski@Sun.COM static int rhine_poll (struct nic *nic, int retreive);
666*8044SWilliam.Kucharski@Sun.COM static void rhine_transmit (struct nic *nic, const char *d, unsigned int t,
667*8044SWilliam.Kucharski@Sun.COM 			    unsigned int s, const char *p);
668*8044SWilliam.Kucharski@Sun.COM 
669*8044SWilliam.Kucharski@Sun.COM /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
670*8044SWilliam.Kucharski@Sun.COM static void
rhine_init_ring(struct nic * nic)671*8044SWilliam.Kucharski@Sun.COM rhine_init_ring (struct nic *nic)
672*8044SWilliam.Kucharski@Sun.COM {
673*8044SWilliam.Kucharski@Sun.COM     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
674*8044SWilliam.Kucharski@Sun.COM     int i;
675*8044SWilliam.Kucharski@Sun.COM 
676*8044SWilliam.Kucharski@Sun.COM     tp->tx_full = 0;
677*8044SWilliam.Kucharski@Sun.COM     tp->cur_rx = tp->cur_tx = 0;
678*8044SWilliam.Kucharski@Sun.COM     tp->dirty_rx = tp->dirty_tx = 0;
679*8044SWilliam.Kucharski@Sun.COM 
680*8044SWilliam.Kucharski@Sun.COM     for (i = 0; i < RX_RING_SIZE; i++)
681*8044SWilliam.Kucharski@Sun.COM     {
682*8044SWilliam.Kucharski@Sun.COM 
683*8044SWilliam.Kucharski@Sun.COM 	tp->rx_ring[i].rx_status.bits.own_bit = 1;
684*8044SWilliam.Kucharski@Sun.COM 	tp->rx_ring[i].rx_ctrl.bits.rx_buf_size = 1536;
685*8044SWilliam.Kucharski@Sun.COM 
686*8044SWilliam.Kucharski@Sun.COM 	tp->rx_ring[i].buf_addr_1 = virt_to_bus (tp->rx_buffs[i]);
687*8044SWilliam.Kucharski@Sun.COM 	tp->rx_ring[i].buf_addr_2 = virt_to_bus (&tp->rx_ring[i + 1]);
688*8044SWilliam.Kucharski@Sun.COM 	/* printf("[%d]buf1=%hX,buf2=%hX",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */
689*8044SWilliam.Kucharski@Sun.COM     }
690*8044SWilliam.Kucharski@Sun.COM     /* Mark the last entry as wrapping the ring. */
691*8044SWilliam.Kucharski@Sun.COM     /* tp->rx_ring[i-1].rx_ctrl.bits.rx_buf_size =1518; */
692*8044SWilliam.Kucharski@Sun.COM     tp->rx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->rx_ring[0]);
693*8044SWilliam.Kucharski@Sun.COM     /*printf("[%d]buf1=%hX,buf2=%hX",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */
694*8044SWilliam.Kucharski@Sun.COM 
695*8044SWilliam.Kucharski@Sun.COM     /* The Tx buffer descriptor is filled in as needed, but we
696*8044SWilliam.Kucharski@Sun.COM        do need to clear the ownership bit. */
697*8044SWilliam.Kucharski@Sun.COM 
698*8044SWilliam.Kucharski@Sun.COM     for (i = 0; i < TX_RING_SIZE; i++)
699*8044SWilliam.Kucharski@Sun.COM     {
700*8044SWilliam.Kucharski@Sun.COM 
701*8044SWilliam.Kucharski@Sun.COM 	tp->tx_ring[i].tx_status.lw = 0;
702*8044SWilliam.Kucharski@Sun.COM 	tp->tx_ring[i].tx_ctrl.lw = 0x00e08000;
703*8044SWilliam.Kucharski@Sun.COM 	tp->tx_ring[i].buf_addr_1 = virt_to_bus (tp->tx_buffs[i]);
704*8044SWilliam.Kucharski@Sun.COM 	tp->tx_ring[i].buf_addr_2 = virt_to_bus (&tp->tx_ring[i + 1]);
705*8044SWilliam.Kucharski@Sun.COM 	/* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */
706*8044SWilliam.Kucharski@Sun.COM     }
707*8044SWilliam.Kucharski@Sun.COM 
708*8044SWilliam.Kucharski@Sun.COM     tp->tx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->tx_ring[0]);
709*8044SWilliam.Kucharski@Sun.COM     /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */
710*8044SWilliam.Kucharski@Sun.COM }
711*8044SWilliam.Kucharski@Sun.COM 
712*8044SWilliam.Kucharski@Sun.COM int
QueryAuto(int ioaddr)713*8044SWilliam.Kucharski@Sun.COM QueryAuto (int ioaddr)
714*8044SWilliam.Kucharski@Sun.COM {
715*8044SWilliam.Kucharski@Sun.COM     int byMIIIndex;
716*8044SWilliam.Kucharski@Sun.COM     int MIIReturn;
717*8044SWilliam.Kucharski@Sun.COM 
718*8044SWilliam.Kucharski@Sun.COM 	int advertising,mii_reg5;
719*8044SWilliam.Kucharski@Sun.COM 	int negociated;
720*8044SWilliam.Kucharski@Sun.COM 
721*8044SWilliam.Kucharski@Sun.COM     byMIIIndex = 0x04;
722*8044SWilliam.Kucharski@Sun.COM     MIIReturn = ReadMII (byMIIIndex, ioaddr);
723*8044SWilliam.Kucharski@Sun.COM 	advertising=MIIReturn;
724*8044SWilliam.Kucharski@Sun.COM 
725*8044SWilliam.Kucharski@Sun.COM     byMIIIndex = 0x05;
726*8044SWilliam.Kucharski@Sun.COM     MIIReturn = ReadMII (byMIIIndex, ioaddr);
727*8044SWilliam.Kucharski@Sun.COM 	mii_reg5=MIIReturn;
728*8044SWilliam.Kucharski@Sun.COM 
729*8044SWilliam.Kucharski@Sun.COM 	negociated=mii_reg5 & advertising;
730*8044SWilliam.Kucharski@Sun.COM 
731*8044SWilliam.Kucharski@Sun.COM 	if ( (negociated & 0x100) || (negociated & 0x1C0) == 0x40 )
732*8044SWilliam.Kucharski@Sun.COM 		return 1;
733*8044SWilliam.Kucharski@Sun.COM 	else
734*8044SWilliam.Kucharski@Sun.COM 		return 0;
735*8044SWilliam.Kucharski@Sun.COM 
736*8044SWilliam.Kucharski@Sun.COM }
737*8044SWilliam.Kucharski@Sun.COM 
738*8044SWilliam.Kucharski@Sun.COM int
ReadMII(int byMIIIndex,int ioaddr)739*8044SWilliam.Kucharski@Sun.COM ReadMII (int byMIIIndex, int ioaddr)
740*8044SWilliam.Kucharski@Sun.COM {
741*8044SWilliam.Kucharski@Sun.COM     int ReturnMII;
742*8044SWilliam.Kucharski@Sun.COM     char byMIIAdrbak;
743*8044SWilliam.Kucharski@Sun.COM     char byMIICRbak;
744*8044SWilliam.Kucharski@Sun.COM     char byMIItemp;
745*8044SWilliam.Kucharski@Sun.COM 
746*8044SWilliam.Kucharski@Sun.COM     byMIIAdrbak = inb (byMIIAD);
747*8044SWilliam.Kucharski@Sun.COM     byMIICRbak = inb (byMIICR);
748*8044SWilliam.Kucharski@Sun.COM     outb (byMIICRbak & 0x7f, byMIICR);
749*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
750*8044SWilliam.Kucharski@Sun.COM 
751*8044SWilliam.Kucharski@Sun.COM     outb (byMIIIndex, byMIIAD);
752*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
753*8044SWilliam.Kucharski@Sun.COM 
754*8044SWilliam.Kucharski@Sun.COM     outb (inb (byMIICR) | 0x40, byMIICR);
755*8044SWilliam.Kucharski@Sun.COM 
756*8044SWilliam.Kucharski@Sun.COM     byMIItemp = inb (byMIICR);
757*8044SWilliam.Kucharski@Sun.COM     byMIItemp = byMIItemp & 0x40;
758*8044SWilliam.Kucharski@Sun.COM 
759*8044SWilliam.Kucharski@Sun.COM     while (byMIItemp != 0)
760*8044SWilliam.Kucharski@Sun.COM     {
761*8044SWilliam.Kucharski@Sun.COM 	byMIItemp = inb (byMIICR);
762*8044SWilliam.Kucharski@Sun.COM 	byMIItemp = byMIItemp & 0x40;
763*8044SWilliam.Kucharski@Sun.COM     }
764*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
765*8044SWilliam.Kucharski@Sun.COM 
766*8044SWilliam.Kucharski@Sun.COM     ReturnMII = inw (wMIIDATA);
767*8044SWilliam.Kucharski@Sun.COM 
768*8044SWilliam.Kucharski@Sun.COM     outb (byMIIAdrbak, byMIIAD);
769*8044SWilliam.Kucharski@Sun.COM     outb (byMIICRbak, byMIICR);
770*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
771*8044SWilliam.Kucharski@Sun.COM 
772*8044SWilliam.Kucharski@Sun.COM     return (ReturnMII);
773*8044SWilliam.Kucharski@Sun.COM 
774*8044SWilliam.Kucharski@Sun.COM }
775*8044SWilliam.Kucharski@Sun.COM 
776*8044SWilliam.Kucharski@Sun.COM void
WriteMII(char byMIISetByte,char byMIISetBit,char byMIIOP,int ioaddr)777*8044SWilliam.Kucharski@Sun.COM WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
778*8044SWilliam.Kucharski@Sun.COM {
779*8044SWilliam.Kucharski@Sun.COM     int ReadMIItmp;
780*8044SWilliam.Kucharski@Sun.COM     int MIIMask;
781*8044SWilliam.Kucharski@Sun.COM     char byMIIAdrbak;
782*8044SWilliam.Kucharski@Sun.COM     char byMIICRbak;
783*8044SWilliam.Kucharski@Sun.COM     char byMIItemp;
784*8044SWilliam.Kucharski@Sun.COM 
785*8044SWilliam.Kucharski@Sun.COM 
786*8044SWilliam.Kucharski@Sun.COM     byMIIAdrbak = inb (byMIIAD);
787*8044SWilliam.Kucharski@Sun.COM 
788*8044SWilliam.Kucharski@Sun.COM     byMIICRbak = inb (byMIICR);
789*8044SWilliam.Kucharski@Sun.COM     outb (byMIICRbak & 0x7f, byMIICR);
790*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
791*8044SWilliam.Kucharski@Sun.COM     outb (byMIISetByte, byMIIAD);
792*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
793*8044SWilliam.Kucharski@Sun.COM 
794*8044SWilliam.Kucharski@Sun.COM     outb (inb (byMIICR) | 0x40, byMIICR);
795*8044SWilliam.Kucharski@Sun.COM 
796*8044SWilliam.Kucharski@Sun.COM     byMIItemp = inb (byMIICR);
797*8044SWilliam.Kucharski@Sun.COM     byMIItemp = byMIItemp & 0x40;
798*8044SWilliam.Kucharski@Sun.COM 
799*8044SWilliam.Kucharski@Sun.COM     while (byMIItemp != 0)
800*8044SWilliam.Kucharski@Sun.COM     {
801*8044SWilliam.Kucharski@Sun.COM 	byMIItemp = inb (byMIICR);
802*8044SWilliam.Kucharski@Sun.COM 	byMIItemp = byMIItemp & 0x40;
803*8044SWilliam.Kucharski@Sun.COM     }
804*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
805*8044SWilliam.Kucharski@Sun.COM 
806*8044SWilliam.Kucharski@Sun.COM     ReadMIItmp = inw (wMIIDATA);
807*8044SWilliam.Kucharski@Sun.COM     MIIMask = 0x0001;
808*8044SWilliam.Kucharski@Sun.COM     MIIMask = MIIMask << byMIISetBit;
809*8044SWilliam.Kucharski@Sun.COM 
810*8044SWilliam.Kucharski@Sun.COM 
811*8044SWilliam.Kucharski@Sun.COM     if (byMIIOP == 0)
812*8044SWilliam.Kucharski@Sun.COM     {
813*8044SWilliam.Kucharski@Sun.COM 	MIIMask = ~MIIMask;
814*8044SWilliam.Kucharski@Sun.COM 	ReadMIItmp = ReadMIItmp & MIIMask;
815*8044SWilliam.Kucharski@Sun.COM     }
816*8044SWilliam.Kucharski@Sun.COM     else
817*8044SWilliam.Kucharski@Sun.COM     {
818*8044SWilliam.Kucharski@Sun.COM 	ReadMIItmp = ReadMIItmp | MIIMask;
819*8044SWilliam.Kucharski@Sun.COM 
820*8044SWilliam.Kucharski@Sun.COM     }
821*8044SWilliam.Kucharski@Sun.COM     outw (ReadMIItmp, wMIIDATA);
822*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
823*8044SWilliam.Kucharski@Sun.COM 
824*8044SWilliam.Kucharski@Sun.COM     outb (inb (byMIICR) | 0x20, byMIICR);
825*8044SWilliam.Kucharski@Sun.COM     byMIItemp = inb (byMIICR);
826*8044SWilliam.Kucharski@Sun.COM     byMIItemp = byMIItemp & 0x20;
827*8044SWilliam.Kucharski@Sun.COM 
828*8044SWilliam.Kucharski@Sun.COM     while (byMIItemp != 0)
829*8044SWilliam.Kucharski@Sun.COM     {
830*8044SWilliam.Kucharski@Sun.COM 	byMIItemp = inb (byMIICR);
831*8044SWilliam.Kucharski@Sun.COM 	byMIItemp = byMIItemp & 0x20;
832*8044SWilliam.Kucharski@Sun.COM     }
833*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
834*8044SWilliam.Kucharski@Sun.COM 
835*8044SWilliam.Kucharski@Sun.COM     outb (byMIIAdrbak & 0x7f, byMIIAD);
836*8044SWilliam.Kucharski@Sun.COM     outb (byMIICRbak, byMIICR);
837*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
838*8044SWilliam.Kucharski@Sun.COM 
839*8044SWilliam.Kucharski@Sun.COM }
840*8044SWilliam.Kucharski@Sun.COM 
841*8044SWilliam.Kucharski@Sun.COM void
MIIDelay(void)842*8044SWilliam.Kucharski@Sun.COM MIIDelay (void)
843*8044SWilliam.Kucharski@Sun.COM {
844*8044SWilliam.Kucharski@Sun.COM     int i;
845*8044SWilliam.Kucharski@Sun.COM     for (i = 0; i < 0x7fff; i++)
846*8044SWilliam.Kucharski@Sun.COM     {
847*8044SWilliam.Kucharski@Sun.COM 	inb (0x61);
848*8044SWilliam.Kucharski@Sun.COM 	inb (0x61);
849*8044SWilliam.Kucharski@Sun.COM 	inb (0x61);
850*8044SWilliam.Kucharski@Sun.COM 	inb (0x61);
851*8044SWilliam.Kucharski@Sun.COM     }
852*8044SWilliam.Kucharski@Sun.COM }
853*8044SWilliam.Kucharski@Sun.COM 
854*8044SWilliam.Kucharski@Sun.COM /* Offsets to the device registers. */
855*8044SWilliam.Kucharski@Sun.COM enum register_offsets {
856*8044SWilliam.Kucharski@Sun.COM         StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
857*8044SWilliam.Kucharski@Sun.COM         IntrStatus=0x0C, IntrEnable=0x0E,
858*8044SWilliam.Kucharski@Sun.COM         MulticastFilter0=0x10, MulticastFilter1=0x14,
859*8044SWilliam.Kucharski@Sun.COM         RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
860*8044SWilliam.Kucharski@Sun.COM         MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
861*8044SWilliam.Kucharski@Sun.COM         MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
862*8044SWilliam.Kucharski@Sun.COM         ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
863*8044SWilliam.Kucharski@Sun.COM         RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
864*8044SWilliam.Kucharski@Sun.COM         StickyHW=0x83, IntrStatus2=0x84, WOLcrClr=0xA4, WOLcgClr=0xA7,
865*8044SWilliam.Kucharski@Sun.COM         PwrcsrClr=0xAC,
866*8044SWilliam.Kucharski@Sun.COM };
867*8044SWilliam.Kucharski@Sun.COM 
868*8044SWilliam.Kucharski@Sun.COM /* Bits in the interrupt status/mask registers. */
869*8044SWilliam.Kucharski@Sun.COM enum intr_status_bits {
870*8044SWilliam.Kucharski@Sun.COM         IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
871*8044SWilliam.Kucharski@Sun.COM         IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210,
872*8044SWilliam.Kucharski@Sun.COM         IntrPCIErr=0x0040,
873*8044SWilliam.Kucharski@Sun.COM         IntrStatsMax=0x0080, IntrRxEarly=0x0100,
874*8044SWilliam.Kucharski@Sun.COM         IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
875*8044SWilliam.Kucharski@Sun.COM         IntrTxAborted=0x2000, IntrLinkChange=0x4000,
876*8044SWilliam.Kucharski@Sun.COM         IntrRxWakeUp=0x8000,
877*8044SWilliam.Kucharski@Sun.COM         IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
878*8044SWilliam.Kucharski@Sun.COM         IntrTxDescRace=0x080000,        /* mapped from IntrStatus2 */
879*8044SWilliam.Kucharski@Sun.COM         IntrTxErrSummary=0x082218,
880*8044SWilliam.Kucharski@Sun.COM };
881*8044SWilliam.Kucharski@Sun.COM #define DEFAULT_INTR (IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | \
882*8044SWilliam.Kucharski@Sun.COM                    IntrRxDropped | IntrRxNoBuf)
883*8044SWilliam.Kucharski@Sun.COM 
884*8044SWilliam.Kucharski@Sun.COM /***************************************************************************
885*8044SWilliam.Kucharski@Sun.COM  IRQ - PXE IRQ Handler
886*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
rhine_irq(struct nic * nic,irq_action_t action)887*8044SWilliam.Kucharski@Sun.COM void rhine_irq ( struct nic *nic, irq_action_t action ) {
888*8044SWilliam.Kucharski@Sun.COM      struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
889*8044SWilliam.Kucharski@Sun.COM      /* Enable interrupts by setting the interrupt mask. */
890*8044SWilliam.Kucharski@Sun.COM      unsigned int intr_status;
891*8044SWilliam.Kucharski@Sun.COM 
892*8044SWilliam.Kucharski@Sun.COM      switch ( action ) {
893*8044SWilliam.Kucharski@Sun.COM           case DISABLE :
894*8044SWilliam.Kucharski@Sun.COM           case ENABLE :
895*8044SWilliam.Kucharski@Sun.COM                intr_status = inw(nic->ioaddr + IntrStatus);
896*8044SWilliam.Kucharski@Sun.COM                /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
897*8044SWilliam.Kucharski@Sun.COM                if (tp->chip_id == 0x3065)
898*8044SWilliam.Kucharski@Sun.COM                    intr_status |= inb(nic->ioaddr + IntrStatus2) << 16;
899*8044SWilliam.Kucharski@Sun.COM                intr_status = (intr_status & ~DEFAULT_INTR);
900*8044SWilliam.Kucharski@Sun.COM                if ( action == ENABLE )
901*8044SWilliam.Kucharski@Sun.COM                    intr_status = intr_status | DEFAULT_INTR;
902*8044SWilliam.Kucharski@Sun.COM                outw(intr_status, nic->ioaddr + IntrEnable);
903*8044SWilliam.Kucharski@Sun.COM                break;
904*8044SWilliam.Kucharski@Sun.COM          case FORCE :
905*8044SWilliam.Kucharski@Sun.COM                outw(0x0010, nic->ioaddr + 0x84);
906*8044SWilliam.Kucharski@Sun.COM                break;
907*8044SWilliam.Kucharski@Sun.COM          }
908*8044SWilliam.Kucharski@Sun.COM }
909*8044SWilliam.Kucharski@Sun.COM 
910*8044SWilliam.Kucharski@Sun.COM static int
rhine_probe(struct dev * dev,struct pci_device * pci)911*8044SWilliam.Kucharski@Sun.COM rhine_probe (struct dev *dev, struct pci_device *pci)
912*8044SWilliam.Kucharski@Sun.COM {
913*8044SWilliam.Kucharski@Sun.COM     struct nic *nic = (struct nic *)dev;
914*8044SWilliam.Kucharski@Sun.COM     struct rhine_private *tp = &rhine;
915*8044SWilliam.Kucharski@Sun.COM     if (!pci->ioaddr)
916*8044SWilliam.Kucharski@Sun.COM 	return 0;
917*8044SWilliam.Kucharski@Sun.COM     rhine_probe1 (nic, pci->ioaddr, pci->dev_id, -1);
918*8044SWilliam.Kucharski@Sun.COM 
919*8044SWilliam.Kucharski@Sun.COM     adjust_pci_device(pci);
920*8044SWilliam.Kucharski@Sun.COM     rhine_reset (nic);
921*8044SWilliam.Kucharski@Sun.COM 
922*8044SWilliam.Kucharski@Sun.COM     dev->disable  = rhine_disable;
923*8044SWilliam.Kucharski@Sun.COM     nic->poll     = rhine_poll;
924*8044SWilliam.Kucharski@Sun.COM     nic->transmit = rhine_transmit;
925*8044SWilliam.Kucharski@Sun.COM     nic->irqno	  = pci->irq;
926*8044SWilliam.Kucharski@Sun.COM     nic->irq      = rhine_irq;
927*8044SWilliam.Kucharski@Sun.COM     nic->ioaddr   = tp->ioaddr;
928*8044SWilliam.Kucharski@Sun.COM 
929*8044SWilliam.Kucharski@Sun.COM 
930*8044SWilliam.Kucharski@Sun.COM     return 1;
931*8044SWilliam.Kucharski@Sun.COM }
932*8044SWilliam.Kucharski@Sun.COM 
set_rx_mode(struct nic * nic __unused)933*8044SWilliam.Kucharski@Sun.COM static void set_rx_mode(struct nic *nic __unused) {
934*8044SWilliam.Kucharski@Sun.COM     	struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
935*8044SWilliam.Kucharski@Sun.COM 	unsigned char rx_mode;
936*8044SWilliam.Kucharski@Sun.COM     	int ioaddr = tp->ioaddr;
937*8044SWilliam.Kucharski@Sun.COM 
938*8044SWilliam.Kucharski@Sun.COM 	/* ! IFF_PROMISC */
939*8044SWilliam.Kucharski@Sun.COM 	outl(0xffffffff, byMAR0);
940*8044SWilliam.Kucharski@Sun.COM 	outl(0xffffffff, byMAR4);
941*8044SWilliam.Kucharski@Sun.COM 	rx_mode = 0x0C;
942*8044SWilliam.Kucharski@Sun.COM 
943*8044SWilliam.Kucharski@Sun.COM 	outb(0x60 /* thresh */ | rx_mode, byRCR );
944*8044SWilliam.Kucharski@Sun.COM }
945*8044SWilliam.Kucharski@Sun.COM 
946*8044SWilliam.Kucharski@Sun.COM static void
rhine_probe1(struct nic * nic,int ioaddr,int chip_id,int options)947*8044SWilliam.Kucharski@Sun.COM rhine_probe1 (struct nic *nic, int ioaddr, int chip_id, int options)
948*8044SWilliam.Kucharski@Sun.COM {
949*8044SWilliam.Kucharski@Sun.COM     struct rhine_private *tp;
950*8044SWilliam.Kucharski@Sun.COM     static int did_version = 0;	/* Already printed version info. */
951*8044SWilliam.Kucharski@Sun.COM     int i;
952*8044SWilliam.Kucharski@Sun.COM     unsigned int timeout;
953*8044SWilliam.Kucharski@Sun.COM     int FDXFlag;
954*8044SWilliam.Kucharski@Sun.COM     int byMIIvalue, LineSpeed, MIICRbak;
955*8044SWilliam.Kucharski@Sun.COM 
956*8044SWilliam.Kucharski@Sun.COM     if (rhine_debug > 0 && did_version++ == 0)
957*8044SWilliam.Kucharski@Sun.COM 	printf (version);
958*8044SWilliam.Kucharski@Sun.COM 
959*8044SWilliam.Kucharski@Sun.COM     /* D-Link provided reset code (with comment additions) */
960*8044SWilliam.Kucharski@Sun.COM     if((chip_id != 0x3043) && (chip_id != 0x6100)) {
961*8044SWilliam.Kucharski@Sun.COM 	unsigned char byOrgValue;
962*8044SWilliam.Kucharski@Sun.COM 
963*8044SWilliam.Kucharski@Sun.COM 	if(rhine_debug > 0)
964*8044SWilliam.Kucharski@Sun.COM 		printf("Enabling Sticky Bit Workaround for Chip_id: 0x%hX\n"
965*8044SWilliam.Kucharski@Sun.COM 				, chip_id);
966*8044SWilliam.Kucharski@Sun.COM 	/* clear sticky bit before reset & read ethernet address */
967*8044SWilliam.Kucharski@Sun.COM 	byOrgValue = inb(bySTICKHW);
968*8044SWilliam.Kucharski@Sun.COM 	byOrgValue = byOrgValue & 0xFC;
969*8044SWilliam.Kucharski@Sun.COM 	outb(byOrgValue, bySTICKHW);
970*8044SWilliam.Kucharski@Sun.COM 
971*8044SWilliam.Kucharski@Sun.COM 	/* (bits written are cleared?) */
972*8044SWilliam.Kucharski@Sun.COM 	/* disable force PME-enable */
973*8044SWilliam.Kucharski@Sun.COM 	outb(0x80, byWOLcgClr);
974*8044SWilliam.Kucharski@Sun.COM 	/* disable power-event config bit */
975*8044SWilliam.Kucharski@Sun.COM 	outb(0xFF, byWOLcrClr);
976*8044SWilliam.Kucharski@Sun.COM 	/* clear power status (undocumented in vt6102 docs?) */
977*8044SWilliam.Kucharski@Sun.COM 	outb(0xFF, byPwrcsrClr);
978*8044SWilliam.Kucharski@Sun.COM 
979*8044SWilliam.Kucharski@Sun.COM     }
980*8044SWilliam.Kucharski@Sun.COM 
981*8044SWilliam.Kucharski@Sun.COM     /* Perhaps this should be read from the EEPROM? */
982*8044SWilliam.Kucharski@Sun.COM     for (i = 0; i < ETH_ALEN; i++)
983*8044SWilliam.Kucharski@Sun.COM 	nic->node_addr[i] = inb (byPAR0 + i);
984*8044SWilliam.Kucharski@Sun.COM     printf ("IO address %hX Ethernet Address: %!\n", ioaddr, nic->node_addr);
985*8044SWilliam.Kucharski@Sun.COM 
986*8044SWilliam.Kucharski@Sun.COM     /* restart MII auto-negotiation */
987*8044SWilliam.Kucharski@Sun.COM     WriteMII (0, 9, 1, ioaddr);
988*8044SWilliam.Kucharski@Sun.COM     printf ("Analyzing Media type,this will take several seconds........");
989*8044SWilliam.Kucharski@Sun.COM     for (i = 0; i < 5; i++)
990*8044SWilliam.Kucharski@Sun.COM     {
991*8044SWilliam.Kucharski@Sun.COM 	/* need to wait 1 millisecond - we will round it up to 50-100ms */
992*8044SWilliam.Kucharski@Sun.COM 	timeout = currticks() + 2;
993*8044SWilliam.Kucharski@Sun.COM 	for (timeout = currticks() + 2; currticks() < timeout;)
994*8044SWilliam.Kucharski@Sun.COM 	    /* nothing */;
995*8044SWilliam.Kucharski@Sun.COM 	if (ReadMII (1, ioaddr) & 0x0020)
996*8044SWilliam.Kucharski@Sun.COM 	    break;
997*8044SWilliam.Kucharski@Sun.COM     }
998*8044SWilliam.Kucharski@Sun.COM     printf ("OK\n");
999*8044SWilliam.Kucharski@Sun.COM 
1000*8044SWilliam.Kucharski@Sun.COM #if	0
1001*8044SWilliam.Kucharski@Sun.COM 	/* JJM : for Debug */
1002*8044SWilliam.Kucharski@Sun.COM 	printf("MII : Address %hhX ",inb(ioaddr+0x6c));
1003*8044SWilliam.Kucharski@Sun.COM 	{
1004*8044SWilliam.Kucharski@Sun.COM 	 unsigned char st1,st2,adv1,adv2,l1,l2;
1005*8044SWilliam.Kucharski@Sun.COM 
1006*8044SWilliam.Kucharski@Sun.COM 	 st1=ReadMII(1,ioaddr)>>8;
1007*8044SWilliam.Kucharski@Sun.COM 	 st2=ReadMII(1,ioaddr)&0xFF;
1008*8044SWilliam.Kucharski@Sun.COM 	 adv1=ReadMII(4,ioaddr)>>8;
1009*8044SWilliam.Kucharski@Sun.COM 	 adv2=ReadMII(4,ioaddr)&0xFF;
1010*8044SWilliam.Kucharski@Sun.COM 	 l1=ReadMII(5,ioaddr)>>8;
1011*8044SWilliam.Kucharski@Sun.COM 	 l2=ReadMII(5,ioaddr)&0xFF;
1012*8044SWilliam.Kucharski@Sun.COM 	 printf(" status 0x%hhX%hhX, advertising 0x%hhX%hhX, link 0x%hhX%hhX\n", st1,st2,adv1,adv2,l1,l2);
1013*8044SWilliam.Kucharski@Sun.COM 	}
1014*8044SWilliam.Kucharski@Sun.COM #endif
1015*8044SWilliam.Kucharski@Sun.COM 
1016*8044SWilliam.Kucharski@Sun.COM 
1017*8044SWilliam.Kucharski@Sun.COM     /* query MII to know LineSpeed,duplex mode */
1018*8044SWilliam.Kucharski@Sun.COM     byMIIvalue = inb (ioaddr + 0x6d);
1019*8044SWilliam.Kucharski@Sun.COM     LineSpeed = byMIIvalue & MIISR_SPEED;
1020*8044SWilliam.Kucharski@Sun.COM     if (LineSpeed != 0)						//JJM
1021*8044SWilliam.Kucharski@Sun.COM     {
1022*8044SWilliam.Kucharski@Sun.COM 	printf ("Linespeed=10Mbs");
1023*8044SWilliam.Kucharski@Sun.COM     }
1024*8044SWilliam.Kucharski@Sun.COM     else
1025*8044SWilliam.Kucharski@Sun.COM     {
1026*8044SWilliam.Kucharski@Sun.COM 	printf ("Linespeed=100Mbs");
1027*8044SWilliam.Kucharski@Sun.COM     }
1028*8044SWilliam.Kucharski@Sun.COM 
1029*8044SWilliam.Kucharski@Sun.COM     FDXFlag = QueryAuto (ioaddr);
1030*8044SWilliam.Kucharski@Sun.COM     if (FDXFlag == 1)
1031*8044SWilliam.Kucharski@Sun.COM     {
1032*8044SWilliam.Kucharski@Sun.COM 	printf (" Fullduplex\n");
1033*8044SWilliam.Kucharski@Sun.COM 	outw (CR_FDX, byCR0);
1034*8044SWilliam.Kucharski@Sun.COM     }
1035*8044SWilliam.Kucharski@Sun.COM     else
1036*8044SWilliam.Kucharski@Sun.COM     {
1037*8044SWilliam.Kucharski@Sun.COM 	printf (" Halfduplex\n");
1038*8044SWilliam.Kucharski@Sun.COM     }
1039*8044SWilliam.Kucharski@Sun.COM 
1040*8044SWilliam.Kucharski@Sun.COM 
1041*8044SWilliam.Kucharski@Sun.COM     /* set MII 10 FULL ON */
1042*8044SWilliam.Kucharski@Sun.COM     WriteMII (17, 1, 1, ioaddr);
1043*8044SWilliam.Kucharski@Sun.COM 
1044*8044SWilliam.Kucharski@Sun.COM     /* turn on MII link change */
1045*8044SWilliam.Kucharski@Sun.COM     MIICRbak = inb (byMIICR);
1046*8044SWilliam.Kucharski@Sun.COM     outb (MIICRbak & 0x7F, byMIICR);
1047*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
1048*8044SWilliam.Kucharski@Sun.COM     outb (0x41, byMIIAD);
1049*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
1050*8044SWilliam.Kucharski@Sun.COM 
1051*8044SWilliam.Kucharski@Sun.COM     /* while((inb(byMIIAD)&0x20)==0) ; */
1052*8044SWilliam.Kucharski@Sun.COM     outb (MIICRbak | 0x80, byMIICR);
1053*8044SWilliam.Kucharski@Sun.COM 
1054*8044SWilliam.Kucharski@Sun.COM     nic->priv_data = &rhine;
1055*8044SWilliam.Kucharski@Sun.COM     tp = &rhine;
1056*8044SWilliam.Kucharski@Sun.COM     tp->chip_id = chip_id;
1057*8044SWilliam.Kucharski@Sun.COM     tp->ioaddr = ioaddr;
1058*8044SWilliam.Kucharski@Sun.COM     tp->phys[0] = -1;
1059*8044SWilliam.Kucharski@Sun.COM 
1060*8044SWilliam.Kucharski@Sun.COM     /* The lower four bits are the media type. */
1061*8044SWilliam.Kucharski@Sun.COM     if (options > 0)
1062*8044SWilliam.Kucharski@Sun.COM     {
1063*8044SWilliam.Kucharski@Sun.COM 	tp->full_duplex = (options & 16) ? 1 : 0;
1064*8044SWilliam.Kucharski@Sun.COM 	tp->default_port = options & 15;
1065*8044SWilliam.Kucharski@Sun.COM 	if (tp->default_port)
1066*8044SWilliam.Kucharski@Sun.COM 	    tp->medialock = 1;
1067*8044SWilliam.Kucharski@Sun.COM     }
1068*8044SWilliam.Kucharski@Sun.COM     return;
1069*8044SWilliam.Kucharski@Sun.COM }
1070*8044SWilliam.Kucharski@Sun.COM 
1071*8044SWilliam.Kucharski@Sun.COM static void
rhine_disable(struct dev * dev)1072*8044SWilliam.Kucharski@Sun.COM rhine_disable (struct dev *dev)
1073*8044SWilliam.Kucharski@Sun.COM {
1074*8044SWilliam.Kucharski@Sun.COM     struct nic *nic = (struct nic *)dev;
1075*8044SWilliam.Kucharski@Sun.COM     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
1076*8044SWilliam.Kucharski@Sun.COM     int ioaddr = tp->ioaddr;
1077*8044SWilliam.Kucharski@Sun.COM 
1078*8044SWilliam.Kucharski@Sun.COM     /* merge reset and disable */
1079*8044SWilliam.Kucharski@Sun.COM     rhine_reset(nic);
1080*8044SWilliam.Kucharski@Sun.COM 
1081*8044SWilliam.Kucharski@Sun.COM     printf ("rhine disable\n");
1082*8044SWilliam.Kucharski@Sun.COM     /* Switch to loopback mode to avoid hardware races. */
1083*8044SWilliam.Kucharski@Sun.COM     writeb(0x60 | 0x01, byTCR);
1084*8044SWilliam.Kucharski@Sun.COM     /* Stop the chip's Tx and Rx processes. */
1085*8044SWilliam.Kucharski@Sun.COM     writew(CR_STOP, byCR0);
1086*8044SWilliam.Kucharski@Sun.COM }
1087*8044SWilliam.Kucharski@Sun.COM 
1088*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
1089*8044SWilliam.Kucharski@Sun.COM ETH_RESET - Reset adapter
1090*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
1091*8044SWilliam.Kucharski@Sun.COM static void
rhine_reset(struct nic * nic)1092*8044SWilliam.Kucharski@Sun.COM rhine_reset (struct nic *nic)
1093*8044SWilliam.Kucharski@Sun.COM {
1094*8044SWilliam.Kucharski@Sun.COM     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
1095*8044SWilliam.Kucharski@Sun.COM     int ioaddr = tp->ioaddr;
1096*8044SWilliam.Kucharski@Sun.COM     int i, j;
1097*8044SWilliam.Kucharski@Sun.COM     int FDXFlag, CRbak;
1098*8044SWilliam.Kucharski@Sun.COM     int rx_ring_tmp, rx_ring_tmp1;
1099*8044SWilliam.Kucharski@Sun.COM     int tx_ring_tmp, tx_ring_tmp1;
1100*8044SWilliam.Kucharski@Sun.COM     int rx_bufs_tmp, rx_bufs_tmp1;
1101*8044SWilliam.Kucharski@Sun.COM     int tx_bufs_tmp, tx_bufs_tmp1;
1102*8044SWilliam.Kucharski@Sun.COM 
1103*8044SWilliam.Kucharski@Sun.COM     static char buf1[RX_RING_SIZE * PKT_BUF_SZ + 32];
1104*8044SWilliam.Kucharski@Sun.COM     static char buf2[RX_RING_SIZE * PKT_BUF_SZ + 32];
1105*8044SWilliam.Kucharski@Sun.COM     static char desc1[TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32];
1106*8044SWilliam.Kucharski@Sun.COM     static char desc2[TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32];
1107*8044SWilliam.Kucharski@Sun.COM 
1108*8044SWilliam.Kucharski@Sun.COM     /* printf ("rhine_reset\n"); */
1109*8044SWilliam.Kucharski@Sun.COM     /* Soft reset the chip. */
1110*8044SWilliam.Kucharski@Sun.COM     /*outb(CmdReset, ioaddr + ChipCmd); */
1111*8044SWilliam.Kucharski@Sun.COM 
1112*8044SWilliam.Kucharski@Sun.COM     tx_bufs_tmp = (int) buf1;
1113*8044SWilliam.Kucharski@Sun.COM     tx_ring_tmp = (int) desc1;
1114*8044SWilliam.Kucharski@Sun.COM     rx_bufs_tmp = (int) buf2;
1115*8044SWilliam.Kucharski@Sun.COM     rx_ring_tmp = (int) desc2;
1116*8044SWilliam.Kucharski@Sun.COM 
1117*8044SWilliam.Kucharski@Sun.COM     /* tune RD TD 32 byte alignment */
1118*8044SWilliam.Kucharski@Sun.COM     rx_ring_tmp1 = (int) virt_to_bus ((char *) rx_ring_tmp);
1119*8044SWilliam.Kucharski@Sun.COM     j = (rx_ring_tmp1 + 32) & (~0x1f);
1120*8044SWilliam.Kucharski@Sun.COM     /* printf ("txring[%d]", j); */
1121*8044SWilliam.Kucharski@Sun.COM     tp->rx_ring = (struct rhine_rx_desc *) bus_to_virt (j);
1122*8044SWilliam.Kucharski@Sun.COM 
1123*8044SWilliam.Kucharski@Sun.COM     tx_ring_tmp1 = (int) virt_to_bus ((char *) tx_ring_tmp);
1124*8044SWilliam.Kucharski@Sun.COM     j = (tx_ring_tmp1 + 32) & (~0x1f);
1125*8044SWilliam.Kucharski@Sun.COM     tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j);
1126*8044SWilliam.Kucharski@Sun.COM     /* printf ("rxring[%X]", j); */
1127*8044SWilliam.Kucharski@Sun.COM 
1128*8044SWilliam.Kucharski@Sun.COM 
1129*8044SWilliam.Kucharski@Sun.COM     tx_bufs_tmp1 = (int) virt_to_bus ((char *) tx_bufs_tmp);
1130*8044SWilliam.Kucharski@Sun.COM     j = (int) (tx_bufs_tmp1 + 32) & (~0x1f);
1131*8044SWilliam.Kucharski@Sun.COM     tx_bufs_tmp = (int) bus_to_virt (j);
1132*8044SWilliam.Kucharski@Sun.COM     /* printf ("txb[%X]", j); */
1133*8044SWilliam.Kucharski@Sun.COM 
1134*8044SWilliam.Kucharski@Sun.COM     rx_bufs_tmp1 = (int) virt_to_bus ((char *) rx_bufs_tmp);
1135*8044SWilliam.Kucharski@Sun.COM     j = (int) (rx_bufs_tmp1 + 32) & (~0x1f);
1136*8044SWilliam.Kucharski@Sun.COM     rx_bufs_tmp = (int) bus_to_virt (j);
1137*8044SWilliam.Kucharski@Sun.COM     /* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */
1138*8044SWilliam.Kucharski@Sun.COM 
1139*8044SWilliam.Kucharski@Sun.COM     for (i = 0; i < RX_RING_SIZE; i++)
1140*8044SWilliam.Kucharski@Sun.COM     {
1141*8044SWilliam.Kucharski@Sun.COM 	tp->rx_buffs[i] = (char *) rx_bufs_tmp;
1142*8044SWilliam.Kucharski@Sun.COM 	/* printf("r[%X]",tp->rx_buffs[i]); */
1143*8044SWilliam.Kucharski@Sun.COM 	rx_bufs_tmp += 1536;
1144*8044SWilliam.Kucharski@Sun.COM     }
1145*8044SWilliam.Kucharski@Sun.COM 
1146*8044SWilliam.Kucharski@Sun.COM     for (i = 0; i < TX_RING_SIZE; i++)
1147*8044SWilliam.Kucharski@Sun.COM     {
1148*8044SWilliam.Kucharski@Sun.COM 	tp->tx_buffs[i] = (char *) tx_bufs_tmp;
1149*8044SWilliam.Kucharski@Sun.COM 	/* printf("t[%X]",tp->tx_buffs[i]);  */
1150*8044SWilliam.Kucharski@Sun.COM 	tx_bufs_tmp += 1536;
1151*8044SWilliam.Kucharski@Sun.COM     }
1152*8044SWilliam.Kucharski@Sun.COM 
1153*8044SWilliam.Kucharski@Sun.COM     /* software reset */
1154*8044SWilliam.Kucharski@Sun.COM     outb (CR1_SFRST, byCR1);
1155*8044SWilliam.Kucharski@Sun.COM     MIIDelay ();
1156*8044SWilliam.Kucharski@Sun.COM 
1157*8044SWilliam.Kucharski@Sun.COM     /* printf ("init ring"); */
1158*8044SWilliam.Kucharski@Sun.COM     rhine_init_ring (nic);
1159*8044SWilliam.Kucharski@Sun.COM     /*write TD RD Descriptor to MAC */
1160*8044SWilliam.Kucharski@Sun.COM     outl (virt_to_bus (tp->rx_ring), dwCurrentRxDescAddr);
1161*8044SWilliam.Kucharski@Sun.COM     outl (virt_to_bus (tp->tx_ring), dwCurrentTxDescAddr);
1162*8044SWilliam.Kucharski@Sun.COM 
1163*8044SWilliam.Kucharski@Sun.COM     /* Setup Multicast */
1164*8044SWilliam.Kucharski@Sun.COM     set_rx_mode(nic);
1165*8044SWilliam.Kucharski@Sun.COM 
1166*8044SWilliam.Kucharski@Sun.COM     /* close IMR */
1167*8044SWilliam.Kucharski@Sun.COM     outw (0x0000, byIMR0);
1168*8044SWilliam.Kucharski@Sun.COM 
1169*8044SWilliam.Kucharski@Sun.COM     /* set TCR RCR threshold */
1170*8044SWilliam.Kucharski@Sun.COM     outb (0x06, byBCR0);
1171*8044SWilliam.Kucharski@Sun.COM     outb (0x00, byBCR1);
1172*8044SWilliam.Kucharski@Sun.COM     outb (0x2c, byRCR);
1173*8044SWilliam.Kucharski@Sun.COM     outb (0x60, byTCR);
1174*8044SWilliam.Kucharski@Sun.COM     /* Set Fulldupex */
1175*8044SWilliam.Kucharski@Sun.COM     FDXFlag = QueryAuto (ioaddr);
1176*8044SWilliam.Kucharski@Sun.COM     if (FDXFlag == 1)
1177*8044SWilliam.Kucharski@Sun.COM     {
1178*8044SWilliam.Kucharski@Sun.COM 	outb (CFGD_CFDX, byCFGD);
1179*8044SWilliam.Kucharski@Sun.COM 	outw (CR_FDX, byCR0);
1180*8044SWilliam.Kucharski@Sun.COM     }
1181*8044SWilliam.Kucharski@Sun.COM 
1182*8044SWilliam.Kucharski@Sun.COM     /* KICK NIC to WORK */
1183*8044SWilliam.Kucharski@Sun.COM     CRbak = inw (byCR0);
1184*8044SWilliam.Kucharski@Sun.COM     CRbak = CRbak & 0xFFFB;	/* not CR_STOP */
1185*8044SWilliam.Kucharski@Sun.COM     outw ((CRbak | CR_STRT | CR_TXON | CR_RXON | CR_DPOLL), byCR0);
1186*8044SWilliam.Kucharski@Sun.COM 
1187*8044SWilliam.Kucharski@Sun.COM     /*set IMR to work */
1188*8044SWilliam.Kucharski@Sun.COM     outw (IMRShadow, byIMR0);
1189*8044SWilliam.Kucharski@Sun.COM }
1190*8044SWilliam.Kucharski@Sun.COM /* Beware of PCI posted writes */
1191*8044SWilliam.Kucharski@Sun.COM #define IOSYNC  do { readb(nic->ioaddr + StationAddr); } while (0)
1192*8044SWilliam.Kucharski@Sun.COM 
1193*8044SWilliam.Kucharski@Sun.COM static int
rhine_poll(struct nic * nic,int retreive)1194*8044SWilliam.Kucharski@Sun.COM rhine_poll (struct nic *nic, int retreive)
1195*8044SWilliam.Kucharski@Sun.COM {
1196*8044SWilliam.Kucharski@Sun.COM     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
1197*8044SWilliam.Kucharski@Sun.COM     int rxstatus, good = 0;;
1198*8044SWilliam.Kucharski@Sun.COM 
1199*8044SWilliam.Kucharski@Sun.COM     if (tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit == 0)
1200*8044SWilliam.Kucharski@Sun.COM     {
1201*8044SWilliam.Kucharski@Sun.COM         unsigned int intr_status;
1202*8044SWilliam.Kucharski@Sun.COM         /* There is a packet ready */
1203*8044SWilliam.Kucharski@Sun.COM         if(!retreive)
1204*8044SWilliam.Kucharski@Sun.COM             return 1;
1205*8044SWilliam.Kucharski@Sun.COM 
1206*8044SWilliam.Kucharski@Sun.COM         intr_status = inw(nic->ioaddr + IntrStatus);
1207*8044SWilliam.Kucharski@Sun.COM         /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
1208*8044SWilliam.Kucharski@Sun.COM #if 0
1209*8044SWilliam.Kucharski@Sun.COM 	if (tp->chip_id == 0x3065)
1210*8044SWilliam.Kucharski@Sun.COM 	  intr_status |= inb(nic->ioaddr + IntrStatus2) << 16;
1211*8044SWilliam.Kucharski@Sun.COM #endif
1212*8044SWilliam.Kucharski@Sun.COM         /* Acknowledge all of the current interrupt sources ASAP. */
1213*8044SWilliam.Kucharski@Sun.COM         if (intr_status & IntrTxDescRace)
1214*8044SWilliam.Kucharski@Sun.COM            outb(0x08, nic->ioaddr + IntrStatus2);
1215*8044SWilliam.Kucharski@Sun.COM         outw(intr_status & 0xffff, nic->ioaddr + IntrStatus);
1216*8044SWilliam.Kucharski@Sun.COM 	IOSYNC;
1217*8044SWilliam.Kucharski@Sun.COM 
1218*8044SWilliam.Kucharski@Sun.COM 	rxstatus = tp->rx_ring[tp->cur_rx].rx_status.lw;
1219*8044SWilliam.Kucharski@Sun.COM 	if ((rxstatus & 0x0300) != 0x0300)
1220*8044SWilliam.Kucharski@Sun.COM 	{
1221*8044SWilliam.Kucharski@Sun.COM 	    printf("rhine_poll: bad status\n");
1222*8044SWilliam.Kucharski@Sun.COM 	}
1223*8044SWilliam.Kucharski@Sun.COM 	else if (rxstatus & (RSR_ABNORMAL))
1224*8044SWilliam.Kucharski@Sun.COM 	{
1225*8044SWilliam.Kucharski@Sun.COM 	    printf ("rxerr[%X]\n", rxstatus);
1226*8044SWilliam.Kucharski@Sun.COM 	}
1227*8044SWilliam.Kucharski@Sun.COM 	else
1228*8044SWilliam.Kucharski@Sun.COM 	    good = 1;
1229*8044SWilliam.Kucharski@Sun.COM 
1230*8044SWilliam.Kucharski@Sun.COM 	if (good)
1231*8044SWilliam.Kucharski@Sun.COM 	{
1232*8044SWilliam.Kucharski@Sun.COM 	    nic->packetlen = tp->rx_ring[tp->cur_rx].rx_status.bits.frame_length;
1233*8044SWilliam.Kucharski@Sun.COM 	    memcpy (nic->packet, tp->rx_buffs[tp->cur_rx], nic->packetlen);
1234*8044SWilliam.Kucharski@Sun.COM 	    /* printf ("Packet RXed\n"); */
1235*8044SWilliam.Kucharski@Sun.COM 	}
1236*8044SWilliam.Kucharski@Sun.COM 	tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit = 1;
1237*8044SWilliam.Kucharski@Sun.COM 	tp->cur_rx++;
1238*8044SWilliam.Kucharski@Sun.COM 	tp->cur_rx = tp->cur_rx % RX_RING_SIZE;
1239*8044SWilliam.Kucharski@Sun.COM     }
1240*8044SWilliam.Kucharski@Sun.COM         /* Acknowledge all of the current interrupt sources ASAP. */
1241*8044SWilliam.Kucharski@Sun.COM         outw(DEFAULT_INTR & ~IntrRxDone, nic->ioaddr + IntrStatus);
1242*8044SWilliam.Kucharski@Sun.COM 
1243*8044SWilliam.Kucharski@Sun.COM         IOSYNC;
1244*8044SWilliam.Kucharski@Sun.COM 
1245*8044SWilliam.Kucharski@Sun.COM     return good;
1246*8044SWilliam.Kucharski@Sun.COM }
1247*8044SWilliam.Kucharski@Sun.COM 
1248*8044SWilliam.Kucharski@Sun.COM static void
rhine_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)1249*8044SWilliam.Kucharski@Sun.COM rhine_transmit (struct nic *nic,
1250*8044SWilliam.Kucharski@Sun.COM 		const char *d, unsigned int t, unsigned int s, const char *p)
1251*8044SWilliam.Kucharski@Sun.COM {
1252*8044SWilliam.Kucharski@Sun.COM     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
1253*8044SWilliam.Kucharski@Sun.COM     int ioaddr = tp->ioaddr;
1254*8044SWilliam.Kucharski@Sun.COM     int entry;
1255*8044SWilliam.Kucharski@Sun.COM     unsigned char CR1bak;
1256*8044SWilliam.Kucharski@Sun.COM 
1257*8044SWilliam.Kucharski@Sun.COM     /*printf ("rhine_transmit\n"); */
1258*8044SWilliam.Kucharski@Sun.COM     /* setup ethernet header */
1259*8044SWilliam.Kucharski@Sun.COM 
1260*8044SWilliam.Kucharski@Sun.COM 
1261*8044SWilliam.Kucharski@Sun.COM     /* Calculate the next Tx descriptor entry. */
1262*8044SWilliam.Kucharski@Sun.COM     entry = tp->cur_tx % TX_RING_SIZE;
1263*8044SWilliam.Kucharski@Sun.COM 
1264*8044SWilliam.Kucharski@Sun.COM     memcpy (tp->tx_buffs[entry], d, ETH_ALEN);	/* dst */
1265*8044SWilliam.Kucharski@Sun.COM     memcpy (tp->tx_buffs[entry] + ETH_ALEN, nic->node_addr, ETH_ALEN);	/* src */
1266*8044SWilliam.Kucharski@Sun.COM     *((char *) tp->tx_buffs[entry] + 12) = t >> 8;	/* type */
1267*8044SWilliam.Kucharski@Sun.COM     *((char *) tp->tx_buffs[entry] + 13) = t;
1268*8044SWilliam.Kucharski@Sun.COM     memcpy (tp->tx_buffs[entry] + ETH_HLEN, p, s);
1269*8044SWilliam.Kucharski@Sun.COM     s += ETH_HLEN;
1270*8044SWilliam.Kucharski@Sun.COM     while (s < ETH_ZLEN)
1271*8044SWilliam.Kucharski@Sun.COM 	*((char *) tp->tx_buffs[entry] + ETH_HLEN + (s++)) = 0;
1272*8044SWilliam.Kucharski@Sun.COM 
1273*8044SWilliam.Kucharski@Sun.COM     tp->tx_ring[entry].tx_ctrl.bits.tx_buf_size = s;
1274*8044SWilliam.Kucharski@Sun.COM 
1275*8044SWilliam.Kucharski@Sun.COM     tp->tx_ring[entry].tx_status.bits.own_bit = 1;
1276*8044SWilliam.Kucharski@Sun.COM 
1277*8044SWilliam.Kucharski@Sun.COM 
1278*8044SWilliam.Kucharski@Sun.COM     CR1bak = inb (byCR1);
1279*8044SWilliam.Kucharski@Sun.COM 
1280*8044SWilliam.Kucharski@Sun.COM     CR1bak = CR1bak | CR1_TDMD1;
1281*8044SWilliam.Kucharski@Sun.COM     /*printf("tdsw=[%X]",tp->tx_ring[entry].tx_status.lw); */
1282*8044SWilliam.Kucharski@Sun.COM     /*printf("tdcw=[%X]",tp->tx_ring[entry].tx_ctrl.lw); */
1283*8044SWilliam.Kucharski@Sun.COM     /*printf("tdbuf1=[%X]",tp->tx_ring[entry].buf_addr_1); */
1284*8044SWilliam.Kucharski@Sun.COM     /*printf("tdbuf2=[%X]",tp->tx_ring[entry].buf_addr_2); */
1285*8044SWilliam.Kucharski@Sun.COM     /*printf("td1=[%X]",inl(dwCurrentTDSE0)); */
1286*8044SWilliam.Kucharski@Sun.COM     /*printf("td2=[%X]",inl(dwCurrentTDSE1)); */
1287*8044SWilliam.Kucharski@Sun.COM     /*printf("td3=[%X]",inl(dwCurrentTDSE2)); */
1288*8044SWilliam.Kucharski@Sun.COM     /*printf("td4=[%X]",inl(dwCurrentTDSE3)); */
1289*8044SWilliam.Kucharski@Sun.COM 
1290*8044SWilliam.Kucharski@Sun.COM     outb (CR1bak, byCR1);
1291*8044SWilliam.Kucharski@Sun.COM     /* Wait until transmit is finished */
1292*8044SWilliam.Kucharski@Sun.COM     while (tp->tx_ring[entry].tx_status.bits.own_bit != 0)
1293*8044SWilliam.Kucharski@Sun.COM 	;
1294*8044SWilliam.Kucharski@Sun.COM     tp->cur_tx++;
1295*8044SWilliam.Kucharski@Sun.COM 
1296*8044SWilliam.Kucharski@Sun.COM     /*outw(IMRShadow,byIMR0); */
1297*8044SWilliam.Kucharski@Sun.COM     /*dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE); */
1298*8044SWilliam.Kucharski@Sun.COM     /*tp->tx_skbuff[entry] = 0; */
1299*8044SWilliam.Kucharski@Sun.COM }
1300*8044SWilliam.Kucharski@Sun.COM 
1301*8044SWilliam.Kucharski@Sun.COM static struct pci_id rhine_nics[] = {
1302*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1106, 0x3065, "dlink-530tx",     "VIA 6102"),
1303*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1106, 0x3106, "via-rhine-6105",  "VIA 6105"),
1304*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1106, 0x3043, "dlink-530tx-old", "VIA 3043"),		/* Rhine-I 86c100a */
1305*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1106, 0x3053, "via6105m",        "VIA 6105M"),
1306*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1106, 0x6100, "via-rhine-old",   "VIA 86C100A"),	/* Rhine-II */
1307*8044SWilliam.Kucharski@Sun.COM };
1308*8044SWilliam.Kucharski@Sun.COM 
1309*8044SWilliam.Kucharski@Sun.COM struct pci_driver rhine_driver = {
1310*8044SWilliam.Kucharski@Sun.COM 	.type     = NIC_DRIVER,
1311*8044SWilliam.Kucharski@Sun.COM 	.name     = "VIA 86C100",
1312*8044SWilliam.Kucharski@Sun.COM 	.probe    = rhine_probe,
1313*8044SWilliam.Kucharski@Sun.COM 	.ids      = rhine_nics,
1314*8044SWilliam.Kucharski@Sun.COM 	.id_count = sizeof(rhine_nics)/sizeof(rhine_nics[0]),
1315*8044SWilliam.Kucharski@Sun.COM 	.class    = 0,
1316*8044SWilliam.Kucharski@Sun.COM };
1317*8044SWilliam.Kucharski@Sun.COM 
1318*8044SWilliam.Kucharski@Sun.COM /* EOF via-rhine.c */
1319