forcedeth.c 184 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
/*
 * forcedeth: Ethernet driver for NVIDIA nForce media access controllers.
 *
 * Note: This driver is a cleanroom reimplementation based on reverse
 *      engineered documentation written by Carl-Daniel Hailfinger
6
 *      and Andrew de Quincey.
Linus Torvalds's avatar
Linus Torvalds committed
7
8
9
10
11
 *
 * NVIDIA, nForce and other NVIDIA marks are trademarks or registered
 * trademarks of NVIDIA Corporation in the United States and other
 * countries.
 *
12
 * Copyright (C) 2003,4,5 Manfred Spraul
Linus Torvalds's avatar
Linus Torvalds committed
13
14
15
 * Copyright (C) 2004 Andrew de Quincey (wol support)
 * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
 *		IRQ rate fixes, bigendian fixes, cleanups, verification)
16
 * Copyright (c) 2004,2005,2006,2007,2008 NVIDIA Corporation
Linus Torvalds's avatar
Linus Torvalds committed
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Known bugs:
 * We suspect that on some hardware no TX done interrupts are generated.
 * This means recovery from netif_stop_queue only happens if the hw timer
 * interrupt fires (100 times/second, configurable with NVREG_POLL_DEFAULT)
 * and the timer is active in the IRQMask, or if a rx packet arrives by chance.
 * If your hardware reliably generates tx done interrupts, then you can remove
 * DEV_NEED_TIMERIRQ from the driver_data flags.
 * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
 * superfluous timer interrupts from the nic.
 */
42
#define FORCEDETH_VERSION		"0.61"
Linus Torvalds's avatar
Linus Torvalds committed
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#define DRV_NAME			"forcedeth"

#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
#include <linux/mii.h>
#include <linux/random.h>
#include <linux/init.h>
59
#include <linux/if_vlan.h>
60
#include <linux/dma-mapping.h>
Linus Torvalds's avatar
Linus Torvalds committed
61
62
63
64
65
66
67
68
69
70
71
72

#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>

#if 0
#define dprintk			printk
#else
#define dprintk(x...)		do { } while (0)
#endif

73
74
#define TX_WORK_PER_LOOP  64
#define RX_WORK_PER_LOOP  64
Linus Torvalds's avatar
Linus Torvalds committed
75
76
77
78
79

/*
 * Hardware access:
 */

Ayaz Abdulla's avatar
Ayaz Abdulla committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#define DEV_NEED_TIMERIRQ          0x00001  /* set the timer irq flag in the irq mask */
#define DEV_NEED_LINKTIMER         0x00002  /* poll link settings. Relies on the timer irq */
#define DEV_HAS_LARGEDESC          0x00004  /* device supports jumbo frames and needs packet format 2 */
#define DEV_HAS_HIGH_DMA           0x00008  /* device supports 64bit dma */
#define DEV_HAS_CHECKSUM           0x00010  /* device supports tx and rx checksum offloads */
#define DEV_HAS_VLAN               0x00020  /* device supports vlan tagging and striping */
#define DEV_HAS_MSI                0x00040  /* device supports MSI */
#define DEV_HAS_MSI_X              0x00080  /* device supports MSI-X */
#define DEV_HAS_POWER_CNTRL        0x00100  /* device supports power savings */
#define DEV_HAS_STATISTICS_V1      0x00200  /* device supports hw statistics version 1 */
#define DEV_HAS_STATISTICS_V2      0x00400  /* device supports hw statistics version 2 */
#define DEV_HAS_TEST_EXTENDED      0x00800  /* device supports extended diagnostic test */
#define DEV_HAS_MGMT_UNIT          0x01000  /* device supports management unit */
#define DEV_HAS_CORRECT_MACADDR    0x02000  /* device supports correct mac address order */
#define DEV_HAS_COLLISION_FIX      0x04000  /* device supports tx collision fix */
#define DEV_HAS_PAUSEFRAME_TX_V1   0x08000  /* device supports tx pause frames version 1 */
#define DEV_HAS_PAUSEFRAME_TX_V2   0x10000  /* device supports tx pause frames version 2 */
#define DEV_HAS_PAUSEFRAME_TX_V3   0x20000  /* device supports tx pause frames version 3 */
Ayaz Abdulla's avatar
Ayaz Abdulla committed
98
#define DEV_NEED_TX_LIMIT          0x40000  /* device needs to limit tx */
99
#define DEV_HAS_GEAR_MODE          0x80000  /* device supports gear mode */
Linus Torvalds's avatar
Linus Torvalds committed
100
101
102
103

enum {
	NvRegIrqStatus = 0x000,
#define NVREG_IRQSTAT_MIIEVENT	0x040
104
#define NVREG_IRQSTAT_MASK		0x81ff
Linus Torvalds's avatar
Linus Torvalds committed
105
106
107
108
109
	NvRegIrqMask = 0x004,
#define NVREG_IRQ_RX_ERROR		0x0001
#define NVREG_IRQ_RX			0x0002
#define NVREG_IRQ_RX_NOBUF		0x0004
#define NVREG_IRQ_TX_ERR		0x0008
110
#define NVREG_IRQ_TX_OK			0x0010
Linus Torvalds's avatar
Linus Torvalds committed
111
112
#define NVREG_IRQ_TIMER			0x0020
#define NVREG_IRQ_LINK			0x0040
113
114
#define NVREG_IRQ_RX_FORCED		0x0080
#define NVREG_IRQ_TX_FORCED		0x0100
115
#define NVREG_IRQ_RECOVER_ERROR		0x8000
116
#define NVREG_IRQMASK_THROUGHPUT	0x00df
Ayaz Abdulla's avatar
Ayaz Abdulla committed
117
#define NVREG_IRQMASK_CPU		0x0060
118
119
#define NVREG_IRQ_TX_ALL		(NVREG_IRQ_TX_ERR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED)
#define NVREG_IRQ_RX_ALL		(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED)
120
#define NVREG_IRQ_OTHER			(NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RECOVER_ERROR)
121
122

#define NVREG_IRQ_UNKNOWN	(~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
123
					NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED| \
124
					NVREG_IRQ_TX_FORCED|NVREG_IRQ_RECOVER_ERROR))
Linus Torvalds's avatar
Linus Torvalds committed
125
126
127
128
129
130
131
132
133

	NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL		3

/*
 * NVREG_POLL_DEFAULT is the interval length of the timer source on the nic
 * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
 */
	NvRegPollingInterval = 0x00c,
Ayaz Abdulla's avatar
Ayaz Abdulla committed
134
#define NVREG_POLL_DEFAULT_THROUGHPUT	970 /* backup tx cleanup if loop max reached */
135
#define NVREG_POLL_DEFAULT_CPU	13
136
137
138
139
	NvRegMSIMap0 = 0x020,
	NvRegMSIMap1 = 0x024,
	NvRegMSIIrqMask = 0x030,
#define NVREG_MSI_VECTOR_0_ENABLED 0x01
Linus Torvalds's avatar
Linus Torvalds committed
140
	NvRegMisc1 = 0x080,
141
#define NVREG_MISC1_PAUSE_TX	0x01
Linus Torvalds's avatar
Linus Torvalds committed
142
143
144
#define NVREG_MISC1_HD		0x02
#define NVREG_MISC1_FORCE	0x3b0f3c

Ayaz Abdulla's avatar
Ayaz Abdulla committed
145
	NvRegMacReset = 0x34,
146
#define NVREG_MAC_RESET_ASSERT	0x0F3
Linus Torvalds's avatar
Linus Torvalds committed
147
148
	NvRegTransmitterControl = 0x084,
