diff options
Diffstat (limited to 'network/ndis/netvmini/6x/rssv2lib.c')
| -rw-r--r-- | network/ndis/netvmini/6x/rssv2lib.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/network/ndis/netvmini/6x/rssv2lib.c b/network/ndis/netvmini/6x/rssv2lib.c new file mode 100644 index 00000000..a2bc5550 --- /dev/null +++ b/network/ndis/netvmini/6x/rssv2lib.c @@ -0,0 +1,657 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + RSSv2Lib.c + +Abstract: + + This module implements RSSv2 helper library. + +--*/ +#pragma warning(push) +#define PRAGMA_ZERO_SIZED_ARRAY 4200 +#define PRAGMA_NAMELESS_STRUCT_UNION 4201 +#define PRAGMA_BIT_FIELD_NOT_INT 4214 +#define PRAGMA_STRUCTURE_PADDED 4324 +#define PRAGMA_NO_RETTYPE_FOR_FUNC 4508 +#pragma warning(disable: PRAGMA_NO_RETTYPE_FOR_FUNC) +#pragma warning(disable: PRAGMA_ZERO_SIZED_ARRAY) +#pragma warning(disable: PRAGMA_NAMELESS_STRUCT_UNION) +#pragma warning(disable: PRAGMA_STRUCTURE_PADDED) +#include <ndis.h> +#pragma warning(pop) + +#define RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE 64 +#include "rssv2lib.h" + +extern +FORCEINLINE +VOID +RssV2InitializeParsingContext ( + _Out_ PRSSV2_PARSING_CONTEXT Context, + _In_ PNDIS_RSS_SET_INDIRECTION_ENTRIES RssV2Oid, + _In_ BOOLEAN IsNativeRss + ) +/*++ +Routine Description: + + This routine initializes RSSv2 command parsing context from the OID. + +Arguments: + + Context - parsing context + + RssV2Oid - OID that needs parsing + + IsNativeRSS - Boolean which tells if the miniport is in NativeRSS mode + +Return Value: + + None. + +--*/ +{ + RtlZeroMemory(Context, sizeof(*Context)); + Context->IsNativeRss = IsNativeRss; + Context->RssV2Oid = RssV2Oid; + Context->MaxIndex = RssV2Oid->NumberOfRssEntries; + Context->LimitIndex = 0; + Context->StartIndex = 0; + Context->LastStartIndex = 0; +} + + +_Success_(return != FALSE) +BOOLEAN +RssV2GetNextCommandRange ( + _Inout_ PRSSV2_PARSING_CONTEXT Context, + _Out_ ULONG* SwitchId, + _Out_ ULONG* VPortId + ) +/*++ +Routine Description: + + This routine finds a group of move commands in the OID, which target the + same SwitchID & VPortID. It updates the Context to facilitate iteration + over the group later. + +Arguments: + + Context - parsing context + + SwitchId - pointer to the variable which receives SwitchId + + VPortId - pointer to the variable which receives VPortId + +Return Value: + + TRUE if a new group of commands is found, FALSE otherwise. + +--*/ +{ + PNDIS_RSS_SET_INDIRECTION_ENTRY command; + ULONG currIndex; + BOOLEAN isRangePresent; + ULONG switchId; + ULONG vPortId; + + isRangePresent = (BOOLEAN)(Context->LimitIndex < Context->MaxIndex); + + if (isRangePresent) + { + Context->StartIndex = Context->LimitIndex; + Context->LastStartIndex = Context->StartIndex; + + if (Context->IsNativeRss) + { + switchId = NDIS_INVALID_SWITCH_ID; + vPortId = NDIS_INVALID_VPORT_ID; + currIndex = Context->MaxIndex; + } + else + { + currIndex = Context->LimitIndex; + command = RSSV2_GET_COMMAND(Context->RssV2Oid, currIndex); + switchId = command->SwitchId; + vPortId = command->VPortId; + + for (; currIndex < Context->MaxIndex; currIndex++) + { + command = RSSV2_GET_COMMAND(Context->RssV2Oid, currIndex); + + if ((command->SwitchId != switchId) || + (command->VPortId != vPortId)) + { + break; + } + } + } + + Context->LimitIndex = currIndex; + *SwitchId = switchId; + *VPortId = vPortId; + } + + return isRangePresent; +} + + +VOID +RssV2RestartRangeIterator ( + _Inout_ PRSSV2_PARSING_CONTEXT Context + ) +/*++ +Routine Description: + + This routine allows to reset the context with respect to iterations + over the command groups. + + This is used by multi-pass OID handlers. + +Arguments: + + Context - parsing context + +Return Value: + + None. + +--*/ +{ + Context->LimitIndex = 0; + Context->StartIndex = 0; + Context->LastStartIndex = 0; +} + + + + +PNDIS_RSS_SET_INDIRECTION_ENTRY +RssV2GetNextCommand ( + _Inout_ PRSSV2_PARSING_CONTEXT Context, + _In_ BOOLEAN SkipProcessedCommands + ) +/*++ +Routine Description: + + This routine returns next command from the current command group (which + target the same SwitchId & VPortId). + +Arguments: + + Context - parsing context + + SkipProcessedCommands - TRUE, if user wants to commands which already + have EntryStatus changed from NDIS_STATUS_PENDING. + FALSE, if user wants to iterate over all commands. + +Return Value: + + Pointer to the next command, NULL - if there are no more commands left. + +--*/ +{ + PNDIS_RSS_SET_INDIRECTION_ENTRY command; + + do + { + if (Context->StartIndex < Context->LimitIndex) + { + command = RSSV2_GET_COMMAND(Context->RssV2Oid, + Context->StartIndex++); + } + else + { + command = NULL; + } + } while (SkipProcessedCommands && + (command != NULL) && + (command->EntryStatus != NDIS_STATUS_PENDING)); + + return command; +} + + + +VOID +RssV2RestartCommandIterator ( + _Inout_ PRSSV2_PARSING_CONTEXT Context + ) +/*++ +Routine Description: + + This routine allows to reset the context with respect to iterations + over the commands inside the same command group. + + This is used by multi-pass OID handlers. + +Arguments: + + Context - parsing context + +Return Value: + + None. + +--*/ +{ + Context->StartIndex = Context->LastStartIndex; +} + + +VOID +RssV2SetCommandRangeStatus ( + _Inout_ PRSSV2_PARSING_CONTEXT Context, + _In_ NDIS_STATUS Status + ) +/*++ +Routine Description: + + This routine sets EntryStatus for all commands of the current command group + +Arguments: + + Context - parsing context + + Status - NDIS_STATUS to set + +Return Value: + + None. + +--*/ +{ + ULONG index; + PNDIS_RSS_SET_INDIRECTION_ENTRY command; + + for (index = Context->LastStartIndex; index < Context->LimitIndex; index++) + { + command = RSSV2_GET_COMMAND(Context->RssV2Oid, index); + command->EntryStatus = Status; + } +} + + +FORCEINLINE +PULONG_PTR +RssV2NQEnforcerGetBitfield ( + _In_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG LocalCpuIndex + ) +/*++ +Routine Description: + + Routine finds a pointer to the bitfield for specified + (RSS-)local processor index. + +Arguments: + + QueueMap - Pointer to the queue map + + LocalCpuIndex - Local index of the processor + +Return Value: + + Pointer to the bitfield. + +--*/ +{ + ASSERT(LocalCpuIndex < QueueMap->MaxProcessors); + + return (PULONG_PTR)((PUINT8)QueueMap + + sizeof(RSSV2_QUEUE_MAP) + + RSSV2_BITFIELD_OFFSET(LocalCpuIndex)); +} + +FORCEINLINE +PUINT8 +RssV2NQEnforceGetReference ( + _In_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG LocalCpuIndex + ) +/*++ +Routine Description: + + Routine finds a pointer to the reference counter for the specified + (RSS-)local processor index. + +Arguments: + + QueueMap - Pointer to the queue map + + LocalCpuIndex - Local index of the processor + +Return Value: + + Pointer to the reference coutner. + +--*/ +{ + ASSERT(LocalCpuIndex < QueueMap->MaxProcessors); + + return (PUINT8)((PUINT8)QueueMap + + sizeof(RSSV2_QUEUE_MAP) + + RSSV2_BITFIELD_SIZE(QueueMap->MaxProcessors) + + RSSV2_REFERENCE_OFFSET(LocalCpuIndex)); +} + + +VOID +RssV2NQEnforcerReset ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap + ) +/*++ +Routine Description: + + Routine resets the already initialized QueueMap. + + Queue Map has zero references by any processors. + +Arguments: + + QueueMap - Pointer to the queue map + +Return Value: + + None. + +--*/ +{ + RtlZeroMemory(RssV2NQEnforcerGetBitfield(QueueMap, 0), + RSSV2_BITFIELD_SIZE(QueueMap->MaxProcessors)); + + RtlZeroMemory(RssV2NQEnforceGetReference(QueueMap, 0), + RSSV2_REFERENCE_SIZE(QueueMap->MaxProcessors)); +} + + +VOID +RssV2NQEnforcerInitialize ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG MaxNumberOfProcessorsInRssTable + ) +/*++ +Routine Description: + + Routine initializes the QueueMap. + +Arguments: + + QueueMap - Pointer to the queue map + + MaxNumberOfProcessorsInRssTable - Maximum number of processors which + RSS table can ever contain. + +Return Value: + + None. + +--*/ +{ + QueueMap->MaxProcessors = MaxNumberOfProcessorsInRssTable; + KeInitializeSpinLock(&QueueMap->SpinLock); + RssV2NQEnforcerReset(QueueMap); +} + + +VOID +RssV2NQEnforcerReference ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG LocalCpuIndex + ) +/*++ +Routine Description: + + Routine marks processor as holding a reference. Corresponding bit in + the bitfiled is set to 1, and reference count is incremented. + +Arguments: + + QueueMap - Pointer to the queue map + + LocalCpuIndex - Local index of the processor + +Return Value: + + None. + +--*/ +{ + PUINT8 reference; + PULONG_PTR bitfield; + + if (LocalCpuIndex < QueueMap->MaxProcessors) + { + reference = RssV2NQEnforceGetReference(QueueMap, LocalCpuIndex); + *reference += 1; + + bitfield = RssV2NQEnforcerGetBitfield(QueueMap, LocalCpuIndex); + *bitfield |= 1UI64 << (LocalCpuIndex % BITS_PER_WORD); + } +} + + +VOID +RssV2NQEnforcerDereference ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG LocalCpuIndex + ) +/*++ +Routine Description: + + Routine removes one reference cause by the processor. Reference count + is decremented, and if it becomes zero, a corresponding bit in + the bitfiled is cleared to 0. + +Arguments: + + QueueMap - Pointer to the queue map + + LocalCpuIndex - Local index of the processor + +Return Value: + + None. + +--*/ +{ + PUINT8 reference; + PULONG_PTR bitfield; + + if (LocalCpuIndex < QueueMap->MaxProcessors) + { + reference = RssV2NQEnforceGetReference(QueueMap, LocalCpuIndex); + *reference -= 1; + if (*reference == 0) + { + bitfield = RssV2NQEnforcerGetBitfield(QueueMap, LocalCpuIndex); + *bitfield &= ~(1UI64 << (LocalCpuIndex % BITS_PER_WORD)); + } + } +} + + +VOID +RssV2NQEnforcerUpdate ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ UINT8 OldCpuIndex, + _In_ UINT8 NewCpuIndex + ) +/*++ +Routine Description: + + Routine updates references for steering parameter (when it is re-points + from one processor to another). + +Arguments: + + QueueMap - Pointer to the queue map + + OldCpuIndex - Old local index of the processor used by steering parameter + + NewCpuIndex - New Local index of the processor for the steering parameter + +Return Value: + + None. + +--*/ +{ + if (OldCpuIndex != NewCpuIndex) + { + RssV2NQEnforcerReference(QueueMap, NewCpuIndex); + RssV2NQEnforcerDereference(QueueMap, OldCpuIndex); + } +} + + +ULONG +RssV2NQEnforcerGetNumberOfProcs ( + _In_ PRSSV2_QUEUE_MAP QueueMap + ) +/*++ +Routine Description: + + Routine counts number of bits set to "1" in the bitfield, this telling + how many processors are used. + +Arguments: + + QueueMap - Pointer to the queue map + + +Return Value: + + Number of processors used. + +--*/ +{ + ULONG localCpuIndex; + ULONG numberOfProcessors; + PULONG_PTR bitfield; + + numberOfProcessors = 0; + + for (localCpuIndex = 0; + localCpuIndex < QueueMap->MaxProcessors; + localCpuIndex += BITS_PER_WORD) + { + bitfield = RssV2NQEnforcerGetBitfield(QueueMap, localCpuIndex); + numberOfProcessors += RtlNumberOfSetBitsUlongPtr(*bitfield); + } + + return numberOfProcessors; +} + + +VOID +RssV2NQEnforcerEnter( + _Inout_ PRSSV2_QUEUE_MAP GlobalQueueMap, + _Inout_ PRSSV2_QUEUE_MAP LocalQueueMap + ) +/*++ +Routine Description: + + Routine takes a spinlock and copies Queue Map locally. + +Arguments: + + GlobalQueueMap - Pointer to the global queue map (e.g. VPort's) visible by + many processors. + + LocalQueueMap - Pointer to the queue map on stack. + +Return Value: + + None. + +--*/ +{ + KeAcquireSpinLockAtDpcLevel(&GlobalQueueMap->SpinLock); + + RtlMoveMemory(LocalQueueMap, + GlobalQueueMap, + RssV2NQEnforcerGetQueueMapSize(GlobalQueueMap->MaxProcessors)); +} + + +NDIS_STATUS +RssV2NQEnforcerLeave ( + _Inout_ PRSSV2_QUEUE_MAP GlobalQueueMap, + _In_ PRSSV2_QUEUE_MAP LocalQueueMap, + _In_ ULONG QueueLimit + ) +/*++ +Routine Description: + + Routine performs "Number of Queues" (NQ-)violation check. + + Usage pattern: + + RssV2NQEnforcerEnter(qm); + + for_all_commands_in_the_current_group() + { + RssV2NQEnforcerUpdate(qm, oldCpuIndex, newCpuIndex); + } + + status = RssV2NQEnforcerLeave(qm); + if (FAILED(status) + { + RssV2SetCommandRangeStatus(&context, status); + } + + // + // Proceed to apply to HW. + // + +Arguments: + + GlobalQueueMap - Pointer to the global queue map (e.g. VPort's) visible by + many processors. + + LocalQueueMap - Pointer to the queue map on stack. If NQ-check succeeds, + the global queue map will be updated from the local copy. + If NQ-check fails, local copy will be discarded and global + copy is unchanged. + + QueueLimit - Configured maximum number of queues for scaling entity (VPort). + +Return Value: + + NDIS_STATUS_SUCCESS - if the accumulated local changes lead to valid + configuration. + + NDIS_STATUS_NO_QUEUES - if the accumulated local configuration exceeds + QueueLimit. + +--*/ +{ + NDIS_STATUS status; + + if (RssV2NQEnforcerGetNumberOfProcs(LocalQueueMap) <= QueueLimit) + { + RtlMoveMemory(GlobalQueueMap, + LocalQueueMap, + RssV2NQEnforcerGetQueueMapSize(GlobalQueueMap->MaxProcessors)); + + status = NDIS_STATUS_SUCCESS; + } + else + { + status = NDIS_STATUS_NO_QUEUES; + } + + KeReleaseSpinLockFromDpcLevel(&GlobalQueueMap->SpinLock); + + return status; +} + |
