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