[NVNET] Add driver for nForce-based NICs

The driver supports all nVidia chipset models from 2001 until 2010, starting from nForce.
All NICs are compatible with x86 and amd64 devices only.

Tested by Daniel Reimer on OG Xbox and by me on MCP board.

CORE-15872 CORE-16216
This commit is contained in:
Dmitry Borisov 2021-07-25 00:53:39 +06:00 committed by Stanislav Motylkov
parent 269f3a2b24
commit b79fbe2333
17 changed files with 7718 additions and 0 deletions

View file

@ -2,5 +2,8 @@
add_subdirectory(e1000)
add_subdirectory(ne2000)
add_subdirectory(netkvm)
if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64")
add_subdirectory(nvnet)
endif()
add_subdirectory(pcnet)
add_subdirectory(rtl8139)

View file

@ -0,0 +1,25 @@
add_definitions(
-DNDIS_MINIPORT_DRIVER
-DNDIS51_MINIPORT=1)
list(APPEND SOURCE
backoff.c
debug.h
init.c
interrupt.c
nic.c
nic.h
nvnet.c
nvnet.h
phy.c
phyreg.h
requests.c
send.c)
add_library(nvnet MODULE ${SOURCE} nvnet.rc)
add_pch(nvnet nvnet.h SOURCE)
set_module_type(nvnet kernelmodedriver)
add_importlibs(nvnet ndis ntoskrnl hal)
add_cd_file(TARGET nvnet DESTINATION reactos/system32/drivers FOR all)
add_driver_inf(nvnet netnv.inf)

View file

