mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
0af84ce12d
Fix suggested by Hermès Bélusca-Maïto. CORE-15872
1481 lines
44 KiB
C
1481 lines
44 KiB
C
/*
|
|
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
* PURPOSE: Miniport information callbacks
|
|
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "nvnet.h"
|
|
|
|
#define NDEBUG
|
|
#include "debug.h"
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
static const NDIS_OID NvpSupportedOidList[] =
|
|
{
|
|
OID_GEN_SUPPORTED_LIST,
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
OID_GEN_HARDWARE_STATUS,
|
|
OID_GEN_MEDIA_SUPPORTED,
|
|
OID_GEN_MEDIA_IN_USE,
|
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
OID_GEN_MAXIMUM_SEND_PACKETS,
|
|
OID_GEN_LINK_SPEED,
|
|
OID_GEN_TRANSMIT_BUFFER_SPACE,
|
|
OID_GEN_RECEIVE_BUFFER_SPACE,
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
OID_GEN_VENDOR_ID,
|
|
OID_GEN_VENDOR_DESCRIPTION,
|
|
OID_GEN_VENDOR_DRIVER_VERSION,
|
|
OID_GEN_CURRENT_LOOKAHEAD,
|
|
OID_GEN_DRIVER_VERSION,
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
OID_GEN_MAC_OPTIONS,
|
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
|
OID_GEN_VLAN_ID,
|
|
OID_802_3_PERMANENT_ADDRESS,
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
OID_802_3_MULTICAST_LIST,
|
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
|
|
/* Statistics */
|
|
OID_GEN_XMIT_OK,
|
|
OID_GEN_RCV_OK,
|
|
OID_GEN_XMIT_ERROR,
|
|
OID_GEN_RCV_ERROR,
|
|
OID_GEN_RCV_NO_BUFFER,
|
|
OID_GEN_DIRECTED_FRAMES_RCV,
|
|
OID_GEN_RCV_CRC_ERROR,
|
|
OID_GEN_TRANSMIT_QUEUE_LENGTH,
|
|
OID_802_3_RCV_ERROR_ALIGNMENT,
|
|
OID_802_3_XMIT_ONE_COLLISION,
|
|
OID_802_3_XMIT_MORE_COLLISIONS,
|
|
OID_802_3_XMIT_DEFERRED,
|
|
OID_802_3_XMIT_MAX_COLLISIONS,
|
|
OID_802_3_RCV_OVERRUN,
|
|
OID_802_3_XMIT_UNDERRUN,
|
|
OID_802_3_XMIT_HEARTBEAT_FAILURE,
|
|
OID_802_3_XMIT_TIMES_CRS_LOST,
|
|
OID_802_3_XMIT_LATE_COLLISIONS,
|
|
|
|
/* Offload */
|
|
OID_TCP_TASK_OFFLOAD,
|
|
|
|
/* Power management */
|
|
OID_PNP_CAPABILITIES,
|
|
OID_PNP_SET_POWER,
|
|
OID_PNP_QUERY_POWER,
|
|
OID_PNP_ADD_WAKE_UP_PATTERN,
|
|
OID_PNP_REMOVE_WAKE_UP_PATTERN,
|
|
OID_PNP_ENABLE_WAKE_UP
|
|
};
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
static
|
|
ULONG
|
|
NvNetGetLinkSpeed(
|
|
_In_ PNVNET_ADAPTER Adapter)
|
|
{
|
|
ULONG LinkSpeedMbps;
|
|
|
|
switch (Adapter->LinkSpeed)
|
|
{
|
|
case NVREG_LINKSPEED_10:
|
|
LinkSpeedMbps = 10;
|
|
break;
|
|
case NVREG_LINKSPEED_100:
|
|
LinkSpeedMbps = 100;
|
|
break;
|
|
case NVREG_LINKSPEED_1000:
|
|
LinkSpeedMbps = 1000;
|
|
break;
|
|
|
|
default:
|
|
UNREACHABLE;
|
|
break;
|
|
}
|
|
|
|
return LinkSpeedMbps;
|
|
}
|
|
|
|
static
|
|
ULONG
|
|
PacketFilterToMask(
|
|
_In_ ULONG PacketFilter)
|
|
{
|
|
ULONG FilterMask = NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR | NVREG_PFF_PROMISC;
|
|
|
|
if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
|
|
{
|
|
FilterMask &= ~NVREG_PFF_MYADDR;
|
|
}
|
|
|
|
if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
|
|
{
|
|
FilterMask &= ~NVREG_PFF_PROMISC;
|
|
}
|
|
|
|
return FilterMask;
|
|
}
|
|
|
|
static
|
|
DECLSPEC_NOINLINE /* Called from pageable code */
|
|
VOID
|
|
NvNetApplyPacketFilter(
|
|
_In_ PNVNET_ADAPTER Adapter)
|
|
{
|
|
UCHAR Address[ETH_LENGTH_OF_ADDRESS];
|
|
UCHAR Mask[ETH_LENGTH_OF_ADDRESS];
|
|
ULONG FilterMask;
|
|
BOOLEAN RestartReceiver;
|
|
|
|
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
|
|
{
|
|
NdisZeroMemory(Address, sizeof(Address));
|
|
NdisZeroMemory(Mask, sizeof(Mask));
|
|
|
|
Address[0] |= NVREG_MCASTADDRA_FORCE;
|
|
Mask[0] |= NVREG_MCASTADDRA_FORCE;
|
|
}
|
|
else if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MULTICAST)
|
|
{
|
|
if (Adapter->MulticastListSize > 0)
|
|
{
|
|
ULONG i, j;
|
|
|
|
NdisFillMemory(Address, sizeof(Address), 0xFF);
|
|
NdisFillMemory(Mask, sizeof(Mask), 0xFF);
|
|
|
|
for (i = 0; i < Adapter->MulticastListSize; ++i)
|
|
{
|
|
PUCHAR MacAddress = Adapter->MulticastList[i].MacAddress;
|
|
|
|
for (j = 0; j < ETH_LENGTH_OF_ADDRESS; ++j)
|
|
{
|
|
Address[j] &= MacAddress[j];
|
|
Mask[j] &= ~MacAddress[j];
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < ETH_LENGTH_OF_ADDRESS; ++j)
|
|
{
|
|
Mask[j] |= Address[j];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NdisZeroMemory(Address, sizeof(Address));
|
|
NdisZeroMemory(Mask, sizeof(Mask));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NdisZeroMemory(Address, sizeof(Address));
|
|
NdisFillMemory(Mask, sizeof(Mask), 0xFF);
|
|
}
|
|
|
|
FilterMask = NV_READ(Adapter, NvRegPacketFilterFlags) & NVREG_PFF_PAUSE_RX;
|
|
FilterMask |= PacketFilterToMask(Adapter->PacketFilter);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Receive.Lock);
|
|
|
|
RestartReceiver = !!(NV_READ(Adapter, NvRegReceiverControl) & NVREG_RCVCTL_START);
|
|
if (RestartReceiver)
|
|
{
|
|
NvNetStopReceiver(Adapter);
|
|
}
|
|
|
|
NV_WRITE(Adapter, NvRegMulticastAddrA,
|
|
Address[3] << 24 | Address[2] << 16 | Address[1] << 8 | Address[0]);
|
|
NV_WRITE(Adapter, NvRegMulticastAddrB, Address[5] << 8 | Address[4]);
|
|
NV_WRITE(Adapter, NvRegMulticastMaskA,
|
|
Mask[3] << 24 | Mask[2] << 16 | Mask[1] << 8 | Mask[0]);
|
|
NV_WRITE(Adapter, NvRegMulticastMaskB, Mask[5] << 8 | Mask[4]);
|
|
|
|
NV_WRITE(Adapter, NvRegPacketFilterFlags, FilterMask);
|
|
|
|
if (RestartReceiver)
|
|
{
|
|
NvNetStartReceiver(Adapter);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->Receive.Lock);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
NvNetReadStatistics(
|
|
_In_ PNVNET_ADAPTER Adapter)
|
|
{
|
|
Adapter->Statistics.HwTxCnt += NV_READ(Adapter, NvRegTxCnt);
|
|
Adapter->Statistics.HwTxZeroReXmt += NV_READ(Adapter, NvRegTxZeroReXmt);
|
|
Adapter->Statistics.HwTxOneReXmt += NV_READ(Adapter, NvRegTxOneReXmt);
|
|
Adapter->Statistics.HwTxManyReXmt += NV_READ(Adapter, NvRegTxManyReXmt);
|
|
Adapter->Statistics.HwTxLateCol += NV_READ(Adapter, NvRegTxLateCol);
|
|
Adapter->Statistics.HwTxUnderflow += NV_READ(Adapter, NvRegTxUnderflow);
|
|
Adapter->Statistics.HwTxLossCarrier += NV_READ(Adapter, NvRegTxLossCarrier);
|
|
Adapter->Statistics.HwTxExcessDef += NV_READ(Adapter, NvRegTxExcessDef);
|
|
Adapter->Statistics.HwTxRetryErr += NV_READ(Adapter, NvRegTxRetryErr);
|
|
Adapter->Statistics.HwRxFrameErr += NV_READ(Adapter, NvRegRxFrameErr);
|
|
Adapter->Statistics.HwRxExtraByte += NV_READ(Adapter, NvRegRxExtraByte);
|
|
Adapter->Statistics.HwRxLateCol += NV_READ(Adapter, NvRegRxLateCol);
|
|
Adapter->Statistics.HwRxRunt += NV_READ(Adapter, NvRegRxRunt);
|
|
Adapter->Statistics.HwRxFrameTooLong += NV_READ(Adapter, NvRegRxFrameTooLong);
|
|
Adapter->Statistics.HwRxOverflow += NV_READ(Adapter, NvRegRxOverflow);
|
|
Adapter->Statistics.HwRxFCSErr += NV_READ(Adapter, NvRegRxFCSErr);
|
|
Adapter->Statistics.HwRxFrameAlignErr += NV_READ(Adapter, NvRegRxFrameAlignErr);
|
|
Adapter->Statistics.HwRxLenErr += NV_READ(Adapter, NvRegRxLenErr);
|
|
Adapter->Statistics.HwRxUnicast += NV_READ(Adapter, NvRegRxUnicast);
|
|
Adapter->Statistics.HwRxMulticast += NV_READ(Adapter, NvRegRxMulticast);
|
|
Adapter->Statistics.HwRxBroadcast += NV_READ(Adapter, NvRegRxBroadcast);
|
|
|
|
if (Adapter->Features & DEV_HAS_STATISTICS_V2)
|
|
{
|
|
Adapter->Statistics.HwTxDef += NV_READ(Adapter, NvRegTxDef);
|
|
Adapter->Statistics.HwTxFrame += NV_READ(Adapter, NvRegTxFrame);
|
|
Adapter->Statistics.HwRxCnt += NV_READ(Adapter, NvRegRxCnt);
|
|
Adapter->Statistics.HwTxPause += NV_READ(Adapter, NvRegTxPause);
|
|
Adapter->Statistics.HwRxPause += NV_READ(Adapter, NvRegRxPause);
|
|
Adapter->Statistics.HwRxDropFrame += NV_READ(Adapter, NvRegRxDropFrame);
|
|
}
|
|
|
|
if (Adapter->Features & DEV_HAS_STATISTICS_V3)
|
|
{
|
|
Adapter->Statistics.HwTxUnicast += NV_READ(Adapter, NvRegTxUnicast);
|
|
Adapter->Statistics.HwTxMulticast += NV_READ(Adapter, NvRegTxMulticast);
|
|
Adapter->Statistics.HwTxBroadcast += NV_READ(Adapter, NvRegTxBroadcast);
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
NvNetQueryHwCounter(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ NDIS_OID Oid,
|
|
_Out_ PULONG64 Counter)
|
|
{
|
|
switch (Oid)
|
|
{
|
|
case OID_GEN_XMIT_OK:
|
|
*Counter = (Adapter->Features & DEV_HAS_STATISTICS_V2)
|
|
? Adapter->Statistics.HwTxFrame
|
|
: (Adapter->Statistics.HwTxZeroReXmt +
|
|
Adapter->Statistics.HwTxOneReXmt +
|
|
Adapter->Statistics.HwTxManyReXmt);
|
|
break;
|
|
case OID_GEN_RCV_OK:
|
|
*Counter = (Adapter->Statistics.HwRxUnicast +
|
|
Adapter->Statistics.HwRxMulticast +
|
|
Adapter->Statistics.HwRxBroadcast);
|
|
break;
|
|
case OID_GEN_XMIT_ERROR:
|
|
*Counter = (Adapter->Statistics.HwTxRetryErr +
|
|
Adapter->Statistics.HwTxLateCol +
|
|
Adapter->Statistics.HwTxUnderflow +
|
|
Adapter->Statistics.HwTxLossCarrier +
|
|
Adapter->Statistics.HwTxExcessDef);
|
|
break;
|
|
case OID_GEN_RCV_ERROR:
|
|
*Counter = (Adapter->Statistics.HwRxFrameAlignErr +
|
|
Adapter->Statistics.HwRxLenErr +
|
|
Adapter->Statistics.HwRxRunt +
|
|
Adapter->Statistics.HwRxFrameTooLong +
|
|
Adapter->Statistics.HwRxFCSErr +
|
|
Adapter->Statistics.HwRxFrameErr +
|
|
Adapter->Statistics.HwRxExtraByte +
|
|
Adapter->Statistics.HwRxLateCol);
|
|
break;
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
*Counter = (Adapter->Statistics.HwRxDropFrame +
|
|
Adapter->Statistics.HwRxOverflow +
|
|
Adapter->Statistics.ReceiveIrqNoBuffers);
|
|
break;
|
|
case OID_GEN_DIRECTED_FRAMES_RCV:
|
|
*Counter = Adapter->Statistics.HwRxUnicast;
|
|
break;
|
|
case OID_GEN_RCV_CRC_ERROR:
|
|
*Counter = Adapter->Statistics.HwRxFCSErr;
|
|
break;
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
*Counter = Adapter->Statistics.HwRxFrameErr;
|
|
break;
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
*Counter = Adapter->Statistics.HwTxOneReXmt;
|
|
break;
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
*Counter = Adapter->Statistics.HwTxManyReXmt;
|
|
break;
|
|
case OID_802_3_XMIT_DEFERRED:
|
|
*Counter = Adapter->Statistics.HwTxDef;
|
|
break;
|
|
case OID_802_3_XMIT_MAX_COLLISIONS:
|
|
*Counter = Adapter->Statistics.HwTxRetryErr;
|
|
break;
|
|
case OID_802_3_RCV_OVERRUN:
|
|
*Counter = Adapter->Statistics.HwRxOverflow;
|
|
break;
|
|
case OID_802_3_XMIT_UNDERRUN:
|
|
*Counter = Adapter->Statistics.HwTxUnderflow;
|
|
break;
|
|
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
|
|
*Counter = Adapter->Statistics.HwTxZeroReXmt;
|
|
break;
|
|
case OID_802_3_XMIT_TIMES_CRS_LOST:
|
|
*Counter = Adapter->Statistics.HwTxLossCarrier;
|
|
break;
|
|
case OID_802_3_XMIT_LATE_COLLISIONS:
|
|
*Counter = Adapter->Statistics.HwTxLateCol;
|
|
break;
|
|
|
|
default:
|
|
UNREACHABLE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
NvNetQuerySoftwareCounter(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ NDIS_OID Oid,
|
|
_Out_ PULONG64 Counter)
|
|
{
|
|
switch (Oid)
|
|
{
|
|
case OID_GEN_XMIT_OK:
|
|
*Counter = Adapter->Statistics.TransmitOk;
|
|
break;
|
|
case OID_GEN_RCV_OK:
|
|
*Counter = Adapter->Statistics.ReceiveOk;
|
|
break;
|
|
case OID_GEN_XMIT_ERROR:
|
|
*Counter = Adapter->Statistics.TransmitErrors;
|
|
break;
|
|
case OID_GEN_RCV_ERROR:
|
|
*Counter = Adapter->Statistics.ReceiveErrors;
|
|
break;
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
*Counter = Adapter->Statistics.ReceiveNoBuffers;
|
|
break;
|
|
case OID_GEN_DIRECTED_FRAMES_RCV:
|
|
*Counter = 0;
|
|
break;
|
|
case OID_GEN_RCV_CRC_ERROR:
|
|
*Counter = Adapter->Statistics.ReceiveCrcErrors;
|
|
break;
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
*Counter = Adapter->Statistics.ReceiveAlignmentErrors;
|
|
break;
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
*Counter = Adapter->Statistics.TransmitOneRetry;
|
|
break;
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
*Counter = (Adapter->Statistics.TransmitOk -
|
|
Adapter->Statistics.TransmitOneRetry -
|
|
Adapter->Statistics.TransmitZeroRetry);
|
|
break;
|
|
case OID_802_3_XMIT_DEFERRED:
|
|
*Counter = Adapter->Statistics.TransmitDeferred;
|
|
break;
|
|
case OID_802_3_XMIT_MAX_COLLISIONS:
|
|
*Counter = Adapter->Statistics.TransmitExcessiveCollisions;
|
|
break;
|
|
case OID_802_3_RCV_OVERRUN:
|
|
*Counter = Adapter->Statistics.ReceiveOverrunErrors;
|
|
break;
|
|
case OID_802_3_XMIT_UNDERRUN:
|
|
*Counter = Adapter->Statistics.TransmitUnderrunErrors;
|
|
break;
|
|
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
|
|
*Counter = Adapter->Statistics.TransmitZeroRetry;
|
|
break;
|
|
case OID_802_3_XMIT_TIMES_CRS_LOST:
|
|
*Counter = Adapter->Statistics.TransmitLostCarrierSense;
|
|
break;
|
|
case OID_802_3_XMIT_LATE_COLLISIONS:
|
|
*Counter = Adapter->Statistics.TransmitLateCollisions;
|
|
break;
|
|
|
|
default:
|
|
UNREACHABLE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static
|
|
NDIS_STATUS
|
|
NvNetFillPowerManagementCapabilities(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_Out_ PNDIS_PNP_CAPABILITIES Capabilities)
|
|
{
|
|
Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp =
|
|
Capabilities->WakeUpCapabilities.MinPatternWakeUp =
|
|
Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateD3;
|
|
|
|
/* All hardware is PM-aware */
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
ULONG
|
|
BuildFrameSignature(
|
|
_In_ PNVNET_WAKE_FRAME WakeFrame)
|
|
{
|
|
ULONG i, j, Crc;
|
|
|
|
Crc = 0xFFFFFFFF;
|
|
for (i = 0; i < sizeof(WakeFrame->WakeUpPattern); ++i)
|
|
{
|
|
if (WakeFrame->PatternMask.AsUCHAR[i / 8] & (1 << (i % 8)))
|
|
{
|
|
Crc ^= WakeFrame->WakeUpPattern[i];
|
|
for (j = 8; j > 0; --j)
|
|
{
|
|
Crc = (Crc >> 1) ^ (-(LONG)(Crc & 1) & 0xEDB88320);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ~Crc;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
WriteWakeFrame(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ PNVNET_WAKE_FRAME WakeFrame,
|
|
_In_ ULONG FrameNumber)
|
|
{
|
|
ULONG Offset = FrameNumber * 5 * sizeof(ULONG);
|
|
|
|
if (FrameNumber >= NV_WAKEUPPATTERNS)
|
|
{
|
|
Offset += NV_PATTERN_V2_OFFSET;
|
|
}
|
|
|
|
NV_WRITE(Adapter, NvRegPatternCrc + Offset, BuildFrameSignature(WakeFrame));
|
|
NV_WRITE(Adapter, NvRegPatternMask0 + Offset, WakeFrame->PatternMask.AsULONG[0]);
|
|
NV_WRITE(Adapter, NvRegPatternMask1 + Offset, WakeFrame->PatternMask.AsULONG[1]);
|
|
NV_WRITE(Adapter, NvRegPatternMask2 + Offset, WakeFrame->PatternMask.AsULONG[2]);
|
|
NV_WRITE(Adapter, NvRegPatternMask3 + Offset, WakeFrame->PatternMask.AsULONG[3]);
|
|
}
|
|
|
|
static
|
|
ULONG
|
|
FrameNumberToWakeUpMask(
|
|
_In_ ULONG FrameNumber)
|
|
{
|
|
if (FrameNumber < 5)
|
|
return 0x10000 << FrameNumber;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
ULONG
|
|
FrameNumberToPowerMask(
|
|
_In_ ULONG FrameNumber)
|
|
{
|
|
switch (FrameNumber)
|
|
{
|
|
case 5:
|
|
return NVREG_POWERSTATE2_WAKEUPPAT_5;
|
|
case 6:
|
|
return NVREG_POWERSTATE2_WAKEUPPAT_6;
|
|
case 7:
|
|
return NVREG_POWERSTATE2_WAKEUPPAT_7;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NvNetSetPowerState(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ NDIS_DEVICE_POWER_STATE NewPowerState,
|
|
_In_ ULONG WakeFlags)
|
|
{
|
|
ULONG i, PowerState, PowerState2, WakeUpFlags;
|
|
|
|
NV_READ(Adapter, NvRegPowerCap);
|
|
|
|
WakeUpFlags = 0;
|
|
PowerState2 = 0;
|
|
if (Adapter->Features & DEV_HAS_POWER_CNTRL)
|
|
{
|
|
PowerState2 = NV_READ(Adapter, NvRegPowerState2);
|
|
PowerState2 &= ~(NVREG_POWERSTATE2_WAKEUPPAT_5 |
|
|
NVREG_POWERSTATE2_WAKEUPPAT_6 |
|
|
NVREG_POWERSTATE2_WAKEUPPAT_7);
|
|
}
|
|
|
|
if (NewPowerState != NdisDeviceStateD0)
|
|
{
|
|
ULONG FramesEnabled = 0;
|
|
|
|
if (WakeFlags & NDIS_PNP_WAKE_UP_PATTERN_MATCH)
|
|
WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_MAGPAT;
|
|
if (WakeFlags & NDIS_PNP_WAKE_UP_LINK_CHANGE)
|
|
WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_LINKCHANGE;
|
|
if (WakeFlags & NDIS_PNP_WAKE_UP_MAGIC_PACKET)
|
|
{
|
|
WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_WAKEUPPAT;
|
|
|
|
for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i)
|
|
{
|
|
PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
|
|
|
|
if (!WakeFrame)
|
|
continue;
|
|
|
|
WriteWakeFrame(Adapter, WakeFrame, i);
|
|
|
|
PowerState2 |= FrameNumberToPowerMask(i);
|
|
WakeUpFlags |= FrameNumberToWakeUpMask(i);
|
|
|
|
++FramesEnabled;
|
|
}
|
|
}
|
|
|
|
if (WakeUpFlags)
|
|
{
|
|
if (!(Adapter->Flags & NV_MAC_IN_USE))
|
|
{
|
|
PowerState2 &= ~NVREG_POWERSTATE2_GATE_CLOCKS;
|
|
PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_3;
|
|
|
|
if (!FramesEnabled && (WakeUpFlags & NVREG_WAKEUPFLAGS_ENABLE_LINKCHANGE))
|
|
PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_1;
|
|
if (FramesEnabled < NV_WAKEUPMASKENTRIES)
|
|
PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_2;
|
|
}
|
|
|
|
NvNetStartReceiver(Adapter);
|
|
}
|
|
else
|
|
{
|
|
if (!(Adapter->Flags & NV_MAC_IN_USE))
|
|
PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCKS;
|
|
}
|
|
}
|
|
|
|
NdisStallExecution(NV_POWER_STALL);
|
|
|
|
NV_WRITE(Adapter, NvRegWakeUpFlags, WakeUpFlags);
|
|
if (Adapter->Features & DEV_HAS_POWER_CNTRL)
|
|
{
|
|
NV_WRITE(Adapter, NvRegPowerState2, PowerState2);
|
|
}
|
|
|
|
NV_WRITE(Adapter, NvRegPowerState,
|
|
NV_READ(Adapter, NvRegPowerState) | NVREG_POWERSTATE_POWEREDUP);
|
|
for (i = 0; i < NV_POWER_ATTEMPTS; ++i)
|
|
{
|
|
ULONG State = NV_READ(Adapter, NvRegPowerState);
|
|
|
|
if (!(State & NVREG_POWERSTATE_POWEREDUP))
|
|
break;
|
|
|
|
NV_WRITE(Adapter, NvRegPowerState, State | NVREG_POWERSTATE_POWEREDUP);
|
|
|
|
NdisStallExecution(NV_POWER_DELAY);
|
|
}
|
|
|
|
PowerState = NewPowerState - 1;
|
|
if (WakeUpFlags)
|
|
{
|
|
PowerState |= NVREG_POWERSTATE_VALID;
|
|
}
|
|
NV_WRITE(Adapter, NvRegPowerState, PowerState);
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
VOID
|
|
NTAPI
|
|
NvNetPowerWorker(
|
|
_In_ PNDIS_WORK_ITEM WorkItem,
|
|
_In_opt_ PVOID Context)
|
|
{
|
|
PNVNET_ADAPTER Adapter = Context;
|
|
|
|
UNREFERENCED_PARAMETER(WorkItem);
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Adapter->PowerStatePending == NdisDeviceStateD0)
|
|
{
|
|
NvNetSetPowerState(Adapter, NdisDeviceStateD0, 0);
|
|
|
|
NT_VERIFY(NvNetInitNIC(Adapter, TRUE) == NDIS_STATUS_SUCCESS);
|
|
|
|
NvNetStartAdapter(Adapter);
|
|
|
|
NvNetApplyPacketFilter(Adapter);
|
|
}
|
|
else
|
|
{
|
|
NvNetPauseProcessing(Adapter);
|
|
|
|
NvNetStopAdapter(Adapter);
|
|
|
|
NvNetIdleTransmitter(Adapter, FALSE);
|
|
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);
|
|
|
|
NvNetSetPowerState(Adapter, Adapter->PowerStatePending, Adapter->WakeFlags);
|
|
}
|
|
|
|
NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
static
|
|
NDIS_STATUS
|
|
NvNetSetPower(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ NDIS_DEVICE_POWER_STATE NewPowerState)
|
|
{
|
|
Adapter->PowerStatePending = NewPowerState;
|
|
|
|
NdisInitializeWorkItem(&Adapter->PowerWorkItem, NvNetPowerWorker, Adapter);
|
|
NdisScheduleWorkItem(&Adapter->PowerWorkItem);
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
static
|
|
NDIS_STATUS
|
|
NvNetAddWakeUpPattern(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ PNDIS_PM_PACKET_PATTERN Pattern)
|
|
{
|
|
ULONG FrameNumber;
|
|
NDIS_STATUS Status;
|
|
PNVNET_WAKE_FRAME WakeFrame;
|
|
|
|
if (!_BitScanForward(&FrameNumber, Adapter->WakeFrameBitmap))
|
|
{
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
Status = NdisAllocateMemoryWithTag((PVOID*)&WakeFrame, sizeof(*WakeFrame), NVNET_TAG);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
Adapter->WakeFrameBitmap &= ~(1 << FrameNumber);
|
|
|
|
NdisZeroMemory(WakeFrame, sizeof(*WakeFrame));
|
|
NdisMoveMemory(&WakeFrame->PatternMask,
|
|
(PUCHAR)Pattern + sizeof(NDIS_PM_PACKET_PATTERN),
|
|
min(Pattern->MaskSize, 16));
|
|
NdisMoveMemory(&WakeFrame->WakeUpPattern,
|
|
(PUCHAR)Pattern + Pattern->PatternOffset,
|
|
min(Pattern->PatternSize, 128));
|
|
Adapter->WakeFrames[FrameNumber] = WakeFrame;
|
|
|
|
/* TODO: VLAN frame translation */
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
NDIS_STATUS
|
|
NvNetRemoveWakeUpPattern(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ PNDIS_PM_PACKET_PATTERN Pattern)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i)
|
|
{
|
|
PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
|
|
|
|
if (!WakeFrame)
|
|
continue;
|
|
|
|
if (!NdisEqualMemory(&WakeFrame->PatternMask,
|
|
(PUCHAR)Pattern + sizeof(NDIS_PM_PACKET_PATTERN),
|
|
min(Pattern->MaskSize, 16)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!NdisEqualMemory(&WakeFrame->WakeUpPattern,
|
|
(PUCHAR)Pattern + Pattern->PatternOffset,
|
|
min(Pattern->PatternSize, 128)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
NdisFreeMemory(WakeFrame, sizeof(*WakeFrame), 0);
|
|
|
|
Adapter->WakeFrameBitmap |= (1 << i);
|
|
Adapter->WakeFrames[i] = NULL;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return NDIS_STATUS_INVALID_DATA;
|
|
}
|
|
|
|
static
|
|
ULONG
|
|
NvNetGetWakeUp(
|
|
_In_ PNVNET_ADAPTER Adapter)
|
|
{
|
|
return Adapter->WakeFlags & (NDIS_PNP_WAKE_UP_MAGIC_PACKET |
|
|
NDIS_PNP_WAKE_UP_PATTERN_MATCH |
|
|
NDIS_PNP_WAKE_UP_LINK_CHANGE);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
NvNetEnableWakeUp(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ ULONG Flags)
|
|
{
|
|
Adapter->WakeFlags = Flags;
|
|
}
|
|
|
|
static
|
|
NDIS_STATUS
|
|
NvNetGetTcpTaskOffload(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,
|
|
_In_ ULONG InformationBufferLength,
|
|
_Out_ PULONG BytesWritten,
|
|
_Out_ PULONG BytesNeeded)
|
|
{
|
|
ULONG InfoLength;
|
|
PNDIS_TASK_OFFLOAD TaskOffload;
|
|
|
|
if (!(Adapter->Flags & (NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND)))
|
|
{
|
|
*BytesWritten = 0;
|
|
*BytesNeeded = 0;
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
InfoLength = sizeof(NDIS_TASK_OFFLOAD_HEADER);
|
|
if (Adapter->Flags & NV_SEND_CHECKSUM)
|
|
{
|
|
InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
|
|
sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
|
|
}
|
|
if (Adapter->Flags & NV_SEND_LARGE_SEND)
|
|
{
|
|
InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
|
|
sizeof(NDIS_TASK_TCP_LARGE_SEND);
|
|
}
|
|
|
|
if (InformationBufferLength < InfoLength)
|
|
{
|
|
*BytesWritten = 0;
|
|
*BytesNeeded = InfoLength;
|
|
return NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
}
|
|
|
|
if ((TaskOffloadHeader->EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) &&
|
|
(TaskOffloadHeader->EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation ||
|
|
TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER)))
|
|
{
|
|
*BytesWritten = 0;
|
|
*BytesNeeded = 0;
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION)
|
|
{
|
|
*BytesWritten = 0;
|
|
*BytesNeeded = 0;
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
TaskOffloadHeader->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER);
|
|
TaskOffload = (PNDIS_TASK_OFFLOAD)(TaskOffloadHeader + 1);
|
|
if (Adapter->Flags & NV_SEND_CHECKSUM)
|
|
{
|
|
PNDIS_TASK_TCP_IP_CHECKSUM ChecksumTask;
|
|
|
|
TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD);
|
|
TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION;
|
|
TaskOffload->Task = TcpIpChecksumNdisTask;
|
|
TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
|
|
TaskOffload->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
|
|
sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
|
|
|
|
ChecksumTask = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer;
|
|
NdisZeroMemory(ChecksumTask, sizeof(*ChecksumTask));
|
|
|
|
ChecksumTask->V4Transmit.IpOptionsSupported = 1;
|
|
ChecksumTask->V4Transmit.TcpOptionsSupported = 1;
|
|
ChecksumTask->V4Transmit.TcpChecksum = 1;
|
|
ChecksumTask->V4Transmit.UdpChecksum = 1;
|
|
ChecksumTask->V4Transmit.IpChecksum = 1;
|
|
|
|
ChecksumTask->V4Receive.IpOptionsSupported = 1;
|
|
ChecksumTask->V4Receive.TcpOptionsSupported = 1;
|
|
ChecksumTask->V4Receive.TcpChecksum = 1;
|
|
ChecksumTask->V4Receive.UdpChecksum = 1;
|
|
ChecksumTask->V4Receive.IpChecksum = 1;
|
|
|
|
TaskOffload = (PNDIS_TASK_OFFLOAD)(ChecksumTask + 1);
|
|
}
|
|
if (Adapter->Flags & NV_SEND_LARGE_SEND)
|
|
{
|
|
PNDIS_TASK_TCP_LARGE_SEND LargeSendTask;
|
|
|
|
TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD);
|
|
TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION;
|
|
TaskOffload->Task = TcpLargeSendNdisTask;
|
|
TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
|
|
TaskOffload->OffsetNextTask = 0;
|
|
|
|
LargeSendTask = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer;
|
|
LargeSendTask->Version = NDIS_TASK_TCP_LARGE_SEND_V0;
|
|
LargeSendTask->MinSegmentCount = NVNET_MINIMUM_LSO_SEGMENT_COUNT;
|
|
LargeSendTask->MaxOffLoadSize = NVNET_MAXIMUM_LSO_FRAME_SIZE;
|
|
LargeSendTask->IpOptions = TRUE;
|
|
LargeSendTask->TcpOptions = TRUE;
|
|
}
|
|
TaskOffload->OffsetNextTask = 0;
|
|
|
|
*BytesWritten = InfoLength;
|
|
*BytesNeeded = 0;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
NDIS_STATUS
|
|
NvNetSetTcpTaskOffload(
|
|
_Inout_ PNVNET_ADAPTER Adapter,
|
|
_In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,
|
|
_In_ PULONG BytesRead)
|
|
{
|
|
ULONG Offset;
|
|
PNDIS_TASK_OFFLOAD TaskOffload;
|
|
|
|
if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION)
|
|
{
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
Adapter->IpHeaderOffset = TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize;
|
|
|
|
TaskOffload = (PNDIS_TASK_OFFLOAD)TaskOffloadHeader;
|
|
Offset = TaskOffloadHeader->OffsetFirstTask;
|
|
|
|
while (Offset)
|
|
{
|
|
*BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
|
|
|
|
TaskOffload = (PNDIS_TASK_OFFLOAD)((PUCHAR)TaskOffload + Offset);
|
|
switch (TaskOffload->Task)
|
|
{
|
|
case TcpIpChecksumNdisTask:
|
|
{
|
|
PNDIS_TASK_TCP_IP_CHECKSUM Task;
|
|
|
|
*BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
|
|
|
|
if (!(Adapter->Flags & NV_SEND_CHECKSUM))
|
|
{
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
Task = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer;
|
|
|
|
Adapter->Offload.SendTcpChecksum = Task->V4Transmit.TcpChecksum;
|
|
Adapter->Offload.SendUdpChecksum = Task->V4Transmit.UdpChecksum;
|
|
Adapter->Offload.SendIpChecksum = Task->V4Transmit.IpChecksum;
|
|
|
|
Adapter->Offload.ReceiveTcpChecksum = Task->V4Receive.TcpChecksum;
|
|
Adapter->Offload.ReceiveUdpChecksum = Task->V4Receive.UdpChecksum;
|
|
Adapter->Offload.ReceiveIpChecksum = Task->V4Receive.IpChecksum;
|
|
break;
|
|
}
|
|
|
|
case TcpLargeSendNdisTask:
|
|
{
|
|
PNDIS_TASK_TCP_LARGE_SEND Task;
|
|
|
|
if (!(Adapter->Flags & NV_SEND_LARGE_SEND))
|
|
{
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
if ((TaskOffloadHeader->
|
|
EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) &&
|
|
(TaskOffloadHeader->
|
|
EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation ||
|
|
TaskOffloadHeader->
|
|
EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER)))
|
|
{
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
*BytesRead += sizeof(NDIS_TASK_TCP_LARGE_SEND);
|
|
|
|
Task = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer;
|
|
|
|
if (Task->MinSegmentCount != NVNET_MINIMUM_LSO_SEGMENT_COUNT)
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
if (Task->MaxOffLoadSize > NVNET_MAXIMUM_LSO_FRAME_SIZE)
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
/* Nothing to do */
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Offset = TaskOffload->OffsetNextTask;
|
|
}
|
|
|
|
NdisAcquireSpinLock(&Adapter->Send.Lock);
|
|
|
|
if (Adapter->Offload.ReceiveTcpChecksum ||
|
|
Adapter->Offload.ReceiveUdpChecksum ||
|
|
Adapter->Offload.ReceiveIpChecksum)
|
|
{
|
|
Adapter->TxRxControl |= NVREG_TXRXCTL_RXCHECK;
|
|
}
|
|
else
|
|
{
|
|
Adapter->TxRxControl &= ~NVREG_TXRXCTL_RXCHECK;
|
|
}
|
|
NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl);
|
|
|
|
NdisReleaseSpinLock(&Adapter->Send.Lock);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
MiniportQueryInformation(
|
|
_In_ NDIS_HANDLE MiniportAdapterContext,
|
|
_In_ NDIS_OID Oid,
|
|
_In_ PVOID InformationBuffer,
|
|
_In_ ULONG InformationBufferLength,
|
|
_Out_ PULONG BytesWritten,
|
|
_Out_ PULONG BytesNeeded)
|
|
{
|
|
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
ULONG InfoLength;
|
|
PVOID InfoPtr;
|
|
union _GENERIC_INFORMATION
|
|
{
|
|
USHORT Ushort;
|
|
ULONG Ulong;
|
|
ULONG64 Ulong64;
|
|
NDIS_MEDIUM Medium;
|
|
NDIS_HARDWARE_STATUS Status;
|
|
NDIS_DEVICE_POWER_STATE PowerState;
|
|
} GenericInfo;
|
|
|
|
InfoLength = sizeof(ULONG);
|
|
InfoPtr = &GenericInfo;
|
|
|
|
switch (Oid)
|
|
{
|
|
case OID_GEN_SUPPORTED_LIST:
|
|
InfoPtr = (PVOID)&NvpSupportedOidList;
|
|
InfoLength = sizeof(NvpSupportedOidList);
|
|
break;
|
|
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
InfoLength = sizeof(NDIS_HARDWARE_STATUS);
|
|
GenericInfo.Status = NdisHardwareStatusReady;
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
{
|
|
InfoLength = sizeof(NDIS_MEDIUM);
|
|
GenericInfo.Medium = NdisMedium802_3;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
case OID_GEN_MAXIMUM_LOOKAHEAD:
|
|
{
|
|
GenericInfo.Ulong = Adapter->MaximumFrameSize - sizeof(ETH_HEADER);
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
{
|
|
GenericInfo.Ulong = Adapter->MaximumFrameSize;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_LINK_SPEED:
|
|
{
|
|
GenericInfo.Ulong = NvNetGetLinkSpeed(Adapter) * 10000;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
|
{
|
|
/* TODO: Change this later, once the driver can handle multipacket sends */
|
|
GenericInfo.Ulong = Adapter->MaximumFrameSize;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
{
|
|
GenericInfo.Ulong = Adapter->MaximumFrameSize * NVNET_RECEIVE_DESCRIPTORS;
|
|
}
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
{
|
|
GenericInfo.Ulong = Adapter->MaximumFrameSize;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
{
|
|
GenericInfo.Ulong = 0;
|
|
GenericInfo.Ulong |= (Adapter->PermanentMacAddress[0] << 16);
|
|
GenericInfo.Ulong |= (Adapter->PermanentMacAddress[1] << 8);
|
|
GenericInfo.Ulong |= (Adapter->PermanentMacAddress[2] & 0xFF);
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_DRIVER_VERSION:
|
|
{
|
|
InfoLength = sizeof(USHORT);
|
|
GenericInfo.Ushort = (NDIS_MINIPORT_MAJOR_VERSION << 8) | NDIS_MINIPORT_MINOR_VERSION;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
{
|
|
static const CHAR VendorDesc[] = "nVidia nForce Ethernet Controller";
|
|
InfoPtr = (PVOID)&VendorDesc;
|
|
InfoLength = sizeof(VendorDesc);
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
{
|
|
GenericInfo.Ulong = Adapter->PacketFilter;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_MAC_OPTIONS:
|
|
{
|
|
GenericInfo.Ulong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
|
|
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
|
|
NDIS_MAC_OPTION_NO_LOOPBACK;
|
|
|
|
if (Adapter->Flags & NV_PACKET_PRIORITY)
|
|
GenericInfo.Ulong |= NDIS_MAC_OPTION_8021P_PRIORITY;
|
|
if (Adapter->Flags & NV_VLAN_TAGGING)
|
|
GenericInfo.Ulong |= NDIS_MAC_OPTION_8021Q_VLAN;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
|
{
|
|
GenericInfo.Ulong = Adapter->Connected ? NdisMediaStateConnected
|
|
: NdisMediaStateDisconnected;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_MAXIMUM_SEND_PACKETS:
|
|
{
|
|
/* TODO: Multipacket sends */
|
|
GenericInfo.Ulong = 1;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_VENDOR_DRIVER_VERSION:
|
|
{
|
|
/* 1.0.0 */
|
|
GenericInfo.Ulong = 0x100;
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_XMIT_OK:
|
|
case OID_GEN_RCV_OK:
|
|
case OID_GEN_XMIT_ERROR:
|
|
case OID_GEN_RCV_ERROR:
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
case OID_GEN_DIRECTED_FRAMES_RCV:
|
|
case OID_GEN_RCV_CRC_ERROR:
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
case OID_802_3_XMIT_DEFERRED:
|
|
case OID_802_3_XMIT_MAX_COLLISIONS:
|
|
case OID_802_3_RCV_OVERRUN:
|
|
case OID_802_3_XMIT_UNDERRUN:
|
|
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
|
|
case OID_802_3_XMIT_TIMES_CRS_LOST:
|
|
case OID_802_3_XMIT_LATE_COLLISIONS:
|
|
{
|
|
if (Adapter->Features & DEV_HAS_STATISTICS_COUNTERS)
|
|
{
|
|
NvNetReadStatistics(Adapter);
|
|
NvNetQueryHwCounter(Adapter, Oid, &GenericInfo.Ulong64);
|
|
}
|
|
else
|
|
{
|
|
NvNetQuerySoftwareCounter(Adapter, Oid, &GenericInfo.Ulong64);
|
|
}
|
|
|
|
*BytesNeeded = sizeof(ULONG64);
|
|
if (InformationBufferLength < sizeof(ULONG))
|
|
{
|
|
*BytesWritten = 0;
|
|
return NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
}
|
|
if (InformationBufferLength >= sizeof(ULONG64))
|
|
{
|
|
*BytesWritten = sizeof(ULONG64);
|
|
NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG64));
|
|
}
|
|
else
|
|
{
|
|
*BytesWritten = sizeof(ULONG);
|
|
NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG));
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
|
|
{
|
|
GenericInfo.Ulong = NVNET_TRANSMIT_BLOCKS - Adapter->Send.TcbSlots;
|
|
break;
|
|
}
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
{
|
|
InfoPtr = Adapter->PermanentMacAddress;
|
|
InfoLength = ETH_LENGTH_OF_ADDRESS;
|
|
break;
|
|
}
|
|
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
{
|
|
InfoPtr = Adapter->CurrentMacAddress;
|
|
InfoLength = ETH_LENGTH_OF_ADDRESS;
|
|
break;
|
|
}
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
{
|
|
InfoPtr = Adapter->MulticastList;
|
|
InfoLength = Adapter->MulticastListSize * ETH_LENGTH_OF_ADDRESS;
|
|
break;
|
|
}
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
{
|
|
GenericInfo.Ulong = NVNET_MULTICAST_LIST_SIZE;
|
|
break;
|
|
}
|
|
|
|
case OID_TCP_TASK_OFFLOAD:
|
|
{
|
|
return NvNetGetTcpTaskOffload(Adapter,
|
|
InformationBuffer,
|
|
InformationBufferLength,
|
|
BytesWritten,
|
|
BytesWritten);
|
|
}
|
|
|
|
case OID_PNP_ENABLE_WAKE_UP:
|
|
{
|
|
GenericInfo.Ulong = NvNetGetWakeUp(Adapter);
|
|
break;
|
|
}
|
|
|
|
case OID_PNP_CAPABILITIES:
|
|
{
|
|
InfoLength = sizeof(NDIS_PNP_CAPABILITIES);
|
|
|
|
if (InformationBufferLength < InfoLength)
|
|
{
|
|
*BytesWritten = 0;
|
|
*BytesNeeded = InfoLength;
|
|
return NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
}
|
|
|
|
*BytesWritten = InfoLength;
|
|
*BytesNeeded = 0;
|
|
return NvNetFillPowerManagementCapabilities(Adapter, InformationBuffer);
|
|
}
|
|
|
|
case OID_PNP_QUERY_POWER:
|
|
{
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
case OID_GEN_VLAN_ID:
|
|
{
|
|
/* TODO: Implement software VLAN support */
|
|
if (!(Adapter->Flags & NV_VLAN_TAGGING))
|
|
{
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
GenericInfo.Ulong = Adapter->VlanId;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (InfoLength > InformationBufferLength)
|
|
{
|
|
*BytesWritten = 0;
|
|
*BytesNeeded = InfoLength;
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
}
|
|
else
|
|
{
|
|
NdisMoveMemory(InformationBuffer, InfoPtr, InfoLength);
|
|
*BytesWritten = InfoLength;
|
|
*BytesNeeded = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*BytesWritten = 0;
|
|
*BytesNeeded = 0;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
MiniportSetInformation(
|
|
_In_ NDIS_HANDLE MiniportAdapterContext,
|
|
_In_ NDIS_OID Oid,
|
|
_In_ PVOID InformationBuffer,
|
|
_In_ ULONG InformationBufferLength,
|
|
_Out_ PULONG BytesRead,
|
|
_Out_ PULONG BytesNeeded)
|
|
{
|
|
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
ULONG GenericUlong;
|
|
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
switch (Oid)
|
|
{
|
|
case OID_802_3_MULTICAST_LIST:
|
|
{
|
|
if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS)
|
|
{
|
|
*BytesNeeded = (InformationBufferLength / ETH_LENGTH_OF_ADDRESS) *
|
|
ETH_LENGTH_OF_ADDRESS;
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
if (InformationBufferLength > sizeof(Adapter->MulticastList))
|
|
{
|
|
*BytesNeeded = sizeof(Adapter->MulticastList);
|
|
Status = NDIS_STATUS_MULTICAST_FULL;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = InformationBufferLength;
|
|
NdisMoveMemory(Adapter->MulticastList, InformationBuffer, InformationBufferLength);
|
|
|
|
Adapter->MulticastListSize = InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
|
|
|
|
NvNetApplyPacketFilter(Adapter);
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
{
|
|
if (InformationBufferLength < sizeof(ULONG))
|
|
{
|
|
*BytesNeeded = sizeof(ULONG);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = sizeof(ULONG);
|
|
NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
|
|
|
|
if (GenericUlong & ~NVNET_PACKET_FILTERS)
|
|
{
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
/* Do not check to see if the filter is the same filter */
|
|
Adapter->PacketFilter = GenericUlong;
|
|
|
|
NvNetApplyPacketFilter(Adapter);
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
{
|
|
if (InformationBufferLength < sizeof(ULONG))
|
|
{
|
|
*BytesNeeded = sizeof(ULONG);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
/* Nothing to do */
|
|
*BytesRead = sizeof(ULONG);
|
|
break;
|
|
}
|
|
|
|
case OID_GEN_VLAN_ID:
|
|
{
|
|
if (InformationBufferLength < sizeof(ULONG))
|
|
{
|
|
*BytesNeeded = sizeof(ULONG);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
if (!(Adapter->Flags & NV_VLAN_TAGGING))
|
|
{
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = sizeof(ULONG);
|
|
NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
|
|
|
|
if (GenericUlong > NVNET_MAXIMUM_VLAN_ID)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
Adapter->VlanId = GenericUlong;
|
|
break;
|
|
}
|
|
|
|
case OID_TCP_TASK_OFFLOAD:
|
|
{
|
|
if (InformationBufferLength < sizeof(NDIS_TASK_OFFLOAD_HEADER))
|
|
{
|
|
*BytesNeeded = sizeof(NDIS_TASK_OFFLOAD_HEADER);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = InformationBufferLength;
|
|
|
|
Status = NvNetSetTcpTaskOffload(Adapter, InformationBuffer, BytesRead);
|
|
break;
|
|
}
|
|
|
|
case OID_PNP_ADD_WAKE_UP_PATTERN:
|
|
{
|
|
if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
|
|
{
|
|
*BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
|
|
|
|
Status = NvNetAddWakeUpPattern(Adapter, InformationBuffer);
|
|
break;
|
|
}
|
|
|
|
case OID_PNP_REMOVE_WAKE_UP_PATTERN:
|
|
{
|
|
if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
|
|
{
|
|
*BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
|
|
|
|
Status = NvNetRemoveWakeUpPattern(Adapter, InformationBuffer);
|
|
break;
|
|
}
|
|
|
|
case OID_PNP_ENABLE_WAKE_UP:
|
|
{
|
|
if (InformationBufferLength < sizeof(ULONG))
|
|
{
|
|
*BytesNeeded = sizeof(ULONG);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = sizeof(ULONG);
|
|
NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
|
|
|
|
NvNetEnableWakeUp(Adapter, GenericUlong);
|
|
break;
|
|
}
|
|
|
|
case OID_PNP_SET_POWER:
|
|
{
|
|
if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
|
|
{
|
|
*BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
*BytesRead = sizeof(ULONG);
|
|
NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
|
|
|
|
if (GenericUlong < NdisDeviceStateD0 || GenericUlong > NdisDeviceStateD3)
|
|
{
|
|
Status = NDIS_STATUS_INVALID_DATA;
|
|
break;
|
|
}
|
|
|
|
Status = NvNetSetPower(Adapter, GenericUlong);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|