14c37757eSNguyen Trung Khanh /*
24c37757eSNguyen Trung Khanh  * This file contains NDIS driver procedures, common for NDIS5 and NDIS6
34c37757eSNguyen Trung Khanh  *
44c37757eSNguyen Trung Khanh  * Copyright (c) 2008-2017 Red Hat, Inc.
54c37757eSNguyen Trung Khanh  *
64c37757eSNguyen Trung Khanh  * Redistribution and use in source and binary forms, with or without
74c37757eSNguyen Trung Khanh  * modification, are permitted provided that the following conditions
84c37757eSNguyen Trung Khanh  * are met :
94c37757eSNguyen Trung Khanh  * 1. Redistributions of source code must retain the above copyright
104c37757eSNguyen Trung Khanh  *    notice, this list of conditions and the following disclaimer.
114c37757eSNguyen Trung Khanh  * 2. Redistributions in binary form must reproduce the above copyright
124c37757eSNguyen Trung Khanh  *    notice, this list of conditions and the following disclaimer in the
134c37757eSNguyen Trung Khanh  *    documentation and / or other materials provided with the distribution.
144c37757eSNguyen Trung Khanh  * 3. Neither the names of the copyright holders nor the names of their contributors
154c37757eSNguyen Trung Khanh  *    may be used to endorse or promote products derived from this software
164c37757eSNguyen Trung Khanh  *    without specific prior written permission.
174c37757eSNguyen Trung Khanh  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
184c37757eSNguyen Trung Khanh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194c37757eSNguyen Trung Khanh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
204c37757eSNguyen Trung Khanh  * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
214c37757eSNguyen Trung Khanh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
224c37757eSNguyen Trung Khanh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
234c37757eSNguyen Trung Khanh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
244c37757eSNguyen Trung Khanh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
254c37757eSNguyen Trung Khanh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264c37757eSNguyen Trung Khanh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274c37757eSNguyen Trung Khanh  * SUCH DAMAGE.
284c37757eSNguyen Trung Khanh  */
294c37757eSNguyen Trung Khanh #include "ndis56common.h"
304c37757eSNguyen Trung Khanh 
314c37757eSNguyen Trung Khanh #ifdef WPP_EVENT_TRACING
324c37757eSNguyen Trung Khanh #include "ParaNdis-Common.tmh"
334c37757eSNguyen Trung Khanh #endif
344c37757eSNguyen Trung Khanh 
354c37757eSNguyen Trung Khanh static void ReuseReceiveBufferRegular(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor);
364c37757eSNguyen Trung Khanh static void ReuseReceiveBufferPowerOff(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor);
374c37757eSNguyen Trung Khanh 
384c37757eSNguyen Trung Khanh //#define ROUNDSIZE(sz) ((sz + 15) & ~15)
394c37757eSNguyen Trung Khanh #define MAX_VLAN_ID     4095
404c37757eSNguyen Trung Khanh 
414c37757eSNguyen Trung Khanh #if 0
424c37757eSNguyen Trung Khanh void FORCEINLINE DebugDumpPacket(LPCSTR prefix, PVOID header, int level)
434c37757eSNguyen Trung Khanh {
444c37757eSNguyen Trung Khanh     PUCHAR peth = (PUCHAR)header;
454c37757eSNguyen Trung Khanh     DPrintf(level, ("[%s] %02X%02X%02X%02X%02X%02X => %02X%02X%02X%02X%02X%02X", prefix,
464c37757eSNguyen Trung Khanh         peth[6], peth[7], peth[8], peth[9], peth[10], peth[11],
474c37757eSNguyen Trung Khanh         peth[0], peth[1], peth[2], peth[3], peth[4], peth[5]));
484c37757eSNguyen Trung Khanh }
494c37757eSNguyen Trung Khanh #else
DebugDumpPacket(LPCSTR prefix,PVOID header,int level)504c37757eSNguyen Trung Khanh void FORCEINLINE DebugDumpPacket(LPCSTR prefix, PVOID header, int level)
514c37757eSNguyen Trung Khanh {
524c37757eSNguyen Trung Khanh }
534c37757eSNguyen Trung Khanh #endif
544c37757eSNguyen Trung Khanh 
554c37757eSNguyen Trung Khanh 
564c37757eSNguyen Trung Khanh 
574c37757eSNguyen Trung Khanh /**********************************************************
584c37757eSNguyen Trung Khanh Validates MAC address
594c37757eSNguyen Trung Khanh Valid MAC address is not broadcast, not multicast, not empty
604c37757eSNguyen Trung Khanh if bLocal is set, it must be LOCAL
614c37757eSNguyen Trung Khanh if not, is must be non-local or local
624c37757eSNguyen Trung Khanh Parameters:
634c37757eSNguyen Trung Khanh     PUCHAR pcMacAddress - MAC address to validate
644c37757eSNguyen Trung Khanh     BOOLEAN bLocal      - TRUE, if we validate locally administered address
654c37757eSNguyen Trung Khanh Return value:
664c37757eSNguyen Trung Khanh     TRUE if valid
674c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_ValidateMacAddress(PUCHAR pcMacAddress,BOOLEAN bLocal)684c37757eSNguyen Trung Khanh BOOLEAN ParaNdis_ValidateMacAddress(PUCHAR pcMacAddress, BOOLEAN bLocal)
694c37757eSNguyen Trung Khanh {
704c37757eSNguyen Trung Khanh     BOOLEAN bLA = FALSE, bEmpty, bBroadcast, bMulticast = FALSE;
714c37757eSNguyen Trung Khanh     bBroadcast = ETH_IS_BROADCAST(pcMacAddress);
724c37757eSNguyen Trung Khanh     bLA = !bBroadcast && ETH_IS_LOCALLY_ADMINISTERED(pcMacAddress);
734c37757eSNguyen Trung Khanh     bMulticast = !bBroadcast && ETH_IS_MULTICAST(pcMacAddress);
744c37757eSNguyen Trung Khanh     bEmpty = ETH_IS_EMPTY(pcMacAddress);
754c37757eSNguyen Trung Khanh     return !bBroadcast && !bEmpty && !bMulticast && (!bLocal || bLA);
764c37757eSNguyen Trung Khanh }
774c37757eSNguyen Trung Khanh 
QueryPacketType(PVOID data)784c37757eSNguyen Trung Khanh static eInspectedPacketType QueryPacketType(PVOID data)
794c37757eSNguyen Trung Khanh {
804c37757eSNguyen Trung Khanh     if (ETH_IS_BROADCAST(data))
814c37757eSNguyen Trung Khanh         return iptBroadcast;
824c37757eSNguyen Trung Khanh     if (ETH_IS_MULTICAST(data))
834c37757eSNguyen Trung Khanh         return iptMulticast;
844c37757eSNguyen Trung Khanh     return iptUnicast;
854c37757eSNguyen Trung Khanh }
864c37757eSNguyen Trung Khanh 
874c37757eSNguyen Trung Khanh typedef struct _tagConfigurationEntry
884c37757eSNguyen Trung Khanh {
894c37757eSNguyen Trung Khanh     const char      *Name;
904c37757eSNguyen Trung Khanh     ULONG           ulValue;
914c37757eSNguyen Trung Khanh     ULONG           ulMinimal;
924c37757eSNguyen Trung Khanh     ULONG           ulMaximal;
934c37757eSNguyen Trung Khanh }tConfigurationEntry;
944c37757eSNguyen Trung Khanh 
954c37757eSNguyen Trung Khanh typedef struct _tagConfigurationEntries
964c37757eSNguyen Trung Khanh {
974c37757eSNguyen Trung Khanh     tConfigurationEntry isPromiscuous;
984c37757eSNguyen Trung Khanh     tConfigurationEntry PrioritySupport;
994c37757eSNguyen Trung Khanh     tConfigurationEntry ConnectRate;
1004c37757eSNguyen Trung Khanh     tConfigurationEntry isLogEnabled;
1014c37757eSNguyen Trung Khanh     tConfigurationEntry debugLevel;
1024c37757eSNguyen Trung Khanh     tConfigurationEntry connectTimer;
1034c37757eSNguyen Trung Khanh     tConfigurationEntry dpcChecker;
1044c37757eSNguyen Trung Khanh     tConfigurationEntry TxCapacity;
1054c37757eSNguyen Trung Khanh     tConfigurationEntry RxCapacity;
1064c37757eSNguyen Trung Khanh     tConfigurationEntry InterruptRecovery;
1074c37757eSNguyen Trung Khanh     tConfigurationEntry LogStatistics;
1084c37757eSNguyen Trung Khanh     tConfigurationEntry PacketFiltering;
1094c37757eSNguyen Trung Khanh     tConfigurationEntry ScatterGather;
1104c37757eSNguyen Trung Khanh     tConfigurationEntry BatchReceive;
1114c37757eSNguyen Trung Khanh     tConfigurationEntry OffloadTxChecksum;
1124c37757eSNguyen Trung Khanh     tConfigurationEntry OffloadTxLSO;
1134c37757eSNguyen Trung Khanh     tConfigurationEntry OffloadRxCS;
1144c37757eSNguyen Trung Khanh     tConfigurationEntry OffloadGuestCS;
1154c37757eSNguyen Trung Khanh     tConfigurationEntry UseSwTxChecksum;
1164c37757eSNguyen Trung Khanh     tConfigurationEntry IPPacketsCheck;
1174c37757eSNguyen Trung Khanh     tConfigurationEntry stdIpcsV4;
1184c37757eSNguyen Trung Khanh     tConfigurationEntry stdTcpcsV4;
1194c37757eSNguyen Trung Khanh     tConfigurationEntry stdTcpcsV6;
1204c37757eSNguyen Trung Khanh     tConfigurationEntry stdUdpcsV4;
1214c37757eSNguyen Trung Khanh     tConfigurationEntry stdUdpcsV6;
1224c37757eSNguyen Trung Khanh     tConfigurationEntry stdLsoV1;
1234c37757eSNguyen Trung Khanh     tConfigurationEntry stdLsoV2ip4;
1244c37757eSNguyen Trung Khanh     tConfigurationEntry stdLsoV2ip6;
1254c37757eSNguyen Trung Khanh     tConfigurationEntry PriorityVlanTagging;
1264c37757eSNguyen Trung Khanh     tConfigurationEntry VlanId;
1274c37757eSNguyen Trung Khanh     tConfigurationEntry UseMergeableBuffers;
1284c37757eSNguyen Trung Khanh     tConfigurationEntry MTU;
1294c37757eSNguyen Trung Khanh     tConfigurationEntry NumberOfHandledRXPackersInDPC;
1304c37757eSNguyen Trung Khanh     tConfigurationEntry Indirect;
1314c37757eSNguyen Trung Khanh }tConfigurationEntries;
1324c37757eSNguyen Trung Khanh 
1334c37757eSNguyen Trung Khanh static const tConfigurationEntries defaultConfiguration =
1344c37757eSNguyen Trung Khanh {
1354c37757eSNguyen Trung Khanh     { "Promiscuous",    0,  0,  1 },
1364c37757eSNguyen Trung Khanh     { "Priority",       0,  0,  1 },
1374c37757eSNguyen Trung Khanh     { "ConnectRate",    100,10,10000 },
1384c37757eSNguyen Trung Khanh     { "DoLog",          1,  0,  1 },
1394c37757eSNguyen Trung Khanh     { "DebugLevel",     2,  0,  8 },
1404c37757eSNguyen Trung Khanh     { "ConnectTimer",   0,  0,  300000 },
1414c37757eSNguyen Trung Khanh     { "DpcCheck",       0,  0,  2 },
1424c37757eSNguyen Trung Khanh     { "TxCapacity",     1024,   16, 1024 },
1434c37757eSNguyen Trung Khanh     { "RxCapacity",     256, 32, 1024 },
1444c37757eSNguyen Trung Khanh     { "InterruptRecovery",  0, 0, 1},
1454c37757eSNguyen Trung Khanh     { "LogStatistics",  0, 0, 10000},
1464c37757eSNguyen Trung Khanh     { "PacketFilter",   1, 0, 1},
1474c37757eSNguyen Trung Khanh     { "Gather",         1, 0, 1},
1484c37757eSNguyen Trung Khanh     { "BatchReceive",   1, 0, 1},
1494c37757eSNguyen Trung Khanh     { "Offload.TxChecksum", 0, 0, 31},
1504c37757eSNguyen Trung Khanh     { "Offload.TxLSO",  0, 0, 2},
1514c37757eSNguyen Trung Khanh     { "Offload.RxCS",   0, 0, 31},
1524c37757eSNguyen Trung Khanh     { "Offload.GuestCS", 0, 0, 1},
1534c37757eSNguyen Trung Khanh     { "UseSwTxChecksum", 0, 0, 1 },
1544c37757eSNguyen Trung Khanh     { "IPPacketsCheck", 0, 0, 3 },
1554c37757eSNguyen Trung Khanh     { "*IPChecksumOffloadIPv4", 3, 0, 3 },
1564c37757eSNguyen Trung Khanh     { "*TCPChecksumOffloadIPv4",3, 0, 3 },
1574c37757eSNguyen Trung Khanh     { "*TCPChecksumOffloadIPv6",3, 0, 3 },
1584c37757eSNguyen Trung Khanh     { "*UDPChecksumOffloadIPv4",3, 0, 3 },
1594c37757eSNguyen Trung Khanh     { "*UDPChecksumOffloadIPv6",3, 0, 3 },
1604c37757eSNguyen Trung Khanh     { "*LsoV1IPv4", 1, 0, 1 },
1614c37757eSNguyen Trung Khanh     { "*LsoV2IPv4", 1, 0, 1 },
1624c37757eSNguyen Trung Khanh     { "*LsoV2IPv6", 1, 0, 1 },
1634c37757eSNguyen Trung Khanh     { "*PriorityVLANTag", 3, 0, 3},
1644c37757eSNguyen Trung Khanh     { "VlanId", 0, 0, MAX_VLAN_ID},
1654c37757eSNguyen Trung Khanh     { "MergeableBuf", 1, 0, 1},
1664c37757eSNguyen Trung Khanh     { "MTU", 1500, 500, 65500},
1674c37757eSNguyen Trung Khanh     { "NumberOfHandledRXPackersInDPC", MAX_RX_LOOPS, 1, 10000},
1684c37757eSNguyen Trung Khanh     { "Indirect", 0, 0, 2},
1694c37757eSNguyen Trung Khanh };
1704c37757eSNguyen Trung Khanh 
ParaNdis_ResetVirtIONetDevice(PARANDIS_ADAPTER * pContext)1714c37757eSNguyen Trung Khanh static void ParaNdis_ResetVirtIONetDevice(PARANDIS_ADAPTER *pContext)
1724c37757eSNguyen Trung Khanh {
1734c37757eSNguyen Trung Khanh     virtio_device_reset(&pContext->IODevice);
1744c37757eSNguyen Trung Khanh     DPrintf(0, ("[%s] Done", __FUNCTION__));
1754c37757eSNguyen Trung Khanh     /* reset all the features in the device */
1764c37757eSNguyen Trung Khanh     pContext->ulCurrentVlansFilterSet = 0;
1774c37757eSNguyen Trung Khanh     pContext->ullGuestFeatures = 0;
1784c37757eSNguyen Trung Khanh #ifdef VIRTIO_RESET_VERIFY
1794c37757eSNguyen Trung Khanh     if (1)
1804c37757eSNguyen Trung Khanh     {
1814c37757eSNguyen Trung Khanh         u8 devStatus;
1824c37757eSNguyen Trung Khanh         devStatus = virtio_get_status(&pContext->IODevice);
1834c37757eSNguyen Trung Khanh         if (devStatus)
1844c37757eSNguyen Trung Khanh         {
1854c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Device status is still %02X", __FUNCTION__, (ULONG)devStatus));
1864c37757eSNguyen Trung Khanh             virtio_device_reset(&pContext->IODevice);
1874c37757eSNguyen Trung Khanh             devStatus = virtio_get_status(&pContext->IODevice);
1884c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Device status on retry %02X", __FUNCTION__, (ULONG)devStatus));
1894c37757eSNguyen Trung Khanh         }
1904c37757eSNguyen Trung Khanh     }
1914c37757eSNguyen Trung Khanh #endif
1924c37757eSNguyen Trung Khanh }
1934c37757eSNguyen Trung Khanh 
1944c37757eSNguyen Trung Khanh /**********************************************************
1954c37757eSNguyen Trung Khanh Gets integer value for specifies in pEntry->Name name
1964c37757eSNguyen Trung Khanh Parameters:
1974c37757eSNguyen Trung Khanh     NDIS_HANDLE cfg  previously open configuration
1984c37757eSNguyen Trung Khanh     tConfigurationEntry *pEntry - Entry to fill value in
1994c37757eSNguyen Trung Khanh ***********************************************************/
GetConfigurationEntry(NDIS_HANDLE cfg,tConfigurationEntry * pEntry)2004c37757eSNguyen Trung Khanh static void GetConfigurationEntry(NDIS_HANDLE cfg, tConfigurationEntry *pEntry)
2014c37757eSNguyen Trung Khanh {
2024c37757eSNguyen Trung Khanh     NDIS_STATUS status;
2034c37757eSNguyen Trung Khanh     const char *statusName;
2044c37757eSNguyen Trung Khanh     NDIS_STRING name = {0};
2054c37757eSNguyen Trung Khanh     PNDIS_CONFIGURATION_PARAMETER pParam = NULL;
2064c37757eSNguyen Trung Khanh     NDIS_PARAMETER_TYPE ParameterType = NdisParameterInteger;
2074c37757eSNguyen Trung Khanh     NdisInitializeString(&name, (PUCHAR)pEntry->Name);
2084c37757eSNguyen Trung Khanh     NdisReadConfiguration(
2094c37757eSNguyen Trung Khanh         &status,
2104c37757eSNguyen Trung Khanh         &pParam,
2114c37757eSNguyen Trung Khanh         cfg,
2124c37757eSNguyen Trung Khanh         &name,
2134c37757eSNguyen Trung Khanh         ParameterType);
2144c37757eSNguyen Trung Khanh     if (status == NDIS_STATUS_SUCCESS)
2154c37757eSNguyen Trung Khanh     {
2164c37757eSNguyen Trung Khanh         ULONG ulValue = pParam->ParameterData.IntegerData;
2174c37757eSNguyen Trung Khanh         if (ulValue >= pEntry->ulMinimal && ulValue <= pEntry->ulMaximal)
2184c37757eSNguyen Trung Khanh         {
2194c37757eSNguyen Trung Khanh             pEntry->ulValue = ulValue;
2204c37757eSNguyen Trung Khanh             statusName = "value";
2214c37757eSNguyen Trung Khanh         }
2224c37757eSNguyen Trung Khanh         else
2234c37757eSNguyen Trung Khanh         {
2244c37757eSNguyen Trung Khanh             statusName = "out of range";
2254c37757eSNguyen Trung Khanh         }
2264c37757eSNguyen Trung Khanh     }
2274c37757eSNguyen Trung Khanh     else
2284c37757eSNguyen Trung Khanh     {
2294c37757eSNguyen Trung Khanh         statusName = "nothing";
2304c37757eSNguyen Trung Khanh     }
2314c37757eSNguyen Trung Khanh     DPrintf(2, ("[%s] %s read for %s - 0x%x",
2324c37757eSNguyen Trung Khanh         __FUNCTION__,
2334c37757eSNguyen Trung Khanh         statusName,
2344c37757eSNguyen Trung Khanh         pEntry->Name,
2354c37757eSNguyen Trung Khanh         pEntry->ulValue));
2364c37757eSNguyen Trung Khanh     if (name.Buffer) NdisFreeString(name);
2374c37757eSNguyen Trung Khanh }
2384c37757eSNguyen Trung Khanh 
DisableLSOv4Permanently(PARANDIS_ADAPTER * pContext,LPCSTR procname,LPCSTR reason)2394c37757eSNguyen Trung Khanh static void DisableLSOv4Permanently(PARANDIS_ADAPTER *pContext, LPCSTR procname, LPCSTR reason)
2404c37757eSNguyen Trung Khanh {
2414c37757eSNguyen Trung Khanh     if (pContext->Offload.flagsValue & osbT4Lso)
2424c37757eSNguyen Trung Khanh     {
2434c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] Warning: %s", procname, reason));
2444c37757eSNguyen Trung Khanh         pContext->Offload.flagsValue &= ~osbT4Lso;
2454c37757eSNguyen Trung Khanh         ParaNdis_ResetOffloadSettings(pContext, NULL, NULL);
2464c37757eSNguyen Trung Khanh     }
2474c37757eSNguyen Trung Khanh }
2484c37757eSNguyen Trung Khanh 
DisableLSOv6Permanently(PARANDIS_ADAPTER * pContext,LPCSTR procname,LPCSTR reason)2494c37757eSNguyen Trung Khanh static void DisableLSOv6Permanently(PARANDIS_ADAPTER *pContext, LPCSTR procname, LPCSTR reason)
2504c37757eSNguyen Trung Khanh {
2514c37757eSNguyen Trung Khanh     if (pContext->Offload.flagsValue & osbT6Lso)
2524c37757eSNguyen Trung Khanh     {
2534c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] Warning: %s", procname, reason));
2544c37757eSNguyen Trung Khanh         pContext->Offload.flagsValue &= ~osbT6Lso;
2554c37757eSNguyen Trung Khanh         ParaNdis_ResetOffloadSettings(pContext, NULL, NULL);
2564c37757eSNguyen Trung Khanh     }
2574c37757eSNguyen Trung Khanh }
2584c37757eSNguyen Trung Khanh 
DisableBothLSOPermanently(PARANDIS_ADAPTER * pContext,LPCSTR procname,LPCSTR reason)2594c37757eSNguyen Trung Khanh static void DisableBothLSOPermanently(PARANDIS_ADAPTER *pContext, LPCSTR procname, LPCSTR reason)
2604c37757eSNguyen Trung Khanh {
2614c37757eSNguyen Trung Khanh     if (pContext->Offload.flagsValue & (osbT4Lso | osbT6Lso))
2624c37757eSNguyen Trung Khanh     {
2634c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] Warning: %s", procname, reason));
2644c37757eSNguyen Trung Khanh         pContext->Offload.flagsValue &= ~(osbT6Lso | osbT4Lso);
2654c37757eSNguyen Trung Khanh         ParaNdis_ResetOffloadSettings(pContext, NULL, NULL);
2664c37757eSNguyen Trung Khanh     }
2674c37757eSNguyen Trung Khanh }
2684c37757eSNguyen Trung Khanh 
2694c37757eSNguyen Trung Khanh /**********************************************************
2704c37757eSNguyen Trung Khanh Loads NIC parameters from adapter registry key
2714c37757eSNguyen Trung Khanh Parameters:
2724c37757eSNguyen Trung Khanh     context
2734c37757eSNguyen Trung Khanh     PUCHAR *ppNewMACAddress - pointer to hold MAC address if configured from host
2744c37757eSNguyen Trung Khanh ***********************************************************/
ReadNicConfiguration(PARANDIS_ADAPTER * pContext,PUCHAR * ppNewMACAddress)2754c37757eSNguyen Trung Khanh static void ReadNicConfiguration(PARANDIS_ADAPTER *pContext, PUCHAR *ppNewMACAddress)
2764c37757eSNguyen Trung Khanh {
2774c37757eSNguyen Trung Khanh     NDIS_HANDLE cfg;
2784c37757eSNguyen Trung Khanh     tConfigurationEntries *pConfiguration = ParaNdis_AllocateMemory(pContext, sizeof(tConfigurationEntries));
2794c37757eSNguyen Trung Khanh     if (pConfiguration)
2804c37757eSNguyen Trung Khanh     {
2814c37757eSNguyen Trung Khanh         *pConfiguration = defaultConfiguration;
2824c37757eSNguyen Trung Khanh         cfg = ParaNdis_OpenNICConfiguration(pContext);
2834c37757eSNguyen Trung Khanh         if (cfg)
2844c37757eSNguyen Trung Khanh         {
2854c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->isLogEnabled);
2864c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->debugLevel);
2874c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->ConnectRate);
2884c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->PrioritySupport);
2894c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->isPromiscuous);
2904c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->TxCapacity);
2914c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->RxCapacity);
2924c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->connectTimer);
2934c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->dpcChecker);
2944c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->InterruptRecovery);
2954c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->LogStatistics);
2964c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->PacketFiltering);
2974c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->ScatterGather);
2984c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->BatchReceive);
2994c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->OffloadTxChecksum);
3004c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->OffloadTxLSO);
3014c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->OffloadRxCS);
3024c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->OffloadGuestCS);
3034c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->UseSwTxChecksum);
3044c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->IPPacketsCheck);
3054c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdIpcsV4);
3064c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdTcpcsV4);
3074c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdTcpcsV6);
3084c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdUdpcsV4);
3094c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdUdpcsV6);
3104c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdLsoV1);
3114c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdLsoV2ip4);
3124c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->stdLsoV2ip6);
3134c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->PriorityVlanTagging);
3144c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->VlanId);
3154c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->UseMergeableBuffers);
3164c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->MTU);
3174c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->NumberOfHandledRXPackersInDPC);
3184c37757eSNguyen Trung Khanh             GetConfigurationEntry(cfg, &pConfiguration->Indirect);
3194c37757eSNguyen Trung Khanh 
3204c37757eSNguyen Trung Khanh     #if !defined(WPP_EVENT_TRACING)
3214c37757eSNguyen Trung Khanh             bDebugPrint = pConfiguration->isLogEnabled.ulValue;
3224c37757eSNguyen Trung Khanh             nDebugLevel = pConfiguration->debugLevel.ulValue;
3234c37757eSNguyen Trung Khanh     #endif
3244c37757eSNguyen Trung Khanh             // ignoring promiscuous setting, nothing to do with it
3254c37757eSNguyen Trung Khanh             pContext->maxFreeTxDescriptors = pConfiguration->TxCapacity.ulValue;
3264c37757eSNguyen Trung Khanh             pContext->NetMaxReceiveBuffers = pConfiguration->RxCapacity.ulValue;
3274c37757eSNguyen Trung Khanh             pContext->ulMilliesToConnect = pConfiguration->connectTimer.ulValue;
3284c37757eSNguyen Trung Khanh             pContext->nEnableDPCChecker = pConfiguration->dpcChecker.ulValue;
3294c37757eSNguyen Trung Khanh             pContext->bDoInterruptRecovery = pConfiguration->InterruptRecovery.ulValue != 0;
3304c37757eSNguyen Trung Khanh             pContext->Limits.nPrintDiagnostic = pConfiguration->LogStatistics.ulValue;
3314c37757eSNguyen Trung Khanh             pContext->uNumberOfHandledRXPacketsInDPC = pConfiguration->NumberOfHandledRXPackersInDPC.ulValue;
3324c37757eSNguyen Trung Khanh             pContext->bDoSupportPriority = pConfiguration->PrioritySupport.ulValue != 0;
3334c37757eSNguyen Trung Khanh             pContext->ulFormalLinkSpeed  = pConfiguration->ConnectRate.ulValue;
3344c37757eSNguyen Trung Khanh             pContext->ulFormalLinkSpeed *= 1000000;
3354c37757eSNguyen Trung Khanh             pContext->bDoHwPacketFiltering = pConfiguration->PacketFiltering.ulValue != 0;
3364c37757eSNguyen Trung Khanh             pContext->bUseScatterGather  = pConfiguration->ScatterGather.ulValue != 0;
3374c37757eSNguyen Trung Khanh             pContext->bBatchReceive      = pConfiguration->BatchReceive.ulValue != 0;
3384c37757eSNguyen Trung Khanh             pContext->bDoHardwareChecksum = pConfiguration->UseSwTxChecksum.ulValue == 0;
3394c37757eSNguyen Trung Khanh             pContext->bDoGuestChecksumOnReceive = pConfiguration->OffloadGuestCS.ulValue != 0;
3404c37757eSNguyen Trung Khanh             pContext->bDoIPCheckTx = pConfiguration->IPPacketsCheck.ulValue & 1;
3414c37757eSNguyen Trung Khanh             pContext->bDoIPCheckRx = pConfiguration->IPPacketsCheck.ulValue & 2;
3424c37757eSNguyen Trung Khanh             pContext->Offload.flagsValue = 0;
3434c37757eSNguyen Trung Khanh             // TX caps: 1 - TCP, 2 - UDP, 4 - IP, 8 - TCPv6, 16 - UDPv6
3444c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadTxChecksum.ulValue & 1) pContext->Offload.flagsValue |= osbT4TcpChecksum | osbT4TcpOptionsChecksum;
3454c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadTxChecksum.ulValue & 2) pContext->Offload.flagsValue |= osbT4UdpChecksum;
3464c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadTxChecksum.ulValue & 4) pContext->Offload.flagsValue |= osbT4IpChecksum | osbT4IpOptionsChecksum;
3474c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadTxChecksum.ulValue & 8) pContext->Offload.flagsValue |= osbT6TcpChecksum | osbT6TcpOptionsChecksum;
3484c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadTxChecksum.ulValue & 16) pContext->Offload.flagsValue |= osbT6UdpChecksum;
3494c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadTxLSO.ulValue) pContext->Offload.flagsValue |= osbT4Lso | osbT4LsoIp | osbT4LsoTcp;
3504c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadTxLSO.ulValue > 1) pContext->Offload.flagsValue |= osbT6Lso | osbT6LsoTcpOptions;
3514c37757eSNguyen Trung Khanh             // RX caps: 1 - TCP, 2 - UDP, 4 - IP, 8 - TCPv6, 16 - UDPv6
3524c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadRxCS.ulValue & 1) pContext->Offload.flagsValue |= osbT4RxTCPChecksum | osbT4RxTCPOptionsChecksum;
3534c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadRxCS.ulValue & 2) pContext->Offload.flagsValue |= osbT4RxUDPChecksum;
3544c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadRxCS.ulValue & 4) pContext->Offload.flagsValue |= osbT4RxIPChecksum | osbT4RxIPOptionsChecksum;
3554c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadRxCS.ulValue & 8) pContext->Offload.flagsValue |= osbT6RxTCPChecksum | osbT6RxTCPOptionsChecksum;
3564c37757eSNguyen Trung Khanh             if (pConfiguration->OffloadRxCS.ulValue & 16) pContext->Offload.flagsValue |= osbT6RxUDPChecksum;
3574c37757eSNguyen Trung Khanh             /* full packet size that can be configured as GSO for VIRTIO is short */
3584c37757eSNguyen Trung Khanh             /* NDIS test fails sometimes fails on segments 50-60K */
3594c37757eSNguyen Trung Khanh             pContext->Offload.maxPacketSize = PARANDIS_MAX_LSO_SIZE;
3604c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.IPv4Checksum = (UCHAR)pConfiguration->stdIpcsV4.ulValue;
3614c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.TCPIPv4Checksum = (UCHAR)pConfiguration->stdTcpcsV4.ulValue;
3624c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.TCPIPv6Checksum = (UCHAR)pConfiguration->stdTcpcsV6.ulValue;
3634c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.UDPIPv4Checksum = (UCHAR)pConfiguration->stdUdpcsV4.ulValue;
3644c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.UDPIPv6Checksum = (UCHAR)pConfiguration->stdUdpcsV6.ulValue;
3654c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.LsoV1 = (UCHAR)pConfiguration->stdLsoV1.ulValue;
3664c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.LsoV2IPv4 = (UCHAR)pConfiguration->stdLsoV2ip4.ulValue;
3674c37757eSNguyen Trung Khanh             pContext->InitialOffloadParameters.LsoV2IPv6 = (UCHAR)pConfiguration->stdLsoV2ip6.ulValue;
3684c37757eSNguyen Trung Khanh             pContext->ulPriorityVlanSetting = pConfiguration->PriorityVlanTagging.ulValue;
3694c37757eSNguyen Trung Khanh             pContext->VlanId = pConfiguration->VlanId.ulValue & 0xfff;
3704c37757eSNguyen Trung Khanh             pContext->bUseMergedBuffers = pConfiguration->UseMergeableBuffers.ulValue != 0;
3714c37757eSNguyen Trung Khanh             pContext->MaxPacketSize.nMaxDataSize = pConfiguration->MTU.ulValue;
3724c37757eSNguyen Trung Khanh             pContext->bUseIndirect = pConfiguration->Indirect.ulValue != 0;
3734c37757eSNguyen Trung Khanh             if (!pContext->bDoSupportPriority)
3744c37757eSNguyen Trung Khanh                 pContext->ulPriorityVlanSetting = 0;
3754c37757eSNguyen Trung Khanh             // if Vlan not supported
3764c37757eSNguyen Trung Khanh             if (!IsVlanSupported(pContext))
3774c37757eSNguyen Trung Khanh                 pContext->VlanId = 0;
3784c37757eSNguyen Trung Khanh             if (1)
3794c37757eSNguyen Trung Khanh             {
3804c37757eSNguyen Trung Khanh                 NDIS_STATUS status;
3814c37757eSNguyen Trung Khanh                 PVOID p;
3824c37757eSNguyen Trung Khanh                 UINT  len = 0;
3834c37757eSNguyen Trung Khanh                 NdisReadNetworkAddress(&status, &p, &len, cfg);
3844c37757eSNguyen Trung Khanh                 if (status == NDIS_STATUS_SUCCESS && len == sizeof(pContext->CurrentMacAddress))
3854c37757eSNguyen Trung Khanh                 {
3864c37757eSNguyen Trung Khanh                     *ppNewMACAddress = ParaNdis_AllocateMemory(pContext, sizeof(pContext->CurrentMacAddress));
3874c37757eSNguyen Trung Khanh                     if (*ppNewMACAddress)
3884c37757eSNguyen Trung Khanh                     {
3894c37757eSNguyen Trung Khanh                         NdisMoveMemory(*ppNewMACAddress, p, len);
3904c37757eSNguyen Trung Khanh                     }
3914c37757eSNguyen Trung Khanh                     else
3924c37757eSNguyen Trung Khanh                     {
3934c37757eSNguyen Trung Khanh                         DPrintf(0, ("[%s] MAC address present, but some problem also...", __FUNCTION__));
3944c37757eSNguyen Trung Khanh                     }
3954c37757eSNguyen Trung Khanh                 }
3964c37757eSNguyen Trung Khanh                 else if (len && len != sizeof(pContext->CurrentMacAddress))
3974c37757eSNguyen Trung Khanh                 {
3984c37757eSNguyen Trung Khanh                     DPrintf(0, ("[%s] MAC address has wrong length of %d", __FUNCTION__, len));
3994c37757eSNguyen Trung Khanh                 }
4004c37757eSNguyen Trung Khanh                 else
4014c37757eSNguyen Trung Khanh                 {
4024c37757eSNguyen Trung Khanh                     DPrintf(4, ("[%s] Nothing read for MAC, error %X", __FUNCTION__, status));
4034c37757eSNguyen Trung Khanh                 }
4044c37757eSNguyen Trung Khanh             }
4054c37757eSNguyen Trung Khanh             NdisCloseConfiguration(cfg);
4064c37757eSNguyen Trung Khanh         }
4074c37757eSNguyen Trung Khanh         NdisFreeMemory(pConfiguration, 0, 0);
4084c37757eSNguyen Trung Khanh     }
4094c37757eSNguyen Trung Khanh }
4104c37757eSNguyen Trung Khanh 
ParaNdis_ResetOffloadSettings(PARANDIS_ADAPTER * pContext,tOffloadSettingsFlags * pDest,PULONG from)4114c37757eSNguyen Trung Khanh void ParaNdis_ResetOffloadSettings(PARANDIS_ADAPTER *pContext, tOffloadSettingsFlags *pDest, PULONG from)
4124c37757eSNguyen Trung Khanh {
4134c37757eSNguyen Trung Khanh     if (!pDest) pDest = &pContext->Offload.flags;
4144c37757eSNguyen Trung Khanh     if (!from)  from = &pContext->Offload.flagsValue;
4154c37757eSNguyen Trung Khanh 
4164c37757eSNguyen Trung Khanh     pDest->fTxIPChecksum = !!(*from & osbT4IpChecksum);
4174c37757eSNguyen Trung Khanh     pDest->fTxTCPChecksum = !!(*from & osbT4TcpChecksum);
4184c37757eSNguyen Trung Khanh     pDest->fTxUDPChecksum = !!(*from & osbT4UdpChecksum);
4194c37757eSNguyen Trung Khanh     pDest->fTxTCPOptions = !!(*from & osbT4TcpOptionsChecksum);
4204c37757eSNguyen Trung Khanh     pDest->fTxIPOptions = !!(*from & osbT4IpOptionsChecksum);
4214c37757eSNguyen Trung Khanh 
4224c37757eSNguyen Trung Khanh     pDest->fTxLso = !!(*from & osbT4Lso);
4234c37757eSNguyen Trung Khanh     pDest->fTxLsoIP = !!(*from & osbT4LsoIp);
4244c37757eSNguyen Trung Khanh     pDest->fTxLsoTCP = !!(*from & osbT4LsoTcp);
4254c37757eSNguyen Trung Khanh 
4264c37757eSNguyen Trung Khanh     pDest->fRxIPChecksum = !!(*from & osbT4RxIPChecksum);
4274c37757eSNguyen Trung Khanh     pDest->fRxIPOptions = !!(*from & osbT4RxIPOptionsChecksum);
4284c37757eSNguyen Trung Khanh     pDest->fRxTCPChecksum = !!(*from & osbT4RxTCPChecksum);
4294c37757eSNguyen Trung Khanh     pDest->fRxTCPOptions = !!(*from & osbT4RxTCPOptionsChecksum);
4304c37757eSNguyen Trung Khanh     pDest->fRxUDPChecksum = !!(*from & osbT4RxUDPChecksum);
4314c37757eSNguyen Trung Khanh 
4324c37757eSNguyen Trung Khanh     pDest->fTxTCPv6Checksum = !!(*from & osbT6TcpChecksum);
4334c37757eSNguyen Trung Khanh     pDest->fTxTCPv6Options = !!(*from & osbT6TcpOptionsChecksum);
4344c37757eSNguyen Trung Khanh     pDest->fTxUDPv6Checksum = !!(*from & osbT6UdpChecksum);
4354c37757eSNguyen Trung Khanh     pDest->fTxIPv6Ext = !!(*from & osbT6IpExtChecksum);
4364c37757eSNguyen Trung Khanh 
4374c37757eSNguyen Trung Khanh     pDest->fTxLsov6 = !!(*from & osbT6Lso);
4384c37757eSNguyen Trung Khanh     pDest->fTxLsov6IP = !!(*from & osbT6LsoIpExt);
4394c37757eSNguyen Trung Khanh     pDest->fTxLsov6TCP = !!(*from & osbT6LsoTcpOptions);
4404c37757eSNguyen Trung Khanh 
4414c37757eSNguyen Trung Khanh     pDest->fRxTCPv6Checksum = !!(*from & osbT6RxTCPChecksum);
4424c37757eSNguyen Trung Khanh     pDest->fRxTCPv6Options = !!(*from & osbT6RxTCPOptionsChecksum);
4434c37757eSNguyen Trung Khanh     pDest->fRxUDPv6Checksum = !!(*from & osbT6RxUDPChecksum);
4444c37757eSNguyen Trung Khanh     pDest->fRxIPv6Ext = !!(*from & osbT6RxIpExtChecksum);
4454c37757eSNguyen Trung Khanh }
4464c37757eSNguyen Trung Khanh 
4474c37757eSNguyen Trung Khanh /**********************************************************
4484c37757eSNguyen Trung Khanh Enumerates adapter resources and fills the structure holding them
4494c37757eSNguyen Trung Khanh Verifies that IO assigned and has correct size
4504c37757eSNguyen Trung Khanh Verifies that interrupt assigned
4514c37757eSNguyen Trung Khanh Parameters:
4524c37757eSNguyen Trung Khanh     PNDIS_RESOURCE_LIST RList - list of resources, received from NDIS
4534c37757eSNguyen Trung Khanh     tAdapterResources *pResources - structure to fill
4544c37757eSNguyen Trung Khanh Return value:
4554c37757eSNguyen Trung Khanh     TRUE if everything is OK
4564c37757eSNguyen Trung Khanh ***********************************************************/
GetAdapterResources(NDIS_HANDLE MiniportHandle,PNDIS_RESOURCE_LIST RList,tAdapterResources * pResources)4574c37757eSNguyen Trung Khanh static BOOLEAN GetAdapterResources(NDIS_HANDLE MiniportHandle, PNDIS_RESOURCE_LIST RList, tAdapterResources *pResources)
4584c37757eSNguyen Trung Khanh {
4594c37757eSNguyen Trung Khanh     UINT i;
4604c37757eSNguyen Trung Khanh     int read, bar = -1;
4614c37757eSNguyen Trung Khanh     PCI_COMMON_HEADER pci_config;
4624c37757eSNguyen Trung Khanh     NdisZeroMemory(pResources, sizeof(*pResources));
4634c37757eSNguyen Trung Khanh 
4644c37757eSNguyen Trung Khanh     // read the PCI config space header
4654c37757eSNguyen Trung Khanh     read = NdisReadPciSlotInformation(
4664c37757eSNguyen Trung Khanh        MiniportHandle,
4674c37757eSNguyen Trung Khanh        0 /* SlotNumber, reserved */,
4684c37757eSNguyen Trung Khanh        0 /* Offset */,
4694c37757eSNguyen Trung Khanh        &pci_config,
4704c37757eSNguyen Trung Khanh        sizeof(pci_config));
4714c37757eSNguyen Trung Khanh     if (read != sizeof(pci_config)) {
4724c37757eSNguyen Trung Khanh        return FALSE;
4734c37757eSNguyen Trung Khanh     }
4744c37757eSNguyen Trung Khanh 
4754c37757eSNguyen Trung Khanh     for (i = 0; i < RList->Count; ++i)
4764c37757eSNguyen Trung Khanh     {
4774c37757eSNguyen Trung Khanh         ULONG type = RList->PartialDescriptors[i].Type;
4784c37757eSNguyen Trung Khanh         if (type == CmResourceTypePort)
4794c37757eSNguyen Trung Khanh         {
4804c37757eSNguyen Trung Khanh             PHYSICAL_ADDRESS Start = RList->PartialDescriptors[i].u.Port.Start;
4814c37757eSNguyen Trung Khanh             ULONG len = RList->PartialDescriptors[i].u.Port.Length;
4824c37757eSNguyen Trung Khanh             DPrintf(0, ("Found IO ports at %08lX(%d)", Start.LowPart, len));
4834c37757eSNguyen Trung Khanh             bar = virtio_get_bar_index(&pci_config, Start);
4844c37757eSNguyen Trung Khanh             if (bar < 0) {
4854c37757eSNguyen Trung Khanh                break;
4864c37757eSNguyen Trung Khanh             }
4874c37757eSNguyen Trung Khanh             pResources->PciBars[bar].BasePA = Start;
4884c37757eSNguyen Trung Khanh             pResources->PciBars[bar].uLength = len;
4894c37757eSNguyen Trung Khanh             pResources->PciBars[bar].bPortSpace = TRUE;
4904c37757eSNguyen Trung Khanh         }
4914c37757eSNguyen Trung Khanh         else if (type == CmResourceTypeMemory)
4924c37757eSNguyen Trung Khanh         {
4934c37757eSNguyen Trung Khanh             PHYSICAL_ADDRESS Start = RList->PartialDescriptors[i].u.Memory.Start;
4944c37757eSNguyen Trung Khanh             ULONG len = RList->PartialDescriptors[i].u.Memory.Length;
4954c37757eSNguyen Trung Khanh             DPrintf(0, ("Found IO memory at %08I64X(%d)", Start.QuadPart, len));
4964c37757eSNguyen Trung Khanh             bar = virtio_get_bar_index(&pci_config, Start);
4974c37757eSNguyen Trung Khanh             if (bar < 0) {
4984c37757eSNguyen Trung Khanh                break;
4994c37757eSNguyen Trung Khanh             }
5004c37757eSNguyen Trung Khanh             pResources->PciBars[bar].BasePA = Start;
5014c37757eSNguyen Trung Khanh             pResources->PciBars[bar].uLength = len;
5024c37757eSNguyen Trung Khanh             pResources->PciBars[bar].bPortSpace = FALSE;
5034c37757eSNguyen Trung Khanh         }
5044c37757eSNguyen Trung Khanh         else if (type == CmResourceTypeInterrupt)
5054c37757eSNguyen Trung Khanh         {
5064c37757eSNguyen Trung Khanh             pResources->Vector = RList->PartialDescriptors[i].u.Interrupt.Vector;
5074c37757eSNguyen Trung Khanh             pResources->Level = RList->PartialDescriptors[i].u.Interrupt.Level;
5084c37757eSNguyen Trung Khanh             pResources->Affinity = RList->PartialDescriptors[i].u.Interrupt.Affinity;
5094c37757eSNguyen Trung Khanh             pResources->InterruptFlags = RList->PartialDescriptors[i].Flags;
5104c37757eSNguyen Trung Khanh             DPrintf(0, ("Found Interrupt vector %d, level %d, affinity %X, flags %X",
5114c37757eSNguyen Trung Khanh                 pResources->Vector, pResources->Level, (ULONG)pResources->Affinity, pResources->InterruptFlags));
5124c37757eSNguyen Trung Khanh         }
5134c37757eSNguyen Trung Khanh     }
5144c37757eSNguyen Trung Khanh     return bar >= 0 && pResources->Vector;
5154c37757eSNguyen Trung Khanh }
5164c37757eSNguyen Trung Khanh 
DumpVirtIOFeatures(PARANDIS_ADAPTER * pContext)5174c37757eSNguyen Trung Khanh static void DumpVirtIOFeatures(PARANDIS_ADAPTER *pContext)
5184c37757eSNguyen Trung Khanh {
5194c37757eSNguyen Trung Khanh     const struct {  ULONG bitmask;  const PCHAR Name; } Features[] =
5204c37757eSNguyen Trung Khanh     {
5214c37757eSNguyen Trung Khanh 
5224c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_CSUM, "VIRTIO_NET_F_CSUM" },
5234c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_GUEST_CSUM, "VIRTIO_NET_F_GUEST_CSUM" },
5244c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_MAC, "VIRTIO_NET_F_MAC" },
5254c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_GSO, "VIRTIO_NET_F_GSO" },
5264c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_GUEST_TSO4, "VIRTIO_NET_F_GUEST_TSO4"},
5274c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_GUEST_TSO6, "VIRTIO_NET_F_GUEST_TSO6"},
5284c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_GUEST_ECN, "VIRTIO_NET_F_GUEST_ECN"},
5294c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_GUEST_UFO, "VIRTIO_NET_F_GUEST_UFO"},
5304c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_HOST_TSO4, "VIRTIO_NET_F_HOST_TSO4"},
5314c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_HOST_TSO6, "VIRTIO_NET_F_HOST_TSO6"},
5324c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_HOST_ECN, "VIRTIO_NET_F_HOST_ECN"},
5334c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_HOST_UFO, "VIRTIO_NET_F_HOST_UFO"},
5344c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_MRG_RXBUF, "VIRTIO_NET_F_MRG_RXBUF"},
5354c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_STATUS, "VIRTIO_NET_F_STATUS"},
5364c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_CTRL_VQ, "VIRTIO_NET_F_CTRL_VQ"},
5374c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_CTRL_RX, "VIRTIO_NET_F_CTRL_RX"},
5384c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_CTRL_VLAN, "VIRTIO_NET_F_CTRL_VLAN"},
5394c37757eSNguyen Trung Khanh         {VIRTIO_NET_F_CTRL_RX_EXTRA, "VIRTIO_NET_F_CTRL_RX_EXTRA"},
5404c37757eSNguyen Trung Khanh         {VIRTIO_RING_F_INDIRECT_DESC, "VIRTIO_RING_F_INDIRECT_DESC"},
5414c37757eSNguyen Trung Khanh         {VIRTIO_F_VERSION_1, "VIRTIO_F_VERSION_1" },
5424c37757eSNguyen Trung Khanh         {VIRTIO_F_ANY_LAYOUT, "VIRTIO_F_ANY_LAYOUT" },
5434c37757eSNguyen Trung Khanh     };
5444c37757eSNguyen Trung Khanh     UINT i;
5454c37757eSNguyen Trung Khanh     for (i = 0; i < sizeof(Features)/sizeof(Features[0]); ++i)
5464c37757eSNguyen Trung Khanh     {
5474c37757eSNguyen Trung Khanh         if (VirtIODeviceGetHostFeature(pContext, Features[i].bitmask))
5484c37757eSNguyen Trung Khanh         {
5494c37757eSNguyen Trung Khanh             DPrintf(0, ("VirtIO Host Feature %s", Features[i].Name));
5504c37757eSNguyen Trung Khanh         }
5514c37757eSNguyen Trung Khanh     }
5524c37757eSNguyen Trung Khanh }
5534c37757eSNguyen Trung Khanh 
5544c37757eSNguyen Trung Khanh /**********************************************************
5554c37757eSNguyen Trung Khanh     Only for test. Prints out if the interrupt line is ON
5564c37757eSNguyen Trung Khanh Parameters:
5574c37757eSNguyen Trung Khanh Return value:
5584c37757eSNguyen Trung Khanh ***********************************************************/
JustForCheckClearInterrupt(PARANDIS_ADAPTER * pContext,const char * Label)5594c37757eSNguyen Trung Khanh static void JustForCheckClearInterrupt(PARANDIS_ADAPTER *pContext, const char *Label)
5604c37757eSNguyen Trung Khanh {
5614c37757eSNguyen Trung Khanh     if (pContext->bEnableInterruptChecking)
5624c37757eSNguyen Trung Khanh     {
5634c37757eSNguyen Trung Khanh         ULONG ulActive;
5644c37757eSNguyen Trung Khanh         ulActive = virtio_read_isr_status(&pContext->IODevice);
5654c37757eSNguyen Trung Khanh         if (ulActive)
5664c37757eSNguyen Trung Khanh         {
5674c37757eSNguyen Trung Khanh             DPrintf(0,("WARNING: Interrupt Line %d(%s)!", ulActive, Label));
5684c37757eSNguyen Trung Khanh         }
5694c37757eSNguyen Trung Khanh     }
5704c37757eSNguyen Trung Khanh }
5714c37757eSNguyen Trung Khanh 
5724c37757eSNguyen Trung Khanh /**********************************************************
5734c37757eSNguyen Trung Khanh Prints out statistics
5744c37757eSNguyen Trung Khanh ***********************************************************/
PrintStatistics(PARANDIS_ADAPTER * pContext)5754c37757eSNguyen Trung Khanh static void PrintStatistics(PARANDIS_ADAPTER *pContext)
5764c37757eSNguyen Trung Khanh {
5774c37757eSNguyen Trung Khanh     ULONG64 totalTxFrames =
5784c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCOutBroadcastPkts +
5794c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCOutMulticastPkts +
5804c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCOutUcastPkts;
5814c37757eSNguyen Trung Khanh     ULONG64 totalRxFrames =
5824c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCInBroadcastPkts +
5834c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCInMulticastPkts +
5844c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCInUcastPkts;
5854c37757eSNguyen Trung Khanh 
5864c37757eSNguyen Trung Khanh     DPrintf(0, ("[Diag!%X] RX buffers at VIRTIO %d of %d",
5874c37757eSNguyen Trung Khanh         pContext->CurrentMacAddress[5],
5884c37757eSNguyen Trung Khanh         pContext->NetNofReceiveBuffers,
5894c37757eSNguyen Trung Khanh         pContext->NetMaxReceiveBuffers));
5904c37757eSNguyen Trung Khanh     DPrintf(0, ("[Diag!] TX desc available %d/%d, buf %d/min. %d",
5914c37757eSNguyen Trung Khanh         pContext->nofFreeTxDescriptors,
5924c37757eSNguyen Trung Khanh         pContext->maxFreeTxDescriptors,
5934c37757eSNguyen Trung Khanh         pContext->nofFreeHardwareBuffers,
5944c37757eSNguyen Trung Khanh         pContext->minFreeHardwareBuffers));
5954c37757eSNguyen Trung Khanh     pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers;
5964c37757eSNguyen Trung Khanh     if (pContext->NetTxPacketsToReturn)
5974c37757eSNguyen Trung Khanh     {
5984c37757eSNguyen Trung Khanh         DPrintf(0, ("[Diag!] TX packets to return %d", pContext->NetTxPacketsToReturn));
5994c37757eSNguyen Trung Khanh     }
6004c37757eSNguyen Trung Khanh     DPrintf(0, ("[Diag!] Bytes transmitted %I64u, received %I64u",
6014c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCOutOctets,
6024c37757eSNguyen Trung Khanh         pContext->Statistics.ifHCInOctets));
6034c37757eSNguyen Trung Khanh     DPrintf(0, ("[Diag!] Tx frames %I64u, CSO %d, LSO %d, indirect %d",
6044c37757eSNguyen Trung Khanh         totalTxFrames,
6054c37757eSNguyen Trung Khanh         pContext->extraStatistics.framesCSOffload,
6064c37757eSNguyen Trung Khanh         pContext->extraStatistics.framesLSO,
6074c37757eSNguyen Trung Khanh         pContext->extraStatistics.framesIndirect));
6084c37757eSNguyen Trung Khanh     DPrintf(0, ("[Diag!] Rx frames %I64u, Rx.Pri %d, RxHwCS.OK %d, FiltOut %d",
6094c37757eSNguyen Trung Khanh         totalRxFrames, pContext->extraStatistics.framesRxPriority,
6104c37757eSNguyen Trung Khanh         pContext->extraStatistics.framesRxCSHwOK, pContext->extraStatistics.framesFilteredOut));
6114c37757eSNguyen Trung Khanh     if (pContext->extraStatistics.framesRxCSHwMissedBad || pContext->extraStatistics.framesRxCSHwMissedGood)
6124c37757eSNguyen Trung Khanh     {
6134c37757eSNguyen Trung Khanh         DPrintf(0, ("[Diag!] RxHwCS mistakes: missed bad %d, missed good %d",
6144c37757eSNguyen Trung Khanh             pContext->extraStatistics.framesRxCSHwMissedBad, pContext->extraStatistics.framesRxCSHwMissedGood));
6154c37757eSNguyen Trung Khanh     }
6164c37757eSNguyen Trung Khanh }
6174c37757eSNguyen Trung Khanh 
NTStatusToNdisStatus(NTSTATUS nt_status)6184c37757eSNguyen Trung Khanh static NDIS_STATUS NTStatusToNdisStatus(NTSTATUS nt_status) {
6194c37757eSNguyen Trung Khanh     switch (nt_status) {
6204c37757eSNguyen Trung Khanh     case STATUS_SUCCESS:
6214c37757eSNguyen Trung Khanh         return NDIS_STATUS_SUCCESS;
6224c37757eSNguyen Trung Khanh     case STATUS_NOT_FOUND:
6234c37757eSNguyen Trung Khanh     case STATUS_DEVICE_NOT_CONNECTED:
6244c37757eSNguyen Trung Khanh         return NDIS_STATUS_ADAPTER_NOT_FOUND;
6254c37757eSNguyen Trung Khanh     case STATUS_INSUFFICIENT_RESOURCES:
6264c37757eSNguyen Trung Khanh         return NDIS_STATUS_RESOURCES;
6274c37757eSNguyen Trung Khanh     case STATUS_INVALID_PARAMETER:
6284c37757eSNguyen Trung Khanh         return NDIS_STATUS_INVALID_DEVICE_REQUEST;
6294c37757eSNguyen Trung Khanh     default:
6304c37757eSNguyen Trung Khanh         return NDIS_STATUS_FAILURE;
6314c37757eSNguyen Trung Khanh     }
6324c37757eSNguyen Trung Khanh }
6334c37757eSNguyen Trung Khanh 
FinalizeFeatures(PARANDIS_ADAPTER * pContext)6344c37757eSNguyen Trung Khanh static NDIS_STATUS FinalizeFeatures(PARANDIS_ADAPTER *pContext)
6354c37757eSNguyen Trung Khanh {
6364c37757eSNguyen Trung Khanh     NTSTATUS nt_status = virtio_set_features(&pContext->IODevice, pContext->ullGuestFeatures);
6374c37757eSNguyen Trung Khanh     if (!NT_SUCCESS(nt_status)) {
6384c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] virtio_set_features failed with %x\n", __FUNCTION__, nt_status));
6394c37757eSNguyen Trung Khanh     }
6404c37757eSNguyen Trung Khanh     return NTStatusToNdisStatus(nt_status);
6414c37757eSNguyen Trung Khanh }
6424c37757eSNguyen Trung Khanh 
6434c37757eSNguyen Trung Khanh /**********************************************************
6444c37757eSNguyen Trung Khanh Initializes the context structure
6454c37757eSNguyen Trung Khanh Major variables, received from NDIS on initialization, must be be set before this call
6464c37757eSNguyen Trung Khanh (for ex. pContext->MiniportHandle)
6474c37757eSNguyen Trung Khanh 
6484c37757eSNguyen Trung Khanh If this procedure fails, no need to call
6494c37757eSNguyen Trung Khanh     ParaNdis_CleanupContext
6504c37757eSNguyen Trung Khanh 
6514c37757eSNguyen Trung Khanh 
6524c37757eSNguyen Trung Khanh Parameters:
6534c37757eSNguyen Trung Khanh Return value:
6544c37757eSNguyen Trung Khanh     SUCCESS, if resources are OK
6554c37757eSNguyen Trung Khanh     NDIS_STATUS_RESOURCE_CONFLICT if not
6564c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_InitializeContext(PARANDIS_ADAPTER * pContext,PNDIS_RESOURCE_LIST pResourceList)6574c37757eSNguyen Trung Khanh NDIS_STATUS ParaNdis_InitializeContext(
6584c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
6594c37757eSNguyen Trung Khanh     PNDIS_RESOURCE_LIST pResourceList)
6604c37757eSNguyen Trung Khanh {
6614c37757eSNguyen Trung Khanh     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
6624c37757eSNguyen Trung Khanh     PUCHAR pNewMacAddress = NULL;
6634c37757eSNguyen Trung Khanh     USHORT linkStatus = 0;
6644c37757eSNguyen Trung Khanh     NTSTATUS nt_status;
6654c37757eSNguyen Trung Khanh 
6664c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0);
6674c37757eSNguyen Trung Khanh     /* read first PCI IO bar*/
6684c37757eSNguyen Trung Khanh     //ulIOAddress = ReadPCIConfiguration(miniportAdapterHandle, 0x10);
6694c37757eSNguyen Trung Khanh     /* check this is IO and assigned */
6704c37757eSNguyen Trung Khanh     ReadNicConfiguration(pContext, &pNewMacAddress);
6714c37757eSNguyen Trung Khanh     if (pNewMacAddress)
6724c37757eSNguyen Trung Khanh     {
6734c37757eSNguyen Trung Khanh         if (ParaNdis_ValidateMacAddress(pNewMacAddress, TRUE))
6744c37757eSNguyen Trung Khanh         {
6754c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] WARNING: MAC address reloaded", __FUNCTION__));
6764c37757eSNguyen Trung Khanh             NdisMoveMemory(pContext->CurrentMacAddress, pNewMacAddress, sizeof(pContext->CurrentMacAddress));
6774c37757eSNguyen Trung Khanh         }
6784c37757eSNguyen Trung Khanh         else
6794c37757eSNguyen Trung Khanh         {
6804c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] WARNING: Invalid MAC address ignored", __FUNCTION__));
6814c37757eSNguyen Trung Khanh         }
6824c37757eSNguyen Trung Khanh         NdisFreeMemory(pNewMacAddress, 0, 0);
6834c37757eSNguyen Trung Khanh     }
6844c37757eSNguyen Trung Khanh 
6854c37757eSNguyen Trung Khanh     pContext->MaxPacketSize.nMaxFullSizeOS = pContext->MaxPacketSize.nMaxDataSize + ETH_HEADER_SIZE;
6864c37757eSNguyen Trung Khanh     pContext->MaxPacketSize.nMaxFullSizeHwTx = pContext->MaxPacketSize.nMaxFullSizeOS;
6874c37757eSNguyen Trung Khanh     pContext->MaxPacketSize.nMaxFullSizeHwRx = pContext->MaxPacketSize.nMaxFullSizeOS + ETH_PRIORITY_HEADER_SIZE;
6884c37757eSNguyen Trung Khanh     if (pContext->ulPriorityVlanSetting)
6894c37757eSNguyen Trung Khanh         pContext->MaxPacketSize.nMaxFullSizeHwTx = pContext->MaxPacketSize.nMaxFullSizeHwRx;
6904c37757eSNguyen Trung Khanh 
6914c37757eSNguyen Trung Khanh     if (GetAdapterResources(pContext->MiniportHandle, pResourceList, &pContext->AdapterResources))
6924c37757eSNguyen Trung Khanh     {
6934c37757eSNguyen Trung Khanh         if (pContext->AdapterResources.InterruptFlags & CM_RESOURCE_INTERRUPT_MESSAGE)
6944c37757eSNguyen Trung Khanh         {
6954c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Message interrupt assigned", __FUNCTION__));
6964c37757eSNguyen Trung Khanh             pContext->bUsingMSIX = TRUE;
6974c37757eSNguyen Trung Khanh         }
6984c37757eSNguyen Trung Khanh 
6994c37757eSNguyen Trung Khanh         nt_status = virtio_device_initialize(
7004c37757eSNguyen Trung Khanh             &pContext->IODevice,
7014c37757eSNguyen Trung Khanh             &ParaNdisSystemOps,
7024c37757eSNguyen Trung Khanh             pContext,
7034c37757eSNguyen Trung Khanh             pContext->bUsingMSIX);
7044c37757eSNguyen Trung Khanh         if (!NT_SUCCESS(nt_status)) {
7054c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] virtio_device_initialize failed with %x\n", __FUNCTION__, nt_status));
7064c37757eSNguyen Trung Khanh             status = NTStatusToNdisStatus(nt_status);
7074c37757eSNguyen Trung Khanh             DEBUG_EXIT_STATUS(0, status);
7084c37757eSNguyen Trung Khanh             return status;
7094c37757eSNguyen Trung Khanh         }
7104c37757eSNguyen Trung Khanh 
7114c37757eSNguyen Trung Khanh         pContext->bIODeviceInitialized = TRUE;
7124c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "init 0");
7134c37757eSNguyen Trung Khanh         ParaNdis_ResetVirtIONetDevice(pContext);
7144c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "init 1");
7154c37757eSNguyen Trung Khanh         virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE);
7164c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "init 2");
7174c37757eSNguyen Trung Khanh         virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_DRIVER);
7184c37757eSNguyen Trung Khanh         pContext->ullHostFeatures = virtio_get_features(&pContext->IODevice);
7194c37757eSNguyen Trung Khanh         DumpVirtIOFeatures(pContext);
7204c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "init 3");
7214c37757eSNguyen Trung Khanh         pContext->bLinkDetectSupported = 0 != VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_STATUS);
7224c37757eSNguyen Trung Khanh 
7234c37757eSNguyen Trung Khanh         if(pContext->bLinkDetectSupported) {
7244c37757eSNguyen Trung Khanh             virtio_get_config(&pContext->IODevice, sizeof(pContext->CurrentMacAddress), &linkStatus, sizeof(linkStatus));
7254c37757eSNguyen Trung Khanh             pContext->bConnected = (linkStatus & VIRTIO_NET_S_LINK_UP) != 0;
7264c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Link status on driver startup: %d", __FUNCTION__, pContext->bConnected));
7274c37757eSNguyen Trung Khanh         }
7284c37757eSNguyen Trung Khanh 
7294c37757eSNguyen Trung Khanh         if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_VERSION_1))
7304c37757eSNguyen Trung Khanh         {
7314c37757eSNguyen Trung Khanh             // virtio 1.0 always uses the extended header
7324c37757eSNguyen Trung Khanh             pContext->nVirtioHeaderSize = sizeof(virtio_net_hdr_ext);
7334c37757eSNguyen Trung Khanh             VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_VERSION_1);
7344c37757eSNguyen Trung Khanh         }
7354c37757eSNguyen Trung Khanh         else
7364c37757eSNguyen Trung Khanh         {
7374c37757eSNguyen Trung Khanh             pContext->nVirtioHeaderSize = sizeof(virtio_net_hdr_basic);
7384c37757eSNguyen Trung Khanh         }
7394c37757eSNguyen Trung Khanh 
7404c37757eSNguyen Trung Khanh         if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_ANY_LAYOUT))
7414c37757eSNguyen Trung Khanh         {
7424c37757eSNguyen Trung Khanh             VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_ANY_LAYOUT);
7434c37757eSNguyen Trung Khanh         }
7444c37757eSNguyen Trung Khanh         if (VirtIODeviceGetHostFeature(pContext, VIRTIO_RING_F_EVENT_IDX))
7454c37757eSNguyen Trung Khanh         {
7464c37757eSNguyen Trung Khanh             VirtIODeviceEnableGuestFeature(pContext, VIRTIO_RING_F_EVENT_IDX);
7474c37757eSNguyen Trung Khanh         }
7484c37757eSNguyen Trung Khanh 
7494c37757eSNguyen Trung Khanh         if (!pContext->bUseMergedBuffers && VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_MRG_RXBUF))
7504c37757eSNguyen Trung Khanh         {
7514c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Not using mergeable buffers", __FUNCTION__));
7524c37757eSNguyen Trung Khanh         }
7534c37757eSNguyen Trung Khanh         else
7544c37757eSNguyen Trung Khanh         {
7554c37757eSNguyen Trung Khanh             pContext->bUseMergedBuffers = VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_MRG_RXBUF) != 0;
7564c37757eSNguyen Trung Khanh             if (pContext->bUseMergedBuffers)
7574c37757eSNguyen Trung Khanh             {
7584c37757eSNguyen Trung Khanh                 pContext->nVirtioHeaderSize = sizeof(virtio_net_hdr_ext);
7594c37757eSNguyen Trung Khanh                 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_MRG_RXBUF);
7604c37757eSNguyen Trung Khanh             }
7614c37757eSNguyen Trung Khanh         }
7624c37757eSNguyen Trung Khanh         if (VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_MAC))
7634c37757eSNguyen Trung Khanh         {
7644c37757eSNguyen Trung Khanh             virtio_get_config(
7654c37757eSNguyen Trung Khanh                 &pContext->IODevice,
7664c37757eSNguyen Trung Khanh                 0, // + offsetof(struct virtio_net_config, mac)
7674c37757eSNguyen Trung Khanh                 &pContext->PermanentMacAddress,
7684c37757eSNguyen Trung Khanh                 ETH_LENGTH_OF_ADDRESS);
7694c37757eSNguyen Trung Khanh             if (!ParaNdis_ValidateMacAddress(pContext->PermanentMacAddress, FALSE))
7704c37757eSNguyen Trung Khanh             {
7714c37757eSNguyen Trung Khanh                 DPrintf(0,("Invalid device MAC ignored(%02x-%02x-%02x-%02x-%02x-%02x)",
7724c37757eSNguyen Trung Khanh                     pContext->PermanentMacAddress[0],
7734c37757eSNguyen Trung Khanh                     pContext->PermanentMacAddress[1],
7744c37757eSNguyen Trung Khanh                     pContext->PermanentMacAddress[2],
7754c37757eSNguyen Trung Khanh                     pContext->PermanentMacAddress[3],
7764c37757eSNguyen Trung Khanh                     pContext->PermanentMacAddress[4],
7774c37757eSNguyen Trung Khanh                     pContext->PermanentMacAddress[5]));
7784c37757eSNguyen Trung Khanh                 NdisZeroMemory(pContext->PermanentMacAddress, sizeof(pContext->PermanentMacAddress));
7794c37757eSNguyen Trung Khanh             }
7804c37757eSNguyen Trung Khanh         }
7814c37757eSNguyen Trung Khanh 
7824c37757eSNguyen Trung Khanh         if (ETH_IS_EMPTY(pContext->PermanentMacAddress))
7834c37757eSNguyen Trung Khanh         {
7844c37757eSNguyen Trung Khanh             DPrintf(0, ("No device MAC present, use default"));
7854c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[0] = 0x02;
7864c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[1] = 0x50;
7874c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[2] = 0xF2;
7884c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[3] = 0x00;
7894c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[4] = 0x01;
7904c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[5] = 0x80 | (UCHAR)(pContext->ulUniqueID & 0xFF);
7914c37757eSNguyen Trung Khanh         }
7924c37757eSNguyen Trung Khanh         DPrintf(0,("Device MAC = %02x-%02x-%02x-%02x-%02x-%02x",
7934c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[0],
7944c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[1],
7954c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[2],
7964c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[3],
7974c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[4],
7984c37757eSNguyen Trung Khanh             pContext->PermanentMacAddress[5]));
7994c37757eSNguyen Trung Khanh 
8004c37757eSNguyen Trung Khanh         if (ETH_IS_EMPTY(pContext->CurrentMacAddress))
8014c37757eSNguyen Trung Khanh         {
8024c37757eSNguyen Trung Khanh             NdisMoveMemory(
8034c37757eSNguyen Trung Khanh                 &pContext->CurrentMacAddress,
8044c37757eSNguyen Trung Khanh                 &pContext->PermanentMacAddress,
8054c37757eSNguyen Trung Khanh                 ETH_LENGTH_OF_ADDRESS);
8064c37757eSNguyen Trung Khanh         }
8074c37757eSNguyen Trung Khanh         else
8084c37757eSNguyen Trung Khanh         {
8094c37757eSNguyen Trung Khanh             DPrintf(0,("Current MAC = %02x-%02x-%02x-%02x-%02x-%02x",
8104c37757eSNguyen Trung Khanh                 pContext->CurrentMacAddress[0],
8114c37757eSNguyen Trung Khanh                 pContext->CurrentMacAddress[1],
8124c37757eSNguyen Trung Khanh                 pContext->CurrentMacAddress[2],
8134c37757eSNguyen Trung Khanh                 pContext->CurrentMacAddress[3],
8144c37757eSNguyen Trung Khanh                 pContext->CurrentMacAddress[4],
8154c37757eSNguyen Trung Khanh                 pContext->CurrentMacAddress[5]));
8164c37757eSNguyen Trung Khanh         }
8174c37757eSNguyen Trung Khanh         if (VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_CTRL_VQ)) {
8184c37757eSNguyen Trung Khanh             pContext->bHasControlQueue = TRUE;
8194c37757eSNguyen Trung Khanh             VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_CTRL_VQ);
8204c37757eSNguyen Trung Khanh         }
8214c37757eSNguyen Trung Khanh     }
8224c37757eSNguyen Trung Khanh     else
8234c37757eSNguyen Trung Khanh     {
8244c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] Error: Incomplete resources", __FUNCTION__));
8254c37757eSNguyen Trung Khanh         status = NDIS_STATUS_RESOURCE_CONFLICT;
8264c37757eSNguyen Trung Khanh     }
8274c37757eSNguyen Trung Khanh 
8284c37757eSNguyen Trung Khanh 
8294c37757eSNguyen Trung Khanh     if (pContext->bDoHardwareChecksum)
8304c37757eSNguyen Trung Khanh     {
8314c37757eSNguyen Trung Khanh         ULONG dependentOptions;
8324c37757eSNguyen Trung Khanh         dependentOptions = osbT4TcpChecksum | osbT4UdpChecksum | osbT4TcpOptionsChecksum;
8334c37757eSNguyen Trung Khanh         if (!VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_CSUM) &&
8344c37757eSNguyen Trung Khanh             (pContext->Offload.flagsValue & dependentOptions))
8354c37757eSNguyen Trung Khanh         {
8364c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Host does not support CSUM, disabling CS offload", __FUNCTION__) );
8374c37757eSNguyen Trung Khanh             pContext->Offload.flagsValue &= ~dependentOptions;
8384c37757eSNguyen Trung Khanh         }
8394c37757eSNguyen Trung Khanh     }
8404c37757eSNguyen Trung Khanh 
8414c37757eSNguyen Trung Khanh     if (pContext->bDoGuestChecksumOnReceive && VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_GUEST_CSUM))
8424c37757eSNguyen Trung Khanh     {
8434c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] Enabling guest checksum", __FUNCTION__) );
8444c37757eSNguyen Trung Khanh         VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_GUEST_CSUM);
8454c37757eSNguyen Trung Khanh     }
8464c37757eSNguyen Trung Khanh     else
8474c37757eSNguyen Trung Khanh     {
8484c37757eSNguyen Trung Khanh         pContext->bDoGuestChecksumOnReceive = FALSE;
8494c37757eSNguyen Trung Khanh     }
8504c37757eSNguyen Trung Khanh 
8514c37757eSNguyen Trung Khanh     // now, after we checked the capabilities, we can initialize current
8524c37757eSNguyen Trung Khanh     // configuration of offload tasks
8534c37757eSNguyen Trung Khanh     ParaNdis_ResetOffloadSettings(pContext, NULL, NULL);
8544c37757eSNguyen Trung Khanh     if (pContext->Offload.flags.fTxLso && !pContext->bUseScatterGather)
8554c37757eSNguyen Trung Khanh     {
8564c37757eSNguyen Trung Khanh         DisableBothLSOPermanently(pContext, __FUNCTION__, "SG is not active");
8574c37757eSNguyen Trung Khanh     }
8584c37757eSNguyen Trung Khanh     if (pContext->Offload.flags.fTxLso &&
8594c37757eSNguyen Trung Khanh         !VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_HOST_TSO4))
8604c37757eSNguyen Trung Khanh     {
8614c37757eSNguyen Trung Khanh         DisableLSOv4Permanently(pContext, __FUNCTION__, "Host does not support TSOv4");
8624c37757eSNguyen Trung Khanh     }
8634c37757eSNguyen Trung Khanh     if (pContext->Offload.flags.fTxLsov6 &&
8644c37757eSNguyen Trung Khanh         !VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_HOST_TSO6))
8654c37757eSNguyen Trung Khanh     {
8664c37757eSNguyen Trung Khanh         DisableLSOv6Permanently(pContext, __FUNCTION__, "Host does not support TSOv6");
8674c37757eSNguyen Trung Khanh     }
8684c37757eSNguyen Trung Khanh     if (pContext->bUseIndirect)
8694c37757eSNguyen Trung Khanh     {
8704c37757eSNguyen Trung Khanh         const char *reason = "";
8714c37757eSNguyen Trung Khanh         if (!VirtIODeviceGetHostFeature(pContext, VIRTIO_RING_F_INDIRECT_DESC))
8724c37757eSNguyen Trung Khanh         {
8734c37757eSNguyen Trung Khanh             pContext->bUseIndirect = FALSE;
8744c37757eSNguyen Trung Khanh             reason = "Host support";
8754c37757eSNguyen Trung Khanh         }
8764c37757eSNguyen Trung Khanh         else if (!pContext->bUseScatterGather)
8774c37757eSNguyen Trung Khanh         {
8784c37757eSNguyen Trung Khanh             pContext->bUseIndirect = FALSE;
8794c37757eSNguyen Trung Khanh             reason = "SG";
8804c37757eSNguyen Trung Khanh         }
8814c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] %sable indirect Tx(!%s)", __FUNCTION__, pContext->bUseIndirect ? "En" : "Dis", reason) );
8824c37757eSNguyen Trung Khanh     }
8834c37757eSNguyen Trung Khanh 
8844c37757eSNguyen Trung Khanh     if (VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_CTRL_RX_EXTRA) &&
8854c37757eSNguyen Trung Khanh         pContext->bDoHwPacketFiltering)
8864c37757eSNguyen Trung Khanh     {
8874c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] Using hardware packet filtering", __FUNCTION__));
8884c37757eSNguyen Trung Khanh         pContext->bHasHardwareFilters = TRUE;
8894c37757eSNguyen Trung Khanh     }
8904c37757eSNguyen Trung Khanh 
8914c37757eSNguyen Trung Khanh     status = FinalizeFeatures(pContext);
8924c37757eSNguyen Trung Khanh 
8934c37757eSNguyen Trung Khanh     pContext->ReuseBufferProc = (tReuseReceiveBufferProc)ReuseReceiveBufferRegular;
8944c37757eSNguyen Trung Khanh 
8954c37757eSNguyen Trung Khanh     NdisInitializeEvent(&pContext->ResetEvent);
8964c37757eSNguyen Trung Khanh     DEBUG_EXIT_STATUS(0, status);
8974c37757eSNguyen Trung Khanh     return status;
8984c37757eSNguyen Trung Khanh }
8994c37757eSNguyen Trung Khanh 
9004c37757eSNguyen Trung Khanh /**********************************************************
9014c37757eSNguyen Trung Khanh Free the resources allocated for VirtIO buffer descriptor
9024c37757eSNguyen Trung Khanh Parameters:
9034c37757eSNguyen Trung Khanh     PVOID pParam                pIONetDescriptor to free
9044c37757eSNguyen Trung Khanh     BOOLEAN bRemoveFromList     TRUE, if also remove it from list
9054c37757eSNguyen Trung Khanh ***********************************************************/
VirtIONetFreeBufferDescriptor(PARANDIS_ADAPTER * pContext,pIONetDescriptor pBufferDescriptor)9064c37757eSNguyen Trung Khanh static void VirtIONetFreeBufferDescriptor(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBufferDescriptor)
9074c37757eSNguyen Trung Khanh {
9084c37757eSNguyen Trung Khanh     if(pBufferDescriptor)
9094c37757eSNguyen Trung Khanh     {
9104c37757eSNguyen Trung Khanh         if (pBufferDescriptor->pHolder)
9114c37757eSNguyen Trung Khanh             ParaNdis_UnbindBufferFromPacket(pContext, pBufferDescriptor);
9124c37757eSNguyen Trung Khanh         if (pBufferDescriptor->DataInfo.Virtual)
9134c37757eSNguyen Trung Khanh             ParaNdis_FreePhysicalMemory(pContext, &pBufferDescriptor->DataInfo);
9144c37757eSNguyen Trung Khanh         if (pBufferDescriptor->HeaderInfo.Virtual)
9154c37757eSNguyen Trung Khanh             ParaNdis_FreePhysicalMemory(pContext, &pBufferDescriptor->HeaderInfo);
9164c37757eSNguyen Trung Khanh         NdisFreeMemory(pBufferDescriptor, 0, 0);
9174c37757eSNguyen Trung Khanh     }
9184c37757eSNguyen Trung Khanh }
9194c37757eSNguyen Trung Khanh 
9204c37757eSNguyen Trung Khanh /**********************************************************
9214c37757eSNguyen Trung Khanh Free all the buffer descriptors from specified list
9224c37757eSNguyen Trung Khanh Parameters:
9234c37757eSNguyen Trung Khanh     PLIST_ENTRY pListRoot           list containing pIONetDescriptor structures
9244c37757eSNguyen Trung Khanh     PNDIS_SPIN_LOCK pLock           lock to protest this list
9254c37757eSNguyen Trung Khanh Return value:
9264c37757eSNguyen Trung Khanh ***********************************************************/
FreeDescriptorsFromList(PARANDIS_ADAPTER * pContext,PLIST_ENTRY pListRoot,PNDIS_SPIN_LOCK pLock)9274c37757eSNguyen Trung Khanh static void FreeDescriptorsFromList(PARANDIS_ADAPTER *pContext, PLIST_ENTRY pListRoot, PNDIS_SPIN_LOCK pLock)
9284c37757eSNguyen Trung Khanh {
9294c37757eSNguyen Trung Khanh     pIONetDescriptor pBufferDescriptor;
9304c37757eSNguyen Trung Khanh     LIST_ENTRY TempList;
9314c37757eSNguyen Trung Khanh     InitializeListHead(&TempList);
9324c37757eSNguyen Trung Khanh     NdisAcquireSpinLock(pLock);
9334c37757eSNguyen Trung Khanh     while(!IsListEmpty(pListRoot))
9344c37757eSNguyen Trung Khanh     {
9354c37757eSNguyen Trung Khanh         pBufferDescriptor = (pIONetDescriptor)RemoveHeadList(pListRoot);
9364c37757eSNguyen Trung Khanh         InsertTailList(&TempList, &pBufferDescriptor->listEntry);
9374c37757eSNguyen Trung Khanh     }
9384c37757eSNguyen Trung Khanh     NdisReleaseSpinLock(pLock);
9394c37757eSNguyen Trung Khanh     while(!IsListEmpty(&TempList))
9404c37757eSNguyen Trung Khanh     {
9414c37757eSNguyen Trung Khanh         pBufferDescriptor = (pIONetDescriptor)RemoveHeadList(&TempList);
9424c37757eSNguyen Trung Khanh         VirtIONetFreeBufferDescriptor(pContext, pBufferDescriptor);
9434c37757eSNguyen Trung Khanh     }
9444c37757eSNguyen Trung Khanh }
9454c37757eSNguyen Trung Khanh 
AllocatePairOfBuffersOnInit(PARANDIS_ADAPTER * pContext,ULONG size1,ULONG size2,BOOLEAN bForTx)9464c37757eSNguyen Trung Khanh static pIONetDescriptor AllocatePairOfBuffersOnInit(
9474c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
9484c37757eSNguyen Trung Khanh     ULONG size1,
9494c37757eSNguyen Trung Khanh     ULONG size2,
9504c37757eSNguyen Trung Khanh     BOOLEAN bForTx)
9514c37757eSNguyen Trung Khanh {
9524c37757eSNguyen Trung Khanh     pIONetDescriptor p;
9534c37757eSNguyen Trung Khanh     p = (pIONetDescriptor)ParaNdis_AllocateMemory(pContext, sizeof(*p));
9544c37757eSNguyen Trung Khanh     if (p)
9554c37757eSNguyen Trung Khanh     {
9564c37757eSNguyen Trung Khanh         BOOLEAN b1 = FALSE, b2 = FALSE;
9574c37757eSNguyen Trung Khanh         NdisZeroMemory(p, sizeof(*p));
9584c37757eSNguyen Trung Khanh         p->HeaderInfo.size = size1;
9594c37757eSNguyen Trung Khanh         p->DataInfo.size   = size2;
9604c37757eSNguyen Trung Khanh         p->HeaderInfo.IsCached = p->DataInfo.IsCached = 1;
9614c37757eSNguyen Trung Khanh         p->HeaderInfo.IsTX = p->DataInfo.IsTX = bForTx;
9624c37757eSNguyen Trung Khanh         p->nofUsedBuffers = 0;
9634c37757eSNguyen Trung Khanh         b1 = ParaNdis_InitialAllocatePhysicalMemory(pContext, &p->HeaderInfo);
9644c37757eSNguyen Trung Khanh         if (b1) b2 = ParaNdis_InitialAllocatePhysicalMemory(pContext, &p->DataInfo);
9654c37757eSNguyen Trung Khanh         if (b1 && b2)
9664c37757eSNguyen Trung Khanh         {
9674c37757eSNguyen Trung Khanh             BOOLEAN b = bForTx || ParaNdis_BindBufferToPacket(pContext, p);
9684c37757eSNguyen Trung Khanh             if (!b)
9694c37757eSNguyen Trung Khanh             {
9704c37757eSNguyen Trung Khanh                 DPrintf(0, ("[INITPHYS](%s) Failed to bind memory to net packet", bForTx ? "TX" : "RX"));
9714c37757eSNguyen Trung Khanh                 VirtIONetFreeBufferDescriptor(pContext, p);
9724c37757eSNguyen Trung Khanh                 p = NULL;
9734c37757eSNguyen Trung Khanh             }
9744c37757eSNguyen Trung Khanh         }
9754c37757eSNguyen Trung Khanh         else
9764c37757eSNguyen Trung Khanh         {
9774c37757eSNguyen Trung Khanh             if (b1) ParaNdis_FreePhysicalMemory(pContext, &p->HeaderInfo);
9784c37757eSNguyen Trung Khanh             if (b2) ParaNdis_FreePhysicalMemory(pContext, &p->DataInfo);
9794c37757eSNguyen Trung Khanh             NdisFreeMemory(p, 0, 0);
9804c37757eSNguyen Trung Khanh             p = NULL;
9814c37757eSNguyen Trung Khanh             DPrintf(0, ("[INITPHYS](%s) Failed to allocate memory block", bForTx ? "TX" : "RX"));
9824c37757eSNguyen Trung Khanh         }
9834c37757eSNguyen Trung Khanh     }
9844c37757eSNguyen Trung Khanh     if (p)
9854c37757eSNguyen Trung Khanh     {
9864c37757eSNguyen Trung Khanh         DPrintf(3, ("[INITPHYS](%s) Header v%p(p%08lX), Data v%p(p%08lX)", bForTx ? "TX" : "RX",
9874c37757eSNguyen Trung Khanh             p->HeaderInfo.Virtual, p->HeaderInfo.Physical.LowPart,
9884c37757eSNguyen Trung Khanh             p->DataInfo.Virtual, p->DataInfo.Physical.LowPart));
9894c37757eSNguyen Trung Khanh     }
9904c37757eSNguyen Trung Khanh     return p;
9914c37757eSNguyen Trung Khanh }
9924c37757eSNguyen Trung Khanh 
9934c37757eSNguyen Trung Khanh /**********************************************************
9944c37757eSNguyen Trung Khanh Allocates TX buffers according to startup setting (pContext->maxFreeTxDescriptors as got from registry)
9954c37757eSNguyen Trung Khanh Buffers are chained in NetFreeSendBuffers
9964c37757eSNguyen Trung Khanh Parameters:
9974c37757eSNguyen Trung Khanh     context
9984c37757eSNguyen Trung Khanh ***********************************************************/
PrepareTransmitBuffers(PARANDIS_ADAPTER * pContext)9994c37757eSNguyen Trung Khanh static void PrepareTransmitBuffers(PARANDIS_ADAPTER *pContext)
10004c37757eSNguyen Trung Khanh {
10014c37757eSNguyen Trung Khanh     UINT nBuffers, nMaxBuffers;
10024c37757eSNguyen Trung Khanh     DEBUG_ENTRY(4);
10034c37757eSNguyen Trung Khanh     nMaxBuffers = virtio_get_queue_size(pContext->NetSendQueue) / 2;
10044c37757eSNguyen Trung Khanh     if (nMaxBuffers > pContext->maxFreeTxDescriptors) nMaxBuffers = pContext->maxFreeTxDescriptors;
10054c37757eSNguyen Trung Khanh 
10064c37757eSNguyen Trung Khanh     for (nBuffers = 0; nBuffers < nMaxBuffers; ++nBuffers)
10074c37757eSNguyen Trung Khanh     {
10084c37757eSNguyen Trung Khanh         pIONetDescriptor pBuffersDescriptor =
10094c37757eSNguyen Trung Khanh             AllocatePairOfBuffersOnInit(
10104c37757eSNguyen Trung Khanh                 pContext,
10114c37757eSNguyen Trung Khanh                 pContext->nVirtioHeaderSize,
10124c37757eSNguyen Trung Khanh                 pContext->MaxPacketSize.nMaxFullSizeHwTx,
10134c37757eSNguyen Trung Khanh                 TRUE);
10144c37757eSNguyen Trung Khanh         if (!pBuffersDescriptor) break;
10154c37757eSNguyen Trung Khanh 
10164c37757eSNguyen Trung Khanh         NdisZeroMemory(pBuffersDescriptor->HeaderInfo.Virtual, pBuffersDescriptor->HeaderInfo.size);
10174c37757eSNguyen Trung Khanh         InsertTailList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry);
10184c37757eSNguyen Trung Khanh         pContext->nofFreeTxDescriptors++;
10194c37757eSNguyen Trung Khanh     }
10204c37757eSNguyen Trung Khanh 
10214c37757eSNguyen Trung Khanh     pContext->maxFreeTxDescriptors = pContext->nofFreeTxDescriptors;
10224c37757eSNguyen Trung Khanh     pContext->nofFreeHardwareBuffers = pContext->nofFreeTxDescriptors * 2;
10234c37757eSNguyen Trung Khanh     pContext->maxFreeHardwareBuffers = pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers;
10244c37757eSNguyen Trung Khanh     DPrintf(0, ("[%s] available %d Tx descriptors, %d hw buffers",
10254c37757eSNguyen Trung Khanh         __FUNCTION__, pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers));
10264c37757eSNguyen Trung Khanh }
10274c37757eSNguyen Trung Khanh 
AddRxBufferToQueue(PARANDIS_ADAPTER * pContext,pIONetDescriptor pBufferDescriptor)10284c37757eSNguyen Trung Khanh static BOOLEAN AddRxBufferToQueue(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBufferDescriptor)
10294c37757eSNguyen Trung Khanh {
10304c37757eSNguyen Trung Khanh     UINT nBuffersToSubmit = 2;
10314c37757eSNguyen Trung Khanh     struct VirtIOBufferDescriptor sg[2];
10324c37757eSNguyen Trung Khanh     if (!pContext->bUseMergedBuffers)
10334c37757eSNguyen Trung Khanh     {
10344c37757eSNguyen Trung Khanh         sg[0].physAddr = pBufferDescriptor->HeaderInfo.Physical;
10354c37757eSNguyen Trung Khanh         sg[0].length = pBufferDescriptor->HeaderInfo.size;
10364c37757eSNguyen Trung Khanh         sg[1].physAddr = pBufferDescriptor->DataInfo.Physical;
10374c37757eSNguyen Trung Khanh         sg[1].length = pBufferDescriptor->DataInfo.size;
10384c37757eSNguyen Trung Khanh     }
10394c37757eSNguyen Trung Khanh     else
10404c37757eSNguyen Trung Khanh     {
10414c37757eSNguyen Trung Khanh         sg[0].physAddr = pBufferDescriptor->DataInfo.Physical;
10424c37757eSNguyen Trung Khanh         sg[0].length = pBufferDescriptor->DataInfo.size;
10434c37757eSNguyen Trung Khanh         nBuffersToSubmit = 1;
10444c37757eSNguyen Trung Khanh     }
10454c37757eSNguyen Trung Khanh     return 0 <= virtqueue_add_buf(
10464c37757eSNguyen Trung Khanh         pContext->NetReceiveQueue,
10474c37757eSNguyen Trung Khanh         sg,
10484c37757eSNguyen Trung Khanh         0,
10494c37757eSNguyen Trung Khanh         nBuffersToSubmit,
10504c37757eSNguyen Trung Khanh         pBufferDescriptor,
10514c37757eSNguyen Trung Khanh         NULL,
10524c37757eSNguyen Trung Khanh         0);
10534c37757eSNguyen Trung Khanh }
10544c37757eSNguyen Trung Khanh 
10554c37757eSNguyen Trung Khanh 
10564c37757eSNguyen Trung Khanh /**********************************************************
10574c37757eSNguyen Trung Khanh Allocates maximum RX buffers for incoming packets
10584c37757eSNguyen Trung Khanh Buffers are chained in NetReceiveBuffers
10594c37757eSNguyen Trung Khanh Parameters:
10604c37757eSNguyen Trung Khanh     context
10614c37757eSNguyen Trung Khanh ***********************************************************/
PrepareReceiveBuffers(PARANDIS_ADAPTER * pContext)10624c37757eSNguyen Trung Khanh static int PrepareReceiveBuffers(PARANDIS_ADAPTER *pContext)
10634c37757eSNguyen Trung Khanh {
10644c37757eSNguyen Trung Khanh     int nRet = 0;
10654c37757eSNguyen Trung Khanh     UINT i;
10664c37757eSNguyen Trung Khanh     DEBUG_ENTRY(4);
10674c37757eSNguyen Trung Khanh 
10684c37757eSNguyen Trung Khanh     for (i = 0; i < pContext->NetMaxReceiveBuffers; ++i)
10694c37757eSNguyen Trung Khanh     {
10704c37757eSNguyen Trung Khanh         ULONG size1 = pContext->bUseMergedBuffers ? 4 : pContext->nVirtioHeaderSize;
10714c37757eSNguyen Trung Khanh         ULONG size2 = pContext->MaxPacketSize.nMaxFullSizeHwRx +
10724c37757eSNguyen Trung Khanh             (pContext->bUseMergedBuffers ? pContext->nVirtioHeaderSize : 0);
10734c37757eSNguyen Trung Khanh         pIONetDescriptor pBuffersDescriptor =
10744c37757eSNguyen Trung Khanh             AllocatePairOfBuffersOnInit(pContext, size1, size2, FALSE);
10754c37757eSNguyen Trung Khanh         if (!pBuffersDescriptor) break;
10764c37757eSNguyen Trung Khanh 
10774c37757eSNguyen Trung Khanh         if (!AddRxBufferToQueue(pContext, pBuffersDescriptor))
10784c37757eSNguyen Trung Khanh         {
10794c37757eSNguyen Trung Khanh             VirtIONetFreeBufferDescriptor(pContext, pBuffersDescriptor);
10804c37757eSNguyen Trung Khanh             break;
10814c37757eSNguyen Trung Khanh         }
10824c37757eSNguyen Trung Khanh 
10834c37757eSNguyen Trung Khanh         InsertTailList(&pContext->NetReceiveBuffers, &pBuffersDescriptor->listEntry);
10844c37757eSNguyen Trung Khanh 
10854c37757eSNguyen Trung Khanh         pContext->NetNofReceiveBuffers++;
10864c37757eSNguyen Trung Khanh     }
10874c37757eSNguyen Trung Khanh 
10884c37757eSNguyen Trung Khanh     pContext->NetMaxReceiveBuffers = pContext->NetNofReceiveBuffers;
10894c37757eSNguyen Trung Khanh     DPrintf(0, ("[%s] MaxReceiveBuffers %d\n", __FUNCTION__, pContext->NetMaxReceiveBuffers) );
10904c37757eSNguyen Trung Khanh 
10914c37757eSNguyen Trung Khanh     virtqueue_kick(pContext->NetReceiveQueue);
10924c37757eSNguyen Trung Khanh 
10934c37757eSNguyen Trung Khanh     return nRet;
10944c37757eSNguyen Trung Khanh }
10954c37757eSNguyen Trung Khanh 
FindNetQueues(PARANDIS_ADAPTER * pContext)10964c37757eSNguyen Trung Khanh static NDIS_STATUS FindNetQueues(PARANDIS_ADAPTER *pContext)
10974c37757eSNguyen Trung Khanh {
10984c37757eSNguyen Trung Khanh     struct virtqueue *queues[3];
10994c37757eSNguyen Trung Khanh     unsigned nvqs = pContext->bHasControlQueue ? 3 : 2;
11004c37757eSNguyen Trung Khanh     NTSTATUS status;
11014c37757eSNguyen Trung Khanh 
11024c37757eSNguyen Trung Khanh     // We work with two or three virtqueues, 0 - receive, 1 - send, 2 - control
11034c37757eSNguyen Trung Khanh     status = virtio_find_queues(
11044c37757eSNguyen Trung Khanh        &pContext->IODevice,
11054c37757eSNguyen Trung Khanh        nvqs,
11064c37757eSNguyen Trung Khanh        queues);
11074c37757eSNguyen Trung Khanh     if (!NT_SUCCESS(status)) {
11084c37757eSNguyen Trung Khanh        DPrintf(0, ("[%s] virtio_find_queues failed with %x\n", __FUNCTION__, status));
11094c37757eSNguyen Trung Khanh        return NTStatusToNdisStatus(status);
11104c37757eSNguyen Trung Khanh     }
11114c37757eSNguyen Trung Khanh 
11124c37757eSNguyen Trung Khanh     pContext->NetReceiveQueue = queues[0];
11134c37757eSNguyen Trung Khanh     pContext->NetSendQueue = queues[1];
11144c37757eSNguyen Trung Khanh     if (pContext->bHasControlQueue) {
11154c37757eSNguyen Trung Khanh        pContext->NetControlQueue = queues[2];
11164c37757eSNguyen Trung Khanh     }
11174c37757eSNguyen Trung Khanh 
11184c37757eSNguyen Trung Khanh     return NDIS_STATUS_SUCCESS;
11194c37757eSNguyen Trung Khanh }
11204c37757eSNguyen Trung Khanh 
11214c37757eSNguyen Trung Khanh // called on PASSIVE upon unsuccessful Init or upon Halt
DeleteNetQueues(PARANDIS_ADAPTER * pContext)11224c37757eSNguyen Trung Khanh static void DeleteNetQueues(PARANDIS_ADAPTER *pContext)
11234c37757eSNguyen Trung Khanh {
11244c37757eSNguyen Trung Khanh     virtio_delete_queues(&pContext->IODevice);
11254c37757eSNguyen Trung Khanh }
11264c37757eSNguyen Trung Khanh 
11274c37757eSNguyen Trung Khanh /**********************************************************
11284c37757eSNguyen Trung Khanh Initializes VirtIO buffering and related stuff:
11294c37757eSNguyen Trung Khanh Allocates RX and TX queues and buffers
11304c37757eSNguyen Trung Khanh Parameters:
11314c37757eSNguyen Trung Khanh     context
11324c37757eSNguyen Trung Khanh Return value:
11334c37757eSNguyen Trung Khanh     TRUE if both queues are allocated
11344c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_VirtIONetInit(PARANDIS_ADAPTER * pContext)11354c37757eSNguyen Trung Khanh static NDIS_STATUS ParaNdis_VirtIONetInit(PARANDIS_ADAPTER *pContext)
11364c37757eSNguyen Trung Khanh {
11374c37757eSNguyen Trung Khanh     NDIS_STATUS status;
11384c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0);
11394c37757eSNguyen Trung Khanh 
11404c37757eSNguyen Trung Khanh     pContext->ControlData.IsCached = 1;
11414c37757eSNguyen Trung Khanh     pContext->ControlData.size = 512;
11424c37757eSNguyen Trung Khanh 
11434c37757eSNguyen Trung Khanh     status = FindNetQueues(pContext);
11444c37757eSNguyen Trung Khanh     if (status != NDIS_STATUS_SUCCESS) {
11454c37757eSNguyen Trung Khanh         return status;
11464c37757eSNguyen Trung Khanh     }
11474c37757eSNguyen Trung Khanh 
11484c37757eSNguyen Trung Khanh     if (pContext->NetReceiveQueue && pContext->NetSendQueue)
11494c37757eSNguyen Trung Khanh     {
11504c37757eSNguyen Trung Khanh         PrepareTransmitBuffers(pContext);
11514c37757eSNguyen Trung Khanh         PrepareReceiveBuffers(pContext);
11524c37757eSNguyen Trung Khanh 
11534c37757eSNguyen Trung Khanh         if (pContext->NetControlQueue)
11544c37757eSNguyen Trung Khanh             ParaNdis_InitialAllocatePhysicalMemory(pContext, &pContext->ControlData);
11554c37757eSNguyen Trung Khanh         if (!pContext->NetControlQueue || !pContext->ControlData.Virtual)
11564c37757eSNguyen Trung Khanh         {
11574c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] The Control vQueue does not work!\n", __FUNCTION__) );
11584c37757eSNguyen Trung Khanh             pContext->bHasHardwareFilters = FALSE;
11594c37757eSNguyen Trung Khanh         }
11604c37757eSNguyen Trung Khanh         if (pContext->nofFreeTxDescriptors &&
11614c37757eSNguyen Trung Khanh             pContext->NetMaxReceiveBuffers &&
11624c37757eSNguyen Trung Khanh             pContext->maxFreeHardwareBuffers)
11634c37757eSNguyen Trung Khanh         {
11644c37757eSNguyen Trung Khanh             pContext->sgTxGatherTable = ParaNdis_AllocateMemory(pContext,
11654c37757eSNguyen Trung Khanh                 pContext->maxFreeHardwareBuffers * sizeof(pContext->sgTxGatherTable[0]));
11664c37757eSNguyen Trung Khanh             if (!pContext->sgTxGatherTable)
11674c37757eSNguyen Trung Khanh             {
11684c37757eSNguyen Trung Khanh                 DisableBothLSOPermanently(pContext, __FUNCTION__, "Can not allocate SG table");
11694c37757eSNguyen Trung Khanh             }
11704c37757eSNguyen Trung Khanh             status = NDIS_STATUS_SUCCESS;
11714c37757eSNguyen Trung Khanh         }
11724c37757eSNguyen Trung Khanh     }
11734c37757eSNguyen Trung Khanh     else
11744c37757eSNguyen Trung Khanh     {
11754c37757eSNguyen Trung Khanh         DeleteNetQueues(pContext);
11764c37757eSNguyen Trung Khanh         status = NDIS_STATUS_RESOURCES;
11774c37757eSNguyen Trung Khanh     }
11784c37757eSNguyen Trung Khanh     return status;
11794c37757eSNguyen Trung Khanh }
11804c37757eSNguyen Trung Khanh 
VirtIODeviceRemoveStatus(VirtIODevice * vdev,u8 status)11814c37757eSNguyen Trung Khanh static void VirtIODeviceRemoveStatus(VirtIODevice *vdev, u8 status)
11824c37757eSNguyen Trung Khanh {
11834c37757eSNguyen Trung Khanh     virtio_set_status(
11844c37757eSNguyen Trung Khanh         vdev,
11854c37757eSNguyen Trung Khanh         virtio_get_status(vdev) & ~status);
11864c37757eSNguyen Trung Khanh }
11874c37757eSNguyen Trung Khanh 
11884c37757eSNguyen Trung Khanh /**********************************************************
11894c37757eSNguyen Trung Khanh Finishes initialization of context structure, calling also version dependent part
11904c37757eSNguyen Trung Khanh If this procedure failed, ParaNdis_CleanupContext must be called
11914c37757eSNguyen Trung Khanh Parameters:
11924c37757eSNguyen Trung Khanh     context
11934c37757eSNguyen Trung Khanh Return value:
11944c37757eSNguyen Trung Khanh     SUCCESS or some kind of failure
11954c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_FinishInitialization(PARANDIS_ADAPTER * pContext)11964c37757eSNguyen Trung Khanh NDIS_STATUS ParaNdis_FinishInitialization(PARANDIS_ADAPTER *pContext)
11974c37757eSNguyen Trung Khanh {
11984c37757eSNguyen Trung Khanh     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
11994c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0);
12004c37757eSNguyen Trung Khanh 
12014c37757eSNguyen Trung Khanh     NdisAllocateSpinLock(&pContext->SendLock);
12024c37757eSNguyen Trung Khanh #if !defined(UNIFY_LOCKS)
12034c37757eSNguyen Trung Khanh     NdisAllocateSpinLock(&pContext->ReceiveLock);
12044c37757eSNguyen Trung Khanh #endif
12054c37757eSNguyen Trung Khanh 
12064c37757eSNguyen Trung Khanh     InitializeListHead(&pContext->NetReceiveBuffers);
12074c37757eSNguyen Trung Khanh     InitializeListHead(&pContext->NetReceiveBuffersWaiting);
12084c37757eSNguyen Trung Khanh     InitializeListHead(&pContext->NetSendBuffersInUse);
12094c37757eSNguyen Trung Khanh     InitializeListHead(&pContext->NetFreeSendBuffers);
12104c37757eSNguyen Trung Khanh 
12114c37757eSNguyen Trung Khanh     status = ParaNdis_FinishSpecificInitialization(pContext);
12124c37757eSNguyen Trung Khanh 
12134c37757eSNguyen Trung Khanh     if (status == NDIS_STATUS_SUCCESS)
12144c37757eSNguyen Trung Khanh     {
12154c37757eSNguyen Trung Khanh         status = ParaNdis_VirtIONetInit(pContext);
12164c37757eSNguyen Trung Khanh     }
12174c37757eSNguyen Trung Khanh 
12184c37757eSNguyen Trung Khanh     pContext->Limits.nReusedRxBuffers = pContext->NetMaxReceiveBuffers / 4 + 1;
12194c37757eSNguyen Trung Khanh 
12204c37757eSNguyen Trung Khanh     if (status == NDIS_STATUS_SUCCESS)
12214c37757eSNguyen Trung Khanh     {
12224c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "start 3");
12234c37757eSNguyen Trung Khanh         pContext->bEnableInterruptHandlingDPC = TRUE;
12244c37757eSNguyen Trung Khanh         ParaNdis_SetPowerState(pContext, NdisDeviceStateD0);
12254c37757eSNguyen Trung Khanh         virtio_device_ready(&pContext->IODevice);
12264c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "start 4");
12274c37757eSNguyen Trung Khanh         ParaNdis_UpdateDeviceFilters(pContext);
12284c37757eSNguyen Trung Khanh     }
12294c37757eSNguyen Trung Khanh     else
12304c37757eSNguyen Trung Khanh     {
12314c37757eSNguyen Trung Khanh         virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_FAILED);
12324c37757eSNguyen Trung Khanh     }
12334c37757eSNguyen Trung Khanh     DEBUG_EXIT_STATUS(0, status);
12344c37757eSNguyen Trung Khanh     return status;
12354c37757eSNguyen Trung Khanh }
12364c37757eSNguyen Trung Khanh 
12374c37757eSNguyen Trung Khanh /**********************************************************
12384c37757eSNguyen Trung Khanh Releases VirtIO related resources - queues and buffers
12394c37757eSNguyen Trung Khanh Parameters:
12404c37757eSNguyen Trung Khanh     context
12414c37757eSNguyen Trung Khanh Return value:
12424c37757eSNguyen Trung Khanh ***********************************************************/
VirtIONetRelease(PARANDIS_ADAPTER * pContext)12434c37757eSNguyen Trung Khanh static void VirtIONetRelease(PARANDIS_ADAPTER *pContext)
12444c37757eSNguyen Trung Khanh {
12454c37757eSNguyen Trung Khanh     BOOLEAN b;
12464c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0);
12474c37757eSNguyen Trung Khanh 
12484c37757eSNguyen Trung Khanh     /* list NetReceiveBuffersWaiting must be free */
12494c37757eSNguyen Trung Khanh     do
12504c37757eSNguyen Trung Khanh     {
12514c37757eSNguyen Trung Khanh         NdisAcquireSpinLock(&pContext->ReceiveLock);
12524c37757eSNguyen Trung Khanh         b = !IsListEmpty(&pContext->NetReceiveBuffersWaiting);
12534c37757eSNguyen Trung Khanh         NdisReleaseSpinLock(&pContext->ReceiveLock);
12544c37757eSNguyen Trung Khanh         if (b)
12554c37757eSNguyen Trung Khanh         {
12564c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] There are waiting buffers", __FUNCTION__));
12574c37757eSNguyen Trung Khanh             PrintStatistics(pContext);
12584c37757eSNguyen Trung Khanh             NdisMSleep(5000000);
12594c37757eSNguyen Trung Khanh         }
12604c37757eSNguyen Trung Khanh     }while (b);
12614c37757eSNguyen Trung Khanh 
12624c37757eSNguyen Trung Khanh     DeleteNetQueues(pContext);
12634c37757eSNguyen Trung Khanh     virtio_device_shutdown(&pContext->IODevice);
12644c37757eSNguyen Trung Khanh     pContext->bIODeviceInitialized = FALSE;
12654c37757eSNguyen Trung Khanh 
12664c37757eSNguyen Trung Khanh     /* intentionally commented out
12674c37757eSNguyen Trung Khanh     FreeDescriptorsFromList(
12684c37757eSNguyen Trung Khanh         pContext,
12694c37757eSNguyen Trung Khanh         &pContext->NetReceiveBuffersWaiting,
12704c37757eSNguyen Trung Khanh         &pContext->ReceiveLock);
12714c37757eSNguyen Trung Khanh     */
12724c37757eSNguyen Trung Khanh 
12734c37757eSNguyen Trung Khanh     /* this can be freed, queue shut down */
12744c37757eSNguyen Trung Khanh     FreeDescriptorsFromList(
12754c37757eSNguyen Trung Khanh         pContext,
12764c37757eSNguyen Trung Khanh         &pContext->NetReceiveBuffers,
12774c37757eSNguyen Trung Khanh         &pContext->ReceiveLock);
12784c37757eSNguyen Trung Khanh 
12794c37757eSNguyen Trung Khanh     /* this can be freed, queue shut down */
12804c37757eSNguyen Trung Khanh     FreeDescriptorsFromList(
12814c37757eSNguyen Trung Khanh         pContext,
12824c37757eSNguyen Trung Khanh         &pContext->NetSendBuffersInUse,
12834c37757eSNguyen Trung Khanh         &pContext->SendLock);
12844c37757eSNguyen Trung Khanh 
12854c37757eSNguyen Trung Khanh     /* this can be freed, send disabled */
12864c37757eSNguyen Trung Khanh     FreeDescriptorsFromList(
12874c37757eSNguyen Trung Khanh         pContext,
12884c37757eSNguyen Trung Khanh         &pContext->NetFreeSendBuffers,
12894c37757eSNguyen Trung Khanh         &pContext->SendLock);
12904c37757eSNguyen Trung Khanh 
12914c37757eSNguyen Trung Khanh     if (pContext->ControlData.Virtual)
12924c37757eSNguyen Trung Khanh         ParaNdis_FreePhysicalMemory(pContext, &pContext->ControlData);
12934c37757eSNguyen Trung Khanh 
12944c37757eSNguyen Trung Khanh     PrintStatistics(pContext);
12954c37757eSNguyen Trung Khanh     if (pContext->sgTxGatherTable)
12964c37757eSNguyen Trung Khanh     {
12974c37757eSNguyen Trung Khanh         NdisFreeMemory(pContext->sgTxGatherTable, 0, 0);
12984c37757eSNguyen Trung Khanh     }
12994c37757eSNguyen Trung Khanh }
13004c37757eSNguyen Trung Khanh 
PreventDPCServicing(PARANDIS_ADAPTER * pContext)13014c37757eSNguyen Trung Khanh static void PreventDPCServicing(PARANDIS_ADAPTER *pContext)
13024c37757eSNguyen Trung Khanh {
13034c37757eSNguyen Trung Khanh     LONG inside;;
13044c37757eSNguyen Trung Khanh     pContext->bEnableInterruptHandlingDPC = FALSE;
13054c37757eSNguyen Trung Khanh     do
13064c37757eSNguyen Trung Khanh     {
13074c37757eSNguyen Trung Khanh         inside = InterlockedIncrement(&pContext->counterDPCInside);
13084c37757eSNguyen Trung Khanh         InterlockedDecrement(&pContext->counterDPCInside);
13094c37757eSNguyen Trung Khanh         if (inside > 1)
13104c37757eSNguyen Trung Khanh         {
13114c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] waiting!", __FUNCTION__));
13124c37757eSNguyen Trung Khanh             NdisMSleep(20000);
13134c37757eSNguyen Trung Khanh         }
13144c37757eSNguyen Trung Khanh     } while (inside > 1);
13154c37757eSNguyen Trung Khanh }
13164c37757eSNguyen Trung Khanh 
13174c37757eSNguyen Trung Khanh /**********************************************************
13184c37757eSNguyen Trung Khanh Frees all the resources allocated when the context initialized,
13194c37757eSNguyen Trung Khanh     calling also version-dependent part
13204c37757eSNguyen Trung Khanh Parameters:
13214c37757eSNguyen Trung Khanh     context
13224c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_CleanupContext(PARANDIS_ADAPTER * pContext)13234c37757eSNguyen Trung Khanh VOID ParaNdis_CleanupContext(PARANDIS_ADAPTER *pContext)
13244c37757eSNguyen Trung Khanh {
13254c37757eSNguyen Trung Khanh     UINT i;
13264c37757eSNguyen Trung Khanh 
13274c37757eSNguyen Trung Khanh     /* disable any interrupt generation */
13284c37757eSNguyen Trung Khanh     if (pContext->IODevice.addr)
13294c37757eSNguyen Trung Khanh     {
13304c37757eSNguyen Trung Khanh         //int nActive;
13314c37757eSNguyen Trung Khanh         //nActive = virtio_read_isr_status(&pContext->IODevice);
13324c37757eSNguyen Trung Khanh         /* back compat - remove the OK flag only in legacy mode */
13334c37757eSNguyen Trung Khanh         VirtIODeviceRemoveStatus(&pContext->IODevice, VIRTIO_CONFIG_S_DRIVER_OK);
13344c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "exit 1");
13354c37757eSNguyen Trung Khanh         //nActive += virtio_read_isr_status(&pContext->IODevice);
13364c37757eSNguyen Trung Khanh         //nActive += virtio_read_isr_status(&pContext->IODevice);
13374c37757eSNguyen Trung Khanh         //DPrintf(0, ("cleanup %d", nActive));
13384c37757eSNguyen Trung Khanh     }
13394c37757eSNguyen Trung Khanh 
13404c37757eSNguyen Trung Khanh     PreventDPCServicing(pContext);
13414c37757eSNguyen Trung Khanh 
13424c37757eSNguyen Trung Khanh     /****************************************
13434c37757eSNguyen Trung Khanh     ensure all the incoming packets returned,
13444c37757eSNguyen Trung Khanh     free all the buffers and their descriptors
13454c37757eSNguyen Trung Khanh     *****************************************/
13464c37757eSNguyen Trung Khanh 
13474c37757eSNguyen Trung Khanh     if (pContext->bIODeviceInitialized)
13484c37757eSNguyen Trung Khanh     {
13494c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "exit 2");
13504c37757eSNguyen Trung Khanh         ParaNdis_ResetVirtIONetDevice(pContext);
13514c37757eSNguyen Trung Khanh         JustForCheckClearInterrupt(pContext, "exit 3");
13524c37757eSNguyen Trung Khanh     }
13534c37757eSNguyen Trung Khanh 
13544c37757eSNguyen Trung Khanh     ParaNdis_SetPowerState(pContext, NdisDeviceStateD3);
13554c37757eSNguyen Trung Khanh     VirtIONetRelease(pContext);
13564c37757eSNguyen Trung Khanh 
13574c37757eSNguyen Trung Khanh     ParaNdis_FinalizeCleanup(pContext);
13584c37757eSNguyen Trung Khanh 
13594c37757eSNguyen Trung Khanh     if (pContext->SendLock.SpinLock)
13604c37757eSNguyen Trung Khanh     {
13614c37757eSNguyen Trung Khanh         NdisFreeSpinLock(&pContext->SendLock);
13624c37757eSNguyen Trung Khanh     }
13634c37757eSNguyen Trung Khanh 
13644c37757eSNguyen Trung Khanh #if !defined(UNIFY_LOCKS)
13654c37757eSNguyen Trung Khanh     if (pContext->ReceiveLock.SpinLock)
13664c37757eSNguyen Trung Khanh     {
13674c37757eSNguyen Trung Khanh         NdisFreeSpinLock(&pContext->ReceiveLock);
13684c37757eSNguyen Trung Khanh     }
13694c37757eSNguyen Trung Khanh #endif
13704c37757eSNguyen Trung Khanh 
13714c37757eSNguyen Trung Khanh     /* free queue shared memory */
13724c37757eSNguyen Trung Khanh     for (i = 0; i < MAX_NUM_OF_QUEUES; i++) {
13734c37757eSNguyen Trung Khanh         if (pContext->SharedMemoryRanges[i].pBase != NULL) {
13744c37757eSNguyen Trung Khanh             NdisMFreeSharedMemory(
13754c37757eSNguyen Trung Khanh                 pContext->MiniportHandle,
13764c37757eSNguyen Trung Khanh                 pContext->SharedMemoryRanges[i].uLength,
13774c37757eSNguyen Trung Khanh                 TRUE /* Cached */,
13784c37757eSNguyen Trung Khanh                 pContext->SharedMemoryRanges[i].pBase,
13794c37757eSNguyen Trung Khanh                 pContext->SharedMemoryRanges[i].BasePA);
13804c37757eSNguyen Trung Khanh             pContext->SharedMemoryRanges[i].pBase = NULL;
13814c37757eSNguyen Trung Khanh         }
13824c37757eSNguyen Trung Khanh     }
13834c37757eSNguyen Trung Khanh 
13844c37757eSNguyen Trung Khanh     /* unmap our port and memory IO resources */
13854c37757eSNguyen Trung Khanh     for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
13864c37757eSNguyen Trung Khanh     {
13874c37757eSNguyen Trung Khanh        tBusResource *pRes = &pContext->AdapterResources.PciBars[i];
13884c37757eSNguyen Trung Khanh        if (pRes->pBase != NULL)
13894c37757eSNguyen Trung Khanh        {
13904c37757eSNguyen Trung Khanh           if (pRes->bPortSpace)
13914c37757eSNguyen Trung Khanh           {
13924c37757eSNguyen Trung Khanh              NdisMDeregisterIoPortRange(
13934c37757eSNguyen Trung Khanh                 pContext->MiniportHandle,
13944c37757eSNguyen Trung Khanh                 pRes->BasePA.LowPart,
13954c37757eSNguyen Trung Khanh                 pRes->uLength,
13964c37757eSNguyen Trung Khanh                 pRes->pBase);
13974c37757eSNguyen Trung Khanh           }
13984c37757eSNguyen Trung Khanh           else
13994c37757eSNguyen Trung Khanh           {
14004c37757eSNguyen Trung Khanh              NdisMUnmapIoSpace(
14014c37757eSNguyen Trung Khanh                 pContext->MiniportHandle,
14024c37757eSNguyen Trung Khanh                 pRes->pBase,
14034c37757eSNguyen Trung Khanh                 pRes->uLength);
14044c37757eSNguyen Trung Khanh           }
14054c37757eSNguyen Trung Khanh        }
14064c37757eSNguyen Trung Khanh     }
14074c37757eSNguyen Trung Khanh }
14084c37757eSNguyen Trung Khanh 
14094c37757eSNguyen Trung Khanh 
14104c37757eSNguyen Trung Khanh /**********************************************************
14114c37757eSNguyen Trung Khanh System shutdown handler (shutdown, restart, bugcheck)
14124c37757eSNguyen Trung Khanh Parameters:
14134c37757eSNguyen Trung Khanh     context
14144c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_OnShutdown(PARANDIS_ADAPTER * pContext)14154c37757eSNguyen Trung Khanh VOID ParaNdis_OnShutdown(PARANDIS_ADAPTER *pContext)
14164c37757eSNguyen Trung Khanh {
14174c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0); // this is only for kdbg :)
14184c37757eSNguyen Trung Khanh     ParaNdis_ResetVirtIONetDevice(pContext);
14194c37757eSNguyen Trung Khanh }
14204c37757eSNguyen Trung Khanh 
14214c37757eSNguyen Trung Khanh /**********************************************************
14224c37757eSNguyen Trung Khanh Handles hardware interrupt
14234c37757eSNguyen Trung Khanh Parameters:
14244c37757eSNguyen Trung Khanh     context
14254c37757eSNguyen Trung Khanh     ULONG knownInterruptSources - bitmask of
14264c37757eSNguyen Trung Khanh Return value:
14274c37757eSNguyen Trung Khanh     TRUE, if it is our interrupt
14284c37757eSNguyen Trung Khanh     sets *pRunDpc to TRUE if the DPC should be fired
14294c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_OnLegacyInterrupt(PARANDIS_ADAPTER * pContext,OUT BOOLEAN * pRunDpc)14304c37757eSNguyen Trung Khanh BOOLEAN ParaNdis_OnLegacyInterrupt(
14314c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
14324c37757eSNguyen Trung Khanh     OUT BOOLEAN *pRunDpc)
14334c37757eSNguyen Trung Khanh {
14344c37757eSNguyen Trung Khanh     ULONG status = virtio_read_isr_status(&pContext->IODevice);
14354c37757eSNguyen Trung Khanh 
14364c37757eSNguyen Trung Khanh     if((status == 0)                                   ||
14374c37757eSNguyen Trung Khanh        (status == VIRTIO_NET_INVALID_INTERRUPT_STATUS) ||
14384c37757eSNguyen Trung Khanh        (pContext->powerState != NdisDeviceStateD0))
14394c37757eSNguyen Trung Khanh     {
14404c37757eSNguyen Trung Khanh         *pRunDpc = FALSE;
14414c37757eSNguyen Trung Khanh         return FALSE;
14424c37757eSNguyen Trung Khanh     }
14434c37757eSNguyen Trung Khanh 
14444c37757eSNguyen Trung Khanh     PARANDIS_STORE_LAST_INTERRUPT_TIMESTAMP(pContext);
14454c37757eSNguyen Trung Khanh     ParaNdis_VirtIODisableIrqSynchronized(pContext, isAny);
14464c37757eSNguyen Trung Khanh     InterlockedOr(&pContext->InterruptStatus, (LONG) ((status & isControl) | isReceive | isTransmit));
14474c37757eSNguyen Trung Khanh     *pRunDpc = TRUE;
14484c37757eSNguyen Trung Khanh     return TRUE;
14494c37757eSNguyen Trung Khanh }
14504c37757eSNguyen Trung Khanh 
ParaNdis_OnQueuedInterrupt(PARANDIS_ADAPTER * pContext,OUT BOOLEAN * pRunDpc,ULONG knownInterruptSources)14514c37757eSNguyen Trung Khanh BOOLEAN ParaNdis_OnQueuedInterrupt(
14524c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
14534c37757eSNguyen Trung Khanh     OUT BOOLEAN *pRunDpc,
14544c37757eSNguyen Trung Khanh     ULONG knownInterruptSources)
14554c37757eSNguyen Trung Khanh {
14564c37757eSNguyen Trung Khanh     struct virtqueue* _vq = ParaNdis_GetQueueForInterrupt(pContext, knownInterruptSources);
14574c37757eSNguyen Trung Khanh 
14584c37757eSNguyen Trung Khanh     /* If interrupts for this queue disabled do nothing */
14594c37757eSNguyen Trung Khanh     if((_vq != NULL) && !ParaNDIS_IsQueueInterruptEnabled(_vq))
14604c37757eSNguyen Trung Khanh     {
14614c37757eSNguyen Trung Khanh         *pRunDpc = FALSE;
14624c37757eSNguyen Trung Khanh     }
14634c37757eSNguyen Trung Khanh     else
14644c37757eSNguyen Trung Khanh     {
14654c37757eSNguyen Trung Khanh         PARANDIS_STORE_LAST_INTERRUPT_TIMESTAMP(pContext);
14664c37757eSNguyen Trung Khanh         InterlockedOr(&pContext->InterruptStatus, (LONG)knownInterruptSources);
14674c37757eSNguyen Trung Khanh         ParaNdis_VirtIODisableIrqSynchronized(pContext, knownInterruptSources);
14684c37757eSNguyen Trung Khanh         *pRunDpc = TRUE;
14694c37757eSNguyen Trung Khanh     }
14704c37757eSNguyen Trung Khanh 
14714c37757eSNguyen Trung Khanh     return *pRunDpc;
14724c37757eSNguyen Trung Khanh }
14734c37757eSNguyen Trung Khanh 
14744c37757eSNguyen Trung Khanh 
14754c37757eSNguyen Trung Khanh /**********************************************************
14764c37757eSNguyen Trung Khanh It is called from Rx processing routines in regular mode of operation.
14774c37757eSNguyen Trung Khanh Returns received buffer back to VirtIO queue, inserting it to NetReceiveBuffers.
14784c37757eSNguyen Trung Khanh If needed, signals end of RX pause operation
14794c37757eSNguyen Trung Khanh 
14804c37757eSNguyen Trung Khanh Must be called with &pContext->ReceiveLock acquired
14814c37757eSNguyen Trung Khanh 
14824c37757eSNguyen Trung Khanh Parameters:
14834c37757eSNguyen Trung Khanh     context
14844c37757eSNguyen Trung Khanh     void *pDescriptor - pIONetDescriptor to return
14854c37757eSNguyen Trung Khanh ***********************************************************/
ReuseReceiveBufferRegular(PARANDIS_ADAPTER * pContext,pIONetDescriptor pBuffersDescriptor)14864c37757eSNguyen Trung Khanh void ReuseReceiveBufferRegular(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor)
14874c37757eSNguyen Trung Khanh {
14884c37757eSNguyen Trung Khanh     DEBUG_ENTRY(4);
14894c37757eSNguyen Trung Khanh 
14904c37757eSNguyen Trung Khanh     if(!pBuffersDescriptor)
14914c37757eSNguyen Trung Khanh         return;
14924c37757eSNguyen Trung Khanh 
14934c37757eSNguyen Trung Khanh     RemoveEntryList(&pBuffersDescriptor->listEntry);
14944c37757eSNguyen Trung Khanh 
14954c37757eSNguyen Trung Khanh     if(AddRxBufferToQueue(pContext, pBuffersDescriptor))
14964c37757eSNguyen Trung Khanh     {
14974c37757eSNguyen Trung Khanh         InsertTailList(&pContext->NetReceiveBuffers, &pBuffersDescriptor->listEntry);
14984c37757eSNguyen Trung Khanh 
14994c37757eSNguyen Trung Khanh         pContext->NetNofReceiveBuffers++;
15004c37757eSNguyen Trung Khanh 
15014c37757eSNguyen Trung Khanh         if (pContext->NetNofReceiveBuffers > pContext->NetMaxReceiveBuffers)
15024c37757eSNguyen Trung Khanh         {
15034c37757eSNguyen Trung Khanh             DPrintf(0, (" Error: NetNofReceiveBuffers > NetMaxReceiveBuffers(%d>%d)",
15044c37757eSNguyen Trung Khanh                 pContext->NetNofReceiveBuffers, pContext->NetMaxReceiveBuffers));
15054c37757eSNguyen Trung Khanh         }
15064c37757eSNguyen Trung Khanh 
15074c37757eSNguyen Trung Khanh         if (++pContext->Counters.nReusedRxBuffers >= pContext->Limits.nReusedRxBuffers)
15084c37757eSNguyen Trung Khanh         {
15094c37757eSNguyen Trung Khanh             pContext->Counters.nReusedRxBuffers = 0;
15104c37757eSNguyen Trung Khanh             virtqueue_kick_always(pContext->NetReceiveQueue);
15114c37757eSNguyen Trung Khanh         }
15124c37757eSNguyen Trung Khanh 
15134c37757eSNguyen Trung Khanh         if (IsListEmpty(&pContext->NetReceiveBuffersWaiting))
15144c37757eSNguyen Trung Khanh         {
15154c37757eSNguyen Trung Khanh             if (pContext->ReceiveState == srsPausing || pContext->ReceivePauseCompletionProc)
15164c37757eSNguyen Trung Khanh             {
15174c37757eSNguyen Trung Khanh                 ONPAUSECOMPLETEPROC callback = pContext->ReceivePauseCompletionProc;
15184c37757eSNguyen Trung Khanh                 pContext->ReceiveState = srsDisabled;
15194c37757eSNguyen Trung Khanh                 pContext->ReceivePauseCompletionProc = NULL;
15204c37757eSNguyen Trung Khanh                 ParaNdis_DebugHistory(pContext, hopInternalReceivePause, NULL, 0, 0, 0);
15214c37757eSNguyen Trung Khanh                 if (callback) callback(pContext);
15224c37757eSNguyen Trung Khanh             }
15234c37757eSNguyen Trung Khanh         }
15244c37757eSNguyen Trung Khanh     }
15254c37757eSNguyen Trung Khanh     else
15264c37757eSNguyen Trung Khanh     {
15274c37757eSNguyen Trung Khanh         DPrintf(0, ("FAILED TO REUSE THE BUFFER!!!!"));
15284c37757eSNguyen Trung Khanh         VirtIONetFreeBufferDescriptor(pContext, pBuffersDescriptor);
15294c37757eSNguyen Trung Khanh         pContext->NetMaxReceiveBuffers--;
15304c37757eSNguyen Trung Khanh     }
15314c37757eSNguyen Trung Khanh }
15324c37757eSNguyen Trung Khanh 
15334c37757eSNguyen Trung Khanh /**********************************************************
15344c37757eSNguyen Trung Khanh It is called from Rx processing routines between power off and power on in non-paused mode (Win8).
15354c37757eSNguyen Trung Khanh Returns received buffer to NetReceiveBuffers.
15364c37757eSNguyen Trung Khanh All the buffers will be placed into Virtio queue during power-on procedure
15374c37757eSNguyen Trung Khanh 
15384c37757eSNguyen Trung Khanh Must be called with &pContext->ReceiveLock acquired
15394c37757eSNguyen Trung Khanh 
15404c37757eSNguyen Trung Khanh Parameters:
15414c37757eSNguyen Trung Khanh     context
15424c37757eSNguyen Trung Khanh     void *pDescriptor - pIONetDescriptor to return
15434c37757eSNguyen Trung Khanh ***********************************************************/
ReuseReceiveBufferPowerOff(PARANDIS_ADAPTER * pContext,pIONetDescriptor pBuffersDescriptor)15444c37757eSNguyen Trung Khanh static void ReuseReceiveBufferPowerOff(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor)
15454c37757eSNguyen Trung Khanh {
15464c37757eSNguyen Trung Khanh     RemoveEntryList(&pBuffersDescriptor->listEntry);
15474c37757eSNguyen Trung Khanh     InsertTailList(&pContext->NetReceiveBuffers, &pBuffersDescriptor->listEntry);
15484c37757eSNguyen Trung Khanh }
15494c37757eSNguyen Trung Khanh 
15504c37757eSNguyen Trung Khanh /**********************************************************
15514c37757eSNguyen Trung Khanh It is called from Tx processing routines
15524c37757eSNguyen Trung Khanh Gets all the finished buffer from VirtIO TX path and
15534c37757eSNguyen Trung Khanh returns them to NetFreeSendBuffers
15544c37757eSNguyen Trung Khanh 
15554c37757eSNguyen Trung Khanh Must be called with &pContext->SendLock acquired
15564c37757eSNguyen Trung Khanh 
15574c37757eSNguyen Trung Khanh Parameters:
15584c37757eSNguyen Trung Khanh     context
15594c37757eSNguyen Trung Khanh Return value:
15604c37757eSNguyen Trung Khanh     (for reference) number of TX buffers returned
15614c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_VirtIONetReleaseTransmitBuffers(PARANDIS_ADAPTER * pContext)15624c37757eSNguyen Trung Khanh UINT ParaNdis_VirtIONetReleaseTransmitBuffers(
15634c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext)
15644c37757eSNguyen Trung Khanh {
15654c37757eSNguyen Trung Khanh     UINT len, i = 0;
15664c37757eSNguyen Trung Khanh     pIONetDescriptor pBufferDescriptor;
15674c37757eSNguyen Trung Khanh 
15684c37757eSNguyen Trung Khanh     DEBUG_ENTRY(4);
15694c37757eSNguyen Trung Khanh 
15704c37757eSNguyen Trung Khanh     while(NULL != (pBufferDescriptor = virtqueue_get_buf(pContext->NetSendQueue, &len)))
15714c37757eSNguyen Trung Khanh     {
15724c37757eSNguyen Trung Khanh         RemoveEntryList(&pBufferDescriptor->listEntry);
15734c37757eSNguyen Trung Khanh         pContext->nofFreeTxDescriptors++;
15744c37757eSNguyen Trung Khanh         if (!pBufferDescriptor->nofUsedBuffers)
15754c37757eSNguyen Trung Khanh         {
15764c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] ERROR: nofUsedBuffers not set!", __FUNCTION__));
15774c37757eSNguyen Trung Khanh         }
15784c37757eSNguyen Trung Khanh         pContext->nofFreeHardwareBuffers += pBufferDescriptor->nofUsedBuffers;
15794c37757eSNguyen Trung Khanh         ParaNdis_OnTransmitBufferReleased(pContext, pBufferDescriptor);
15804c37757eSNguyen Trung Khanh         InsertTailList(&pContext->NetFreeSendBuffers, &pBufferDescriptor->listEntry);
15814c37757eSNguyen Trung Khanh         DPrintf(3, ("[%s] Free Tx: desc %d, buff %d", __FUNCTION__, pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers));
15824c37757eSNguyen Trung Khanh         pBufferDescriptor->nofUsedBuffers = 0;
15834c37757eSNguyen Trung Khanh         ++i;
15844c37757eSNguyen Trung Khanh     }
15854c37757eSNguyen Trung Khanh     if (i)
15864c37757eSNguyen Trung Khanh     {
15874c37757eSNguyen Trung Khanh         NdisGetCurrentSystemTime(&pContext->LastTxCompletionTimeStamp);
15884c37757eSNguyen Trung Khanh         pContext->bDoKickOnNoBuffer = TRUE;
15894c37757eSNguyen Trung Khanh         pContext->nDetectedStoppedTx = 0;
15904c37757eSNguyen Trung Khanh     }
15914c37757eSNguyen Trung Khanh     DEBUG_EXIT_STATUS((i ? 3 : 5), i);
15924c37757eSNguyen Trung Khanh     return i;
15934c37757eSNguyen Trung Khanh }
15944c37757eSNguyen Trung Khanh 
QueryTcpHeaderOffset(PVOID packetData,ULONG ipHeaderOffset,ULONG ipPacketLength)15954c37757eSNguyen Trung Khanh static ULONG FORCEINLINE QueryTcpHeaderOffset(PVOID packetData, ULONG ipHeaderOffset, ULONG ipPacketLength)
15964c37757eSNguyen Trung Khanh {
15974c37757eSNguyen Trung Khanh     ULONG res;
15984c37757eSNguyen Trung Khanh     tTcpIpPacketParsingResult ppr = ParaNdis_ReviewIPPacket(
15994c37757eSNguyen Trung Khanh         (PUCHAR)packetData + ipHeaderOffset,
16004c37757eSNguyen Trung Khanh         ipPacketLength,
16014c37757eSNguyen Trung Khanh         __FUNCTION__);
16024c37757eSNguyen Trung Khanh     if (ppr.xxpStatus == ppresXxpKnown)
16034c37757eSNguyen Trung Khanh     {
16044c37757eSNguyen Trung Khanh         res = ipHeaderOffset + ppr.ipHeaderSize;
16054c37757eSNguyen Trung Khanh     }
16064c37757eSNguyen Trung Khanh     else
16074c37757eSNguyen Trung Khanh     {
16084c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] ERROR: NOT a TCP or UDP packet - expected troubles!", __FUNCTION__));
16094c37757eSNguyen Trung Khanh         res = 0;
16104c37757eSNguyen Trung Khanh     }
16114c37757eSNguyen Trung Khanh     return res;
16124c37757eSNguyen Trung Khanh }
16134c37757eSNguyen Trung Khanh 
16144c37757eSNguyen Trung Khanh 
16154c37757eSNguyen Trung Khanh /*********************************************************
16164c37757eSNguyen Trung Khanh Called with from ProcessTx routine with TxLock held
16174c37757eSNguyen Trung Khanh Uses pContext->sgTxGatherTable
16184c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_DoSubmitPacket(PARANDIS_ADAPTER * pContext,tTxOperationParameters * Params)16194c37757eSNguyen Trung Khanh tCopyPacketResult ParaNdis_DoSubmitPacket(PARANDIS_ADAPTER *pContext, tTxOperationParameters *Params)
16204c37757eSNguyen Trung Khanh {
16214c37757eSNguyen Trung Khanh     tCopyPacketResult result;
16224c37757eSNguyen Trung Khanh     tMapperResult mapResult = {0,0,0};
16234c37757eSNguyen Trung Khanh     // populating priority tag or LSO MAY require additional SG element
16244c37757eSNguyen Trung Khanh     UINT nRequiredBuffers;
16254c37757eSNguyen Trung Khanh     BOOLEAN bUseCopy = FALSE;
16264c37757eSNguyen Trung Khanh     struct VirtIOBufferDescriptor *sg = pContext->sgTxGatherTable;
16274c37757eSNguyen Trung Khanh 
16284c37757eSNguyen Trung Khanh     nRequiredBuffers = Params->nofSGFragments + 1 + ((Params->flags & (pcrPriorityTag | pcrLSO)) ? 1 : 0);
16294c37757eSNguyen Trung Khanh 
16304c37757eSNguyen Trung Khanh     result.size = 0;
16314c37757eSNguyen Trung Khanh     result.error = cpeOK;
16324c37757eSNguyen Trung Khanh     if (!pContext->bUseScatterGather ||         // only copy available
16334c37757eSNguyen Trung Khanh         Params->nofSGFragments == 0 ||          // theoretical case
16344c37757eSNguyen Trung Khanh         !sg ||                                  // only copy available
16354c37757eSNguyen Trung Khanh         ((~Params->flags & pcrLSO) && nRequiredBuffers > pContext->maxFreeHardwareBuffers) // to many fragments and normal size of packet
16364c37757eSNguyen Trung Khanh         )
16374c37757eSNguyen Trung Khanh     {
16384c37757eSNguyen Trung Khanh         nRequiredBuffers = 2;
16394c37757eSNguyen Trung Khanh         bUseCopy = TRUE;
16404c37757eSNguyen Trung Khanh     }
16414c37757eSNguyen Trung Khanh     else if (pContext->bUseIndirect && !(Params->flags & pcrNoIndirect))
16424c37757eSNguyen Trung Khanh     {
16434c37757eSNguyen Trung Khanh         nRequiredBuffers = 1;
16444c37757eSNguyen Trung Khanh     }
16454c37757eSNguyen Trung Khanh 
16464c37757eSNguyen Trung Khanh     // I do not think this will help, but at least we can try freeing some buffers right now
16474c37757eSNguyen Trung Khanh     if (pContext->nofFreeHardwareBuffers < nRequiredBuffers || !pContext->nofFreeTxDescriptors)
16484c37757eSNguyen Trung Khanh     {
16494c37757eSNguyen Trung Khanh         ParaNdis_VirtIONetReleaseTransmitBuffers(pContext);
16504c37757eSNguyen Trung Khanh     }
16514c37757eSNguyen Trung Khanh 
16524c37757eSNguyen Trung Khanh     if (nRequiredBuffers > pContext->maxFreeHardwareBuffers)
16534c37757eSNguyen Trung Khanh     {
16544c37757eSNguyen Trung Khanh         // LSO and too many buffers, impossible to send
16554c37757eSNguyen Trung Khanh         result.error = cpeTooLarge;
16564c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] ERROR: too many fragments(%d required, %d max.avail)!", __FUNCTION__,
16574c37757eSNguyen Trung Khanh             nRequiredBuffers, pContext->maxFreeHardwareBuffers));
16584c37757eSNguyen Trung Khanh     }
16594c37757eSNguyen Trung Khanh     else if (pContext->nofFreeHardwareBuffers < nRequiredBuffers || !pContext->nofFreeTxDescriptors)
16604c37757eSNguyen Trung Khanh     {
16614c37757eSNguyen Trung Khanh         virtqueue_enable_cb_delayed(pContext->NetSendQueue);
16624c37757eSNguyen Trung Khanh         result.error = cpeNoBuffer;
16634c37757eSNguyen Trung Khanh     }
16644c37757eSNguyen Trung Khanh     else if (Params->offloadMss && bUseCopy)
16654c37757eSNguyen Trung Khanh     {
16664c37757eSNguyen Trung Khanh         result.error = cpeInternalError;
16674c37757eSNguyen Trung Khanh         DPrintf(0, ("[%s] ERROR: expecting SG for TSO! (%d buffers, %d bytes)", __FUNCTION__,
16684c37757eSNguyen Trung Khanh             Params->nofSGFragments, Params->ulDataSize));
16694c37757eSNguyen Trung Khanh     }
16704c37757eSNguyen Trung Khanh     else if (bUseCopy)
16714c37757eSNguyen Trung Khanh     {
16724c37757eSNguyen Trung Khanh         result = ParaNdis_DoCopyPacketData(pContext, Params);
16734c37757eSNguyen Trung Khanh     }
16744c37757eSNguyen Trung Khanh     else
16754c37757eSNguyen Trung Khanh     {
16764c37757eSNguyen Trung Khanh         UINT nMappedBuffers;
16774c37757eSNguyen Trung Khanh         ULONGLONG paOfIndirectArea = 0;
16784c37757eSNguyen Trung Khanh         PVOID vaOfIndirectArea = NULL;
16794c37757eSNguyen Trung Khanh         pIONetDescriptor pBuffersDescriptor = (pIONetDescriptor)RemoveHeadList(&pContext->NetFreeSendBuffers);
16804c37757eSNguyen Trung Khanh         pContext->nofFreeTxDescriptors--;
16814c37757eSNguyen Trung Khanh         NdisZeroMemory(pBuffersDescriptor->HeaderInfo.Virtual, pBuffersDescriptor->HeaderInfo.size);
16824c37757eSNguyen Trung Khanh         sg[0].physAddr = pBuffersDescriptor->HeaderInfo.Physical;
16834c37757eSNguyen Trung Khanh         sg[0].length = pBuffersDescriptor->HeaderInfo.size;
16844c37757eSNguyen Trung Khanh         ParaNdis_PacketMapper(
16854c37757eSNguyen Trung Khanh             pContext,
16864c37757eSNguyen Trung Khanh             Params->packet,
16874c37757eSNguyen Trung Khanh             Params->ReferenceValue,
16884c37757eSNguyen Trung Khanh             sg + 1,
16894c37757eSNguyen Trung Khanh             pBuffersDescriptor,
16904c37757eSNguyen Trung Khanh             &mapResult);
16914c37757eSNguyen Trung Khanh         nMappedBuffers = mapResult.usBuffersMapped;
16924c37757eSNguyen Trung Khanh         if (nMappedBuffers)
16934c37757eSNguyen Trung Khanh         {
16944c37757eSNguyen Trung Khanh             nMappedBuffers++;
16954c37757eSNguyen Trung Khanh             if (pContext->bUseIndirect && !(Params->flags & pcrNoIndirect))
16964c37757eSNguyen Trung Khanh             {
16974c37757eSNguyen Trung Khanh                 ULONG space1 = (mapResult.usBufferSpaceUsed + 7) & ~7;
16984c37757eSNguyen Trung Khanh                 ULONG space2 = nMappedBuffers * SIZE_OF_SINGLE_INDIRECT_DESC;
16994c37757eSNguyen Trung Khanh                 if (pBuffersDescriptor->DataInfo.size >= (space1 + space2))
17004c37757eSNguyen Trung Khanh                 {
17014c37757eSNguyen Trung Khanh                     vaOfIndirectArea = RtlOffsetToPointer(pBuffersDescriptor->DataInfo.Virtual, space1);
17024c37757eSNguyen Trung Khanh                     paOfIndirectArea = pBuffersDescriptor->DataInfo.Physical.QuadPart + space1;
17034c37757eSNguyen Trung Khanh                     pContext->extraStatistics.framesIndirect++;
17044c37757eSNguyen Trung Khanh                 }
17054c37757eSNguyen Trung Khanh                 else if (nMappedBuffers <= pContext->nofFreeHardwareBuffers)
17064c37757eSNguyen Trung Khanh                 {
17074c37757eSNguyen Trung Khanh                     // send as is, no indirect
17084c37757eSNguyen Trung Khanh                 }
17094c37757eSNguyen Trung Khanh                 else
17104c37757eSNguyen Trung Khanh                 {
17114c37757eSNguyen Trung Khanh                     result.error = cpeNoIndirect;
17124c37757eSNguyen Trung Khanh                     DPrintf(0, ("[%s] Unexpected ERROR of placement!", __FUNCTION__));
17134c37757eSNguyen Trung Khanh                 }
17144c37757eSNguyen Trung Khanh             }
17154c37757eSNguyen Trung Khanh             if (result.error == cpeOK)
17164c37757eSNguyen Trung Khanh             {
17174c37757eSNguyen Trung Khanh                 if (Params->flags & (pcrTcpChecksum | pcrUdpChecksum))
17184c37757eSNguyen Trung Khanh                 {
17194c37757eSNguyen Trung Khanh                     unsigned short addPriorityLen = (Params->flags & pcrPriorityTag) ? ETH_PRIORITY_HEADER_SIZE : 0;
17204c37757eSNguyen Trung Khanh                     if (pContext->bDoHardwareChecksum)
17214c37757eSNguyen Trung Khanh                     {
17224c37757eSNguyen Trung Khanh                         virtio_net_hdr_basic *pheader = pBuffersDescriptor->HeaderInfo.Virtual;
17234c37757eSNguyen Trung Khanh                         pheader->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
17244c37757eSNguyen Trung Khanh                         if (!Params->tcpHeaderOffset)
17254c37757eSNguyen Trung Khanh                         {
17264c37757eSNguyen Trung Khanh                             Params->tcpHeaderOffset = QueryTcpHeaderOffset(
17274c37757eSNguyen Trung Khanh                                 pBuffersDescriptor->DataInfo.Virtual,
17284c37757eSNguyen Trung Khanh                                 pContext->Offload.ipHeaderOffset + addPriorityLen,
17294c37757eSNguyen Trung Khanh                                 mapResult.usBufferSpaceUsed - pContext->Offload.ipHeaderOffset - addPriorityLen);
17304c37757eSNguyen Trung Khanh                         }
17314c37757eSNguyen Trung Khanh                         else
17324c37757eSNguyen Trung Khanh                         {
17334c37757eSNguyen Trung Khanh                             Params->tcpHeaderOffset += addPriorityLen;
17344c37757eSNguyen Trung Khanh                         }
17354c37757eSNguyen Trung Khanh                         pheader->csum_start = (USHORT)Params->tcpHeaderOffset;
17364c37757eSNguyen Trung Khanh                         pheader->csum_offset = (Params->flags & pcrTcpChecksum) ? TCP_CHECKSUM_OFFSET : UDP_CHECKSUM_OFFSET;
17374c37757eSNguyen Trung Khanh                     }
17384c37757eSNguyen Trung Khanh                     else
17394c37757eSNguyen Trung Khanh                     {
17404c37757eSNguyen Trung Khanh                         // emulation mode - it is slow and intended only for test of flows
17414c37757eSNguyen Trung Khanh                         // and debugging of WLK test cases
17424c37757eSNguyen Trung Khanh                         PVOID pCopy = ParaNdis_AllocateMemory(pContext, Params->ulDataSize);
17434c37757eSNguyen Trung Khanh                         if (pCopy)
17444c37757eSNguyen Trung Khanh                         {
17454c37757eSNguyen Trung Khanh                             tTcpIpPacketParsingResult ppr;
17464c37757eSNguyen Trung Khanh                             // duplicate entire packet
17474c37757eSNguyen Trung Khanh                             ParaNdis_PacketCopier(Params->packet, pCopy, Params->ulDataSize, Params->ReferenceValue, FALSE);
17484c37757eSNguyen Trung Khanh                             // calculate complete TCP/UDP checksum
17494c37757eSNguyen Trung Khanh                             ppr = ParaNdis_CheckSumVerify(
17504c37757eSNguyen Trung Khanh                                 RtlOffsetToPointer(pCopy, pContext->Offload.ipHeaderOffset + addPriorityLen),
17514c37757eSNguyen Trung Khanh                                 Params->ulDataSize - pContext->Offload.ipHeaderOffset - addPriorityLen,
17524c37757eSNguyen Trung Khanh                                 pcrAnyChecksum | pcrFixXxpChecksum,
17534c37757eSNguyen Trung Khanh                                 __FUNCTION__);
17544c37757eSNguyen Trung Khanh                             // data portion in aside buffer contains complete IP+TCP header
17554c37757eSNguyen Trung Khanh                             // rewrite copy of original buffer by one new with calculated data
17564c37757eSNguyen Trung Khanh                             NdisMoveMemory(
17574c37757eSNguyen Trung Khanh                                 pBuffersDescriptor->DataInfo.Virtual,
17584c37757eSNguyen Trung Khanh                                 pCopy,
17594c37757eSNguyen Trung Khanh                                 mapResult.usBufferSpaceUsed);
17604c37757eSNguyen Trung Khanh                             NdisFreeMemory(pCopy, 0, 0);
17614c37757eSNguyen Trung Khanh                         }
17624c37757eSNguyen Trung Khanh                     }
17634c37757eSNguyen Trung Khanh                 }
17644c37757eSNguyen Trung Khanh 
17654c37757eSNguyen Trung Khanh                 if (0 <= virtqueue_add_buf(
17664c37757eSNguyen Trung Khanh                     pContext->NetSendQueue,
17674c37757eSNguyen Trung Khanh                     sg,
17684c37757eSNguyen Trung Khanh                     nMappedBuffers,
17694c37757eSNguyen Trung Khanh                     0,
17704c37757eSNguyen Trung Khanh                     pBuffersDescriptor,
17714c37757eSNguyen Trung Khanh                     vaOfIndirectArea,
17724c37757eSNguyen Trung Khanh                     paOfIndirectArea))
17734c37757eSNguyen Trung Khanh                 {
17744c37757eSNguyen Trung Khanh                     pBuffersDescriptor->nofUsedBuffers = nMappedBuffers;
17754c37757eSNguyen Trung Khanh                     pContext->nofFreeHardwareBuffers -= nMappedBuffers;
17764c37757eSNguyen Trung Khanh                     if (pContext->minFreeHardwareBuffers > pContext->nofFreeHardwareBuffers)
17774c37757eSNguyen Trung Khanh                         pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers;
17784c37757eSNguyen Trung Khanh                     pBuffersDescriptor->ReferenceValue = Params->ReferenceValue;
17794c37757eSNguyen Trung Khanh                     result.size = Params->ulDataSize;
17804c37757eSNguyen Trung Khanh                     DPrintf(2, ("[%s] Submitted %d buffers (%d bytes), avail %d desc, %d bufs",
17814c37757eSNguyen Trung Khanh                         __FUNCTION__, nMappedBuffers, result.size,
17824c37757eSNguyen Trung Khanh                         pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers
17834c37757eSNguyen Trung Khanh                     ));
17844c37757eSNguyen Trung Khanh                 }
17854c37757eSNguyen Trung Khanh                 else
17864c37757eSNguyen Trung Khanh                 {
17874c37757eSNguyen Trung Khanh                     result.error = cpeInternalError;
17884c37757eSNguyen Trung Khanh                     DPrintf(0, ("[%s] Unexpected ERROR adding buffer to TX engine!..", __FUNCTION__));
17894c37757eSNguyen Trung Khanh                 }
17904c37757eSNguyen Trung Khanh             }
17914c37757eSNguyen Trung Khanh         }
17924c37757eSNguyen Trung Khanh         else
17934c37757eSNguyen Trung Khanh         {
17944c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Unexpected ERROR: packet not mapped!", __FUNCTION__));
17954c37757eSNguyen Trung Khanh             result.error = cpeInternalError;
17964c37757eSNguyen Trung Khanh         }
17974c37757eSNguyen Trung Khanh 
17984c37757eSNguyen Trung Khanh         if (result.error == cpeOK)
17994c37757eSNguyen Trung Khanh         {
18004c37757eSNguyen Trung Khanh             UCHAR ethernetHeader[sizeof(ETH_HEADER)];
18014c37757eSNguyen Trung Khanh             eInspectedPacketType packetType;
18024c37757eSNguyen Trung Khanh             /* get the ethernet header for review */
18034c37757eSNguyen Trung Khanh             ParaNdis_PacketCopier(Params->packet, ethernetHeader, sizeof(ethernetHeader), Params->ReferenceValue, TRUE);
18044c37757eSNguyen Trung Khanh             packetType = QueryPacketType(ethernetHeader);
18054c37757eSNguyen Trung Khanh             DebugDumpPacket("sending", ethernetHeader, 3);
18064c37757eSNguyen Trung Khanh             InsertTailList(&pContext->NetSendBuffersInUse, &pBuffersDescriptor->listEntry);
18074c37757eSNguyen Trung Khanh             pContext->Statistics.ifHCOutOctets += result.size;
18084c37757eSNguyen Trung Khanh             switch (packetType)
18094c37757eSNguyen Trung Khanh             {
18104c37757eSNguyen Trung Khanh                 case iptBroadcast:
18114c37757eSNguyen Trung Khanh                     pContext->Statistics.ifHCOutBroadcastOctets += result.size;
18124c37757eSNguyen Trung Khanh                     pContext->Statistics.ifHCOutBroadcastPkts++;
18134c37757eSNguyen Trung Khanh                     break;
18144c37757eSNguyen Trung Khanh                 case iptMulticast:
18154c37757eSNguyen Trung Khanh                     pContext->Statistics.ifHCOutMulticastOctets += result.size;
18164c37757eSNguyen Trung Khanh                     pContext->Statistics.ifHCOutMulticastPkts++;
18174c37757eSNguyen Trung Khanh                     break;
18184c37757eSNguyen Trung Khanh                 default:
18194c37757eSNguyen Trung Khanh                     pContext->Statistics.ifHCOutUcastOctets += result.size;
18204c37757eSNguyen Trung Khanh                     pContext->Statistics.ifHCOutUcastPkts++;
18214c37757eSNguyen Trung Khanh                     break;
18224c37757eSNguyen Trung Khanh             }
18234c37757eSNguyen Trung Khanh 
18244c37757eSNguyen Trung Khanh             if (Params->flags & pcrLSO)
18254c37757eSNguyen Trung Khanh                 pContext->extraStatistics.framesLSO++;
18264c37757eSNguyen Trung Khanh         }
18274c37757eSNguyen Trung Khanh         else
18284c37757eSNguyen Trung Khanh         {
18294c37757eSNguyen Trung Khanh             pContext->nofFreeTxDescriptors++;
18304c37757eSNguyen Trung Khanh             InsertHeadList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry);
18314c37757eSNguyen Trung Khanh         }
18324c37757eSNguyen Trung Khanh     }
18334c37757eSNguyen Trung Khanh     if (result.error == cpeNoBuffer && pContext->bDoKickOnNoBuffer)
18344c37757eSNguyen Trung Khanh     {
18354c37757eSNguyen Trung Khanh         virtqueue_kick_always(pContext->NetSendQueue);
18364c37757eSNguyen Trung Khanh         pContext->bDoKickOnNoBuffer = FALSE;
18374c37757eSNguyen Trung Khanh     }
18384c37757eSNguyen Trung Khanh     if (result.error == cpeOK)
18394c37757eSNguyen Trung Khanh     {
18404c37757eSNguyen Trung Khanh         if (Params->flags & (pcrTcpChecksum | pcrUdpChecksum))
18414c37757eSNguyen Trung Khanh             pContext->extraStatistics.framesCSOffload++;
18424c37757eSNguyen Trung Khanh     }
18434c37757eSNguyen Trung Khanh     return result;
18444c37757eSNguyen Trung Khanh }
18454c37757eSNguyen Trung Khanh 
18464c37757eSNguyen Trung Khanh 
18474c37757eSNguyen Trung Khanh /**********************************************************
18484c37757eSNguyen Trung Khanh It is called from Tx processing routines
18494c37757eSNguyen Trung Khanh Prepares the VirtIO buffer and copies to it the data from provided packet
18504c37757eSNguyen Trung Khanh 
18514c37757eSNguyen Trung Khanh Must be called with &pContext->SendLock acquired
18524c37757eSNguyen Trung Khanh 
18534c37757eSNguyen Trung Khanh Parameters:
18544c37757eSNguyen Trung Khanh     context
18554c37757eSNguyen Trung Khanh     tPacketType packet          specific type is NDIS dependent
18564c37757eSNguyen Trung Khanh     tCopyPacketDataFunction     PacketCopier procedure for NDIS-specific type of packet
18574c37757eSNguyen Trung Khanh Return value:
18584c37757eSNguyen Trung Khanh     (for reference) number of TX buffers returned
18594c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_DoCopyPacketData(PARANDIS_ADAPTER * pContext,tTxOperationParameters * pParams)18604c37757eSNguyen Trung Khanh tCopyPacketResult ParaNdis_DoCopyPacketData(
18614c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
18624c37757eSNguyen Trung Khanh     tTxOperationParameters *pParams)
18634c37757eSNguyen Trung Khanh {
18644c37757eSNguyen Trung Khanh     tCopyPacketResult result;
18654c37757eSNguyen Trung Khanh     tCopyPacketResult CopierResult;
18664c37757eSNguyen Trung Khanh     struct VirtIOBufferDescriptor sg[2];
18674c37757eSNguyen Trung Khanh     pIONetDescriptor pBuffersDescriptor = NULL;
18684c37757eSNguyen Trung Khanh     ULONG flags = pParams->flags;
18694c37757eSNguyen Trung Khanh     UINT nRequiredHardwareBuffers = 2;
18704c37757eSNguyen Trung Khanh     result.size  = 0;
18714c37757eSNguyen Trung Khanh     result.error = cpeOK;
18724c37757eSNguyen Trung Khanh     if (pContext->nofFreeHardwareBuffers < nRequiredHardwareBuffers ||
18734c37757eSNguyen Trung Khanh         IsListEmpty(&pContext->NetFreeSendBuffers))
18744c37757eSNguyen Trung Khanh     {
18754c37757eSNguyen Trung Khanh         result.error = cpeNoBuffer;
18764c37757eSNguyen Trung Khanh     }
18774c37757eSNguyen Trung Khanh     if(result.error == cpeOK)
18784c37757eSNguyen Trung Khanh     {
18794c37757eSNguyen Trung Khanh         pBuffersDescriptor = (pIONetDescriptor)RemoveHeadList(&pContext->NetFreeSendBuffers);
18804c37757eSNguyen Trung Khanh         NdisZeroMemory(pBuffersDescriptor->HeaderInfo.Virtual, pBuffersDescriptor->HeaderInfo.size);
18814c37757eSNguyen Trung Khanh         sg[0].physAddr = pBuffersDescriptor->HeaderInfo.Physical;
18824c37757eSNguyen Trung Khanh         sg[0].length = pBuffersDescriptor->HeaderInfo.size;
18834c37757eSNguyen Trung Khanh         sg[1].physAddr = pBuffersDescriptor->DataInfo.Physical;
18844c37757eSNguyen Trung Khanh         CopierResult = ParaNdis_PacketCopier(
18854c37757eSNguyen Trung Khanh             pParams->packet,
18864c37757eSNguyen Trung Khanh             pBuffersDescriptor->DataInfo.Virtual,
18874c37757eSNguyen Trung Khanh             pBuffersDescriptor->DataInfo.size,
18884c37757eSNguyen Trung Khanh             pParams->ReferenceValue,
18894c37757eSNguyen Trung Khanh             FALSE);
18904c37757eSNguyen Trung Khanh         sg[1].length = result.size = CopierResult.size;
18914c37757eSNguyen Trung Khanh         // did NDIS ask us to compute CS?
18924c37757eSNguyen Trung Khanh         if ((flags & (pcrTcpChecksum | pcrUdpChecksum | pcrIpChecksum)) != 0)
18934c37757eSNguyen Trung Khanh         {
18944c37757eSNguyen Trung Khanh             // we asked
18954c37757eSNguyen Trung Khanh             unsigned short addPriorityLen = (pParams->flags & pcrPriorityTag) ? ETH_PRIORITY_HEADER_SIZE : 0;
18964c37757eSNguyen Trung Khanh             PVOID ipPacket = RtlOffsetToPointer(
18974c37757eSNguyen Trung Khanh                 pBuffersDescriptor->DataInfo.Virtual, pContext->Offload.ipHeaderOffset + addPriorityLen);
18984c37757eSNguyen Trung Khanh             ULONG ipPacketLength = CopierResult.size - pContext->Offload.ipHeaderOffset - addPriorityLen;
18994c37757eSNguyen Trung Khanh             if (!pParams->tcpHeaderOffset &&
19004c37757eSNguyen Trung Khanh                 (flags & (pcrTcpChecksum | pcrUdpChecksum)) )
19014c37757eSNguyen Trung Khanh             {
19024c37757eSNguyen Trung Khanh                 pParams->tcpHeaderOffset = QueryTcpHeaderOffset(
19034c37757eSNguyen Trung Khanh                     pBuffersDescriptor->DataInfo.Virtual,
19044c37757eSNguyen Trung Khanh                     pContext->Offload.ipHeaderOffset + addPriorityLen,
19054c37757eSNguyen Trung Khanh                     ipPacketLength);
19064c37757eSNguyen Trung Khanh             }
19074c37757eSNguyen Trung Khanh             else
19084c37757eSNguyen Trung Khanh             {
19094c37757eSNguyen Trung Khanh                 pParams->tcpHeaderOffset += addPriorityLen;
19104c37757eSNguyen Trung Khanh             }
19114c37757eSNguyen Trung Khanh 
19124c37757eSNguyen Trung Khanh             if (pContext->bDoHardwareChecksum)
19134c37757eSNguyen Trung Khanh             {
19144c37757eSNguyen Trung Khanh                 if (flags & (pcrTcpChecksum | pcrUdpChecksum))
19154c37757eSNguyen Trung Khanh                 {
19164c37757eSNguyen Trung Khanh                     // hardware offload
19174c37757eSNguyen Trung Khanh                     virtio_net_hdr_basic *pvnh = (virtio_net_hdr_basic *)pBuffersDescriptor->HeaderInfo.Virtual;
19184c37757eSNguyen Trung Khanh                     pvnh->csum_start = (USHORT)pParams->tcpHeaderOffset;
19194c37757eSNguyen Trung Khanh                     pvnh->csum_offset = (flags & pcrTcpChecksum) ? TCP_CHECKSUM_OFFSET : UDP_CHECKSUM_OFFSET;
19204c37757eSNguyen Trung Khanh                     pvnh->flags |= VIRTIO_NET_HDR_F_NEEDS_CSUM;
19214c37757eSNguyen Trung Khanh                 }
19224c37757eSNguyen Trung Khanh                 if (flags & (pcrIpChecksum))
19234c37757eSNguyen Trung Khanh                 {
19244c37757eSNguyen Trung Khanh                     ParaNdis_CheckSumVerify(
19254c37757eSNguyen Trung Khanh                         ipPacket,
19264c37757eSNguyen Trung Khanh                         ipPacketLength,
19274c37757eSNguyen Trung Khanh                         pcrIpChecksum | pcrFixIPChecksum,
19284c37757eSNguyen Trung Khanh                         __FUNCTION__);
19294c37757eSNguyen Trung Khanh                 }
19304c37757eSNguyen Trung Khanh             }
19314c37757eSNguyen Trung Khanh             else if (CopierResult.size > pContext->Offload.ipHeaderOffset)
19324c37757eSNguyen Trung Khanh             {
19334c37757eSNguyen Trung Khanh                 ULONG csFlags = 0;
19344c37757eSNguyen Trung Khanh                 if (flags & pcrIpChecksum) csFlags |= pcrIpChecksum | pcrFixIPChecksum;
19354c37757eSNguyen Trung Khanh                 if (flags & (pcrTcpChecksum | pcrUdpChecksum)) csFlags |= pcrTcpChecksum | pcrUdpChecksum| pcrFixXxpChecksum;
19364c37757eSNguyen Trung Khanh                 // software offload
19374c37757eSNguyen Trung Khanh                 ParaNdis_CheckSumVerify(
19384c37757eSNguyen Trung Khanh                     ipPacket,
19394c37757eSNguyen Trung Khanh                     ipPacketLength,
19404c37757eSNguyen Trung Khanh                     csFlags,
19414c37757eSNguyen Trung Khanh                     __FUNCTION__);
19424c37757eSNguyen Trung Khanh             }
19434c37757eSNguyen Trung Khanh             else
19444c37757eSNguyen Trung Khanh             {
19454c37757eSNguyen Trung Khanh                 DPrintf(0, ("[%s] ERROR: Invalid buffer size for offload!", __FUNCTION__));
19464c37757eSNguyen Trung Khanh                 result.size = 0;
19474c37757eSNguyen Trung Khanh                 result.error = cpeInternalError;
19484c37757eSNguyen Trung Khanh             }
19494c37757eSNguyen Trung Khanh         }
19504c37757eSNguyen Trung Khanh         pContext->nofFreeTxDescriptors--;
19514c37757eSNguyen Trung Khanh         if (result.size)
19524c37757eSNguyen Trung Khanh         {
19534c37757eSNguyen Trung Khanh             eInspectedPacketType packetType;
19544c37757eSNguyen Trung Khanh             packetType = QueryPacketType(pBuffersDescriptor->DataInfo.Virtual);
19554c37757eSNguyen Trung Khanh             DebugDumpPacket("sending", pBuffersDescriptor->DataInfo.Virtual, 3);
19564c37757eSNguyen Trung Khanh 
19574c37757eSNguyen Trung Khanh             pBuffersDescriptor->nofUsedBuffers = nRequiredHardwareBuffers;
19584c37757eSNguyen Trung Khanh             pContext->nofFreeHardwareBuffers -= nRequiredHardwareBuffers;
19594c37757eSNguyen Trung Khanh             if (pContext->minFreeHardwareBuffers > pContext->nofFreeHardwareBuffers)
19604c37757eSNguyen Trung Khanh                 pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers;
19614c37757eSNguyen Trung Khanh             if (0 > virtqueue_add_buf(
19624c37757eSNguyen Trung Khanh                 pContext->NetSendQueue,
19634c37757eSNguyen Trung Khanh                 sg,
19644c37757eSNguyen Trung Khanh                 2,
19654c37757eSNguyen Trung Khanh                 0,
19664c37757eSNguyen Trung Khanh                 pBuffersDescriptor,
19674c37757eSNguyen Trung Khanh                 NULL,
19684c37757eSNguyen Trung Khanh                 0
19694c37757eSNguyen Trung Khanh                 ))
19704c37757eSNguyen Trung Khanh             {
19714c37757eSNguyen Trung Khanh                 pBuffersDescriptor->nofUsedBuffers = 0;
19724c37757eSNguyen Trung Khanh                 pContext->nofFreeHardwareBuffers += nRequiredHardwareBuffers;
19734c37757eSNguyen Trung Khanh                 result.error = cpeInternalError;
19744c37757eSNguyen Trung Khanh                 result.size  = 0;
19754c37757eSNguyen Trung Khanh                 DPrintf(0, ("[%s] Unexpected ERROR adding buffer to TX engine!..", __FUNCTION__));
19764c37757eSNguyen Trung Khanh             }
19774c37757eSNguyen Trung Khanh             else
19784c37757eSNguyen Trung Khanh             {
19794c37757eSNguyen Trung Khanh                 DPrintf(2, ("[%s] Submitted %d buffers (%d bytes), avail %d desc, %d bufs",
19804c37757eSNguyen Trung Khanh                     __FUNCTION__, nRequiredHardwareBuffers, result.size,
19814c37757eSNguyen Trung Khanh                     pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers
19824c37757eSNguyen Trung Khanh                 ));
19834c37757eSNguyen Trung Khanh             }
19844c37757eSNguyen Trung Khanh             if (result.error != cpeOK)
19854c37757eSNguyen Trung Khanh             {
19864c37757eSNguyen Trung Khanh                 InsertTailList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry);
19874c37757eSNguyen Trung Khanh                 pContext->nofFreeTxDescriptors++;
19884c37757eSNguyen Trung Khanh             }
19894c37757eSNguyen Trung Khanh             else
19904c37757eSNguyen Trung Khanh             {
19914c37757eSNguyen Trung Khanh                 ULONG reportedSize = pParams->ulDataSize;
19924c37757eSNguyen Trung Khanh                 pBuffersDescriptor->ReferenceValue = pParams->ReferenceValue;
19934c37757eSNguyen Trung Khanh                 InsertTailList(&pContext->NetSendBuffersInUse, &pBuffersDescriptor->listEntry);
19944c37757eSNguyen Trung Khanh                 pContext->Statistics.ifHCOutOctets += reportedSize;
19954c37757eSNguyen Trung Khanh                 switch (packetType)
19964c37757eSNguyen Trung Khanh                 {
19974c37757eSNguyen Trung Khanh                     case iptBroadcast:
19984c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCOutBroadcastOctets += reportedSize;
19994c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCOutBroadcastPkts++;
20004c37757eSNguyen Trung Khanh                         break;
20014c37757eSNguyen Trung Khanh                     case iptMulticast:
20024c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCOutMulticastOctets += reportedSize;
20034c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCOutMulticastPkts++;
20044c37757eSNguyen Trung Khanh                         break;
20054c37757eSNguyen Trung Khanh                     default:
20064c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCOutUcastOctets += reportedSize;
20074c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCOutUcastPkts++;
20084c37757eSNguyen Trung Khanh                         break;
20094c37757eSNguyen Trung Khanh                 }
20104c37757eSNguyen Trung Khanh             }
20114c37757eSNguyen Trung Khanh         }
20124c37757eSNguyen Trung Khanh         else
20134c37757eSNguyen Trung Khanh         {
20144c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] Unexpected ERROR in copying packet data! Continue...", __FUNCTION__));
20154c37757eSNguyen Trung Khanh             InsertTailList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry);
20164c37757eSNguyen Trung Khanh             pContext->nofFreeTxDescriptors++;
20174c37757eSNguyen Trung Khanh             // the buffer is not copied and the callback will not be called
20184c37757eSNguyen Trung Khanh             result.error = cpeInternalError;
20194c37757eSNguyen Trung Khanh         }
20204c37757eSNguyen Trung Khanh     }
20214c37757eSNguyen Trung Khanh 
20224c37757eSNguyen Trung Khanh     return result;
20234c37757eSNguyen Trung Khanh }
20244c37757eSNguyen Trung Khanh 
ShallPassPacket(PARANDIS_ADAPTER * pContext,PVOID address,UINT len,eInspectedPacketType * pType)20254c37757eSNguyen Trung Khanh static ULONG ShallPassPacket(PARANDIS_ADAPTER *pContext, PVOID address, UINT len, eInspectedPacketType *pType)
20264c37757eSNguyen Trung Khanh {
20274c37757eSNguyen Trung Khanh     ULONG b;
20284c37757eSNguyen Trung Khanh     if (len <= sizeof(ETH_HEADER)) return FALSE;
20294c37757eSNguyen Trung Khanh     if (len > pContext->MaxPacketSize.nMaxFullSizeHwRx) return FALSE;
20304c37757eSNguyen Trung Khanh     if (len > pContext->MaxPacketSize.nMaxFullSizeOS && !ETH_HAS_PRIO_HEADER(address)) return FALSE;
20314c37757eSNguyen Trung Khanh     *pType = QueryPacketType(address);
20324c37757eSNguyen Trung Khanh     if (pContext->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)  return TRUE;
20334c37757eSNguyen Trung Khanh 
20344c37757eSNguyen Trung Khanh     switch(*pType)
20354c37757eSNguyen Trung Khanh     {
20364c37757eSNguyen Trung Khanh         case iptBroadcast:
20374c37757eSNguyen Trung Khanh             b = pContext->PacketFilter & NDIS_PACKET_TYPE_BROADCAST;
20384c37757eSNguyen Trung Khanh             break;
20394c37757eSNguyen Trung Khanh         case iptMulticast:
20404c37757eSNguyen Trung Khanh             b = pContext->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST;
20414c37757eSNguyen Trung Khanh             if (!b && (pContext->PacketFilter & NDIS_PACKET_TYPE_MULTICAST))
20424c37757eSNguyen Trung Khanh             {
20434c37757eSNguyen Trung Khanh                 UINT i, n = pContext->MulticastData.nofMulticastEntries * ETH_LENGTH_OF_ADDRESS;
20444c37757eSNguyen Trung Khanh                 b = 1;
20454c37757eSNguyen Trung Khanh                 for (i = 0; b && i < n; i += ETH_LENGTH_OF_ADDRESS)
20464c37757eSNguyen Trung Khanh                 {
20474c37757eSNguyen Trung Khanh                     ETH_COMPARE_NETWORK_ADDRESSES((PUCHAR)address, &pContext->MulticastData.MulticastList[i], &b)
20484c37757eSNguyen Trung Khanh                 }
20494c37757eSNguyen Trung Khanh                 b = !b;
20504c37757eSNguyen Trung Khanh             }
20514c37757eSNguyen Trung Khanh             break;
20524c37757eSNguyen Trung Khanh         default:
20534c37757eSNguyen Trung Khanh             ETH_COMPARE_NETWORK_ADDRESSES((PUCHAR)address, pContext->CurrentMacAddress, &b);
20544c37757eSNguyen Trung Khanh             b = !b && (pContext->PacketFilter & NDIS_PACKET_TYPE_DIRECTED);
20554c37757eSNguyen Trung Khanh             break;
20564c37757eSNguyen Trung Khanh     }
20574c37757eSNguyen Trung Khanh     if (!b)
20584c37757eSNguyen Trung Khanh     {
20594c37757eSNguyen Trung Khanh         pContext->extraStatistics.framesFilteredOut++;
20604c37757eSNguyen Trung Khanh     }
20614c37757eSNguyen Trung Khanh     return b;
20624c37757eSNguyen Trung Khanh }
20634c37757eSNguyen Trung Khanh 
20644c37757eSNguyen Trung Khanh void
ParaNdis_PadPacketReceived(PVOID pDataBuffer,PULONG pLength)20654c37757eSNguyen Trung Khanh ParaNdis_PadPacketReceived(PVOID pDataBuffer, PULONG pLength)
20664c37757eSNguyen Trung Khanh {
20674c37757eSNguyen Trung Khanh     // Ethernet standard declares minimal possible packet size
20684c37757eSNguyen Trung Khanh     // Packets smaller than that must be padded before transfer
20694c37757eSNguyen Trung Khanh     // Ethernet HW pads packets on transmit, however in our case
20704c37757eSNguyen Trung Khanh     // some packets do not travel over Ethernet but being routed
20714c37757eSNguyen Trung Khanh     // guest-to-guest by virtual switch.
20724c37757eSNguyen Trung Khanh     // In this case padding is not performed and we may
20734c37757eSNguyen Trung Khanh     // receive packet smaller than minimal allowed size. This is not
20744c37757eSNguyen Trung Khanh     // a problem for real life scenarios however WHQL/HCK contains
20754c37757eSNguyen Trung Khanh     // tests that check padding of received packets.
20764c37757eSNguyen Trung Khanh     // To make these tests happy we have to pad small packets on receive
20774c37757eSNguyen Trung Khanh 
20784c37757eSNguyen Trung Khanh     //NOTE: This function assumes that VLAN header has been already stripped out
20794c37757eSNguyen Trung Khanh 
20804c37757eSNguyen Trung Khanh     if(*pLength < ETH_MIN_PACKET_SIZE)
20814c37757eSNguyen Trung Khanh     {
20824c37757eSNguyen Trung Khanh         RtlZeroMemory(RtlOffsetToPointer(pDataBuffer, *pLength), ETH_MIN_PACKET_SIZE - *pLength);
20834c37757eSNguyen Trung Khanh         *pLength = ETH_MIN_PACKET_SIZE;
20844c37757eSNguyen Trung Khanh     }
20854c37757eSNguyen Trung Khanh }
20864c37757eSNguyen Trung Khanh 
20874c37757eSNguyen Trung Khanh /**********************************************************
20884c37757eSNguyen Trung Khanh Manages RX path, calling NDIS-specific procedure for packet indication
20894c37757eSNguyen Trung Khanh Parameters:
20904c37757eSNguyen Trung Khanh     context
20914c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_ProcessRxPath(PARANDIS_ADAPTER * pContext,ULONG ulMaxPacketsToIndicate)20924c37757eSNguyen Trung Khanh static UINT ParaNdis_ProcessRxPath(PARANDIS_ADAPTER *pContext, ULONG ulMaxPacketsToIndicate)
20934c37757eSNguyen Trung Khanh {
20944c37757eSNguyen Trung Khanh     pIONetDescriptor pBuffersDescriptor;
20954c37757eSNguyen Trung Khanh     UINT len, headerSize = pContext->nVirtioHeaderSize;
20964c37757eSNguyen Trung Khanh     eInspectedPacketType packetType = iptInvalid;
20974c37757eSNguyen Trung Khanh     UINT nReceived = 0, nRetrieved = 0, nReported = 0;
20984c37757eSNguyen Trung Khanh     tPacketIndicationType   *pBatchOfPackets;
20994c37757eSNguyen Trung Khanh     UINT                    maxPacketsInBatch = pContext->NetMaxReceiveBuffers;
21004c37757eSNguyen Trung Khanh     pBatchOfPackets = pContext->bBatchReceive ?
21014c37757eSNguyen Trung Khanh         ParaNdis_AllocateMemory(pContext, maxPacketsInBatch * sizeof(tPacketIndicationType)) : NULL;
21024c37757eSNguyen Trung Khanh     NdisAcquireSpinLock(&pContext->ReceiveLock);
21034c37757eSNguyen Trung Khanh     while ((nReported < ulMaxPacketsToIndicate) && NULL != (pBuffersDescriptor = virtqueue_get_buf(pContext->NetReceiveQueue, &len)))
21044c37757eSNguyen Trung Khanh     {
21054c37757eSNguyen Trung Khanh         PVOID pDataBuffer = RtlOffsetToPointer(pBuffersDescriptor->DataInfo.Virtual, pContext->bUseMergedBuffers ? pContext->nVirtioHeaderSize : 0);
21064c37757eSNguyen Trung Khanh         RemoveEntryList(&pBuffersDescriptor->listEntry);
21074c37757eSNguyen Trung Khanh         InsertTailList(&pContext->NetReceiveBuffersWaiting, &pBuffersDescriptor->listEntry);
21084c37757eSNguyen Trung Khanh         pContext->NetNofReceiveBuffers--;
21094c37757eSNguyen Trung Khanh         nRetrieved++;
21104c37757eSNguyen Trung Khanh         DPrintf(2, ("[%s] retrieved header+%d b.", __FUNCTION__, len - headerSize));
21114c37757eSNguyen Trung Khanh         DebugDumpPacket("receive", pDataBuffer, 3);
21124c37757eSNguyen Trung Khanh 
21134c37757eSNguyen Trung Khanh         if( !pContext->bSurprizeRemoved &&
21144c37757eSNguyen Trung Khanh             ShallPassPacket(pContext, pDataBuffer, len - headerSize, &packetType) &&
21154c37757eSNguyen Trung Khanh             pContext->ReceiveState == srsEnabled &&
21164c37757eSNguyen Trung Khanh             pContext->bConnected)
21174c37757eSNguyen Trung Khanh         {
21184c37757eSNguyen Trung Khanh             BOOLEAN b = FALSE;
21194c37757eSNguyen Trung Khanh             ULONG length = len - headerSize;
21204c37757eSNguyen Trung Khanh             if (!pBatchOfPackets)
21214c37757eSNguyen Trung Khanh             {
21224c37757eSNguyen Trung Khanh                 NdisReleaseSpinLock(&pContext->ReceiveLock);
21234c37757eSNguyen Trung Khanh                 b = NULL != ParaNdis_IndicateReceivedPacket(
21244c37757eSNguyen Trung Khanh                     pContext,
21254c37757eSNguyen Trung Khanh                     pDataBuffer,
21264c37757eSNguyen Trung Khanh                     &length,
21274c37757eSNguyen Trung Khanh                     FALSE,
21284c37757eSNguyen Trung Khanh                     pBuffersDescriptor);
21294c37757eSNguyen Trung Khanh                 NdisAcquireSpinLock(&pContext->ReceiveLock);
21304c37757eSNguyen Trung Khanh             }
21314c37757eSNguyen Trung Khanh             else
21324c37757eSNguyen Trung Khanh             {
21334c37757eSNguyen Trung Khanh                 tPacketIndicationType packet;
21344c37757eSNguyen Trung Khanh                 packet = ParaNdis_IndicateReceivedPacket(
21354c37757eSNguyen Trung Khanh                     pContext,
21364c37757eSNguyen Trung Khanh                     pDataBuffer,
21374c37757eSNguyen Trung Khanh                     &length,
21384c37757eSNguyen Trung Khanh                     TRUE,
21394c37757eSNguyen Trung Khanh                     pBuffersDescriptor);
21404c37757eSNguyen Trung Khanh                 b = packet != NULL;
21414c37757eSNguyen Trung Khanh                 if (b) pBatchOfPackets[nReceived] = packet;
21424c37757eSNguyen Trung Khanh             }
21434c37757eSNguyen Trung Khanh             if (!b)
21444c37757eSNguyen Trung Khanh             {
21454c37757eSNguyen Trung Khanh                 pContext->ReuseBufferProc(pContext, pBuffersDescriptor);
21464c37757eSNguyen Trung Khanh                 //only possible reason for that is unexpected Vlan tag
21474c37757eSNguyen Trung Khanh                 //shall I count it as error?
21484c37757eSNguyen Trung Khanh                 pContext->Statistics.ifInErrors++;
21494c37757eSNguyen Trung Khanh                 pContext->Statistics.ifInDiscards++;
21504c37757eSNguyen Trung Khanh             }
21514c37757eSNguyen Trung Khanh             else
21524c37757eSNguyen Trung Khanh             {
21534c37757eSNguyen Trung Khanh                 nReceived++;
21544c37757eSNguyen Trung Khanh                 nReported++;
21554c37757eSNguyen Trung Khanh                 pContext->Statistics.ifHCInOctets += length;
21564c37757eSNguyen Trung Khanh                 switch(packetType)
21574c37757eSNguyen Trung Khanh                 {
21584c37757eSNguyen Trung Khanh                     case iptBroadcast:
21594c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCInBroadcastPkts++;
21604c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCInBroadcastOctets += length;
21614c37757eSNguyen Trung Khanh                         break;
21624c37757eSNguyen Trung Khanh                     case iptMulticast:
21634c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCInMulticastPkts++;
21644c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCInMulticastOctets += length;
21654c37757eSNguyen Trung Khanh                         break;
21664c37757eSNguyen Trung Khanh                     default:
21674c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCInUcastPkts++;
21684c37757eSNguyen Trung Khanh                         pContext->Statistics.ifHCInUcastOctets += length;
21694c37757eSNguyen Trung Khanh                         break;
21704c37757eSNguyen Trung Khanh                 }
21714c37757eSNguyen Trung Khanh                 if (pBatchOfPackets && nReceived == maxPacketsInBatch)
21724c37757eSNguyen Trung Khanh                 {
21734c37757eSNguyen Trung Khanh                     DPrintf(1, ("[%s] received %d buffers of max %d", __FUNCTION__, nReceived, ulMaxPacketsToIndicate));
21744c37757eSNguyen Trung Khanh                     NdisReleaseSpinLock(&pContext->ReceiveLock);
21754c37757eSNguyen Trung Khanh                     ParaNdis_IndicateReceivedBatch(pContext, pBatchOfPackets, nReceived);
21764c37757eSNguyen Trung Khanh                     NdisAcquireSpinLock(&pContext->ReceiveLock);
21774c37757eSNguyen Trung Khanh                     nReceived = 0;
21784c37757eSNguyen Trung Khanh                 }
21794c37757eSNguyen Trung Khanh             }
21804c37757eSNguyen Trung Khanh         }
21814c37757eSNguyen Trung Khanh         else
21824c37757eSNguyen Trung Khanh         {
21834c37757eSNguyen Trung Khanh             // reuse packet, there is no data or the RX is suppressed
21844c37757eSNguyen Trung Khanh             pContext->ReuseBufferProc(pContext, pBuffersDescriptor);
21854c37757eSNguyen Trung Khanh         }
21864c37757eSNguyen Trung Khanh     }
21874c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopReceiveStat, NULL, nRetrieved, nReported, pContext->NetNofReceiveBuffers);
21884c37757eSNguyen Trung Khanh     NdisReleaseSpinLock(&pContext->ReceiveLock);
21894c37757eSNguyen Trung Khanh     if (nReceived && pBatchOfPackets)
21904c37757eSNguyen Trung Khanh     {
21914c37757eSNguyen Trung Khanh         DPrintf(1, ("[%s]%d: received %d buffers of max %d", __FUNCTION__, KeGetCurrentProcessorNumber(), nReceived, ulMaxPacketsToIndicate));
21924c37757eSNguyen Trung Khanh         ParaNdis_IndicateReceivedBatch(pContext, pBatchOfPackets, nReceived);
21934c37757eSNguyen Trung Khanh     }
21944c37757eSNguyen Trung Khanh     if (pBatchOfPackets) NdisFreeMemory(pBatchOfPackets, 0, 0);
21954c37757eSNguyen Trung Khanh     return nReported;
21964c37757eSNguyen Trung Khanh }
21974c37757eSNguyen Trung Khanh 
ParaNdis_ReportLinkStatus(PARANDIS_ADAPTER * pContext,BOOLEAN bForce)21984c37757eSNguyen Trung Khanh void ParaNdis_ReportLinkStatus(PARANDIS_ADAPTER *pContext, BOOLEAN bForce)
21994c37757eSNguyen Trung Khanh {
22004c37757eSNguyen Trung Khanh     BOOLEAN bConnected = TRUE;
22014c37757eSNguyen Trung Khanh     if (pContext->bLinkDetectSupported)
22024c37757eSNguyen Trung Khanh     {
22034c37757eSNguyen Trung Khanh         USHORT linkStatus = 0;
22044c37757eSNguyen Trung Khanh         USHORT offset = sizeof(pContext->CurrentMacAddress);
22054c37757eSNguyen Trung Khanh         // link changed
22064c37757eSNguyen Trung Khanh         virtio_get_config(&pContext->IODevice, offset, &linkStatus, sizeof(linkStatus));
22074c37757eSNguyen Trung Khanh         bConnected = (linkStatus & VIRTIO_NET_S_LINK_UP) != 0;
22084c37757eSNguyen Trung Khanh     }
22094c37757eSNguyen Trung Khanh     ParaNdis_IndicateConnect(pContext, bConnected, bForce);
22104c37757eSNguyen Trung Khanh }
22114c37757eSNguyen Trung Khanh 
RestartQueueSynchronously(tSynchronizedContext * SyncContext)2212*dc6dfbf6SDmitry Borisov static BOOLEAN NTAPI RestartQueueSynchronously(tSynchronizedContext *SyncContext)
22134c37757eSNguyen Trung Khanh {
22144c37757eSNguyen Trung Khanh     struct virtqueue * _vq = (struct virtqueue *) SyncContext->Parameter;
22154c37757eSNguyen Trung Khanh     bool res = true;
22164c37757eSNguyen Trung Khanh     if (!virtqueue_enable_cb(_vq))
22174c37757eSNguyen Trung Khanh     {
22184c37757eSNguyen Trung Khanh         virtqueue_disable_cb(_vq);
22194c37757eSNguyen Trung Khanh         res = false;
22204c37757eSNguyen Trung Khanh     }
22214c37757eSNguyen Trung Khanh 
22224c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(SyncContext->pContext, hopDPC, (PVOID)SyncContext->Parameter, 0x20, res, 0);
22234c37757eSNguyen Trung Khanh     return !res;
22244c37757eSNguyen Trung Khanh }
22254c37757eSNguyen Trung Khanh /**********************************************************
22264c37757eSNguyen Trung Khanh DPC implementation, common for both NDIS
22274c37757eSNguyen Trung Khanh Parameters:
22284c37757eSNguyen Trung Khanh     context
22294c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_DPCWorkBody(PARANDIS_ADAPTER * pContext,ULONG ulMaxPacketsToIndicate)22304c37757eSNguyen Trung Khanh ULONG ParaNdis_DPCWorkBody(PARANDIS_ADAPTER *pContext, ULONG ulMaxPacketsToIndicate)
22314c37757eSNguyen Trung Khanh {
22324c37757eSNguyen Trung Khanh     ULONG stillRequiresProcessing = 0;
22334c37757eSNguyen Trung Khanh     ULONG interruptSources;
22344c37757eSNguyen Trung Khanh     UINT uIndicatedRXPackets = 0;
22354c37757eSNguyen Trung Khanh     UINT numOfPacketsToIndicate = min(ulMaxPacketsToIndicate, pContext->uNumberOfHandledRXPacketsInDPC);
22364c37757eSNguyen Trung Khanh 
22374c37757eSNguyen Trung Khanh     DEBUG_ENTRY(5);
22384c37757eSNguyen Trung Khanh     if (pContext->bEnableInterruptHandlingDPC)
22394c37757eSNguyen Trung Khanh     {
22404c37757eSNguyen Trung Khanh         InterlockedIncrement(&pContext->counterDPCInside);
22414c37757eSNguyen Trung Khanh         if (pContext->bEnableInterruptHandlingDPC)
22424c37757eSNguyen Trung Khanh         {
22434c37757eSNguyen Trung Khanh             BOOLEAN bDoKick = FALSE;
22444c37757eSNguyen Trung Khanh 
22454c37757eSNguyen Trung Khanh             InterlockedExchange(&pContext->bDPCInactive, 0);
22464c37757eSNguyen Trung Khanh             interruptSources = InterlockedExchange(&pContext->InterruptStatus, 0);
22474c37757eSNguyen Trung Khanh             ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)1, interruptSources, 0, 0);
22484c37757eSNguyen Trung Khanh             if ((interruptSources & isControl) && pContext->bLinkDetectSupported)
22494c37757eSNguyen Trung Khanh             {
22504c37757eSNguyen Trung Khanh                 ParaNdis_ReportLinkStatus(pContext, FALSE);
22514c37757eSNguyen Trung Khanh             }
22524c37757eSNguyen Trung Khanh             if (interruptSources & isTransmit)
22534c37757eSNguyen Trung Khanh             {
22544c37757eSNguyen Trung Khanh                 bDoKick = ParaNdis_ProcessTx(pContext, TRUE, TRUE);
22554c37757eSNguyen Trung Khanh             }
22564c37757eSNguyen Trung Khanh             if (interruptSources & isReceive)
22574c37757eSNguyen Trung Khanh             {
22584c37757eSNguyen Trung Khanh                 int nRestartResult = 0;
22594c37757eSNguyen Trung Khanh 
22604c37757eSNguyen Trung Khanh                 do
22614c37757eSNguyen Trung Khanh                 {
22624c37757eSNguyen Trung Khanh                     LONG rxActive = InterlockedIncrement(&pContext->dpcReceiveActive);
22634c37757eSNguyen Trung Khanh                     if (rxActive == 1)
22644c37757eSNguyen Trung Khanh                     {
22654c37757eSNguyen Trung Khanh                         uIndicatedRXPackets += ParaNdis_ProcessRxPath(pContext, numOfPacketsToIndicate - uIndicatedRXPackets);
22664c37757eSNguyen Trung Khanh                         InterlockedDecrement(&pContext->dpcReceiveActive);
22674c37757eSNguyen Trung Khanh                         NdisAcquireSpinLock(&pContext->ReceiveLock);
22684c37757eSNguyen Trung Khanh                         nRestartResult = ParaNdis_SynchronizeWithInterrupt(
22694c37757eSNguyen Trung Khanh                             pContext, pContext->ulRxMessage, RestartQueueSynchronously, pContext->NetReceiveQueue);
22704c37757eSNguyen Trung Khanh                         ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)3, nRestartResult, 0, 0);
22714c37757eSNguyen Trung Khanh                         NdisReleaseSpinLock(&pContext->ReceiveLock);
22724c37757eSNguyen Trung Khanh                         DPrintf(nRestartResult ? 2 : 6, ("[%s] queue restarted%s", __FUNCTION__, nRestartResult ? "(Rerun)" : "(Done)"));
22734c37757eSNguyen Trung Khanh 
22744c37757eSNguyen Trung Khanh                         if (uIndicatedRXPackets < numOfPacketsToIndicate)
22754c37757eSNguyen Trung Khanh                         {
22764c37757eSNguyen Trung Khanh 
22774c37757eSNguyen Trung Khanh                         }
22784c37757eSNguyen Trung Khanh                         else if (uIndicatedRXPackets == numOfPacketsToIndicate)
22794c37757eSNguyen Trung Khanh                         {
22804c37757eSNguyen Trung Khanh                             DPrintf(1, ("[%s] Breaking Rx loop after %d indications", __FUNCTION__, uIndicatedRXPackets));
22814c37757eSNguyen Trung Khanh                             ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)4, nRestartResult, 0, 0);
22824c37757eSNguyen Trung Khanh                             break;
22834c37757eSNguyen Trung Khanh                         }
22844c37757eSNguyen Trung Khanh                         else
22854c37757eSNguyen Trung Khanh                         {
22864c37757eSNguyen Trung Khanh                             DPrintf(0, ("[%s] Glitch found: %d allowed, %d indicated", __FUNCTION__, numOfPacketsToIndicate, uIndicatedRXPackets));
22874c37757eSNguyen Trung Khanh                             ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)6, nRestartResult, 0, 0);
22884c37757eSNguyen Trung Khanh                         }
22894c37757eSNguyen Trung Khanh                     }
22904c37757eSNguyen Trung Khanh                     else
22914c37757eSNguyen Trung Khanh                     {
22924c37757eSNguyen Trung Khanh                         InterlockedDecrement(&pContext->dpcReceiveActive);
22934c37757eSNguyen Trung Khanh                         if (!nRestartResult)
22944c37757eSNguyen Trung Khanh                         {
22954c37757eSNguyen Trung Khanh                             NdisAcquireSpinLock(&pContext->ReceiveLock);
22964c37757eSNguyen Trung Khanh                             nRestartResult = ParaNdis_SynchronizeWithInterrupt(
22974c37757eSNguyen Trung Khanh                                 pContext, pContext->ulRxMessage, RestartQueueSynchronously, pContext->NetReceiveQueue);
22984c37757eSNguyen Trung Khanh                             ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)5, nRestartResult, 0, 0);
22994c37757eSNguyen Trung Khanh                             NdisReleaseSpinLock(&pContext->ReceiveLock);
23004c37757eSNguyen Trung Khanh                         }
23014c37757eSNguyen Trung Khanh                         DPrintf(1, ("[%s] Skip Rx processing no.%d", __FUNCTION__, rxActive));
23024c37757eSNguyen Trung Khanh                         break;
23034c37757eSNguyen Trung Khanh                     }
23044c37757eSNguyen Trung Khanh                 } while (nRestartResult);
23054c37757eSNguyen Trung Khanh 
23064c37757eSNguyen Trung Khanh                 if (nRestartResult) stillRequiresProcessing |= isReceive;
23074c37757eSNguyen Trung Khanh             }
23084c37757eSNguyen Trung Khanh 
23094c37757eSNguyen Trung Khanh             if (interruptSources & isTransmit)
23104c37757eSNguyen Trung Khanh             {
23114c37757eSNguyen Trung Khanh                 NdisAcquireSpinLock(&pContext->SendLock);
23124c37757eSNguyen Trung Khanh                 if (ParaNdis_SynchronizeWithInterrupt(pContext, pContext->ulTxMessage, RestartQueueSynchronously, pContext->NetSendQueue))
23134c37757eSNguyen Trung Khanh                     stillRequiresProcessing |= isTransmit;
23144c37757eSNguyen Trung Khanh                 if(bDoKick)
23154c37757eSNguyen Trung Khanh                 {
23164c37757eSNguyen Trung Khanh #ifdef PARANDIS_TEST_TX_KICK_ALWAYS
23174c37757eSNguyen Trung Khanh                     virtqueue_kick_always(pContext->NetSendQueue);
23184c37757eSNguyen Trung Khanh #else
23194c37757eSNguyen Trung Khanh                     virtqueue_kick(pContext->NetSendQueue);
23204c37757eSNguyen Trung Khanh #endif
23214c37757eSNguyen Trung Khanh                 }
23224c37757eSNguyen Trung Khanh                 NdisReleaseSpinLock(&pContext->SendLock);
23234c37757eSNguyen Trung Khanh             }
23244c37757eSNguyen Trung Khanh         }
23254c37757eSNguyen Trung Khanh         InterlockedDecrement(&pContext->counterDPCInside);
23264c37757eSNguyen Trung Khanh         ParaNdis_DebugHistory(pContext, hopDPC, NULL, stillRequiresProcessing, pContext->nofFreeHardwareBuffers, pContext->nofFreeTxDescriptors);
23274c37757eSNguyen Trung Khanh     }
23284c37757eSNguyen Trung Khanh     return stillRequiresProcessing;
23294c37757eSNguyen Trung Khanh }
23304c37757eSNguyen Trung Khanh 
23314c37757eSNguyen Trung Khanh /**********************************************************
23324c37757eSNguyen Trung Khanh Periodically called procedure, checking dpc activity
23334c37757eSNguyen Trung Khanh If DPC are not running, it does exactly the same that the DPC
23344c37757eSNguyen Trung Khanh Parameters:
23354c37757eSNguyen Trung Khanh     context
23364c37757eSNguyen Trung Khanh ***********************************************************/
CheckRunningDpc(PARANDIS_ADAPTER * pContext)23374c37757eSNguyen Trung Khanh static BOOLEAN CheckRunningDpc(PARANDIS_ADAPTER *pContext)
23384c37757eSNguyen Trung Khanh {
23394c37757eSNguyen Trung Khanh     BOOLEAN bStopped;
23404c37757eSNguyen Trung Khanh     BOOLEAN bReportHang = FALSE;
23414c37757eSNguyen Trung Khanh     bStopped = 0 != InterlockedExchange(&pContext->bDPCInactive, TRUE);
23424c37757eSNguyen Trung Khanh 
23434c37757eSNguyen Trung Khanh     if (bStopped)
23444c37757eSNguyen Trung Khanh     {
23454c37757eSNguyen Trung Khanh         pContext->nDetectedInactivity++;
23464c37757eSNguyen Trung Khanh         if (pContext->nEnableDPCChecker)
23474c37757eSNguyen Trung Khanh         {
23484c37757eSNguyen Trung Khanh             if (pContext->NetTxPacketsToReturn)
23494c37757eSNguyen Trung Khanh             {
23504c37757eSNguyen Trung Khanh                 DPrintf(0, ("[%s] - NO ACTIVITY!", __FUNCTION__));
23514c37757eSNguyen Trung Khanh                 if (!pContext->Limits.nPrintDiagnostic) PrintStatistics(pContext);
23524c37757eSNguyen Trung Khanh                 if (pContext->nEnableDPCChecker > 1)
23534c37757eSNguyen Trung Khanh                 {
23544c37757eSNguyen Trung Khanh                     int isrStatus1, isrStatus2;
23554c37757eSNguyen Trung Khanh                     isrStatus1 = virtio_read_isr_status(&pContext->IODevice);
23564c37757eSNguyen Trung Khanh                     isrStatus2 = virtio_read_isr_status(&pContext->IODevice);
23574c37757eSNguyen Trung Khanh                     if (isrStatus1 || isrStatus2)
23584c37757eSNguyen Trung Khanh                     {
23594c37757eSNguyen Trung Khanh                         DPrintf(0, ("WARNING: Interrupt status %d=>%d", isrStatus1, isrStatus2));
23604c37757eSNguyen Trung Khanh                     }
23614c37757eSNguyen Trung Khanh                 }
23624c37757eSNguyen Trung Khanh                 // simulateDPC
23634c37757eSNguyen Trung Khanh                 InterlockedOr(&pContext->InterruptStatus, isAny);
23644c37757eSNguyen Trung Khanh                 ParaNdis_DPCWorkBody(pContext, PARANDIS_UNLIMITED_PACKETS_TO_INDICATE);
23654c37757eSNguyen Trung Khanh             }
23664c37757eSNguyen Trung Khanh         }
23674c37757eSNguyen Trung Khanh     }
23684c37757eSNguyen Trung Khanh     else
23694c37757eSNguyen Trung Khanh     {
23704c37757eSNguyen Trung Khanh         pContext->nDetectedInactivity = 0;
23714c37757eSNguyen Trung Khanh     }
23724c37757eSNguyen Trung Khanh 
23734c37757eSNguyen Trung Khanh     NdisAcquireSpinLock(&pContext->SendLock);
23744c37757eSNguyen Trung Khanh     if (pContext->nofFreeHardwareBuffers != pContext->maxFreeHardwareBuffers)
23754c37757eSNguyen Trung Khanh     {
23764c37757eSNguyen Trung Khanh         if (pContext->nDetectedStoppedTx++ > 1)
23774c37757eSNguyen Trung Khanh         {
23784c37757eSNguyen Trung Khanh             DPrintf(0, ("[%s] - Suspicious Tx inactivity (%d)!", __FUNCTION__, pContext->nofFreeHardwareBuffers));
23794c37757eSNguyen Trung Khanh             //bReportHang = TRUE;
23804c37757eSNguyen Trung Khanh #ifdef DBG_USE_VIRTIO_PCI_ISR_FOR_HOST_REPORT
23814c37757eSNguyen Trung Khanh             WriteVirtIODeviceByte(pContext->IODevice.isr, 0);
23824c37757eSNguyen Trung Khanh #endif
23834c37757eSNguyen Trung Khanh         }
23844c37757eSNguyen Trung Khanh     }
23854c37757eSNguyen Trung Khanh     NdisReleaseSpinLock(&pContext->SendLock);
23864c37757eSNguyen Trung Khanh 
23874c37757eSNguyen Trung Khanh 
23884c37757eSNguyen Trung Khanh     if (pContext->Limits.nPrintDiagnostic &&
23894c37757eSNguyen Trung Khanh         ++pContext->Counters.nPrintDiagnostic >= pContext->Limits.nPrintDiagnostic)
23904c37757eSNguyen Trung Khanh     {
23914c37757eSNguyen Trung Khanh         pContext->Counters.nPrintDiagnostic = 0;
23924c37757eSNguyen Trung Khanh         // todo - collect more and put out optionally
23934c37757eSNguyen Trung Khanh         PrintStatistics(pContext);
23944c37757eSNguyen Trung Khanh     }
23954c37757eSNguyen Trung Khanh 
23964c37757eSNguyen Trung Khanh     if (pContext->Statistics.ifHCInOctets == pContext->Counters.prevIn)
23974c37757eSNguyen Trung Khanh     {
23984c37757eSNguyen Trung Khanh         pContext->Counters.nRxInactivity++;
23994c37757eSNguyen Trung Khanh         if (pContext->Counters.nRxInactivity >= 10)
24004c37757eSNguyen Trung Khanh         {
24014c37757eSNguyen Trung Khanh //#define CRASH_ON_NO_RX
24024c37757eSNguyen Trung Khanh #if defined(CRASH_ON_NO_RX)
24034c37757eSNguyen Trung Khanh             ONPAUSECOMPLETEPROC proc = (ONPAUSECOMPLETEPROC)(PVOID)1;
24044c37757eSNguyen Trung Khanh             proc(pContext);
24054c37757eSNguyen Trung Khanh #endif
24064c37757eSNguyen Trung Khanh         }
24074c37757eSNguyen Trung Khanh     }
24084c37757eSNguyen Trung Khanh     else
24094c37757eSNguyen Trung Khanh     {
24104c37757eSNguyen Trung Khanh         pContext->Counters.nRxInactivity = 0;
24114c37757eSNguyen Trung Khanh         pContext->Counters.prevIn = pContext->Statistics.ifHCInOctets;
24124c37757eSNguyen Trung Khanh     }
24134c37757eSNguyen Trung Khanh     return bReportHang;
24144c37757eSNguyen Trung Khanh }
24154c37757eSNguyen Trung Khanh 
24164c37757eSNguyen Trung Khanh /**********************************************************
24174c37757eSNguyen Trung Khanh Common implementation of periodic poll
24184c37757eSNguyen Trung Khanh Parameters:
24194c37757eSNguyen Trung Khanh     context
24204c37757eSNguyen Trung Khanh Return:
24214c37757eSNguyen Trung Khanh     TRUE, if reset required
24224c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_CheckForHang(PARANDIS_ADAPTER * pContext)24234c37757eSNguyen Trung Khanh BOOLEAN ParaNdis_CheckForHang(PARANDIS_ADAPTER *pContext)
24244c37757eSNguyen Trung Khanh {
24254c37757eSNguyen Trung Khanh     static int nHangOn = 0;
24264c37757eSNguyen Trung Khanh     BOOLEAN b = nHangOn >= 3 && nHangOn < 6;
24274c37757eSNguyen Trung Khanh     DEBUG_ENTRY(3);
24284c37757eSNguyen Trung Khanh     b |= CheckRunningDpc(pContext);
24294c37757eSNguyen Trung Khanh     //uncomment to cause 3 consecutive resets
24304c37757eSNguyen Trung Khanh     //nHangOn++;
24314c37757eSNguyen Trung Khanh     DEBUG_EXIT_STATUS(b ? 0 : 6, b);
24324c37757eSNguyen Trung Khanh     return b;
24334c37757eSNguyen Trung Khanh }
24344c37757eSNguyen Trung Khanh 
24354c37757eSNguyen Trung Khanh /**********************************************************
24364c37757eSNguyen Trung Khanh Common handler of multicast address configuration
24374c37757eSNguyen Trung Khanh Parameters:
24384c37757eSNguyen Trung Khanh     PVOID Buffer            array of addresses from NDIS
24394c37757eSNguyen Trung Khanh     ULONG BufferSize        size of incoming buffer
24404c37757eSNguyen Trung Khanh     PUINT pBytesRead        update on success
24414c37757eSNguyen Trung Khanh     PUINT pBytesNeeded      update on wrong buffer size
24424c37757eSNguyen Trung Khanh Return value:
24434c37757eSNguyen Trung Khanh     SUCCESS or kind of failure
24444c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_SetMulticastList(PARANDIS_ADAPTER * pContext,PVOID Buffer,ULONG BufferSize,PUINT pBytesRead,PUINT pBytesNeeded)24454c37757eSNguyen Trung Khanh NDIS_STATUS ParaNdis_SetMulticastList(
24464c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
24474c37757eSNguyen Trung Khanh     PVOID Buffer,
24484c37757eSNguyen Trung Khanh     ULONG BufferSize,
24494c37757eSNguyen Trung Khanh     PUINT pBytesRead,
24504c37757eSNguyen Trung Khanh     PUINT pBytesNeeded)
24514c37757eSNguyen Trung Khanh {
24524c37757eSNguyen Trung Khanh     NDIS_STATUS status;
24534c37757eSNguyen Trung Khanh     ULONG length = BufferSize;
24544c37757eSNguyen Trung Khanh     if (length > sizeof(pContext->MulticastData.MulticastList))
24554c37757eSNguyen Trung Khanh     {
24564c37757eSNguyen Trung Khanh         status = NDIS_STATUS_MULTICAST_FULL;
24574c37757eSNguyen Trung Khanh         *pBytesNeeded = sizeof(pContext->MulticastData.MulticastList);
24584c37757eSNguyen Trung Khanh     }
24594c37757eSNguyen Trung Khanh     else if (length % ETH_LENGTH_OF_ADDRESS)
24604c37757eSNguyen Trung Khanh     {
24614c37757eSNguyen Trung Khanh         status = NDIS_STATUS_INVALID_LENGTH;
24624c37757eSNguyen Trung Khanh         *pBytesNeeded = (length / ETH_LENGTH_OF_ADDRESS) * ETH_LENGTH_OF_ADDRESS;
24634c37757eSNguyen Trung Khanh     }
24644c37757eSNguyen Trung Khanh     else
24654c37757eSNguyen Trung Khanh     {
24664c37757eSNguyen Trung Khanh         NdisZeroMemory(pContext->MulticastData.MulticastList, sizeof(pContext->MulticastData.MulticastList));
24674c37757eSNguyen Trung Khanh         if (length)
24684c37757eSNguyen Trung Khanh             NdisMoveMemory(pContext->MulticastData.MulticastList, Buffer, length);
24694c37757eSNguyen Trung Khanh         pContext->MulticastData.nofMulticastEntries = length / ETH_LENGTH_OF_ADDRESS;
24704c37757eSNguyen Trung Khanh         DPrintf(1, ("[%s] New multicast list of %d bytes", __FUNCTION__, length));
24714c37757eSNguyen Trung Khanh         *pBytesRead = length;
24724c37757eSNguyen Trung Khanh         status = NDIS_STATUS_SUCCESS;
24734c37757eSNguyen Trung Khanh     }
24744c37757eSNguyen Trung Khanh     return status;
24754c37757eSNguyen Trung Khanh }
24764c37757eSNguyen Trung Khanh 
24774c37757eSNguyen Trung Khanh /**********************************************************
24784c37757eSNguyen Trung Khanh Callable from synchronized routine or interrupt handler
24794c37757eSNguyen Trung Khanh to enable or disable Rx and/or Tx interrupt generation
24804c37757eSNguyen Trung Khanh Parameters:
24814c37757eSNguyen Trung Khanh     context
24824c37757eSNguyen Trung Khanh     interruptSource - isReceive, isTransmit
24834c37757eSNguyen Trung Khanh     b - 1/0 enable/disable
24844c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_VirtIOEnableIrqSynchronized(PARANDIS_ADAPTER * pContext,ULONG interruptSource)24854c37757eSNguyen Trung Khanh VOID ParaNdis_VirtIOEnableIrqSynchronized(PARANDIS_ADAPTER *pContext, ULONG interruptSource)
24864c37757eSNguyen Trung Khanh {
24874c37757eSNguyen Trung Khanh     if (interruptSource & isTransmit)
24884c37757eSNguyen Trung Khanh         virtqueue_enable_cb(pContext->NetSendQueue);
24894c37757eSNguyen Trung Khanh     if (interruptSource & isReceive)
24904c37757eSNguyen Trung Khanh         virtqueue_enable_cb(pContext->NetReceiveQueue);
24914c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)0x10, interruptSource, TRUE, 0);
24924c37757eSNguyen Trung Khanh }
24934c37757eSNguyen Trung Khanh 
ParaNdis_VirtIODisableIrqSynchronized(PARANDIS_ADAPTER * pContext,ULONG interruptSource)24944c37757eSNguyen Trung Khanh VOID ParaNdis_VirtIODisableIrqSynchronized(PARANDIS_ADAPTER *pContext, ULONG interruptSource)
24954c37757eSNguyen Trung Khanh {
24964c37757eSNguyen Trung Khanh     if (interruptSource & isTransmit)
24974c37757eSNguyen Trung Khanh         virtqueue_disable_cb(pContext->NetSendQueue);
24984c37757eSNguyen Trung Khanh     if (interruptSource & isReceive)
24994c37757eSNguyen Trung Khanh         virtqueue_disable_cb(pContext->NetReceiveQueue);
25004c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)0x10, interruptSource, FALSE, 0);
25014c37757eSNguyen Trung Khanh }
25024c37757eSNguyen Trung Khanh 
25034c37757eSNguyen Trung Khanh /**********************************************************
25044c37757eSNguyen Trung Khanh Common handler of PnP events
25054c37757eSNguyen Trung Khanh Parameters:
25064c37757eSNguyen Trung Khanh Return value:
25074c37757eSNguyen Trung Khanh ***********************************************************/
ParaNdis_OnPnPEvent(PARANDIS_ADAPTER * pContext,NDIS_DEVICE_PNP_EVENT pEvent,PVOID pInfo,ULONG ulSize)25084c37757eSNguyen Trung Khanh VOID ParaNdis_OnPnPEvent(
25094c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
25104c37757eSNguyen Trung Khanh     NDIS_DEVICE_PNP_EVENT pEvent,
25114c37757eSNguyen Trung Khanh     PVOID   pInfo,
25124c37757eSNguyen Trung Khanh     ULONG   ulSize)
25134c37757eSNguyen Trung Khanh {
25144c37757eSNguyen Trung Khanh     const char *pName = "";
25154c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0);
25164c37757eSNguyen Trung Khanh #undef MAKECASE
25174c37757eSNguyen Trung Khanh #define MAKECASE(x) case (x): pName = #x; break;
25184c37757eSNguyen Trung Khanh     switch (pEvent)
25194c37757eSNguyen Trung Khanh     {
25204c37757eSNguyen Trung Khanh         MAKECASE(NdisDevicePnPEventQueryRemoved)
25214c37757eSNguyen Trung Khanh         MAKECASE(NdisDevicePnPEventRemoved)
25224c37757eSNguyen Trung Khanh         MAKECASE(NdisDevicePnPEventSurpriseRemoved)
25234c37757eSNguyen Trung Khanh         MAKECASE(NdisDevicePnPEventQueryStopped)
25244c37757eSNguyen Trung Khanh         MAKECASE(NdisDevicePnPEventStopped)
25254c37757eSNguyen Trung Khanh         MAKECASE(NdisDevicePnPEventPowerProfileChanged)
25264c37757eSNguyen Trung Khanh         default:
25274c37757eSNguyen Trung Khanh             break;
25284c37757eSNguyen Trung Khanh     }
25294c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopPnpEvent, NULL, pEvent, 0, 0);
25304c37757eSNguyen Trung Khanh     DPrintf(0, ("[%s] (%s)", __FUNCTION__, pName));
25314c37757eSNguyen Trung Khanh     if (pEvent == NdisDevicePnPEventSurpriseRemoved)
25324c37757eSNguyen Trung Khanh     {
25334c37757eSNguyen Trung Khanh         // on simulated surprise removal (under PnpTest) we need to reset the device
25344c37757eSNguyen Trung Khanh         // to prevent any access of device queues to memory buffers
25354c37757eSNguyen Trung Khanh         pContext->bSurprizeRemoved = TRUE;
25364c37757eSNguyen Trung Khanh         ParaNdis_ResetVirtIONetDevice(pContext);
25374c37757eSNguyen Trung Khanh     }
25384c37757eSNguyen Trung Khanh     pContext->PnpEvents[pContext->nPnpEventIndex++] = pEvent;
25394c37757eSNguyen Trung Khanh     if (pContext->nPnpEventIndex > sizeof(pContext->PnpEvents)/sizeof(pContext->PnpEvents[0]))
25404c37757eSNguyen Trung Khanh         pContext->nPnpEventIndex = 0;
25414c37757eSNguyen Trung Khanh }
25424c37757eSNguyen Trung Khanh 
SendControlMessage(PARANDIS_ADAPTER * pContext,UCHAR cls,UCHAR cmd,PVOID buffer1,ULONG size1,PVOID buffer2,ULONG size2,int levelIfOK)25434c37757eSNguyen Trung Khanh static BOOLEAN SendControlMessage(
25444c37757eSNguyen Trung Khanh     PARANDIS_ADAPTER *pContext,
25454c37757eSNguyen Trung Khanh     UCHAR cls,
25464c37757eSNguyen Trung Khanh     UCHAR cmd,
25474c37757eSNguyen Trung Khanh     PVOID buffer1,
25484c37757eSNguyen Trung Khanh     ULONG size1,
25494c37757eSNguyen Trung Khanh     PVOID buffer2,
25504c37757eSNguyen Trung Khanh     ULONG size2,
25514c37757eSNguyen Trung Khanh     int levelIfOK
25524c37757eSNguyen Trung Khanh     )
25534c37757eSNguyen Trung Khanh {
25544c37757eSNguyen Trung Khanh     BOOLEAN bOK = FALSE;
25554c37757eSNguyen Trung Khanh     NdisAcquireSpinLock(&pContext->ReceiveLock);
25564c37757eSNguyen Trung Khanh     if (pContext->ControlData.Virtual && pContext->ControlData.size > (size1 + size2 + 16))
25574c37757eSNguyen Trung Khanh     {
25584c37757eSNguyen Trung Khanh         struct VirtIOBufferDescriptor sg[4];
25594c37757eSNguyen Trung Khanh         PUCHAR pBase = (PUCHAR)pContext->ControlData.Virtual;
25604c37757eSNguyen Trung Khanh         PHYSICAL_ADDRESS phBase = pContext->ControlData.Physical;
25614c37757eSNguyen Trung Khanh         ULONG offset = 0;
25624c37757eSNguyen Trung Khanh         UINT nOut = 1;
25634c37757eSNguyen Trung Khanh 
25644c37757eSNguyen Trung Khanh         ((virtio_net_ctrl_hdr *)pBase)->class_of_command = cls;
25654c37757eSNguyen Trung Khanh         ((virtio_net_ctrl_hdr *)pBase)->cmd = cmd;
25664c37757eSNguyen Trung Khanh         sg[0].physAddr = phBase;
25674c37757eSNguyen Trung Khanh         sg[0].length = sizeof(virtio_net_ctrl_hdr);
25684c37757eSNguyen Trung Khanh         offset += sg[0].length;
25694c37757eSNguyen Trung Khanh         offset = (offset + 3) & ~3;
25704c37757eSNguyen Trung Khanh         if (size1)
25714c37757eSNguyen Trung Khanh         {
25724c37757eSNguyen Trung Khanh             NdisMoveMemory(pBase + offset, buffer1, size1);
25734c37757eSNguyen Trung Khanh             sg[nOut].physAddr = phBase;
25744c37757eSNguyen Trung Khanh             sg[nOut].physAddr.QuadPart += offset;
25754c37757eSNguyen Trung Khanh             sg[nOut].length = size1;
25764c37757eSNguyen Trung Khanh             offset += size1;
25774c37757eSNguyen Trung Khanh             offset = (offset + 3) & ~3;
25784c37757eSNguyen Trung Khanh             nOut++;
25794c37757eSNguyen Trung Khanh         }
25804c37757eSNguyen Trung Khanh         if (size2)
25814c37757eSNguyen Trung Khanh         {
25824c37757eSNguyen Trung Khanh             NdisMoveMemory(pBase + offset, buffer2, size2);
25834c37757eSNguyen Trung Khanh             sg[nOut].physAddr = phBase;
25844c37757eSNguyen Trung Khanh             sg[nOut].physAddr.QuadPart += offset;
25854c37757eSNguyen Trung Khanh             sg[nOut].length = size2;
25864c37757eSNguyen Trung Khanh             offset += size2;
25874c37757eSNguyen Trung Khanh             offset = (offset + 3) & ~3;
25884c37757eSNguyen Trung Khanh             nOut++;
25894c37757eSNguyen Trung Khanh         }
25904c37757eSNguyen Trung Khanh         sg[nOut].physAddr = phBase;
25914c37757eSNguyen Trung Khanh         sg[nOut].physAddr.QuadPart += offset;
25924c37757eSNguyen Trung Khanh         sg[nOut].length = sizeof(virtio_net_ctrl_ack);
25934c37757eSNguyen Trung Khanh         *(virtio_net_ctrl_ack *)(pBase + offset) = VIRTIO_NET_ERR;
25944c37757eSNguyen Trung Khanh 
25954c37757eSNguyen Trung Khanh         if (0 <= virtqueue_add_buf(pContext->NetControlQueue, sg, nOut, 1, (PVOID)1, NULL, 0))
25964c37757eSNguyen Trung Khanh         {
25974c37757eSNguyen Trung Khanh             UINT len;
25984c37757eSNguyen Trung Khanh             void *p;
25994c37757eSNguyen Trung Khanh             virtqueue_kick_always(pContext->NetControlQueue);
26004c37757eSNguyen Trung Khanh             p = virtqueue_get_buf(pContext->NetControlQueue, &len);
26014c37757eSNguyen Trung Khanh             if (!p)
26024c37757eSNguyen Trung Khanh             {
26034c37757eSNguyen Trung Khanh                 DPrintf(0, ("%s - ERROR: get_buf failed", __FUNCTION__));
26044c37757eSNguyen Trung Khanh             }
26054c37757eSNguyen Trung Khanh             else if (len != sizeof(virtio_net_ctrl_ack))
26064c37757eSNguyen Trung Khanh             {
26074c37757eSNguyen Trung Khanh                 DPrintf(0, ("%s - ERROR: wrong len %d", __FUNCTION__, len));
26084c37757eSNguyen Trung Khanh             }
26094c37757eSNguyen Trung Khanh             else if (*(virtio_net_ctrl_ack *)(pBase + offset) != VIRTIO_NET_OK)
26104c37757eSNguyen Trung Khanh             {
26114c37757eSNguyen Trung Khanh                 DPrintf(0, ("%s - ERROR: error %d returned", __FUNCTION__, *(virtio_net_ctrl_ack *)(pBase + offset)));
26124c37757eSNguyen Trung Khanh             }
26134c37757eSNguyen Trung Khanh             else
26144c37757eSNguyen Trung Khanh             {
26154c37757eSNguyen Trung Khanh                 // everything is OK
26164c37757eSNguyen Trung Khanh                 DPrintf(levelIfOK, ("%s OK(%d.%d,buffers of %d and %d) ", __FUNCTION__, cls, cmd, size1, size2));
26174c37757eSNguyen Trung Khanh                 bOK = TRUE;
26184c37757eSNguyen Trung Khanh             }
26194c37757eSNguyen Trung Khanh         }
26204c37757eSNguyen Trung Khanh         else
26214c37757eSNguyen Trung Khanh         {
26224c37757eSNguyen Trung Khanh             DPrintf(0, ("%s - ERROR: add_buf failed", __FUNCTION__));
26234c37757eSNguyen Trung Khanh         }
26244c37757eSNguyen Trung Khanh     }
26254c37757eSNguyen Trung Khanh     else
26264c37757eSNguyen Trung Khanh     {
26274c37757eSNguyen Trung Khanh         DPrintf(0, ("%s (buffer %d,%d) - ERROR: message too LARGE", __FUNCTION__, size1, size2));
26284c37757eSNguyen Trung Khanh     }
26294c37757eSNguyen Trung Khanh     NdisReleaseSpinLock(&pContext->ReceiveLock);
26304c37757eSNguyen Trung Khanh     return bOK;
26314c37757eSNguyen Trung Khanh }
26324c37757eSNguyen Trung Khanh 
ParaNdis_DeviceFiltersUpdateRxMode(PARANDIS_ADAPTER * pContext)26334c37757eSNguyen Trung Khanh static VOID ParaNdis_DeviceFiltersUpdateRxMode(PARANDIS_ADAPTER *pContext)
26344c37757eSNguyen Trung Khanh {
26354c37757eSNguyen Trung Khanh     u8 val;
26364c37757eSNguyen Trung Khanh     ULONG f = pContext->PacketFilter;
26374c37757eSNguyen Trung Khanh     val = (f & NDIS_PACKET_TYPE_ALL_MULTICAST) ? 1 : 0;
26384c37757eSNguyen Trung Khanh     SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_ALLMULTI, &val, sizeof(val), NULL, 0, 2);
26394c37757eSNguyen Trung Khanh     //SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_ALLUNI, &val, sizeof(val), NULL, 0, 2);
26404c37757eSNguyen Trung Khanh     val = (f & (NDIS_PACKET_TYPE_MULTICAST | NDIS_PACKET_TYPE_ALL_MULTICAST)) ? 0 : 1;
26414c37757eSNguyen Trung Khanh     SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_NOMULTI, &val, sizeof(val), NULL, 0, 2);
26424c37757eSNguyen Trung Khanh     val = (f & NDIS_PACKET_TYPE_DIRECTED) ? 0 : 1;
26434c37757eSNguyen Trung Khanh     SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_NOUNI, &val, sizeof(val), NULL, 0, 2);
26444c37757eSNguyen Trung Khanh     val = (f & NDIS_PACKET_TYPE_BROADCAST) ? 0 : 1;
26454c37757eSNguyen Trung Khanh     SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_NOBCAST, &val, sizeof(val), NULL, 0, 2);
26464c37757eSNguyen Trung Khanh     val = (f & NDIS_PACKET_TYPE_PROMISCUOUS) ? 1 : 0;
26474c37757eSNguyen Trung Khanh     SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_PROMISC, &val, sizeof(val), NULL, 0, 2);
26484c37757eSNguyen Trung Khanh }
26494c37757eSNguyen Trung Khanh 
ParaNdis_DeviceFiltersUpdateAddresses(PARANDIS_ADAPTER * pContext)26504c37757eSNguyen Trung Khanh static VOID ParaNdis_DeviceFiltersUpdateAddresses(PARANDIS_ADAPTER *pContext)
26514c37757eSNguyen Trung Khanh {
26524c37757eSNguyen Trung Khanh     struct
26534c37757eSNguyen Trung Khanh     {
26544c37757eSNguyen Trung Khanh         struct virtio_net_ctrl_mac header;
26554c37757eSNguyen Trung Khanh         UCHAR addr[ETH_LENGTH_OF_ADDRESS];
26564c37757eSNguyen Trung Khanh     } uCast;
26574c37757eSNguyen Trung Khanh     uCast.header.entries = 1;
26584c37757eSNguyen Trung Khanh     NdisMoveMemory(uCast.addr, pContext->CurrentMacAddress, sizeof(uCast.addr));
26594c37757eSNguyen Trung Khanh     SendControlMessage(pContext, VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_TABLE_SET,
26604c37757eSNguyen Trung Khanh         &uCast, sizeof(uCast), &pContext->MulticastData,sizeof(pContext->MulticastData.nofMulticastEntries) + pContext->MulticastData.nofMulticastEntries * ETH_ALEN, 2);
26614c37757eSNguyen Trung Khanh }
26624c37757eSNguyen Trung Khanh 
SetSingleVlanFilter(PARANDIS_ADAPTER * pContext,ULONG vlanId,BOOLEAN bOn,int levelIfOK)26634c37757eSNguyen Trung Khanh static VOID SetSingleVlanFilter(PARANDIS_ADAPTER *pContext, ULONG vlanId, BOOLEAN bOn, int levelIfOK)
26644c37757eSNguyen Trung Khanh {
26654c37757eSNguyen Trung Khanh     u16 val = vlanId & 0xfff;
26664c37757eSNguyen Trung Khanh     UCHAR cmd = bOn ? VIRTIO_NET_CTRL_VLAN_ADD : VIRTIO_NET_CTRL_VLAN_DEL;
26674c37757eSNguyen Trung Khanh     SendControlMessage(pContext, VIRTIO_NET_CTRL_VLAN, cmd, &val, sizeof(val), NULL, 0, levelIfOK);
26684c37757eSNguyen Trung Khanh }
26694c37757eSNguyen Trung Khanh 
SetAllVlanFilters(PARANDIS_ADAPTER * pContext,BOOLEAN bOn)26704c37757eSNguyen Trung Khanh static VOID SetAllVlanFilters(PARANDIS_ADAPTER *pContext, BOOLEAN bOn)
26714c37757eSNguyen Trung Khanh {
26724c37757eSNguyen Trung Khanh     ULONG i;
26734c37757eSNguyen Trung Khanh     for (i = 0; i <= MAX_VLAN_ID; ++i)
26744c37757eSNguyen Trung Khanh         SetSingleVlanFilter(pContext, i, bOn, 7);
26754c37757eSNguyen Trung Khanh }
26764c37757eSNguyen Trung Khanh 
26774c37757eSNguyen Trung Khanh /*
26784c37757eSNguyen Trung Khanh     possible values of filter set (pContext->ulCurrentVlansFilterSet):
26794c37757eSNguyen Trung Khanh     0 - all disabled
26804c37757eSNguyen Trung Khanh     1..4095 - one selected enabled
26814c37757eSNguyen Trung Khanh     4096 - all enabled
26824c37757eSNguyen Trung Khanh     Note that only 0th vlan can't be enabled
26834c37757eSNguyen Trung Khanh */
ParaNdis_DeviceFiltersUpdateVlanId(PARANDIS_ADAPTER * pContext)26844c37757eSNguyen Trung Khanh VOID ParaNdis_DeviceFiltersUpdateVlanId(PARANDIS_ADAPTER *pContext)
26854c37757eSNguyen Trung Khanh {
26864c37757eSNguyen Trung Khanh     if (pContext->bHasHardwareFilters)
26874c37757eSNguyen Trung Khanh     {
26884c37757eSNguyen Trung Khanh         ULONG newFilterSet;
26894c37757eSNguyen Trung Khanh         if (IsVlanSupported(pContext))
26904c37757eSNguyen Trung Khanh             newFilterSet = pContext->VlanId ? pContext->VlanId : (MAX_VLAN_ID + 1);
26914c37757eSNguyen Trung Khanh         else
26924c37757eSNguyen Trung Khanh             newFilterSet = IsPrioritySupported(pContext) ? (MAX_VLAN_ID + 1) : 0;
26934c37757eSNguyen Trung Khanh         if (newFilterSet != pContext->ulCurrentVlansFilterSet)
26944c37757eSNguyen Trung Khanh         {
26954c37757eSNguyen Trung Khanh             if (pContext->ulCurrentVlansFilterSet > MAX_VLAN_ID)
26964c37757eSNguyen Trung Khanh                 SetAllVlanFilters(pContext, FALSE);
26974c37757eSNguyen Trung Khanh             else if (pContext->ulCurrentVlansFilterSet)
26984c37757eSNguyen Trung Khanh                 SetSingleVlanFilter(pContext, pContext->ulCurrentVlansFilterSet, FALSE, 2);
26994c37757eSNguyen Trung Khanh 
27004c37757eSNguyen Trung Khanh             pContext->ulCurrentVlansFilterSet = newFilterSet;
27014c37757eSNguyen Trung Khanh 
27024c37757eSNguyen Trung Khanh             if (pContext->ulCurrentVlansFilterSet > MAX_VLAN_ID)
27034c37757eSNguyen Trung Khanh                 SetAllVlanFilters(pContext, TRUE);
27044c37757eSNguyen Trung Khanh             else if (pContext->ulCurrentVlansFilterSet)
27054c37757eSNguyen Trung Khanh                 SetSingleVlanFilter(pContext, pContext->ulCurrentVlansFilterSet, TRUE, 2);
27064c37757eSNguyen Trung Khanh         }
27074c37757eSNguyen Trung Khanh     }
27084c37757eSNguyen Trung Khanh }
27094c37757eSNguyen Trung Khanh 
ParaNdis_UpdateDeviceFilters(PARANDIS_ADAPTER * pContext)27104c37757eSNguyen Trung Khanh VOID ParaNdis_UpdateDeviceFilters(PARANDIS_ADAPTER *pContext)
27114c37757eSNguyen Trung Khanh {
27124c37757eSNguyen Trung Khanh     if (pContext->bHasHardwareFilters)
27134c37757eSNguyen Trung Khanh     {
27144c37757eSNguyen Trung Khanh         ParaNdis_DeviceFiltersUpdateRxMode(pContext);
27154c37757eSNguyen Trung Khanh         ParaNdis_DeviceFiltersUpdateAddresses(pContext);
27164c37757eSNguyen Trung Khanh         ParaNdis_DeviceFiltersUpdateVlanId(pContext);
27174c37757eSNguyen Trung Khanh     }
27184c37757eSNguyen Trung Khanh }
27194c37757eSNguyen Trung Khanh 
ParaNdis_PowerOn(PARANDIS_ADAPTER * pContext)27204c37757eSNguyen Trung Khanh NDIS_STATUS ParaNdis_PowerOn(PARANDIS_ADAPTER *pContext)
27214c37757eSNguyen Trung Khanh {
27224c37757eSNguyen Trung Khanh     LIST_ENTRY TempList;
27234c37757eSNguyen Trung Khanh     NDIS_STATUS status;
27244c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0);
27254c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopPowerOn, NULL, 1, 0, 0);
27264c37757eSNguyen Trung Khanh     ParaNdis_ResetVirtIONetDevice(pContext);
27274c37757eSNguyen Trung Khanh     virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER);
27284c37757eSNguyen Trung Khanh     /* virtio_get_features must be called once upon device initialization:
27294c37757eSNguyen Trung Khanh      otherwise the device will not work properly */
27304c37757eSNguyen Trung Khanh     (void)virtio_get_features(&pContext->IODevice);
27314c37757eSNguyen Trung Khanh 
27324c37757eSNguyen Trung Khanh     if (pContext->bUseMergedBuffers)
27334c37757eSNguyen Trung Khanh         VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_MRG_RXBUF);
27344c37757eSNguyen Trung Khanh     if (VirtIODeviceGetHostFeature(pContext, VIRTIO_RING_F_EVENT_IDX))
27354c37757eSNguyen Trung Khanh         VirtIODeviceEnableGuestFeature(pContext, VIRTIO_RING_F_EVENT_IDX);
27364c37757eSNguyen Trung Khanh     if (pContext->bDoGuestChecksumOnReceive)
27374c37757eSNguyen Trung Khanh         VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_GUEST_CSUM);
27384c37757eSNguyen Trung Khanh     if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_VERSION_1))
27394c37757eSNguyen Trung Khanh         VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_VERSION_1);
27404c37757eSNguyen Trung Khanh     if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_ANY_LAYOUT))
27414c37757eSNguyen Trung Khanh         VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_ANY_LAYOUT);
27424c37757eSNguyen Trung Khanh 
27434c37757eSNguyen Trung Khanh     status = FinalizeFeatures(pContext);
27444c37757eSNguyen Trung Khanh     if (status == NDIS_STATUS_SUCCESS) {
27454c37757eSNguyen Trung Khanh         status = FindNetQueues(pContext);
27464c37757eSNguyen Trung Khanh     }
27474c37757eSNguyen Trung Khanh     if (status != NDIS_STATUS_SUCCESS) {
27484c37757eSNguyen Trung Khanh         virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_FAILED);
27494c37757eSNguyen Trung Khanh         return status;
27504c37757eSNguyen Trung Khanh     }
27514c37757eSNguyen Trung Khanh 
27524c37757eSNguyen Trung Khanh     ParaNdis_RestoreDeviceConfigurationAfterReset(pContext);
27534c37757eSNguyen Trung Khanh 
27544c37757eSNguyen Trung Khanh     ParaNdis_UpdateDeviceFilters(pContext);
27554c37757eSNguyen Trung Khanh 
27564c37757eSNguyen Trung Khanh     InitializeListHead(&TempList);
27574c37757eSNguyen Trung Khanh 
27584c37757eSNguyen Trung Khanh     /* submit all the receive buffers */
27594c37757eSNguyen Trung Khanh     NdisAcquireSpinLock(&pContext->ReceiveLock);
27604c37757eSNguyen Trung Khanh 
27614c37757eSNguyen Trung Khanh     pContext->ReuseBufferProc = (tReuseReceiveBufferProc)ReuseReceiveBufferRegular;
27624c37757eSNguyen Trung Khanh 
27634c37757eSNguyen Trung Khanh     while (!IsListEmpty(&pContext->NetReceiveBuffers))
27644c37757eSNguyen Trung Khanh     {
27654c37757eSNguyen Trung Khanh         pIONetDescriptor pBufferDescriptor =
27664c37757eSNguyen Trung Khanh             (pIONetDescriptor)RemoveHeadList(&pContext->NetReceiveBuffers);
27674c37757eSNguyen Trung Khanh         InsertTailList(&TempList, &pBufferDescriptor->listEntry);
27684c37757eSNguyen Trung Khanh     }
27694c37757eSNguyen Trung Khanh     pContext->NetNofReceiveBuffers = 0;
27704c37757eSNguyen Trung Khanh     while (!IsListEmpty(&TempList))
27714c37757eSNguyen Trung Khanh     {
27724c37757eSNguyen Trung Khanh         pIONetDescriptor pBufferDescriptor =
27734c37757eSNguyen Trung Khanh             (pIONetDescriptor)RemoveHeadList(&TempList);
27744c37757eSNguyen Trung Khanh         if (AddRxBufferToQueue(pContext, pBufferDescriptor))
27754c37757eSNguyen Trung Khanh         {
27764c37757eSNguyen Trung Khanh             InsertTailList(&pContext->NetReceiveBuffers, &pBufferDescriptor->listEntry);
27774c37757eSNguyen Trung Khanh             pContext->NetNofReceiveBuffers++;
27784c37757eSNguyen Trung Khanh         }
27794c37757eSNguyen Trung Khanh         else
27804c37757eSNguyen Trung Khanh         {
27814c37757eSNguyen Trung Khanh             DPrintf(0, ("FAILED TO REUSE THE BUFFER!!!!"));
27824c37757eSNguyen Trung Khanh             VirtIONetFreeBufferDescriptor(pContext, pBufferDescriptor);
27834c37757eSNguyen Trung Khanh             pContext->NetMaxReceiveBuffers--;
27844c37757eSNguyen Trung Khanh         }
27854c37757eSNguyen Trung Khanh     }
27864c37757eSNguyen Trung Khanh     virtqueue_kick(pContext->NetReceiveQueue);
27874c37757eSNguyen Trung Khanh     ParaNdis_SetPowerState(pContext, NdisDeviceStateD0);
27884c37757eSNguyen Trung Khanh     pContext->bEnableInterruptHandlingDPC = TRUE;
27894c37757eSNguyen Trung Khanh     virtio_device_ready(&pContext->IODevice);
27904c37757eSNguyen Trung Khanh 
27914c37757eSNguyen Trung Khanh     NdisReleaseSpinLock(&pContext->ReceiveLock);
27924c37757eSNguyen Trung Khanh 
27934c37757eSNguyen Trung Khanh     // if bFastSuspendInProcess is set by Win8 power-off procedure,
27944c37757eSNguyen Trung Khanh     // the ParaNdis_Resume enables Tx and RX
27954c37757eSNguyen Trung Khanh     // otherwise it does not do anything in Vista+ (Tx and RX are enabled after power-on by Restart)
27964c37757eSNguyen Trung Khanh     ParaNdis_Resume(pContext);
27974c37757eSNguyen Trung Khanh     pContext->bFastSuspendInProcess = FALSE;
27984c37757eSNguyen Trung Khanh 
27994c37757eSNguyen Trung Khanh     ParaNdis_ReportLinkStatus(pContext, TRUE);
28004c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopPowerOn, NULL, 0, 0, 0);
28014c37757eSNguyen Trung Khanh 
28024c37757eSNguyen Trung Khanh     return status;
28034c37757eSNguyen Trung Khanh }
28044c37757eSNguyen Trung Khanh 
ParaNdis_PowerOff(PARANDIS_ADAPTER * pContext)28054c37757eSNguyen Trung Khanh VOID ParaNdis_PowerOff(PARANDIS_ADAPTER *pContext)
28064c37757eSNguyen Trung Khanh {
28074c37757eSNguyen Trung Khanh     DEBUG_ENTRY(0);
28084c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopPowerOff, NULL, 1, 0, 0);
28094c37757eSNguyen Trung Khanh 
28104c37757eSNguyen Trung Khanh     ParaNdis_IndicateConnect(pContext, FALSE, FALSE);
28114c37757eSNguyen Trung Khanh 
28124c37757eSNguyen Trung Khanh     // if bFastSuspendInProcess is set by Win8 power-off procedure
28134c37757eSNguyen Trung Khanh     // the ParaNdis_Suspend does fast Rx stop without waiting (=>srsPausing, if there are some RX packets in Ndis)
28144c37757eSNguyen Trung Khanh     pContext->bFastSuspendInProcess = pContext->bNoPauseOnSuspend && pContext->ReceiveState == srsEnabled;
28154c37757eSNguyen Trung Khanh     ParaNdis_Suspend(pContext);
28164c37757eSNguyen Trung Khanh     if (pContext->IODevice.addr)
28174c37757eSNguyen Trung Khanh     {
28184c37757eSNguyen Trung Khanh         /* back compat - remove the OK flag only in legacy mode */
28194c37757eSNguyen Trung Khanh         VirtIODeviceRemoveStatus(&pContext->IODevice, VIRTIO_CONFIG_S_DRIVER_OK);
28204c37757eSNguyen Trung Khanh     }
28214c37757eSNguyen Trung Khanh 
28224c37757eSNguyen Trung Khanh     if (pContext->bFastSuspendInProcess)
28234c37757eSNguyen Trung Khanh     {
28244c37757eSNguyen Trung Khanh         NdisAcquireSpinLock(&pContext->ReceiveLock);
28254c37757eSNguyen Trung Khanh         pContext->ReuseBufferProc = (tReuseReceiveBufferProc)ReuseReceiveBufferPowerOff;
28264c37757eSNguyen Trung Khanh         NdisReleaseSpinLock(&pContext->ReceiveLock);
28274c37757eSNguyen Trung Khanh     }
28284c37757eSNguyen Trung Khanh 
28294c37757eSNguyen Trung Khanh     ParaNdis_SetPowerState(pContext, NdisDeviceStateD3);
28304c37757eSNguyen Trung Khanh 
28314c37757eSNguyen Trung Khanh     PreventDPCServicing(pContext);
28324c37757eSNguyen Trung Khanh 
28334c37757eSNguyen Trung Khanh     /*******************************************************************
28344c37757eSNguyen Trung Khanh         shutdown queues to have all the receive buffers under our control
28354c37757eSNguyen Trung Khanh         all the transmit buffers move to list of free buffers
28364c37757eSNguyen Trung Khanh     ********************************************************************/
28374c37757eSNguyen Trung Khanh 
28384c37757eSNguyen Trung Khanh     NdisAcquireSpinLock(&pContext->SendLock);
28394c37757eSNguyen Trung Khanh     virtqueue_shutdown(pContext->NetSendQueue);
28404c37757eSNguyen Trung Khanh     while (!IsListEmpty(&pContext->NetSendBuffersInUse))
28414c37757eSNguyen Trung Khanh     {
28424c37757eSNguyen Trung Khanh         pIONetDescriptor pBufferDescriptor =
28434c37757eSNguyen Trung Khanh             (pIONetDescriptor)RemoveHeadList(&pContext->NetSendBuffersInUse);
28444c37757eSNguyen Trung Khanh         InsertTailList(&pContext->NetFreeSendBuffers, &pBufferDescriptor->listEntry);
28454c37757eSNguyen Trung Khanh         pContext->nofFreeTxDescriptors++;
28464c37757eSNguyen Trung Khanh         pContext->nofFreeHardwareBuffers += pBufferDescriptor->nofUsedBuffers;
28474c37757eSNguyen Trung Khanh     }
28484c37757eSNguyen Trung Khanh     NdisReleaseSpinLock(&pContext->SendLock);
28494c37757eSNguyen Trung Khanh 
28504c37757eSNguyen Trung Khanh     NdisAcquireSpinLock(&pContext->ReceiveLock);
28514c37757eSNguyen Trung Khanh     virtqueue_shutdown(pContext->NetReceiveQueue);
28524c37757eSNguyen Trung Khanh     NdisReleaseSpinLock(&pContext->ReceiveLock);
28534c37757eSNguyen Trung Khanh     if (pContext->NetControlQueue) {
28544c37757eSNguyen Trung Khanh         virtqueue_shutdown(pContext->NetControlQueue);
28554c37757eSNguyen Trung Khanh     }
28564c37757eSNguyen Trung Khanh 
28574c37757eSNguyen Trung Khanh     DPrintf(0, ("WARNING: deleting queues!!!!!!!!!"));
28584c37757eSNguyen Trung Khanh     DeleteNetQueues(pContext);
28594c37757eSNguyen Trung Khanh     pContext->NetSendQueue = NULL;
28604c37757eSNguyen Trung Khanh     pContext->NetReceiveQueue = NULL;
28614c37757eSNguyen Trung Khanh     pContext->NetControlQueue = NULL;
28624c37757eSNguyen Trung Khanh 
28634c37757eSNguyen Trung Khanh     ParaNdis_ResetVirtIONetDevice(pContext);
28644c37757eSNguyen Trung Khanh     ParaNdis_DebugHistory(pContext, hopPowerOff, NULL, 0, 0, 0);
28654c37757eSNguyen Trung Khanh }
28664c37757eSNguyen Trung Khanh 
ParaNdis_CallOnBugCheck(PARANDIS_ADAPTER * pContext)28674c37757eSNguyen Trung Khanh void ParaNdis_CallOnBugCheck(PARANDIS_ADAPTER *pContext)
28684c37757eSNguyen Trung Khanh {
28694c37757eSNguyen Trung Khanh     if (pContext->IODevice.isr)
28704c37757eSNguyen Trung Khanh     {
28714c37757eSNguyen Trung Khanh #ifdef DBG_USE_VIRTIO_PCI_ISR_FOR_HOST_REPORT
28724c37757eSNguyen Trung Khanh         WriteVirtIODeviceByte(pContext->IODevice.isr, 1);
28734c37757eSNguyen Trung Khanh #endif
28744c37757eSNguyen Trung Khanh     }
28754c37757eSNguyen Trung Khanh }
28764c37757eSNguyen Trung Khanh 
ParaNdis_CheckRxChecksum(PARANDIS_ADAPTER * pContext,ULONG virtioFlags,PVOID pRxPacket,ULONG len)28774c37757eSNguyen Trung Khanh tChecksumCheckResult ParaNdis_CheckRxChecksum(PARANDIS_ADAPTER *pContext, ULONG virtioFlags, PVOID pRxPacket, ULONG len)
28784c37757eSNguyen Trung Khanh {
28794c37757eSNguyen Trung Khanh     tOffloadSettingsFlags f = pContext->Offload.flags;
28804c37757eSNguyen Trung Khanh     tChecksumCheckResult res, resIp;
28814c37757eSNguyen Trung Khanh     PVOID pIpHeader = RtlOffsetToPointer(pRxPacket, ETH_HEADER_SIZE);
28824c37757eSNguyen Trung Khanh     tTcpIpPacketParsingResult ppr;
28834c37757eSNguyen Trung Khanh     ULONG flagsToCalculate = 0;
28844c37757eSNguyen Trung Khanh     res.value = 0;
28854c37757eSNguyen Trung Khanh     resIp.value = 0;
28864c37757eSNguyen Trung Khanh 
28874c37757eSNguyen Trung Khanh     //VIRTIO_NET_HDR_F_NEEDS_CSUM - we need to calculate TCP/UDP CS
28884c37757eSNguyen Trung Khanh     //VIRTIO_NET_HDR_F_DATA_VALID - host tells us TCP/UDP CS is OK
28894c37757eSNguyen Trung Khanh 
28904c37757eSNguyen Trung Khanh     if (f.fRxIPChecksum) flagsToCalculate |= pcrIpChecksum; // check only
28914c37757eSNguyen Trung Khanh 
28924c37757eSNguyen Trung Khanh     if (!(virtioFlags & VIRTIO_NET_HDR_F_DATA_VALID))
28934c37757eSNguyen Trung Khanh     {
28944c37757eSNguyen Trung Khanh         if (virtioFlags & VIRTIO_NET_HDR_F_NEEDS_CSUM)
28954c37757eSNguyen Trung Khanh         {
28964c37757eSNguyen Trung Khanh             flagsToCalculate |= pcrFixXxpChecksum | pcrTcpChecksum | pcrUdpChecksum;
28974c37757eSNguyen Trung Khanh         }
28984c37757eSNguyen Trung Khanh         else
28994c37757eSNguyen Trung Khanh         {
29004c37757eSNguyen Trung Khanh             if (f.fRxTCPChecksum) flagsToCalculate |= pcrTcpV4Checksum;
29014c37757eSNguyen Trung Khanh             if (f.fRxUDPChecksum) flagsToCalculate |= pcrUdpV4Checksum;
29024c37757eSNguyen Trung Khanh             if (f.fRxTCPv6Checksum) flagsToCalculate |= pcrTcpV6Checksum;
29034c37757eSNguyen Trung Khanh             if (f.fRxUDPv6Checksum) flagsToCalculate |= pcrUdpV6Checksum;
29044c37757eSNguyen Trung Khanh         }
29054c37757eSNguyen Trung Khanh     }
29064c37757eSNguyen Trung Khanh 
29074c37757eSNguyen Trung Khanh     ppr = ParaNdis_CheckSumVerify(pIpHeader, len - ETH_HEADER_SIZE, flagsToCalculate, __FUNCTION__);
29084c37757eSNguyen Trung Khanh 
29094c37757eSNguyen Trung Khanh     if (virtioFlags & VIRTIO_NET_HDR_F_DATA_VALID)
29104c37757eSNguyen Trung Khanh     {
29114c37757eSNguyen Trung Khanh         pContext->extraStatistics.framesRxCSHwOK++;
29124c37757eSNguyen Trung Khanh         ppr.xxpCheckSum = ppresCSOK;
29134c37757eSNguyen Trung Khanh     }
29144c37757eSNguyen Trung Khanh 
29154c37757eSNguyen Trung Khanh     if (ppr.ipStatus == ppresIPV4 && !ppr.IsFragment)
29164c37757eSNguyen Trung Khanh     {
29174c37757eSNguyen Trung Khanh         if (f.fRxIPChecksum)
29184c37757eSNguyen Trung Khanh         {
29194c37757eSNguyen Trung Khanh             res.flags.IpOK =  ppr.ipCheckSum == ppresCSOK;
29204c37757eSNguyen Trung Khanh             res.flags.IpFailed = ppr.ipCheckSum == ppresCSBad;
29214c37757eSNguyen Trung Khanh         }
29224c37757eSNguyen Trung Khanh         if(ppr.xxpStatus == ppresXxpKnown)
29234c37757eSNguyen Trung Khanh         {
29244c37757eSNguyen Trung Khanh             if(ppr.TcpUdp == ppresIsTCP) /* TCP */
29254c37757eSNguyen Trung Khanh             {
29264c37757eSNguyen Trung Khanh                 if (f.fRxTCPChecksum)
29274c37757eSNguyen Trung Khanh                 {
29284c37757eSNguyen Trung Khanh                     res.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS;
29294c37757eSNguyen Trung Khanh                     res.flags.TcpFailed = !res.flags.TcpOK;
29304c37757eSNguyen Trung Khanh                 }
29314c37757eSNguyen Trung Khanh             }
29324c37757eSNguyen Trung Khanh             else /* UDP */
29334c37757eSNguyen Trung Khanh             {
29344c37757eSNguyen Trung Khanh                 if (f.fRxUDPChecksum)
29354c37757eSNguyen Trung Khanh                 {
29364c37757eSNguyen Trung Khanh                     res.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS;
29374c37757eSNguyen Trung Khanh                     res.flags.UdpFailed = !res.flags.UdpOK;
29384c37757eSNguyen Trung Khanh                 }
29394c37757eSNguyen Trung Khanh             }
29404c37757eSNguyen Trung Khanh         }
29414c37757eSNguyen Trung Khanh     }
29424c37757eSNguyen Trung Khanh     else if (ppr.ipStatus == ppresIPV6)
29434c37757eSNguyen Trung Khanh     {
29444c37757eSNguyen Trung Khanh         if(ppr.xxpStatus == ppresXxpKnown)
29454c37757eSNguyen Trung Khanh         {
29464c37757eSNguyen Trung Khanh             if(ppr.TcpUdp == ppresIsTCP) /* TCP */
29474c37757eSNguyen Trung Khanh             {
29484c37757eSNguyen Trung Khanh                 if (f.fRxTCPv6Checksum)
29494c37757eSNguyen Trung Khanh                 {
29504c37757eSNguyen Trung Khanh                     res.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS;
29514c37757eSNguyen Trung Khanh                     res.flags.TcpFailed = !res.flags.TcpOK;
29524c37757eSNguyen Trung Khanh                 }
29534c37757eSNguyen Trung Khanh             }
29544c37757eSNguyen Trung Khanh             else /* UDP */
29554c37757eSNguyen Trung Khanh             {
29564c37757eSNguyen Trung Khanh                 if (f.fRxUDPv6Checksum)
29574c37757eSNguyen Trung Khanh                 {
29584c37757eSNguyen Trung Khanh                     res.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS;
29594c37757eSNguyen Trung Khanh                     res.flags.UdpFailed = !res.flags.UdpOK;
29604c37757eSNguyen Trung Khanh                 }
29614c37757eSNguyen Trung Khanh             }
29624c37757eSNguyen Trung Khanh         }
29634c37757eSNguyen Trung Khanh     }
29644c37757eSNguyen Trung Khanh 
29654c37757eSNguyen Trung Khanh     if (pContext->bDoIPCheckRx &&
29664c37757eSNguyen Trung Khanh         (f.fRxIPChecksum || f.fRxTCPChecksum || f.fRxUDPChecksum || f.fRxTCPv6Checksum || f.fRxUDPv6Checksum))
29674c37757eSNguyen Trung Khanh     {
29684c37757eSNguyen Trung Khanh         ppr = ParaNdis_CheckSumVerify(pIpHeader, len - ETH_HEADER_SIZE, pcrAnyChecksum, __FUNCTION__);
29694c37757eSNguyen Trung Khanh         if (ppr.ipStatus == ppresIPV4 && !ppr.IsFragment)
29704c37757eSNguyen Trung Khanh         {
29714c37757eSNguyen Trung Khanh             resIp.flags.IpOK = !!f.fRxIPChecksum && ppr.ipCheckSum == ppresCSOK;
29724c37757eSNguyen Trung Khanh             resIp.flags.IpFailed = !!f.fRxIPChecksum && ppr.ipCheckSum == ppresCSBad;
29734c37757eSNguyen Trung Khanh             if (f.fRxTCPChecksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsTCP)
29744c37757eSNguyen Trung Khanh             {
29754c37757eSNguyen Trung Khanh                 resIp.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK;
29764c37757eSNguyen Trung Khanh                 resIp.flags.TcpFailed = ppr.xxpCheckSum == ppresCSBad;
29774c37757eSNguyen Trung Khanh             }
29784c37757eSNguyen Trung Khanh             if (f.fRxUDPChecksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsUDP)
29794c37757eSNguyen Trung Khanh             {
29804c37757eSNguyen Trung Khanh                 resIp.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK;
29814c37757eSNguyen Trung Khanh                 resIp.flags.UdpFailed = ppr.xxpCheckSum == ppresCSBad;
29824c37757eSNguyen Trung Khanh             }
29834c37757eSNguyen Trung Khanh         }
29844c37757eSNguyen Trung Khanh         else if (ppr.ipStatus == ppresIPV6)
29854c37757eSNguyen Trung Khanh         {
29864c37757eSNguyen Trung Khanh             if (f.fRxTCPv6Checksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsTCP)
29874c37757eSNguyen Trung Khanh             {
29884c37757eSNguyen Trung Khanh                 resIp.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK;
29894c37757eSNguyen Trung Khanh                 resIp.flags.TcpFailed = ppr.xxpCheckSum == ppresCSBad;
29904c37757eSNguyen Trung Khanh             }
29914c37757eSNguyen Trung Khanh             if (f.fRxUDPv6Checksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsUDP)
29924c37757eSNguyen Trung Khanh             {
29934c37757eSNguyen Trung Khanh                 resIp.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK;
29944c37757eSNguyen Trung Khanh                 resIp.flags.UdpFailed = ppr.xxpCheckSum == ppresCSBad;
29954c37757eSNguyen Trung Khanh             }
29964c37757eSNguyen Trung Khanh         }
29974c37757eSNguyen Trung Khanh 
29984c37757eSNguyen Trung Khanh         if (res.value != resIp.value)
29994c37757eSNguyen Trung Khanh         {
30004c37757eSNguyen Trung Khanh             // if HW did not set some bits that IP checker set, it is a mistake:
30014c37757eSNguyen Trung Khanh             // or GOOD CS is not labeled, or BAD checksum is not labeled
30024c37757eSNguyen Trung Khanh             tChecksumCheckResult diff;
30034c37757eSNguyen Trung Khanh             diff.value = resIp.value & ~res.value;
30044c37757eSNguyen Trung Khanh             if (diff.flags.IpFailed || diff.flags.TcpFailed || diff.flags.UdpFailed)
30054c37757eSNguyen Trung Khanh                 pContext->extraStatistics.framesRxCSHwMissedBad++;
30064c37757eSNguyen Trung Khanh             if (diff.flags.IpOK || diff.flags.TcpOK || diff.flags.UdpOK)
30074c37757eSNguyen Trung Khanh                 pContext->extraStatistics.framesRxCSHwMissedGood++;
30084c37757eSNguyen Trung Khanh             if (diff.value)
30094c37757eSNguyen Trung Khanh             {
30104c37757eSNguyen Trung Khanh                 DPrintf(0, ("[%s] real %X <> %X (virtio %X)", __FUNCTION__, resIp.value, res.value, virtioFlags));
30114c37757eSNguyen Trung Khanh             }
30124c37757eSNguyen Trung Khanh             res.value = resIp.value;
30134c37757eSNguyen Trung Khanh         }
30144c37757eSNguyen Trung Khanh     }
30154c37757eSNguyen Trung Khanh 
30164c37757eSNguyen Trung Khanh     return res;
30174c37757eSNguyen Trung Khanh }
3018