summaryrefslogtreecommitdiff
path: root/network/ndis/netvmini/6x/rssv2lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'network/ndis/netvmini/6x/rssv2lib.c')
-rw-r--r--network/ndis/netvmini/6x/rssv2lib.c657
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;
+}
+