#define NVREG_XMITCTL_START	0x01
149
150
151
152
153
154
155
156
157
#define NVREG_XMITCTL_MGMT_ST	0x40000000
#define NVREG_XMITCTL_SYNC_MASK		0x000f0000
#define NVREG_XMITCTL_SYNC_NOT_READY	0x0
#define NVREG_XMITCTL_SYNC_PHY_INIT	0x00040000
#define NVREG_XMITCTL_MGMT_SEMA_MASK	0x00000f00
#define NVREG_XMITCTL_MGMT_SEMA_FREE	0x0
#define NVREG_XMITCTL_HOST_SEMA_MASK	0x0000f000
#define NVREG_XMITCTL_HOST_SEMA_ACQ	0x0000f000
#define NVREG_XMITCTL_HOST_LOADED	0x00004000
158
#define NVREG_XMITCTL_TX_PATH_EN	0x01000000
Linus Torvalds's avatar
Linus Torvalds committed
159
160
161
162
	NvRegTransmitterStatus = 0x088,
#define NVREG_XMITSTAT_BUSY	0x01

	NvRegPacketFilterFlags = 0x8c,
163
164
#define NVREG_PFF_PAUSE_RX	0x08
#define NVREG_PFF_ALWAYS	0x7F0000
Linus Torvalds's avatar
Linus Torvalds committed
165
166
#define NVREG_PFF_PROMISC	0x80
#define NVREG_PFF_MYADDR	0x20
167
#define NVREG_PFF_LOOPBACK	0x10
Linus Torvalds's avatar
Linus Torvalds committed
168
169
170
171
172
173

	NvRegOffloadConfig = 0x90,
#define NVREG_OFFLOAD_HOMEPHY	0x601
#define NVREG_OFFLOAD_NORMAL	RX_NIC_BUFSIZE
	NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START	0x01
174
#define NVREG_RCVCTL_RX_PATH_EN	0x01000000
Linus Torvalds's avatar
Linus Torvalds committed
175
176
177
	NvRegReceiverStatus = 0x98,
#define NVREG_RCVSTAT_BUSY	0x01

178
179
180
181
182
183
184
	NvRegSlotTime = 0x9c,
#define NVREG_SLOTTIME_LEGBF_ENABLED	0x80000000
#define NVREG_SLOTTIME_10_100_FULL	0x00007f00
#define NVREG_SLOTTIME_1000_FULL 	0x0003ff00
#define NVREG_SLOTTIME_HALF		0x0000ff00
#define NVREG_SLOTTIME_DEFAULT	 	0x00007f00
#define NVREG_SLOTTIME_MASK		0x000000ff
Linus Torvalds's avatar
Linus Torvalds committed
185

186
	NvRegTxDeferral = 0xA0,
Ayaz Abdulla's avatar
Ayaz Abdulla committed
187
188
189
190
191
192
#define NVREG_TX_DEFERRAL_DEFAULT		0x15050f
#define NVREG_TX_DEFERRAL_RGMII_10_100		0x16070f
#define NVREG_TX_DEFERRAL_RGMII_1000		0x14050f
#define NVREG_TX_DEFERRAL_RGMII_STRETCH_10	0x16190f
#define NVREG_TX_DEFERRAL_RGMII_STRETCH_100	0x16300f
#define NVREG_TX_DEFERRAL_MII_STRETCH		0x152000
193
194
	NvRegRxDeferral = 0xA4,
#define NVREG_RX_DEFERRAL_DEFAULT	0x16
Linus Torvalds's avatar
Linus Torvalds committed
195
196
197
198
199
200
	NvRegMacAddrA = 0xA8,
	NvRegMacAddrB = 0xAC,
	NvRegMulticastAddrA = 0xB0,
#define NVREG_MCASTADDRA_FORCE	0x01
	NvRegMulticastAddrB = 0xB4,
	NvRegMulticastMaskA = 0xB8,
Ayaz Abdulla's avatar
Ayaz Abdulla committed
201
#define NVREG_MCASTMASKA_NONE		0xffffffff
Linus Torvalds's avatar
Linus Torvalds committed
202
	NvRegMulticastMaskB = 0xBC,
Ayaz Abdulla's avatar
Ayaz Abdulla committed
203
#define NVREG_MCASTMASKB_NONE		0xffff
Linus Torvalds's avatar
Linus Torvalds committed
204
205
206

	NvRegPhyInterface = 0xC0,
#define PHY_RGMII		0x10000000
207
208
209
210
211
	NvRegBackOffControl = 0xC4,
#define NVREG_BKOFFCTRL_DEFAULT			0x70000000
#define NVREG_BKOFFCTRL_SEED_MASK		0x000003ff
#define NVREG_BKOFFCTRL_SELECT			24
#define NVREG_BKOFFCTRL_GEAR			12
Linus Torvalds's avatar
Linus Torvalds committed
212
213
214
215
216
217

	NvRegTxRingPhysAddr = 0x100,
	NvRegRxRingPhysAddr = 0x104,
	NvRegRingSizes = 0x108,
#define NVREG_RINGSZ_TXSHIFT 0
#define NVREG_RINGSZ_RXSHIFT 16
218
219
	NvRegTransmitPoll = 0x10c,
#define NVREG_TRANSMITPOLL_MAC_ADDR_REV	0x00008000
Linus Torvalds's avatar
Linus Torvalds committed
220
221
222
223
224
225
226
227
	NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
#define NVREG_LINKSPEED_10	1000
#define NVREG_LINKSPEED_100	100
#define NVREG_LINKSPEED_1000	50
#define NVREG_LINKSPEED_MASK	(0xFFF)
	NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31	(1<<31)
228
229
230
231
	NvRegTxWatermark = 0x13c,
#define NVREG_TX_WM_DESC1_DEFAULT	0x0200010
#define NVREG_TX_WM_DESC2_3_DEFAULT	0x1e08000
#define NVREG_TX_WM_DESC2_3_1000	0xfe08000
Linus Torvalds's avatar
Linus Torvalds committed
232
233
234
235
236
237
238
	NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK	0x0001
#define NVREG_TXRXCTL_BIT1	0x0002
#define NVREG_TXRXCTL_BIT2	0x0004
#define NVREG_TXRXCTL_IDLE	0x0008
#define NVREG_TXRXCTL_RESET	0x0010
#define NVREG_TXRXCTL_RXCHECK	0x0400
239
#define NVREG_TXRXCTL_DESC_1	0
Ayaz Abdulla's avatar
Ayaz Abdulla committed
240
241
#define NVREG_TXRXCTL_DESC_2	0x002100
#define NVREG_TXRXCTL_DESC_3	0xc02200
242
243
#define NVREG_TXRXCTL_VLANSTRIP 0x00040
#define NVREG_TXRXCTL_VLANINS	0x00080
244
245
	NvRegTxRingPhysAddrHigh = 0x148,
	NvRegRxRingPhysAddrHigh = 0x14C,
246
	NvRegTxPauseFrame = 0x170,
Ayaz Abdulla's avatar
Ayaz Abdulla committed
247
248
249
250
#define NVREG_TX_PAUSEFRAME_DISABLE	0x0fff0080
#define NVREG_TX_PAUSEFRAME_ENABLE_V1	0x01800010
#define NVREG_TX_PAUSEFRAME_ENABLE_V2	0x056003f0
#define NVREG_TX_PAUSEFRAME_ENABLE_V3	0x09f00880
Linus Torvalds's avatar
Linus Torvalds committed
251
252
253
	NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR		0x0001
#define NVREG_MIISTAT_LINKCHANGE	0x0008
Ayaz Abdulla's avatar
Ayaz Abdulla committed
254
255
#define NVREG_MIISTAT_MASK_RW		0x0007
#define NVREG_MIISTAT_MASK_ALL		0x000f
256
257
	NvRegMIIMask = 0x184,
#define NVREG_MII_LINKCHANGE		0x0008
Linus Torvalds's avatar
Linus Torvalds committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

	NvRegAdapterControl = 0x188,
#define NVREG_ADAPTCTL_START	0x02
#define NVREG_ADAPTCTL_LINKUP	0x04
#define NVREG_ADAPTCTL_PHYVALID	0x40000
#define NVREG_ADAPTCTL_RUNNING	0x100000
#define NVREG_ADAPTCTL_PHYSHIFT	24
	NvRegMIISpeed = 0x18c,
