xref: /reactos/drivers/network/dd/nvnet/nic.c (revision b79fbe23)
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