1 /*
2 * PROJECT: ReactOS DC21x4 Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Miniport driver entry
5 * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include "dc21x4.h"
11
12 #include <debug.h>
13
14 /* FUNCTIONS ******************************************************************/
15
16 ULONG
DcEthernetCrc(_In_reads_bytes_ (Size)const VOID * Buffer,_In_ ULONG Size)17 DcEthernetCrc(
18 _In_reads_bytes_(Size) const VOID* Buffer,
19 _In_ ULONG Size)
20 {
21 ULONG i, j, Crc;
22 const UCHAR* Data = Buffer;
23
24 Crc = 0xFFFFFFFF;
25 for (i = 0; i < Size; ++i)
26 {
27 Crc ^= Data[i];
28 for (j = 8; j > 0; j--)
29 {
30 /* CRC-32 polynomial little-endian */
31 Crc = (Crc >> 1) ^ (-(LONG)(Crc & 1) & 0xEDB88320);
32 }
33 }
34
35 return Crc;
36 }
37
38 static
39 VOID
DcFlushTransmitQueue(_In_ PDC21X4_ADAPTER Adapter)40 DcFlushTransmitQueue(
41 _In_ PDC21X4_ADAPTER Adapter)
42 {
43 LIST_ENTRY DoneList;
44 PLIST_ENTRY Entry;
45 PNDIS_PACKET Packet;
46 PDC_TCB Tcb;
47
48 InitializeListHead(&DoneList);
49
50 NdisAcquireSpinLock(&Adapter->SendLock);
51
52 /* Remove pending transmissions from the transmit ring */
53 for (Tcb = Adapter->LastTcb;
54 Tcb != Adapter->CurrentTcb;
55 Tcb = DC_NEXT_TCB(Adapter, Tcb))
56 {
57 Packet = Tcb->Packet;
58
59 if (!Packet)
60 continue;
61
62 InsertTailList(&DoneList, DC_LIST_ENTRY_FROM_PACKET(Packet));
63
64 DC_RELEASE_TCB(Adapter, Tcb);
65 }
66 Adapter->CurrentTcb = Tcb;
67
68 /* Remove pending transmissions from the internal queue */
69 while (!IsListEmpty(&Adapter->SendQueueList))
70 {
71 Entry = RemoveHeadList(&Adapter->SendQueueList);
72
73 InsertTailList(&DoneList, Entry);
74 }
75
76 NdisReleaseSpinLock(&Adapter->SendLock);
77
78 while (!IsListEmpty(&DoneList))
79 {
80 Entry = RemoveHeadList(&DoneList);
81
82 NdisMSendComplete(Adapter->AdapterHandle,
83 DC_PACKET_FROM_LIST_ENTRY(Entry),
84 NDIS_STATUS_FAILURE);
85 }
86 }
87
88 static
89 VOID
DcStopReceivePath(_In_ PDC21X4_ADAPTER Adapter)90 DcStopReceivePath(
91 _In_ PDC21X4_ADAPTER Adapter)
92 {
93 BOOLEAN RxStopped;
94
95 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
96
97 #if DBG
98 NdisAcquireSpinLock(&Adapter->ReceiveLock);
99 if (Adapter->RcbFree != Adapter->RcbCount)
100 {
101 INFO("RX packets: %u/%u\n", Adapter->RcbFree, Adapter->RcbCount);
102 }
103 NdisReleaseSpinLock(&Adapter->ReceiveLock);
104 #endif
105
106 while (TRUE)
107 {
108 NdisAcquireSpinLock(&Adapter->ReceiveLock);
109
110 RxStopped = (Adapter->RcbFree == Adapter->RcbCount);
111
112 NdisReleaseSpinLock(&Adapter->ReceiveLock);
113
114 if (RxStopped)
115 break;
116
117 NdisMSleep(10);
118 }
119 }
120
121 DECLSPEC_NOINLINE /* Called from pageable code */
122 VOID
DcStopAdapter(_In_ PDC21X4_ADAPTER Adapter,_In_ BOOLEAN WaitForPackets)123 DcStopAdapter(
124 _In_ PDC21X4_ADAPTER Adapter,
125 _In_ BOOLEAN WaitForPackets)
126 {
127 BOOLEAN TimerCancelled;
128
129 /* Attempt to disable interrupts to complete more quickly */
130 DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
131
132 /* Prevent DPCs from executing and stop accepting incoming packets */
133 NdisAcquireSpinLock(&Adapter->SendLock);
134 Adapter->Flags &= ~DC_ACTIVE;
135 NdisReleaseSpinLock(&Adapter->SendLock);
136
137 NdisMCancelTimer(&Adapter->MediaMonitorTimer, &TimerCancelled);
138
139 /* Wait for any DPCs to complete */
140 KeFlushQueuedDpcs();
141
142 /* Disable interrupts */
143 DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
144
145 /* Wait for completion of TX/RX and stop the DMA engine inside the NIC */
146 DcStopTxRxProcess(Adapter);
147 Adapter->OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
148
149 DcFlushTransmitQueue(Adapter);
150
151 /* Wait for the packets to be returned to the driver */
152 if (WaitForPackets)
153 {
154 DcStopReceivePath(Adapter);
155 }
156
157 /* Make sure there is no pending OID request */
158 if (Adapter->OidPending)
159 {
160 NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
161
162 Adapter->OidPending = FALSE;
163 }
164 }
165
166 CODE_SEG("PAGE")
167 VOID
DcStartAdapter(_In_ PDC21X4_ADAPTER Adapter)168 DcStartAdapter(
169 _In_ PDC21X4_ADAPTER Adapter)
170 {
171 PAGED_CODE();
172
173 /* Enable interrupts */
174 _InterlockedExchange((PLONG)&Adapter->CurrentInterruptMask, Adapter->InterruptMask);
175 DC_WRITE(Adapter, DcCsr7_IrqMask, Adapter->InterruptMask);
176
177 Adapter->Flags |= DC_ACTIVE;
178
179 /* Start the RX process */
180 Adapter->OpMode |= DC_OPMODE_RX_ENABLE;
181 DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
182
183 /* Start the media monitor, wait the selected media to become ready */
184 NdisMSetTimer(&Adapter->MediaMonitorTimer, 2400);
185 }
186
187 CODE_SEG("PAGE")
188 VOID
189 NTAPI
DcResetWorker(_In_ PNDIS_WORK_ITEM WorkItem,_In_opt_ PVOID Context)190 DcResetWorker(
191 _In_ PNDIS_WORK_ITEM WorkItem,
192 _In_opt_ PVOID Context)
193 {
194 PDC21X4_ADAPTER Adapter = Context;
195 NDIS_STATUS Status;
196 ULONG InterruptStatus;
197 LONG ResetReason;
198
199 UNREFERENCED_PARAMETER(WorkItem);
200
201 PAGED_CODE();
202
203 Status = NDIS_STATUS_SUCCESS;
204
205 /* Check if the device is present */
206 InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
207 if (InterruptStatus == 0xFFFFFFFF)
208 {
209 ERR("Hardware is gone...\n");
210
211 /* Remove this adapter */
212 NdisMRemoveMiniport(Adapter->AdapterHandle);
213
214 Status = NDIS_STATUS_HARD_ERRORS;
215 goto Done;
216 }
217
218 DcStopAdapter(Adapter, FALSE);
219
220 if (Adapter->LinkUp)
221 {
222 Adapter->LinkUp = FALSE;
223
224 NdisMIndicateStatus(Adapter->AdapterHandle,
225 NDIS_STATUS_MEDIA_DISCONNECT,
226 NULL,
227 0);
228 NdisMIndicateStatusComplete(Adapter->AdapterHandle);
229 }
230
231 DcSetupAdapter(Adapter);
232
233 DcStartAdapter(Adapter);
234
235 Done:
236 ResetReason = _InterlockedExchange(&Adapter->ResetLock, 0);
237
238 /* Complete the pending reset request */
239 if (ResetReason == 1)
240 {
241 NdisMResetComplete(Adapter->AdapterHandle, Status, FALSE);
242 }
243 }
244
245 VOID
246 NTAPI
DcTransmitTimeoutRecoveryWorker(_In_ PNDIS_WORK_ITEM WorkItem,_In_opt_ PVOID Context)247 DcTransmitTimeoutRecoveryWorker(
248 _In_ PNDIS_WORK_ITEM WorkItem,
249 _In_opt_ PVOID Context)
250 {
251 PDC21X4_ADAPTER Adapter = Context;
252
253 UNREFERENCED_PARAMETER(WorkItem);
254
255 NdisAcquireSpinLock(&Adapter->ModeLock);
256
257 DcStopTxRxProcess(Adapter);
258 DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
259
260 NdisDprAcquireSpinLock(&Adapter->SendLock);
261
262 DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
263
264 NdisDprReleaseSpinLock(&Adapter->SendLock);
265
266 NdisReleaseSpinLock(&Adapter->ModeLock);
267 }
268
269 static
270 BOOLEAN
271 NTAPI
DcCheckForHang(_In_ NDIS_HANDLE MiniportAdapterContext)272 DcCheckForHang(
273 _In_ NDIS_HANDLE MiniportAdapterContext)
274 {
275 PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
276 ULONG TcbCompleted;
277 BOOLEAN TxHang = FALSE;
278
279 if (!(Adapter->Flags & DC_ACTIVE))
280 return FALSE;
281
282 NdisDprAcquireSpinLock(&Adapter->SendLock);
283
284 if (Adapter->TcbSlots != (DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE))
285 {
286 TcbCompleted = Adapter->TcbCompleted;
287 TxHang = (TcbCompleted == Adapter->LastTcbCompleted);
288 Adapter->LastTcbCompleted = TcbCompleted;
289 }
290
291 NdisDprReleaseSpinLock(&Adapter->SendLock);
292
293 if (TxHang)
294 {
295 WARN("Transmit timeout, CSR12 %08lx, CSR5 %08lx\n",
296 DC_READ(Adapter, DcCsr12_SiaStatus),
297 DC_READ(Adapter, DcCsr5_Status));
298
299 NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem);
300 }
301
302 return FALSE;
303 }
304
305 static
306 NDIS_STATUS
307 NTAPI
DcReset(_Out_ PBOOLEAN AddressingReset,_In_ NDIS_HANDLE MiniportAdapterContext)308 DcReset(
309 _Out_ PBOOLEAN AddressingReset,
310 _In_ NDIS_HANDLE MiniportAdapterContext)
311 {
312 PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
313
314 WARN("Called\n");
315
316 if (_InterlockedCompareExchange(&Adapter->ResetLock, 1, 0))
317 {
318 return NDIS_STATUS_RESET_IN_PROGRESS;
319 }
320
321 NdisScheduleWorkItem(&Adapter->ResetWorkItem);
322
323 return NDIS_STATUS_PENDING;
324 }
325
326 static
327 CODE_SEG("PAGE")
328 VOID
329 NTAPI
DcHalt(_In_ NDIS_HANDLE MiniportAdapterContext)330 DcHalt(
331 _In_ NDIS_HANDLE MiniportAdapterContext)
332 {
333 PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
334
335 PAGED_CODE();
336
337 INFO("Called\n");
338
339 DcStopAdapter(Adapter, TRUE);
340
341 DcDisableHw(Adapter);
342
343 DcFreeAdapter(Adapter);
344 }
345
346 static
347 VOID
348 NTAPI
DcShutdown(_In_ NDIS_HANDLE MiniportAdapterContext)349 DcShutdown(
350 _In_ NDIS_HANDLE MiniportAdapterContext)
351 {
352 PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
353
354 INFO("Called\n");
355
356 DcDisableHw(Adapter);
357 }
358
359 CODE_SEG("INIT")
360 NTSTATUS
361 NTAPI
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath)362 DriverEntry(
363 _In_ PDRIVER_OBJECT DriverObject,
364 _In_ PUNICODE_STRING RegistryPath)
365 {
366 NDIS_HANDLE WrapperHandle;
367 NDIS_STATUS Status;
368 NDIS_MINIPORT_CHARACTERISTICS Characteristics = { 0 };
369
370 INFO("Called\n");
371
372 NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);
373 if (!WrapperHandle)
374 return NDIS_STATUS_FAILURE;
375
376 Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
377 Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
378 Characteristics.CheckForHangHandler = DcCheckForHang;
379 Characteristics.HaltHandler = DcHalt;
380 Characteristics.HandleInterruptHandler = DcHandleInterrupt;
381 Characteristics.InitializeHandler = DcInitialize;
382 Characteristics.ISRHandler = DcIsr;
383 Characteristics.QueryInformationHandler = DcQueryInformation;
384 Characteristics.ResetHandler = DcReset;
385 Characteristics.SetInformationHandler = DcSetInformation;
386 Characteristics.ReturnPacketHandler = DcReturnPacket;
387 Characteristics.SendPacketsHandler = DcSendPackets;
388 Characteristics.CancelSendPacketsHandler = DcCancelSendPackets;
389 Characteristics.AdapterShutdownHandler = DcShutdown;
390
391 Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
392 if (Status != NDIS_STATUS_SUCCESS)
393 {
394 NdisTerminateWrapper(WrapperHandle, NULL);
395 return Status;
396 }
397
398 InitializeListHead(&SRompAdapterList);
399
400 return NDIS_STATUS_SUCCESS;
401 }
402