#define NVREG_MIISPEED_BIT8	(1<<8)
#define NVREG_MIIDELAY	5
	NvRegMIIControl = 0x190,
#define NVREG_MIICTL_INUSE	0x08000
#define NVREG_MIICTL_WRITE	0x00400
#define NVREG_MIICTL_ADDRSHIFT	5
	NvRegMIIData = 0x194,
	NvRegWakeUpFlags = 0x200,
#define NVREG_WAKEUPFLAGS_VAL		0x7770
#define NVREG_WAKEUPFLAGS_BUSYSHIFT	24
#define NVREG_WAKEUPFLAGS_ENABLESHIFT	16
#define NVREG_WAKEUPFLAGS_D3SHIFT	12
#define NVREG_WAKEUPFLAGS_D2SHIFT	8
#define NVREG_WAKEUPFLAGS_D1SHIFT	4
#define NVREG_WAKEUPFLAGS_D0SHIFT	0
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT		0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT	0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE	0x04
#define NVREG_WAKEUPFLAGS_ENABLE	0x1111

	NvRegPatternCRC = 0x204,
	NvRegPatternMask = 0x208,
	NvRegPowerCap = 0x268,
#define NVREG_POWERCAP_D3SUPP	(1<<30)
#define NVREG_POWERCAP_D2SUPP	(1<<26)
#define NVREG_POWERCAP_D1SUPP	(1<<25)
	NvRegPowerState = 0x26c,
#define NVREG_POWERSTATE_POWEREDUP	0x8000
#define NVREG_POWERSTATE_VALID		0x0100
#define NVREG_POWERSTATE_MASK		0x0003
#define NVREG_POWERSTATE_D0		0x0000
#define NVREG_POWERSTATE_D1		0x0001
#define NVREG_POWERSTATE_D2		0x0002
#define NVREG_POWERSTATE_D3		0x0003
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
	NvRegTxCnt = 0x280,
	NvRegTxZeroReXmt = 0x284,
	NvRegTxOneReXmt = 0x288,
	NvRegTxManyReXmt = 0x28c,
	NvRegTxLateCol = 0x290,
	NvRegTxUnderflow = 0x294,
	NvRegTxLossCarrier = 0x298,
	NvRegTxExcessDef = 0x29c,
	NvRegTxRetryErr = 0x2a0,
	NvRegRxFrameErr = 0x2a4,
	NvRegRxExtraByte = 0x2a8,
	NvRegRxLateCol = 0x2ac,
	NvRegRxRunt = 0x2b0,
	NvRegRxFrameTooLong = 0x2b4,
	NvRegRxOverflow = 0x2b8,
	NvRegRxFCSErr = 0x2bc,
	NvRegRxFrameAlignErr = 0x2c0,
	NvRegRxLenErr = 0x2c4,
	NvRegRxUnicast = 0x2c8,
	NvRegRxMulticast = 0x2cc,
	NvRegRxBroadcast = 0x2d0,
	NvRegTxDef = 0x2d4,
	NvRegTxFrame = 0x2d8,
	NvRegRxCnt = 0x2dc,
	NvRegTxPause = 0x2e0,
	NvRegRxPause = 0x2e4,
	NvRegRxDropFrame = 0x2e8,
327
328
	NvRegVlanControl = 0x300,
#define NVREG_VLANCONTROL_ENABLE	0x2000
329
330
331
	NvRegMSIXMap0 = 0x3e0,
	NvRegMSIXMap1 = 0x3e4,
	NvRegMSIXIrqStatus = 0x3f0,
332
333
334
335

	NvRegPowerState2 = 0x600,
#define NVREG_POWERSTATE2_POWERUP_MASK		0x0F11
#define NVREG_POWERSTATE2_POWERUP_REV_A3	0x0001
Linus Torvalds's avatar
Linus Torvalds committed
336
337
338
339
};

/* Big endian: should work, but is untested */
struct ring_desc {
340
341
	__le32 buf;
	__le32 flaglen;
Linus Torvalds's avatar
Linus Torvalds committed
342
343
};

344
struct ring_desc_ex {
345
346
347
348
	__le32 bufhigh;
	__le32 buflow;
	__le32 txvlan;
	__le32 flaglen;
349
350
};

351
union ring_type {
352
353
	struct ring_desc* orig;
	struct ring_desc_ex* ex;
354
};
355

Linus Torvalds's avatar
Linus Torvalds committed
356
357
358
359
360
361
362
#define FLAG_MASK_V1 0xffff0000
#define FLAG_MASK_V2 0xffffc000
#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
#define LEN_MASK_V2 (0xffffffff ^ FLAG_MASK_V2)

#define NV_TX_LASTPACKET	(1<<16)
#define NV_TX_RETRYERROR	(1<<19)
363
#define NV_TX_RETRYCOUNT_MASK	(0xF<<20)
364
#define NV_TX_FORCED_INTERRUPT	(1<<24)
Linus Torvalds's avatar
Linus Torvalds committed
365
366
367
368
369
370
371
372
373
#define NV_TX_DEFERRED		(1<<26)
#define NV_TX_CARRIERLOST	(1<<27)
#define NV_TX_LATECOLLISION	(1<<28)
#define NV_TX_UNDERFLOW		(1<<29)
#define NV_TX_ERROR		(1<<30)
#define NV_TX_VALID		(1<<31)

#define NV_TX2_LASTPACKET	(1<<29)
#define NV_TX2_RETRYERROR	(1<<18)
374
#define NV_TX2_RETRYCOUNT_MASK	(0xF<<19)
375
#define NV_TX2_FORCED_INTERRUPT	(1<<30)
Linus Torvalds's avatar
Linus Torvalds committed
376
377
378
379
380
381
382
#define NV_TX2_DEFERRED		(1<<25)
#define NV_TX2_CARRIERLOST	(1<<26)
#define NV_TX2_LATECOLLISION	(1<<27)
#define NV_TX2_UNDERFLOW	(1<<28)
/* error and valid are the same for both */
#define NV_TX2_ERROR		(1<<30)
#define NV_TX2_VALID		(1<<31)
383
384
#define NV_TX2_TSO		(1<<28)
#define NV_TX2_TSO_SHIFT	14
385
386
#define NV_TX2_TSO_MAX_SHIFT	14
#define NV_TX2_TSO_MAX_SIZE	(1<<NV_TX2_TSO_MAX_SHIFT)
387
388
#define NV_TX2_CHECKSUM_L3	(1<<27)
#define NV_TX2_CHECKSUM_L4	(1<<26)
Linus Torvalds's avatar
Linus Torvalds committed
389

390
391
#define NV_TX3_VLAN_TAG_PRESENT (1<<18)

Linus Torvalds's avatar
Linus Torvalds committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#define NV_RX_DESCRIPTORVALID	(1<<16)
#define NV_RX_MISSEDFRAME	(1<<17)
#define NV_RX_SUBSTRACT1	(1<<18)
#define NV_RX_ERROR1		(1<<23)
#define NV_RX_ERROR2		(1<<24)
#define NV_RX_ERROR3		(1<<25)
#define NV_RX_ERROR4		(1<<26)
#define NV_RX_CRCERR		(1<<27)
#define NV_RX_OVERFLOW		(1<<28)
#define NV_RX_FRAMINGERR	(1<<29)
#define NV_RX_ERROR		(1<<30)
#define NV_RX_AVAIL		(1<<31)

