From 9764486ad7f64de72787230206b322828def030f Mon Sep 17 00:00:00 2001 From: "Dmitry Malloy (MESHCHANINOV)" Date: Mon, 23 Apr 2018 11:38:13 -0700 Subject: [PATCH] RSSv2 library and sample OID handlers --- network/ndis/netvmini/6x/680/netvmini680.inf | Bin 0 -> 15762 bytes network/ndis/netvmini/6x/680/netvmini680.rc | 50 + .../ndis/netvmini/6x/680/netvmini680.vcxproj | 217 +++ .../6x/680/netvmini680.vcxproj.Filters | 58 + network/ndis/netvmini/6x/adapter.c | 11 + network/ndis/netvmini/6x/adapter.h | 9 + network/ndis/netvmini/6x/ctrlpath.c | 208 +++ network/ndis/netvmini/6x/ctrlpath.h | 4 +- network/ndis/netvmini/6x/miniport.c | 9 + network/ndis/netvmini/6x/miniport.h | 3 + network/ndis/netvmini/6x/netvmin6.h | 1 + network/ndis/netvmini/6x/netvmini.sln | 13 + network/ndis/netvmini/6x/rssv2.c | 1283 +++++++++++++++++ network/ndis/netvmini/6x/rssv2.h | 136 ++ network/ndis/netvmini/6x/rssv2lib.c | 657 +++++++++ network/ndis/netvmini/6x/rssv2lib.h | 205 +++ 16 files changed, 2863 insertions(+), 1 deletion(-) create mode 100644 network/ndis/netvmini/6x/680/netvmini680.inf create mode 100644 network/ndis/netvmini/6x/680/netvmini680.rc create mode 100644 network/ndis/netvmini/6x/680/netvmini680.vcxproj create mode 100644 network/ndis/netvmini/6x/680/netvmini680.vcxproj.Filters create mode 100644 network/ndis/netvmini/6x/rssv2.c create mode 100644 network/ndis/netvmini/6x/rssv2.h create mode 100644 network/ndis/netvmini/6x/rssv2lib.c create mode 100644 network/ndis/netvmini/6x/rssv2lib.h diff --git a/network/ndis/netvmini/6x/680/netvmini680.inf b/network/ndis/netvmini/6x/680/netvmini680.inf new file mode 100644 index 0000000000000000000000000000000000000000..876441f214180b1daf9a0c26f6d07fa51da409f7 GIT binary patch literal 15762 zcmeHOZBH9V5Z=4YRyP3t-EPD=E(HSsp;eQ-VD%w7x#K7otvgP#`P-7A59zgy7*^}7p8@0XDIV- zmf{NNoSCn<-!UK1j`e>AkNY@>xUqf@E%@I=?G8#^peppYh*9 zT_Vump5fgdY6zu2?UNmgrfWHzTMDFKGSBfVn;*^Zc-{rAQ}YEaDZ>WtmTlV=U})kl z@4E-vZh_aptM#jS2U*vXx~%oLc?{Z%&_vt(VxE`<*ijqT3uXzWc^pT$o->Egz!9$I zpfBpIh8l->GLOxAlPC;qS>gEG~?{V7_Uk>|-`rXV+d|#K5`~YJu<#!YQIrEZ9=CAAUl5{?r`N_;r zbft8F+539NhPyhOaCLVwTpjwBGFx%Y<`Q=;{cY>-yX_-B!1=3vs43bAVXr zy4gl7@Eu~F8+M)Y0C(Qw&R4{}+&Gp-Jkq#F4Y8=@gxbUSlR+OEGBf{Kq6mJhZ101PV2gS zB!2f8R8<~AH`aEP4`akF^skMmUsg8mRX9E*t!UFOm3!u%M=8{rZ5fN|*f_An8|5uu zBB0d-lTY16l`V(3yfv?(FPE0ay*0v_+LlW#M5}6Jnv9vJZHbP*xOG=;RI@jXy=eqg zB*utm`piWjP?XM(5(*6YsUJ=|&7 zG;eWcM4vHs>WQ(uGnDDEjPZ%?`Vnaq)wYZUugq`IzTl=k@539FQy*6k5=5*q&XH2l z2xvZqn#E8V@{_3ib)joPii|y4b4l%WvYiLSDn2{+pO_#z#4QzlmcEYxrvXCblk= z)%CZm3$yFMzqkvN)D(@{rN1WdyjrIj({)oJH!#k2M=l@=BS5%J|#~ z4rUJuCH{xvYZ86**9@X((X#5i*jaLmwrtKCvpIV~t&x_#mvfaG9%(1xpN$3PQBeMV zR8Jy=teqUmQiD2Z*%D$Gl5M_MQ%W<4^ly%ZgL$49|;#V=!_ zU^LRrgcgb16~A$_eoI#FjJ0O1L#~;nD%sQdo-!Kq7Ox50PZj#(zQaR%ELbm$`Ct~6 zP?h4l@^>f1vWj!}ExVc^_vseFB3xrF z{rQI@YFd|jcKjlNYjVm!vg%ofyN=9P=boRObquXoTcQVYv_64;CHI>5_hCor6MmVX zT5AvYbE=RxzsK2Zc68old|u~*6dAu~;2~?fC(cN4xpqTxiMLYTu3WO* zT~xFhv78;qhI#su)y|RP6Mj18=w2H=NGx4OlTYyV7J5}l#<+4Kt2~;jJEfWLEA$8P zU5=uP_crhR6C?Nj>ega8uW-E3`Gs=hw>nZwySeU*&J1yO>sZ* z>rph>^~2~YL-B;sjJ~zxanFu9O1a3nD0f%3CCH#_=MLtK$Zox?5$W49LYB-A!(C(g zvhJrB!IZ5NL&z+ik9G`U?#)|_(QW(dCmKvH7$v#VI#Y@6P+jAAl8C +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Miniport Driver" +#define VER_INTERNALNAME_STR "netvmini680.sys" +#define VER_ORIGINALFILENAME_STR "netvmini680.sys" + + +#define VER_FILEVERSION 4,30,00,0000 +#define VER_FILEVERSION_STR "4.30.00.0000" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION VER_FILEVERSION + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR + +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2009 Microsoft Corporation" +#ifdef VER_COMPANYNAME_STR +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR "Microsoft Corporation" +#endif + +#undef VER_PRODUCTNAME_STR +#define VER_PRODUCTNAME_STR "Microsoft Virtual Network Adapter (NDIS 6.80 Miniport)" +#define VER_LANGNEUTRAL + +#include "common.ver" + diff --git a/network/ndis/netvmini/6x/680/netvmini680.vcxproj b/network/ndis/netvmini/6x/680/netvmini680.vcxproj new file mode 100644 index 000000000..503b040b2 --- /dev/null +++ b/network/ndis/netvmini/6x/680/netvmini680.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {7B9C33BA-F817-42B9-A355-9E54854CE9D6} + $(MSBuildProjectName) + Debug + Win32 + {173BE266-31F2-4D74-A9C1-35B20D4DD5EA} + + + + Windows10 + False + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + WDM + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + DEBUGP(LEVEL,MSG,...) + + + true + true + DEBUGP(LEVEL,MSG,...) + + + + netvmini680 + + + netvmini680 + + + netvmini680 + + + netvmini680 + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + true + Level4 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + %(DisableSpecificWarnings);4201;4214;4127 + + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib + + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + true + Level4 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + %(DisableSpecificWarnings);4201;4214;4127 + + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib + + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + true + Level4 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + %(DisableSpecificWarnings);4201;4214;4127 + + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib + + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + true + Level4 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + %(DisableSpecificWarnings);4201;4214;4127 + + + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(PreprocessorDefinitions);NDIS680_MINIPORT=1 + %(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1 + %(PreprocessorDefinitions);NDIS_WDM=1 + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/network/ndis/netvmini/6x/680/netvmini680.vcxproj.Filters b/network/ndis/netvmini/6x/680/netvmini680.vcxproj.Filters new file mode 100644 index 000000000..f7c437373 --- /dev/null +++ b/network/ndis/netvmini/6x/680/netvmini680.vcxproj.Filters @@ -0,0 +1,58 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {1FEAFB34-8DD3-4B56-A9A1-F6572B7E94F0} + + + h;hpp;hxx;hm;inl;inc;xsd + {4E98F484-F310-4E1A-A097-D7ADBAE1351F} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {D8093E47-6AB1-4358-AC7C-7ACE55606993} + + + inf;inv;inx;mof;mc; + {7E4706EB-3B87-4AB9-BA5C-93CC3E3B78CA} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/network/ndis/netvmini/6x/adapter.c b/network/ndis/netvmini/6x/adapter.c index 0cea21d49..f1beefc8d 100644 --- a/network/ndis/netvmini/6x/adapter.c +++ b/network/ndis/netvmini/6x/adapter.c @@ -480,6 +480,17 @@ Routine Description: break; } +#if (NDIS_SUPPORT_NDIS680) + // + // Set miniport attributes for supported and enabled NDIS RSS features. + // + Status = InitializeRSSConfig(Adapter); + if (NDIS_STATUS_SUCCESS != Status) + { + DEBUGP(MP_ERROR, "[%p] InitializeRSSConfig Status 0x%08x\n", Adapter, Status); + break; + } +#endif // // For hardware devices, you should register your interrupt handlers // here, using NdisMRegisterInterruptEx. diff --git a/network/ndis/netvmini/6x/adapter.h b/network/ndis/netvmini/6x/adapter.h index 7162fc020..cfc540d3c 100644 --- a/network/ndis/netvmini/6x/adapter.h +++ b/network/ndis/netvmini/6x/adapter.h @@ -299,6 +299,15 @@ typedef struct _MP_ADAPTER #endif +#if (NDIS_SUPPORT_NDIS680) + + // + // NDIS RSSv2-related data + // + MP_ADAPTER_RSS_DATA RSSData; + +#endif + } MP_ADAPTER, *PMP_ADAPTER; #define MP_ADAPTER_FROM_CONTEXT(_ctx_) ((PMP_ADAPTER)(_ctx_)) diff --git a/network/ndis/netvmini/6x/ctrlpath.c b/network/ndis/netvmini/6x/ctrlpath.c index 019697057..6a745a360 100644 --- a/network/ndis/netvmini/6x/ctrlpath.c +++ b/network/ndis/netvmini/6x/ctrlpath.c @@ -29,6 +29,12 @@ MPMethodRequest( _In_ PMP_ADAPTER Adapter, _In_ PNDIS_OID_REQUEST NdisRequest); +static +NDIS_STATUS +MPSynchronousMethodRequest( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisRequest); + static NDIS_STATUS MPSetInformation( @@ -108,6 +114,20 @@ NICSetQOSParameters( #endif +#if (NDIS_SUPPORT_NDIS680) +static +NDIS_STATUS +MPSetRSSv2Parameters( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisSetRequest); + +static +NDIS_STATUS +MPSetRSSv2IndirectionTableEntries( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisSetRequest); +#endif + static NDIS_STATUS MPSetPower( @@ -194,6 +214,52 @@ Return Value: return Status; } +#if (NDIS_SUPPORT_NDIS680) +NDIS_STATUS +MPSynchronousOidRequest( + _In_ NDIS_HANDLE MiniportAdapterContext, + _In_ PNDIS_OID_REQUEST NdisRequest) +/*++ + +Routine Description: + + Entry point called by NDIS to get or set the value of a specified + synchronous OID. + +Arguments: + + MiniportAdapterContext - Our adapter handle + NdisRequest - The OID request to handle + +Return Value: + + Return code from the NdisRequest below. + +--*/ +{ + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext); + + DEBUGP(MP_LOUD, "[%p] ---> MPSynchronousOidRequest\n", Adapter); + + switch (NdisRequest->RequestType) + { + case NdisRequestMethod: + Status = MPSynchronousMethodRequest(Adapter, NdisRequest); + break; + default: + // + // The entry point may by used by other requests + // + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + + DEBUGP(MP_LOUD, "[%p] <--- MPSynchronousOidRequest Status = 0x%08x\n", Adapter, Status); + return Status; +} +#endif VOID MPCancelOidRequest( @@ -875,6 +941,15 @@ Return Value: NdisSetRequest); break; +#if (NDIS_SUPPORT_NDIS680) + case OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: + // + // Update RSSv2 parameters + // + Status = MPSetRSSv2Parameters(Adapter, NdisSetRequest); + break; +#endif + #if (NDIS_SUPPORT_NDIS620) case OID_PM_ADD_WOL_PATTERN: case OID_PM_REMOVE_WOL_PATTERN: @@ -996,6 +1071,55 @@ Return Value: } +#if (NDIS_SUPPORT_NDIS680) +NDIS_STATUS +MPSynchronousMethodRequest( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisRequest) +/*++ +Routine Description: + + Helper function to perform a synchronous method OID request + +Arguments: + + Adapter - + NdisRequest - THe synchronous method OID request + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_NOT_SUPPORTED + +--*/ +{ + NDIS_STATUS Status; + NDIS_OID Oid; + + DEBUGP(MP_LOUD, "[%p] ---> MPSynchronousMethodRequest ", Adapter); + + Oid = NdisRequest->DATA.METHOD_INFORMATION.Oid; + DbgPrintOidName(Oid); + + switch (Oid) + { + case OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: + // + // Handle RSSv2 traffic steering OID. + // + Status = MPSetRSSv2IndirectionTableEntries(Adapter, NdisRequest); + break; + + default: + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + + DEBUGP(MP_LOUD, "[%p] <--- MPSynchronousMethodRequest Status = 0x%08x\n", Adapter, Status); + return Status; +} +#endif NDIS_STATUS @@ -1753,3 +1877,87 @@ Return Value: return Status; } + + +#if (NDIS_SUPPORT_NDIS680) +static +NDIS_STATUS +MPSetRSSv2Parameters( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisSetRequest) +/*++ +Routine Description: + + This routine handles OID_GEN_RECEIVE_SCALE_PARAMETERS_V2 set request. + +Arguments: + + Adapter - Pointer to adapter block + NdisSetRequest - The OID data for the request + +Return Value: + + NDIS_STATUS + +--*/ +{ + struct _SET *Set; + + Set = &NdisSetRequest->DATA.SET_INFORMATION; + + // + // Validate the request + // + if (Set->InformationBufferLength < + NDIS_SIZEOF_RECEIVE_SCALE_PARAMETERS_V2_REVISION_1) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Invalid InformationBufferLength\n"); + + return NDIS_STATUS_INVALID_LENGTH; + } + + return NICSetRSSv2Parameters(Adapter, NdisSetRequest); +} + + +static +NDIS_STATUS +MPSetRSSv2IndirectionTableEntries( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisMethodRequest) +/*++ +Routine Description: + + This routine handles OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES method request. + +Arguments: + + Adapter - Pointer to adapter block + NdisSetRequest - The OID data for the request + +Return Value: + + NDIS_STATUS + +--*/ +{ + struct _METHOD *Method; + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + Method = &NdisMethodRequest->DATA.METHOD_INFORMATION; + + // + // Validate the request + // + if (Method->InputBufferLength < + NDIS_SIZEOF_RSS_SET_INDIRECTION_ENTRIES_REVISION_1) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Invalid InformationBufferLength\n"); + + return NDIS_STATUS_INVALID_LENGTH; + } + + return NICSetRSSv2IndirectionTableEntries(Adapter, NdisMethodRequest); +} +#endif \ No newline at end of file diff --git a/network/ndis/netvmini/6x/ctrlpath.h b/network/ndis/netvmini/6x/ctrlpath.h index 99fd791e5..e37f4a953 100644 --- a/network/ndis/netvmini/6x/ctrlpath.h +++ b/network/ndis/netvmini/6x/ctrlpath.h @@ -22,7 +22,9 @@ Module Name: MINIPORT_OID_REQUEST MPOidRequest; - +#if (NDIS_SUPPORT_NDIS680) +MINIPORT_SYNCHRONOUS_OID_REQUEST MPSynchronousOidRequest; +#endif #endif // _CTRLPATH_H diff --git a/network/ndis/netvmini/6x/miniport.c b/network/ndis/netvmini/6x/miniport.c index 08d8cc3b0..317f8c54a 100644 --- a/network/ndis/netvmini/6x/miniport.c +++ b/network/ndis/netvmini/6x/miniport.c @@ -157,6 +157,9 @@ Routine Description: MPChar.DevicePnPEventNotifyHandler = MPDevicePnpEventNotify; MPChar.ShutdownHandlerEx = MPShutdownEx; MPChar.CancelOidRequestHandler = MPCancelOidRequest; +#if (NDIS_SUPPORT_NDIS680) + MPChar.SynchronousOidRequestHandler = MPSynchronousOidRequest; +#endif // // Associate the miniport driver with NDIS by calling the @@ -592,6 +595,12 @@ DbgPrintOidName( /* NDIS QoS OIDs for NDIS 6.30 */ MAKECASE(OID_QOS_PARAMETERS) #endif + +#if (NDIS_SUPPORT_NDIS680) + /* RSSv2 OIDS*/ + MAKECASE(OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES) + MAKECASE(OID_GEN_RECEIVE_SCALE_PARAMETERS_V2) +#endif } if (oidName) diff --git a/network/ndis/netvmini/6x/miniport.h b/network/ndis/netvmini/6x/miniport.h index 9b922b1aa..364ad7043 100644 --- a/network/ndis/netvmini/6x/miniport.h +++ b/network/ndis/netvmini/6x/miniport.h @@ -53,6 +53,9 @@ Module Name: #elif defined(NDIS630_MINIPORT) # define MP_NDIS_MAJOR_VERSION 6 # define MP_NDIS_MINOR_VERSION 30 +#elif defined(NDIS680_MINIPORT) +# define MP_NDIS_MAJOR_VERSION 6 +# define MP_NDIS_MINOR_VERSION 80 #else # error Unsupported NDIS version #endif diff --git a/network/ndis/netvmini/6x/netvmin6.h b/network/ndis/netvmini/6x/netvmin6.h index 334194870..b7331fc81 100644 --- a/network/ndis/netvmini/6x/netvmin6.h +++ b/network/ndis/netvmini/6x/netvmin6.h @@ -33,6 +33,7 @@ _Analysis_mode_(_Analysis_code_type_kernel_driver_); #include "miniport.h" #include "vmq.h" #include "qos.h" +#include "rssv2.h" #include "adapter.h" #include "mphal.h" #include "tcbrcb.h" diff --git a/network/ndis/netvmini/6x/netvmini.sln b/network/ndis/netvmini/6x/netvmini.sln index d42e00a08..e5eaca43b 100644 --- a/network/ndis/netvmini/6x/netvmini.sln +++ b/network/ndis/netvmini/6x/netvmini.sln @@ -9,12 +9,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "620", "620", "{60E2C616-EC5 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "630", "630", "{C6046890-63CF-4299-B25C-6C97B4ED890A}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "680", "680", "{BB8C555B-1DE0-4C5E-B2FD-12B2B0C7C8B4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini60", "60\netvmini60.vcxproj", "{50458BE9-A423-44C1-AF44-21D4B5233063}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini620", "620\netvmini620.vcxproj", "{062B87F8-6021-4BE2-B677-3AEF2456CBA0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini630", "630\netvmini630.vcxproj", "{7B9C33BA-F817-42B9-A355-9E54854CE9D6}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini680", "680\netvmini680.vcxproj", "{B08F62D4-7A4C-4789-A0F7-862E622839A7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -47,6 +51,14 @@ Global {7B9C33BA-F817-42B9-A355-9E54854CE9D6}.Debug|x64.Build.0 = Debug|x64 {7B9C33BA-F817-42B9-A355-9E54854CE9D6}.Release|x64.ActiveCfg = Release|x64 {7B9C33BA-F817-42B9-A355-9E54854CE9D6}.Release|x64.Build.0 = Release|x64 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Debug|Win32.ActiveCfg = Debug|Win32 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Debug|Win32.Build.0 = Debug|Win32 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Release|Win32.ActiveCfg = Release|Win32 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Release|Win32.Build.0 = Release|Win32 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Debug|x64.ActiveCfg = Debug|x64 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Debug|x64.Build.0 = Debug|x64 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Release|x64.ActiveCfg = Release|x64 + {B08F62D4-7A4C-4789-A0F7-862E622839A7}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -55,5 +67,6 @@ Global {50458BE9-A423-44C1-AF44-21D4B5233063} = {0D16B31B-2170-40BA-8850-F16E85EE02F0} {062B87F8-6021-4BE2-B677-3AEF2456CBA0} = {60E2C616-EC5B-4B24-ADDD-1BE70657EDEC} {7B9C33BA-F817-42B9-A355-9E54854CE9D6} = {C6046890-63CF-4299-B25C-6C97B4ED890A} + {B08F62D4-7A4C-4789-A0F7-862E622839A7} = {BB8C555B-1DE0-4C5E-B2FD-12B2B0C7C8B4} EndGlobalSection EndGlobal diff --git a/network/ndis/netvmini/6x/rssv2.c b/network/ndis/netvmini/6x/rssv2.c new file mode 100644 index 000000000..f1785ef4d --- /dev/null +++ b/network/ndis/netvmini/6x/rssv2.c @@ -0,0 +1,1283 @@ +/*++ + +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: + + RSSv2.c + +Abstract: + + This module implements the NDIS RSSv2-related functionality for the adapter. + +--*/ + +#include "netvmin6.h" +#include "rssv2.tmh" + +// +// Constant defines the maximum number of processors in the RSS processor set +// the hardware can support. +// +#define RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE 64 +#include "rssv2lib.h" + +VOID +MiniportApplyMoveITECommandToHW( + _Inout_ PMP_ADAPTER Adapter, + _Inout_ PMP_ADAPTER_VPORT VPort, + _In_ PNDIS_RSS_SET_INDIRECTION_ENTRY Command, + _In_ UINT8 NewLocalCpuIndex + ) +/*++ +Routine Description: + + This routine propagates changes as specified by the move command to the HW. + + NOTE: This routine cannot fail. All failures should have been handled and + reported before calling this function. + + If there is an underlying transient condition (for example in FIRWMARE), + it is miniport's responsibility to retry to clear transient error. + +Arguments: + + Adapter - Pointer to our adapter + + Vport - Pointer to the VPort + + Command - Move command which identifies the steering + parameter and the target processor. + + NewLocalCpuIndex - Local index of the target processor the steering + parameter is being pointed to. + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER(Adapter); + UNREFERENCED_PARAMETER(VPort); + UNREFERENCED_PARAMETER(Command); + UNREFERENCED_PARAMETER(NewLocalCpuIndex); +} + +VOID +MiniportApplyConfigurationToHW( + _Inout_ PMP_ADAPTER Adapter, + _Inout_ PMP_ADAPTER_VPORT VPort, + _In_ BOOLEAN IsRssEnabled, + _In_ USHORT NewITCount, + _In_ ULONG NewNumberOfQueues + ) +/*++ +Routine Description: + + This routine propagates changes as specified by the configuration OID to + the HW. + + All failures cases are already handled and before calling this function. + +Arguments: + + Adapter - Pointer to our adapter + + Vport - Pointer to the VPort + + IsRssEnabled - New RSS state + + NewITCount - New size of the indirection table + + NewNumberOfQueues - New number of HW queues allocated to the VPort + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER(Adapter); + UNREFERENCED_PARAMETER(VPort); + UNREFERENCED_PARAMETER(IsRssEnabled); + UNREFERENCED_PARAMETER(NewITCount); + UNREFERENCED_PARAMETER(NewNumberOfQueues); +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NDIS_STATUS +InitializeRSSConfig( + _Inout_ PMP_ADAPTER Adapter + ) +/*++ +Routine Description: + + This routine will initialize RSS for the miniport. + +Arguments: + + Adapter - Pointer to our adapter + +Return Value: + + NDIS_STATUS + +--*/ +{ + SIZE_T RssInfoSize; + NDIS_STATUS Status; + + DEBUGP(MP_TRACE, "[%p] ---> InitializeRSSConfig\n", Adapter); + + PAGED_CODE(); + + RssInfoSize = 0; + Status = NdisGetRssProcessorInformation(Adapter->AdapterHandle, + NULL, + &RssInfoSize); + + if (Status != NDIS_STATUS_BUFFER_TOO_SHORT) + { + DEBUGP(MP_ERROR, "%s: Unabled to get rss information size\n", __FUNCTION__); + goto Cleanup; + } + + // + // Allocate the neccessary memory for reading the available processors + // + Adapter->RSSData.RssProcessorInfo = + (PNDIS_RSS_PROCESSOR_INFO)ExAllocatePoolWithTag(NonPagedPoolNx, + RssInfoSize, + 'IRMT'); + if (Adapter->RSSData.RssProcessorInfo == NULL) + { + DEBUGP(MP_ERROR, "%s: Failed to allocate memory for rss information\n", __FUNCTION__); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + Status = NdisGetRssProcessorInformation(Adapter->AdapterHandle, + Adapter->RSSData.RssProcessorInfo, + &RssInfoSize); + + if (Status != NDIS_STATUS_SUCCESS) + { + DEBUGP(MP_ERROR, "%s: Unabled to get rss information\n", __FUNCTION__); + goto Cleanup; + } + + Adapter->RSSData.RssProcessorArray = (PNDIS_RSS_PROCESSOR) + ((PUCHAR)Adapter->RSSData.RssProcessorInfo + + Adapter->RSSData.RssProcessorInfo->RssProcessorArrayOffset); + + Status = NDIS_STATUS_SUCCESS; + +Cleanup: + + DEBUGP(MP_TRACE, "<--- [%p] InitializeRSSSConfig Status 0x%08x\n", Adapter, Status); + + return Status; +} + + +UINT8 +NICSetRSSv2FindProcessorInRssSet( + _In_ PMP_ADAPTER Adapter, + _In_ PROCESSOR_NUMBER ProcessorNumber + ) +/*++ +Routine Description: + + This routine finds processor in RSS table and returns its local index + (relative to RSS table). + +Arguments: + + Adapter - Pointer to our adapter + + ProcessorNumber - Processor number to lookup + +Return Value: + + Local index + +--*/ +{ + UINT8 index; + PNDIS_RSS_PROCESSOR processor; + + for (index = 0; + index < Adapter->RSSData.RssProcessorInfo->RssProcessorCount; + index++) + { + processor = &Adapter->RSSData.RssProcessorArray[index]; + + if ((processor->ProcNum.Group == ProcessorNumber.Group) && + (processor->ProcNum.Number == ProcessorNumber.Number)) + { + return index; + } + } + + return 0xFF; +} + + +PROCESSOR_NUMBER +NICSetRSSv2RssGetBaseProcessor( + _In_ PMP_ADAPTER Adapter + ) +/*++ +Routine Description: + + This routine returns base RSS processor for the miniport. + +Arguments: + + Adapter - Pointer to our adapter + +Return Value: + + Processor Number. + +--*/ +{ + PROCESSOR_NUMBER baseProcessor; + + // + // Mark processor as invalid. + // + baseProcessor.Reserved = 1; + + if (Adapter->RSSData.RssProcessorInfo != NULL) + { + baseProcessor = Adapter->RSSData.RssProcessorInfo->RssBaseProcessor; + } + + return baseProcessor; +} + + +BOOLEAN +NICSetRSSv2ValidateRssProcessor( + _In_ PMP_ADAPTER Adapter, + _In_ PROCESSOR_NUMBER ProcessorNumber, + _Out_ UINT8* LocalCpuIndex + ) +/*++ +Routine Description: + + This routine validates processor against minport's RSS settings, and if it + is valid, returns local index. + +Arguments: + + Adapter - Pointer to our adapter + + ProcessorNumber - Processor number to validate + + LocalCpuIndex - Poitner to local index if processor is valid + +Return Value: + + TRUE if processor is valid, FALSE otherwise. + +--*/ +{ + UINT8 CpuIndex; + PNDIS_RSS_PROCESSOR_INFO RssProcessorInfo; + + *LocalCpuIndex = (UINT8)(-1); + RssProcessorInfo = Adapter->RSSData.RssProcessorInfo; + + if (ProcessorNumber.Group < (USHORT)RssProcessorInfo->RssBaseProcessor.Group) + { + DEBUGP(MP_ERROR, "RssValidateProcessor: Invalid Proc Group %d:%d, below RssBaseProcGroup\n", + ProcessorNumber.Group, ProcessorNumber.Number); + return FALSE; + } + + if ((ProcessorNumber.Group == (USHORT)RssProcessorInfo->RssBaseProcessor.Group) && + (ProcessorNumber.Number < (UCHAR)RssProcessorInfo->RssBaseProcessor.Number)) + { + DEBUGP(MP_ERROR, "RssValidateProcessor: Invalid Proc Number %d:%d, below RssBaseProcNumber\n", + ProcessorNumber.Group, ProcessorNumber.Number); + return FALSE; + } + + if (ProcessorNumber.Group > (USHORT)RssProcessorInfo->RssMaxProcessor.Group) + { + DEBUGP(MP_ERROR, "RssValidateProcessor: Invalid Proc Group %d:%d, above RssMaxProcGroup\n", + ProcessorNumber.Group, ProcessorNumber.Number); + return FALSE; + } + + if ((ProcessorNumber.Group == (USHORT)RssProcessorInfo->RssMaxProcessor.Group) && + (ProcessorNumber.Number > (UCHAR)RssProcessorInfo->RssMaxProcessor.Number)) + { + DEBUGP(MP_ERROR, "RssValidateProcessor: Invalid Proc Number %d:%d, above RssMaxProcNumber\n", + ProcessorNumber.Group, ProcessorNumber.Number); + return FALSE; + } + + CpuIndex = NICSetRSSv2FindProcessorInRssSet(Adapter, ProcessorNumber); + if (CpuIndex == 0xFF) + { + DEBUGP(MP_ERROR, "RssValidateProcessor: Invalid Proc Number %d:%d, outside of RSS table\n", + ProcessorNumber.Group, ProcessorNumber.Number); + return FALSE; + } + + *LocalCpuIndex = CpuIndex; + + return TRUE; +} + + +NDIS_STATUS +NICSetRSSv2InitializeVPortRSS ( + _In_ PMP_ADAPTER Adapter, + _Inout_ PMP_ADAPTER_VPORT VPort, + _In_ PROCESSOR_NUMBER PrimaryProcessor + ) +/*++ +Routine Description: + + This routine initializes RSS state for a given VPort. + +Arguments: + + Adapter - Pointer to our adapter + + VPort - Pointer to the VPort which contains RSS state + + PrimaryProcessor - Primary processor to use + +Return Value: + + NDIS_STATUS + +--*/ +{ + SIZE_T Size; + NDIS_STATUS Status; + UINT8 PrimaryProcessorIndex; + + VPort->RssEnabled = FALSE; + + if (!NICSetRSSv2ValidateRssProcessor(Adapter, + PrimaryProcessor, + &PrimaryProcessorIndex)) + { + DEBUGP(MP_TRACE, "Primary is not a valid RSS processor.\n"); + Status = NDIS_STATUS_INVALID_DATA; + goto Cleanup; + } + + Size = RssV2NQEnforcerGetQueueMapSize(RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE); + + VPort->QueueMap = (PRSSV2_QUEUE_MAP)ExAllocatePoolWithTag(NonPagedPoolNx, + Size, + 'QNMT'); + if (VPort->QueueMap == NULL) + { + DEBUGP(MP_TRACE, "Inisufficient memory for QueueMap processor.\n"); + Status = NDIS_STATUS_RESOURCES; + goto Cleanup; + } + + RssV2NQEnforcerInitialize(VPort->QueueMap, + RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE); + + RtlFillMemory(&VPort->RssV2IndexTable, sizeof(VPort->RssV2IndexTable), 0xFF); + + VPort->DefaultProcessorNumber = PrimaryProcessor; + VPort->PrimaryProcessorNumber = PrimaryProcessor; + VPort->DefaultProcessorIndex = PrimaryProcessorIndex; + VPort->PrimaryProcessorIndex = PrimaryProcessorIndex; + + VPort->RssV2Params.NumberOfIndirectionTableEntries = 1; + VPort->RssV2Table[0] = PrimaryProcessor; + VPort->RssV2IndexTable[0] = PrimaryProcessorIndex; + + // + // When RSS is OFF, only the primary is active and holds a queue reference. + // + RssV2NQEnforcerReference(VPort->QueueMap, VPort->PrimaryProcessorIndex); + + Status = NDIS_STATUS_SUCCESS; + +Cleanup: + + return Status; +} + + +VOID +NICSetRSSv2SetCurrentProcessor( + _Inout_ PMP_ADAPTER_VPORT VPort, + _In_ PNDIS_RSS_SET_INDIRECTION_ENTRY Command, + _In_ PROCESSOR_NUMBER NewProcessor, + _In_ UINT8 NewCpuIndex + ) +/*++ +Routine Description: + + This routine updates tracking information for the steering parameter + (Primary, Default or ITE[n]), as selected by the Command. + + Routine is called after the "move command" has fully succeeded. + +Arguments: + + VPort - Pointer to the VPort + + Command - Move command used to update steering parameter + + NewProcessor - New processor number + + NewCpuIndex - Corresponding local index + +Return Value: + + None. + +--*/ +{ + if ((Command->Flags & NDIS_RSS_SET_INDIRECTION_ENTRY_FLAG_DEFAULT_PROCESSOR) != 0) + { + VPort->DefaultProcessorIndex = NewCpuIndex; + VPort->DefaultProcessorNumber = NewProcessor; + + DEBUGP(MP_TRACE, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: OK: DEFAULT_PROCESSOR: VPortId %d, RssEnabled %d, TargetProc %d:%d \n", + Command->VPortId, VPort->RssEnabled, NewProcessor.Group, NewProcessor.Number); + } + else if ((Command->Flags & NDIS_RSS_SET_INDIRECTION_ENTRY_FLAG_PRIMARY_PROCESSOR) != 0) + { + VPort->PrimaryProcessorIndex = NewCpuIndex; + VPort->PrimaryProcessorNumber = NewProcessor; + + DEBUGP(MP_TRACE, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: OK: PRIMARY_PROCESSOR: VPortId %d, RssEnabled %d, TargetProc %d:%d \n", + Command->VPortId, VPort->RssEnabled, NewProcessor.Group, NewProcessor.Number); + + } + else if (Command->Flags == 0) + { + VPort->RssV2IndexTable[Command->IndirectionTableIndex] = NewCpuIndex; + VPort->RssV2Table[Command->IndirectionTableIndex] = NewProcessor; + + DEBUGP(MP_TRACE, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: OK: ITE[%d] VPortId %d, RssEnabled %d, TargetProc %d:%d\n", + Command->IndirectionTableIndex, + Command->VPortId, + VPort->RssEnabled, + NewProcessor.Group, + NewProcessor.Number); + } +} + + +_Success_(return != FALSE) +BOOLEAN +NICSetRSSv2ValidateCommandAndGetProcessor ( + _In_ PMP_ADAPTER_VPORT VPort, + _In_ PNDIS_RSS_SET_INDIRECTION_ENTRY Command, + _Out_ PPROCESSOR_NUMBER CurrentProcessor, + _Out_ UINT8* CurrentCpuIndex, + _Out_ BOOLEAN* IsActiveSteeringParameter + ) +/*++ +Routine Description: + + This routine validates the move command, and returns information about + specified steering parameter (Primary, Default or ITE[n] if command is valid. + +Arguments: + + VPort - Pointer to the VPort + + Command - Move command used to update steering parameter + + CurrentProcessor - Pointer which receives processor where steering + parameter currenty points to. + + CurrentCpuIndex - Corresponding local index + + IsActiveSteeringParameter - Pointer to the boolean which say if steering + parameter is currently ACTIVE or not. + +Return Value: + + TRUE if move command is valid, FALSE - otherwise. + +--*/ +{ + BOOLEAN isSucceeded; + + isSucceeded = FALSE; + *CurrentCpuIndex = 0xFF; + *IsActiveSteeringParameter = FALSE; + + if ((Command->Flags & NDIS_RSS_SET_INDIRECTION_ENTRY_FLAG_DEFAULT_PROCESSOR) != 0) + { + *CurrentProcessor = VPort->DefaultProcessorNumber; + *CurrentCpuIndex = VPort->DefaultProcessorIndex; + *IsActiveSteeringParameter = VPort->RssEnabled; + isSucceeded = TRUE; + } + else if ((Command->Flags & NDIS_RSS_SET_INDIRECTION_ENTRY_FLAG_PRIMARY_PROCESSOR) != 0) + { + *CurrentProcessor = VPort->PrimaryProcessorNumber; + *CurrentCpuIndex = VPort->PrimaryProcessorIndex; + *IsActiveSteeringParameter = (BOOLEAN)(VPort->RssEnabled == FALSE); + isSucceeded = TRUE; + } + else if (Command->Flags == 0) + { + if (Command->IndirectionTableIndex < + VPort->RssV2Params.NumberOfIndirectionTableEntries) + { + *CurrentProcessor = VPort->RssV2Table[Command->IndirectionTableIndex]; + *CurrentCpuIndex = VPort->RssV2IndexTable[Command->IndirectionTableIndex]; + *IsActiveSteeringParameter = VPort->RssEnabled; + isSucceeded = TRUE; + } + else + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Invalid IndirectionTableIndex(%d) >= %d\n", + Command->IndirectionTableIndex, + VPort->RssV2Params.NumberOfIndirectionTableEntries); + } + } + else + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Invalid flags=0x%x\n", Command->Flags); + } + + return isSucceeded; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NDIS_STATUS +NICSetRSSv2Parameters( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisRequest) +/*++ +Routine Description: + + This routine handles OID_GEN_RECEIVE_SCALE_PARAMETERS_V2 set request. + +Arguments: + + Adapter - Pointer to adapter block + NdisRequest - The OID data for the request + +Return Value: + + NDIS_STATUS + +--*/ +{ + USHORT EntryIndex; + BOOLEAN IsHashInfoChanged; + BOOLEAN IsHashKeyChanged; + BOOLEAN IsNumITEsChanged; + BOOLEAN IsNumQueuesChanged; + BOOLEAN IsRssEnabled; + UINT8 LocalCpuIndex; + USHORT NewITCount; + ULONG NewNumberOfQueues; + ULONG NumProcs; + USHORT OldITCount; + PROCESSOR_NUMBER PrimaryProcessorNumber; + PROCESSOR_NUMBER ProcessorNumber; + PNDIS_RECEIVE_SCALE_PARAMETERS_V2 RssParams; + struct _SET *Set; + NDIS_STATUS Status; + ULONG VPortId; + PMP_ADAPTER_VPORT VPort; + + PAGED_CODE(); + + DEBUGP(MP_TRACE, "[%p] ---> NICSetRSSv2Parameters\n", Adapter); + + Set = &NdisRequest->DATA.SET_INFORMATION; + RssParams = (PNDIS_RECEIVE_SCALE_PARAMETERS_V2)Set->InformationBuffer; + + // + // Validate the request + // + if (RssParams->HashSecretKeySize != + NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Invalid HashSecretKeySize\n"); + return NDIS_STATUS_INVALID_LENGTH; + } + + if ((Set->InformationBufferLength < + (RssParams->HashSecretKeyOffset + RssParams->HashSecretKeySize)) + || + (RssParams->HashSecretKeyOffset < + NDIS_SIZEOF_RECEIVE_SCALE_PARAMETERS_V2_REVISION_1)) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Invalid HashSecretKeyOffset\n"); + return NDIS_STATUS_INVALID_LENGTH; + } + + if ((NdisRequest->Flags & NDIS_OID_REQUEST_FLAGS_VPORT_ID_VALID) != 0) + { + DEBUGP(MP_TRACE, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Issued for VPortId=%d, Flags=0x%x \n", + NdisRequest->VPortId, RssParams->Flags); + VPortId = NdisRequest->VPortId; + } + else + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Issued for miniport (NativeRSS), Flags=0x%x\n", RssParams->Flags); + VPortId = NDIS_INVALID_VPORT_ID; + } + + if ((VPortId != NDIS_INVALID_VPORT_ID) && + (VPortId >= MAX_NIC_SWITCH_VPORTS)) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Invalid VPortId\n"); + return NDIS_STATUS_INVALID_PORT; + } + + if (VPortId != NDIS_INVALID_VPORT_ID) + { + VPort = &Adapter->RSSData.VPort[VPortId]; + } + else + { + VPort = &Adapter->RSSData.NativeVPort; + } + + IsNumQueuesChanged = + ((RssParams->Flags & NDIS_RECEIVE_SCALE_PARAM_NUMBER_OF_QUEUES_CHANGED) != 0) && + (RssParams->NumberOfQueues != VPort->RssV2Params.NumberOfQueues); + + IsRssEnabled = + ((RssParams->Flags & NDIS_RECEIVE_SCALE_PARAM_ENABLE_RSS) != 0); + + IsNumITEsChanged = + ((RssParams->Flags & NDIS_RECEIVE_SCALE_PARAM_NUMBER_OF_ENTRIES_CHANGED) != 0) && + (RssParams->NumberOfIndirectionTableEntries != + VPort->RssV2Params.NumberOfIndirectionTableEntries); + + IsHashInfoChanged = + ((RssParams->Flags & NDIS_RECEIVE_SCALE_PARAM_HASH_INFO_CHANGED) != 0) && + (VPort->RssV2Params.HashInformation != RssParams->HashInformation); + + IsHashKeyChanged = + ((RssParams->Flags & NDIS_RECEIVE_SCALE_PARAM_HASH_KEY_CHANGED) != 0) && + !RtlEqualMemory(&VPort->RssV2Key, + (PUCHAR)RssParams + RssParams->HashSecretKeyOffset, + RssParams->HashSecretKeySize); + + NewNumberOfQueues = VPort->RssV2Params.NumberOfQueues; + if (IsNumQueuesChanged) + { + NewNumberOfQueues = RssParams->NumberOfQueues; + if (VPort->RssEnabled) + { + // + // Check for NQ-violation during queue change. + // + // Since RSS is enabled, the VPort->QueueMap reflects up-to-date + // queue-to-processor mapping. + // + // Get the number of current referenced processors. + // + NumProcs = RssV2NQEnforcerGetNumberOfProcs(VPort->QueueMap); + if (NumProcs > NewNumberOfQueues) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: VPortId=%d, NQ-Violation (queue change): NQueues=%d < NProcs=%d\n", + NdisRequest->VPortId, + NewNumberOfQueues, + NumProcs); + Status = NDIS_STATUS_NO_QUEUES; + goto Cleanup; + } + } + } + + OldITCount = (USHORT)VPort->RssV2Params.NumberOfIndirectionTableEntries; + NewITCount = OldITCount; + + // + // IT size change: check for non-repeat violation during shrinking. + // + if (IsNumITEsChanged) + { + NewITCount = (USHORT)RssParams->NumberOfIndirectionTableEntries; + if (OldITCount > NewITCount) + { + ASSERT((OldITCount % NewITCount) == 0); + + // + // IT shrinking should fail if pattern is non-repeat. + // + for (EntryIndex = NewITCount; EntryIndex < OldITCount; EntryIndex++) + { + ProcessorNumber = VPort->RssV2Table[EntryIndex % NewITCount]; + if ((ProcessorNumber.Group != VPort->RssV2Table[EntryIndex].Group) || + (ProcessorNumber.Number != VPort->RssV2Table[EntryIndex].Number)) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: VPortId %d, Cannot shrink IT size from %d to %d, mismatch at ITE[%d]\n", + NdisRequest->VPortId, + OldITCount, + NewITCount, + EntryIndex); + Status = NDIS_STATUS_INVALID_DATA; + goto Cleanup; + } + } + } + } + + if (VPort->RssEnabled == FALSE && IsRssEnabled) + { + RssV2NQEnforcerReset(VPort->QueueMap); + + // + // Check for processor numbers sanity in the default processor + // and the indirection table. + // + if (!NICSetRSSv2ValidateRssProcessor(Adapter, + VPort->DefaultProcessorNumber, + &LocalCpuIndex)) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Invalid DedfaultProcessorNumebr: %d:%d \n", + VPort->DefaultProcessorNumber.Group, + VPort->DefaultProcessorNumber.Number); + + Status = NDIS_STATUS_INVALID_DATA; + goto Cleanup; + } + + VPort->DefaultProcessorIndex = LocalCpuIndex; + RssV2NQEnforcerReference(VPort->QueueMap, LocalCpuIndex); + + OldITCount = (USHORT)VPort->RssV2Params.NumberOfIndirectionTableEntries; + + for (EntryIndex = 0; EntryIndex < OldITCount; EntryIndex++) + { + ProcessorNumber = VPort->RssV2Table[EntryIndex]; + + if (!NICSetRSSv2ValidateRssProcessor(Adapter, + ProcessorNumber, + &LocalCpuIndex)) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Invalid ITE[%d]: %d:%d \n", + EntryIndex, + ProcessorNumber.Group, + ProcessorNumber.Number); + + Status = NDIS_STATUS_INVALID_DATA; + goto Cleanup; + } + + VPort->RssV2IndexTable[EntryIndex] = LocalCpuIndex; + RssV2NQEnforcerReference(VPort->QueueMap, LocalCpuIndex); + } + + // + // After VPort->QueueMap is built, check for NQ-violation during + // RSS enablement. + // + // Get number of queues after RSS enablement. + // + NumProcs = RssV2NQEnforcerGetNumberOfProcs(VPort->QueueMap); + if (NumProcs > NewNumberOfQueues) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: NQ-Violation: NQueues=%d < NProcs=%d\n", + NewNumberOfQueues, + NumProcs); + Status = NDIS_STATUS_NO_QUEUES; + goto Cleanup; + } + } + + if (VPort->RssEnabled && (IsRssEnabled == FALSE)) + { + // + // Check for primary processor number sanity during RSS=OFF + // + PrimaryProcessorNumber = VPort->PrimaryProcessorNumber; + + if (!NICSetRSSv2ValidateRssProcessor(Adapter, + PrimaryProcessorNumber, + &LocalCpuIndex)) + { + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: Invalid PrimaryProcessorNumebr: %d:%d \n", + PrimaryProcessorNumber.Group, + PrimaryProcessorNumber.Number); + + Status = NDIS_STATUS_INVALID_DATA; + goto Cleanup; + } + + RssV2NQEnforcerReset(VPort->QueueMap); + VPort->PrimaryProcessorIndex = LocalCpuIndex; + RssV2NQEnforcerReference(VPort->QueueMap, LocalCpuIndex); + } + + // + // COMMIT PASS: NO FAILURES AFTER THIS POINT! + // + if (IsHashKeyChanged) + { + VPort->RssV2Params.HashSecretKeySize = + RssParams->HashSecretKeySize; + + NdisMoveMemory(&VPort->RssV2Key, + (PUCHAR)RssParams + RssParams->HashSecretKeyOffset, + RssParams->HashSecretKeySize); + } + + if (IsHashInfoChanged) + { + VPort->RssV2Params.HashInformation = RssParams->HashInformation; + } + + // + // IT size change: actual application (cannot fail) + // + if (IsNumITEsChanged) + { + if (OldITCount < NewITCount) + { + // + // IT expansion + // + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: VPortId %d, Expand IT size from %d to %d\n", + NdisRequest->VPortId, OldITCount, NewITCount); + + ASSERT((NewITCount % OldITCount) == 0); + for (EntryIndex = OldITCount; EntryIndex < NewITCount; EntryIndex++) + { + ProcessorNumber = VPort->RssV2Table[EntryIndex % OldITCount]; + VPort->RssV2Table[EntryIndex] = ProcessorNumber; + + LocalCpuIndex = VPort->RssV2IndexTable[EntryIndex % OldITCount]; + VPort->RssV2IndexTable[EntryIndex] = LocalCpuIndex; + RssV2NQEnforcerReference(VPort->QueueMap, LocalCpuIndex); + } + } + else if (OldITCount > NewITCount) + { + // + // IT contraction + // + DEBUGP(MP_ERROR, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: VPortId %d, Shrink IT size from %d to %d\n", + NdisRequest->VPortId, OldITCount, NewITCount); + ASSERT((OldITCount % NewITCount) == 0); + + for (EntryIndex = NewITCount; EntryIndex < OldITCount; EntryIndex++) + { + ProcessorNumber = VPort->RssV2Table[EntryIndex % NewITCount]; + ASSERT(ProcessorNumber.Group == VPort->RssV2Table[EntryIndex].Group); + ASSERT(ProcessorNumber.Number == VPort->RssV2Table[EntryIndex].Number); + LocalCpuIndex = VPort->RssV2IndexTable[EntryIndex]; + VPort->RssV2IndexTable[EntryIndex] = 0xFF; + RssV2NQEnforcerDereference(VPort->QueueMap, LocalCpuIndex); + } + } + } + + // + // Apply new configuration to HW (hash key and information is already in + // the VPort object). + // + MiniportApplyConfigurationToHW(Adapter, + VPort, + IsRssEnabled, + NewITCount, + NewNumberOfQueues); + + VPort->RssV2Params.NumberOfIndirectionTableEntries = NewITCount; + VPort->RssV2Params.NumberOfQueues = NewNumberOfQueues; + VPort->RssEnabled = IsRssEnabled; + + DEBUGP(MP_TRACE, "OID_GEN_RECEIVE_SCALE_PARAMETERS_V2: VPortId=%d, RssEnabled=%d, IT.size=%d\n", + NdisRequest->VPortId, IsRssEnabled, VPort->RssV2Params.NumberOfIndirectionTableEntries); + + Set->BytesNeeded = Set->InformationBufferLength; + Status = NDIS_STATUS_SUCCESS; + +Cleanup: + + DEBUGP(MP_TRACE, "<--- [%p] NICSetRSSv2Parameters Status 0x%08x\n", Adapter, Status); + + return Status; +} + + +_IRQL_requires_(DISPATCH_LEVEL) +NDIS_STATUS +NICSetRSSv2IndirectionTableEntries( + _In_ PMP_ADAPTER Adapter, + _In_ PNDIS_OID_REQUEST NdisRequest) +/*++ +Routine Description: + + This routine handles OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES method request. + +Arguments: + + Adapter - Pointer to adapter block + NdisRequest - The OID data for the request + +Return Value: + + NDIS_STATUS + +--*/ +{ + PROCESSOR_NUMBER ActorProcessorNumber; + PNDIS_RSS_SET_INDIRECTION_ENTRY Command; + RSSV2_PARSING_CONTEXT Context; + PROCESSOR_NUMBER CurrentProcessorNumber; + PNDIS_RSS_SET_INDIRECTION_ENTRY EntryArray; + BOOLEAN IsActive; + BOOLEAN IsNativeRss; + BOOLEAN IsValid; + ULONG InputBufferLength; + struct _METHOD *Method; + UINT8 NewCpuIndex; + ULONG NumCommandsToExecute; + UINT8 OldCpuIndex; + PNDIS_RSS_SET_INDIRECTION_ENTRIES RssEntries; + NDIS_STATUS Status; + ULONG SwitchId; + PROCESSOR_NUMBER TargetProcessorNumber; + ULONG VPortId; + PMP_ADAPTER_VPORT VPort; + + // + // Allocate a local queue map on stack, to hold temporary results during + // handling of each "move all" group. + // + DECLARE_RSSV2_QUEUE_MAP_ON_STACK(LocalQueueMap, + RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE); + + DEBUGP(MP_TRACE, "[%p] ---> NICSetRSSv2IndirectionTableEntries\n", Adapter); + + Method = &NdisRequest->DATA.METHOD_INFORMATION; + RssEntries = (PNDIS_RSS_SET_INDIRECTION_ENTRIES)Method->InformationBuffer; + InputBufferLength = Method->InputBufferLength; + + Method->BytesRead = 0; + Method->BytesNeeded = 0; + Method->BytesWritten = 0; + + // + // Validate the request + // + if (InputBufferLength < + (NDIS_SIZEOF_RSS_SET_INDIRECTION_ENTRIES_REVISION_1 + + RssEntries->NumberOfRssEntries * RssEntries->RssEntrySize)) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Invalid InformationBufferLength \n"); + Status = NDIS_STATUS_INVALID_LENGTH; + goto Cleanup; + } + + // + // RSSv2 spec requires up to 130 entries to be handled in a single batch. + // + if (RssEntries->NumberOfRssEntries > + (2 + MAX_NUMBER_OF_INDIRECTION_TABLE_ENTRIES)) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Invalid NumberOfRssEntries \n"); + Status = NDIS_STATUS_INVALID_DATA; + goto Cleanup; + } + + KeGetCurrentProcessorNumberEx(&ActorProcessorNumber); + + IsNativeRss = (BOOLEAN)(Adapter->RSSData.IsNicSwitchCreated == FALSE); + + RssV2InitializeParsingContext(&Context, RssEntries, IsNativeRss); + + EntryArray = (PNDIS_RSS_SET_INDIRECTION_ENTRY) + ((PUCHAR)RssEntries + RssEntries->RssEntryTableOffset); + + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Actor %d:%d, NumberOfRssEntries %d \n", + ActorProcessorNumber.Group, + ActorProcessorNumber.Number, + RssEntries->NumberOfRssEntries); + + NumCommandsToExecute = 0; + + // + // PASS 1: validation + // + while (RssV2GetNextCommandRange(&Context, &SwitchId, &VPortId)) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: 1ST PASS FOR VPortId=%d\n", + VPortId); + if (IsNativeRss) + { + ASSERT(VPortId == NDIS_INVALID_SWITCH_ID); + ASSERT(VPortId == NDIS_INVALID_VPORT_ID); + VPort = &Adapter->RSSData.NativeVPort; + } + else + { + if (SwitchId != NDIS_DEFAULT_SWITCH_ID) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Invalid SwitchId (%d)\n", + SwitchId); + RssV2SetCommandRangeStatus(&Context, + NDIS_STATUS_INVALID_PARAMETER); + continue; // while (RssV2FindNextCommandRange()) + } + + if (VPortId > MAX_NIC_SWITCH_VPORTS) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: Invalid VPortId (%d)\n", + VPortId); + RssV2SetCommandRangeStatus(&Context, + NDIS_STATUS_INVALID_PARAMETER); + continue; // while (RssV2FindNextCommandRange()) + } + + VPort = &Adapter->RSSData.VPort[VPortId]; + + if (VPort->Created == FALSE) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: VPort %d is not created\n", + VPortId); + RssV2SetCommandRangeStatus(&Context, + NDIS_STATUS_INVALID_PARAMETER); + continue; // while (RssV2FindNextCommandRange()) + } + + if (VPort->Active == FALSE) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: VPort %d is not active\n", + VPortId); + RssV2SetCommandRangeStatus(&Context, + NDIS_STATUS_INVALID_PORT_STATE); + continue; // while (RssV2FindNextCommandRange()) + } + } + + ASSERT(VPort != NULL); + + // + // Once valid VPort for the Command range is acquired, perform + // validation of individual "move entry" commands. + // + while ((Command = RssV2GetNextCommand(&Context, FALSE)) != NULL) + { + if (!NICSetRSSv2ValidateCommandAndGetProcessor( + VPort, + Command, + &CurrentProcessorNumber, + &OldCpuIndex, + &IsActive)) + { + Command->EntryStatus = NDIS_STATUS_INVALID_PARAMETER; + continue; // while (Command = RssV2GetNextCommand()) + } + + if ((ActorProcessorNumber.Group != CurrentProcessorNumber.Group) || + (ActorProcessorNumber.Number != CurrentProcessorNumber.Number)) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: VPortId=%d, Flags=0x%x, EntryIndex=%d: Invalid Actor %d:%d, expected %d:%d\n", + Command->VPortId, + Command->Flags, + Command->IndirectionTableIndex, + ActorProcessorNumber.Group, + ActorProcessorNumber.Number, + CurrentProcessorNumber.Group, + CurrentProcessorNumber.Number); + + Command->EntryStatus = NDIS_STATUS_NOT_ACCEPTED; + __debugbreak(); + continue; // while (Command = RssV2GetNextCommand()) + } + + TargetProcessorNumber = Command->TargetProcessorNumber; + + // + // Treat no-op commands as "succeded". + // + if ((TargetProcessorNumber.Group == CurrentProcessorNumber.Group) && + (TargetProcessorNumber.Number == CurrentProcessorNumber.Number)) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: OK1: VPortId=%d, Flags=0x%x, EntryIndex=%d: TargetProc=%d:%d\n", + Command->VPortId, + Command->Flags, + Command->IndirectionTableIndex, + TargetProcessorNumber.Group, + TargetProcessorNumber.Number); + + Command->EntryStatus = NDIS_STATUS_SUCCESS; + continue; // while (Command = RssV2GetNextCommand()) + } + + if (IsActive == FALSE) + { + // + // INACTIVE steering entities are only tracked and will be + // enforced during RSS transition to ON/OFF. + // + NICSetRSSv2SetCurrentProcessor(VPort, + Command, + TargetProcessorNumber, + 0xFF); + + DEBUGP(MP_ERROR, "NDIS_SET_INDIRECTION_TABLE_ENTRY: OK2: VPortId=%d, Flags=0x%x, EntryIndex=%d, TargetProc=%d:%d\n", + Command->VPortId, + Command->Flags, + Command->IndirectionTableIndex, + TargetProcessorNumber.Group, + TargetProcessorNumber.Number); + + Command->EntryStatus = NDIS_STATUS_SUCCESS; + continue; // while (Command = RssV2GetNextCommand()) + } + + if (!NICSetRSSv2ValidateRssProcessor(Adapter, + TargetProcessorNumber, + &NewCpuIndex)) + { + Command->EntryStatus = NDIS_STATUS_INVALID_DATA; + continue; // while (Command = RssV2GetNextCommand()) + } + + // + // Marked commands as candidates for NQ-check and HW execution + // if they: + // + // - refer to ACTIVE steering entities + // - contain a validated target processor + // - target processor actualy changes + // + ASSERT(Command->EntryStatus == NDIS_STATUS_PENDING); + NumCommandsToExecute++; + } + } + + if (NumCommandsToExecute == 0) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: 2ND PASS EMPTY FOR VPortId=%d\n", + VPortId); + Status = NDIS_STATUS_SUCCESS; + goto Cleanup; + } + + RssV2RestartRangeIterator(&Context); + + // + // PASS 2: NQ-enforcement and execution for ACTIVE steering parameters only. + // + while (RssV2GetNextCommandRange(&Context, &SwitchId, &VPortId)) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: 2ND PASS FOR VPortId=%d\n", + VPortId); + // + // VPorts are already validated + // + VPort = IsNativeRss ? &Adapter->RSSData.NativeVPort : + &Adapter->RSSData.VPort[VPortId]; + + RssV2NQEnforcerEnter(VPort->QueueMap, LocalQueueMap); + + // + // Iterate over non-processed commands and update LocalQueueMap + // + while ((Command = RssV2GetNextCommand(&Context, TRUE)) != NULL) + { + TargetProcessorNumber = Command->TargetProcessorNumber; + IsValid = NICSetRSSv2ValidateRssProcessor(Adapter, + TargetProcessorNumber, + &NewCpuIndex); + ASSERT(IsValid); + + IsValid = NICSetRSSv2ValidateCommandAndGetProcessor( + VPort, + Command, + &CurrentProcessorNumber, + &OldCpuIndex, + &IsActive); + ASSERT(IsValid && IsActive); + RssV2NQEnforcerUpdate(LocalQueueMap, OldCpuIndex, NewCpuIndex); + } + + Status = RssV2NQEnforcerLeave(VPort->QueueMap, + LocalQueueMap, + VPort->RssV2Params.NumberOfQueues); + if (Status != NDIS_STATUS_SUCCESS) + { + DEBUGP(MP_ERROR, "OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES: VPortId=%d: NQ-violation: NQueues=%d < NProcs=%d\n", + VPortId, + VPort->RssV2Params.NumberOfQueues, + RssV2NQEnforcerGetNumberOfProcs(LocalQueueMap)); + RssV2SetCommandRangeStatus(&Context, Status); + continue; // while (RssV2GetNextCommandRange()) + } + + // + // NO FAILURES AFTER THIS POINT (INCLUDING IN HW !!!) + // + + // + // Iterate over the same Command range to actually update the + // processor numbers/indices. + // + RssV2RestartCommandIterator(&Context); + + while ((Command = RssV2GetNextCommand(&Context, TRUE)) != NULL) + { + TargetProcessorNumber = Command->TargetProcessorNumber; + IsValid = NICSetRSSv2ValidateRssProcessor(Adapter, + TargetProcessorNumber, + &NewCpuIndex); + ASSERT(IsValid); + + // + // Apply "move ITE" command to hardware + // + MiniportApplyMoveITECommandToHW(Adapter, VPort, Command, NewCpuIndex); + + // + // Reflect the change in software structure. + // + NICSetRSSv2SetCurrentProcessor(VPort, + Command, + TargetProcessorNumber, + NewCpuIndex); + + DEBUGP(MP_ERROR, "NDIS_SET_INDIRECTION_TABLE_ENTRY: OK3: VPortId=%d, Flags=0x%x, EntryIndex=%d, TargetProc=%d:%d\n", + Command->VPortId, + Command->Flags, + Command->IndirectionTableIndex, + TargetProcessorNumber.Group, + TargetProcessorNumber.Number); + + Command->EntryStatus = NDIS_STATUS_SUCCESS; + } + } + + + Method->BytesRead = InputBufferLength; + Method->BytesWritten = InputBufferLength; + Status = NDIS_STATUS_SUCCESS; + +Cleanup: + + DEBUGP(MP_TRACE, "<--- [%p] NICSetRSSv2IndirectionTableEntries Status 0x%08x\n", Adapter, Status); + + return Status; +} diff --git a/network/ndis/netvmini/6x/rssv2.h b/network/ndis/netvmini/6x/rssv2.h new file mode 100644 index 000000000..7795dfcc7 --- /dev/null +++ b/network/ndis/netvmini/6x/rssv2.h @@ -0,0 +1,136 @@ +/*++ + +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: + + RSSv2.h + +Abstract: + + This module declares the NDIS-RSSv2 related data types, flags, macros, and functions. + +Revision History: + +--*/ + +#pragma once + +#if (NDIS_SUPPORT_NDIS680) + +#define MAX_NIC_SWITCH_VPORTS 64 + +#define MAX_NUMBER_OF_INDIRECTION_TABLE_ENTRIES \ + (NDIS_RSS_INDIRECTION_TABLE_MAX_SIZE_REVISION_3 / \ + sizeof(PROCESSOR_NUMBER)) + +// +// This define controls if QueueMap's functionality of the rssv2lib will +// be compiled-in. +// +#define RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE 64 + +typedef struct _RSSV2_QUEUE_MAP* PRSSV2_QUEUE_MAP; +typedef struct _MP_ADAPTER_VPORT +{ + // + // CREATE_VPORT OID was issues for this VPort + // + BOOLEAN Created; + + // + // VPort is activated + // + BOOLEAN Active; + + // + // If HwRSS (VMMQ) is enabled for this VPort + // + BOOLEAN RssEnabled; + + // + // RSSv2 parameters + // + NDIS_RECEIVE_SCALE_PARAMETERS_V2 RssV2Params; + + // + // Hashing key + // + UCHAR RssV2Key[NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2]; + + // + // Processor numbers for steering parameters + // + PROCESSOR_NUMBER PrimaryProcessorNumber; + PROCESSOR_NUMBER DefaultProcessorNumber; + PROCESSOR_NUMBER RssV2Table[MAX_NUMBER_OF_INDIRECTION_TABLE_ENTRIES]; + + // + // Local indexes (relative to RSS table) for steering parameters + // + UINT8 PrimaryProcessorIndex; + UINT8 DefaultProcessorIndex; + UINT8 RssV2IndexTable[MAX_NUMBER_OF_INDIRECTION_TABLE_ENTRIES]; + + // + // NQ ("number of queues") enforcement helper object. + // Tracks how many entries reference each RSS processor + // + PRSSV2_QUEUE_MAP QueueMap; + +} MP_ADAPTER_VPORT, *PMP_ADAPTER_VPORT; + +// +// The MP_ADAPTER_RSS_DATA structure is used to track RSS state +// +typedef struct _MP_ADAPTER_RSS_DATA +{ + // + // Flag determines if miniport is in Native RSS or NicSwitch mode + // + BOOLEAN IsNicSwitchCreated; + + // + // RSS processor information from NDIS + // + PNDIS_RSS_PROCESSOR_INFO RssProcessorInfo; + PNDIS_RSS_PROCESSOR RssProcessorArray; + + // + // RSS state for a single "VPort" in NativeRSS mode + // + MP_ADAPTER_VPORT NativeVPort; + + // + // RSS state for VPorts in NicSwitch mode + // + MP_ADAPTER_VPORT VPort[MAX_NIC_SWITCH_VPORTS]; + +} MP_ADAPTER_RSS_DATA, *PMP_ADAPTER_RSS_DATA; + + +_IRQL_requires_(PASSIVE_LEVEL) +NDIS_STATUS +InitializeRSSConfig( + _Inout_ struct _MP_ADAPTER* Adapter + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NDIS_STATUS +NICSetRSSv2Parameters( + _In_ struct _MP_ADAPTER* Adapter, + _In_ PNDIS_OID_REQUEST NdisRequest); + +_IRQL_requires_(DISPATCH_LEVEL) +NDIS_STATUS +NICSetRSSv2IndirectionTableEntries( + _In_ struct _MP_ADAPTER* Adapter, + _In_ PNDIS_OID_REQUEST NdisRequest); + + +#endif // NDIS_SUPPORT_NDIS680 diff --git a/network/ndis/netvmini/6x/rssv2lib.c b/network/ndis/netvmini/6x/rssv2lib.c new file mode 100644 index 000000000..a2bc55507 --- /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 +#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; +} + diff --git a/network/ndis/netvmini/6x/rssv2lib.h b/network/ndis/netvmini/6x/rssv2lib.h new file mode 100644 index 000000000..619624ecd --- /dev/null +++ b/network/ndis/netvmini/6x/rssv2lib.h @@ -0,0 +1,205 @@ +/*++ + +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.h + +Abstract: + + This module declares the NDIS RSSv2 helper data types, flags, macros, and functions. + +Revision History: + +--*/ + +#pragma once + +// +// Temporary workaround until new definition reaches WDK. +// +#if !defined(NDIS_STATUS_NO_QUEUES) +#define NDIS_STATUS_NO_QUEUES 0xC0230031L +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct _RSSV2_PARSING_CONTEXT +{ + PNDIS_RSS_SET_INDIRECTION_ENTRIES RssV2Oid; + ULONG MaxIndex; + ULONG StartIndex; + ULONG LimitIndex; + ULONG LastStartIndex; + BOOLEAN IsNativeRss; + +} RSSV2_PARSING_CONTEXT, *PRSSV2_PARSING_CONTEXT; + + +#define RSSV2_GET_COMMAND(_RssV2Oid_,_Index_) \ + (PNDIS_RSS_SET_INDIRECTION_ENTRY) \ + ((PUCHAR)(_RssV2Oid_) + (_RssV2Oid_)->RssEntryTableOffset + \ + (_Index_) * (_RssV2Oid_)->RssEntrySize) + +extern +FORCEINLINE +VOID +RssV2InitializeParsingContext ( + _Out_ PRSSV2_PARSING_CONTEXT Context, + _In_ PNDIS_RSS_SET_INDIRECTION_ENTRIES RssV2Oid, + _In_ BOOLEAN IsNativeRss + ); + +_Success_(return != FALSE) +BOOLEAN +RssV2GetNextCommandRange ( + _Inout_ PRSSV2_PARSING_CONTEXT Context, + _Out_ ULONG* SwitchId, + _Out_ ULONG* VPortId + ); + +VOID +RssV2RestartRangeIterator ( + _Inout_ PRSSV2_PARSING_CONTEXT Context + ); + +PNDIS_RSS_SET_INDIRECTION_ENTRY +RssV2GetNextCommand ( + _Inout_ PRSSV2_PARSING_CONTEXT Context, + _In_ BOOLEAN SkipProcessedCommands + ); + +VOID +RssV2RestartCommandIterator ( + _Inout_ PRSSV2_PARSING_CONTEXT Context + ); + +VOID +RssV2SetCommandRangeStatus ( + _Inout_ PRSSV2_PARSING_CONTEXT Context, + _In_ NDIS_STATUS Status + ); + +// +// Conditionally include support for example RSSV2_QUEUE_MAP implementation. +// Miniports don't have to use this implementation (as they may have different +// locking schema) +// +#if defined(RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE) && (RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE != 0) + +// +// Queue map for VPort (or for adapter's in NativeRSS mode) +// +#define BITS_PER_WORD (sizeof(ULONG_PTR) * 8) +#define RSSV2_BITFIELD_OFFSET(_PROC_INDEX_) ((_PROC_INDEX_) / BITS_PER_WORD) +#define RSSV2_BITFIELD_SIZE(_MAX_PROC_) \ + sizeof(ULONG_PTR) * (1 + RSSV2_BITFIELD_OFFSET((_MAX_PROC_) - 1)) + +#define RSSV2_REFERENCE_OFFSET(_PROC_INDEX_) ((_PROC_INDEX_) * sizeof(UINT8)) +#define RSSV2_REFERENCE_SIZE(_MAX_PROC_) ((_MAX_PROC_) * sizeof(UINT8)) + +typedef struct _RSSV2_QUEUE_MAP +{ + // + // Members to help enforce "NQ-violation" (per-VPort limit on number of queues) + // + KSPIN_LOCK SpinLock; + + // + // Maximum number of processors in adapter's RSS table. + // + ULONG MaxProcessors; + ULONG ReservedField; + + // + // Two variable-size fields follow this structure: + // + // - Bitmask of referenced processors + // - Array with reference counts for each RSS processor + // (indexed by a local CPU index, which is relative to RSS table). + // + // + // ULONG_PTR ReferenceBitmask[]; + // UINT8 ReferenceCount[]; + +} RSSV2_QUEUE_MAP, *PRSSV2_QUEUE_MAP; + + +#define DECLARE_RSSV2_QUEUE_MAP_ON_STACK(_LOCAL_NAME_, _MAX_PROCS_) \ + __pragma(warning(suppress: 6255)) \ + PRSSV2_QUEUE_MAP _LOCAL_NAME_ = \ + (PRSSV2_QUEUE_MAP)_alloca(RssV2NQEnforcerGetQueueMapSize(_MAX_PROCS_)) + +FORCEINLINE +ULONG +RssV2NQEnforcerGetQueueMapSize ( + _In_ ULONG MaxNumberOfProcessorsInRssTable + ) +{ + return sizeof(RSSV2_QUEUE_MAP) + + RSSV2_BITFIELD_SIZE(MaxNumberOfProcessorsInRssTable) + + RSSV2_REFERENCE_SIZE(MaxNumberOfProcessorsInRssTable); +} + +VOID +RssV2NQEnforcerReset ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap + ); + +VOID +RssV2NQEnforcerInitialize ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG MaxNumberOfProcessorsInRssTable + ); + +VOID +RssV2NQEnforcerReference ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG LocalCpuIndex + ); + +VOID +RssV2NQEnforcerDereference ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ ULONG LocalCpuIndex + ); + +VOID +RssV2NQEnforcerUpdate ( + _Inout_ PRSSV2_QUEUE_MAP QueueMap, + _In_ UINT8 OldCpuIndex, + _In_ UINT8 NewCpuIndex + ); + +ULONG +RssV2NQEnforcerGetNumberOfProcs ( + _In_ PRSSV2_QUEUE_MAP QueueMap + ); + +VOID +RssV2NQEnforcerEnter( + _Inout_ PRSSV2_QUEUE_MAP GlobalQueueMap, + _Inout_ PRSSV2_QUEUE_MAP LocalQueueMap + ); + +NDIS_STATUS +RssV2NQEnforcerLeave ( + _Inout_ PRSSV2_QUEUE_MAP GlobalQueueMap, + _In_ PRSSV2_QUEUE_MAP LocalQueueMap, + _In_ ULONG QueueLimit + ); + +#endif // defined(RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE) && (RSSV2_MAX_NUMBER_OF_PROCESSORS_IN_RSS_TABLE != 0) + +#ifdef __cplusplus +} +#endif