xref: /reactos/drivers/network/dd/nvnet/init.c (revision f308c6a2)
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 initialization helper routines
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 /* FUNCTIONS ******************************************************************/
16 
17 static
18 CODE_SEG("PAGE")
19 VOID
20 QueryInteger(
21     _In_ NDIS_HANDLE ConfigurationHandle,
22     _In_ PCWSTR EntryName,
23     _Out_ PULONG EntryContext,
24     _In_ ULONG DefaultValue,
25     _In_ ULONG Minimum,
26     _In_ ULONG Maximum)
27 {
28     NDIS_STATUS Status;
29     UNICODE_STRING Keyword;
30     PNDIS_CONFIGURATION_PARAMETER ConfigurationParameter;
31 
32     PAGED_CODE();
33 
34     NdisInitUnicodeString(&Keyword, EntryName);
35     NdisReadConfiguration(&Status,
36                           &ConfigurationParameter,
37                           ConfigurationHandle,
38                           &Keyword,
39                           NdisParameterInteger);
40     if (Status != NDIS_STATUS_SUCCESS)
41     {
42         NDIS_DbgPrint(MIN_TRACE, ("'%S' request failed\n", EntryName));
43 
44         *EntryContext = DefaultValue;
45     }
46     else
47     {
48         if (ConfigurationParameter->ParameterData.IntegerData >= Minimum &&
49             ConfigurationParameter->ParameterData.IntegerData <= Maximum)
50         {
51             *EntryContext = ConfigurationParameter->ParameterData.IntegerData;
52         }
53         else
54         {
55             NDIS_DbgPrint(MAX_TRACE, ("'%S' value out of range\n", EntryName));
56 
57             *EntryContext = DefaultValue;
58         }
59     }
60 
61     NDIS_DbgPrint(MIN_TRACE, ("Set '%S' to %d\n", EntryName, *EntryContext));
62 }
63 
64 static
65 CODE_SEG("PAGE")
66 NDIS_STATUS
67 NvNetReadConfiguration(
68     _Inout_ PNVNET_ADAPTER Adapter)
69 {
70     NDIS_STATUS Status;
71     NDIS_HANDLE ConfigurationHandle;
72     PUCHAR NetworkAddress;
73     UINT Length;
74     ULONG GenericUlong;
75 
76     PAGED_CODE();
77 
78     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
79 
80     NdisOpenConfiguration(&Status,
81                           &ConfigurationHandle,
82                           Adapter->WrapperConfigurationHandle);
83     if (Status != NDIS_STATUS_SUCCESS)
84         return Status;
85 
86     QueryInteger(ConfigurationHandle,
87                  L"OptimizationMode",
88                  &GenericUlong,
89                  NV_OPTIMIZATION_MODE_DYNAMIC,
90                  NV_OPTIMIZATION_MODE_THROUGHPUT,
91                  NV_OPTIMIZATION_MODE_DYNAMIC);
92     Adapter->OptimizationMode = GenericUlong;
93 
94     QueryInteger(ConfigurationHandle,
95                  L"FlowControl",
96                  &GenericUlong,
97                  NV_FLOW_CONTROL_AUTO,
98                  NV_FLOW_CONTROL_DISABLE,
99                  NV_FLOW_CONTROL_RX_TX);
100     Adapter->FlowControlMode = GenericUlong;
101 
102     QueryInteger(ConfigurationHandle,
103                  L"SpeedDuplex",
104                  &GenericUlong,
105                  0,
106                  0,
107                  4);
108     switch (GenericUlong)
109     {
110         case 1:
111             Adapter->Flags |= NV_FORCE_SPEED_AND_DUPLEX;
112             break;
113         case 2:
114             Adapter->Flags |= (NV_FORCE_SPEED_AND_DUPLEX | NV_FORCE_FULL_DUPLEX);
115             break;
116         case 3:
117             Adapter->Flags |= (NV_FORCE_SPEED_AND_DUPLEX | NV_USER_SPEED_100);
118             break;
119         case 4:
120             Adapter->Flags |= (NV_FORCE_SPEED_AND_DUPLEX | NV_FORCE_FULL_DUPLEX |
121                                NV_USER_SPEED_100);
122             break;
123 
124         default:
125             break;
126     }
127 
128     QueryInteger(ConfigurationHandle,
129                  L"ChecksumOffload",
130                  &GenericUlong,
131                  0,
132                  0,
133                  1);
134     if (GenericUlong)
135         Adapter->Flags |= NV_SEND_CHECKSUM;
136 
137     QueryInteger(ConfigurationHandle,
138                  L"LargeSendOffload",
139                  &GenericUlong,
140                  0,
141                  0,
142                  1);
143     if (GenericUlong)
144         Adapter->Flags |= NV_SEND_LARGE_SEND;
145 
146     QueryInteger(ConfigurationHandle,
147                  L"JumboSize",
148                  &GenericUlong,
149                  NVNET_MAXIMUM_FRAME_SIZE,
150                  NVNET_MAXIMUM_FRAME_SIZE,
151                  NVNET_MAXIMUM_FRAME_SIZE_JUMBO);
152     Adapter->MaximumFrameSize = GenericUlong;
153 
154     QueryInteger(ConfigurationHandle,
155                  L"Priority",
156                  &GenericUlong,
157                  0,
158                  0,
159                  1);
160     if (GenericUlong)
161         Adapter->Flags |= NV_PACKET_PRIORITY;
162 
163     QueryInteger(ConfigurationHandle,
164                  L"VlanTag",
165                  &GenericUlong,
166                  0,
167                  0,
168                  1);
169     if (GenericUlong)
170         Adapter->Flags |= NV_VLAN_TAGGING;
171 
172     QueryInteger(ConfigurationHandle,
173                  L"VlanID",
174                  &GenericUlong,
175                  0,
176                  0,
177                  NVNET_MAXIMUM_VLAN_ID);
178 
179     NdisReadNetworkAddress(&Status,
180                            (PVOID*)&NetworkAddress,
181                            &Length,
182                            ConfigurationHandle);
183     if ((Status == NDIS_STATUS_SUCCESS) && (Length == ETH_LENGTH_OF_ADDRESS))
184     {
185         if ((ETH_IS_MULTICAST(NetworkAddress) || ETH_IS_BROADCAST(NetworkAddress)) ||
186             !ETH_IS_LOCALLY_ADMINISTERED(NetworkAddress))
187         {
188             NDIS_DbgPrint(MAX_TRACE, ("Invalid software MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
189                                       NetworkAddress[0],
190                                       NetworkAddress[1],
191                                       NetworkAddress[2],
192                                       NetworkAddress[3],
193                                       NetworkAddress[4],
194                                       NetworkAddress[5]));
195         }
196         else
197         {
198             NDIS_DbgPrint(MIN_TRACE, ("Using software MAC\n"));
199 
200             ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentMacAddress, NetworkAddress);
201 
202             Adapter->Flags |= NV_USE_SOFT_MAC_ADDRESS;
203         }
204     }
205     Status = NDIS_STATUS_SUCCESS;
206 
207     NdisCloseConfiguration(ConfigurationHandle);
208 
209     return Status;
210 }
211 
212 static
213 CODE_SEG("PAGE")
214 NDIS_STATUS
215 NvNetInitializeAdapterResources(
216     _Inout_ PNVNET_ADAPTER Adapter)
217 {
218     NDIS_STATUS Status;
219     PNDIS_RESOURCE_LIST AssignedResources = NULL;
220     UINT i, ResourceListSize = 0;
221 
222     PAGED_CODE();
223 
224     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
225 
226     NdisMQueryAdapterResources(&Status,
227                                Adapter->WrapperConfigurationHandle,
228                                AssignedResources,
229                                &ResourceListSize);
230     if (Status != NDIS_STATUS_RESOURCES)
231     {
232         NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
233         return NDIS_STATUS_FAILURE;
234     }
235 
236     Status = NdisAllocateMemoryWithTag((PVOID*)&AssignedResources,
237                                        ResourceListSize,
238                                        NVNET_TAG);
239     if (Status != NDIS_STATUS_SUCCESS)
240     {
241         NvNetLogError(Adapter, NDIS_ERROR_CODE_OUT_OF_RESOURCES);
242         return Status;
243     }
244 
245     NdisMQueryAdapterResources(&Status,
246                                Adapter->WrapperConfigurationHandle,
247                                AssignedResources,
248                                &ResourceListSize);
249     if (Status != NDIS_STATUS_SUCCESS)
250     {
251         NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
252         goto Cleanup;
253     }
254 
255     for (i = 0; i < AssignedResources->Count; ++i)
256     {
257         PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &AssignedResources->PartialDescriptors[i];
258 
259         switch (Descriptor->Type)
260         {
261             case CmResourceTypeMemory:
262             {
263                 Adapter->IoAddress = Descriptor->u.Memory.Start;
264                 Adapter->IoLength = Descriptor->u.Memory.Length;
265                 break;
266             }
267 
268             case CmResourceTypeInterrupt:
269             {
270                 Adapter->InterruptVector = Descriptor->u.Interrupt.Vector;
271                 Adapter->InterruptLevel = Descriptor->u.Interrupt.Level;
272                 Adapter->InterruptShared = (Descriptor->ShareDisposition == CmResourceShareShared);
273                 Adapter->InterruptFlags = Descriptor->Flags;
274                 break;
275             }
276 
277             default:
278                 break;
279         }
280     }
281 
282     if (!Adapter->IoAddress.QuadPart || !Adapter->InterruptVector)
283     {
284         Status = NDIS_STATUS_RESOURCES;
285         NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
286         goto Cleanup;
287     }
288 
289     NDIS_DbgPrint(MIN_TRACE, ("MEM at [%I64X-%I64X]\n",
290                               Adapter->IoAddress.QuadPart,
291                               Adapter->IoAddress.QuadPart + Adapter->IoLength));
292     NDIS_DbgPrint(MIN_TRACE, ("IRQ Vector %d Level %d\n",
293                               Adapter->InterruptVector,
294                               Adapter->InterruptLevel));
295 
296     Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase,
297                              Adapter->AdapterHandle,
298                              Adapter->IoAddress,
299                              Adapter->IoLength);
300     if (Status != NDIS_STATUS_SUCCESS)
301     {
302         NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
303         goto Cleanup;
304     }
305 
306 Cleanup:
307     NdisFreeMemory(AssignedResources, ResourceListSize, 0);
308 
309     return Status;
310 }
311 
312 static
313 CODE_SEG("PAGE")
314 NDIS_STATUS
315 AllocateTransmitBuffers(
316     _In_ PNVNET_ADAPTER Adapter)
317 {
318     ULONG i;
319     BOOLEAN HasBuffer = FALSE;
320     PNVNET_TX_BUFFER CoalesceBuffer;
321     NDIS_STATUS Status;
322 
323     PAGED_CODE();
324 
325     Status = NdisAllocateMemoryWithTag((PVOID*)&CoalesceBuffer,
326                                        NVNET_TRANSMIT_BUFFERS * sizeof(NVNET_TX_BUFFER),
327                                        NVNET_TAG);
328     if (Status != NDIS_STATUS_SUCCESS)
329         return Status;
330 
331     NdisZeroMemory(CoalesceBuffer, NVNET_TRANSMIT_BUFFERS * sizeof(NVNET_TX_BUFFER));
332 
333     Adapter->SendBuffer = CoalesceBuffer;
334 
335     for (i = 0; i < NVNET_TRANSMIT_BUFFERS; ++i)
336     {
337         PVOID VirtualAddress;
338         NDIS_PHYSICAL_ADDRESS PhysicalAddress;
339 
340         NdisMAllocateSharedMemory(Adapter->AdapterHandle,
341                                   Adapter->MaximumFrameSize + NVNET_ALIGNMENT,
342                                   TRUE, /* Cached */
343                                   &VirtualAddress,
344                                   &PhysicalAddress);
345         if (!VirtualAddress)
346             continue;
347 
348         CoalesceBuffer->VirtualAddress = ALIGN_UP_POINTER_BY(VirtualAddress, NVNET_ALIGNMENT);
349         CoalesceBuffer->PhysicalAddress.QuadPart =
350             ALIGN_UP_BY(PhysicalAddress.QuadPart, NVNET_ALIGNMENT);
351 
352         Adapter->SendBufferAllocationData[i].PhysicalAddress.QuadPart = PhysicalAddress.QuadPart;
353         Adapter->SendBufferAllocationData[i].VirtualAddress = VirtualAddress;
354 
355         PushEntryList(&Adapter->Send.BufferList, &CoalesceBuffer->Link);
356         ++CoalesceBuffer;
357 
358         HasBuffer = TRUE;
359     }
360     if (!HasBuffer)
361     {
362         return NDIS_STATUS_RESOURCES;
363     }
364 
365     return NDIS_STATUS_SUCCESS;
366 }
367 
368 static
369 CODE_SEG("PAGE")
370 NDIS_STATUS
371 AllocateTransmitBlocks(
372     _In_ PNVNET_ADAPTER Adapter)
373 {
374     PNVNET_TCB Tcb;
375     NDIS_STATUS Status;
376 
377     PAGED_CODE();
378 
379     Status = NdisAllocateMemoryWithTag((PVOID*)&Tcb,
380                                        NVNET_TRANSMIT_BLOCKS * sizeof(NVNET_TCB),
381                                        NVNET_TAG);
382     if (Status != NDIS_STATUS_SUCCESS)
383         return Status;
384 
385     NdisZeroMemory(Tcb, NVNET_TRANSMIT_BLOCKS * sizeof(NVNET_TCB));
386 
387     Adapter->Send.TailTcb = Tcb + (NVNET_TRANSMIT_BLOCKS - 1);
388     Adapter->Send.HeadTcb = Tcb;
389     Adapter->Send.CurrentTcb = Tcb;
390     Adapter->Send.LastTcb = Tcb;
391 
392     return NDIS_STATUS_SUCCESS;
393 }
394 
395 static
396 CODE_SEG("PAGE")
397 NDIS_STATUS
398 AllocateTransmitDescriptors(
399     _In_ PNVNET_ADAPTER Adapter)
400 {
401     NVNET_TBD Tbd;
402     ULONG Size;
403 
404     PAGED_CODE();
405 
406     if (Adapter->Features & DEV_HAS_HIGH_DMA)
407     {
408         Size = sizeof(NVNET_DESCRIPTOR_64);
409     }
410     else
411     {
412         Size = sizeof(NVNET_DESCRIPTOR_32);
413     }
414     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
415                               Size * NVNET_TRANSMIT_DESCRIPTORS + NVNET_ALIGNMENT,
416                               TRUE, /* Cached */
417                               &Adapter->TbdOriginal,
418                               &Adapter->TbdPhysOriginal);
419     if (!Adapter->TbdOriginal)
420         return NDIS_STATUS_RESOURCES;
421 
422     Tbd.Memory = ALIGN_UP_POINTER_BY(Adapter->TbdOriginal, NVNET_ALIGNMENT);
423     Adapter->TbdPhys.QuadPart = ALIGN_UP_BY(Adapter->TbdPhysOriginal.QuadPart, NVNET_ALIGNMENT);
424 
425     Adapter->Send.HeadTbd = Tbd;
426     Adapter->Send.CurrentTbd = Tbd;
427 
428     if (Adapter->Features & DEV_HAS_HIGH_DMA)
429     {
430         Adapter->Send.TailTbd.x64 = Tbd.x64 + (NVNET_TRANSMIT_DESCRIPTORS - 1);
431     }
432     else
433     {
434         Adapter->Send.TailTbd.x32 = Tbd.x32 + (NVNET_TRANSMIT_DESCRIPTORS - 1);
435     }
436 
437     return NDIS_STATUS_SUCCESS;
438 }
439 
440 static
441 CODE_SEG("PAGE")
442 NDIS_STATUS
443 AllocateReceiveDescriptors(
444     _In_ PNVNET_ADAPTER Adapter)
445 {
446     ULONG Size;
447 
448     PAGED_CODE();
449 
450     if (Adapter->Features & DEV_HAS_HIGH_DMA)
451     {
452         Size = sizeof(NVNET_DESCRIPTOR_64);
453     }
454     else
455     {
456         Size = sizeof(NVNET_DESCRIPTOR_32);
457     }
458     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
459                               Size * NVNET_RECEIVE_DESCRIPTORS + NVNET_ALIGNMENT,
460                               TRUE, /* Cached */
461                               &Adapter->RbdOriginal,
462                               &Adapter->RbdPhysOriginal);
463     if (!Adapter->RbdOriginal)
464         return NDIS_STATUS_RESOURCES;
465 
466     Adapter->Receive.NvRbd.Memory = ALIGN_UP_POINTER_BY(Adapter->RbdOriginal, NVNET_ALIGNMENT);
467     Adapter->RbdPhys.QuadPart = ALIGN_UP_BY(Adapter->RbdPhysOriginal.QuadPart, NVNET_ALIGNMENT);
468 
469     return NDIS_STATUS_SUCCESS;
470 }
471 
472 static
473 CODE_SEG("PAGE")
474 NDIS_STATUS
475 AllocateReceiveBuffers(
476     _In_ PNVNET_ADAPTER Adapter)
477 {
478     PAGED_CODE();
479 
480     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
481                               NVNET_RECEIVE_BUFFER_SIZE * NVNET_RECEIVE_DESCRIPTORS,
482                               TRUE, /* Cached */
483                               (PVOID*)&Adapter->ReceiveBuffer,
484                               &Adapter->ReceiveBufferPhys);
485     if (!Adapter->ReceiveBuffer)
486     {
487         return NDIS_STATUS_RESOURCES;
488     }
489 
490     return NDIS_STATUS_SUCCESS;
491 }
492 
493 static
494 CODE_SEG("PAGE")
495 NDIS_STATUS
496 AllocateAdapterMemory(
497     _In_ PNVNET_ADAPTER Adapter)
498 {
499     NDIS_STATUS Status;
500 
501     PAGED_CODE();
502 
503     Status = AllocateTransmitBuffers(Adapter);
504     if (Status != NDIS_STATUS_SUCCESS)
505         return Status;
506 
507     Status = AllocateTransmitBlocks(Adapter);
508     if (Status != NDIS_STATUS_SUCCESS)
509         return Status;
510 
511     Status = AllocateTransmitDescriptors(Adapter);
512     if (Status != NDIS_STATUS_SUCCESS)
513         return Status;
514 
515     Status = AllocateReceiveDescriptors(Adapter);
516     if (Status != NDIS_STATUS_SUCCESS)
517         return Status;
518 
519     Status = AllocateReceiveBuffers(Adapter);
520     if (Status != NDIS_STATUS_SUCCESS)
521         return Status;
522 
523     NdisAllocateSpinLock(&Adapter->Send.Lock);
524     NdisAllocateSpinLock(&Adapter->Receive.Lock);
525     NdisAllocateSpinLock(&Adapter->Lock);
526 
527     return NDIS_STATUS_SUCCESS;
528 }
529 
530 CODE_SEG("PAGE")
531 VOID
532 NvNetInitTransmitMemory(
533     _In_ PNVNET_ADAPTER Adapter)
534 {
535     PAGED_CODE();
536 
537     Adapter->Send.TcbSlots = NVNET_TRANSMIT_BLOCKS;
538     Adapter->Send.TbdSlots = NVNET_TRANSMIT_DESCRIPTORS;
539 
540     if (Adapter->Features & DEV_HAS_HIGH_DMA)
541     {
542         NdisZeroMemory(Adapter->Send.HeadTbd.x64,
543                        sizeof(NVNET_DESCRIPTOR_64) * NVNET_TRANSMIT_DESCRIPTORS);
544     }
545     else
546     {
547         NdisZeroMemory(Adapter->Send.HeadTbd.x32,
548                        sizeof(NVNET_DESCRIPTOR_32) * NVNET_TRANSMIT_DESCRIPTORS);
549     }
550 }
551 
552 static
553 CODE_SEG("PAGE")
554 VOID
555 NvNetInitReceiveMemory(
556     _In_ PNVNET_ADAPTER Adapter)
557 {
558     NV_RBD NvRbd;
559     ULONG i;
560 
561     PAGED_CODE();
562 
563     Adapter->CurrentRx = 0;
564 
565     if (Adapter->Features & DEV_HAS_HIGH_DMA)
566     {
567         for (i = 0; i < NVNET_RECEIVE_DESCRIPTORS; ++i)
568         {
569             NvRbd.x64 = &Adapter->Receive.NvRbd.x64[i];
570 
571             NvRbd.x64->AddressHigh = NdisGetPhysicalAddressHigh(Adapter->ReceiveBufferPhys)
572                                      + i * NVNET_RECEIVE_BUFFER_SIZE;
573             NvRbd.x64->AddressLow = NdisGetPhysicalAddressLow(Adapter->ReceiveBufferPhys)
574                                     + i * NVNET_RECEIVE_BUFFER_SIZE;
575             NvRbd.x64->VlanTag = 0;
576             NvRbd.x64->FlagsLength = NV_RX2_AVAIL | NVNET_RECEIVE_BUFFER_SIZE;
577         }
578     }
579     else
580     {
581         for (i = 0; i < NVNET_RECEIVE_DESCRIPTORS; ++i)
582         {
583             NvRbd.x32 = &Adapter->Receive.NvRbd.x32[i];
584 
585             NvRbd.x32->Address = NdisGetPhysicalAddressLow(Adapter->ReceiveBufferPhys)
586                                  + i * NVNET_RECEIVE_BUFFER_SIZE;
587             NvRbd.x32->FlagsLength = NV_RX_AVAIL | NVNET_RECEIVE_BUFFER_SIZE;
588         }
589     }
590 }
591 
592 
593 CODE_SEG("PAGE")
594 VOID
595 NvNetFreeAdapter(
596     _In_ PNVNET_ADAPTER Adapter)
597 {
598     ULONG i;
599     ULONG DescriptorSize;
600 
601     PAGED_CODE();
602 
603     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
604 
605     for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i)
606     {
607         PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
608 
609         if (!WakeFrame)
610             continue;
611 
612         NdisFreeMemory(WakeFrame, sizeof(*WakeFrame), 0);
613     }
614 
615     if (Adapter->Interrupt.InterruptObject)
616     {
617         NdisMDeregisterInterrupt(&Adapter->Interrupt);
618         Adapter->Interrupt.InterruptObject = NULL;
619     }
620 
621     if (Adapter->Features & DEV_HAS_HIGH_DMA)
622     {
623         DescriptorSize = sizeof(NVNET_DESCRIPTOR_64);
624     }
625     else
626     {
627         DescriptorSize = sizeof(NVNET_DESCRIPTOR_32);
628     }
629     if (Adapter->TbdOriginal)
630     {
631         NdisMFreeSharedMemory(Adapter->AdapterHandle,
632                               DescriptorSize * NVNET_TRANSMIT_DESCRIPTORS,
633                               FALSE,
634                               Adapter->TbdOriginal,
635                               Adapter->TbdPhysOriginal);
636         Adapter->TbdOriginal = NULL;
637     }
638     if (Adapter->RbdOriginal)
639     {
640         NdisMFreeSharedMemory(Adapter->AdapterHandle,
641                               DescriptorSize * NVNET_RECEIVE_DESCRIPTORS,
642                               FALSE,
643                               Adapter->RbdOriginal,
644                               Adapter->RbdPhysOriginal);
645         Adapter->RbdOriginal = NULL;
646     }
647     if (Adapter->SendBuffer)
648     {
649         ULONG Length = ALIGN_UP_BY(Adapter->MaximumFrameSize, NVNET_ALIGNMENT);
650 
651         for (i = 0; i < NVNET_TRANSMIT_BUFFERS; ++i)
652         {
653             PNVNET_TX_BUFFER_DATA SendBufferData = &Adapter->SendBufferAllocationData[i];
654 
655             if (!SendBufferData->VirtualAddress)
656                 continue;
657 
658             NdisMFreeSharedMemory(Adapter->AdapterHandle,
659                                   Length,
660                                   TRUE,
661                                   SendBufferData->VirtualAddress,
662                                   SendBufferData->PhysicalAddress);
663         }
664 
665         NdisFreeMemory(Adapter->SendBuffer, NVNET_TRANSMIT_BUFFERS * sizeof(NVNET_TX_BUFFER), 0);
666         Adapter->SendBuffer = NULL;
667     }
668 
669     if (Adapter->ReceiveBuffer)
670     {
671         NdisMFreeSharedMemory(Adapter->AdapterHandle,
672                               NVNET_RECEIVE_BUFFER_SIZE * NVNET_RECEIVE_DESCRIPTORS,
673                               FALSE,
674                               Adapter->ReceiveBuffer,
675                               Adapter->ReceiveBufferPhys);
676         Adapter->ReceiveBuffer = NULL;
677     }
678 
679     if (Adapter->IoBase)
680     {
681         NdisMUnmapIoSpace(Adapter->AdapterHandle,
682                           Adapter->IoBase,
683                           Adapter->IoLength);
684         Adapter->IoBase = NULL;
685     }
686 
687     if (Adapter->Lock.SpinLock)
688         NdisFreeSpinLock(&Adapter->Lock);
689     if (Adapter->Send.Lock.SpinLock)
690         NdisFreeSpinLock(&Adapter->Send.Lock);
691     if (Adapter->Receive.Lock.SpinLock)
692         NdisFreeSpinLock(&Adapter->Receive.Lock);
693 
694     NdisFreeMemory(Adapter->AdapterOriginal, sizeof(NVNET_ADAPTER), 0);
695 }
696 
697 CODE_SEG("PAGE")
698 NDIS_STATUS
699 NTAPI
700 MiniportInitialize(
701     _Out_ PNDIS_STATUS OpenErrorStatus,
702     _Out_ PUINT SelectedMediumIndex,
703     _In_ PNDIS_MEDIUM MediumArray,
704     _In_ UINT MediumArraySize,
705     _In_ NDIS_HANDLE MiniportAdapterHandle,
706     _In_ NDIS_HANDLE WrapperConfigurationContext)
707 {
708     UINT i;
709     ULONG Size;
710     PVOID UnalignedAdapter;
711     PNVNET_ADAPTER Adapter;
712     NDIS_STATUS Status;
713 
714     PAGED_CODE();
715 
716     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
717 
718     for (i = 0; i < MediumArraySize; ++i)
719     {
720         if (MediumArray[i] == NdisMedium802_3)
721         {
722             *SelectedMediumIndex = i;
723             break;
724         }
725     }
726     if (i == MediumArraySize)
727     {
728         NDIS_DbgPrint(MAX_TRACE, ("No supported media\n"));
729         return NDIS_STATUS_UNSUPPORTED_MEDIA;
730     }
731 
732     Size = sizeof(NVNET_ADAPTER) + NdisGetSharedDataAlignment();
733 
734     Status = NdisAllocateMemoryWithTag((PVOID*)&UnalignedAdapter,
735                                        Size,
736                                        NVNET_TAG);
737     if (Status != NDIS_STATUS_SUCCESS)
738     {
739         NDIS_DbgPrint(MAX_TRACE, ("Failed to allocate adapter\n"));
740         return NDIS_STATUS_RESOURCES;
741     }
742 
743     NdisZeroMemory(UnalignedAdapter, Size);
744     Adapter = ALIGN_UP_POINTER_BY(UnalignedAdapter, NdisGetSharedDataAlignment());
745     Adapter->AdapterOriginal = UnalignedAdapter;
746     Adapter->AdapterHandle = MiniportAdapterHandle;
747     Adapter->WrapperConfigurationHandle = WrapperConfigurationContext;
748 
749     Status = NvNetReadConfiguration(Adapter);
750     if (Status != NDIS_STATUS_SUCCESS)
751     {
752         goto Failure;
753     }
754 
755     NdisMSetAttributesEx(MiniportAdapterHandle,
756                          Adapter,
757                          0,
758                          NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS |
759                          // NDIS_ATTRIBUTE_DESERIALIZE |  TODO
760                          NDIS_ATTRIBUTE_BUS_MASTER,
761                          NdisInterfacePci);
762 
763     Status = NvNetRecognizeHardware(Adapter);
764     if (Status != NDIS_STATUS_SUCCESS)
765     {
766         if (Status == NDIS_STATUS_ADAPTER_NOT_FOUND)
767         {
768             NvNetLogError(Adapter, NDIS_ERROR_CODE_ADAPTER_NOT_FOUND);
769         }
770         else if (Status == NDIS_STATUS_NOT_RECOGNIZED)
771         {
772             NvNetLogError(Adapter, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION);
773         }
774 
775         goto Failure;
776     }
777 
778     Status = NvNetInitializeAdapterResources(Adapter);
779     if (Status != NDIS_STATUS_SUCCESS)
780     {
781         goto Failure;
782     }
783 
784     Status = NdisMInitializeScatterGatherDma(Adapter->AdapterHandle,
785                                              !!(Adapter->Features & DEV_HAS_HIGH_DMA),
786                                              NVNET_MAXIMUM_FRAME_SIZE);
787                                              // ^TODO: NVNET_MAX_DMA_TRANSFER);
788     if (Status != NDIS_STATUS_SUCCESS)
789     {
790         NvNetLogError(Adapter, NDIS_ERROR_CODE_OUT_OF_RESOURCES);
791         goto Failure;
792     }
793 
794     Status = AllocateAdapterMemory(Adapter);
795     if (Status != NDIS_STATUS_SUCCESS)
796     {
797         NDIS_DbgPrint(MAX_TRACE, ("Failed to allocate adapter memory\n"));
798 
799         NvNetLogError(Adapter, NDIS_ERROR_CODE_OUT_OF_RESOURCES);
800         goto Failure;
801     }
802 
803     NvNetInitTransmitMemory(Adapter);
804     NvNetInitReceiveMemory(Adapter);
805 
806     if (Adapter->Features & DEV_HAS_HIGH_DMA)
807     {
808         Adapter->TransmitPacket = NvNetTransmitPacket64;
809         Adapter->ProcessTransmit = ProcessTransmitDescriptors64;
810     }
811     else
812     {
813         Adapter->TransmitPacket = NvNetTransmitPacket32;
814 
815         if (Adapter->Features & DEV_HAS_LARGEDESC)
816         {
817             Adapter->ProcessTransmit = ProcessTransmitDescriptors32;
818         }
819         else
820         {
821             Adapter->ProcessTransmit = ProcessTransmitDescriptorsLegacy;
822         }
823     }
824 
825     Status = NvNetGetPermanentMacAddress(Adapter, Adapter->PermanentMacAddress);
826     if (Status != NDIS_STATUS_SUCCESS)
827     {
828         NvNetLogError(Adapter, NDIS_ERROR_CODE_NETWORK_ADDRESS);
829         goto Failure;
830     }
831 
832     if (!(Adapter->Flags & NV_USE_SOFT_MAC_ADDRESS))
833     {
834         ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentMacAddress,
835                                  Adapter->PermanentMacAddress);
836     }
837 
838     NvNetSetupMacAddress(Adapter, Adapter->CurrentMacAddress);
839 
840     Status = NvNetInitNIC(Adapter, TRUE);
841     if (Status != NDIS_STATUS_SUCCESS)
842     {
843         NDIS_DbgPrint(MAX_TRACE, ("Failed to initialize the NIC\n"));
844 
845         NvNetLogError(Adapter, NDIS_ERROR_CODE_HARDWARE_FAILURE);
846         goto Failure;
847     }
848 
849     NvNetDisableInterrupts(Adapter);
850     NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_ALL);
851     NV_WRITE(Adapter, NvRegIrqStatus, NVREG_IRQSTAT_MASK);
852 
853 /* FIXME: Bug in the PIC HAL? */
854 #if defined(SARCH_XBOX)
855     Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
856                                     Adapter->AdapterHandle,
857                                     Adapter->InterruptVector,
858                                     Adapter->InterruptLevel,
859                                     TRUE, /* Request ISR calls */
860                                     FALSE,
861                                     NdisInterruptLatched);
862 #else
863     Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
864                                     Adapter->AdapterHandle,
865                                     Adapter->InterruptVector,
866                                     Adapter->InterruptLevel,
867                                     TRUE, /* Request ISR calls */
868                                     TRUE, /* Shared */
869                                     NdisInterruptLevelSensitive);
870 #endif
871     if (Status != NDIS_STATUS_SUCCESS)
872     {
873         NvNetLogError(Adapter, NDIS_ERROR_CODE_INTERRUPT_CONNECT);
874         goto Failure;
875     }
876 
877     NvNetStartAdapter(Adapter);
878 
879     return NDIS_STATUS_SUCCESS;
880 
881 Failure:
882     NvNetFreeAdapter(Adapter);
883 
884     return Status;
885 }
886