https://git.reactos.org/?p=reactos.git;a=commitdiff;h=b79fbe23339892bbd7375…
commit b79fbe23339892bbd737513d24af4edf65bff255
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Sun Jul 25 00:53:39 2021 +0600
Commit: Stanislav Motylkov <x86corez(a)gmail.com>
CommitDate: Sat Apr 16 11:54:24 2022 +0300
[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
---
drivers/network/dd/CMakeLists.txt | 3 +
drivers/network/dd/nvnet/CMakeLists.txt | 25 +
drivers/network/dd/nvnet/backoff.c | 184 ++++
drivers/network/dd/nvnet/debug.h | 43 +
drivers/network/dd/nvnet/eth.h | 57 ++
drivers/network/dd/nvnet/init.c | 885 ++++++++++++++++++
drivers/network/dd/nvnet/interrupt.c | 549 +++++++++++
drivers/network/dd/nvnet/netnv.inf | 288 ++++++
drivers/network/dd/nvnet/nic.c | 927 +++++++++++++++++++
drivers/network/dd/nvnet/nic.h | 567 ++++++++++++
drivers/network/dd/nvnet/nvnet.c | 298 ++++++
drivers/network/dd/nvnet/nvnet.h | 672 ++++++++++++++
drivers/network/dd/nvnet/nvnet.rc | 5 +
drivers/network/dd/nvnet/phy.c | 1144 +++++++++++++++++++++++
drivers/network/dd/nvnet/phyreg.h | 42 +
drivers/network/dd/nvnet/requests.c | 1505 +++++++++++++++++++++++++++++++
drivers/network/dd/nvnet/send.c | 524 +++++++++++
17 files changed, 7718 insertions(+)
diff --git a/drivers/network/dd/CMakeLists.txt b/drivers/network/dd/CMakeLists.txt
index 39a20fce8e3..f8b967412a3 100644
--- a/drivers/network/dd/CMakeLists.txt
+++ b/drivers/network/dd/CMakeLists.txt
@@ -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)
diff --git a/drivers/network/dd/nvnet/CMakeLists.txt
b/drivers/network/dd/nvnet/CMakeLists.txt
new file mode 100644
index 00000000000..81d38fe1c6e
--- /dev/null
+++ b/drivers/network/dd/nvnet/CMakeLists.txt
@@ -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)
diff --git a/drivers/network/dd/nvnet/backoff.c b/drivers/network/dd/nvnet/backoff.c
new file mode 100644
index 00000000000..3dc91ed12ec
--- /dev/null
+++ b/drivers/network/dd/nvnet/backoff.c
@@ -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(a)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);
+ }
+}
diff --git a/drivers/network/dd/nvnet/debug.h b/drivers/network/dd/nvnet/debug.h
new file mode 100644
index 00000000000..5d57903f561
--- /dev/null
+++ b/drivers/network/dd/nvnet/debug.h
@@ -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(a)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
diff --git a/drivers/network/dd/nvnet/eth.h b/drivers/network/dd/nvnet/eth.h
new file mode 100644
index 00000000000..82d7097548d
--- /dev/null
+++ b/drivers/network/dd/nvnet/eth.h
@@ -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(a)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)
diff --git a/drivers/network/dd/nvnet/init.c b/drivers/network/dd/nvnet/init.c
new file mode 100644
index 00000000000..8964805494c
--- /dev/null
+++ b/drivers/network/dd/nvnet/init.c
@@ -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(a)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;
+}
diff --git a/drivers/network/dd/nvnet/interrupt.c b/drivers/network/dd/nvnet/interrupt.c
new file mode 100644
index 00000000000..2d8a3df867e
--- /dev/null
+++ b/drivers/network/dd/nvnet/interrupt.c
@@ -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(a)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;
+ }
+}
diff --git a/drivers/network/dd/nvnet/netnv.inf b/drivers/network/dd/nvnet/netnv.inf
new file mode 100644
index 00000000000..9e1aafd4fee
--- /dev/null
+++ b/drivers/network/dd/nvnet/netnv.inf
@@ -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 сетевой контроллер"
diff --git a/drivers/network/dd/nvnet/nic.c b/drivers/network/dd/nvnet/nic.c
new file mode 100644
index 00000000000..88e7a29e3ee
--- /dev/null
+++ b/drivers/network/dd/nvnet/nic.c
@@ -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(a)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;
+}
diff --git a/drivers/network/dd/nvnet/nic.h b/drivers/network/dd/nvnet/nic.h
new file mode 100644
index 00000000000..9b4e1ec4613
--- /dev/null
+++ b/drivers/network/dd/nvnet/nic.h
@@ -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(a)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
diff --git a/drivers/network/dd/nvnet/nvnet.c b/drivers/network/dd/nvnet/nvnet.c
new file mode 100644
index 00000000000..18193b6b7d4
--- /dev/null
+++ b/drivers/network/dd/nvnet/nvnet.c
@@ -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(a)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;
+}
diff --git a/drivers/network/dd/nvnet/nvnet.h b/drivers/network/dd/nvnet/nvnet.h
new file mode 100644
index 00000000000..d4bef9c4d9c
--- /dev/null
+++ b/drivers/network/dd/nvnet/nvnet.h
@@ -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(a)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_ */
diff --git a/drivers/network/dd/nvnet/nvnet.rc b/drivers/network/dd/nvnet/nvnet.rc
new file mode 100644
index 00000000000..edaa46d858d
--- /dev/null
+++ b/drivers/network/dd/nvnet/nvnet.rc
@@ -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>
diff --git a/drivers/network/dd/nvnet/phy.c b/drivers/network/dd/nvnet/phy.c
new file mode 100644
index 00000000000..3558a785161
--- /dev/null
+++ b/drivers/network/dd/nvnet/phy.c
@@ -0,0 +1,1144 @@
+/*
+ * 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 setup and management
+ * COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean(a)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 ********************************************************************/
+
+BOOLEAN
+MiiWrite(
+ _In_ PNVNET_ADAPTER Adapter,
+ _In_ ULONG PhyAddress,
+ _In_ ULONG RegAddress,
+ _In_ ULONG Data)
+{
+ ULONG i;
+
+ NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_RW);
+
+ if (NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE)
+ {
+ NV_WRITE(Adapter, NvRegMIIControl, NVREG_MIICTL_INUSE);
+ NdisStallExecution(NV_MIIBUSY_DELAY);
+ }
+
+ NV_WRITE(Adapter, NvRegMIIData, Data);
+ NV_WRITE(Adapter, NvRegMIIControl,
+ NVREG_MIICTL_WRITE | (PhyAddress << NVREG_MIICTL_ADDRSHIFT) |
RegAddress);
+
+ for (i = NV_MIIPHY_DELAYMAX; i > 0; --i)
+ {
+ NdisStallExecution(NV_MIIPHY_DELAY);
+
+ if (!(NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE))
+ break;
+ }
+ if (i == 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+MiiRead(
+ _In_ PNVNET_ADAPTER Adapter,
+ _In_ ULONG PhyAddress,
+ _In_ ULONG RegAddress,
+ _Out_ PULONG Data)
+{
+ ULONG i;
+
+ NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_RW);
+
+ if (NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE)
+ {
+ NV_WRITE(Adapter, NvRegMIIControl, NVREG_MIICTL_INUSE);
+ NdisStallExecution(NV_MIIBUSY_DELAY);
+ }
+
+ NV_WRITE(Adapter, NvRegMIIControl, (PhyAddress << NVREG_MIICTL_ADDRSHIFT) |
RegAddress);
+
+ for (i = NV_MIIPHY_DELAYMAX; i > 0; --i)
+ {
+ NdisStallExecution(NV_MIIPHY_DELAY);
+
+ if (!(NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE))
+ break;
+ }
+ if (i == 0)
+ {
+ *Data = 0;
+ return FALSE;
+ }
+
+ if (NV_READ(Adapter, NvRegMIIStatus) & NVREG_MIISTAT_ERROR)
+ {
+ *Data = 0;
+ return FALSE;
+ }
+
+ *Data = NV_READ(Adapter, NvRegMIIData);
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+PhyInitRealtek8211b(
+ _In_ PNVNET_ADAPTER Adapter)
+{
+ ULONG i;
+ const struct
+ {
+ ULONG Register;
+ ULONG Data;
+ } Sequence[] =
+ {
+ { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 },
+ { PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2 },
+ { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3 },
+ { PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4 },
+ { PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5 },
+ { PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6 },
+ { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 }
+ };
+
+ PAGED_CODE();
+
+ NDIS_DbgPrint(MIN_TRACE, ("()\n"));
+
+ for (i = 0; i < RTL_NUMBER_OF(Sequence); ++i)
+ {
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, Sequence[i].Register,
Sequence[i].Data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+PhyInitRealtek8211c(
+ _In_ PNVNET_ADAPTER Adapter)
+{
+ ULONG PowerState, MiiRegister;
+
+ PAGED_CODE();
+
+ NDIS_DbgPrint(MIN_TRACE, ("()\n"));
+
+ PowerState = NV_READ(Adapter, NvRegPowerState2);
+
+ NV_WRITE(Adapter, NvRegPowerState2, PowerState | NVREG_POWERSTATE2_PHY_RESET);
+ NdisMSleep(25000);
+
+ NV_WRITE(Adapter, NvRegPowerState2, PowerState);
+ NdisMSleep(25000);
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6, &MiiRegister);
+ MiiRegister |= PHY_REALTEK_INIT9;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6, MiiRegister))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1,
PHY_REALTEK_INIT10))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG7, &MiiRegister);
+ if (!(MiiRegister & PHY_REALTEK_INIT11))
+ {
+ MiiRegister |= PHY_REALTEK_INIT11;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG7,
MiiRegister))
+ return FALSE;
+ }
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1,
PHY_REALTEK_INIT1))
+ return FALSE;
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+PhyInitRealtek8201(
+ _In_ PNVNET_ADAPTER Adapter,
+ _In_ BOOLEAN DisableCrossoverDetection)
+{
+ ULONG MiiRegister;
+
+ PAGED_CODE();
+
+ NDIS_DbgPrint(MIN_TRACE, ("()\n"));
+
+ if (Adapter->Features & DEV_NEED_PHY_INIT_FIX)
+ {
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6,
&MiiRegister);
+ MiiRegister |= PHY_REALTEK_INIT7;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6,
MiiRegister))
+ return FALSE;
+ }
+
+ if (DisableCrossoverDetection)
+ {
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1,
PHY_REALTEK_INIT3))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG2,
&MiiRegister);
+ MiiRegister &= ~PHY_REALTEK_INIT_MSK1;
+ MiiRegister |= PHY_REALTEK_INIT3;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG2,
MiiRegister))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1,
PHY_REALTEK_INIT1))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+PhyInitCicadaSemiconductor(
+ _In_ PNVNET_ADAPTER Adapter,
+ _In_ ULONG PhyInterface)
+{
+ ULONG MiiRegister;
+
+ PAGED_CODE();
+
+ NDIS_DbgPrint(MIN_TRACE, ("()\n"));
+
+ if (PhyInterface & PHY_RGMII)
+ {
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG2,
&MiiRegister);
+ MiiRegister &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2);
+ MiiRegister |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4);
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG2,
MiiRegister))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG3,
&MiiRegister);
+ MiiRegister |= PHY_CICADA_INIT5;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG3,
MiiRegister))
+ return FALSE;
+ }
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG1, &MiiRegister);
+ MiiRegister |= PHY_CICADA_INIT6;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG1, MiiRegister))
+ return FALSE;
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+PhyInitVitesseSemiconductor(
+ _In_ PNVNET_ADAPTER Adapter)
+{
+ ULONG MiiRegister;
+
+ PAGED_CODE();
+
+ NDIS_DbgPrint(MIN_TRACE, ("()\n"));
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG1,
PHY_VITESSE_INIT1))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2,
PHY_VITESSE_INIT2))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, &MiiRegister);
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, MiiRegister))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, &MiiRegister);
+ MiiRegister &= ~PHY_VITESSE_INIT_MSK1;
+ MiiRegister |= PHY_VITESSE_INIT3;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, MiiRegister))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2,
PHY_VITESSE_INIT4))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2,
PHY_VITESSE_INIT5))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, &MiiRegister);
+ MiiRegister &= ~PHY_VITESSE_INIT_MSK1;
+ MiiRegister |= PHY_VITESSE_INIT3;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, MiiRegister))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, &MiiRegister);
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, MiiRegister))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2,
PHY_VITESSE_INIT6))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2,
PHY_VITESSE_INIT7))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, &MiiRegister);
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, MiiRegister))
+ return FALSE;
+
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, &MiiRegister);
+ MiiRegister &= ~PHY_VITESSE_INIT_MSK2;
+ MiiRegister |= PHY_VITESSE_INIT8;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, MiiRegister))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2,
PHY_VITESSE_INIT9))
+ return FALSE;
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG1,
PHY_VITESSE_INIT10))
+ return FALSE;
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+PhyReset(
+ _In_ PNVNET_ADAPTER Adapter,
+ _In_ ULONG ControlSetup)
+{
+ ULONG Tries = 0, MiiControl = MII_CR_RESET | ControlSetup;
+
+ PAGED_CODE();
+
+ NDIS_DbgPrint(MIN_TRACE, ("()\n"));
+
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl))
+ return FALSE;
+
+ NdisMSleep(500000);
+
+ do
+ {
+ NdisMSleep(10000);
+
+ MiiRead(Adapter, Adapter->PhyAddress, MII_CONTROL, &MiiControl);
+
+ if (Tries++ > 100)
+ return FALSE;
+ }
+ while (MiiControl & MII_CR_RESET);
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+PhyInit(
+ _In_ PNVNET_ADAPTER Adapter)
+{
+ ULONG PhyInterface, MiiRegister, MiiStatus, MiiControl;
+
+ PAGED_CODE();
+
+ NDIS_DbgPrint(MIN_TRACE, ("()\n"));
+
+ /* PHY errata for E3016 PHY */
+ if (Adapter->PhyModel == PHY_MODEL_MARVELL_E3016)
+ {
+ MiiRead(Adapter, Adapter->PhyAddress, PHY_MARVELL_INIT_REG1,
&MiiRegister);
+ MiiRegister &= ~PHY_MARVELL_E3016_INITMASK;
+ if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_MARVELL_INIT_REG1,
MiiRegister))
+ {
+ NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n"));
+ return NDIS_STATUS_FAILURE;
... 2858 lines suppressed ...