@ -0,0 +1,184 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Re-seeding random values for the backoff algorithms
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
/*
* HW access code was taken from the Linux forcedeth driver
* Copyright (C) 2003,4,5 Manfred Spraul
* Copyright (C) 2004 Andrew de Quincey
* Copyright (C) 2004 Carl-Daniel Hailfinger
* Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA Corporation
*/
/* INCLUDES *******************************************************************/
#include "nvnet.h"
#define NDEBUG
#include "debug.h"
/* GLOBALS ********************************************************************/
#define BACKOFF_SEEDSET_ROWS 8
#define BACKOFF_SEEDSET_LFSRS 15
#define REVERSE_SEED(s) ((((s) & 0xF00) >> 8) | ((s) & 0x0F0) | (((s) & 0x00F) << 8))
static const ULONG NvpMainSeedSet[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] =
{
{145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
{245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 385, 761, 790, 974},
{145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
{245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 386, 761, 790, 974},
{266, 265, 276, 585, 397, 208, 345, 355, 365, 376, 385, 396, 771, 700, 984},
{266, 265, 276, 586, 397, 208, 346, 355, 365, 376, 285, 396, 771, 700, 984},
{366, 365, 376, 686, 497, 308, 447, 455, 466, 476, 485, 496, 871, 800, 84},
{466, 465, 476, 786, 597, 408, 547, 555, 566, 576, 585, 597, 971, 900, 184}
};
static const ULONG NvpGearSeedSet[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] =
{
{251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
{351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
{351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 397},
{251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
{251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
{351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
{351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
{351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395}
};
/* FUNCTIONS ******************************************************************/
CODE_SEG("PAGE")
VOID
NvNetBackoffSetSlotTime(
_In_ PNVNET_ADAPTER Adapter)
{
LARGE_INTEGER Sample = KeQueryPerformanceCounter(NULL);
PAGED_CODE();
if ((Sample.LowPart & NVREG_SLOTTIME_MASK) == 0)
{
Sample.LowPart = 8;
}
if (Adapter->Features & (DEV_HAS_HIGH_DMA | DEV_HAS_LARGEDESC))
{
if (Adapter->Features & DEV_HAS_GEAR_MODE)
{
NV_WRITE(Adapter, NvRegSlotTime, NVREG_SLOTTIME_10_100_FULL);
NvNetBackoffReseedEx(Adapter);
}
else
{
NV_WRITE(Adapter, NvRegSlotTime, (Sample.LowPart & NVREG_SLOTTIME_MASK) |
NVREG_SLOTTIME_LEGBF_ENABLED | NVREG_SLOTTIME_10_100_FULL);
}
}
else
{
NV_WRITE(Adapter, NvRegSlotTime,
(Sample.LowPart & NVREG_SLOTTIME_MASK) | NVREG_SLOTTIME_DEFAULT);
}
}
VOID
NvNetBackoffReseed(
_In_ PNVNET_ADAPTER Adapter)
{
ULONG SlotTime;
BOOLEAN RestartTransmitter = FALSE;
LARGE_INTEGER Sample = KeQueryPerformanceCounter(NULL);
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
if ((Sample.LowPart & NVREG_SLOTTIME_MASK) == 0)
{
Sample.LowPart = 8;
}
SlotTime = NV_READ(Adapter, NvRegSlotTime) & ~NVREG_SLOTTIME_MASK;
SlotTime |= Sample.LowPart & NVREG_SLOTTIME_MASK;
if (NV_READ(Adapter, NvRegTransmitterControl) & NVREG_XMITCTL_START)
{
RestartTransmitter = TRUE;
NvNetStopTransmitter(Adapter);
}
NvNetStopReceiver(Adapter);
NV_WRITE(Adapter, NvRegSlotTime, SlotTime);
if (RestartTransmitter)
{
NvNetStartTransmitter(Adapter);
}
NvNetStartReceiver(Adapter);
}
VOID
NvNetBackoffReseedEx(
_In_ PNVNET_ADAPTER Adapter)
{
LARGE_INTEGER Sample;
ULONG Seed[3], ReversedSeed[2], CombinedSeed, SeedSet;
ULONG i, Temp;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
Sample = KeQueryPerformanceCounter(NULL);
Seed[0] = Sample.LowPart & 0x0FFF;
if (Seed[0] == 0)
{
Seed[0] = 0x0ABC;
}
Sample = KeQueryPerformanceCounter(NULL);
Seed[1] = Sample.LowPart & 0x0FFF;
if (Seed[1] == 0)
{
Seed[1] = 0x0ABC;
}
ReversedSeed[0] = REVERSE_SEED(Seed[1]);
Sample = KeQueryPerformanceCounter(NULL);
Seed[2] = Sample.LowPart & 0x0FFF;
if (Seed[2] == 0)
{
Seed[2] = 0x0ABC;
}
ReversedSeed[1] = REVERSE_SEED(Seed[2]);
CombinedSeed = ((Seed[0] ^ ReversedSeed[0]) << 12) | (Seed[1] ^ ReversedSeed[1]);
if ((CombinedSeed & NVREG_BKOFFCTRL_SEED_MASK) == 0)
{
CombinedSeed |= 8;
}
if ((CombinedSeed & (NVREG_BKOFFCTRL_SEED_MASK << NVREG_BKOFFCTRL_GEAR)) == 0)
{
CombinedSeed |= 8 << NVREG_BKOFFCTRL_GEAR;
}
/* No need to disable transmitter here */
Temp = NVREG_BKOFFCTRL_DEFAULT | (0 << NVREG_BKOFFCTRL_SELECT);
Temp |= CombinedSeed & NVREG_BKOFFCTRL_SEED_MASK;
Temp |= CombinedSeed >> NVREG_BKOFFCTRL_GEAR;
NV_WRITE(Adapter, NvRegBackOffControl, Temp);
/* Setup seeds for all gear LFSRs */
Sample = KeQueryPerformanceCounter(NULL);
SeedSet = Sample.LowPart % BACKOFF_SEEDSET_ROWS;
for (i = 1; i <= BACKOFF_SEEDSET_LFSRS; ++i)
{
Temp = NVREG_BKOFFCTRL_DEFAULT | (i << NVREG_BKOFFCTRL_SELECT);
Temp |= NvpMainSeedSet[SeedSet][i - 1] & NVREG_BKOFFCTRL_SEED_MASK;
Temp |= (NvpGearSeedSet[SeedSet][i - 1] & NVREG_BKOFFCTRL_SEED_MASK)
<< NVREG_BKOFFCTRL_GEAR;
NV_WRITE(Adapter, NvRegBackOffControl, Temp);
}
}

View file

@ -0,0 +1,43 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Debugging support
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#define MIN_TRACE 0x00000001
#define MAX_TRACE 0x00000003
#if DBG
#ifndef NDEBUG
#define NDIS_DbgPrint(_t_, _x_) \
do { \
if (DbgPrint("(%s:%d) %s ", __FILE__, __LINE__, __FUNCTION__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __FILE__, __LINE__); \
if (DbgPrint _x_) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __FILE__, __LINE__); \
} while(0)
#else
#define NDIS_DbgPrint(_t_, _x_) \
if (_t_ == MAX_TRACE) \
{ \
if (DbgPrint("(%s:%d) %s ", __FILE__, __LINE__, __FUNCTION__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __FILE__, __LINE__); \
if (DbgPrint _x_) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __FILE__, __LINE__); \
}
#endif
#else
#define NDIS_DbgPrint(_t_, _x_)
#define ASSERT_IRQL(x)
#define ASSERT_IRQL_EQUAL(x)
#endif

View file

@ -0,0 +1,57 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Ethernet definitions
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#include <pshpack1.h>
typedef struct _ETH_HEADER
{
UCHAR Destination[ETH_LENGTH_OF_ADDRESS];
UCHAR Source[ETH_LENGTH_OF_ADDRESS];
USHORT PayloadType;
} ETH_HEADER, *PETH_HEADER;
#include <poppack.h>
#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
(BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x02))
#define ETH_IS_EMPTY(Address) \
(BOOLEAN)((((PUCHAR)(Address))[0] | ((PUCHAR)(Address))[1] | ((PUCHAR)(Address))[2] | \
((PUCHAR)(Address))[3] | ((PUCHAR)(Address))[5] | ((PUCHAR)(Address))[5]) == 0)
typedef struct IPv4_HEADER
{
UCHAR VersionLength;
UCHAR Tos;
USHORT TotalLength;
USHORT Id;
USHORT Offset;
UCHAR Ttl;
UCHAR Protocol;
USHORT Checksum;
ULONG Source;
ULONG Destination;
} IPv4_HEADER, *PIPv4_HEADER;
typedef struct TCPv4_HEADER
{
USHORT SourcePort;
USHORT DestinationPort;
ULONG SequenceNumber;
ULONG AckNumber;
UCHAR DataOffset;
UCHAR Flags;
USHORT Window;
USHORT Checksum;
USHORT Urgent;
} TCPv4_HEADER, *PTCPv4_HEADER;
#define IP_HEADER_LENGTH(Header) \
(((Header)->VersionLength & 0x0F) << 2)
#define TCP_HEADER_LENGTH(Header) \
((Header->DataOffset & 0xF0) >> 2)

View file

@ -0,0 +1,885 @@
/*
* 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;
}

View file

@ -0,0 +1,549 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Interrupt handling
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "nvnet.h"
#define NDEBUG
#include "debug.h"
/* FUNCTIONS ******************************************************************/
ULONG
ProcessTransmitDescriptorsLegacy(
_In_ PNVNET_ADAPTER Adapter,
_Inout_ PLIST_ENTRY SendReadyList)
{
PNVNET_TCB Tcb = Adapter->Send.LastTcb;
ULONG TcbProcessed = 0;
while (Tcb != Adapter->Send.CurrentTcb)
{
NVNET_TBD Tbd = Tcb->Tbd;
ULONG Flags = Tbd.x32->FlagsLength;
if (Flags & NV_TX_VALID)
break;
NDIS_DbgPrint(MIN_TRACE, ("Packet transmitted (flags %lx)\n",
Flags & FLAG_MASK_V1));
if (Flags & NV_TX_ERROR)
{
++Adapter->Statistics.TransmitErrors;
if (Flags & NV_TX_UNDERFLOW)
++Adapter->Statistics.TransmitUnderrunErrors;
if (Flags & NV_TX_LATECOLLISION)
++Adapter->Statistics.TransmitLateCollisions;
if (Flags & NV_TX_CARRIERLOST)
++Adapter->Statistics.TransmitLostCarrierSense;
if (Flags & NV_TX_RETRYERROR)
{
++Adapter->Statistics.TransmitExcessiveCollisions;
if (!(Flags & NV_TX_RETRYCOUNT_MASK))
{
NvNetBackoffReseed(Adapter);
}
}
}
else
{
++Adapter->Statistics.TransmitOk;
if (Flags & NV_TX_DEFERRED)
{
++Adapter->Statistics.TransmitDeferred;
}
if (!(Flags & NV_TX_RETRYCOUNT_MASK))
++Adapter->Statistics.TransmitZeroRetry;
else if ((Flags & NV_TX_RETRYCOUNT_MASK) == NV_TX_ONE_RETRY)
++Adapter->Statistics.TransmitOneRetry;
}
InsertTailList(SendReadyList, PACKET_ENTRY(Tcb->Packet));
NV_RELEASE_TCB(Adapter, Tcb);
++TcbProcessed;
Tcb = NV_NEXT_TCB(Adapter, Tcb);
}
Adapter->Send.LastTcb = Tcb;
return TcbProcessed;
}
ULONG
ProcessTransmitDescriptors32(
_In_ PNVNET_ADAPTER Adapter,
_Inout_ PLIST_ENTRY SendReadyList)
{
PNVNET_TCB Tcb = Adapter->Send.LastTcb;
ULONG TcbProcessed = 0;
while (Tcb != Adapter->Send.CurrentTcb)
{
NVNET_TBD Tbd = Tcb->Tbd;
ULONG Flags = Tbd.x32->FlagsLength;
if (Flags & NV_TX_VALID)
break;
NDIS_DbgPrint(MIN_TRACE, ("Packet transmitted (flags %lx)\n",
Flags & FLAG_MASK_V2));
if (Flags & NV_TX2_ERROR)
{
if ((Flags & NV_TX2_RETRYERROR) && !(Flags & NV_TX2_RETRYCOUNT_MASK))
{
if (Adapter->Features & DEV_HAS_GEAR_MODE)
NvNetBackoffReseedEx(Adapter);
else
NvNetBackoffReseed(Adapter);
}
}
InsertTailList(SendReadyList, PACKET_ENTRY(Tcb->Packet));
NV_RELEASE_TCB(Adapter, Tcb);
++TcbProcessed;
Tcb = NV_NEXT_TCB(Adapter, Tcb);
}
Adapter->Send.LastTcb = Tcb;
return TcbProcessed;
}
ULONG
ProcessTransmitDescriptors64(
_In_ PNVNET_ADAPTER Adapter,
_Inout_ PLIST_ENTRY SendReadyList)
{
PNVNET_TCB Tcb = Adapter->Send.LastTcb;
ULONG TcbProcessed = 0;
while (Tcb != Adapter->Send.CurrentTcb)
{
NVNET_TBD Tbd = Tcb->Tbd;
ULONG Flags = Tbd.x64->FlagsLength;
if (Flags & NV_TX_VALID)
break;
if (Adapter->Flags & NV_SEND_ERRATA_PRESENT)
{
PNVNET_TCB DeferredTcb;
--Adapter->Send.PacketsCount;
DeferredTcb = Adapter->Send.DeferredTcb;
if (DeferredTcb)
{
DeferredTcb->DeferredTbd.x64->FlagsLength |= NV_TX2_VALID;
++Adapter->Send.PacketsCount;
Adapter->Send.DeferredTcb = NV_NEXT_TCB(Adapter, DeferredTcb);
if (Adapter->Send.DeferredTcb == Adapter->Send.CurrentTcb)
{
Adapter->Send.DeferredTcb = NULL;
}
NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_KICK);
}
}
NDIS_DbgPrint(MIN_TRACE, ("Packet transmitted (flags %lx)\n",
Flags & FLAG_MASK_V2));
if (Flags & NV_TX2_ERROR)
{
if ((Flags & NV_TX2_RETRYERROR) && !(Flags & NV_TX2_RETRYCOUNT_MASK))
{
if (Adapter->Features & DEV_HAS_GEAR_MODE)
NvNetBackoffReseedEx(Adapter);
else
NvNetBackoffReseed(Adapter);
}
}
InsertTailList(SendReadyList, PACKET_ENTRY(Tcb->Packet));
NV_RELEASE_TCB(Adapter, Tcb);
++TcbProcessed;
Tcb = NV_NEXT_TCB(Adapter, Tcb);
}
Adapter->Send.LastTcb = Tcb;
return TcbProcessed;
}
static
BOOLEAN
HandleLengthError(
_In_ PVOID EthHeader,
_Inout_ PUSHORT Length)
{
PUCHAR Buffer = EthHeader;
ULONG i;
DBG_UNREFERENCED_LOCAL_VARIABLE(Buffer);
/* TODO */
NDIS_DbgPrint(MAX_TRACE, ("() Length error detected (%u): \n", *Length));
for (i = 0; i < *Length; ++i)
{
NDIS_DbgPrint(MAX_TRACE, ("%02x ", Buffer[i]));
}
NDIS_DbgPrint(MAX_TRACE, ("\n\n*** Please report it to the team! ***\n\n"));
return FALSE;
}
/* TODO: This need to be rewritten. I leave it as-is for now */
static
ULONG
ProcessReceiveDescriptors(
_In_ PNVNET_ADAPTER Adapter,
_In_ ULONG TotalRxProcessed)
{
ULONG i, RxProcessed = 0;
BOOLEAN IndicateComplete = FALSE;
for (i = 0; i < NVNET_RECEIVE_DESCRIPTORS; ++i)
{
ULONG Flags;
USHORT Length;
PUCHAR EthHeader;
NV_RBD NvRbd;
if (Adapter->Features & DEV_HAS_HIGH_DMA)
{
NvRbd.x64 = &Adapter->Receive.NvRbd.x64[Adapter->CurrentRx];
Flags = NvRbd.x64->FlagsLength;
}
else
{
NvRbd.x32 = &Adapter->Receive.NvRbd.x32[Adapter->CurrentRx];
Flags = NvRbd.x32->FlagsLength;
}
if (Flags & NV_RX_AVAIL)
break;
if (TotalRxProcessed + RxProcessed >= NVNET_RECEIVE_PROCESSING_LIMIT)
break;
if (!Adapter->PacketFilter)
goto NextDescriptor;
if (Adapter->Features & (DEV_HAS_HIGH_DMA | DEV_HAS_LARGEDESC))
{
if (!(Flags & NV_RX2_DESCRIPTORVALID))
goto NextDescriptor;
Length = Flags & LEN_MASK_V2;
EthHeader = &Adapter->ReceiveBuffer[Adapter->CurrentRx * NVNET_RECEIVE_BUFFER_SIZE];
if (Flags & NV_RX2_ERROR)
{
if ((Flags & NV_RX2_ERROR_MASK) == NV_RX2_ERROR4)
{
if (!HandleLengthError(EthHeader, &Length))
goto NextDescriptor;
}
else if ((Flags & NV_RX2_ERROR_MASK) == NV_RX2_FRAMINGERR)
{
if (Flags & NV_RX2_SUBTRACT1)
--Length;
}
else
{
goto NextDescriptor;
}
}
NDIS_DbgPrint(MIN_TRACE, ("Packet %d received (length %d, flags %lx)\n",
Adapter->CurrentRx, Length, Flags & FLAG_MASK_V2));
}
else
{
if (!(Flags & NV_RX_DESCRIPTORVALID))
goto NextDescriptor;
Length = Flags & LEN_MASK_V1;
EthHeader = &Adapter->ReceiveBuffer[Adapter->CurrentRx * NVNET_RECEIVE_BUFFER_SIZE];
if (Flags & NV_RX_ERROR)
{
if ((Flags & NV_RX_ERROR_MASK) == NV_RX_ERROR4)
{
if (!HandleLengthError(EthHeader, &Length))
goto NextDescriptor;
}
else if ((Flags & NV_RX_ERROR_MASK) == NV_RX_FRAMINGERR)
{
if (Flags & NV_RX_SUBTRACT1)
--Length;
}
else
{
++Adapter->Statistics.ReceiveErrors;
if (Flags & NV_RX_MISSEDFRAME)
++Adapter->Statistics.ReceiveNoBuffers;
if (Flags & NV_RX_FRAMINGERR)
++Adapter->Statistics.ReceiveAlignmentErrors;
if (Flags & NV_RX_OVERFLOW)
++Adapter->Statistics.ReceiveOverrunErrors;
if (Flags & NV_RX_CRCERR)
++Adapter->Statistics.ReceiveCrcErrors;
goto NextDescriptor;
}
}
++Adapter->Statistics.ReceiveOk;
NDIS_DbgPrint(MIN_TRACE, ("Packet %d received (length %d, flags %lx)\n",
Adapter->CurrentRx, Length, Flags & FLAG_MASK_V1));
}
NdisMEthIndicateReceive(Adapter->AdapterHandle,
NULL,
(PCHAR)EthHeader,
sizeof(ETH_HEADER),
EthHeader + sizeof(ETH_HEADER),
Length - sizeof(ETH_HEADER),
Length - sizeof(ETH_HEADER));
IndicateComplete = TRUE;
NextDescriptor:
/* Invalidate the buffer length and release the descriptor */
if (Adapter->Features & DEV_HAS_HIGH_DMA)
NvRbd.x64->FlagsLength = NV_RX2_AVAIL | NVNET_RECEIVE_BUFFER_SIZE;
else
NvRbd.x32->FlagsLength = NV_RX_AVAIL | NVNET_RECEIVE_BUFFER_SIZE;
Adapter->CurrentRx = (Adapter->CurrentRx + 1) % NVNET_RECEIVE_DESCRIPTORS;
++RxProcessed;
}
if (IndicateComplete)
{
NdisMEthIndicateReceiveComplete(Adapter->AdapterHandle);
}
return RxProcessed;
}
static
inline
VOID
ChangeInterruptMode(
_In_ PNVNET_ADAPTER Adapter,
_In_ ULONG Workload)
{
if (Workload > NVNET_IM_THRESHOLD)
{
Adapter->InterruptIdleCount = 0;
/* High activity, polling based strategy */
Adapter->InterruptMask = NVREG_IRQMASK_CPU;
}
else
{
if (Adapter->InterruptIdleCount < NVNET_IM_MAX_IDLE)
{
++Adapter->InterruptIdleCount;
}
else
{
/* Low activity, 1 interrupt per packet */
Adapter->InterruptMask = NVREG_IRQMASK_THROUGHPUT;
}
}
}
static
VOID
HandleLinkStateChange(
_In_ PNVNET_ADAPTER Adapter)
{
ULONG MiiStatus;
BOOLEAN Connected, Report = FALSE;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
NdisDprAcquireSpinLock(&Adapter->Lock);
MiiStatus = NV_READ(Adapter, NvRegMIIStatus);
/* Clear the link change interrupt */
NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_LINKCHANGE);
if (MiiStatus & NVREG_MIISTAT_LINKCHANGE)
{
Connected = NvNetUpdateLinkSpeed(Adapter);
if (Adapter->Connected != Connected)
{
Adapter->Connected = Connected;
Report = TRUE;
if (Connected)
{
/* Link up */
NvNetToggleClockPowerGating(Adapter, FALSE);
NdisDprAcquireSpinLock(&Adapter->Receive.Lock);
NvNetStartReceiver(Adapter);
}
else
{
/* Link down */
NvNetToggleClockPowerGating(Adapter, TRUE);
NdisDprAcquireSpinLock(&Adapter->Receive.Lock);
NvNetStopReceiver(Adapter);
}
NdisDprReleaseSpinLock(&Adapter->Receive.Lock);
}
}
NdisDprReleaseSpinLock(&Adapter->Lock);
if (Report)
{
NdisMIndicateStatus(Adapter->AdapterHandle,
Connected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
NULL,
0);
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
}
}
static
VOID
HandleRecoverableError(
_In_ PNVNET_ADAPTER Adapter)
{
/* TODO */
NDIS_DbgPrint(MAX_TRACE, ("() Recoverable error detected\n"));
}
VOID
NTAPI
MiniportHandleInterrupt(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
ULONG InterruptStatus = Adapter->InterruptStatus;
ULONG RxProcessed, TotalTxProcessed = 0, TotalRxProcessed = 0;
LIST_ENTRY SendReadyList;
NDIS_DbgPrint(MIN_TRACE, ("() Events 0x%lx\n", InterruptStatus));
if (!(Adapter->Flags & NV_ACTIVE))
return;
InitializeListHead(&SendReadyList);
/* Process the rings and measure network activity */
while (TotalRxProcessed < NVNET_RECEIVE_PROCESSING_LIMIT)
{
NdisDprAcquireSpinLock(&Adapter->Send.Lock);
TotalTxProcessed += Adapter->ProcessTransmit(Adapter, &SendReadyList);
NdisDprReleaseSpinLock(&Adapter->Send.Lock);
while (!IsListEmpty(&SendReadyList))
{
PLIST_ENTRY Entry = RemoveHeadList(&SendReadyList);
NdisMSendComplete(Adapter->AdapterHandle,
CONTAINING_RECORD(Entry, NDIS_PACKET, MiniportReserved),
NDIS_STATUS_SUCCESS);
}
RxProcessed = ProcessReceiveDescriptors(Adapter, TotalRxProcessed);
if (!RxProcessed)
break;
TotalRxProcessed += RxProcessed;
}
NDIS_DbgPrint(MIN_TRACE, ("Total TX: %d, RX: %d\n", TotalTxProcessed, TotalRxProcessed));
/* Moderate the interrupts */
if (Adapter->OptimizationMode == NV_OPTIMIZATION_MODE_DYNAMIC)
{
ChangeInterruptMode(Adapter, TotalTxProcessed + TotalRxProcessed);
}
if (InterruptStatus & NVREG_IRQ_RX_NOBUF)
{
++Adapter->Statistics.ReceiveIrqNoBuffers;
}
if (InterruptStatus & NVREG_IRQ_LINK)
{
HandleLinkStateChange(Adapter);
}
if (InterruptStatus & NVREG_IRQ_RECOVER_ERROR)
{
HandleRecoverableError(Adapter);
}
/* Enable interrupts on the NIC */
NvNetApplyInterruptMask(Adapter);
}
VOID
NTAPI
MiniportISR(
_Out_ PBOOLEAN InterruptRecognized,
_Out_ PBOOLEAN QueueMiniportHandleInterrupt,
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
ULONG InterruptStatus;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
InterruptStatus = NV_READ(Adapter, NvRegIrqStatus);
/* Clear any interrupt events */
NV_WRITE(Adapter, NvRegIrqStatus, InterruptStatus);
if (InterruptStatus & Adapter->InterruptMask)
{
/* Disable further interrupts */
NvNetDisableInterrupts(Adapter);
Adapter->InterruptStatus = InterruptStatus;
*InterruptRecognized = TRUE;
*QueueMiniportHandleInterrupt = TRUE;
}
else
{
/* This interrupt is not ours */
*InterruptRecognized = FALSE;
*QueueMiniportHandleInterrupt = FALSE;
}
}

View file

@ -0,0 +1,288 @@
; NETNV.INF
; Installation file for nForce-based NICs
[Version]
Signature = "$Windows NT$"
;Signature = "$ReactOS$"
LayoutFile = layout.inf
Class = Net
ClassGUID = {4D36E972-E325-11CE-BFC1-08002BE10318}
Provider = %ReactOS%
DriverVer = 08/01/2021,1.00
[DestinationDirs]
DefaultDestDir = 12
[Manufacturer]
%nVidiaMfg% = nVidiaMfg
[ControlFlags]
ExcludeFromSelect = *
[nVidiaMfg]
%NVNET.DeviceDesc% = NVNET_Inst_V1.ndi,PCI\VEN_10DE&DEV_01C3
%NVNET.DeviceDesc% = NVNET_Inst_V1.ndi,PCI\VEN_10DE&DEV_0066
%NVNET.DeviceDesc% = NVNET_Inst_V1.ndi,PCI\VEN_10DE&DEV_00D6
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_0086
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_008C
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_00E6
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_00DF
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_0056
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_0057
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_0037
%NVNET.DeviceDesc% = NVNET_Inst_V2.ndi,PCI\VEN_10DE&DEV_0038
%NVNET.DeviceDesc% = NVNET_Inst_V1.ndi,PCI\VEN_10DE&DEV_0268
%NVNET.DeviceDesc% = NVNET_Inst_V1.ndi,PCI\VEN_10DE&DEV_0269
%NVNET.DeviceDesc% = NVNET_Inst_V3.ndi,PCI\VEN_10DE&DEV_0372
%NVNET.DeviceDesc% = NVNET_Inst_V3.ndi,PCI\VEN_10DE&DEV_0373
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_03E5
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_03E6
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_03EE
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_03EF
%NVNET.DeviceDesc% = NVNET_Inst_V5.ndi,PCI\VEN_10DE&DEV_0450
%NVNET.DeviceDesc% = NVNET_Inst_V5.ndi,PCI\VEN_10DE&DEV_0451
%NVNET.DeviceDesc% = NVNET_Inst_V5.ndi,PCI\VEN_10DE&DEV_0452
%NVNET.DeviceDesc% = NVNET_Inst_V5.ndi,PCI\VEN_10DE&DEV_0453
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_054C
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_054D
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_054E
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_054F
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_07DC
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_07DD
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_07DE
%NVNET.DeviceDesc% = NVNET_Inst_V4.ndi,PCI\VEN_10DE&DEV_07DF
%NVNET.DeviceDesc% = NVNET_Inst_V6.ndi,PCI\VEN_10DE&DEV_0760
%NVNET.DeviceDesc% = NVNET_Inst_V6.ndi,PCI\VEN_10DE&DEV_0761
%NVNET.DeviceDesc% = NVNET_Inst_V6.ndi,PCI\VEN_10DE&DEV_0762
%NVNET.DeviceDesc% = NVNET_Inst_V6.ndi,PCI\VEN_10DE&DEV_0763
%NVNET.DeviceDesc% = NVNET_Inst_V7.ndi,PCI\VEN_10DE&DEV_0AB0
%NVNET.DeviceDesc% = NVNET_Inst_V7.ndi,PCI\VEN_10DE&DEV_0AB1
%NVNET.DeviceDesc% = NVNET_Inst_V7.ndi,PCI\VEN_10DE&DEV_0AB2
%NVNET.DeviceDesc% = NVNET_Inst_V7.ndi,PCI\VEN_10DE&DEV_0AB3
%NVNET.DeviceDesc% = NVNET_Inst_V7.ndi,PCI\VEN_10DE&DEV_0D7D
;----------------------------- NVNET DRIVER -----------------------------
[NVNET_Inst_V1.ndi.NT]
Characteristics = 0x84 ; NCF_PHYSICAL | NCF_HAS_UI
BusType = 5 ; PCIBus
CopyFiles = NVNET_CopyFiles.NT
AddReg = NVNET_AddReg, NVNET_Generic, NVNET_Flow
[NVNET_Inst_V2.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = NVNET_CopyFiles.NT
AddReg = NVNET_AddReg, NVNET_Generic, NVNET_Flow, NVNET_Jumbo, NVNET_Offload
[NVNET_Inst_V3.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = NVNET_CopyFiles.NT
AddReg = NVNET_AddReg, NVNET_Generic, NVNET_Flow_V2, NVNET_Jumbo, NVNET_Offload, NVNET_VLAN
[NVNET_Inst_V4.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = NVNET_CopyFiles.NT
AddReg = NVNET_AddReg, NVNET_Generic, NVNET_Flow_V2
[NVNET_Inst_V5.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = NVNET_CopyFiles.NT
AddReg = NVNET_AddReg, NVNET_Generic, NVNET_Flow_V2, NVNET_Jumbo
[NVNET_Inst_V6.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = NVNET_CopyFiles.NT
AddReg = NVNET_AddReg, NVNET_Generic, NVNET_Flow_V2, NVNET_Offload
[NVNET_Inst_V7.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = NVNET_CopyFiles.NT
AddReg = NVNET_AddReg, NVNET_Generic, NVNET_Flow_V2, NVNET_Jumbo, NVNET_Offload
[NVNET_CopyFiles.NT]
nvnet.sys
[NVNET_Inst_V1.ndi.NT.Services]
AddService = nvnet, 2, NVNET_Service_Inst, NVNET_EventLog
[NVNET_Inst_V2.ndi.NT.Services]
AddService = nvnet, 2, NVNET_Service_Inst, NVNET_EventLog
[NVNET_Inst_V3.ndi.NT.Services]
AddService = nvnet, 2, NVNET_Service_Inst, NVNET_EventLog
[NVNET_Inst_V4.ndi.NT.Services]
AddService = nvnet, 2, NVNET_Service_Inst, NVNET_EventLog
[NVNET_Inst_V5.ndi.NT.Services]
AddService = nvnet, 2, NVNET_Service_Inst, NVNET_EventLog
[NVNET_Inst_V6.ndi.NT.Services]
AddService = nvnet, 2, NVNET_Service_Inst, NVNET_EventLog
[NVNET_Inst_V7.ndi.NT.Services]
AddService = nvnet, 2, NVNET_Service_Inst, NVNET_EventLog
[NVNET_AddReg]
HKR, Ndi, Service, 0, "nvnet"
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
[NVNET_Generic]
HKR, Ndi\params\OptimizationMode, ParamDesc, 0, %OM%
HKR, Ndi\params\OptimizationMode, type, 0, "enum"
HKR, Ndi\params\OptimizationMode, default, 0, "0"
HKR, Ndi\params\OptimizationMode\enum, "0", 0, "%M1%"
HKR, Ndi\params\OptimizationMode\enum, "1", 0, "%M2%"
HKR, Ndi\params\OptimizationMode\enum, "2", 0, "%M3%"
HKR, Ndi\params\NetworkAddress, ParamDesc, 0, %NA%
HKR, Ndi\params\NetworkAddress, type, 0, "edit"
HKR, Ndi\params\NetworkAddress, LimitText, 0, "12"
HKR, Ndi\params\NetworkAddress, UpperCase, 0, "1"
HKR, Ndi\params\NetworkAddress, default, 0, " "
HKR, Ndi\params\NetworkAddress, optional, 0, "1"
HKR, Ndi\params\SpeedDuplex, ParamDesc, 0, %SD%
HKR, Ndi\params\SpeedDuplex, type, 0, "enum"
HKR, Ndi\params\SpeedDuplex, default, 0, "0"
HKR, Ndi\params\SpeedDuplex\enum, "0", 0, "%Auto%"
HKR, Ndi\params\SpeedDuplex\enum, "1", 0, "10HD"
HKR, Ndi\params\SpeedDuplex\enum, "2", 0, "10FD"
HKR, Ndi\params\SpeedDuplex\enum, "3", 0, "100HD"
HKR, Ndi\params\SpeedDuplex\enum, "4", 0, "100FD"
[NVNET_Flow]
HKR, Ndi\params\FlowControl, ParamDesc, 0, %FC%
HKR, Ndi\params\FlowControl, type, 0, "enum"
HKR, Ndi\params\FlowControl, default, 0, "1"
HKR, Ndi\params\FlowControl\enum, "0", 0, "%No%"
HKR, Ndi\params\FlowControl\enum, "1", 0, "%Auto%"
HKR, Ndi\params\FlowControl\enum, "2", 0, "%FlowRx%"
[NVNET_Flow_V2]
HKR, Ndi\params\FlowControl, ParamDesc, 0, %FC%
HKR, Ndi\params\FlowControl, type, 0, "enum"
HKR, Ndi\params\FlowControl, default, 0, "1"
HKR, Ndi\params\FlowControl\enum, "0", 0, "%No%"
HKR, Ndi\params\FlowControl\enum, "1", 0, "%Auto%"
HKR, Ndi\params\FlowControl\enum, "2", 0, "%FRx%"
HKR, Ndi\params\FlowControl\enum, "3", 0, "%FTx%"
HKR, Ndi\params\FlowControl\enum, "4", 0, "%FBoth%"
[NVNET_Offload]
HKR, Ndi\params\ChecksumOffload, ParamDesc, 0, %CO%
HKR, Ndi\params\ChecksumOffload, type, 0, "enum"
HKR, Ndi\params\ChecksumOffload, default, 0, "1"
HKR, Ndi\params\ChecksumOffload\enum, "0", 0, "%No%"
HKR, Ndi\params\ChecksumOffload\enum, "1", 0, "%Yes%"
HKR, Ndi\params\LargeSendOffload, ParamDesc, 0, %LS%
HKR, Ndi\params\LargeSendOffload, type, 0, "enum"
HKR, Ndi\params\LargeSendOffload, default, 0, "1"
HKR, Ndi\params\LargeSendOffload\enum, "0", 0, "%No%"
HKR, Ndi\params\LargeSendOffload\enum, "1", 0, "%Yes%"
[NVNET_Jumbo]
HKR, Ndi\params\JumboSize, ParamDesc, 0, %JF%
HKR, Ndi\params\JumboSize, type, 0, "int"
HKR, Ndi\params\JumboSize, default, 0, "1514"
HKR, Ndi\params\JumboSize, min, 0, "1514"
HKR, Ndi\params\JumboSize, max, 0, "9014"
HKR, Ndi\params\JumboSize, step, 0, "1"
HKR, Ndi\params\JumboSize, base, 0, "10"
[NVNET_VLAN]
HKR, Ndi\params\Priority, ParamDesc, 0, %PP%
HKR, Ndi\params\Priority, type, 0, "enum"
HKR, Ndi\params\Priority, default, 0, "1"
HKR, Ndi\params\Priority\enum, "0", 0, "%No%"
HKR, Ndi\params\Priority\enum, "1", 0, "%Yes%"
HKR, Ndi\params\VlanTag, ParamDesc, 0, %VT%
HKR, Ndi\params\VlanTag, type, 0, "enum"
HKR, Ndi\params\VlanTag, default, 0, "1"
HKR, Ndi\params\VlanTag\enum, "0", 0, "%No%"
HKR, Ndi\params\VlanTag\enum, "1", 0, "%Yes%"
HKR, Ndi\params\VlanID, ParamDesc, 0, %VI%
HKR, Ndi\params\VlanID, type, 0, "long"
HKR, Ndi\params\VlanID, default, 0, "0"
HKR, Ndi\params\VlanID, min, 0, "0"
HKR, Ndi\params\VlanID, max, 0, "4095"
HKR, Ndi\params\VlanID, step, 0, "1"
HKR, Ndi\params\VlanID, base, 0, "10"
[NVNET_Service_Inst]
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\nvnet.sys
LoadOrderGroup = NDIS
[NVNET_EventLog]
AddReg = NVNET_EventLog_AddReg
[NVNET_EventLog_AddReg]
HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
HKR, , TypesSupported, 0x00010001, 7
;-------------------------------- STRINGS -------------------------------
[Strings]
ReactOS = "ReactOS Team"
nVidiaMfg = "nVidia"
OM = "Optimization Mode"
M1 = "Dynamic"
M2 = "CPU"
M3 = "Throughput"
NA = "Network Address"
SD = "Speed & Duplex"
Auto = "Auto"
CO = "Checksum Offload"
LS = "Large Send Offload"
FC = "Flow Control"
FRx = "Rx Pause"
FTx = "Tx Pause"
FBoth = "Rx & Tx Pause"
No = "No"
Yes = "Yes"
PP = "Packet Priority"
VT = "VLAN Tagging"
VI = "VLAN ID"
JF = "Jumbo Frame"
NVNET.DeviceDesc = "nVidia nForce PCI Ethernet Controller"
[Strings.0419]
ReactOS = "Команда ReactOS"
OM = "Оптимизировать"
M1 = "Динамически"
M2 = "Нагрузку на ЦП"
M3 = "Пропускную способность"
NA = "Сетевой адрес"
SD = "Скорость и дуплекс"
Auto = "Авто"
CO = "Разгрузка контрольной суммы"
LS = "Разгрузка при большой отправке"
FC = "Управление потоком"
FRx = "Кадры паузы приема"
FTx = "Кадры паузы передачи"
FBoth = "Кадры паузы приема и передачи"
No = "Нет"
Yes = "Да"
PP = "Приоритет кадров"
VT = "Маркировка кадров"
JF = "Кадры большого размера"
NVNET.DeviceDesc = "nVidia nForce PCI сетевой контроллер"

View file

@ -0,0 +1,927 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: NIC support code
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
/*
* HW access code was taken from the Linux forcedeth driver
* Copyright (C) 2003,4,5 Manfred Spraul
* Copyright (C) 2004 Andrew de Quincey
* Copyright (C) 2004 Carl-Daniel Hailfinger
* Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA Corporation
*/
/* INCLUDES *******************************************************************/
#include "nvnet.h"
#define NDEBUG
#include "debug.h"
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
VOID
NvNetClearStatisticsCounters(
_In_ PNVNET_ADAPTER Adapter)
{
NVNET_REGISTER Counter, CounterEnd;
PAGED_CODE();
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
if (Adapter->Features & DEV_HAS_STATISTICS_V2)
CounterEnd = NvRegRxDropFrame;
else
CounterEnd = NvRegRxBroadcast;
for (Counter = NvRegTxCnt; Counter <= CounterEnd; Counter += sizeof(ULONG))
{
NV_READ(Adapter, Counter);
}
if (Adapter->Features & DEV_HAS_STATISTICS_V3)
{
NV_READ(Adapter, NvRegTxUnicast);
NV_READ(Adapter, NvRegTxMulticast);
NV_READ(Adapter, NvRegTxBroadcast);
}
}
static
CODE_SEG("PAGE")
VOID
NvNetResetMac(
_In_ PNVNET_ADAPTER Adapter)
{
ULONG Temp[3];
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
if (!(Adapter->Features & DEV_HAS_POWER_CNTRL))
return;
NV_WRITE(Adapter, NvRegTxRxControl,
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
/* Save registers since they will be cleared on reset */
Temp[0] = NV_READ(Adapter, NvRegMacAddrA);
Temp[1] = NV_READ(Adapter, NvRegMacAddrB);
Temp[2] = NV_READ(Adapter, NvRegTransmitPoll);
NV_WRITE(Adapter, NvRegMacReset, NVREG_MAC_RESET_ASSERT);
NdisStallExecution(NV_MAC_RESET_DELAY);
NV_WRITE(Adapter, NvRegMacReset, 0);
NdisStallExecution(NV_MAC_RESET_DELAY);
/* Restore saved registers */
NV_WRITE(Adapter, NvRegMacAddrA, Temp[0]);
NV_WRITE(Adapter, NvRegMacAddrB, Temp[1]);
NV_WRITE(Adapter, NvRegTransmitPoll, Temp[2]);
NV_WRITE(Adapter, NvRegTxRxControl,
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2);
}
VOID
NvNetResetReceiverAndTransmitter(
_In_ PNVNET_ADAPTER Adapter)
{
NV_WRITE(Adapter, NvRegTxRxControl,
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
NdisStallExecution(NV_TXRX_RESET_DELAY);
NV_WRITE(Adapter, NvRegTxRxControl,
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2);
}
VOID
NvNetStartReceiver(
_In_ PNVNET_ADAPTER Adapter)
{
ULONG RxControl;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
RxControl = NV_READ(Adapter, NvRegReceiverControl);
if ((NV_READ(Adapter, NvRegReceiverControl) & NVREG_RCVCTL_START) &&
!(Adapter->Flags & NV_MAC_IN_USE))
{
/* Already running? Stop it */
RxControl &= ~NVREG_RCVCTL_START;
NV_WRITE(Adapter, NvRegReceiverControl, RxControl);
}
NV_WRITE(Adapter, NvRegLinkSpeed, Adapter->LinkSpeed | NVREG_LINKSPEED_FORCE);
RxControl |= NVREG_RCVCTL_START;
if (Adapter->Flags & NV_MAC_IN_USE)
{
RxControl &= ~NVREG_RCVCTL_RX_PATH_EN;
}
NV_WRITE(Adapter, NvRegReceiverControl, RxControl);
}
VOID
NvNetStartTransmitter(
_In_ PNVNET_ADAPTER Adapter)
{
ULONG TxControl;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
TxControl = NV_READ(Adapter, NvRegTransmitterControl);
TxControl |= NVREG_XMITCTL_START;
if (Adapter->Flags & NV_MAC_IN_USE)
{
TxControl &= ~NVREG_XMITCTL_TX_PATH_EN;
}
NV_WRITE(Adapter, NvRegTransmitterControl, TxControl);
}
VOID
NvNetStopReceiver(
_In_ PNVNET_ADAPTER Adapter)
{
ULONG RxControl, i;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
RxControl = NV_READ(Adapter, NvRegReceiverControl);
if (!(Adapter->Flags & NV_MAC_IN_USE))
RxControl &= ~NVREG_RCVCTL_START;
else
RxControl |= NVREG_RCVCTL_RX_PATH_EN;
NV_WRITE(Adapter, NvRegReceiverControl, RxControl);
for (i = 0; i < NV_RXSTOP_DELAY1MAX; ++i)
{
if (!(NV_READ(Adapter, NvRegReceiverStatus) & NVREG_RCVSTAT_BUSY))
break;
NdisStallExecution(NV_RXSTOP_DELAY1);
}
NdisStallExecution(NV_RXSTOP_DELAY2);
if (!(Adapter->Flags & NV_MAC_IN_USE))
{
NV_WRITE(Adapter, NvRegLinkSpeed, 0);
}
}
VOID
NvNetStopTransmitter(
_In_ PNVNET_ADAPTER Adapter)
{
ULONG TxControl, i;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
TxControl = NV_READ(Adapter, NvRegTransmitterControl);
if (!(Adapter->Flags & NV_MAC_IN_USE))
TxControl &= ~NVREG_XMITCTL_START;
else
TxControl |= NVREG_XMITCTL_TX_PATH_EN;
NV_WRITE(Adapter, NvRegTransmitterControl, TxControl);
for (i = 0; i < NV_TXSTOP_DELAY1MAX; ++i)
{
if (!(NV_READ(Adapter, NvRegTransmitterStatus) & NVREG_XMITSTAT_BUSY))
break;
NdisStallExecution(NV_TXSTOP_DELAY1);
}
NdisStallExecution(NV_TXSTOP_DELAY2);
if (!(Adapter->Flags & NV_MAC_IN_USE))
{
NV_WRITE(Adapter, NvRegTransmitPoll,
NV_READ(Adapter, NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV);
}
}
CODE_SEG("PAGE")
VOID
NvNetIdleTransmitter(
_In_ PNVNET_ADAPTER Adapter,
_In_ BOOLEAN ClearPhyControl)
{
ULONG i;
PAGED_CODE();
if (ClearPhyControl)
{
NV_WRITE(Adapter, NvRegAdapterControl,
NV_READ(Adapter, NvRegAdapterControl) & ~NVREG_ADAPTCTL_RUNNING);
}
else
{
NV_WRITE(Adapter, NvRegAdapterControl,
(Adapter->PhyAddress << NVREG_ADAPTCTL_PHYSHIFT) |
NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING);
}
NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_BIT2);
for (i = 0; i < NV_TXIDLE_ATTEMPTS; ++i)
{
if (NV_READ(Adapter, NvRegTxRxControl) & NVREG_TXRXCTL_IDLE)
break;
NdisStallExecution(NV_TXIDLE_DELAY);
}
}
VOID
NvNetUpdatePauseFrame(
_Inout_ PNVNET_ADAPTER Adapter,
_In_ ULONG PauseFlags)
{
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
Adapter->PauseFlags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE);
if (Adapter->PauseFlags & NV_PAUSEFRAME_RX_CAPABLE)
{
ULONG PacketFilter = NV_READ(Adapter, NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX;
if (PauseFlags & NV_PAUSEFRAME_RX_ENABLE)
{
PacketFilter |= NVREG_PFF_PAUSE_RX;
Adapter->PauseFlags |= NV_PAUSEFRAME_RX_ENABLE;
}
NV_WRITE(Adapter, NvRegPacketFilterFlags, PacketFilter);
}
if (Adapter->PauseFlags & NV_PAUSEFRAME_TX_CAPABLE)
{
ULONG Mics = NV_READ(Adapter, NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX;
if (PauseFlags & NV_PAUSEFRAME_TX_ENABLE)
{
ULONG PauseEnable = NVREG_TX_PAUSEFRAME_ENABLE_V1;
if (Adapter->Features & DEV_HAS_PAUSEFRAME_TX_V2)
PauseEnable = NVREG_TX_PAUSEFRAME_ENABLE_V2;
if (Adapter->Features & DEV_HAS_PAUSEFRAME_TX_V3)
{
PauseEnable = NVREG_TX_PAUSEFRAME_ENABLE_V3;
/* Limit the number of TX pause frames to a default of 8 */
NV_WRITE(Adapter,
NvRegTxPauseFrameLimit,
NV_READ(Adapter, NvRegTxPauseFrameLimit) |
NVREG_TX_PAUSEFRAMELIMIT_ENABLE);
}
NV_WRITE(Adapter, NvRegTxPauseFrame, PauseEnable);
NV_WRITE(Adapter, NvRegMisc1, Mics | NVREG_MISC1_PAUSE_TX);
Adapter->PauseFlags |= NV_PAUSEFRAME_TX_ENABLE;
}
else
{
NV_WRITE(Adapter, NvRegTxPauseFrame, NVREG_TX_PAUSEFRAME_DISABLE);
NV_WRITE(Adapter, NvRegMisc1, Mics);
}
}
}
VOID
NvNetToggleClockPowerGating(
_In_ PNVNET_ADAPTER Adapter,
_In_ BOOLEAN Gate)
{
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
if (!(Adapter->Flags & NV_MAC_IN_USE) && (Adapter->Features & DEV_HAS_POWER_CNTRL))
{
ULONG PowerState = NV_READ(Adapter, NvRegPowerState2);
if (Gate)
PowerState |= NVREG_POWERSTATE2_GATE_CLOCKS;
else
PowerState &= ~NVREG_POWERSTATE2_GATE_CLOCKS;
NV_WRITE(Adapter, NvRegPowerState2, PowerState);
}
}
VOID
NTAPI
NvNetMediaDetectionDpc(
_In_ PVOID SystemSpecific1,
_In_ PVOID FunctionContext,
_In_ PVOID SystemSpecific2,
_In_ PVOID SystemSpecific3)
{
PNVNET_ADAPTER Adapter = FunctionContext;
BOOLEAN Connected, Report = FALSE;
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
NdisDprAcquireSpinLock(&Adapter->Lock);
Connected = NvNetUpdateLinkSpeed(Adapter);
if (Adapter->Connected != Connected)
{
Adapter->Connected = Connected;
Report = TRUE;
if (Connected)
{
/* Link up */
NvNetToggleClockPowerGating(Adapter, FALSE);
NdisDprAcquireSpinLock(&Adapter->Receive.Lock);
NvNetStartReceiver(Adapter);
}
else
{
/* Link down */
NvNetToggleClockPowerGating(Adapter, TRUE);
NdisDprAcquireSpinLock(&Adapter->Receive.Lock);
NvNetStopReceiver(Adapter);
}
NdisDprReleaseSpinLock(&Adapter->Receive.Lock);
}
NdisDprReleaseSpinLock(&Adapter->Lock);
if (Report)
{
NdisMIndicateStatus(Adapter->AdapterHandle,
Connected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
NULL,
0);
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
}
}
BOOLEAN
NTAPI
NvNetInitPhaseSynchronized(
_In_ PVOID SynchronizeContext)
{
PNVNET_ADAPTER Adapter = SynchronizeContext;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
/* Enable interrupts on the NIC */
NvNetApplyInterruptMask(Adapter);
/*
* One manual link speed update: Interrupts are enabled,
* future link speed changes cause interrupts.
*/
NV_READ(Adapter, NvRegMIIStatus);
NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_ALL);
/* Set link speed to invalid value, thus force NvNetUpdateLinkSpeed() to init HW */
Adapter->LinkSpeed = 0xFFFFFFFF;
Adapter->Connected = NvNetUpdateLinkSpeed(Adapter);
NvNetStartReceiver(Adapter);
NvNetStartTransmitter(Adapter);
Adapter->Flags |= NV_ACTIVE;
return TRUE;
}
CODE_SEG("PAGE")
NDIS_STATUS
NvNetInitNIC(
_In_ PNVNET_ADAPTER Adapter,
_In_ BOOLEAN InitPhy)
{
ULONG MiiControl, i;
NDIS_STATUS Status;
PAGED_CODE();
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
/* Disable WOL */
NV_WRITE(Adapter, NvRegWakeUpFlags, 0);
if (InitPhy)
{
Status = NvNetPhyInit(Adapter);
if (Status != NDIS_STATUS_SUCCESS)
{
return Status;
}
}
if (Adapter->PauseFlags & NV_PAUSEFRAME_TX_CAPABLE)
{
NV_WRITE(Adapter, NvRegTxPauseFrame, NVREG_TX_PAUSEFRAME_DISABLE);
}
/* Power up PHY */
MiiRead(Adapter, Adapter->PhyAddress, MII_CONTROL, &MiiControl);
MiiControl &= ~MII_CR_POWER_DOWN;
MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl);
NvNetToggleClockPowerGating(Adapter, FALSE);
NvNetResetMac(Adapter);
/* Clear multicast masks and addresses */
NV_WRITE(Adapter, NvRegMulticastAddrA, 0);
NV_WRITE(Adapter, NvRegMulticastAddrB, 0);
NV_WRITE(Adapter, NvRegMulticastMaskA, NVREG_MCASTMASKA_NONE);
NV_WRITE(Adapter, NvRegMulticastMaskB, NVREG_MCASTMASKB_NONE);
NV_WRITE(Adapter, NvRegTransmitterControl, 0);
NV_WRITE(Adapter, NvRegReceiverControl, 0);
NV_WRITE(Adapter, NvRegAdapterControl, 0);
NV_WRITE(Adapter, NvRegLinkSpeed, 0);
NV_WRITE(Adapter, NvRegTransmitPoll,
NV_READ(Adapter, NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV);
NvNetResetReceiverAndTransmitter(Adapter);
NV_WRITE(Adapter, NvRegUnknownSetupReg6, 0);
/* Receive descriptor ring buffer */
NV_WRITE(Adapter, NvRegRxRingPhysAddr,
NdisGetPhysicalAddressLow(Adapter->RbdPhys));
if (Adapter->Features & DEV_HAS_HIGH_DMA)
{
NV_WRITE(Adapter, NvRegRxRingPhysAddrHigh,
NdisGetPhysicalAddressHigh(Adapter->RbdPhys));
}
/* Transmit descriptor ring buffer */
NV_WRITE(Adapter, NvRegTxRingPhysAddr,
NdisGetPhysicalAddressLow(Adapter->TbdPhys));
if (Adapter->Features & DEV_HAS_HIGH_DMA)
{
NV_WRITE(Adapter, NvRegTxRingPhysAddrHigh,
NdisGetPhysicalAddressHigh(Adapter->TbdPhys));
}
/* Ring sizes */
NV_WRITE(Adapter, NvRegRingSizes,
(NVNET_RECEIVE_DESCRIPTORS - 1) << NVREG_RINGSZ_RXSHIFT |
(NVNET_TRANSMIT_DESCRIPTORS - 1) << NVREG_RINGSZ_TXSHIFT);
/* Set default link speed settings */
NV_WRITE(Adapter, NvRegLinkSpeed, NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10);
if (Adapter->Features & (DEV_HAS_HIGH_DMA | DEV_HAS_LARGEDESC))
NV_WRITE(Adapter, NvRegTxWatermark, NVREG_TX_WM_DESC2_3_DEFAULT);
else
NV_WRITE(Adapter, NvRegTxWatermark, NVREG_TX_WM_DESC1_DEFAULT);
NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl);
NV_WRITE(Adapter, NvRegVlanControl, Adapter->VlanControl);
NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_BIT1);
for (i = 0; i < NV_SETUP5_DELAYMAX; ++i)
{
if (NV_READ(Adapter, NvRegUnknownSetupReg5) & NVREG_UNKSETUP5_BIT31)
break;
NdisStallExecution(NV_SETUP5_DELAY);
}
NV_WRITE(Adapter, NvRegMIIMask, 0);
NV_WRITE(Adapter, NvRegIrqStatus, NVREG_IRQSTAT_MASK);
NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_ALL);
NV_WRITE(Adapter, NvRegMisc1, NVREG_MISC1_FORCE | NVREG_MISC1_HD);
NV_WRITE(Adapter, NvRegTransmitterStatus, NV_READ(Adapter, NvRegTransmitterStatus));
NV_WRITE(Adapter, NvRegPacketFilterFlags, NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR);
NV_WRITE(Adapter, NvRegOffloadConfig, (NVNET_MAXIMUM_FRAME_SIZE - sizeof(ETH_HEADER))
+ NV_RX_HEADERS);
NV_WRITE(Adapter, NvRegReceiverStatus, NV_READ(Adapter, NvRegReceiverStatus));
NvNetBackoffSetSlotTime(Adapter);
NV_WRITE(Adapter, NvRegTxDeferral, NVREG_TX_DEFERRAL_DEFAULT);
NV_WRITE(Adapter, NvRegRxDeferral, NVREG_RX_DEFERRAL_DEFAULT);
if (Adapter->OptimizationMode == NV_OPTIMIZATION_MODE_THROUGHPUT)
NV_WRITE(Adapter, NvRegPollingInterval, NVREG_POLL_DEFAULT_THROUGHPUT);
else
NV_WRITE(Adapter, NvRegPollingInterval, NVREG_POLL_DEFAULT_CPU);
NV_WRITE(Adapter, NvRegUnknownSetupReg6, NVREG_UNKSETUP6_VAL);
NV_WRITE(Adapter, NvRegAdapterControl,
(Adapter->PhyAddress << NVREG_ADAPTCTL_PHYSHIFT) |
NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING);
NV_WRITE(Adapter, NvRegMIISpeed, NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY);
NV_WRITE(Adapter, NvRegMIIMask, NVREG_MII_LINKCHANGE);
NdisStallExecution(10);
NV_WRITE(Adapter, NvRegPowerState,
NV_READ(Adapter, NvRegPowerState) & ~NVREG_POWERSTATE_VALID);
if (Adapter->Features & DEV_HAS_STATISTICS_COUNTERS)
{
NvNetClearStatisticsCounters(Adapter);
}
return NDIS_STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NDIS_STATUS
NvNetGetPermanentMacAddress(
_Inout_ PNVNET_ADAPTER Adapter,
_Out_writes_bytes_all_(ETH_LENGTH_OF_ADDRESS) PUCHAR MacAddress)
{
ULONG Temp[2], TxPoll;
PAGED_CODE();
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
Temp[0] = NV_READ(Adapter, NvRegMacAddrA);
Temp[1] = NV_READ(Adapter, NvRegMacAddrB);
TxPoll = NV_READ(Adapter, NvRegTransmitPoll);
if (Adapter->Features & DEV_HAS_CORRECT_MACADDR)
{
/* MAC address is already in the correct order */
MacAddress[0] = (Temp[0] >> 0) & 0xFF;
MacAddress[1] = (Temp[0] >> 8) & 0xFF;
MacAddress[2] = (Temp[0] >> 16) & 0xFF;
MacAddress[3] = (Temp[0] >> 24) & 0xFF;
MacAddress[4] = (Temp[1] >> 0) & 0xFF;
MacAddress[5] = (Temp[1] >> 8) & 0xFF;
}
/* Handle the special flag for the correct MAC address order */
else if (TxPoll & NVREG_TRANSMITPOLL_MAC_ADDR_REV)
{
/* MAC address is already in the correct order */
MacAddress[0] = (Temp[0] >> 0) & 0xFF;
MacAddress[1] = (Temp[0] >> 8) & 0xFF;
MacAddress[2] = (Temp[0] >> 16) & 0xFF;
MacAddress[3] = (Temp[0] >> 24) & 0xFF;
MacAddress[4] = (Temp[1] >> 0) & 0xFF;
MacAddress[5] = (Temp[1] >> 8) & 0xFF;
/*
* Set original MAC address back to the reversed version.
* This flag will be cleared during low power transition.
* Therefore, we should always put back the reversed address.
*/
Temp[0] = (MacAddress[5] << 0) | (MacAddress[4] << 8) |
(MacAddress[3] << 16) | (MacAddress[2] << 24);
Temp[1] = (MacAddress[1] << 0) | (MacAddress[0] << 8);
}
else
{
/* Need to reverse MAC address to the correct order */
MacAddress[0] = (Temp[1] >> 8) & 0xFF;
MacAddress[1] = (Temp[1] >> 0) & 0xFF;
MacAddress[2] = (Temp[0] >> 24) & 0xFF;
MacAddress[3] = (Temp[0] >> 16) & 0xFF;
MacAddress[4] = (Temp[0] >> 8) & 0xFF;
MacAddress[5] = (Temp[0] >> 0) & 0xFF;
/*
* Use a flag to signal the driver whether the MAC address was already corrected,
* so that it is not reversed again on a subsequent initialize.
*/
NV_WRITE(Adapter, NvRegTransmitPoll, TxPoll | NVREG_TRANSMITPOLL_MAC_ADDR_REV);
}
Adapter->OriginalMacAddress[0] = Temp[0];
Adapter->OriginalMacAddress[1] = Temp[1];
NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
MacAddress[0],
MacAddress[1],
MacAddress[2],
MacAddress[3],
MacAddress[4],
MacAddress[5]));
if (ETH_IS_MULTICAST(MacAddress) || ETH_IS_EMPTY(MacAddress))
return NDIS_STATUS_INVALID_ADDRESS;
return NDIS_STATUS_SUCCESS;
}
CODE_SEG("PAGE")
VOID
NvNetSetupMacAddress(
_In_ PNVNET_ADAPTER Adapter,
_In_reads_bytes_(ETH_LENGTH_OF_ADDRESS) PUCHAR MacAddress)
{
PAGED_CODE();
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
NV_WRITE(Adapter, NvRegMacAddrA,
MacAddress[3] << 24 | MacAddress[2] << 16 | MacAddress[1] << 8 | MacAddress[0]);
NV_WRITE(Adapter, NvRegMacAddrB, MacAddress[5] << 8 | MacAddress[4]);
}
static
VOID
CODE_SEG("PAGE")
NvNetValidateConfiguration(
_Inout_ PNVNET_ADAPTER Adapter)
{
PAGED_CODE();
if (!(Adapter->Features & DEV_HAS_LARGEDESC))
{
Adapter->MaximumFrameSize = NVNET_MAXIMUM_FRAME_SIZE;
}
if (!(Adapter->Features & DEV_HAS_CHECKSUM))
{
Adapter->Flags &= ~(NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND);
}
if (!(Adapter->Features & DEV_HAS_VLAN))
{
Adapter->Flags &= ~(NV_PACKET_PRIORITY | NV_VLAN_TAGGING);
}
if ((Adapter->Features & DEV_NEED_TIMERIRQ) &&
(Adapter->OptimizationMode == NV_OPTIMIZATION_MODE_DYNAMIC))
{
Adapter->OptimizationMode = NV_OPTIMIZATION_MODE_THROUGHPUT;
}
if (!(Adapter->Features & DEV_HAS_TX_PAUSEFRAME))
{
if (Adapter->FlowControlMode == NV_FLOW_CONTROL_TX)
{
Adapter->FlowControlMode = NV_FLOW_CONTROL_AUTO;
}
else if (Adapter->FlowControlMode == NV_FLOW_CONTROL_RX_TX)
{
Adapter->FlowControlMode = NV_FLOW_CONTROL_RX;
}
}
}
CODE_SEG("PAGE")
NDIS_STATUS
NvNetRecognizeHardware(
_Inout_ PNVNET_ADAPTER Adapter)
{
ULONG Bytes;
PCI_COMMON_CONFIG PciConfig;
PAGED_CODE();
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
Bytes = NdisReadPciSlotInformation(Adapter->AdapterHandle,
0,
FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID),
&PciConfig,
PCI_COMMON_HDR_LENGTH);
if (Bytes != PCI_COMMON_HDR_LENGTH)
return NDIS_STATUS_ADAPTER_NOT_FOUND;
if (PciConfig.VendorID != 0x10DE)
return NDIS_STATUS_ADAPTER_NOT_FOUND;
Adapter->DeviceId = PciConfig.DeviceID;
Adapter->RevisionId = PciConfig.RevisionID;
switch (PciConfig.DeviceID)
{
case 0x01C3: /* nForce */
case 0x0066: /* nForce2 */
case 0x00D6: /* nForce2 */
Adapter->Features = DEV_NEED_TIMERIRQ | DEV_NEED_LINKTIMER;
break;
case 0x0086: /* nForce3 */
case 0x008C: /* nForce3 */
case 0x00E6: /* nForce3 */
case 0x00DF: /* nForce3 */
Adapter->Features = DEV_NEED_TIMERIRQ | DEV_NEED_LINKTIMER |
DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM;
break;
case 0x0056: /* CK804 */
case 0x0057: /* CK804 */
case 0x0037: /* MCP04 */
case 0x0038: /* MCP04 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
DEV_HAS_HIGH_DMA | DEV_HAS_STATISTICS_V1 | DEV_NEED_TX_LIMIT;
break;
case 0x0268: /* MCP51 */
case 0x0269: /* MCP51 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
DEV_HAS_STATISTICS_V1 | DEV_NEED_LOW_POWER_FIX;
break;
case 0x0372: /* MCP55 */
case 0x0373: /* MCP55 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
DEV_HAS_HIGH_DMA | DEV_HAS_VLAN | DEV_HAS_MSI | DEV_HAS_MSI_X |
DEV_HAS_POWER_CNTRL | DEV_HAS_PAUSEFRAME_TX_V1 |
DEV_HAS_STATISTICS_V1 | DEV_HAS_STATISTICS_V2 |
DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
DEV_NEED_TX_LIMIT | DEV_NEED_MSI_FIX;
break;
case 0x03E5: /* MCP61 */
case 0x03E6: /* MCP61 */
case 0x03EE: /* MCP61 */
case 0x03EF: /* MCP61 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 | DEV_HAS_STATISTICS_V1 |
DEV_HAS_STATISTICS_V2 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
DEV_HAS_CORRECT_MACADDR | DEV_NEED_MSI_FIX;
break;
case 0x0450: /* MCP65 */
case 0x0451: /* MCP65 */
case 0x0452: /* MCP65 */
case 0x0453: /* MCP65 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_HIGH_DMA |
DEV_HAS_POWER_CNTRL | DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 |
DEV_HAS_STATISTICS_V1 | DEV_HAS_STATISTICS_V2 |
DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
DEV_HAS_CORRECT_MACADDR | DEV_NEED_TX_LIMIT |
DEV_HAS_GEAR_MODE | DEV_NEED_MSI_FIX;
break;
case 0x054C: /* MCP67 */
case 0x054D: /* MCP67 */
case 0x054E: /* MCP67 */
case 0x054F: /* MCP67 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 | DEV_HAS_STATISTICS_V1 |
DEV_HAS_STATISTICS_V2 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
DEV_HAS_CORRECT_MACADDR | DEV_HAS_GEAR_MODE | DEV_NEED_MSI_FIX;
break;
case 0x07DC: /* MCP73 */
case 0x07DD: /* MCP73 */
case 0x07DE: /* MCP73 */
case 0x07DF: /* MCP73 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_HIGH_DMA | DEV_HAS_POWER_CNTRL |
DEV_HAS_MSI | DEV_HAS_PAUSEFRAME_TX_V1 | DEV_HAS_STATISTICS_V1 |
DEV_HAS_STATISTICS_V2 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
DEV_HAS_CORRECT_MACADDR | DEV_HAS_COLLISION_FIX |
DEV_HAS_GEAR_MODE | DEV_NEED_MSI_FIX;
break;
case 0x0760: /* MCP77 */
case 0x0761: /* MCP77 */
case 0x0762: /* MCP77 */
case 0x0763: /* MCP77 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_CHECKSUM | DEV_HAS_HIGH_DMA |
DEV_HAS_MSI | DEV_HAS_POWER_CNTRL | DEV_HAS_PAUSEFRAME_TX_V2 |
DEV_HAS_STATISTICS_V1 | DEV_HAS_STATISTICS_V2 |
DEV_HAS_STATISTICS_V3 | DEV_HAS_TEST_EXTENDED | DEV_HAS_MGMT_UNIT |
DEV_HAS_CORRECT_MACADDR | DEV_HAS_COLLISION_FIX |
DEV_NEED_TX_LIMIT2 | DEV_HAS_GEAR_MODE |
DEV_NEED_PHY_INIT_FIX | DEV_NEED_MSI_FIX;
break;
case 0x0AB0: /* MCP79 */
case 0x0AB1: /* MCP79 */
case 0x0AB2: /* MCP79 */
case 0x0AB3: /* MCP79 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
DEV_HAS_HIGH_DMA | DEV_HAS_MSI | DEV_HAS_POWER_CNTRL |
DEV_HAS_PAUSEFRAME_TX_V3 | DEV_HAS_STATISTICS_V1 |
DEV_HAS_STATISTICS_V2 | DEV_HAS_STATISTICS_V3 |
DEV_HAS_TEST_EXTENDED | DEV_HAS_CORRECT_MACADDR |
DEV_HAS_COLLISION_FIX | DEV_NEED_TX_LIMIT2 |
DEV_HAS_GEAR_MODE | DEV_NEED_PHY_INIT_FIX | DEV_NEED_MSI_FIX;
break;
case 0x0D7D: /* MCP89 */
Adapter->Features = DEV_NEED_LINKTIMER | DEV_HAS_LARGEDESC | DEV_HAS_CHECKSUM |
DEV_HAS_HIGH_DMA | DEV_HAS_MSI | DEV_HAS_POWER_CNTRL |
DEV_HAS_PAUSEFRAME_TX_V3 | DEV_HAS_STATISTICS_V1 |
DEV_HAS_STATISTICS_V2 | DEV_HAS_STATISTICS_V3 |
DEV_HAS_TEST_EXTENDED | DEV_HAS_CORRECT_MACADDR |
DEV_HAS_COLLISION_FIX | DEV_HAS_GEAR_MODE | DEV_NEED_PHY_INIT_FIX;
break;
default:
return NDIS_STATUS_NOT_RECOGNIZED;
}
/* Normalize all .INF parameters */
NvNetValidateConfiguration(Adapter);
/* FIXME: Disable some NIC features, we don't support these yet */
#if 1
Adapter->VlanControl = 0;
Adapter->Flags &= ~(NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND |
NV_PACKET_PRIORITY | NV_VLAN_TAGGING);
#endif
/* For code paths debugging (32-bit descriptors work on all hardware variants) */
#if 0
Adapter->Features &= ~(DEV_HAS_HIGH_DMA | DEV_HAS_LARGEDESC);
#endif
if (Adapter->Features & DEV_HAS_POWER_CNTRL)
Adapter->WakeFrameBitmap = ~(0xFFFFFFFF << NV_WAKEUPPATTERNS_V2);
else
Adapter->WakeFrameBitmap = ~(0xFFFFFFFF << NV_WAKEUPPATTERNS);
/* 64-bit descriptors */
if (Adapter->Features & DEV_HAS_HIGH_DMA)
{
/* Note: Some devices here also support Jumbo Frames */
Adapter->TxRxControl = NVREG_TXRXCTL_DESC_3;
}
/* 32-bit descriptors */
else
{
if (Adapter->Features & DEV_HAS_LARGEDESC)
{
/* Jumbo Frames */
Adapter->TxRxControl = NVREG_TXRXCTL_DESC_2;
}
else
{
/* Original packet format */
Adapter->TxRxControl = NVREG_TXRXCTL_DESC_1;
}
}
/* Flow control */
Adapter->PauseFlags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
if (Adapter->Features & DEV_HAS_TX_PAUSEFRAME)
{
Adapter->PauseFlags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ;
}
if (Adapter->FlowControlMode != NV_FLOW_CONTROL_AUTO)
{
Adapter->PauseFlags &= ~(NV_PAUSEFRAME_AUTONEG | NV_PAUSEFRAME_RX_REQ |
NV_PAUSEFRAME_TX_REQ);
switch (Adapter->FlowControlMode)
{
case NV_FLOW_CONTROL_RX:
Adapter->PauseFlags |= NV_PAUSEFRAME_RX_REQ;
break;
case NV_FLOW_CONTROL_TX:
Adapter->PauseFlags |= NV_PAUSEFRAME_TX_REQ;
break;
case NV_FLOW_CONTROL_RX_TX:
Adapter->PauseFlags |= NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_TX_REQ;
break;
default:
break;
}
}
/* Work around errata in some NICs */
if (Adapter->Features & (DEV_NEED_TX_LIMIT | DEV_NEED_TX_LIMIT2))
{
Adapter->Flags |= NV_SEND_ERRATA_PRESENT;
if ((Adapter->Features & DEV_NEED_TX_LIMIT2) && Adapter->RevisionId >= 0xA2)
{
Adapter->Flags &= ~NV_SEND_ERRATA_PRESENT;
}
}
if (Adapter->Flags & NV_SEND_ERRATA_PRESENT)
{
NDIS_DbgPrint(MIN_TRACE, ("Transmit workaround active\n"));
}
/* Initialize the interrupt mask */
if (Adapter->OptimizationMode == NV_OPTIMIZATION_MODE_CPU)
{
Adapter->InterruptMask = NVREG_IRQMASK_CPU;
}
else
{
Adapter->InterruptMask = NVREG_IRQMASK_THROUGHPUT;
}
if (Adapter->Features & DEV_NEED_TIMERIRQ)
{
Adapter->InterruptMask |= NVREG_IRQ_TIMER;
}
if (Adapter->Features & DEV_NEED_LINKTIMER)
{
NdisMInitializeTimer(&Adapter->MediaDetectionTimer,
Adapter->AdapterHandle,
NvNetMediaDetectionDpc,
Adapter);
}
return NDIS_STATUS_SUCCESS;
}

View file

@ -0,0 +1,567 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Hardware specific definitions
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
/*
* Definitions were taken from the Linux forcedeth driver
* Copyright (C) 2003,4,5 Manfred Spraul
* Copyright (C) 2004 Andrew de Quincey
* Copyright (C) 2004 Carl-Daniel Hailfinger
* Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA Corporation
*/
#pragma once
#define DEV_NEED_TIMERIRQ 0x00000001 /* Set the timer IRQ flag in the IRQ mask */
#define DEV_NEED_LINKTIMER 0x00000002 /* Poll link settings. Relies on the timer IRQ */
#define DEV_HAS_LARGEDESC 0x00000004 /* Device supports Jumbo Frames
* and needs packet format 2 */
#define DEV_HAS_HIGH_DMA 0x00000008 /* Device supports 64-bit DMA */
#define DEV_HAS_CHECKSUM 0x00000010 /* Device supports TX and RX checksum offloads */
#define DEV_HAS_VLAN 0x00000020 /* Device supports VLAN tagging and striping */
#define DEV_HAS_MSI 0x00000040 /* Device supports MSI */
#define DEV_HAS_MSI_X 0x00000080 /* Device supports MSI-X */
#define DEV_HAS_POWER_CNTRL 0x00000100 /* Device supports power savings */
#define DEV_HAS_STATISTICS_V1 0x00000200 /* Device supports HW statistics version 1 */
#define DEV_HAS_STATISTICS_V2 0x00000400 /* Device supports HW statistics version 2 */
#define DEV_HAS_STATISTICS_V3 0x00000800 /* Device supports HW statistics version 3 */
#define DEV_HAS_TEST_EXTENDED 0x00001000 /* Device supports extended diagnostic test */
#define DEV_HAS_MGMT_UNIT 0x00002000 /* Device supports management unit */
#define DEV_HAS_CORRECT_MACADDR 0x00004000 /* Device supports correct MAC address order */
#define DEV_HAS_COLLISION_FIX 0x00008000 /* Device supports TX collision fix */
#define DEV_HAS_PAUSEFRAME_TX_V1 0x00010000 /* Device supports TX pause frames version 1 */
#define DEV_HAS_PAUSEFRAME_TX_V2 0x00020000 /* Device supports TX pause frames version 2 */
#define DEV_HAS_PAUSEFRAME_TX_V3 0x00040000 /* Device supports TX pause frames version 3 */
#define DEV_NEED_TX_LIMIT 0x00080000 /* Device needs to limit TX */
#define DEV_NEED_TX_LIMIT2 0x00100000 /* Device needs to limit TX, expect for some revs */
#define DEV_HAS_GEAR_MODE 0x00200000 /* Device supports gear mode */
#define DEV_NEED_PHY_INIT_FIX 0x00400000 /* Device needs specific PHY workaround */
#define DEV_NEED_LOW_POWER_FIX 0x00800000 /* Device needs special power up workaround */
#define DEV_NEED_MSI_FIX 0x01000000 /* Device needs MSI workaround */
#define DEV_HAS_STATISTICS_COUNTERS (DEV_HAS_STATISTICS_V1 | DEV_HAS_STATISTICS_V2 | \
DEV_HAS_STATISTICS_V3)
#define DEV_HAS_TX_PAUSEFRAME (DEV_HAS_PAUSEFRAME_TX_V1 | DEV_HAS_PAUSEFRAME_TX_V2 | \
DEV_HAS_PAUSEFRAME_TX_V3)
typedef enum _NVNET_REGISTER
{
NvRegIrqStatus = 0x000,
#define NVREG_IRQSTAT_MIIEVENT 0x040
#define NVREG_IRQSTAT_MASK 0x83ff
NvRegIrqMask = 0x004,
#define NVREG_IRQ_RX_ERROR 0x0001
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERR 0x0008
#define NVREG_IRQ_TX_OK 0x0010
#define NVREG_IRQ_TIMER 0x0020
#define NVREG_IRQ_LINK 0x0040
#define NVREG_IRQ_RX_FORCED 0x0080
#define NVREG_IRQ_TX_FORCED 0x0100
#define NVREG_IRQ_RECOVER_ERROR 0x8200
#define NVREG_IRQMASK_THROUGHPUT 0x00df
#define NVREG_IRQMASK_CPU 0x0060
#define NVREG_IRQ_TX_ALL (NVREG_IRQ_TX_ERR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED)
#define NVREG_IRQ_RX_ALL (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF| \
NVREG_IRQ_RX_FORCED)
#define NVREG_IRQ_OTHER (NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RECOVER_ERROR)
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
NvRegPollingInterval = 0x00c,
#define NVREG_POLL_DEFAULT_THROUGHPUT 65535
#define NVREG_POLL_DEFAULT_CPU 13
NvRegMSIMap0 = 0x020,
NvRegMSIMap1 = 0x024,
NvRegMSIIrqMask = 0x030,
#define NVREG_MSI_VECTOR_0_ENABLED 0x01
NvRegMacReset = 0x34,
#define NVREG_MAC_RESET_ASSERT 0x0F3
NvRegMisc1 = 0x080,
#define NVREG_MISC1_PAUSE_TX 0x01
#define NVREG_MISC1_HD 0x02
#define NVREG_MISC1_FORCE 0x3b0f3c
NvRegTransmitterControl = 0x084,
#define NVREG_XMITCTL_START 0x01
#define NVREG_XMITCTL_MGMT_ST 0x40000000
#define NVREG_XMITCTL_SYNC_MASK 0x000f0000
#define NVREG_XMITCTL_SYNC_NOT_READY 0x0
#define NVREG_XMITCTL_SYNC_PHY_INIT 0x00040000
#define NVREG_XMITCTL_MGMT_SEMA_MASK 0x00000f00
#define NVREG_XMITCTL_MGMT_SEMA_FREE 0x0
#define NVREG_XMITCTL_HOST_SEMA_MASK 0x0000f000
#define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000
#define NVREG_XMITCTL_HOST_LOADED 0x00004000
#define NVREG_XMITCTL_TX_PATH_EN 0x01000000
#define NVREG_XMITCTL_DATA_START 0x00100000
#define NVREG_XMITCTL_DATA_READY 0x00010000
#define NVREG_XMITCTL_DATA_ERROR 0x00020000
NvRegTransmitterStatus = 0x088,
#define NVREG_XMITSTAT_BUSY 0x01
NvRegPacketFilterFlags = 0x8c,
#define NVREG_PFF_PAUSE_RX 0x08
#define NVREG_PFF_ALWAYS 0x7F0000
#define NVREG_PFF_PROMISC 0x80
#define NVREG_PFF_MYADDR 0x20
#define NVREG_PFF_LOOPBACK 0x10
NvRegOffloadConfig = 0x90,
#define NVREG_OFFLOAD_HOMEPHY 0x601
#define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE
NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START 0x01
#define NVREG_RCVCTL_RX_PATH_EN 0x01000000
NvRegReceiverStatus = 0x98,
#define NVREG_RCVSTAT_BUSY 0x01
NvRegSlotTime = 0x9c,
#define NVREG_SLOTTIME_LEGBF_ENABLED 0x80000000
#define NVREG_SLOTTIME_10_100_FULL 0x00007f00
#define NVREG_SLOTTIME_1000_FULL 0x0003ff00
#define NVREG_SLOTTIME_HALF 0x0000ff00
#define NVREG_SLOTTIME_DEFAULT 0x00007f00
#define NVREG_SLOTTIME_MASK 0x000000ff
NvRegTxDeferral = 0xA0,
#define NVREG_TX_DEFERRAL_DEFAULT 0x15050f
#define NVREG_TX_DEFERRAL_RGMII_10_100 0x16070f
#define NVREG_TX_DEFERRAL_RGMII_1000 0x14050f
#define NVREG_TX_DEFERRAL_RGMII_STRETCH_10 0x16190f
#define NVREG_TX_DEFERRAL_RGMII_STRETCH_100 0x16300f
#define NVREG_TX_DEFERRAL_MII_STRETCH 0x152000
NvRegRxDeferral = 0xA4,
#define NVREG_RX_DEFERRAL_DEFAULT 0x16
NvRegMacAddrA = 0xA8,
NvRegMacAddrB = 0xAC,
NvRegMulticastAddrA = 0xB0,
NvRegMulticastAddrB = 0xB4,
#define NVREG_MCASTADDRA_FORCE 0x01
NvRegMulticastMaskA = 0xB8,
#define NVREG_MCASTMASKA_NONE 0xffffffff
NvRegMulticastMaskB = 0xBC,
#define NVREG_MCASTMASKB_NONE 0xffff
NvRegPhyInterface = 0xC0,
#define PHY_100 0x1
#define PHY_1000 0x2
#define PHY_HALF 0x100
#define PHY_RGMII 0x10000000
NvRegBackOffControl = 0xC4,
#define NVREG_BKOFFCTRL_DEFAULT 0x70000000
#define NVREG_BKOFFCTRL_SEED_MASK 0x000003ff
#define NVREG_BKOFFCTRL_SELECT 24
#define NVREG_BKOFFCTRL_GEAR 12
NvRegTxRingPhysAddr = 0x100,
NvRegRxRingPhysAddr = 0x104,
NvRegRingSizes = 0x108,
#define NVREG_RINGSZ_TXSHIFT 0
#define NVREG_RINGSZ_RXSHIFT 16
NvRegTransmitPoll = 0x10c,
#define NVREG_TRANSMITPOLL_MAC_ADDR_REV 0x00008000
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
#define NVREG_LINKSPEED_10 1000
#define NVREG_LINKSPEED_100 100
#define NVREG_LINKSPEED_1000 50
#define NVREG_LINKSPEED_MASK (0xFFF)
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
NvRegTxWatermark = 0x13c,
#define NVREG_TX_WM_DESC1_DEFAULT 0x0200010
#define NVREG_TX_WM_DESC2_3_DEFAULT 0x1e08000
#define NVREG_TX_WM_DESC2_3_1000 0xfe08000
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
#define NVREG_TXRXCTL_BIT1 0x0002
#define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
#define NVREG_TXRXCTL_DESC_1 0
#define NVREG_TXRXCTL_DESC_2 0x002100
#define NVREG_TXRXCTL_DESC_3 0xc02200
#define NVREG_TXRXCTL_VLANSTRIP 0x00040
#define NVREG_TXRXCTL_VLANINS 0x00080
NvRegTxRingPhysAddrHigh = 0x148,
NvRegRxRingPhysAddrHigh = 0x14C,
NvRegTxPauseFrame = 0x170,
#define NVREG_TX_PAUSEFRAME_DISABLE 0x0fff0080
#define NVREG_TX_PAUSEFRAME_ENABLE_V1 0x01800010
#define NVREG_TX_PAUSEFRAME_ENABLE_V2 0x056003f0
#define NVREG_TX_PAUSEFRAME_ENABLE_V3 0x09f00880
NvRegTxPauseFrameLimit = 0x174,
#define NVREG_TX_PAUSEFRAMELIMIT_ENABLE 0x00010000
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
#define NVREG_MIISTAT_MASK_RW 0x0007
#define NVREG_MIISTAT_MASK_ALL 0x000f
NvRegMIIMask = 0x184,
#define NVREG_MII_LINKCHANGE 0x0008
NvRegAdapterControl = 0x188,
#define NVREG_ADAPTCTL_START 0x02
#define NVREG_ADAPTCTL_LINKUP 0x04
#define NVREG_ADAPTCTL_PHYVALID 0x40000
#define NVREG_ADAPTCTL_RUNNING 0x100000
#define NVREG_ADAPTCTL_PHYSHIFT 24
NvRegMIISpeed = 0x18c,
#define NVREG_MIISPEED_BIT8 (1<<8)
#define NVREG_MIIDELAY 5
NvRegMIIControl = 0x190,
#define NVREG_MIICTL_INUSE 0x08000
#define NVREG_MIICTL_WRITE 0x00400
#define NVREG_MIICTL_ADDRSHIFT 5
NvRegMIIData = 0x194,
NvRegTxUnicast = 0x1a0,
NvRegTxMulticast = 0x1a4,
NvRegTxBroadcast = 0x1a8,
NvRegWakeUpFlags = 0x200,
#define NVREG_WAKEUPFLAGS_VAL 0x7770
#define NVREG_WAKEUPFLAGS_BUSYSHIFT 24
#define NVREG_WAKEUPFLAGS_ENABLESHIFT 16
#define NVREG_WAKEUPFLAGS_D3SHIFT 12
#define NVREG_WAKEUPFLAGS_D2SHIFT 8
#define NVREG_WAKEUPFLAGS_D1SHIFT 4
#define NVREG_WAKEUPFLAGS_D0SHIFT 0
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
#define NVREG_WAKEUPFLAGS_ENABLE_MAGPAT 0x1111
#define NVREG_WAKEUPFLAGS_ENABLE_WAKEUPPAT 0x2222
#define NVREG_WAKEUPFLAGS_ENABLE_LINKCHANGE 0x4444
NvRegPatternCrc = 0x204,
NvRegPatternMask0 = 0x208,
NvRegPatternMask1 = 0x20C,
NvRegPatternMask2 = 0x210,
NvRegPatternMask3 = 0x214,
NvRegMgmtUnitGetVersion = 0x204,
#define NVREG_MGMTUNITGETVERSION 0x01
NvRegMgmtUnitVersion = 0x208,
#define NVREG_MGMTUNITVERSION 0x08
NvRegPowerCap = 0x268,
#define NVREG_POWERCAP_D3SUPP (1<<30)
#define NVREG_POWERCAP_D2SUPP (1<<26)
#define NVREG_POWERCAP_D1SUPP (1<<25)
NvRegPowerState = 0x26c,
#define NVREG_POWERSTATE_POWEREDUP 0x8000
#define NVREG_POWERSTATE_VALID 0x0100
#define NVREG_POWERSTATE_MASK 0x0003
#define NVREG_POWERSTATE_D0 0x0000
#define NVREG_POWERSTATE_D1 0x0001
#define NVREG_POWERSTATE_D2 0x0002
#define NVREG_POWERSTATE_D3 0x0003
NvRegMgmtUnitControl = 0x278,
#define NVREG_MGMTUNITCONTROL_INUSE 0x20000
NvRegTxCnt = 0x280,
NvRegTxZeroReXmt = 0x284,
NvRegTxOneReXmt = 0x288,
NvRegTxManyReXmt = 0x28c,
NvRegTxLateCol = 0x290,
NvRegTxUnderflow = 0x294,
NvRegTxLossCarrier = 0x298,
NvRegTxExcessDef = 0x29c,
NvRegTxRetryErr = 0x2a0,
NvRegRxFrameErr = 0x2a4,
NvRegRxExtraByte = 0x2a8,
NvRegRxLateCol = 0x2ac,
NvRegRxRunt = 0x2b0,
NvRegRxFrameTooLong = 0x2b4,
NvRegRxOverflow = 0x2b8,
NvRegRxFCSErr = 0x2bc,
NvRegRxFrameAlignErr = 0x2c0,
NvRegRxLenErr = 0x2c4,
NvRegRxUnicast = 0x2c8,
NvRegRxMulticast = 0x2cc,
NvRegRxBroadcast = 0x2d0,
NvRegTxDef = 0x2d4,
NvRegTxFrame = 0x2d8,
NvRegRxCnt = 0x2dc,
NvRegTxPause = 0x2e0,
NvRegRxPause = 0x2e4,
NvRegRxDropFrame = 0x2e8,
NvRegVlanControl = 0x300,
#define NVREG_VLANCONTROL_ENABLE 0x2000
NvRegMSIXMap0 = 0x3e0,
NvRegMSIXMap1 = 0x3e4,
NvRegMSIXIrqStatus = 0x3f0,
NvRegPowerState2 = 0x600,
#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F15
#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001
#define NVREG_POWERSTATE2_PHY_RESET 0x0004
#define NVREG_POWERSTATE2_GATE_CLOCK_1 0x0100
#define NVREG_POWERSTATE2_GATE_CLOCK_2 0x0200
#define NVREG_POWERSTATE2_GATE_CLOCK_3 0x0400
#define NVREG_POWERSTATE2_GATE_CLOCKS 0x0F00
#define NVREG_POWERSTATE2_WAKEUPPAT_5 (1<<16)
#define NVREG_POWERSTATE2_WAKEUPPAT_6 (1<<17)
#define NVREG_POWERSTATE2_WAKEUPPAT_7 (1<<18)
NvRegPatternCrcEx = 0x604,
NvRegPatternMask0Ex = 0x608,
NvRegPatternMask1Ex = 0x60C,
NvRegPatternMask2Ex = 0x610,
NvRegPatternMask3Ex = 0x614
} NVNET_REGISTER;
#include <pshpack1.h>
typedef struct _NVNET_DESCRIPTOR_32
{
ULONG Address;
ULONG FlagsLength;
} NVNET_DESCRIPTOR_32, *PNVNET_DESCRIPTOR_32;
typedef struct _NVNET_DESCRIPTOR_64
{
ULONG AddressHigh;
ULONG AddressLow;
ULONG VlanTag;
ULONG FlagsLength;
} NVNET_DESCRIPTOR_64, *PNVNET_DESCRIPTOR_64;
#include <poppack.h>
#define FLAG_MASK_V1 0xffff0000
#define FLAG_MASK_V2 0xffffc000
#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
#define LEN_MASK_V2 (0xffffffff ^ FLAG_MASK_V2)
#define NV_TX_LASTPACKET (1<<16)
#define NV_TX_RETRYERROR (1<<19)
#define NV_TX_RETRYCOUNT_MASK (0xF<<20)
#define NV_TX_ONE_RETRY (1<<20)
#define NV_TX_FORCED_INTERRUPT (1<<24)
#define NV_TX_DEFERRED (1<<26)
#define NV_TX_CARRIERLOST (1<<27)
#define NV_TX_LATECOLLISION (1<<28)
#define NV_TX_UNDERFLOW (1<<29)
#define NV_TX_ERROR (1<<30)
#define NV_TX_VALID (1<<31)
#define NV_TX2_LASTPACKET (1<<29)
#define NV_TX2_RETRYERROR (1<<18)
#define NV_TX2_RETRYCOUNT_MASK (0xF<<19)
#define NV_TX2_FORCED_INTERRUPT (1<<30)
#define NV_TX2_DEFERRED (1<<25)
#define NV_TX2_CARRIERLOST (1<<26)
#define NV_TX2_LATECOLLISION (1<<27)
#define NV_TX2_UNDERFLOW (1<<28)
/* Error and valid are the same for both */
#define NV_TX2_ERROR (1<<30)
#define NV_TX2_VALID (1<<31)
#define NV_TX2_TSO (1<<28)
#define NV_TX2_TSO_SHIFT 14
#define NV_TX2_TSO_MAX_SHIFT 14
#define NV_TX2_CHECKSUM_L3 (1<<27)
#define NV_TX2_CHECKSUM_L4 (1<<26)
#define NV_MAXIMUM_SG_SIZE (1<<NV_TX2_TSO_MAX_SHIFT)
#define NV_TX3_VLAN_TAG_PRESENT (1<<18)
#define NV_RX_DESCRIPTORVALID (1<<16)
#define NV_RX_MISSEDFRAME (1<<17)
#define NV_RX_SUBTRACT1 (1<<18)
#define NV_RX_ERROR1 (1<<23)
#define NV_RX_ERROR2 (1<<24)
#define NV_RX_ERROR3 (1<<25)
#define NV_RX_ERROR4 (1<<26)
#define NV_RX_CRCERR (1<<27)
#define NV_RX_OVERFLOW (1<<28)
#define NV_RX_FRAMINGERR (1<<29)
#define NV_RX_ERROR (1<<30)
#define NV_RX_AVAIL (1<<31)
#define NV_RX_ERROR_MASK (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4|NV_RX_CRCERR| \
NV_RX_OVERFLOW|NV_RX_FRAMINGERR)
#define NV_RX2_CHECKSUMMASK (0x1C000000)
#define NV_RX2_CHECKSUM_IP (0x10000000)
#define NV_RX2_CHECKSUM_IP_TCP (0x14000000)
#define NV_RX2_CHECKSUM_IP_UDP (0x18000000)
#define NV_RX2_DESCRIPTORVALID (1<<29)
#define NV_RX2_SUBTRACT1 (1<<25)
#define NV_RX2_ERROR1 (1<<18)
#define NV_RX2_ERROR2 (1<<19)
#define NV_RX2_ERROR3 (1<<20)
#define NV_RX2_ERROR4 (1<<21)
#define NV_RX2_CRCERR (1<<22)
#define NV_RX2_OVERFLOW (1<<23)
#define NV_RX2_FRAMINGERR (1<<24)
/* Error and avail are the same for both */
#define NV_RX2_ERROR (1<<30)
#define NV_RX2_AVAIL (1<<31)
#define NV_RX2_ERROR_MASK (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4| \
NV_RX2_CRCERR|NV_RX2_OVERFLOW|NV_RX2_FRAMINGERR)
#define NV_RX3_VLAN_TAG_PRESENT (1<<16)
#define NV_RX3_VLAN_TAG_MASK (0x0000FFFF)
#define NV_TXRX_RESET_DELAY 4
#define NV_TXSTOP_DELAY1 10
#define NV_TXSTOP_DELAY1MAX 500000
#define NV_TXSTOP_DELAY2 100
#define NV_TXIDLE_DELAY 10
#define NV_TXIDLE_ATTEMPTS 100000
#define NV_RXSTOP_DELAY1 10
#define NV_RXSTOP_DELAY1MAX 500000
#define NV_RXSTOP_DELAY2 100
#define NV_SETUP5_DELAY 5
#define NV_SETUP5_DELAYMAX 50000
#define NV_POWERUP_DELAY 5
#define NV_POWERUP_DELAYMAX 5000
#define NV_POWER_DELAY 50
#define NV_POWER_STALL 3000
#define NV_POWER_ATTEMPTS 20
#define NV_MIIBUSY_DELAY 50
#define NV_MIIPHY_DELAY 10
#define NV_MIIPHY_DELAYMAX 10000
#define NV_MAC_RESET_DELAY 64
#define NV_WAKEUPPATTERNS 5
#define NV_WAKEUPPATTERNS_V2 8
#define NV_WAKEUPMASKENTRIES 4
#define NV_PATTERN_V2_OFFSET 0x39C
/* RX/TX MAC address + type + VLAN + align + slack */
#define NV_RX_HEADERS (64)
/* even more slack. */
#define NV_RX_ALLOC_PAD (64)
#define PHY_OUI_MARVELL 0x5043
#define PHY_OUI_CICADA 0x03f1
#define PHY_OUI_VITESSE 0x01c1
#define PHY_OUI_REALTEK 0x0732
#define PHY_OUI_REALTEK2 0x0020
#define PHY_MODEL_REALTEK_8211 0x0110
#define PHY_MODEL_REALTEK_8201 0x0200
#define PHY_MODEL_MARVELL_E3016 0x0220
#define PHYID1_OUI_MASK 0x03ff
#define PHYID1_OUI_SHFT 6
#define PHYID2_MODEL_MASK 0x03f0
#define PHYID2_OUI_MASK 0xfc00
#define PHYID2_OUI_SHFT 10
#define PHY_GIGABIT 0x0100
#define PHY_CICADA_INIT_REG1 0x16
#define PHY_CICADA_INIT6 0x02000
#define PHY_CICADA_INIT_REG2 0x17
#define PHY_CICADA_INIT1 0x0f000
#define PHY_CICADA_INIT2 0x0e00
#define PHY_CICADA_INIT3 0x01000
#define PHY_CICADA_INIT4 0x0200
#define PHY_CICADA_INIT_REG3 0x1c
#define PHY_CICADA_INIT5 0x0004
#define PHY_MARVELL_INIT_REG1 0x1c
#define PHY_MARVELL_E3016_INITMASK 0x0300
#define PHY_VITESSE_INIT_REG2 0x10
#define PHY_VITESSE_INIT2 0xaf8a
#define PHY_VITESSE_INIT4 0x8f8a
#define PHY_VITESSE_INIT5 0xaf86
#define PHY_VITESSE_INIT6 0x8f86
#define PHY_VITESSE_INIT7 0xaf82
#define PHY_VITESSE_INIT9 0x8f82
#define PHY_VITESSE_INIT_REG3 0x11
#define PHY_VITESSE_INIT_REG4 0x12
#define PHY_VITESSE_INIT_MSK1 0xc
#define PHY_VITESSE_INIT3 0x8
#define PHY_VITESSE_INIT_MSK2 0x0180
#define PHY_VITESSE_INIT8 0x0100
#define PHY_VITESSE_INIT_REG1 0x1f
#define PHY_VITESSE_INIT1 0x52b5
#define PHY_VITESSE_INIT10 0x0
#define PHY_REALTEK_INIT_REG7 0x01
#define PHY_REALTEK_INIT11 0x0200
#define PHY_REALTEK_INIT_REG6 0x11
#define PHY_REALTEK_INIT7 0x1000
#define PHY_REALTEK_INIT9 0x0008
#define PHY_REALTEK_INIT_REG3 0x13
#define PHY_REALTEK_INIT4 0xad17
#define PHY_REALTEK_INIT_REG4 0x14
#define PHY_REALTEK_INIT5 0xfb54
#define PHY_REALTEK_REVISION 0x17
#define PHY_REV_MASK 0x0001
#define PHY_REV_REALTEK_8211B 0x0000
#define PHY_REV_REALTEK_8211C 0x0001
#define PHY_REALTEK_INIT_REG5 0x18
#define PHY_REALTEK_INIT6 0xf5c7
#define PHY_REALTEK_INIT_REG2 0x19
#define PHY_REALTEK_INIT2 0x8e00
#define PHY_REALTEK_INIT8 0x0003
#define PHY_REALTEK_INIT_MSK1 0x0003
#define PHY_REALTEK_INIT_REG1 0x1f
#define PHY_REALTEK_INIT1 0x0000
#define PHY_REALTEK_INIT3 0x0001
#define PHY_REALTEK_INIT10 0x0005
#define NV_PAUSEFRAME_RX_CAPABLE 0x0001
#define NV_PAUSEFRAME_TX_CAPABLE 0x0002
#define NV_PAUSEFRAME_RX_ENABLE 0x0004
#define NV_PAUSEFRAME_TX_ENABLE 0x0008
#define NV_PAUSEFRAME_RX_REQ 0x0010
#define NV_PAUSEFRAME_TX_REQ 0x0020
#define NV_PAUSEFRAME_AUTONEG 0x0040
#define NV_MSI_X_MAX_VECTORS 8
#define NV_MSI_X_VECTORS_MASK 0x000f
#define NV_MSI_CAPABLE 0x0010
#define NV_MSI_X_CAPABLE 0x0020
#define NV_MSI_ENABLED 0x0040
#define NV_MSI_X_ENABLED 0x0080
#define NV_MSI_X_VECTOR_ALL 0x0
#define NV_MSI_X_VECTOR_RX 0x0
#define NV_MSI_X_VECTOR_TX 0x1
#define NV_MSI_X_VECTOR_OTHER 0x2
#define NV_MSI_PRIV_OFFSET 0x68
#define NV_MSI_PRIV_VALUE 0xffffffff
#define NV_TX_LIMIT_COUNT 16

View file

@ -0,0 +1,298 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Miniport driver entrypoint
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "nvnet.h"
#define NDEBUG
#include "debug.h"
/* GLOBALS ********************************************************************/
CODE_SEG("INIT")
DRIVER_INITIALIZE DriverEntry;
/* FUNCTIONS ******************************************************************/
CODE_SEG("PAGE")
VOID
NvNetFlushTransmitQueue(
_In_ PNVNET_ADAPTER Adapter,
_In_ NDIS_STATUS CompleteStatus)
{
PNVNET_TCB Tcb;
PAGED_CODE();
for (Tcb = Adapter->Send.LastTcb;
Tcb != Adapter->Send.CurrentTcb;
Tcb = NV_NEXT_TCB(Adapter, Tcb))
{
NdisMSendComplete(Adapter->AdapterHandle,
Tcb->Packet,
CompleteStatus);
NV_RELEASE_TCB(Adapter, Tcb);
}
}
DECLSPEC_NOINLINE /* Called from pageable code */
VOID
NvNetPauseProcessing(
_In_ PNVNET_ADAPTER Adapter)
{
NvNetDisableInterrupts(Adapter);
NdisAcquireSpinLock(&Adapter->Send.Lock);
Adapter->Flags &= ~NV_ACTIVE;
NdisReleaseSpinLock(&Adapter->Send.Lock);
}
CODE_SEG("PAGE")
VOID
NvNetStopAdapter(
_In_ PNVNET_ADAPTER Adapter)
{
BOOLEAN Dummy;
PAGED_CODE();
NdisMCancelTimer(&Adapter->MediaDetectionTimer, &Dummy);
NvNetDisableInterrupts(Adapter);
KeFlushQueuedDpcs();
}
CODE_SEG("PAGE")
VOID
NvNetStartAdapter(
_In_ PNVNET_ADAPTER Adapter)
{
PAGED_CODE();
NdisMSynchronizeWithInterrupt(&Adapter->Interrupt,
NvNetInitPhaseSynchronized,
Adapter);
/* Setup the link timer right after the NIC is initialized */
if (Adapter->Features & DEV_NEED_LINKTIMER)
{
NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer,
NVNET_MEDIA_DETECTION_INTERVAL);
}
}
static
CODE_SEG("PAGE")
VOID
NTAPI
NvNetResetWorker(
_In_ PNDIS_WORK_ITEM WorkItem,
_In_opt_ PVOID Context)
{
PNVNET_ADAPTER Adapter = Context;
PAGED_CODE();
NvNetStopAdapter(Adapter);
NvNetIdleTransmitter(Adapter, TRUE);
NvNetStopTransmitter(Adapter);
NvNetStopReceiver(Adapter);
NV_WRITE(Adapter, NvRegTxRxControl,
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
NdisStallExecution(NV_TXRX_RESET_DELAY);
NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
NT_VERIFY(NvNetInitNIC(Adapter, FALSE) == NDIS_STATUS_SUCCESS);
NvNetStartAdapter(Adapter);
_InterlockedDecrement(&Adapter->ResetLock);
NdisMResetComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS, TRUE);
}
/* NDIS CALLBACKS *************************************************************/
static
BOOLEAN
NTAPI
MiniportCheckForHang(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
NdisDprAcquireSpinLock(&Adapter->Send.Lock);
if (Adapter->Flags & NV_ACTIVE &&
Adapter->Send.TcbSlots < NVNET_TRANSMIT_BLOCKS)
{
if (++Adapter->Send.StuckCount > NVNET_TRANSMIT_HANG_THRESHOLD)
{
NDIS_DbgPrint(MAX_TRACE, ("Transmit timeout!\n"));
#if defined(SARCH_XBOX)
/* Apply a HACK to make XQEMU happy... */
NvNetDisableInterrupts(Adapter);
NvNetApplyInterruptMask(Adapter);
#endif
Adapter->Send.StuckCount = 0;
}
}
NdisDprReleaseSpinLock(&Adapter->Send.Lock);
return FALSE;
}
static
CODE_SEG("PAGE")
VOID
NTAPI
MiniportHalt(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
BOOLEAN IsActive = !!(Adapter->Flags & NV_ACTIVE);
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
PAGED_CODE();
if (IsActive)
{
NvNetPauseProcessing(Adapter);
}
NvNetStopAdapter(Adapter);
if (IsActive)
{
NvNetIdleTransmitter(Adapter, TRUE);
NvNetStopTransmitter(Adapter);
NvNetStopReceiver(Adapter);
NV_WRITE(Adapter, NvRegTxRxControl,
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
NdisStallExecution(NV_TXRX_RESET_DELAY);
}
NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
NvNetToggleClockPowerGating(Adapter, TRUE);
NV_WRITE(Adapter, NvRegMacAddrA, Adapter->OriginalMacAddress[0]);
NV_WRITE(Adapter, NvRegMacAddrB, Adapter->OriginalMacAddress[1]);
NV_WRITE(Adapter, NvRegTransmitPoll,
NV_READ(Adapter, NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV);
SidebandUnitReleaseSemaphore(Adapter);
NvNetFreeAdapter(Adapter);
}
static
NDIS_STATUS
NTAPI
MiniportReset(
_Out_ PBOOLEAN AddressingReset,
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
if (_InterlockedCompareExchange(&Adapter->ResetLock, 1, 0))
{
return NDIS_STATUS_RESET_IN_PROGRESS;
}
NvNetPauseProcessing(Adapter);
NdisInitializeWorkItem(&Adapter->ResetWorkItem, NvNetResetWorker, Adapter);
NdisScheduleWorkItem(&Adapter->ResetWorkItem);
return NDIS_STATUS_PENDING;
}
static
VOID
NTAPI
MiniportShutdown(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
if (Adapter->Flags & NV_ACTIVE)
{
if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
{
NvNetPauseProcessing(Adapter);
}
NvNetIdleTransmitter(Adapter, TRUE);
NvNetStopTransmitter(Adapter);
NvNetStopReceiver(Adapter);
NV_WRITE(Adapter, NvRegTxRxControl,
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
NdisStallExecution(NV_TXRX_RESET_DELAY);
SidebandUnitReleaseSemaphore(Adapter);
}
NvNetDisableInterrupts(Adapter);
NvNetSetPowerState(Adapter, NdisDeviceStateD3, 0);
}
CODE_SEG("INIT")
NTSTATUS
NTAPI
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath)
{
NDIS_HANDLE WrapperHandle;
NDIS_MINIPORT_CHARACTERISTICS Characteristics = { 0 };
NDIS_STATUS Status;
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);
if (!WrapperHandle)
{
return NDIS_STATUS_FAILURE;
}
Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
Characteristics.CheckForHangHandler = MiniportCheckForHang;
Characteristics.HaltHandler = MiniportHalt;
Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
Characteristics.InitializeHandler = MiniportInitialize;
Characteristics.ISRHandler = MiniportISR;
Characteristics.QueryInformationHandler = MiniportQueryInformation;
Characteristics.ResetHandler = MiniportReset;
Characteristics.SendHandler = MiniportSend; /* TODO */
Characteristics.SetInformationHandler = MiniportSetInformation;
// Characteristics.ReturnPacketHandler = MiniportReturnPacket; /* TODO */
// Characteristics.SendPacketsHandler = MiniportSendPackets; /* TODO */
Characteristics.AdapterShutdownHandler = MiniportShutdown;
Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
if (Status != NDIS_STATUS_SUCCESS)
{
NdisTerminateWrapper(WrapperHandle, NULL);
return Status;
}
return Status;
}

View file

@ -0,0 +1,672 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Common header file
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
#ifndef _NVNET_PCH_
#define _NVNET_PCH_
#if !DBG
#define NO_KERNEL_LIST_ENTRY_CHECKS
#endif
#include <ndis.h>
#include <section_attribs.h>
#include "eth.h"
#include "nic.h"
#include "phyreg.h"
#define NVNET_TAG 'ENVN'
#if defined(SARCH_XBOX)
/* Reduce memory requirements on OG Xbox */
#define NVNET_TRANSMIT_BLOCKS 8
#define NVNET_TRANSMIT_DESCRIPTORS 32
#define NVNET_TRANSMIT_BUFFERS 1
#define NVNET_RECEIVE_DESCRIPTORS 16
#else
#define NVNET_TRANSMIT_BLOCKS 64
#define NVNET_TRANSMIT_DESCRIPTORS 512
#define NVNET_TRANSMIT_BUFFERS 16
#define NVNET_RECEIVE_DESCRIPTORS 512
#endif
#define NVNET_ALIGNMENT 64
#define NVNET_RECEIVE_BUFFER_SIZE 2048
#define NVNET_RECEIVE_PROCESSING_LIMIT 64
#define NVNET_IM_THRESHOLD 4
#define NVNET_IM_MAX_IDLE 40
#if defined(SARCH_XBOX)
#define NVNET_TRANSMIT_HANG_THRESHOLD 3
#else
#define NVNET_TRANSMIT_HANG_THRESHOLD 5
#endif
#if defined(SARCH_XBOX)
#define NVNET_FRAGMENTATION_THRESHOLD 8
#else
#define NVNET_FRAGMENTATION_THRESHOLD 32
#endif
#define NVNET_MEDIA_DETECTION_INTERVAL 5000
#define NVNET_MAXIMUM_FRAME_SIZE 1514
#define NVNET_MAXIMUM_FRAME_SIZE_JUMBO 9014
#define NVNET_MAXIMUM_VLAN_ID 0xFFF
#define NVNET_MULTICAST_LIST_SIZE 32
#define NVNET_MINIMUM_LSO_SEGMENT_COUNT 2
#define NVNET_MAXIMUM_LSO_FRAME_SIZE 0xFC00
#define NVNET_PACKET_FILTERS ( \
NDIS_PACKET_TYPE_DIRECTED | \
NDIS_PACKET_TYPE_MULTICAST | \
NDIS_PACKET_TYPE_BROADCAST | \
NDIS_PACKET_TYPE_PROMISCUOUS | \
NDIS_PACKET_TYPE_ALL_MULTICAST)
#define PACKET_ENTRY(Packet) ((PLIST_ENTRY)(&(Packet)->MiniportReserved[0]))
typedef enum _NVNET_OPTIMIZATION_MODE
{
NV_OPTIMIZATION_MODE_DYNAMIC = 0,
NV_OPTIMIZATION_MODE_CPU,
NV_OPTIMIZATION_MODE_THROUGHPUT
} NVNET_OPTIMIZATION_MODE;
typedef enum _NVNET_FLOW_CONTROL_MODE
{
NV_FLOW_CONTROL_DISABLE = 0,
NV_FLOW_CONTROL_AUTO,
NV_FLOW_CONTROL_RX,
NV_FLOW_CONTROL_TX,
NV_FLOW_CONTROL_RX_TX
} NVNET_FLOW_CONTROL_MODE;
typedef union _NVNET_OFFLOAD
{
struct {
ULONG SendIpOptions:1;
ULONG SendTcpOptions:1;
ULONG SendTcpChecksum:1;
ULONG SendUdpChecksum:1;
ULONG SendIpChecksum:1;
ULONG ReceiveIpOptions:1;
ULONG ReceiveTcpOptions:1;
ULONG ReceiveTcpChecksum:1;
ULONG ReceiveUdpChecksum:1;
ULONG ReceiveIpChecksum:1;
ULONG SendIpV6Options:1;
ULONG SendTcpV6Options:1;
ULONG SendTcpV6Checksum:1;
ULONG SendUdpV6Checksum:1;
ULONG ReceiveIpV6Options:1;
ULONG ReceiveTcpV6Options:1;
ULONG ReceiveTcpV6Checksum:1;
ULONG ReceiveUdpV6Checksum:1;
};
ULONG Value;
} NVNET_OFFLOAD, *PNVNET_OFFLOAD;
typedef struct _NVNET_STATISTICS
{
ULONG64 HwTxCnt;
ULONG64 HwTxZeroReXmt;
ULONG64 HwTxOneReXmt;
ULONG64 HwTxManyReXmt;
ULONG64 HwTxLateCol;
ULONG64 HwTxUnderflow;
ULONG64 HwTxLossCarrier;
ULONG64 HwTxExcessDef;
ULONG64 HwTxRetryErr;
ULONG64 HwRxFrameErr;
ULONG64 HwRxExtraByte;
ULONG64 HwRxLateCol;
ULONG64 HwRxRunt;
ULONG64 HwRxFrameTooLong;
ULONG64 HwRxOverflow;
ULONG64 HwRxFCSErr;
ULONG64 HwRxFrameAlignErr;
ULONG64 HwRxLenErr;
ULONG64 HwTxDef;
ULONG64 HwTxFrame;
ULONG64 HwRxCnt;
ULONG64 HwTxPause;
ULONG64 HwRxPause;
ULONG64 HwRxDropFrame;
ULONG64 HwRxUnicast;
ULONG64 HwRxMulticast;
ULONG64 HwRxBroadcast;
ULONG64 HwTxUnicast;
ULONG64 HwTxMulticast;
ULONG64 HwTxBroadcast;
ULONG64 TransmitOk;
ULONG64 ReceiveOk;
ULONG64 TransmitErrors;
ULONG64 ReceiveErrors;
ULONG64 ReceiveNoBuffers;
ULONG64 ReceiveCrcErrors;
ULONG64 ReceiveAlignmentErrors;
ULONG64 TransmitDeferred;
ULONG64 TransmitExcessiveCollisions;
ULONG64 ReceiveOverrunErrors;
ULONG64 TransmitUnderrunErrors;
ULONG64 TransmitZeroRetry;
ULONG64 TransmitOneRetry;
ULONG64 TransmitLostCarrierSense;
ULONG64 TransmitLateCollisions;
ULONG ReceiveIrqNoBuffers;
} NVNET_STATISTICS, *PNVNET_STATISTICS;
typedef struct _NVNET_WAKE_FRAME
{
union
{
UCHAR AsUCHAR[16];
ULONG AsULONG[4];
} PatternMask;
UCHAR WakeUpPattern[128];
} NVNET_WAKE_FRAME, *PNVNET_WAKE_FRAME;
typedef struct _NVNET_TX_BUFFER_DATA
{
PVOID VirtualAddress;
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
} NVNET_TX_BUFFER_DATA, *PNVNET_TX_BUFFER_DATA;
typedef struct _NVNET_TX_BUFFER
{
SINGLE_LIST_ENTRY Link;
PVOID VirtualAddress;
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
} NVNET_TX_BUFFER, *PNVNET_TX_BUFFER;
typedef union _NVNET_TBD
{
PNVNET_DESCRIPTOR_32 x32;
PNVNET_DESCRIPTOR_64 x64;
PVOID Memory;
} NVNET_TBD;
typedef struct _NVNET_TCB
{
NVNET_TBD Tbd;
NVNET_TBD DeferredTbd;
PNDIS_PACKET Packet;
PNVNET_TX_BUFFER Buffer;
ULONG Slots;
ULONG Flags;
#define NV_TCB_LARGE_SEND 0x00000001
#define NV_TCB_CHECKSUM_IP 0x00000002
#define NV_TCB_CHECKSUM_TCP 0x00000004
#define NV_TCB_CHECKSUM_UDP 0x00000008
#define NV_TCB_COALESCE 0x00000010
ULONG Mss;
} NVNET_TCB, *PNVNET_TCB;
typedef union _NV_RBD
{
PNVNET_DESCRIPTOR_32 x32;
PNVNET_DESCRIPTOR_64 x64;
PVOID Memory;
} NV_RBD;
typedef struct _NVNET_RBD
{
NV_RBD NvRbd;
PNDIS_PACKET Packet;
PNDIS_BUFFER Buffer;
} NVNET_RBD, *PNVNET_RBD;
typedef struct _NVNET_SEND
{
NDIS_SPIN_LOCK Lock;
PNVNET_TCB HeadTcb;
PNVNET_TCB TailTcb;
PNVNET_TCB LastTcb;
PNVNET_TCB CurrentTcb;
PNVNET_TCB DeferredTcb;
NVNET_TBD HeadTbd;
NVNET_TBD TailTbd;
NVNET_TBD CurrentTbd;
ULONG TcbSlots;
ULONG TbdSlots;
ULONG StuckCount;
ULONG PacketsCount;
SINGLE_LIST_ENTRY BufferList;
} NVNET_SEND, *PNVNET_SEND;
typedef struct _NVNET_RECEIVE
{
NDIS_SPIN_LOCK Lock;
NV_RBD NvRbd;
} NVNET_RECEIVE, *PNVNET_RECEIVE;
typedef struct _NVNET_ADAPTER NVNET_ADAPTER, *PNVNET_ADAPTER;
typedef VOID
(NVNET_TRANSMIT_PACKET)(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNVNET_TCB Tcb,
_In_ PSCATTER_GATHER_LIST SgList);
typedef NVNET_TRANSMIT_PACKET *PNVNET_TRANSMIT_PACKET;
typedef ULONG
(NVNET_PROCESS_TRANSMIT)(
_In_ PNVNET_ADAPTER Adapter,
_Inout_ PLIST_ENTRY SendReadyList);
typedef NVNET_PROCESS_TRANSMIT *PNVNET_PROCESS_TRANSMIT;
typedef ULONG
(NVNET_PROCESS_RECEIVE)(
_In_ PNVNET_ADAPTER Adapter,
_In_ ULONG TotalRxProcessed);
typedef NVNET_PROCESS_RECEIVE *PNVNET_PROCESS_RECEIVE;
typedef struct _NVNET_ADAPTER
{
volatile PUCHAR IoBase;
NDIS_HANDLE AdapterHandle;
ULONG Features;
ULONG Flags;
#define NV_ACTIVE 0x80000000
#define NV_SEND_CHECKSUM 0x00000002
#define NV_SEND_LARGE_SEND 0x00000004
#define NV_SEND_ERRATA_PRESENT 0x00000008
#define NV_MAC_IN_USE 0x00000010
#define NV_GIGABIT_PHY 0x00000020
#define NV_UNIT_SEMAPHORE_ACQUIRED 0x00000040
#define NV_USE_SOFT_MAC_ADDRESS 0x00000100
#define NV_FORCE_SPEED_AND_DUPLEX 0x00000200
#define NV_FORCE_FULL_DUPLEX 0x00000400
#define NV_USER_SPEED_100 0x00000800
#define NV_PACKET_PRIORITY 0x00001000
#define NV_VLAN_TAGGING 0x00002000
ULONG TxRxControl;
ULONG InterruptMask;
ULONG InterruptStatus;
ULONG InterruptIdleCount;
ULONG AdapterStatus;
NVNET_OPTIMIZATION_MODE OptimizationMode;
NVNET_OFFLOAD Offload;
ULONG IpHeaderOffset;
ULONG PacketFilter;
NVNET_SEND Send;
NVNET_RECEIVE Receive;
PUCHAR ReceiveBuffer;
ULONG CurrentRx;
PNVNET_TRANSMIT_PACKET TransmitPacket;
PNVNET_PROCESS_TRANSMIT ProcessTransmit;
NVNET_STATISTICS Statistics;
NDIS_SPIN_LOCK Lock;
ULONG MaximumFrameSize;
ULONG ReceiveBufferSize;
ULONG VlanId;
ULONG WakeFlags;
ULONG PhyAddress;
ULONG PhyModel;
ULONG PhyRevision;
ULONG PhyOui;
ULONG PowerStatePending;
ULONG VlanControl;
ULONG PauseFlags;
ULONG LinkSpeed;
BOOLEAN Connected;
BOOLEAN FullDuplex;
ULONG OriginalMacAddress[2];
UCHAR PermanentMacAddress[ETH_LENGTH_OF_ADDRESS];
UCHAR CurrentMacAddress[ETH_LENGTH_OF_ADDRESS];
_Field_range_(0, NVNET_MULTICAST_LIST_SIZE)
ULONG MulticastListSize;
struct
{
UCHAR MacAddress[ETH_LENGTH_OF_ADDRESS];
} MulticastList[NVNET_MULTICAST_LIST_SIZE];
ULONG WakeFrameBitmap;
PNVNET_WAKE_FRAME WakeFrames[NV_WAKEUPPATTERNS_V2];
NDIS_HANDLE WrapperConfigurationHandle;
NDIS_WORK_ITEM PowerWorkItem;
NDIS_WORK_ITEM ResetWorkItem;
_Interlocked_
volatile LONG ResetLock;
NDIS_PHYSICAL_ADDRESS IoAddress;
ULONG IoLength;
NVNET_FLOW_CONTROL_MODE FlowControlMode;
NDIS_MINIPORT_TIMER MediaDetectionTimer;
USHORT DeviceId;
UCHAR RevisionId;
BOOLEAN InterruptShared;
NDIS_MINIPORT_INTERRUPT Interrupt;
ULONG InterruptVector;
ULONG InterruptLevel;
ULONG InterruptFlags;
NDIS_PHYSICAL_ADDRESS TbdPhys;
NDIS_PHYSICAL_ADDRESS RbdPhys;
NDIS_PHYSICAL_ADDRESS ReceiveBufferPhys;
PVOID SendBuffer;
PVOID TbdOriginal;
PVOID RbdOriginal;
PVOID AdapterOriginal;
NDIS_PHYSICAL_ADDRESS TbdPhysOriginal;
NDIS_PHYSICAL_ADDRESS RbdPhysOriginal;
NVNET_TX_BUFFER_DATA SendBufferAllocationData[NVNET_TRANSMIT_BUFFERS];
} NVNET_ADAPTER, *PNVNET_ADAPTER;
#define NvNetLogError(Adapter, ErrorCode) \
NdisWriteErrorLogEntry((Adapter)->AdapterHandle, ErrorCode, 1, __LINE__)
NVNET_TRANSMIT_PACKET NvNetTransmitPacket32;
NVNET_TRANSMIT_PACKET NvNetTransmitPacket64;
NVNET_PROCESS_TRANSMIT ProcessTransmitDescriptorsLegacy;
NVNET_PROCESS_TRANSMIT ProcessTransmitDescriptors32;
NVNET_PROCESS_TRANSMIT ProcessTransmitDescriptors64;
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);
CODE_SEG("PAGE")
VOID
NvNetFreeAdapter(
_In_ PNVNET_ADAPTER Adapter);
CODE_SEG("PAGE")
NDIS_STATUS
NvNetRecognizeHardware(
_Inout_ PNVNET_ADAPTER Adapter);
CODE_SEG("PAGE")
NDIS_STATUS
NvNetGetPermanentMacAddress(
_Inout_ PNVNET_ADAPTER Adapter,
_Out_writes_bytes_all_(ETH_LENGTH_OF_ADDRESS) PUCHAR MacAddress);
CODE_SEG("PAGE")
VOID
NvNetSetupMacAddress(
_In_ PNVNET_ADAPTER Adapter,
_In_reads_bytes_(ETH_LENGTH_OF_ADDRESS) PUCHAR MacAddress);
CODE_SEG("PAGE")
NDIS_STATUS
NvNetInitNIC(
_In_ PNVNET_ADAPTER Adapter,
_In_ BOOLEAN InitPhy);
CODE_SEG("PAGE")
NDIS_STATUS
NvNetFindPhyDevice(
_In_ PNVNET_ADAPTER Adapter);
CODE_SEG("PAGE")
NDIS_STATUS
NvNetPhyInit(
_In_ PNVNET_ADAPTER Adapter);
VOID
SidebandUnitReleaseSemaphore(
_In_ PNVNET_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
NvNetStartAdapter(
_In_ PNVNET_ADAPTER Adapter);
DECLSPEC_NOINLINE
VOID
NvNetPauseProcessing(
_In_ PNVNET_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
NvNetStopAdapter(
_In_ PNVNET_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
NvNetFlushTransmitQueue(
_In_ PNVNET_ADAPTER Adapter,
_In_ NDIS_STATUS CompleteStatus);
KSYNCHRONIZE_ROUTINE NvNetInitPhaseSynchronized;
NDIS_TIMER_FUNCTION NvNetMediaDetectionDpc;
BOOLEAN
MiiWrite(
_In_ PNVNET_ADAPTER Adapter,
_In_ ULONG PhyAddress,
_In_ ULONG RegAddress,
_In_ ULONG Data);
BOOLEAN
MiiRead(
_In_ PNVNET_ADAPTER Adapter,
_In_ ULONG PhyAddress,
_In_ ULONG RegAddress,
_Out_ PULONG Data);
BOOLEAN
NvNetUpdateLinkSpeed(
_In_ PNVNET_ADAPTER Adapter);
VOID
NvNetResetReceiverAndTransmitter(
_In_ PNVNET_ADAPTER Adapter);
VOID
NvNetStartReceiver(
_In_ PNVNET_ADAPTER Adapter);
VOID
NvNetStartTransmitter(
_In_ PNVNET_ADAPTER Adapter);
VOID
NvNetStopReceiver(
_In_ PNVNET_ADAPTER Adapter);
VOID
NvNetStopTransmitter(
_In_ PNVNET_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
NvNetIdleTransmitter(
_In_ PNVNET_ADAPTER Adapter,
_In_ BOOLEAN ClearPhyControl);
VOID
NvNetUpdatePauseFrame(
_Inout_ PNVNET_ADAPTER Adapter,
_In_ ULONG PauseFlags);
VOID
NvNetToggleClockPowerGating(
_In_ PNVNET_ADAPTER Adapter,
_In_ BOOLEAN Gate);
VOID
NvNetSetPowerState(
_In_ PNVNET_ADAPTER Adapter,
_In_ NDIS_DEVICE_POWER_STATE NewPowerState,
_In_ ULONG WakeFlags);
CODE_SEG("PAGE")
VOID
NvNetBackoffSetSlotTime(
_In_ PNVNET_ADAPTER Adapter);
VOID
NvNetBackoffReseed(
_In_ PNVNET_ADAPTER Adapter);
VOID
NvNetBackoffReseedEx(
_In_ PNVNET_ADAPTER Adapter);
NDIS_STATUS
NTAPI
MiniportSend(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PNDIS_PACKET Packet,
_In_ UINT Flags);
VOID
NTAPI
MiniportISR(
_Out_ PBOOLEAN InterruptRecognized,
_Out_ PBOOLEAN QueueMiniportHandleInterrupt,
_In_ NDIS_HANDLE MiniportAdapterContext);
VOID
NTAPI
MiniportHandleInterrupt(
_In_ NDIS_HANDLE MiniportAdapterContext);
NDIS_STATUS
NTAPI
MiniportQueryInformation(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ NDIS_OID Oid,
_In_ PVOID InformationBuffer,
_In_ ULONG InformationBufferLength,
_Out_ PULONG BytesWritten,
_Out_ PULONG BytesNeeded);
NDIS_STATUS
NTAPI
MiniportSetInformation(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ NDIS_OID Oid,
_In_ PVOID InformationBuffer,
_In_ ULONG InformationBufferLength,
_Out_ PULONG BytesRead,
_Out_ PULONG BytesNeeded);
#define NV_IMPLICIT_ENTRIES(Length) \
(((Length - (NV_MAXIMUM_SG_SIZE + 1)) >> NV_TX2_TSO_MAX_SHIFT) + 1)
FORCEINLINE
VOID
NV_RELEASE_TCB(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNVNET_TCB Tcb)
{
if (Tcb->Flags & NV_TCB_COALESCE)
{
PushEntryList(&Adapter->Send.BufferList, &Tcb->Buffer->Link);
}
Tcb->Packet = NULL;
++Adapter->Send.TcbSlots;
Adapter->Send.TbdSlots += Tcb->Slots;
Adapter->Send.StuckCount = 0;
}
FORCEINLINE
PNVNET_TCB
NV_NEXT_TCB(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNVNET_TCB Tcb)
{
if (Tcb++ == Adapter->Send.TailTcb)
return Adapter->Send.HeadTcb;
else
return Tcb;
}
FORCEINLINE
NVNET_TBD
NV_NEXT_TBD_32(
_In_ PNVNET_ADAPTER Adapter,
_In_ NVNET_TBD Tbd)
{
if (Tbd.x32++ == Adapter->Send.TailTbd.x32)
return Adapter->Send.HeadTbd;
else
return Tbd;
}
FORCEINLINE
NVNET_TBD
NV_NEXT_TBD_64(
_In_ PNVNET_ADAPTER Adapter,
_In_ NVNET_TBD Tbd)
{
if (Tbd.x64++ == Adapter->Send.TailTbd.x64)
return Adapter->Send.HeadTbd;
else
return Tbd;
}
FORCEINLINE
VOID
NV_WRITE(
_In_ PNVNET_ADAPTER Adapter,
_In_ NVNET_REGISTER Register,
_In_ ULONG Value)
{
NdisWriteRegisterUlong((PULONG)(Adapter->IoBase + Register), Value);
}
FORCEINLINE
ULONG
NV_READ(
_In_ PNVNET_ADAPTER Adapter,
_In_ NVNET_REGISTER Register)
{
ULONG Value;
NdisReadRegisterUlong((PULONG)(Adapter->IoBase + Register), &Value);
return Value;
}
#define NvNetDisableInterrupts(Adapter) \
NV_WRITE(Adapter, NvRegIrqMask, 0);
#define NvNetApplyInterruptMask(Adapter) \
NV_WRITE(Adapter, NvRegIrqMask, (Adapter)->InterruptMask);
#endif /* _NVNET_PCH_ */

View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "nVidia nForce Ethernet Controller Driver"
#define REACTOS_STR_INTERNAL_NAME "nvnet"
#define REACTOS_STR_ORIGINAL_FILENAME "nvnet.sys"
#include <reactos/version.rc>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: PHY layer register definitions
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
/* IEEE 802.3 */
#define MII_CONTROL 0x00
#define MII_CR_AUTONEG_RESTART 0x0200
#define MII_CR_POWER_DOWN 0x0800
#define MII_CR_AUTONEG 0x1000
#define MII_CR_RESET 0x8000
#define MII_STATUS 0x01
#define MII_SR_LINK_STATUS 0x0004
#define MII_SR_AUTONEG_COMPLETE 0x0020
#define MII_PHY_ID1 0x02
#define MII_PHY_ID2 0x03
#define MII_AUTONEG_ADVERTISE 0x04
#define MII_ADV_10T_HD 0x0020
#define MII_ADV_10T_FD 0x0040
#define MII_ADV_100T_HD 0x0080
#define MII_ADV_100T_FD 0x0100
#define MII_ADV_100T4 0x0200
#define MII_ADV_PAUSE_SYM 0x0400
#define MII_ADV_PAUSE_ASYM 0x0800
#define MII_AUTONEG_LINK_PARTNER 0x05
#define MII_LP_10T_HD 0x0020
#define MII_LP_10T_FD 0x0040
#define MII_LP_100T_HD 0x0080
#define MII_LP_100T_FD 0x0100
#define MII_LP_PAUSE_SYM 0x0400
#define MII_LP_PAUSE_ASYM 0x0800
#define MII_AUTONEG_EXPANSION 0x06
#define MII_EXP_LP_AUTONEG 0x0001
#define MII_MASTER_SLAVE_CONTROL 0x09
#define MII_MS_CR_1000T_HD 0x0100
#define MII_MS_CR_1000T_FD 0x0200
#define MII_MASTER_SLAVE_STATUS 0x0A
#define MII_MS_SR_1000T_FD 0x0800

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,524 @@
/*
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Packet sending
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "nvnet.h"
#define NDEBUG
#include "debug.h"
/* FUNCTIONS ******************************************************************/
VOID
NvNetTransmitPacket32(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNVNET_TCB Tcb,
_In_ PSCATTER_GATHER_LIST SgList)
{
NVNET_TBD Tbd, LastTbd;
ULONG i, Flags;
ULONG Slots;
Flags = 0;
Slots = 0;
Tbd = Adapter->Send.CurrentTbd;
for (i = 0; i < SgList->NumberOfElements; ++i)
{
ULONG Address = NdisGetPhysicalAddressLow(SgList->Elements[i].Address);
ULONG Length = SgList->Elements[i].Length;
if (Length > NV_MAXIMUM_SG_SIZE)
{
ULONG ImplicitEntries = NV_IMPLICIT_ENTRIES(Length);
do
{
++Slots;
Tbd.x32->Address = Address;
Tbd.x32->FlagsLength = Flags | (NV_MAXIMUM_SG_SIZE - 1);
LastTbd = Tbd;
Tbd = NV_NEXT_TBD_32(Adapter, Tbd);
Flags = NV_TX_VALID;
Length -= NV_MAXIMUM_SG_SIZE;
Address += NV_MAXIMUM_SG_SIZE;
--ImplicitEntries;
}
while (ImplicitEntries);
}
++Slots;
Tbd.x32->Address = Address;
Tbd.x32->FlagsLength = Flags | (Length - 1);
LastTbd = Tbd;
Tbd = NV_NEXT_TBD_32(Adapter, Tbd);
Flags = NV_TX_VALID;
}
Tcb->Slots = Slots;
Tcb->Tbd = LastTbd;
if (Adapter->Features & DEV_HAS_LARGEDESC)
{
LastTbd.x32->FlagsLength |= NV_TX2_LASTPACKET;
}
else
{
LastTbd.x32->FlagsLength |= NV_TX_LASTPACKET;
}
if (Tcb->Flags & NV_TCB_LARGE_SEND)
{
Flags |= (Tcb->Mss << NV_TX2_TSO_SHIFT) | NV_TX2_TSO;
}
else
{
if (Tcb->Flags & NV_TCB_CHECKSUM_IP)
{
Flags |= NV_TX2_CHECKSUM_L3;
}
if (Tcb->Flags & (NV_TCB_CHECKSUM_TCP | NV_TCB_CHECKSUM_UDP))
{
Flags |= NV_TX2_CHECKSUM_L4;
}
}
Adapter->Send.CurrentTbd.x32->FlagsLength |= Flags;
Adapter->Send.CurrentTbd = Tbd;
NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_KICK);
}
VOID
NvNetTransmitPacket64(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNVNET_TCB Tcb,
_In_ PSCATTER_GATHER_LIST SgList)
{
NVNET_TBD Tbd, LastTbd;
ULONG i, Flags;
ULONG Slots;
Flags = 0;
Slots = 0;
Tbd = Adapter->Send.CurrentTbd;
for (i = 0; i < SgList->NumberOfElements; ++i)
{
ULONG64 Address = SgList->Elements[i].Address.QuadPart;
ULONG Length = SgList->Elements[i].Length;
if (Length > NV_MAXIMUM_SG_SIZE)
{
ULONG ImplicitEntries = NV_IMPLICIT_ENTRIES(Length);
do
{
++Slots;
Tbd.x64->AddressLow = (ULONG)Address;
Tbd.x64->AddressHigh = Address >> 32;
Tbd.x64->VlanTag = 0;
Tbd.x64->FlagsLength = Flags | (NV_MAXIMUM_SG_SIZE - 1);
LastTbd = Tbd;
Tbd = NV_NEXT_TBD_64(Adapter, Tbd);
Flags = NV_TX2_VALID;
Length -= NV_MAXIMUM_SG_SIZE;
Address += NV_MAXIMUM_SG_SIZE;
--ImplicitEntries;
}
while (ImplicitEntries);
}
++Slots;
Tbd.x64->AddressLow = (ULONG)Address;
Tbd.x64->AddressHigh = Address >> 32;
Tbd.x64->VlanTag = 0;
Tbd.x64->FlagsLength = Flags | (Length - 1);
LastTbd = Tbd;
Tbd = NV_NEXT_TBD_64(Adapter, Tbd);
Flags = NV_TX2_VALID;
}
Tcb->Slots = Slots;
Tcb->Tbd = LastTbd;
LastTbd.x64->FlagsLength |= NV_TX2_LASTPACKET;
if (Adapter->Flags & NV_SEND_ERRATA_PRESENT)
{
if (Adapter->Send.PacketsCount == NV_TX_LIMIT_COUNT)
{
Tcb->DeferredTbd = Adapter->Send.CurrentTbd;
if (!Adapter->Send.DeferredTcb)
{
Adapter->Send.DeferredTcb = Tcb;
}
Flags = 0;
}
else
{
++Adapter->Send.PacketsCount;
}
}
if (Tcb->Flags & NV_TCB_LARGE_SEND)
{
Flags |= (Tcb->Mss << NV_TX2_TSO_SHIFT) | NV_TX2_TSO;
}
else
{
if (Tcb->Flags & NV_TCB_CHECKSUM_IP)
{
Flags |= NV_TX2_CHECKSUM_L3;
}
if (Tcb->Flags & (NV_TCB_CHECKSUM_TCP | NV_TCB_CHECKSUM_UDP))
{
Flags |= NV_TX2_CHECKSUM_L4;
}
}
// Adapter->Send.CurrentTbd.x64->VlanTag = NV_TX3_VLAN_TAG_PRESENT; TODO
Adapter->Send.CurrentTbd.x64->FlagsLength |= Flags;
Adapter->Send.CurrentTbd = Tbd;
NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_KICK);
}
static
DECLSPEC_NOINLINE
ULONG
NvNetQueryTcpIpHeaders(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNDIS_PACKET Packet)
{
PNDIS_BUFFER CurrentBuffer;
PVOID Address;
UINT CurrentLength;
UINT PacketLength;
PIPv4_HEADER IpHeader;
PTCPv4_HEADER TcpHeader;
ULONG BytesCopied = 0;
UCHAR Buffer[136];
NdisGetFirstBufferFromPacketSafe(Packet,
&CurrentBuffer,
&Address,
&CurrentLength,
&PacketLength,
HighPagePriority);
if (!Address)
return 0;
while (TRUE)
{
CurrentLength = min(CurrentLength, sizeof(Buffer) - BytesCopied);
NdisMoveMemory(&Buffer[BytesCopied], Address, CurrentLength);
BytesCopied += CurrentLength;
if (BytesCopied >= sizeof(Buffer))
break;
NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
if (!CurrentBuffer)
return 0;
NdisQueryBufferSafe(CurrentBuffer,
&Address,
&CurrentLength,
HighPagePriority);
}
IpHeader = (PIPv4_HEADER)&Buffer[Adapter->IpHeaderOffset];
TcpHeader = (PTCPv4_HEADER)((PUCHAR)IpHeader + IP_HEADER_LENGTH(IpHeader));
return IP_HEADER_LENGTH(IpHeader) + TCP_HEADER_LENGTH(TcpHeader);
}
static
BOOLEAN
NvNetCopyPacket(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNDIS_PACKET Packet,
_In_ PNVNET_TX_BUFFER Buffer)
{
PNDIS_BUFFER CurrentBuffer;
PVOID Address;
UINT CurrentLength;
UINT PacketLength;
PUCHAR Destination;
NdisGetFirstBufferFromPacketSafe(Packet,
&CurrentBuffer,
&Address,
&CurrentLength,
&PacketLength,
HighPagePriority);
if (!Address)
return FALSE;
Destination = Buffer->VirtualAddress;
while (TRUE)
{
NdisMoveMemory(Destination, Address, CurrentLength);
Destination += CurrentLength;
NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
if (!CurrentBuffer)
break;
NdisQueryBufferSafe(CurrentBuffer,
&Address,
&CurrentLength,
HighPagePriority);
if (!Address)
return FALSE;
}
return TRUE;
}
static
NDIS_STATUS
NvNetSendPacketLargeSend(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNDIS_PACKET Packet,
_In_ ULONG TotalLength)
{
PSCATTER_GATHER_LIST SgList;
ULONG Mss, Length;
PNVNET_TCB Tcb;
if (!Adapter->Send.TcbSlots)
{
return NDIS_STATUS_RESOURCES;
}
SgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
/* Make sure we have room to setup all fragments */
C_ASSERT(NVNET_TRANSMIT_DESCRIPTORS > ((NVNET_MAXIMUM_LSO_FRAME_SIZE / PAGE_SIZE) + 3));
ASSERT(SgList->NumberOfElements +
(NVNET_MAXIMUM_LSO_FRAME_SIZE / (NV_MAXIMUM_SG_SIZE + 1)) <=
NVNET_TRANSMIT_DESCRIPTORS);
if (SgList->NumberOfElements +
(NVNET_MAXIMUM_LSO_FRAME_SIZE / (NV_MAXIMUM_SG_SIZE + 1)) < Adapter->Send.TbdSlots)
{
return NDIS_STATUS_RESOURCES;
}
Length = NvNetQueryTcpIpHeaders(Adapter, Packet);
if (!Length)
{
return NDIS_STATUS_RESOURCES;
}
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo) =
UlongToPtr(TotalLength - Adapter->IpHeaderOffset - Length);
--Adapter->Send.TcbSlots;
Mss = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo));
Tcb = Adapter->Send.CurrentTcb;
Tcb->Mss = Mss;
Tcb->Packet = Packet;
Tcb->Flags = NV_TCB_LARGE_SEND;
Adapter->TransmitPacket(Adapter, Tcb, SgList);
ASSERT(Adapter->Send.TbdSlots >= Tcb->Slots);
Adapter->Send.TbdSlots -= Tcb->Slots;
Adapter->Send.CurrentTcb = NV_NEXT_TCB(Adapter, Tcb);
return NDIS_STATUS_SUCCESS;
}
static
ULONG
NvNetGetChecksumInfo(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNDIS_PACKET Packet)
{
ULONG Flags;
NDIS_TCP_IP_CHECKSUM_PACKET_INFO ChecksumInfo;
if (NDIS_GET_PACKET_PROTOCOL_TYPE(Packet) != NDIS_PROTOCOL_ID_TCP_IP)
return 0;
ChecksumInfo.Value = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
TcpIpChecksumPacketInfo));
Flags = 0;
if (ChecksumInfo.Transmit.NdisPacketChecksumV4)
{
if (ChecksumInfo.Transmit.NdisPacketTcpChecksum && Adapter->Offload.SendTcpChecksum)
{
Flags |= NV_TCB_CHECKSUM_TCP;
}
if (ChecksumInfo.Transmit.NdisPacketUdpChecksum && Adapter->Offload.SendUdpChecksum)
{
Flags |= NV_TCB_CHECKSUM_UDP;
}
if (ChecksumInfo.Transmit.NdisPacketIpChecksum && Adapter->Offload.SendIpChecksum)
{
Flags |= NV_TCB_CHECKSUM_IP;
}
}
return Flags;
}
static
NDIS_STATUS
NvNetSendPacket(
_In_ PNVNET_ADAPTER Adapter,
_In_ PNDIS_PACKET Packet,
_In_ ULONG TotalLength)
{
PSCATTER_GATHER_LIST SgList;
SCATTER_GATHER_LIST LocalSgList;
PNVNET_TCB Tcb;
ULONG Flags;
ASSERT(TotalLength <= Adapter->MaximumFrameSize);
if (!Adapter->Send.TcbSlots)
{
return NDIS_STATUS_RESOURCES;
}
Flags = NvNetGetChecksumInfo(Adapter, Packet);
SgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
if (SgList->NumberOfElements > NVNET_FRAGMENTATION_THRESHOLD)
{
if (!Adapter->Send.TbdSlots || !Adapter->Send.BufferList.Next)
{
return NDIS_STATUS_RESOURCES;
}
else
{
PNVNET_TX_BUFFER CoalesceBuffer;
BOOLEAN Success;
--Adapter->Send.TcbSlots;
CoalesceBuffer = (PNVNET_TX_BUFFER)PopEntryList(&Adapter->Send.BufferList);
NdisDprReleaseSpinLock(&Adapter->Send.Lock);
Success = NvNetCopyPacket(Adapter, Packet, CoalesceBuffer);
NdisDprAcquireSpinLock(&Adapter->Send.Lock);
if (!Success || !Adapter->Send.TbdSlots || !(Adapter->Flags & NV_ACTIVE))
{
PushEntryList(&Adapter->Send.BufferList, &CoalesceBuffer->Link);
++Adapter->Send.TcbSlots;
return NDIS_STATUS_RESOURCES;
}
Flags |= NV_TCB_COALESCE;
LocalSgList.NumberOfElements = 1;
LocalSgList.Elements[0].Address = CoalesceBuffer->PhysicalAddress;
LocalSgList.Elements[0].Length = TotalLength;
SgList = &LocalSgList;
Tcb = Adapter->Send.CurrentTcb;
Tcb->Buffer = CoalesceBuffer;
}
}
else
{
if (SgList->NumberOfElements +
(NVNET_MAXIMUM_FRAME_SIZE_JUMBO / (NV_MAXIMUM_SG_SIZE + 1)) > Adapter->Send.TbdSlots)
{
return NDIS_STATUS_RESOURCES;
}
--Adapter->Send.TcbSlots;
Tcb = Adapter->Send.CurrentTcb;
}
Tcb->Packet = Packet;
Tcb->Flags = Flags;
Adapter->TransmitPacket(Adapter, Tcb, SgList);
ASSERT(Adapter->Send.TbdSlots >= Tcb->Slots);
Adapter->Send.TbdSlots -= Tcb->Slots;
Adapter->Send.CurrentTcb = NV_NEXT_TCB(Adapter, Tcb);
return NDIS_STATUS_PENDING;
}
/* FIXME: Use the proper send function (MiniportSendPackets) */
NDIS_STATUS
NTAPI
MiniportSend(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PNDIS_PACKET Packet,
_In_ UINT Flags)
{
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
UINT TotalLength;
NDIS_STATUS Status;
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
NdisQueryPacketLength(Packet, &TotalLength);
NdisDprAcquireSpinLock(&Adapter->Send.Lock);
if (!(Adapter->Flags & NV_ACTIVE))
{
NdisDprReleaseSpinLock(&Adapter->Send.Lock);
return NDIS_STATUS_FAILURE;
}
if (Adapter->Flags & NV_SEND_LARGE_SEND &&
PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo)))
{
Status = NvNetSendPacketLargeSend(Adapter, Packet, TotalLength);
}
else
{
Status = NvNetSendPacket(Adapter, Packet, TotalLength);
}
NdisDprReleaseSpinLock(&Adapter->Send.Lock);
return Status;
}