1 /*
2 * PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: NIC support code
5 * COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8 /*
9 * HW access code was taken from the Linux forcedeth driver
10 * Copyright (C) 2003,4,5 Manfred Spraul
11 * Copyright (C) 2004 Andrew de Quincey
12 * Copyright (C) 2004 Carl-Daniel Hailfinger
13 * Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA Corporation
14 */
15
16 /* INCLUDES *******************************************************************/
17
18 #include "nvnet.h"
19
20 #define NDEBUG
21 #include "debug.h"
22
23 /* FUNCTIONS ******************************************************************/
24
25 static
26 CODE_SEG("PAGE")
27 VOID
NvNetClearStatisticsCounters(_In_ PNVNET_ADAPTER Adapter)28 NvNetClearStatisticsCounters(
29 _In_ PNVNET_ADAPTER Adapter)
30 {
31 NVNET_REGISTER Counter, CounterEnd;
32
33 PAGED_CODE();
34
35 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
36
37 if (Adapter->Features & DEV_HAS_STATISTICS_V2)
38 CounterEnd = NvRegRxDropFrame;
39 else
40 CounterEnd = NvRegRxBroadcast;
41
42 for (Counter = NvRegTxCnt; Counter <= CounterEnd; Counter += sizeof(ULONG))
43 {
44 NV_READ(Adapter, Counter);
45 }
46
47 if (Adapter->Features & DEV_HAS_STATISTICS_V3)
48 {
49 NV_READ(Adapter, NvRegTxUnicast);
50 NV_READ(Adapter, NvRegTxMulticast);
51 NV_READ(Adapter, NvRegTxBroadcast);
52 }
53 }
54
55 static
56 CODE_SEG("PAGE")
57 VOID
NvNetResetMac(_In_ PNVNET_ADAPTER Adapter)58 NvNetResetMac(
59 _In_ PNVNET_ADAPTER Adapter)
60 {
61 ULONG Temp[3];
62
63 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
64
65 if (!(Adapter->Features & DEV_HAS_POWER_CNTRL))
66 return;
67
68 NV_WRITE(Adapter, NvRegTxRxControl,
69 Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
70
71 /* Save registers since they will be cleared on reset */
72 Temp[0] = NV_READ(Adapter, NvRegMacAddrA);
73 Temp[1] = NV_READ(Adapter, NvRegMacAddrB);
74 Temp[2] = NV_READ(Adapter, NvRegTransmitPoll);
75
76 NV_WRITE(Adapter, NvRegMacReset, NVREG_MAC_RESET_ASSERT);
77 NdisStallExecution(NV_MAC_RESET_DELAY);
78 NV_WRITE(Adapter, NvRegMacReset, 0);
79 NdisStallExecution(NV_MAC_RESET_DELAY);
80
81 /* Restore saved registers */
82 NV_WRITE(Adapter, NvRegMacAddrA, Temp[0]);
83 NV_WRITE(Adapter, NvRegMacAddrB, Temp[1]);
84 NV_WRITE(Adapter, NvRegTransmitPoll, Temp[2]);
85
86 NV_WRITE(Adapter, NvRegTxRxControl,
87 Adapter->TxRxControl | NVREG_TXRXCTL_BIT2);
88 }
89
90 VOID
NvNetResetReceiverAndTransmitter(_In_ PNVNET_ADAPTER Adapter)91 NvNetResetReceiverAndTransmitter(
92 _In_ PNVNET_ADAPTER Adapter)
93 {
94 NV_WRITE(Adapter, NvRegTxRxControl,
95 Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
96
97 NdisStallExecution(NV_TXRX_RESET_DELAY);
98
99 NV_WRITE(Adapter, NvRegTxRxControl,
100 Adapter->TxRxControl | NVREG_TXRXCTL_BIT2);
101 }
102
103 VOID
NvNetStartReceiver(_In_ PNVNET_ADAPTER Adapter)104 NvNetStartReceiver(
105 _In_ PNVNET_ADAPTER Adapter)
106 {
107 ULONG RxControl;
108
109 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
110
111 RxControl = NV_READ(Adapter, NvRegReceiverControl);
112 if ((NV_READ(Adapter, NvRegReceiverControl) & NVREG_RCVCTL_START) &&
113 !(Adapter->Flags & NV_MAC_IN_USE))
114 {
115 /* Already running? Stop it */
116 RxControl &= ~NVREG_RCVCTL_START;
117 NV_WRITE(Adapter, NvRegReceiverControl, RxControl);
118 }
119 NV_WRITE(Adapter, NvRegLinkSpeed, Adapter->LinkSpeed | NVREG_LINKSPEED_FORCE);
120
121 RxControl |= NVREG_RCVCTL_START;
122 if (Adapter->Flags & NV_MAC_IN_USE)
123 {
124 RxControl &= ~NVREG_RCVCTL_RX_PATH_EN;
125 }
126 NV_WRITE(Adapter, NvRegReceiverControl, RxControl);
127 }
128
129 VOID
NvNetStartTransmitter(_In_ PNVNET_ADAPTER Adapter)130 NvNetStartTransmitter(
131 _In_ PNVNET_ADAPTER Adapter)
132 {
133 ULONG TxControl;
134
135 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
136
137 TxControl = NV_READ(Adapter, NvRegTransmitterControl);
138 TxControl |= NVREG_XMITCTL_START;
139 if (Adapter->Flags & NV_MAC_IN_USE)
140 {
141 TxControl &= ~NVREG_XMITCTL_TX_PATH_EN;
142 }
143 NV_WRITE(Adapter, NvRegTransmitterControl, TxControl);
144 }
145
146 VOID
NvNetStopReceiver(_In_ PNVNET_ADAPTER Adapter)147 NvNetStopReceiver(
148 _In_ PNVNET_ADAPTER Adapter)
149 {
150 ULONG RxControl, i;
151
152 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
153
154 RxControl = NV_READ(Adapter, NvRegReceiverControl);
155 if (!(Adapter->Flags & NV_MAC_IN_USE))
156 RxControl &= ~NVREG_RCVCTL_START;
157 else
158 RxControl |= NVREG_RCVCTL_RX_PATH_EN;
159 NV_WRITE(Adapter, NvRegReceiverControl, RxControl);
160
161 for (i = 0; i < NV_RXSTOP_DELAY1MAX; ++i)
162 {
163 if (!(NV_READ(Adapter, NvRegReceiverStatus) & NVREG_RCVSTAT_BUSY))
164 break;
165
166 NdisStallExecution(NV_RXSTOP_DELAY1);
167 }
168
169 NdisStallExecution(NV_RXSTOP_DELAY2);
170
171 if (!(Adapter->Flags & NV_MAC_IN_USE))
172 {
173 NV_WRITE(Adapter, NvRegLinkSpeed, 0);
174 }
175 }
176
177 VOID
NvNetStopTransmitter(_In_ PNVNET_ADAPTER Adapter)178 NvNetStopTransmitter(
179 _In_ PNVNET_ADAPTER Adapter)
180 {
181 ULONG TxControl, i;
182
183 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
184
185 TxControl = NV_READ(Adapter, NvRegTransmitterControl);
186 if (!(Adapter->Flags & NV_MAC_IN_USE))
187 TxControl &= ~NVREG_XMITCTL_START;
188 else
189 TxControl |= NVREG_XMITCTL_TX_PATH_EN;
190 NV_WRITE(Adapter, NvRegTransmitterControl, TxControl);
191
192 for (i = 0; i < NV_TXSTOP_DELAY1MAX; ++i)
193 {
194 if (!(NV_READ(Adapter, NvRegTransmitterStatus) & NVREG_XMITSTAT_BUSY))
195 break;
196
197 NdisStallExecution(NV_TXSTOP_DELAY1);
198 }
199
200 NdisStallExecution(NV_TXSTOP_DELAY2);
201
202 if (!(Adapter->Flags & NV_MAC_IN_USE))
203 {
204 NV_WRITE(Adapter, NvRegTransmitPoll,
205 NV_READ(Adapter, NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV);
206 }
207 }
208
209 CODE_SEG("PAGE")
210 VOID
NvNetIdleTransmitter(_In_ PNVNET_ADAPTER Adapter,_In_ BOOLEAN ClearPhyControl)211 NvNetIdleTransmitter(
212 _In_ PNVNET_ADAPTER Adapter,
213 _In_ BOOLEAN ClearPhyControl)
214 {
215 ULONG i;
216
217 PAGED_CODE();
218
219 if (ClearPhyControl)
220 {
221 NV_WRITE(Adapter, NvRegAdapterControl,
222 NV_READ(Adapter, NvRegAdapterControl) & ~NVREG_ADAPTCTL_RUNNING);
223 }
224 else
225 {
226 NV_WRITE(Adapter, NvRegAdapterControl,
227 (Adapter->PhyAddress << NVREG_ADAPTCTL_PHYSHIFT) |
228 NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING);
229 }
230
231 NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_BIT2);
232 for (i = 0; i < NV_TXIDLE_ATTEMPTS; ++i)
233 {
234 if (NV_READ(Adapter, NvRegTxRxControl) & NVREG_TXRXCTL_IDLE)
235 break;
236
237 NdisStallExecution(NV_TXIDLE_DELAY);
238 }
239 }
240
241 VOID
NvNetUpdatePauseFrame(_Inout_ PNVNET_ADAPTER Adapter,_In_ ULONG PauseFlags)242 NvNetUpdatePauseFrame(
243 _Inout_ PNVNET_ADAPTER Adapter,
244 _In_ ULONG PauseFlags)
245 {
246 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
247
248 Adapter->PauseFlags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE);
249
250 if (Adapter->PauseFlags & NV_PAUSEFRAME_RX_CAPABLE)
251 {
252 ULONG PacketFilter = NV_READ(Adapter, NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX;
253
254 if (PauseFlags & NV_PAUSEFRAME_RX_ENABLE)
255 {
256 PacketFilter |= NVREG_PFF_PAUSE_RX;
257 Adapter->PauseFlags |= NV_PAUSEFRAME_RX_ENABLE;
258 }
259 NV_WRITE(Adapter, NvRegPacketFilterFlags, PacketFilter);
260 }
261
262 if (Adapter->PauseFlags & NV_PAUSEFRAME_TX_CAPABLE)
263 {
264 ULONG Mics = NV_READ(Adapter, NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX;
265
266 if (PauseFlags & NV_PAUSEFRAME_TX_ENABLE)
267 {
268 ULONG PauseEnable = NVREG_TX_PAUSEFRAME_ENABLE_V1;
269
270 if (Adapter->Features & DEV_HAS_PAUSEFRAME_TX_V2)
271 PauseEnable = NVREG_TX_PAUSEFRAME_ENABLE_V2;
272 if (Adapter->Features & DEV_HAS_PAUSEFRAME_TX_V3)
273 {
274 PauseEnable = NVREG_TX_PAUSEFRAME_ENABLE_V3;
275 /* Limit the number of TX pause frames to a default of 8 */
276 NV_WRITE(Adapter,
277 NvRegTxPauseFrameLimit,
278 NV_READ(Adapter, NvRegTxPauseFrameLimit) |
279 NVREG_TX_PAUSEFRAMELIMIT_ENABLE);
280 }
281 NV_WRITE(Adapter, NvRegTxPauseFrame, PauseEnable);
282 NV_WRITE(Adapter, NvRegMisc1, Mics | NVREG_MISC1_PAUSE_TX);
283 Adapter->PauseFlags |= NV_PAUSEFRAME_TX_ENABLE;
284 }
285 else
286 {
287 NV_WRITE(Adapter, NvRegTxPauseFrame, NVREG_TX_PAUSEFRAME_DISABLE);
288 NV_WRITE(Adapter, NvRegMisc1, Mics);
289 }
290 }
291 }
292
293 VOID
NvNetToggleClockPowerGating(_In_ PNVNET_ADAPTER Adapter,_In_ BOOLEAN Gate)294 NvNetToggleClockPowerGating(
295 _In_ PNVNET_ADAPTER Adapter,
296 _In_ BOOLEAN Gate)
297 {
298 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
299
300 if (!(Adapter->Flags & NV_MAC_IN_USE) && (Adapter->Features & DEV_HAS_POWER_CNTRL))
301 {
302 ULONG PowerState = NV_READ(Adapter, NvRegPowerState2);
303
304 if (Gate)
305 PowerState |= NVREG_POWERSTATE2_GATE_CLOCKS;
306 else
307 PowerState &= ~NVREG_POWERSTATE2_GATE_CLOCKS;
308 NV_WRITE(Adapter, NvRegPowerState2, PowerState);
309 }
310 }
311
312 VOID
313 NTAPI
NvNetMediaDetectionDpc(_In_ PVOID SystemSpecific1,_In_ PVOID FunctionContext,_In_ PVOID SystemSpecific2,_In_ PVOID SystemSpecific3)314 NvNetMediaDetectionDpc(
315 _In_ PVOID SystemSpecific1,
316 _In_ PVOID FunctionContext,
317 _In_ PVOID SystemSpecific2,
318 _In_ PVOID SystemSpecific3)
319 {
320 PNVNET_ADAPTER Adapter = FunctionContext;
321 BOOLEAN Connected, Report = FALSE;
322
323 UNREFERENCED_PARAMETER(SystemSpecific1);
324 UNREFERENCED_PARAMETER(SystemSpecific2);
325 UNREFERENCED_PARAMETER(SystemSpecific3);
326
327 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
328
329 NdisDprAcquireSpinLock(&Adapter->Lock);
330
331 Connected = NvNetUpdateLinkSpeed(Adapter);
332 if (Adapter->Connected != Connected)
333 {
334 Adapter->Connected = Connected;
335 Report = TRUE;
336
337 if (Connected)
338 {
339 /* Link up */
340 NvNetToggleClockPowerGating(Adapter, FALSE);
341 NdisDprAcquireSpinLock(&Adapter->Receive.Lock);
342 NvNetStartReceiver(Adapter);
343 }
344 else
345 {
346 /* Link down */
347 NvNetToggleClockPowerGating(Adapter, TRUE);
348 NdisDprAcquireSpinLock(&Adapter->Receive.Lock);
349 NvNetStopReceiver(Adapter);
350 }
351
352 NdisDprReleaseSpinLock(&Adapter->Receive.Lock);
353 }
354
355 NdisDprReleaseSpinLock(&Adapter->Lock);
356
357 if (Report)
358 {
359 NdisMIndicateStatus(Adapter->AdapterHandle,
360 Connected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
361 NULL,
362 0);
363 NdisMIndicateStatusComplete(Adapter->AdapterHandle);
364 }
365 }
366
367 BOOLEAN
368 NTAPI
NvNetInitPhaseSynchronized(_In_ PVOID SynchronizeContext)369 NvNetInitPhaseSynchronized(
370 _In_ PVOID SynchronizeContext)
371 {
372 PNVNET_ADAPTER Adapter = SynchronizeContext;
373
374 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
375
376 /* Enable interrupts on the NIC */
377 NvNetApplyInterruptMask(Adapter);
378
379 /*
380 * One manual link speed update: Interrupts are enabled,
381 * future link speed changes cause interrupts.
382 */
383 NV_READ(Adapter, NvRegMIIStatus);
384 NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_ALL);
385
386 /* Set link speed to invalid value, thus force NvNetUpdateLinkSpeed() to init HW */
387 Adapter->LinkSpeed = 0xFFFFFFFF;
388
389 Adapter->Connected = NvNetUpdateLinkSpeed(Adapter);
390
391 NvNetStartReceiver(Adapter);
392 NvNetStartTransmitter(Adapter);
393
394 Adapter->Flags |= NV_ACTIVE;
395
396 return TRUE;
397 }
398
399 CODE_SEG("PAGE")
400 NDIS_STATUS
NvNetInitNIC(_In_ PNVNET_ADAPTER Adapter,_In_ BOOLEAN InitPhy)401 NvNetInitNIC(
402 _In_ PNVNET_ADAPTER Adapter,
403 _In_ BOOLEAN InitPhy)
404 {
405 ULONG MiiControl, i;
406 NDIS_STATUS Status;
407
408 PAGED_CODE();
409
410 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
411
412 /* Disable WOL */
413 NV_WRITE(Adapter, NvRegWakeUpFlags, 0);
414
415 if (InitPhy)
416 {
417 Status = NvNetPhyInit(Adapter);
418 if (Status != NDIS_STATUS_SUCCESS)
419 {
420 return Status;
421 }
422 }
423
424 if (Adapter->PauseFlags & NV_PAUSEFRAME_TX_CAPABLE)
425 {
426 NV_WRITE(Adapter, NvRegTxPauseFrame, NVREG_TX_PAUSEFRAME_DISABLE);
427 }
428
429 /* Power up PHY */
430 MiiRead(Adapter, Adapter->PhyAddress, MII_CONTROL, &MiiControl);
431 MiiControl &= ~MII_CR_POWER_DOWN;
432 MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl);
433
434 NvNetToggleClockPowerGating(Adapter, FALSE);
435
436 NvNetResetMac(Adapter);
437
438 /* Clear multicast masks and addresses */
439 NV_WRITE(Adapter, NvRegMulticastAddrA, 0);
440 NV_WRITE(Adapter, NvRegMulticastAddrB, 0);
441 NV_WRITE(Adapter, NvRegMulticastMaskA, NVREG_MCASTMASKA_NONE);
442 NV_WRITE(Adapter, NvRegMulticastMaskB, NVREG_MCASTMASKB_NONE);
443
444 NV_WRITE(Adapter, NvRegTransmitterControl, 0);
445 NV_WRITE(Adapter, NvRegReceiverControl, 0);
446
447 NV_WRITE(Adapter, NvRegAdapterControl, 0);
448
449 NV_WRITE(Adapter, NvRegLinkSpeed, 0);
450 NV_WRITE(Adapter, NvRegTransmitPoll,
451 NV_READ(Adapter, NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV);
452 NvNetResetReceiverAndTransmitter(Adapter);
453 NV_WRITE(Adapter, NvRegUnknownSetupReg6, 0);
454
455 /* Receive descriptor ring buffer */
456 NV_WRITE(Adapter, NvRegRxRingPhysAddr,
457 NdisGetPhysicalAddressLow(Adapter->RbdPhys));
458 if (Adapter->Features & DEV_HAS_HIGH_DMA)
459 {
460 NV_WRITE(Adapter, NvRegRxRingPhysAddrHigh,
461 NdisGetPhysicalAddressHigh(Adapter->RbdPhys));
462 }
463
464 /* Transmit descriptor ring buffer */
465 NV_WRITE(Adapter, NvRegTxRingPhysAddr,
466 NdisGetPhysicalAddressLow(Adapter->TbdPhys));
467 if (Adapter->Features & DEV_HAS_HIGH_DMA)
468 {
469 NV_WRITE(Adapter, NvRegTxRingPhysAddrHigh,
470 NdisGetPhysicalAddressHigh(Adapter->TbdPhys));
471 }
472
473 /* Ring sizes */
474 NV_WRITE(Adapter, NvRegRingSizes,
475 (NVNET_RECEIVE_DESCRIPTORS - 1) << NVREG_RINGSZ_RXSHIFT |
476 (NVNET_TRANSMIT_DESCRIPTORS - 1) << NVREG_RINGSZ_TXSHIFT);
477
478 /* Set default link speed settings */
479 NV_WRITE(Adapter, NvRegLinkSpeed, NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10);
480
481 if (Adapter->Features & (DEV_HAS_HIGH_DMA | DEV_HAS_LARGEDESC))
482 NV_WRITE(Adapter, NvRegTxWatermark, NVREG_TX_WM_DESC2_3_DEFAULT);
483 else
484 NV_WRITE(Adapter, NvRegTxWatermark, NVREG_TX_WM_DESC1_DEFAULT);
485
486 NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl);
487 NV_WRITE(Adapter, NvRegVlanControl, Adapter->VlanControl);
488 NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_BIT1);
489
490 for (i = 0; i < NV_SETUP5_DELAYMAX; ++i)
491 {
492 if (NV_READ(Adapter, NvRegUnknownSetupReg5) & NVREG_UNKSETUP5_BIT31)
493 break;
494
495 NdisStallExecution(NV_SETUP5_DELAY);
496 }
497
498 NV_WRITE(Adapter, NvRegMIIMask, 0);
499 NV_WRITE(Adapter, NvRegIrqStatus, NVREG_IRQSTAT_MASK);
500 NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_ALL);
501
502 NV_WRITE(Adapter, NvRegMisc1, NVREG_MISC1_FORCE | NVREG_MISC1_HD);
503 NV_WRITE(Adapter, NvRegTransmitterStatus, NV_READ(Adapter, NvRegTransmitterStatus));
504 NV_WRITE(Adapter, NvRegPacketFilterFlags, NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR);
505 NV_WRITE(Adapter, NvRegOffloadConfig, (NVNET_MAXIMUM_FRAME_SIZE - sizeof(ETH_HEADER))
506 + NV_RX_HEADERS);
507
508 NV_WRITE(Adapter, NvRegReceiverStatus, NV_READ(Adapter, NvRegReceiverStatus));
509
510 NvNetBackoffSetSlotTime(Adapter);
511
512 NV_WRITE(Adapter, NvRegTxDeferral, NVREG_TX_DEFERRAL_DEFAULT);
513 NV_WRITE(Adapter, NvRegRxDeferral, NVREG_RX_DEFERRAL_DEFAULT);
514
515 if (Adapter->OptimizationMode == NV_OPTIMIZATION_MODE_THROUGHPUT)
516 NV_WRITE(Adapter, NvRegPollingInterval, NVREG_POLL_DEFAULT_THROUGHPUT);
517 else
518 NV_WRITE(Adapter, NvRegPollingInterval, NVREG_POLL_DEFAULT_CPU);
519 NV_WRITE(Adapter, NvRegUnknownSetupReg6, NVREG_UNKSETUP6_VAL);
520
521 NV_WRITE(Adapter, NvRegAdapterControl,
522 (Adapter->PhyAddress << NVREG_ADAPTCTL_PHYSHIFT) |
523 NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING);
524 NV_WRITE(Adapter, NvRegMIISpeed, NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY);
525 NV_WRITE(Adapter, NvRegMIIMask, NVREG_MII_LINKCHANGE);
526
527 NdisStallExecution(10);
528 NV_WRITE(Adapter, NvRegPowerState,
529 NV_READ(Adapter, NvRegPowerState) & ~NVREG_POWERSTATE_VALID);
530
531 if (Adapter->Features & DEV_HAS_STATISTICS_COUNTERS)
532 {
533 NvNetClearStatisticsCounters(Adapter);
534 }
535
536 return NDIS_STATUS_SUCCESS;
537 }
538
539 CODE_SEG("PAGE")
540 NDIS_STATUS
NvNetGetPermanentMacAddress(_Inout_ PNVNET_ADAPTER Adapter,_Out_writes_bytes_all_ (ETH_LENGTH_OF_ADDRESS)PUCHAR MacAddress)541 NvNetGetPermanentMacAddress(
542 _Inout_ PNVNET_ADAPTER Adapter,
543 _Out_writes_bytes_all_(ETH_LENGTH_OF_ADDRESS) PUCHAR MacAddress)
544 {
545 ULONG Temp[2], TxPoll;
546
547 PAGED_CODE();
548
549 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
550
551 Temp[0] = NV_READ(Adapter, NvRegMacAddrA);
552 Temp[1] = NV_READ(Adapter, NvRegMacAddrB);
553
554 TxPoll = NV_READ(Adapter, NvRegTransmitPoll);
555
556 if (Adapter->Features & DEV_HAS_CORRECT_MACADDR)
557 {
558 /* MAC address is already in the correct order */
559 MacAddress[0] = (Temp[0] >> 0) & 0xFF;
560 MacAddress[1] = (Temp[0] >> 8) & 0xFF;
561 MacAddress[2] = (Temp[0] >> 16) & 0xFF;
562 MacAddress[3] = (Temp[0] >> 24) & 0xFF;
563 MacAddress[4] = (Temp[1] >> 0) & 0xFF;
564 MacAddress[5] = (Temp[1] >> 8) & 0xFF;
565 }
566 /* Handle the special flag for the correct MAC address order */
567 else if (TxPoll & NVREG_TRANSMITPOLL_MAC_ADDR_REV)
568 {
569 /* MAC address is already in the correct order */
570 MacAddress[0] = (Temp[0] >> 0) & 0xFF;
571 MacAddress[1] = (Temp[0] >> 8) & 0xFF;
572 MacAddress[2] = (Temp[0] >> 16) & 0xFF;
573 MacAddress[3] = (Temp[0] >> 24) & 0xFF;
574 MacAddress[4] = (Temp[1] >> 0) & 0xFF;
575 MacAddress[5] = (Temp[1] >> 8) & 0xFF;
576
577 /*
578 * Set original MAC address back to the reversed version.
579 * This flag will be cleared during low power transition.
580 * Therefore, we should always put back the reversed address.
581 */
582 Temp[0] = (MacAddress[5] << 0) | (MacAddress[4] << 8) |
583 (MacAddress[3] << 16) | (MacAddress[2] << 24);
584 Temp[1] = (MacAddress[1] << 0) | (MacAddress[0] << 8);
585 }
586 else
587 {
588 /* Need to reverse MAC address to the correct order */
589 MacAddress[0] = (Temp[1] >> 8) & 0xFF;
590 MacAddress[1] = (Temp[1] >> 0) & 0xFF;
591 MacAddress[2] = (Temp[0] >> 24) & 0xFF;
592 MacAddress[3] = (Temp[0] >> 16) & 0xFF;
593 MacAddress[4] = (Temp[0] >> 8) & 0xFF;
594 MacAddress[5] = (Temp[0] >> 0) & 0xFF;
595
596 /*
597 * Use a flag to signal the driver whether the MAC address was already corrected,
598 * so that it is not reversed again on a subsequent initialize.
599 */
600 NV_WRITE(Adapter, NvRegTransmitPoll, TxPoll | NVREG_TRANSMITPOLL_MAC_ADDR_REV);
601 }
602
603 Adapter->OriginalMacAddress[0] = Temp[0];
604 Adapter->OriginalMacAddress[1] = Temp[1];
605
606 NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
607 MacAddress[0],
608 MacAddress[1],
609 MacAddress[2],
610 MacAddress[3],
611 MacAddress[4],
612 MacAddress[5]));
613
614 if (ETH_IS_MULTICAST(MacAddress) || ETH_IS_EMPTY(MacAddress))
615 return NDIS_STATUS_INVALID_ADDRESS;
616
617 return NDIS_STATUS_SUCCESS;
618 }
619
620 CODE_SEG("PAGE")
621 VOID
NvNetSetupMacAddress(_In_ PNVNET_ADAPTER Adapter,_In_reads_bytes_ (ETH_LENGTH_OF_ADDRESS)PUCHAR MacAddress)622 NvNetSetupMacAddress(
623 _In_ PNVNET_ADAPTER Adapter,
624 _In_reads_bytes_(ETH_LENGTH_OF_ADDRESS) PUCHAR MacAddress)
625 {
626 PAGED_CODE();
627
628 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
629
630 NV_WRITE(Adapter, NvRegMacAddrA,
631 MacAddress[3] << 24 | MacAddress[2] << 16 | MacAddress[1] << 8 | MacAddress[0]);
632 NV_WRITE(Adapter, NvRegMacAddrB, MacAddress[5] << 8 | MacAddress[4]);
633 }
634
635 static
636 VOID
637 CODE_SEG("PAGE")
NvNetValidateConfiguration(_Inout_ PNVNET_ADAPTER Adapter)638 NvNetValidateConfiguration(
639 _Inout_ PNVNET_ADAPTER Adapter)
640 {
641 PAGED_CODE();
642
643 if (!(Adapter->Features & DEV_HAS_LARGEDESC))
644 {
645 Adapter->MaximumFrameSize = NVNET_MAXIMUM_FRAME_SIZE;
646 }
647 if (!(Adapter->Features & DEV_HAS_CHECKSUM))
648 {
649 Adapter->Flags &= ~(NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND);
650 }
651 if (!(Adapter->Features & DEV_HAS_VLAN))
652 {
653 Adapter->Flags &= ~(NV_PACKET_PRIORITY | NV_VLAN_TAGGING);
654 }
655 if ((Adapter->Features & DEV_NEED_TIMERIRQ) &&
656 (Adapter->OptimizationMode == NV_OPTIMIZATION_MODE_DYNAMIC))
657 {
658 Adapter->OptimizationMode = NV_OPTIMIZATION_MODE_THROUGHPUT;
659 }
660 if (!(Adapter->Features & DEV_HAS_TX_PAUSEFRAME))
661 {
662 if (Adapter->FlowControlMode == NV_FLOW_CONTROL_TX)
663 {
664 Adapter->FlowControlMode = NV_FLOW_CONTROL_AUTO;
665 }
666 else if (Adapter->FlowControlMode == NV_FLOW_CONTROL_RX_TX)
667 {
668 Adapter->FlowControlMode = NV_FLOW_CONTROL_RX;
669 }
670 }
671 }
672
673 CODE_SEG("PAGE")
674 NDIS_STATUS
NvNetRecognizeHardware(_Inout_ PNVNET_ADAPTER Adapter)675 NvNetRecognizeHardware(
676 _Inout_ PNVNET_ADAPTER Adapter)
677 {
678 ULONG Bytes;
679 PCI_COMMON_CONFIG PciConfig;
680
681 PAGED_CODE();
682
683 NDIS_DbgPrint(MIN_TRACE, ("()\n"));
684
685 Bytes = NdisReadPciSlotInformation(Adapter->AdapterHandle,
686 0,
687 FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID),
688 &PciConfig,
689 PCI_COMMON_HDR_LENGTH);
690 if (Bytes != PCI_COMMON_HDR_LENGTH)
691 return NDIS_STATUS_ADAPTER_NOT_FOUND;
692
693 if (PciConfig.VendorID != 0x10DE)
694 return NDIS_STATUS_ADAPTER_NOT_FOUND;
695
696 Adapter->DeviceId = PciConfig.DeviceID;
697 Adapter->RevisionId = PciConfig.RevisionID;
698
699 switch (PciConfig.DeviceID)
700 {
701 case 0x01C3: /* nForce */
702 case 0x0066: /* nForce2 */
703 case 0x00D6: /* nForce2 */
704 Adapter->Features = DEV_NEED_TIMERIRQ | DEV_NEED_LINKTIMER;
705 break;
706
707 case 0x0086: /* nForce3 */
708 case 0x008C: /* nForce3 */
709 case 0x00E6: /* nForce3 */
710 case 0x00DF: /* nForce3 */
711 Adapter->Features = DEV_NEED_TIMERIRQ | DEV_NEED_LINKTIMER |
712 DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM;
713 break;
714
715 case 0x0056: /* CK804 */
716 case 0x0057: /* CK804 */
717 case 0x0037: /* MCP04 */
718 case 0x0038: /* MCP04 */
719 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
720 DEV_HAS_HIGH_DMA | DEV_HAS_STATISTICS_V1 | DEV_NEED_TX_LIMIT;
721 break;
722
723 case 0x0268: /* MCP51 */
724 case 0x0269: /* MCP51 */
725 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
726 DEV_HAS_STATISTICS_V1 | DEV_NEED_LOW_POWER_FIX;
727 break;
728
729 case 0x0372: /* MCP55 */
730 case 0x0373: /* MCP55 */
731 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
732 DEV_HAS_HIGH_DMA | DEV_HAS_VLAN | DEV_HAS_MSI | DEV_HAS_MSI_X |
733 DEV_HAS_POWER_CNTRL | DEV_HAS_PAUSEFRAME_TX_V1 |
734 DEV_HAS_STATISTICS_V1 | DEV_HAS_STATISTICS_V2 |
735 DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
736 DEV_NEED_TX_LIMIT | DEV_NEED_MSI_FIX;
737 break;
738
739 case 0x03E5: /* MCP61 */
740 case 0x03E6: /* MCP61 */
741 case 0x03EE: /* MCP61 */
742 case 0x03EF: /* MCP61 */
743 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
744 DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 | DEV_HAS_STATISTICS_V1 |
745 DEV_HAS_STATISTICS_V2 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
746 DEV_HAS_CORRECT_MACADDR | DEV_NEED_MSI_FIX;
747 break;
748
749 case 0x0450: /* MCP65 */
750 case 0x0451: /* MCP65 */
751 case 0x0452: /* MCP65 */
752 case 0x0453: /* MCP65 */
753 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_HIGH_DMA |
754 DEV_HAS_POWER_CNTRL | DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 |
755 DEV_HAS_STATISTICS_V1 | DEV_HAS_STATISTICS_V2 |
756 DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
757 DEV_HAS_CORRECT_MACADDR | DEV_NEED_TX_LIMIT |
758 DEV_HAS_GEAR_MODE | DEV_NEED_MSI_FIX;
759 break;
760
761 case 0x054C: /* MCP67 */
762 case 0x054D: /* MCP67 */
763 case 0x054E: /* MCP67 */
764 case 0x054F: /* MCP67 */
765 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
766 DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 | DEV_HAS_STATISTICS_V1 |
767 DEV_HAS_STATISTICS_V2 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
768 DEV_HAS_CORRECT_MACADDR | DEV_HAS_GEAR_MODE | DEV_NEED_MSI_FIX;
769 break;
770
771 case 0x07DC: /* MCP73 */
772 case 0x07DD: /* MCP73 */
773 case 0x07DE: /* MCP73 */
774 case 0x07DF: /* MCP73 */
775 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
776 DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 | DEV_HAS_STATISTICS_V1 |
777 DEV_HAS_STATISTICS_V2 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
778 DEV_HAS_CORRECT_MACADDR | DEV_HAS_COLLISION_FIX |
779 DEV_HAS_GEAR_MODE | DEV_NEED_MSI_FIX;
780 break;
781
782 case 0x0760: /* MCP77 */
783 case 0x0761: /* MCP77 */
784 case 0x0762: /* MCP77 */
785 case 0x0763: /* MCP77 */
786 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_CHECKSUM | DEV_HAS_HIGH_DMA |
787 DEV_HAS_MSI | DEV_HAS_POWER_CNTRL | DEV_HAS_PAUSEFRAME_TX_V2 |
788 DEV_HAS_STATISTICS_V1 | DEV_HAS_STATISTICS_V2 |
789 DEV_HAS_STATISTICS_V3 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
790 DEV_HAS_CORRECT_MACADDR | DEV_HAS_COLLISION_FIX |
791 DEV_NEED_TX_LIMIT2 | DEV_HAS_GEAR_MODE |
792 DEV_NEED_PHY_INIT_FIX | DEV_NEED_MSI_FIX;
793 break;
794
795 case 0x0AB0: /* MCP79 */
796 case 0x0AB1: /* MCP79 */
797 case 0x0AB2: /* MCP79 */
798 case 0x0AB3: /* MCP79 */
799 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
800 DEV_HAS_HIGH_DMA | DEV_HAS_MSI | DEV_HAS_POWER_CNTRL |
801 DEV_HAS_PAUSEFRAME_TX_V3 | DEV_HAS_STATISTICS_V1 |
802 DEV_HAS_STATISTICS_V2 | DEV_HAS_STATISTICS_V3 |
803 DEV_HAS_TEST_EXTENDED | DEV_HAS_CORRECT_MACADDR |
804 DEV_HAS_COLLISION_FIX | DEV_NEED_TX_LIMIT2 |
805 DEV_HAS_GEAR_MODE | DEV_NEED_PHY_INIT_FIX | DEV_NEED_MSI_FIX;
806 break;
807
808 case 0x0D7D: /* MCP89 */
809 Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
810 DEV_HAS_HIGH_DMA | DEV_HAS_MSI | DEV_HAS_POWER_CNTRL |
811 DEV_HAS_PAUSEFRAME_TX_V3 | DEV_HAS_STATISTICS_V1 |
812 DEV_HAS_STATISTICS_V2 | DEV_HAS_STATISTICS_V3 |
813 DEV_HAS_TEST_EXTENDED | DEV_HAS_CORRECT_MACADDR |
814 DEV_HAS_COLLISION_FIX | DEV_HAS_GEAR_MODE | DEV_NEED_PHY_INIT_FIX;
815 break;
816
817 default:
818 return NDIS_STATUS_NOT_RECOGNIZED;
819 }
820
821 /* Normalize all .INF parameters */
822 NvNetValidateConfiguration(Adapter);
823
824 /* FIXME: Disable some NIC features, we don't support these yet */
825 #if 1
826 Adapter->VlanControl = 0;
827 Adapter->Flags &= ~(NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND |
828 NV_PACKET_PRIORITY | NV_VLAN_TAGGING);
829 #endif
830
831 /* For code paths debugging (32-bit descriptors work on all hardware variants) */
832 #if 0
833 Adapter->Features &= ~(DEV_HAS_HIGH_DMA | DEV_HAS_LARGEDESC);
834 #endif
835
836 if (Adapter->Features & DEV_HAS_POWER_CNTRL)
837 Adapter->WakeFrameBitmap = ~(0xFFFFFFFF << NV_WAKEUPPATTERNS_V2);
838 else
839 Adapter->WakeFrameBitmap = ~(0xFFFFFFFF << NV_WAKEUPPATTERNS);
840
841 /* 64-bit descriptors */
842 if (Adapter->Features & DEV_HAS_HIGH_DMA)
843 {
844 /* Note: Some devices here also support Jumbo Frames */
845 Adapter->TxRxControl = NVREG_TXRXCTL_DESC_3;
846 }
847 /* 32-bit descriptors */
848 else
849 {
850 if (Adapter->Features & DEV_HAS_LARGEDESC)
851 {
852 /* Jumbo Frames */
853 Adapter->TxRxControl = NVREG_TXRXCTL_DESC_2;
854 }
855 else
856 {
857 /* Original packet format */
858 Adapter->TxRxControl = NVREG_TXRXCTL_DESC_1;
859 }
860 }
861
862 /* Flow control */
863 Adapter->PauseFlags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
864 if (Adapter->Features & DEV_HAS_TX_PAUSEFRAME)
865 {
866 Adapter->PauseFlags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ;
867 }
868 if (Adapter->FlowControlMode != NV_FLOW_CONTROL_AUTO)
869 {
870 Adapter->PauseFlags &= ~(NV_PAUSEFRAME_AUTONEG | NV_PAUSEFRAME_RX_REQ |
871 NV_PAUSEFRAME_TX_REQ);
872 switch (Adapter->FlowControlMode)
873 {
874 case NV_FLOW_CONTROL_RX:
875 Adapter->PauseFlags |= NV_PAUSEFRAME_RX_REQ;
876 break;
877 case NV_FLOW_CONTROL_TX:
878 Adapter->PauseFlags |= NV_PAUSEFRAME_TX_REQ;
879 break;
880 case NV_FLOW_CONTROL_RX_TX:
881 Adapter->PauseFlags |= NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_TX_REQ;
882 break;
883
884 default:
885 break;
886 }
887 }
888
889 /* Work around errata in some NICs */
890 if (Adapter->Features & (DEV_NEED_TX_LIMIT | DEV_NEED_TX_LIMIT2))
891 {
892 Adapter->Flags |= NV_SEND_ERRATA_PRESENT;
893
894 if ((Adapter->Features & DEV_NEED_TX_LIMIT2) && Adapter->RevisionId >= 0xA2)
895 {
896 Adapter->Flags &= ~NV_SEND_ERRATA_PRESENT;
897 }
898 }
899 if (Adapter->Flags & NV_SEND_ERRATA_PRESENT)
900 {
901 NDIS_DbgPrint(MIN_TRACE, ("Transmit workaround active\n"));
902 }
903
904 /* Initialize the interrupt mask */
905 if (Adapter->OptimizationMode == NV_OPTIMIZATION_MODE_CPU)
906 {
907 Adapter->InterruptMask = NVREG_IRQMASK_CPU;
908 }
909 else
910 {
911 Adapter->InterruptMask = NVREG_IRQMASK_THROUGHPUT;
912 }
913 if (Adapter->Features & DEV_NEED_TIMERIRQ)
914 {
915 Adapter->InterruptMask |= NVREG_IRQ_TIMER;
916 }
917
918 if (Adapter->Features & DEV_NEED_LINKTIMER)
919 {
920 NdisMInitializeTimer(&Adapter->MediaDetectionTimer,
921 Adapter->AdapterHandle,
922 NvNetMediaDetectionDpc,
923 Adapter);
924 }
925
926 return NDIS_STATUS_SUCCESS;
927 }
928