#define NV_RX2_CHECKSUMMASK	(0x1C000000)
Ayaz Abdulla's avatar
Ayaz Abdulla committed
406
407
408
#define NV_RX2_CHECKSUM_IP	(0x10000000)
#define NV_RX2_CHECKSUM_IP_TCP	(0x14000000)
#define NV_RX2_CHECKSUM_IP_UDP	(0x18000000)
Linus Torvalds's avatar
Linus Torvalds committed
409
410
411
412
413
414
415
416
417
418
419
420
421
#define NV_RX2_DESCRIPTORVALID	(1<<29)
#define NV_RX2_SUBSTRACT1	(1<<25)
#define NV_RX2_ERROR1		(1<<18)
#define NV_RX2_ERROR2		(1<<19)
#define NV_RX2_ERROR3		(1<<20)
#define NV_RX2_ERROR4		(1<<21)
#define NV_RX2_CRCERR		(1<<22)
#define NV_RX2_OVERFLOW		(1<<23)
#define NV_RX2_FRAMINGERR	(1<<24)
/* error and avail are the same for both */
#define NV_RX2_ERROR		(1<<30)
#define NV_RX2_AVAIL		(1<<31)

422
423
424
#define NV_RX3_VLAN_TAG_PRESENT (1<<16)
#define NV_RX3_VLAN_TAG_MASK	(0x0000FFFF)

Linus Torvalds's avatar
Linus Torvalds committed
425
/* Miscelaneous hardware related defines: */
426
#define NV_PCI_REGSZ_VER1      	0x270
Ayaz Abdulla's avatar
Ayaz Abdulla committed
427
428
#define NV_PCI_REGSZ_VER2      	0x2d4
#define NV_PCI_REGSZ_VER3      	0x604
429
#define NV_PCI_REGSZ_MAX       	0x604
Linus Torvalds's avatar
Linus Torvalds committed
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY	4
#define NV_TXSTOP_DELAY1	10
#define NV_TXSTOP_DELAY1MAX	500000
#define NV_TXSTOP_DELAY2	100
#define NV_RXSTOP_DELAY1	10
#define NV_RXSTOP_DELAY1MAX	500000
#define NV_RXSTOP_DELAY2	100
#define NV_SETUP5_DELAY		5
#define NV_SETUP5_DELAYMAX	50000
#define NV_POWERUP_DELAY	5
#define NV_POWERUP_DELAYMAX	5000
#define NV_MIIBUSY_DELAY	50
#define NV_MIIPHY_DELAY	10
#define NV_MIIPHY_DELAYMAX	10000
446
#define NV_MAC_RESET_DELAY	64
Linus Torvalds's avatar
Linus Torvalds committed
447
448
449
450
451
452
453

#define NV_WAKEUPPATTERNS	5
#define NV_WAKEUPMASKENTRIES	4

/* General driver defaults */
#define NV_WATCHDOG_TIMEO	(5*HZ)

454
455
456
457
458
459
#define RX_RING_DEFAULT		128
#define TX_RING_DEFAULT		256
#define RX_RING_MIN		128
#define TX_RING_MIN		64
#define RING_MAX_DESC_VER_1	1024
#define RING_MAX_DESC_VER_2_3	16384
Linus Torvalds's avatar
Linus Torvalds committed
460
461

/* rx/tx mac addr + type + vlan + align + slack*/
462
463
464
465
466
467
468
#define NV_RX_HEADERS		(64)
/* even more slack. */
#define NV_RX_ALLOC_PAD		(64)

/* maximum mtu size */
#define NV_PKTLIMIT_1	ETH_DATA_LEN	/* hard limit not known */
#define NV_PKTLIMIT_2	9100	/* Actual limit according to NVidia: 9202 */
Linus Torvalds's avatar
Linus Torvalds committed
469
470
471
472

#define OOM_REFILL	(1+HZ/20)
#define POLL_WAIT	(1+HZ/100)
#define LINK_TIMEOUT	(3*HZ)
473
#define STATS_INTERVAL	(10*HZ)
Linus Torvalds's avatar
Linus Torvalds committed
474

475
/*
Linus Torvalds's avatar
Linus Torvalds committed
476
 * desc_ver values:
477
478
479
480
 * The nic supports three different descriptor types:
 * - DESC_VER_1: Original
 * - DESC_VER_2: support for jumbo frames.
 * - DESC_VER_3: 64-bit format.
Linus Torvalds's avatar
Linus Torvalds committed
481
 */
482
483
484
#define DESC_VER_1	1
#define DESC_VER_2	2
#define DESC_VER_3	3
Linus Torvalds's avatar
Linus Torvalds committed
485
486

/* PHY defines */
487
488
489
490
491
#define PHY_OUI_MARVELL		0x5043
#define PHY_OUI_CICADA		0x03f1
#define PHY_OUI_VITESSE		0x01c1
#define PHY_OUI_REALTEK		0x0732
#define PHY_OUI_REALTEK2	0x0020
Linus Torvalds's avatar
Linus Torvalds committed
492
493
494
495
#define PHYID1_OUI_MASK	0x03ff
#define PHYID1_OUI_SHFT	6
#define PHYID2_OUI_MASK	0xfc00
#define PHYID2_OUI_SHFT	10
496
#define PHYID2_MODEL_MASK		0x03f0
497
498
499
500
501
502
#define PHY_MODEL_REALTEK_8211		0x0110
#define PHY_REV_MASK			0x0001
#define PHY_REV_REALTEK_8211B		0x0000
#define PHY_REV_REALTEK_8211C		0x0001
#define PHY_MODEL_REALTEK_8201		0x0200
#define PHY_MODEL_MARVELL_E3016		0x0220
503
#define PHY_MARVELL_E3016_INITMASK	0x0300
Ayaz Abdulla's avatar
Ayaz Abdulla committed
504
505
506
507
508
509
#define PHY_CICADA_INIT1	0x0f000
#define PHY_CICADA_INIT2	0x0e00
#define PHY_CICADA_INIT3	0x01000
#define PHY_CICADA_INIT4	0x0200
#define PHY_CICADA_INIT5	0x0004
#define PHY_CICADA_INIT6	0x02000
Ayaz Abdulla's avatar
Ayaz Abdulla committed
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
#define PHY_VITESSE_INIT_REG1	0x1f
#define PHY_VITESSE_INIT_REG2	0x10
#define PHY_VITESSE_INIT_REG3	0x11
#define PHY_VITESSE_INIT_REG4	0x12
#define PHY_VITESSE_INIT_MSK1	0xc
#define PHY_VITESSE_INIT_MSK2	0x0180
#define PHY_VITESSE_INIT1	0x52b5
#define PHY_VITESSE_INIT2	0xaf8a
#define PHY_VITESSE_INIT3	0x8
#define PHY_VITESSE_INIT4	0x8f8a
#define PHY_VITESSE_INIT5	0xaf86
#define PHY_VITESSE_INIT6	0x8f86
#define PHY_VITESSE_INIT7	0xaf82
#define PHY_VITESSE_INIT8	0x0100
#define PHY_VITESSE_INIT9	0x8f82
#define PHY_VITESSE_INIT10	0x0
Ayaz Abdulla's avatar
Ayaz Abdulla committed
526
527
528
#define PHY_REALTEK_INIT_REG1	0x1f
#define PHY_REALTEK_INIT_REG2	0x19
#define PHY_REALTEK_INIT_REG3	0x13
529
530
531
#define PHY_REALTEK_INIT_REG4	0x14
#define PHY_REALTEK_INIT_REG5	0x18
#define PHY_REALTEK_INIT_REG6	0x11
Ayaz Abdulla's avatar
Ayaz Abdulla committed
532
533
534
535
#define PHY_REALTEK_INIT1	0x0000
#define PHY_REALTEK_INIT2	0x8e00
#define PHY_REALTEK_INIT3	0x0001
#define PHY_REALTEK_INIT4	0xad17
536
537
538
539
540
#define PHY_REALTEK_INIT5	0xfb54
#define PHY_REALTEK_INIT6	0xf5c7
#define PHY_REALTEK_INIT7	0x1000
#define PHY_REALTEK_INIT8	0x0003
#define PHY_REALTEK_INIT_MSK1	0x0003
Ayaz Abdulla's avatar
Ayaz Abdulla committed
541

