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