xref: /reactos/drivers/network/dd/nvnet/nvnet.c (revision 1de09c47)
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:     Miniport driver entrypoint
5  * COPYRIGHT:   Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include "nvnet.h"
11 
12 #define NDEBUG
13 #include "debug.h"
14 
15 /* GLOBALS ********************************************************************/
16 
17 CODE_SEG("INIT")
18 DRIVER_INITIALIZE DriverEntry;
19 
20 /* FUNCTIONS ******************************************************************/
21 
22 CODE_SEG("PAGE")
23 VOID
24 NvNetFlushTransmitQueue(
25     _In_ PNVNET_ADAPTER Adapter,
26     _In_ NDIS_STATUS CompleteStatus)
27 {
28     PNVNET_TCB Tcb;
29 
30     PAGED_CODE();
31 
32     for (Tcb = Adapter->Send.LastTcb;
33          Tcb != Adapter->Send.CurrentTcb;
34          Tcb = NV_NEXT_TCB(Adapter, Tcb))
35     {
36         NdisMSendComplete(Adapter->AdapterHandle,
37                           Tcb->Packet,
38                           CompleteStatus);
39 
40         NV_RELEASE_TCB(Adapter, Tcb);
41     }
42 }
43 
44 DECLSPEC_NOINLINE /* Called from pageable code */
45 VOID
46 NvNetPauseProcessing(
47     _In_ PNVNET_ADAPTER Adapter)
48 {
49     NvNetDisableInterrupts(Adapter);
50 
51     NdisAcquireSpinLock(&Adapter->Send.Lock);
52     Adapter->Flags &= ~NV_ACTIVE;
53     NdisReleaseSpinLock(&Adapter->Send.Lock);
54 }
55 
56 CODE_SEG("PAGE")
57 VOID
58 NvNetStopAdapter(
59     _In_ PNVNET_ADAPTER Adapter)
60 {
61     BOOLEAN Dummy;
62 
63     PAGED_CODE();
64 
65     NdisMCancelTimer(&Adapter->MediaDetectionTimer, &Dummy);
66 
67     NvNetDisableInterrupts(Adapter);
68 
69     KeFlushQueuedDpcs();
70 }
71 
72 CODE_SEG("PAGE")
73 VOID
74 NvNetStartAdapter(
75     _In_ PNVNET_ADAPTER Adapter)
76 {
77     PAGED_CODE();
78 
79     NdisMSynchronizeWithInterrupt(&Adapter->Interrupt,
80                                   NvNetInitPhaseSynchronized,
81                                   Adapter);
82 
83     /* Setup the link timer right after the NIC is initialized */
84     if (Adapter->Features & DEV_NEED_LINKTIMER)
85     {
86         NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer,
87                               NVNET_MEDIA_DETECTION_INTERVAL);
88     }
89 }
90 
91 static
92 CODE_SEG("PAGE")
93 VOID
94 NTAPI
95 NvNetResetWorker(
96     _In_ PNDIS_WORK_ITEM WorkItem,
97     _In_opt_ PVOID Context)
98 {
99     PNVNET_ADAPTER Adapter = Context;
100 
101     PAGED_CODE();
102 
103     NvNetStopAdapter(Adapter);
104 
105     NvNetIdleTransmitter(Adapter, TRUE);
106     NvNetStopTransmitter(Adapter);
107     NvNetStopReceiver(Adapter);
108     NV_WRITE(Adapter, NvRegTxRxControl,
109              Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
110     NdisStallExecution(NV_TXRX_RESET_DELAY);
111 
112     NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
113 
114     NT_VERIFY(NvNetInitNIC(Adapter, FALSE) == NDIS_STATUS_SUCCESS);
115 
116     NvNetStartAdapter(Adapter);
117 
118     _InterlockedDecrement(&Adapter->ResetLock);
119 
120     NdisMResetComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS, TRUE);
121 }
122 
123 /* NDIS CALLBACKS *************************************************************/
124 
125 static
126 BOOLEAN
127 NTAPI
128 MiniportCheckForHang(
129     _In_ NDIS_HANDLE MiniportAdapterContext)
130 {
131     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
132 
133     NdisDprAcquireSpinLock(&Adapter->Send.Lock);
134 
135     if (Adapter->Flags & NV_ACTIVE &&
136         Adapter->Send.TcbSlots < NVNET_TRANSMIT_BLOCKS)
137     {
138         if (++Adapter->Send.StuckCount > NVNET_TRANSMIT_HANG_THRESHOLD)
139         {
140             NDIS_DbgPrint(MAX_TRACE, ("Transmit timeout!\n"));
141 
142 #if defined(SARCH_XBOX)
143             /* Apply a HACK to make XQEMU happy... */
144             NvNetDisableInterrupts(Adapter);
145             NvNetApplyInterruptMask(Adapter);
146 #endif
147 
148             Adapter->Send.StuckCount = 0;
149         }
150     }
151 
152     NdisDprReleaseSpinLock(&Adapter->Send.Lock);
153 
154     return FALSE;
155 }
156 
157 static
158 CODE_SEG("PAGE")
159 VOID
160 NTAPI
161 MiniportHalt(
162     _In_ NDIS_HANDLE MiniportAdapterContext)
163 {
164     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
165     BOOLEAN IsActive = !!(Adapter->Flags & NV_ACTIVE);
166 
167     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
168 
169     PAGED_CODE();
170 
171     if (IsActive)
172     {
173         NvNetPauseProcessing(Adapter);
174     }
175 
176     NvNetStopAdapter(Adapter);
177 
178     if (IsActive)
179     {
180         NvNetIdleTransmitter(Adapter, TRUE);
181         NvNetStopTransmitter(Adapter);
182         NvNetStopReceiver(Adapter);
183         NV_WRITE(Adapter, NvRegTxRxControl,
184                  Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
185         NdisStallExecution(NV_TXRX_RESET_DELAY);
186     }
187 
188     NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
189 
190     NvNetToggleClockPowerGating(Adapter, TRUE);
191 
192     NV_WRITE(Adapter, NvRegMacAddrA, Adapter->OriginalMacAddress[0]);
193     NV_WRITE(Adapter, NvRegMacAddrB, Adapter->OriginalMacAddress[1]);
194     NV_WRITE(Adapter, NvRegTransmitPoll,
195              NV_READ(Adapter, NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV);
196 
197     SidebandUnitReleaseSemaphore(Adapter);
198 
199     NvNetFreeAdapter(Adapter);
200 }
201 
202 static
203 NDIS_STATUS
204 NTAPI
205 MiniportReset(
206     _Out_ PBOOLEAN AddressingReset,
207     _In_ NDIS_HANDLE MiniportAdapterContext)
208 {
209     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
210 
211     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
212 
213     if (_InterlockedCompareExchange(&Adapter->ResetLock, 1, 0))
214     {
215         return NDIS_STATUS_RESET_IN_PROGRESS;
216     }
217 
218     NvNetPauseProcessing(Adapter);
219 
220     NdisInitializeWorkItem(&Adapter->ResetWorkItem, NvNetResetWorker, Adapter);
221     NdisScheduleWorkItem(&Adapter->ResetWorkItem);
222 
223     return NDIS_STATUS_PENDING;
224 }
225 
226 static
227 VOID
228 NTAPI
229 MiniportShutdown(
230     _In_ NDIS_HANDLE MiniportAdapterContext)
231 {
232     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
233 
234     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
235 
236     if (Adapter->Flags & NV_ACTIVE)
237     {
238         if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
239         {
240             NvNetPauseProcessing(Adapter);
241         }
242 
243         NvNetIdleTransmitter(Adapter, TRUE);
244         NvNetStopTransmitter(Adapter);
245         NvNetStopReceiver(Adapter);
246         NV_WRITE(Adapter, NvRegTxRxControl,
247                  Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
248         NdisStallExecution(NV_TXRX_RESET_DELAY);
249 
250         SidebandUnitReleaseSemaphore(Adapter);
251     }
252 
253     NvNetDisableInterrupts(Adapter);
254 
255     NvNetSetPowerState(Adapter, NdisDeviceStateD3, 0);
256 }
257 
258 CODE_SEG("INIT")
259 NTSTATUS
260 NTAPI
261 DriverEntry(
262     _In_ PDRIVER_OBJECT DriverObject,
263     _In_ PUNICODE_STRING RegistryPath)
264 {
265     NDIS_HANDLE WrapperHandle;
266     NDIS_MINIPORT_CHARACTERISTICS Characteristics = { 0 };
267     NDIS_STATUS Status;
268 
269     NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);
270     if (!WrapperHandle)
271     {
272         return NDIS_STATUS_FAILURE;
273     }
274 
275     Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
276     Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
277     Characteristics.CheckForHangHandler = MiniportCheckForHang;
278     Characteristics.HaltHandler = MiniportHalt;
279     Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
280     Characteristics.InitializeHandler = MiniportInitialize;
281     Characteristics.ISRHandler = MiniportISR;
282     Characteristics.QueryInformationHandler = MiniportQueryInformation;
283     Characteristics.ResetHandler = MiniportReset;
284     Characteristics.SendHandler = MiniportSend; /* TODO */
285     Characteristics.SetInformationHandler = MiniportSetInformation;
286     // Characteristics.ReturnPacketHandler = MiniportReturnPacket; /* TODO */
287     // Characteristics.SendPacketsHandler = MiniportSendPackets; /* TODO */
288     Characteristics.AdapterShutdownHandler = MiniportShutdown;
289 
290     Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
291     if (Status != NDIS_STATUS_SUCCESS)
292     {
293         NdisTerminateWrapper(WrapperHandle, NULL);
294         return Status;
295     }
296 
297     return Status;
298 }
299