Linus Torvalds's avatar
Linus Torvalds committed
542
543
544
545
546
547
548
549
550
#define PHY_GIGABIT	0x0100

#define PHY_TIMEOUT	0x1
#define PHY_ERROR	0x2

#define PHY_100	0x1
#define PHY_1000	0x2
#define PHY_HALF	0x100

551
552
553
554
#define NV_PAUSEFRAME_RX_CAPABLE 0x0001
#define NV_PAUSEFRAME_TX_CAPABLE 0x0002
#define NV_PAUSEFRAME_RX_ENABLE  0x0004
#define NV_PAUSEFRAME_TX_ENABLE  0x0008
555
556
557
#define NV_PAUSEFRAME_RX_REQ     0x0010
#define NV_PAUSEFRAME_TX_REQ     0x0020
#define NV_PAUSEFRAME_AUTONEG    0x0040
Linus Torvalds's avatar
Linus Torvalds committed
558

559
560
561
562
563
564
565
566
567
568
569
570
/* MSI/MSI-X defines */
#define NV_MSI_X_MAX_VECTORS  8
#define NV_MSI_X_VECTORS_MASK 0x000f
#define NV_MSI_CAPABLE        0x0010
#define NV_MSI_X_CAPABLE      0x0020
#define NV_MSI_ENABLED        0x0040
#define NV_MSI_X_ENABLED      0x0080

#define NV_MSI_X_VECTOR_ALL   0x0
#define NV_MSI_X_VECTOR_RX    0x0
#define NV_MSI_X_VECTOR_TX    0x1
#define NV_MSI_X_VECTOR_OTHER 0x2
Linus Torvalds's avatar
Linus Torvalds committed
571

Ayaz Abdulla's avatar
Ayaz Abdulla committed
572
573
574
#define NV_RESTART_TX         0x1
#define NV_RESTART_RX         0x2

Ayaz Abdulla's avatar
Ayaz Abdulla committed
575
576
#define NV_TX_LIMIT_COUNT     16

577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
/* statistics */
struct nv_ethtool_str {
	char name[ETH_GSTRING_LEN];
};

static const struct nv_ethtool_str nv_estats_str[] = {
	{ "tx_bytes" },
	{ "tx_zero_rexmt" },
	{ "tx_one_rexmt" },
	{ "tx_many_rexmt" },
	{ "tx_late_collision" },
	{ "tx_fifo_errors" },
	{ "tx_carrier_errors" },
	{ "tx_excess_deferral" },
	{ "tx_retry_error" },
	{ "rx_frame_error" },
	{ "rx_extra_byte" },
	{ "rx_late_collision" },
	{ "rx_runt" },
	{ "rx_frame_too_long" },
	{ "rx_over_errors" },
	{ "rx_crc_errors" },
	{ "rx_frame_align_error" },
	{ "rx_length_error" },
	{ "rx_unicast" },
	{ "rx_multicast" },
	{ "rx_broadcast" },
Ayaz Abdulla's avatar
Ayaz Abdulla committed
604
605
606
607
608
609
610
	{ "rx_packets" },
	{ "rx_errors_total" },
	{ "tx_errors_total" },

	/* version 2 stats */
	{ "tx_deferral" },
	{ "tx_packets" },
611
	{ "rx_bytes" },
Ayaz Abdulla's avatar
Ayaz Abdulla committed
612
	{ "tx_pause" },
613
	{ "rx_pause" },
Ayaz Abdulla's avatar
Ayaz Abdulla committed
614
	{ "rx_drop_frame" }
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
};

struct nv_ethtool_stats {
	u64 tx_bytes;
	u64 tx_zero_rexmt;
	u64 tx_one_rexmt;
	u64 tx_many_rexmt;
	u64 tx_late_collision;
	u64 tx_fifo_errors;
	u64 tx_carrier_errors;
	u64 tx_excess_deferral;
	u64 tx_retry_error;
	u64 rx_frame_error;
	u64 rx_extra_byte;
	u64 rx_late_collision;
	u64 rx_runt;
	u64 rx_frame_too_long;
	u64 rx_over_errors;
	u64 rx_crc_errors;
	u64 rx_frame_align_error;
	u64 rx_length_error;
	u64 rx_unicast;
	u64 rx_multicast;
	u64 rx_broadcast;
Ayaz Abdulla's avatar
Ayaz Abdulla committed
639
640
641
642
643
644
645
	u64 rx_packets;
	u64 rx_errors_total;
	u64 tx_errors_total;

	/* version 2 stats */
	u64 tx_deferral;
	u64 tx_packets;
646
	u64 rx_bytes;
Ayaz Abdulla's avatar
Ayaz Abdulla committed
647
	u64 tx_pause;
648
649
650
651
	u64 rx_pause;
	u64 rx_drop_frame;
};

Ayaz Abdulla's avatar
Ayaz Abdulla committed
652
653
654
#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64))
#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6)

655
656
657
658
659
660
661
662
663
664
665
666
/* diagnostics */
#define NV_TEST_COUNT_BASE 3
#define NV_TEST_COUNT_EXTENDED 4

static const struct nv_ethtool_str nv_etests_str[] = {
	{ "link      (online/offline)" },
	{ "register  (offline)       " },
	{ "interrupt (offline)       " },
	{ "loopback  (offline)       " }
};

struct register_test {
Al Viro's avatar
Al Viro committed
667
668
	__u32 reg;
	__u32 mask;
669
670
671
672
673
674
675
};

static const struct register_test nv_registers_test[] = {
	{ NvRegUnknownSetupReg6, 0x01 },
	{ NvRegMisc1, 0x03c },
	{ NvRegOffloadConfig, 0x03ff },
	{ NvRegMulticastAddrA, 0xffffffff },
676
	{ NvRegTxWatermark, 0x0ff },
677
678
679
680
	{ NvRegWakeUpFlags, 0x07777 },
	{ 0,0 }
};

Ayaz Abdulla's avatar
Ayaz Abdulla committed
681
682
683
684
struct nv_skb_map {
	struct sk_buff *skb;
	dma_addr_t dma;
	unsigned int dma_len;
Ayaz Abdulla's avatar
Ayaz Abdulla committed
685
686
	struct ring_desc_ex *first_tx_desc;
	struct nv_skb_map *next_tx_ctx;
Ayaz Abdulla's avatar
Ayaz Abdulla committed
687
688
};

Linus Torvalds's avatar
Linus Torvalds committed
689
690
691
692
693
694
/*
 * SMP locking:
 * All hardware access under dev->priv->lock, except the performance
 * critical parts:
 * - rx is (pseudo-) lockless: it relies on the single-threading provided
 *	by the arch code for interrupts.
Herbert Xu's avatar
Herbert Xu committed
695
 * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
Linus Torvalds's avatar
Linus Torvalds committed
696
 *	needs dev->priv->lock :-(
Herbert Xu's avatar
Herbert Xu committed
697
 * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
Linus Torvalds's avatar
Linus Torvalds committed
698
699
700
701
702
703
 */

/* in dev: base, irq */
struct fe_priv {
	spinlock_t lock;

704
705
706
	struct net_device *dev;
	struct napi_struct napi;

Linus Torvalds's avatar
Linus Torvalds committed
707
708
	/* General data:
	 * Locking: spin_lock(&np->lock); */
709
	struct nv_ethtool_stats estats;
Linus Torvalds's avatar
Linus Torvalds committed
710
711
712
713
714
715
716
717
	int in_shutdown;
	u32 linkspeed;
	int duplex;
	int autoneg;
	int fixed_mode;
	int phyaddr;
	int wolenabled;
	unsigned int phy_oui;
718
	unsigned int phy_model;
719
	unsigned int phy_rev;
Linus Torvalds's avatar
Linus Torvalds committed
720
	u16 gigabit;
721
	int intr_test;
722
	int recover_error;
Linus Torvalds's avatar
Linus Torvalds committed
723
724
725
726
727
728
729

