mirror of
https://github.com/reactos/reactos.git
synced 2024-10-07 18:04:41 +00:00
886 lines
25 KiB
C
886 lines
25 KiB
C
|
/*
|
||
|
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
|
||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||
|
* PURPOSE: Miniport initialization helper routines
|
||
|
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
|
||
|
*/
|
||
|
|
||
|
/* INCLUDES *******************************************************************/
|
||
|
|
||
|
#include "nvnet.h"
|
||
|
|
||
|
#define NDEBUG
|
||
|
#include "debug.h"
|
||
|
|
||
|
/* FUNCTIONS ******************************************************************/
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
VOID
|
||
|
QueryInteger(
|
||
|
_In_ NDIS_HANDLE ConfigurationHandle,
|
||
|
_In_ PCWSTR EntryName,
|
||
|
_Out_ PULONG EntryContext,
|
||
|
_In_ ULONG DefaultValue,
|
||
|
_In_ ULONG Minimum,
|
||
|
_In_ ULONG Maximum)
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
UNICODE_STRING Keyword;
|
||
|
PNDIS_CONFIGURATION_PARAMETER ConfigurationParameter;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
NdisInitUnicodeString(&Keyword, EntryName);
|
||
|
NdisReadConfiguration(&Status,
|
||
|
&ConfigurationParameter,
|
||
|
ConfigurationHandle,
|
||
|
&Keyword,
|
||
|
NdisParameterInteger);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("'%S' request failed\n", EntryName));
|
||
|
|
||
|
*EntryContext = DefaultValue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ConfigurationParameter->ParameterData.IntegerData >= Minimum &&
|
||
|
ConfigurationParameter->ParameterData.IntegerData <= Maximum)
|
||
|
{
|
||
|
*EntryContext = ConfigurationParameter->ParameterData.IntegerData;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NDIS_DbgPrint(MAX_TRACE, ("'%S' value out of range\n", EntryName));
|
||
|
|
||
|
*EntryContext = DefaultValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("Set '%S' to %d\n", EntryName, *EntryContext));
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
NvNetReadConfiguration(
|
||
|
_Inout_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
NDIS_HANDLE ConfigurationHandle;
|
||
|
PUCHAR NetworkAddress;
|
||
|
UINT Length;
|
||
|
ULONG GenericUlong;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
|
||
|
|
||
|
NdisOpenConfiguration(&Status,
|
||
|
&ConfigurationHandle,
|
||
|
Adapter->WrapperConfigurationHandle);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"OptimizationMode",
|
||
|
&GenericUlong,
|
||
|
NV_OPTIMIZATION_MODE_DYNAMIC,
|
||
|
NV_OPTIMIZATION_MODE_THROUGHPUT,
|
||
|
NV_OPTIMIZATION_MODE_DYNAMIC);
|
||
|
Adapter->OptimizationMode = GenericUlong;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"FlowControl",
|
||
|
&GenericUlong,
|
||
|
NV_FLOW_CONTROL_AUTO,
|
||
|
NV_FLOW_CONTROL_DISABLE,
|
||
|
NV_FLOW_CONTROL_RX_TX);
|
||
|
Adapter->FlowControlMode = GenericUlong;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"SpeedDuplex",
|
||
|
&GenericUlong,
|
||
|
0,
|
||
|
0,
|
||
|
4);
|
||
|
switch (GenericUlong)
|
||
|
{
|
||
|
case 1:
|
||
|
Adapter->Flags |= NV_FORCE_SPEED_AND_DUPLEX;
|
||
|
break;
|
||
|
case 2:
|
||
|
Adapter->Flags |= (NV_FORCE_SPEED_AND_DUPLEX | NV_FORCE_FULL_DUPLEX);
|
||
|
break;
|
||
|
case 3:
|
||
|
Adapter->Flags |= (NV_FORCE_SPEED_AND_DUPLEX | NV_USER_SPEED_100);
|
||
|
break;
|
||
|
case 4:
|
||
|
Adapter->Flags |= (NV_FORCE_SPEED_AND_DUPLEX | NV_FORCE_FULL_DUPLEX |
|
||
|
NV_USER_SPEED_100);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"ChecksumOffload",
|
||
|
&GenericUlong,
|
||
|
0,
|
||
|
0,
|
||
|
1);
|
||
|
if (GenericUlong)
|
||
|
Adapter->Flags |= NV_SEND_CHECKSUM;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"LargeSendOffload",
|
||
|
&GenericUlong,
|
||
|
0,
|
||
|
0,
|
||
|
1);
|
||
|
if (GenericUlong)
|
||
|
Adapter->Flags |= NV_SEND_LARGE_SEND;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"JumboSize",
|
||
|
&GenericUlong,
|
||
|
NVNET_MAXIMUM_FRAME_SIZE,
|
||
|
NVNET_MAXIMUM_FRAME_SIZE,
|
||
|
NVNET_MAXIMUM_FRAME_SIZE_JUMBO);
|
||
|
Adapter->MaximumFrameSize = GenericUlong;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"Priority",
|
||
|
&GenericUlong,
|
||
|
0,
|
||
|
0,
|
||
|
1);
|
||
|
if (GenericUlong)
|
||
|
Adapter->Flags |= NV_PACKET_PRIORITY;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"VlanTag",
|
||
|
&GenericUlong,
|
||
|
0,
|
||
|
0,
|
||
|
1);
|
||
|
if (GenericUlong)
|
||
|
Adapter->Flags |= NV_VLAN_TAGGING;
|
||
|
|
||
|
QueryInteger(ConfigurationHandle,
|
||
|
L"VlanID",
|
||
|
&GenericUlong,
|
||
|
0,
|
||
|
0,
|
||
|
NVNET_MAXIMUM_VLAN_ID);
|
||
|
|
||
|
NdisReadNetworkAddress(&Status,
|
||
|
(PVOID*)&NetworkAddress,
|
||
|
&Length,
|
||
|
ConfigurationHandle);
|
||
|
if ((Status == NDIS_STATUS_SUCCESS) && (Length == ETH_LENGTH_OF_ADDRESS))
|
||
|
{
|
||
|
if ((ETH_IS_MULTICAST(NetworkAddress) || ETH_IS_BROADCAST(NetworkAddress)) ||
|
||
|
!ETH_IS_LOCALLY_ADMINISTERED(NetworkAddress))
|
||
|
{
|
||
|
NDIS_DbgPrint(MAX_TRACE, ("Invalid software MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||
|
NetworkAddress[0],
|
||
|
NetworkAddress[1],
|
||
|
NetworkAddress[2],
|
||
|
NetworkAddress[3],
|
||
|
NetworkAddress[4],
|
||
|
NetworkAddress[5]));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("Using software MAC\n"));
|
||
|
|
||
|
ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentMacAddress, NetworkAddress);
|
||
|
|
||
|
Adapter->Flags |= NV_USE_SOFT_MAC_ADDRESS;
|
||
|
}
|
||
|
}
|
||
|
Status = NDIS_STATUS_SUCCESS;
|
||
|
|
||
|
NdisCloseConfiguration(ConfigurationHandle);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
NvNetInitializeAdapterResources(
|
||
|
_Inout_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
PNDIS_RESOURCE_LIST AssignedResources = NULL;
|
||
|
UINT i, ResourceListSize = 0;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
|
||
|
|
||
|
NdisMQueryAdapterResources(&Status,
|
||
|
Adapter->WrapperConfigurationHandle,
|
||
|
AssignedResources,
|
||
|
&ResourceListSize);
|
||
|
if (Status != NDIS_STATUS_RESOURCES)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
|
||
|
return NDIS_STATUS_FAILURE;
|
||
|
}
|
||
|
|
||
|
Status = NdisAllocateMemoryWithTag((PVOID*)&AssignedResources,
|
||
|
ResourceListSize,
|
||
|
NVNET_TAG);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_OUT_OF_RESOURCES);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NdisMQueryAdapterResources(&Status,
|
||
|
Adapter->WrapperConfigurationHandle,
|
||
|
AssignedResources,
|
||
|
&ResourceListSize);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < AssignedResources->Count; ++i)
|
||
|
{
|
||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &AssignedResources->PartialDescriptors[i];
|
||
|
|
||
|
switch (Descriptor->Type)
|
||
|
{
|
||
|
case CmResourceTypeMemory:
|
||
|
{
|
||
|
Adapter->IoAddress = Descriptor->u.Memory.Start;
|
||
|
Adapter->IoLength = Descriptor->u.Memory.Length;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CmResourceTypeInterrupt:
|
||
|
{
|
||
|
Adapter->InterruptVector = Descriptor->u.Interrupt.Vector;
|
||
|
Adapter->InterruptLevel = Descriptor->u.Interrupt.Level;
|
||
|
Adapter->InterruptShared = (Descriptor->ShareDisposition == CmResourceShareShared);
|
||
|
Adapter->InterruptFlags = Descriptor->Flags;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!Adapter->IoAddress.QuadPart || !Adapter->InterruptVector)
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("MEM at [%I64X-%I64X]\n",
|
||
|
Adapter->IoAddress.QuadPart,
|
||
|
Adapter->IoAddress.QuadPart + Adapter->IoLength));
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("IRQ Vector %d Level %d\n",
|
||
|
Adapter->InterruptVector,
|
||
|
Adapter->InterruptLevel));
|
||
|
|
||
|
Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase,
|
||
|
Adapter->AdapterHandle,
|
||
|
Adapter->IoAddress,
|
||
|
Adapter->IoLength);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_RESOURCE_CONFLICT);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
NdisFreeMemory(AssignedResources, ResourceListSize, 0);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
AllocateTransmitBuffers(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
ULONG i;
|
||
|
BOOLEAN HasBuffer = FALSE;
|
||
|
PNVNET_TX_BUFFER CoalesceBuffer;
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
Status = NdisAllocateMemoryWithTag((PVOID*)&CoalesceBuffer,
|
||
|
NVNET_TRANSMIT_BUFFERS * sizeof(NVNET_TX_BUFFER),
|
||
|
NVNET_TAG);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
NdisZeroMemory(CoalesceBuffer, NVNET_TRANSMIT_BUFFERS * sizeof(NVNET_TX_BUFFER));
|
||
|
|
||
|
Adapter->SendBuffer = CoalesceBuffer;
|
||
|
|
||
|
for (i = 0; i < NVNET_TRANSMIT_BUFFERS; ++i)
|
||
|
{
|
||
|
PVOID VirtualAddress;
|
||
|
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
|
||
|
|
||
|
NdisMAllocateSharedMemory(Adapter->AdapterHandle,
|
||
|
Adapter->MaximumFrameSize + NVNET_ALIGNMENT,
|
||
|
TRUE, /* Cached */
|
||
|
&VirtualAddress,
|
||
|
&PhysicalAddress);
|
||
|
if (!VirtualAddress)
|
||
|
continue;
|
||
|
|
||
|
CoalesceBuffer->VirtualAddress = ALIGN_UP_POINTER_BY(VirtualAddress, NVNET_ALIGNMENT);
|
||
|
CoalesceBuffer->PhysicalAddress.QuadPart =
|
||
|
ALIGN_UP_BY(PhysicalAddress.QuadPart, NVNET_ALIGNMENT);
|
||
|
|
||
|
Adapter->SendBufferAllocationData[i].PhysicalAddress.QuadPart = PhysicalAddress.QuadPart;
|
||
|
Adapter->SendBufferAllocationData[i].VirtualAddress = VirtualAddress;
|
||
|
|
||
|
PushEntryList(&Adapter->Send.BufferList, &CoalesceBuffer->Link);
|
||
|
++CoalesceBuffer;
|
||
|
|
||
|
HasBuffer = TRUE;
|
||
|
}
|
||
|
if (!HasBuffer)
|
||
|
{
|
||
|
return NDIS_STATUS_RESOURCES;
|
||
|
}
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
AllocateTransmitBlocks(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
PNVNET_TCB Tcb;
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
Status = NdisAllocateMemoryWithTag((PVOID*)&Tcb,
|
||
|
NVNET_TRANSMIT_BLOCKS * sizeof(NVNET_TCB),
|
||
|
NVNET_TAG);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
NdisZeroMemory(Tcb, NVNET_TRANSMIT_BLOCKS * sizeof(NVNET_TCB));
|
||
|
|
||
|
Adapter->Send.TailTcb = Tcb + (NVNET_TRANSMIT_BLOCKS - 1);
|
||
|
Adapter->Send.HeadTcb = Tcb;
|
||
|
Adapter->Send.CurrentTcb = Tcb;
|
||
|
Adapter->Send.LastTcb = Tcb;
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
AllocateTransmitDescriptors(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
NVNET_TBD Tbd;
|
||
|
ULONG Size;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_HIGH_DMA)
|
||
|
{
|
||
|
Size = sizeof(NVNET_DESCRIPTOR_64);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Size = sizeof(NVNET_DESCRIPTOR_32);
|
||
|
}
|
||
|
NdisMAllocateSharedMemory(Adapter->AdapterHandle,
|
||
|
Size * NVNET_TRANSMIT_DESCRIPTORS + NVNET_ALIGNMENT,
|
||
|
TRUE, /* Cached */
|
||
|
&Adapter->TbdOriginal,
|
||
|
&Adapter->TbdPhysOriginal);
|
||
|
if (!Adapter->TbdOriginal)
|
||
|
return NDIS_STATUS_RESOURCES;
|
||
|
|
||
|
Tbd.Memory = ALIGN_UP_POINTER_BY(Adapter->TbdOriginal, NVNET_ALIGNMENT);
|
||
|
Adapter->TbdPhys.QuadPart = ALIGN_UP_BY(Adapter->TbdPhysOriginal.QuadPart, NVNET_ALIGNMENT);
|
||
|
|
||
|
Adapter->Send.HeadTbd = Tbd;
|
||
|
Adapter->Send.CurrentTbd = Tbd;
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_HIGH_DMA)
|
||
|
{
|
||
|
Adapter->Send.TailTbd.x64 = Tbd.x64 + (NVNET_TRANSMIT_DESCRIPTORS - 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Adapter->Send.TailTbd.x32 = Tbd.x32 + (NVNET_TRANSMIT_DESCRIPTORS - 1);
|
||
|
}
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
AllocateReceiveDescriptors(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
ULONG Size;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_HIGH_DMA)
|
||
|
{
|
||
|
Size = sizeof(NVNET_DESCRIPTOR_64);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Size = sizeof(NVNET_DESCRIPTOR_32);
|
||
|
}
|
||
|
NdisMAllocateSharedMemory(Adapter->AdapterHandle,
|
||
|
Size * NVNET_RECEIVE_DESCRIPTORS + NVNET_ALIGNMENT,
|
||
|
TRUE, /* Cached */
|
||
|
&Adapter->RbdOriginal,
|
||
|
&Adapter->RbdPhysOriginal);
|
||
|
if (!Adapter->RbdOriginal)
|
||
|
return NDIS_STATUS_RESOURCES;
|
||
|
|
||
|
Adapter->Receive.NvRbd.Memory = ALIGN_UP_POINTER_BY(Adapter->RbdOriginal, NVNET_ALIGNMENT);
|
||
|
Adapter->RbdPhys.QuadPart = ALIGN_UP_BY(Adapter->RbdPhysOriginal.QuadPart, NVNET_ALIGNMENT);
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
AllocateReceiveBuffers(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
NdisMAllocateSharedMemory(Adapter->AdapterHandle,
|
||
|
NVNET_RECEIVE_BUFFER_SIZE * NVNET_RECEIVE_DESCRIPTORS,
|
||
|
TRUE, /* Cached */
|
||
|
(PVOID*)&Adapter->ReceiveBuffer,
|
||
|
&Adapter->ReceiveBufferPhys);
|
||
|
if (!Adapter->ReceiveBuffer)
|
||
|
{
|
||
|
return NDIS_STATUS_RESOURCES;
|
||
|
}
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
AllocateAdapterMemory(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
Status = AllocateTransmitBuffers(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
Status = AllocateTransmitBlocks(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
Status = AllocateTransmitDescriptors(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
Status = AllocateReceiveDescriptors(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
Status = AllocateReceiveBuffers(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
return Status;
|
||
|
|
||
|
NdisAllocateSpinLock(&Adapter->Send.Lock);
|
||
|
NdisAllocateSpinLock(&Adapter->Receive.Lock);
|
||
|
NdisAllocateSpinLock(&Adapter->Lock);
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
CODE_SEG("PAGE")
|
||
|
VOID
|
||
|
NvNetInitTransmitMemory(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
Adapter->Send.TcbSlots = NVNET_TRANSMIT_BLOCKS;
|
||
|
Adapter->Send.TbdSlots = NVNET_TRANSMIT_DESCRIPTORS;
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_HIGH_DMA)
|
||
|
{
|
||
|
NdisZeroMemory(Adapter->Send.HeadTbd.x64,
|
||
|
sizeof(NVNET_DESCRIPTOR_64) * NVNET_TRANSMIT_DESCRIPTORS);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NdisZeroMemory(Adapter->Send.HeadTbd.x32,
|
||
|
sizeof(NVNET_DESCRIPTOR_32) * NVNET_TRANSMIT_DESCRIPTORS);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
CODE_SEG("PAGE")
|
||
|
VOID
|
||
|
NvNetInitReceiveMemory(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
NV_RBD NvRbd;
|
||
|
ULONG i;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
Adapter->CurrentRx = 0;
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_HIGH_DMA)
|
||
|
{
|
||
|
for (i = 0; i < NVNET_RECEIVE_DESCRIPTORS; ++i)
|
||
|
{
|
||
|
NvRbd.x64 = &Adapter->Receive.NvRbd.x64[i];
|
||
|
|
||
|
NvRbd.x64->AddressHigh = NdisGetPhysicalAddressHigh(Adapter->ReceiveBufferPhys)
|
||
|
+ i * NVNET_RECEIVE_BUFFER_SIZE;
|
||
|
NvRbd.x64->AddressLow = NdisGetPhysicalAddressLow(Adapter->ReceiveBufferPhys)
|
||
|
+ i * NVNET_RECEIVE_BUFFER_SIZE;
|
||
|
NvRbd.x64->VlanTag = 0;
|
||
|
NvRbd.x64->FlagsLength = NV_RX2_AVAIL | NVNET_RECEIVE_BUFFER_SIZE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 0; i < NVNET_RECEIVE_DESCRIPTORS; ++i)
|
||
|
{
|
||
|
NvRbd.x32 = &Adapter->Receive.NvRbd.x32[i];
|
||
|
|
||
|
NvRbd.x32->Address = NdisGetPhysicalAddressLow(Adapter->ReceiveBufferPhys)
|
||
|
+ i * NVNET_RECEIVE_BUFFER_SIZE;
|
||
|
NvRbd.x32->FlagsLength = NV_RX_AVAIL | NVNET_RECEIVE_BUFFER_SIZE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
CODE_SEG("PAGE")
|
||
|
VOID
|
||
|
NvNetFreeAdapter(
|
||
|
_In_ PNVNET_ADAPTER Adapter)
|
||
|
{
|
||
|
ULONG i;
|
||
|
ULONG DescriptorSize;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
|
||
|
|
||
|
for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i)
|
||
|
{
|
||
|
PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
|
||
|
|
||
|
if (!WakeFrame)
|
||
|
continue;
|
||
|
|
||
|
NdisFreeMemory(WakeFrame, sizeof(*WakeFrame), 0);
|
||
|
}
|
||
|
|
||
|
if (Adapter->Interrupt.InterruptObject)
|
||
|
{
|
||
|
NdisMDeregisterInterrupt(&Adapter->Interrupt);
|
||
|
Adapter->Interrupt.InterruptObject = NULL;
|
||
|
}
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_HIGH_DMA)
|
||
|
{
|
||
|
DescriptorSize = sizeof(NVNET_DESCRIPTOR_64);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DescriptorSize = sizeof(NVNET_DESCRIPTOR_32);
|
||
|
}
|
||
|
if (Adapter->TbdOriginal)
|
||
|
{
|
||
|
NdisMFreeSharedMemory(Adapter->AdapterHandle,
|
||
|
DescriptorSize * NVNET_TRANSMIT_DESCRIPTORS,
|
||
|
FALSE,
|
||
|
Adapter->TbdOriginal,
|
||
|
Adapter->TbdPhysOriginal);
|
||
|
Adapter->TbdOriginal = NULL;
|
||
|
}
|
||
|
if (Adapter->RbdOriginal)
|
||
|
{
|
||
|
NdisMFreeSharedMemory(Adapter->AdapterHandle,
|
||
|
DescriptorSize * NVNET_RECEIVE_DESCRIPTORS,
|
||
|
FALSE,
|
||
|
Adapter->RbdOriginal,
|
||
|
Adapter->RbdPhysOriginal);
|
||
|
Adapter->RbdOriginal = NULL;
|
||
|
}
|
||
|
if (Adapter->SendBuffer)
|
||
|
{
|
||
|
ULONG Length = ALIGN_UP_BY(Adapter->MaximumFrameSize, NVNET_ALIGNMENT);
|
||
|
|
||
|
for (i = 0; i < NVNET_TRANSMIT_BUFFERS; ++i)
|
||
|
{
|
||
|
PNVNET_TX_BUFFER_DATA SendBufferData = &Adapter->SendBufferAllocationData[i];
|
||
|
|
||
|
if (!SendBufferData->VirtualAddress)
|
||
|
continue;
|
||
|
|
||
|
NdisMFreeSharedMemory(Adapter->AdapterHandle,
|
||
|
Length,
|
||
|
TRUE,
|
||
|
SendBufferData->VirtualAddress,
|
||
|
SendBufferData->PhysicalAddress);
|
||
|
}
|
||
|
|
||
|
NdisFreeMemory(Adapter->SendBuffer, NVNET_TRANSMIT_BUFFERS * sizeof(NVNET_TX_BUFFER), 0);
|
||
|
Adapter->SendBuffer = NULL;
|
||
|
}
|
||
|
|
||
|
if (Adapter->ReceiveBuffer)
|
||
|
{
|
||
|
NdisMFreeSharedMemory(Adapter->AdapterHandle,
|
||
|
NVNET_RECEIVE_BUFFER_SIZE * NVNET_RECEIVE_DESCRIPTORS,
|
||
|
FALSE,
|
||
|
Adapter->ReceiveBuffer,
|
||
|
Adapter->ReceiveBufferPhys);
|
||
|
Adapter->ReceiveBuffer = NULL;
|
||
|
}
|
||
|
|
||
|
if (Adapter->IoBase)
|
||
|
{
|
||
|
NdisMUnmapIoSpace(Adapter->AdapterHandle,
|
||
|
Adapter->IoBase,
|
||
|
Adapter->IoLength);
|
||
|
Adapter->IoBase = NULL;
|
||
|
}
|
||
|
|
||
|
if (Adapter->Lock.SpinLock)
|
||
|
NdisFreeSpinLock(&Adapter->Lock);
|
||
|
if (Adapter->Send.Lock.SpinLock)
|
||
|
NdisFreeSpinLock(&Adapter->Send.Lock);
|
||
|
if (Adapter->Receive.Lock.SpinLock)
|
||
|
NdisFreeSpinLock(&Adapter->Receive.Lock);
|
||
|
|
||
|
NdisFreeMemory(Adapter->AdapterOriginal, sizeof(NVNET_ADAPTER), 0);
|
||
|
}
|
||
|
|
||
|
CODE_SEG("PAGE")
|
||
|
NDIS_STATUS
|
||
|
NTAPI
|
||
|
MiniportInitialize(
|
||
|
_Out_ PNDIS_STATUS OpenErrorStatus,
|
||
|
_Out_ PUINT SelectedMediumIndex,
|
||
|
_In_ PNDIS_MEDIUM MediumArray,
|
||
|
_In_ UINT MediumArraySize,
|
||
|
_In_ NDIS_HANDLE MiniportAdapterHandle,
|
||
|
_In_ NDIS_HANDLE WrapperConfigurationContext)
|
||
|
{
|
||
|
UINT i;
|
||
|
ULONG Size;
|
||
|
PVOID UnalignedAdapter;
|
||
|
PNVNET_ADAPTER Adapter;
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
|
||
|
|
||
|
for (i = 0; i < MediumArraySize; ++i)
|
||
|
{
|
||
|
if (MediumArray[i] == NdisMedium802_3)
|
||
|
{
|
||
|
*SelectedMediumIndex = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (i == MediumArraySize)
|
||
|
{
|
||
|
NDIS_DbgPrint(MAX_TRACE, ("No supported media\n"));
|
||
|
return NDIS_STATUS_UNSUPPORTED_MEDIA;
|
||
|
}
|
||
|
|
||
|
Size = sizeof(NVNET_ADAPTER) + NdisGetSharedDataAlignment();
|
||
|
|
||
|
Status = NdisAllocateMemoryWithTag((PVOID*)&UnalignedAdapter,
|
||
|
Size,
|
||
|
NVNET_TAG);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NDIS_DbgPrint(MAX_TRACE, ("Failed to allocate adapter\n"));
|
||
|
return NDIS_STATUS_RESOURCES;
|
||
|
}
|
||
|
|
||
|
NdisZeroMemory(UnalignedAdapter, Size);
|
||
|
Adapter = ALIGN_UP_POINTER_BY(UnalignedAdapter, NdisGetSharedDataAlignment());
|
||
|
Adapter->AdapterOriginal = UnalignedAdapter;
|
||
|
Adapter->AdapterHandle = MiniportAdapterHandle;
|
||
|
Adapter->WrapperConfigurationHandle = WrapperConfigurationContext;
|
||
|
|
||
|
Status = NvNetReadConfiguration(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
NdisMSetAttributesEx(MiniportAdapterHandle,
|
||
|
Adapter,
|
||
|
0,
|
||
|
NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS |
|
||
|
// NDIS_ATTRIBUTE_DESERIALIZE | TODO
|
||
|
NDIS_ATTRIBUTE_BUS_MASTER,
|
||
|
NdisInterfacePci);
|
||
|
|
||
|
Status = NvNetRecognizeHardware(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
if (Status == NDIS_STATUS_ADAPTER_NOT_FOUND)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_ADAPTER_NOT_FOUND);
|
||
|
}
|
||
|
else if (Status == NDIS_STATUS_NOT_RECOGNIZED)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION);
|
||
|
}
|
||
|
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
Status = NvNetInitializeAdapterResources(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
Status = NdisMInitializeScatterGatherDma(Adapter->AdapterHandle,
|
||
|
!!(Adapter->Features & DEV_HAS_HIGH_DMA),
|
||
|
NVNET_MAXIMUM_FRAME_SIZE);
|
||
|
// ^TODO: NVNET_MAX_DMA_TRANSFER);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_OUT_OF_RESOURCES);
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
Status = AllocateAdapterMemory(Adapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NDIS_DbgPrint(MAX_TRACE, ("Failed to allocate adapter memory\n"));
|
||
|
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_OUT_OF_RESOURCES);
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
NvNetInitTransmitMemory(Adapter);
|
||
|
NvNetInitReceiveMemory(Adapter);
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_HIGH_DMA)
|
||
|
{
|
||
|
Adapter->TransmitPacket = NvNetTransmitPacket64;
|
||
|
Adapter->ProcessTransmit = ProcessTransmitDescriptors64;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Adapter->TransmitPacket = NvNetTransmitPacket32;
|
||
|
|
||
|
if (Adapter->Features & DEV_HAS_LARGEDESC)
|
||
|
{
|
||
|
Adapter->ProcessTransmit = ProcessTransmitDescriptors32;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Adapter->ProcessTransmit = ProcessTransmitDescriptorsLegacy;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Status = NvNetGetPermanentMacAddress(Adapter, Adapter->PermanentMacAddress);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_NETWORK_ADDRESS);
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
if (!(Adapter->Flags & NV_USE_SOFT_MAC_ADDRESS))
|
||
|
{
|
||
|
ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentMacAddress,
|
||
|
Adapter->PermanentMacAddress);
|
||
|
}
|
||
|
|
||
|
NvNetSetupMacAddress(Adapter, Adapter->CurrentMacAddress);
|
||
|
|
||
|
Status = NvNetInitNIC(Adapter, TRUE);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NDIS_DbgPrint(MAX_TRACE, ("Failed to initialize the NIC\n"));
|
||
|
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_HARDWARE_FAILURE);
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
NvNetDisableInterrupts(Adapter);
|
||
|
NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_ALL);
|
||
|
NV_WRITE(Adapter, NvRegIrqStatus, NVREG_IRQSTAT_MASK);
|
||
|
|
||
|
/* FIXME: Bug in the PIC HAL? */
|
||
|
#if defined(SARCH_XBOX)
|
||
|
Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
|
||
|
Adapter->AdapterHandle,
|
||
|
Adapter->InterruptVector,
|
||
|
Adapter->InterruptLevel,
|
||
|
TRUE, /* Request ISR calls */
|
||
|
FALSE,
|
||
|
NdisInterruptLatched);
|
||
|
#else
|
||
|
Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
|
||
|
Adapter->AdapterHandle,
|
||
|
Adapter->InterruptVector,
|
||
|
Adapter->InterruptLevel,
|
||
|
TRUE, /* Request ISR calls */
|
||
|
TRUE, /* Shared */
|
||
|
NdisInterruptLevelSensitive);
|
||
|
#endif
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NvNetLogError(Adapter, NDIS_ERROR_CODE_INTERRUPT_CONNECT);
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
NvNetStartAdapter(Adapter);
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
|
||
|
Failure:
|
||
|
NvNetFreeAdapter(Adapter);
|
||
|
|
||
|
return Status;
|
||
|
}
|