	/* General data: RO fields */
	dma_addr_t ring_addr;
	struct pci_dev *pci_dev;
	u32 orig_mac[2];
	u32 irqmask;
	u32 desc_ver;
730
	u32 txrxctl_bits;
731
	u32 vlanctl_bits;
732
	u32 driver_data;
733
	u32 device_id;
734
	u32 register_size;
735
	int rx_csum;
736
	u32 mac_in_use;
Linus Torvalds's avatar
Linus Torvalds committed
737
738
739
740
741
742

	void __iomem *base;

	/* rx specific fields.
	 * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
	 */
Ayaz Abdulla's avatar
Ayaz Abdulla committed
743
744
745
746
747
	union ring_type get_rx, put_rx, first_rx, last_rx;
	struct nv_skb_map *get_rx_ctx, *put_rx_ctx;
	struct nv_skb_map *first_rx_ctx, *last_rx_ctx;
	struct nv_skb_map *rx_skb;

748
	union ring_type rx_ring;
Linus Torvalds's avatar
Linus Torvalds committed
749
	unsigned int rx_buf_sz;
750
	unsigned int pkt_limit;
Linus Torvalds's avatar
Linus Torvalds committed
751
752
	struct timer_list oom_kick;
	struct timer_list nic_poll;
753
	struct timer_list stats_poll;
754
	u32 nic_poll_irq;
755
	int rx_ring_size;
Linus Torvalds's avatar
Linus Torvalds committed
756
757
758
759
760
761
762
763
764

	/* media detection workaround.
	 * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
	 */
	int need_linktimer;
	unsigned long link_timeout;
	/*
	 * tx specific fields.
	 */
Ayaz Abdulla's avatar
Ayaz Abdulla committed
765
766
767
768
769
	union ring_type get_tx, put_tx, first_tx, last_tx;
	struct nv_skb_map *get_tx_ctx, *put_tx_ctx;
	struct nv_skb_map *first_tx_ctx, *last_tx_ctx;
	struct nv_skb_map *tx_skb;

770
	union ring_type tx_ring;
Linus Torvalds's avatar
Linus Torvalds committed
771
	u32 tx_flags;
772
	int tx_ring_size;
Ayaz Abdulla's avatar
Ayaz Abdulla committed
773
774
775
776
	int tx_limit;
	u32 tx_pkts_in_progress;
	struct nv_skb_map *tx_change_owner;
	struct nv_skb_map *tx_end_flip;
Ayaz Abdulla's avatar
Ayaz Abdulla committed
777
	int tx_stop;
778
779
780

	/* vlan fields */
	struct vlan_group *vlangrp;
781
782
783
784

	/* msi/msi-x fields */
	u32 msi_flags;
	struct msix_entry msi_x_entry[NV_MSI_X_MAX_VECTORS];
785
786
787

	/* flow control */
	u32 pause_flags;
788
789
790

	/* power saved state */
	u32 saved_config_space[NV_PCI_REGSZ_MAX/4];
Linus Torvalds's avatar
Linus Torvalds committed
791
792
793
794
795
796
797
798
};

/*
 * Maximum number of loops until we assume that a bit in the irq mask
 * is stuck. Overridable with module param.
 */
static int max_interrupt_work = 5;

799
800
/*
 * Optimization can be either throuput mode or cpu mode
801
 *
802
803
804
 * Throughput Mode: Every tx and rx packet will generate an interrupt.
 * CPU Mode: Interrupts are controlled by a timer.
 */
805
806
807
808
enum {
	NV_OPTIMIZATION_MODE_THROUGHPUT,
	NV_OPTIMIZATION_MODE_CPU
};
809
810
811
812
813
814
815
816
817
818
819
static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;

/*
 * Poll interval for timer irq
 *
 * This interval determines how frequent an interrupt is generated.
 * The is value is determined by [(time_in_micro_secs * 100) / (2^10)]
 * Min = 0, and Max = 65535
 */
static int poll_interval = -1;

820
/*
821
 * MSI interrupts
822
 */
823
824
825
826
827
enum {
	NV_MSI_INT_DISABLED,
	NV_MSI_INT_ENABLED
};
static int msi = NV_MSI_INT_ENABLED;
828
829

/*
830
 * MSIX interrupts
831
 */
832
833
834
835
enum {
	NV_MSIX_INT_DISABLED,
	NV_MSIX_INT_ENABLED
};
Ayaz Abdulla's avatar
Ayaz Abdulla committed
836
static int msix = NV_MSIX_INT_DISABLED;
837
838
839
840
841
842
843
844
845

/*
 * DMA 64bit
 */
enum {
	NV_DMA_64BIT_DISABLED,
	NV_DMA_64BIT_ENABLED
};
static int dma_64bit = NV_DMA_64BIT_ENABLED;
846

847
848
849
850
851
852
853
854
855
856
/*
 * Crossover Detection
 * Realtek 8201 phy + some OEM boards do not work properly.
 */
enum {
	NV_CROSSOVER_DETECTION_DISABLED,
	NV_CROSSOVER_DETECTION_ENABLED
};
static int phy_cross = NV_CROSSOVER_DETECTION_DISABLED;

Linus Torvalds's avatar
Linus Torvalds committed
857
858
859
860
861
862
863
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
	return netdev_priv(dev);
}

static inline u8 __iomem *get_hwbase(struct net_device *dev)
{
864
	return ((struct fe_priv *)netdev_priv(dev))->base;
Linus Torvalds's avatar
Linus Torvalds committed
865
866
867
868
869
870
871
872
873
874
}

static inline void pci_push(u8 __iomem *base)
{
	/* force out pending posted writes */
	readl(base);
}

static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
{
875
	return le32_to_cpu(prd->flaglen)
Linus Torvalds's avatar
Linus Torvalds committed
876
877
878
		& ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
}

879
880
static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
{
881
	return le32_to_cpu(prd->flaglen) & LEN_MASK_V2;
882
883
}

884
885
886
887
888
889
890
static bool nv_optimized(struct fe_priv *np)
{
	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
		return false;
	return true;
}

Linus Torvalds's avatar
Linus Torvalds committed
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
				int delay, int delaymax, const char *msg)
{
	u8 __iomem *base = get_hwbase(dev);

	pci_push(base);
	do {
		udelay(delay);
		delaymax -= delay;
		if (delaymax < 0) {
			if (msg)
				printk(msg);
			return 1;
		}
	} while ((readl(base + offset) & mask) != target);
	return 0;
}

909
910
911
#define NV_SETUP_RX_RING 0x01
#define NV_SETUP_TX_RING 0x02

Al Viro's avatar
Al Viro committed
912
913
914
915
916
917
918
919
920
921
static inline u32 dma_low(dma_addr_t addr)
{
	return addr;
}

static inline u32 dma_high(dma_addr_t addr)
{
	return addr>>31>>1;	/* 0 if 32bit, shift down by 32 if 64bit */
}

922
923
924
925
926
static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
{
	struct fe_priv *np = get_nvpriv(dev);
	u8 __iomem *base = get_hwbase(dev);

927
	if (!nv_optimized(np)) {
928
		if (rxtx_flags & NV_SETUP_RX_RING) {
Al Viro's avatar
Al Viro committed
929
			writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr);
930
931
		}
		if (rxtx_flags & NV_SETUP_TX_RING) {
Al Viro's avatar
Al Viro committed
932
			writel(dma_low(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
933
934
935
		}
	} else {
		if (rxtx_flags & NV_SETUP_RX_RING) {
Al Viro's avatar
Al Viro committed
936
937
			writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr);
			writel(dma_high(np->ring_addr), base + NvRegRxRingPhysAddrHigh);
938
939
		}
		if (rxtx_flags & NV_SETUP_TX_RING) {
Al Viro's avatar
Al Viro committed
940
941
			writel(dma_low(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
			writel(dma_high(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddrHigh);
942
943
944
945
		}
	}
}

946
947
948
949
static void free_rings(struct net_device *dev)
{
	struct fe_priv *np = get_nvpriv(dev);

950
	if (!nv_optimized(np)) {
951
		if (np->rx_ring.orig)
952
953
954
955
956
957
958
			pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
					    np->rx_ring.orig, np->ring_addr);
	} else {
		if (np->rx_ring.ex)
			pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
					    np->rx_ring.ex, np->ring_addr);
	}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
959
960
961
962
	if (np->rx_skb)
		kfree(np->rx_skb);
	if (np->tx_skb)
		kfree(np->tx_skb);
963
964
}

965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
static int using_multi_irqs(struct net_device *dev)
{
	struct fe_priv *np = get_nvpriv(dev);

	if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
	    ((np->msi_flags & NV_MSI_X_ENABLED) &&
	     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1)))
		return 0;
	else
		return 1;
}

static void nv_enable_irq(struct net_device *dev)
{
	struct fe_priv *np = get_nvpriv(dev);

	if (!using_multi_irqs(dev)) {
		if (np->msi_flags & NV_MSI_X_ENABLED)
			enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
		else
Manfred Spraul's avatar
Manfred Spraul committed
985
			enable_irq(np->pci_dev->irq);
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
	} else {
		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
	}
}

static void nv_disable_irq(struct net_device *dev)
{
	struct fe_priv *np = get_nvpriv(dev);

	if (!using_multi_irqs(dev)) {
		if (np->msi_flags & NV_MSI_X_ENABLED)
			disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
		else
Manfred Spraul's avatar
Manfred Spraul committed
1001
			disable_irq(np->pci_dev->irq);
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
	} else {
		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
	}
}

/* In MSIX mode, a write to irqmask behaves as XOR */
static void nv_enable_hw_interrupts(struct net_device *dev, u32 mask)
{
	u8 __iomem *base = get_hwbase(dev);

	writel(mask, base + NvRegIrqMask);
}

static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask)
{
	struct fe_priv *np = get_nvpriv(dev);
	u8 __iomem *base = get_hwbase(dev);

	if (np->msi_flags & NV_MSI_X_ENABLED) {
		writel(mask, base + NvRegIrqMask);
	} else {
		if (np->msi_flags & NV_MSI_ENABLED)
			writel(0, base + NvRegMSIIrqMask);
		writel(0, base + NvRegIrqMask);
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
#define MII_READ	(-1)
/* mii_rw: read/write a register on the PHY.
 *
 * Caller must guarantee serialization
 */
static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
{
	u8 __iomem *base = get_hwbase(dev);
	u32 reg;
	int retval;

Ayaz Abdulla's avatar
Ayaz Abdulla committed
1042
	writel(NVREG_MIISTAT_MASK_RW, base + NvRegMIIStatus);
Linus Torvalds's avatar
Linus Torvalds committed
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079

	reg = readl(base + NvRegMIIControl);
	if (reg & NVREG_MIICTL_INUSE) {
		writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl);
		udelay(NV_MIIBUSY_DELAY);
	}

	reg = (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
	if (value != MII_READ) {
		writel(value, base + NvRegMIIData);
		reg |= NVREG_MIICTL_WRITE;
	}
	writel(reg, base + NvRegMIIControl);

	if (reg_delay(dev, NvRegMIIControl, NVREG_MIICTL_INUSE, 0,
			NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) {
		dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d timed out.\n",
				dev->name, miireg, addr);
		retval = -1;
	} else if (value != MII_READ) {
		/* it was a write operation - fewer failures are detectable */
		dprintk(KERN_DEBUG "%s: mii_rw wrote 0x%x to reg %d at PHY %d\n",
				dev->name, value, miireg, addr);
		retval = 0;
	} else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) {
		dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d failed.\n",
				dev->name, miireg, addr);
		retval = -1;
	} else {
		retval = readl(base + NvRegMIIData);
		dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n",
				dev->name, miireg, addr, retval);
	}

	return retval;
}

1080
static int phy_reset(struct net_device *dev, u32 bmcr_setup)
Linus Torvalds's avatar
Linus Torvalds committed
1081
{
1082
	struct fe_priv *np = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1083
1084
1085
	u32 miicontrol;
	unsigned int tries = 0;

1086
	miicontrol = BMCR_RESET | bmcr_setup;
Linus Torvalds's avatar
Linus Torvalds committed
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
	if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) {
		return -1;
	}

	/* wait for 500ms */
	msleep(500);

	/* must wait till reset is deasserted */
	while (miicontrol & BMCR_RESET) {
		msleep(10);
		miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
		/* FIXME: 100 tries seem excessive */
		if (tries++ > 100)
			return -1;
	}
	return 0;
}

static int phy_init(struct net_device *dev)
{
	struct fe_priv *np = get_nvpriv(dev);
	u8 __iomem *base = get_hwbase(dev);
	u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;

1111
1112
1113
1114
1115
1116
1117
1118
1119
	/* phy errata for E3016 phy */
	if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
		reg = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
		reg &= ~PHY_MARVELL_E3016_INITMASK;
		if (mii_rw(dev, np->phyaddr, MII_NCONFIG, reg)) {
			printk(KERN_INFO "%s: phy write to errata reg failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
	}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1120
	if (np->phy_oui == PHY_OUI_REALTEK) {
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
		if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
		    np->phy_rev == PHY_REV_REALTEK_8211B) {
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1151
		}
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
		if (np->phy_model == PHY_MODEL_REALTEK_8201) {
			if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
				phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
				phy_reserved |= PHY_REALTEK_INIT7;
				if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
					printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
					return PHY_ERROR;
				}
			}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1168
1169
		}
	}
1170

Linus Torvalds's avatar
Linus Torvalds committed
1171
1172
	/* set advertise register */
	reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
1173
	reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP);
Linus Torvalds's avatar
Linus Torvalds committed
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
	if (mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg)) {
		printk(KERN_INFO "%s: phy write to advertise failed.\n", pci_name(np->pci_dev));
		return PHY_ERROR;
	}

	/* get phy interface type */
	phyinterface = readl(base + NvRegPhyInterface);

	/* see if gigabit phy */
	mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
	if (mii_status & PHY_GIGABIT) {
		np->gigabit = PHY_GIGABIT;
1186
		mii_control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ);
Linus Torvalds's avatar
Linus Torvalds committed
1187
1188
1189
1190
1191
1192
		mii_control_1000 &= ~ADVERTISE_1000HALF;
		if (phyinterface & PHY_RGMII)
			mii_control_1000 |= ADVERTISE_1000FULL;
		else
			mii_control_1000 &= ~ADVERTISE_1000FULL;

1193
		if (mii_rw(dev, np->phyaddr, MII_CTRL1000, mii_control_1000)) {
Linus Torvalds's avatar
Linus Torvalds committed
1194
1195
1196
1197
1198
1199
1200
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
	}
	else
		np->gigabit = 0;

1201
1202
1203
1204
1205
1206
1207
	mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
	mii_control |= BMCR_ANENABLE;

	/* reset the phy
	 * (certain phys need bmcr to be setup with reset)
	 */
	if (phy_reset(dev, mii_control)) {
Linus Torvalds's avatar
Linus Torvalds committed
1208
1209
1210
1211
1212
1213
1214
		printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
		return PHY_ERROR;
	}

	/* phy vendor specific configuration */
	if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) {
		phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ);
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1215
1216
		phy_reserved &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2);
		phy_reserved |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4);
Linus Torvalds's avatar
Linus Torvalds committed
1217
1218
1219
1220
1221
		if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1222
		phy_reserved |= PHY_CICADA_INIT5;
Linus Torvalds's avatar
Linus Torvalds committed
1223
1224
1225
1226
1227
1228
1229
		if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
	}
	if (np->phy_oui == PHY_OUI_CICADA) {
		phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ);
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1230
		phy_reserved |= PHY_CICADA_INIT6;
Linus Torvalds's avatar
Linus Torvalds committed
1231
1232
1233
1234
1235
		if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
	}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
	if (np->phy_oui == PHY_OUI_VITESSE) {
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT1)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT2)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
		phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
		phy_reserved |= PHY_VITESSE_INIT3;
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT4)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT5)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
		phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
		phy_reserved |= PHY_VITESSE_INIT3;
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT6)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT7)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
		phy_reserved &= ~PHY_VITESSE_INIT_MSK2;
		phy_reserved |= PHY_VITESSE_INIT8;
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT9)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
		if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT10)) {
			printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
			return PHY_ERROR;
		}
	}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1306
	if (np->phy_oui == PHY_OUI_REALTEK) {
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
		if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
		    np->phy_rev == PHY_REV_REALTEK_8211B) {
			/* reset could have cleared these out, set them back */
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
			if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
				printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
				return PHY_ERROR;
			}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1338
		}
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
		if (np->phy_model == PHY_MODEL_REALTEK_8201) {
			if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
			    np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
				phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
				phy_reserved |= PHY_REALTEK_INIT7;
				if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
					printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
					return PHY_ERROR;
				}
			}
			if (phy_cross == NV_CROSSOVER_DETECTION_DISABLED) {
				if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
					printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
					return PHY_ERROR;
				}
				phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ);
				phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
				phy_reserved |= PHY_REALTEK_INIT3;
				if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved)) {
					printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
					return PHY_ERROR;
				}
				if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
					printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
					return PHY_ERROR;
				}
			}
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1372
1373
1374
		}
	}

1375
1376
	/* some phys clear out pause advertisment on reset, set it back */
	mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg);
Linus Torvalds's avatar
Linus Torvalds committed
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389

	/* restart auto negotiation */
	mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
	mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
	if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) {
		return PHY_ERROR;
	}

	return 0;
}

static void nv_start_rx(struct net_device *dev)
{
1390
	struct fe_priv *np = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1391
	u8 __iomem *base = get_hwbase(dev);
1392
	u32 rx_ctrl = readl(base + NvRegReceiverControl);
Linus Torvalds's avatar
Linus Torvalds committed
1393
1394
1395

	dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
	/* Already running? Stop it. */
1396
1397
1398
	if ((readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) && !np->mac_in_use) {
		rx_ctrl &= ~NVREG_RCVCTL_START;
		writel(rx_ctrl, base + NvRegReceiverControl);
Linus Torvalds's avatar
Linus Torvalds committed
1399
1400
1401
1402
		pci_push(base);
	}
	writel(np->linkspeed, base + NvRegLinkSpeed);
	pci_push(base);
1403
1404
1405
1406
        rx_ctrl |= NVREG_RCVCTL_START;
        if (np->mac_in_use)
		rx_ctrl &= ~NVREG_RCVCTL_RX_PATH_EN;
	writel(rx_ctrl, base + NvRegReceiverControl);
Linus Torvalds's avatar
Linus Torvalds committed
1407
1408
1409
1410
1411
1412
1413
	dprintk(KERN_DEBUG "%s: nv_start_rx to duplex %d, speed 0x%08x.\n",
				dev->name, np->duplex, np->linkspeed);
	pci_push(base);
}

static void nv_stop_rx(struct net_device *dev)
{
1414
	struct fe_priv *np = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1415
	u8 __iomem *base = get_hwbase(dev);
1416
	u32 rx_ctrl = readl(base + NvRegReceiverControl);
Linus Torvalds's avatar
Linus Torvalds committed
1417
1418

	dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
1419
1420
1421
1422
1423
	if (!np->mac_in_use)
		rx_ctrl &= ~NVREG_RCVCTL_START;
	else
		rx_ctrl |= NVREG_RCVCTL_RX_PATH_EN;
	writel(rx_ctrl, base + NvRegReceiverControl);
Linus Torvalds's avatar
Linus Torvalds committed
1424
1425
1426
1427
1428
	reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
			NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
			KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");

	udelay(NV_RXSTOP_DELAY2);
1429
1430
	if (!np->mac_in_use)
		writel(0, base + NvRegLinkSpeed);
Linus Torvalds's avatar
Linus Torvalds committed
1431
1432
1433
1434
}

static void nv_start_tx(struct net_device *dev)
{
1435
	struct fe_priv *np = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1436
	u8 __iomem *base = get_hwbase(dev);
1437
	u32 tx_ctrl = readl(base + NvRegTransmitterControl);
Linus Torvalds's avatar
Linus Torvalds committed
1438
1439

	dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
1440
1441
1442
1443
	tx_ctrl |= NVREG_XMITCTL_START;
	if (np->mac_in_use)
		tx_ctrl &= ~NVREG_XMITCTL_TX_PATH_EN;
	writel(tx_ctrl, base + NvRegTransmitterControl);
Linus Torvalds's avatar
Linus Torvalds committed
1444
1445
1446
1447
1448
	pci_push(base);
}

static void nv_stop_tx(struct net_device *dev)
{
1449
	struct fe_priv *np = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1450
	u8 __iomem *base = get_hwbase(dev);
1451
	u32 tx_ctrl = readl(base + NvRegTransmitterControl);
Linus Torvalds's avatar
Linus Torvalds committed
1452
1453

	dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
1454
1455
1456
1457
1458
	if (!np->mac_in_use)
		tx_ctrl &= ~NVREG_XMITCTL_START;
	else
		tx_ctrl |= NVREG_XMITCTL_TX_PATH_EN;
	writel(tx_ctrl, base + NvRegTransmitterControl);
Linus Torvalds's avatar
Linus Torvalds committed
1459
1460
1461
1462
1463
	reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
			NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
			KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");

	udelay(NV_TXSTOP_DELAY2);
1464
1465
1466
	if (!np->mac_in_use)
		writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV,
		       base + NvRegTransmitPoll);
Linus Torvalds's avatar
Linus Torvalds committed
1467
1468
}

1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
static void nv_start_rxtx(struct net_device *dev)
{
	nv_start_rx(dev);
	nv_start_tx(dev);
}

static void nv_stop_rxtx(struct net_device *dev)
{
	nv_stop_rx(dev);
	nv_stop_tx(dev);
}

Linus Torvalds's avatar
Linus Torvalds committed
1481
1482
static void nv_txrx_reset(struct net_device *dev)
{
1483
	struct fe_priv *np = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1484
1485
1486
	u8 __iomem *base = get_hwbase(dev);

	dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
1487
	writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
Linus Torvalds's avatar
Linus Torvalds committed
1488
1489
	pci_push(base);
	udelay(NV_TXRX_RESET_DELAY);
1490
	writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
Linus Torvalds's avatar
Linus Torvalds committed
1491
1492
1493
	pci_push(base);
}

1494
1495
1496
1497
static void nv_mac_reset(struct net_device *dev)
{
	struct fe_priv *np = netdev_priv(dev);
	u8 __iomem *base = get_hwbase(dev);
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1498
	u32 temp1, temp2, temp3;
1499
1500

	dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1501

1502
1503
	writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
	pci_push(base);
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1504
1505
1506
1507
1508
1509

	/* save registers since they will be cleared on reset */
	temp1 = readl(base + NvRegMacAddrA);
	temp2 = readl(base + NvRegMacAddrB);
	temp3 = readl(base + NvRegTransmitPoll);

1510
1511
1512
1513
1514
1515
	writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset);
	pci_push(base);
	udelay(NV_MAC_RESET_DELAY);
	writel(0, base + NvRegMacReset);
	pci_push(base);
	udelay(NV_MAC_RESET_DELAY);
Ayaz Abdulla's avatar
Ayaz Abdulla committed
1516
1517
1518
1519
1520
1521

	/* restore saved registers */
	writel(temp1, base + NvRegMacAddrA);
	writel(temp2, base + NvRegMacAddrB);
	writel(temp3, base + NvRegTransmitPoll);

1522
1523
1524
1525
	writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits