repository: C:/dev/kvm-guest-drivers-windows
branch: master
commit 738df9db5cec3199894839c265f72cfd72974d57
Author: Yan Vugenfirer <[email protected]>
Date:   Tue Apr 27 16:57:36 2010 +0300

    [WIN-GUEST-DRIVERS] Add complete support for MSI interrupts
    
        Signed-off-by: Yan Vugenfirer [email protected]

diff --git a/NetKVM/Common/ParaNdis-Common.c b/NetKVM/Common/ParaNdis-Common.c
index 35ec8e3..3c64cb0 100644
--- a/NetKVM/Common/ParaNdis-Common.c
+++ b/NetKVM/Common/ParaNdis-Common.c
@@ -916,8 +916,6 @@ NDIS_STATUS ParaNdis_FinishInitialization(PARANDIS_ADAPTER 
*pContext)
 #if !defined(UNIFY_LOCKS)
        NdisAllocateSpinLock(&pContext->ReceiveLock);
 #endif
-       NdisAllocateSpinLock(&pContext->DPCLock);
-
 
        InitializeListHead(&pContext->NetReceiveBuffers);
        InitializeListHead(&pContext->NetReceiveBuffersWaiting);
@@ -926,20 +924,6 @@ NDIS_STATUS ParaNdis_FinishInitialization(PARANDIS_ADAPTER 
*pContext)
 
        status = ParaNdis_FinishSpecificInitialization(pContext);
 
-       if (pContext->bBatchReceive && status == NDIS_STATUS_SUCCESS)
-       {
-               // prepare the buffer for batch data indication
-               // just to be on the safe side - double the number, 
pContext->NetMaxReceiveBuffers is enough
-               pContext->maxPacketsInBatch = pContext->NetMaxReceiveBuffers * 
2;
-               pContext->pBatchOfPackets =
-                       ParaNdis_AllocateMemory(pContext, 
sizeof(tPacketIndicationType) * pContext->maxPacketsInBatch);
-               if (!pContext->pBatchOfPackets)
-               {
-                       pContext->maxPacketsInBatch = 0;
-                       status = NDIS_STATUS_RESOURCES;
-               }
-       }
-
        if (status == NDIS_STATUS_SUCCESS)
        {
                status = ParaNdis_VirtIONetInit(pContext);
@@ -1028,6 +1012,22 @@ static void VirtIONetRelease(PARANDIS_ADAPTER *pContext)
 }
 
 
+static void PreventDPCServicing(PARANDIS_ADAPTER *pContext)
+{
+       LONG inside;;
+       pContext->bEnableInterruptHandlingDPC = FALSE;
+       do 
+       {
+               inside = InterlockedIncrement(&pContext->counterDPCInside);
+               InterlockedDecrement(&pContext->counterDPCInside);
+               if (inside > 1)
+               {
+                       DPrintf(0, ("[%s] waiting!", __FUNCTION__));
+                       NdisMSleep(20000);
+               }
+       } while (inside > 1);
+}
+
 /**********************************************************
 Frees all the resources allocated when the context initialized,
        calling also version-dependent part
@@ -1048,9 +1048,7 @@ VOID ParaNdis_CleanupContext(PARANDIS_ADAPTER *pContext)
                //DPrintf(0, ("cleanup %d", nActive));
        }
 
-       NdisAcquireSpinLock(&pContext->DPCLock);
-       pContext->bEnableInterruptHandlingDPC = FALSE;
-       NdisReleaseSpinLock(&pContext->DPCLock);
+       PreventDPCServicing(pContext);
 
        /****************************************
        ensure all the incoming packets returned,
@@ -1065,11 +1063,6 @@ VOID ParaNdis_CleanupContext(PARANDIS_ADAPTER *pContext)
        }
        VirtIONetRelease(pContext);
 
-       if (pContext->pBatchOfPackets)
-       {
-               NdisFreeMemory(pContext->pBatchOfPackets, 0, 0);
-       }
-
        ParaNdis_FinalizeCleanup(pContext);
 
        if (pContext->SendLock.SpinLock)
@@ -1083,10 +1076,6 @@ VOID ParaNdis_CleanupContext(PARANDIS_ADAPTER *pContext)
                NdisFreeSpinLock(&pContext->ReceiveLock);
        }
 #endif
-       if (pContext->DPCLock.SpinLock)
-       {
-               NdisFreeSpinLock(&pContext->DPCLock);
-       }
 
        if (pContext->AdapterResources.ulIOAddress)
        {
@@ -1095,7 +1084,7 @@ VOID ParaNdis_CleanupContext(PARANDIS_ADAPTER *pContext)
                        pContext->AdapterResources.ulIOAddress,
                        pContext->AdapterResources.IOLength,
                        pContext->pIoPortOffset);
-
+               pContext->AdapterResources.ulIOAddress = 0;
        }
 }
 
@@ -1115,32 +1104,48 @@ VOID ParaNdis_OnShutdown(PARANDIS_ADAPTER *pContext)
 Handles hardware interrupt
 Parameters:
        context
-       void *pDescriptor - pIONetDescriptor to return
+       ULONG knownInterruptSources - bitmask of 
 Return value:
        TRUE, if it is our interrupt
        sets *pRunDpc to TRUE if the DPC should be fired
 ***********************************************************/
 BOOLEAN ParaNdis_OnInterrupt(
        PARANDIS_ADAPTER *pContext,
-       BOOLEAN *pRunDpc)
+       OUT BOOLEAN *pRunDpc,
+       ULONG knownInterruptSources)
 {
        ULONG status;
-       BOOLEAN b;
-       status = VirtIODeviceISR(&pContext->IODevice);
-       // ignore interrupts with invalid status bits
-       if (
-               status == VIRTIO_NET_INVALID_INTERRUPT_STATUS ||
-               pContext->powerState != NetDeviceStateD0
-               )
-               status = 0;
-       InterlockedOr(&pContext->InterruptStatus, (LONG)status);
-       b = !!status;
-       *pRunDpc = b;
-       if (b)
+       BOOLEAN b = FALSE;
+       if (knownInterruptSources == isAny)
+       {
+               status = VirtIODeviceISR(&pContext->IODevice);
+               // ignore interrupts with invalid status bits
+               if (
+                       status == VIRTIO_NET_INVALID_INTERRUPT_STATUS ||
+                       pContext->powerState != NetDeviceStateD0
+                       )
+                       status = 0;
+               if (status)
+               {
+                       *pRunDpc = TRUE;
+                       b = TRUE;
+                       
NdisGetCurrentSystemTime(&pContext->LastInterruptTimeStamp);
+                       ParaNdis_VirtIOEnableIrqSynchronized(pContext, isAny, 
FALSE);
+                       status = (status & 2) ? isControl : 0;
+                       status |= isReceive | isTransmit;
+                       InterlockedOr(&pContext->InterruptStatus, (LONG)status);
+               }
+       }
+       else
        {
+               b = TRUE;       
+               *pRunDpc = TRUE;
                NdisGetCurrentSystemTime(&pContext->LastInterruptTimeStamp);
-               ParaNdis_VirtIOEnableInterrupt(pContext, FALSE);
+               InterlockedOr(&pContext->InterruptStatus, 
(LONG)knownInterruptSources);
+               ParaNdis_VirtIOEnableIrqSynchronized(pContext, 
knownInterruptSources, FALSE);
+               status = knownInterruptSources;
        }
+       DPrintf(5, ("[%s](src%X)=>st%X", __FUNCTION__, knownInterruptSources, 
status));
        return b;
 }
 
@@ -1244,11 +1249,16 @@ UINT ParaNdis_VirtIONetReleaseTransmitBuffers(
        {
                NdisGetCurrentSystemTime(&pContext->LastTxCompletionTimeStamp);
                pContext->bDoKickOnNoBuffer = TRUE;
+               pContext->nDetectedStoppedTx = 0;
        }
        DEBUG_EXIT_STATUS((i ? 3 : 5), i);
        return i;
 }
 
+/*********************************************************
+Called with from ProcessTx routine with TxLock held
+Uses pContext->sgTxGatherTable
+***********************************************************/
 tCopyPacketResult ParaNdis_DoSubmitPacket(PARANDIS_ADAPTER *pContext, 
tTxOperationParameters *Params)
 {
        tCopyPacketResult result;
@@ -1604,6 +1614,10 @@ static UINT ParaNdis_ProcessRxPath(PARANDIS_ADAPTER 
*pContext)
        UINT len, headerSize = pContext->nVirtioHeaderSize;
        eInspectedPacketType packetType = iptInvalid;
        UINT nReceived = 0, nRetrieved = 0, nReported = 0;
+       tPacketIndicationType   *pBatchOfPackets;
+       UINT                                    maxPacketsInBatch = 
pContext->NetMaxReceiveBuffers;
+       pBatchOfPackets = pContext->bBatchReceive ? 
+               ParaNdis_AllocateMemory(pContext, maxPacketsInBatch * 
sizeof(tPacketIndicationType)) : NULL;
        NdisAcquireSpinLock(&pContext->ReceiveLock);
        while ((uLoopCount++ < pContext->uRXPacketsDPCLimit) && NULL != 
(pBuffersDescriptor = 
pContext->NetReceiveQueue->vq_ops->get_buf(pContext->NetReceiveQueue, &len)))
        {
@@ -1622,7 +1636,7 @@ static UINT ParaNdis_ProcessRxPath(PARANDIS_ADAPTER 
*pContext)
                {
                        BOOLEAN b = FALSE;
                        ULONG length = len - headerSize;
-                       if (!pContext->pBatchOfPackets)
+                       if (!pBatchOfPackets)
                        {
                                NdisReleaseSpinLock(&pContext->ReceiveLock);
                                b = NULL != ParaNdis_IndicateReceivedPacket(
@@ -1643,7 +1657,7 @@ static UINT ParaNdis_ProcessRxPath(PARANDIS_ADAPTER 
*pContext)
                                        TRUE,
                                        pBuffersDescriptor);
                                b = packet != NULL;
-                               if (b) pContext->pBatchOfPackets[nReceived] = 
packet;
+                               if (b) pBatchOfPackets[nReceived] = packet;
                        }
                        if (!b)
                        {
@@ -1673,10 +1687,11 @@ static UINT ParaNdis_ProcessRxPath(PARANDIS_ADAPTER 
*pContext)
                                                
pContext->Statistics.ifHCInUcastOctets += length;
                                                break;
                                }
-                               if (pContext->pBatchOfPackets && nReceived == 
pContext->maxPacketsInBatch)
+                               if (pBatchOfPackets && nReceived == 
maxPacketsInBatch)
                                {
+                                       DPrintf(1, ("[%s] received %d buffers", 
__FUNCTION__, nReceived));
                                        
NdisReleaseSpinLock(&pContext->ReceiveLock);
-                                       
ParaNdis_IndicateReceivedBatch(pContext, nReceived);
+                                       
ParaNdis_IndicateReceivedBatch(pContext, pBatchOfPackets, nReceived);
                                        
NdisAcquireSpinLock(&pContext->ReceiveLock);
                                        nReceived = 0;
                                }
@@ -1690,12 +1705,12 @@ static UINT ParaNdis_ProcessRxPath(PARANDIS_ADAPTER 
*pContext)
        }
        ParaNdis_DebugHistory(pContext, hopReceiveStat, NULL, nRetrieved, 
nReported, pContext->NetNofReceiveBuffers);
        NdisReleaseSpinLock(&pContext->ReceiveLock);
-       if (nReceived)
+       if (nReceived && pBatchOfPackets)
        {
                DPrintf(1, ("[%s] received %d buffers", __FUNCTION__, 
nReceived));
-               if (pContext->pBatchOfPackets)
-                       ParaNdis_IndicateReceivedBatch(pContext, nReceived);
+               ParaNdis_IndicateReceivedBatch(pContext, pBatchOfPackets, 
nReceived);
        }
+       if (pBatchOfPackets) NdisFreeMemory(pBatchOfPackets, 0, 0);
        return nRetrieved;
 }
 
@@ -1713,71 +1728,82 @@ void ParaNdis_ReportLinkStatus(PARANDIS_ADAPTER 
*pContext)
        ParaNdis_IndicateConnect(pContext, bConnected, FALSE);
 }
 
-BOOLEAN ParaNdis_MiniportSynchronizeInterruptEnable(IN PVOID  
SynchronizeContext)
-{
-       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)SynchronizeContext;
-
-       DEBUG_ENTRY(6);
-       ParaNdis_VirtIOEnableInterrupt(pContext, TRUE);
 
-       return TRUE;
+static BOOLEAN RestartQueueSynchronously(tSynchronizedContext *SyncContext)
+{
+       PARANDIS_ADAPTER *pContext = SyncContext->pContext;
+       BOOLEAN b = 0;
+       if (SyncContext->Parameter & isReceive)
+       {
+               b = 
!pContext->NetReceiveQueue->vq_ops->restart(pContext->NetReceiveQueue);
+       }
+       if (SyncContext->Parameter & isTransmit)
+       {
+               b = 
!pContext->NetSendQueue->vq_ops->restart(pContext->NetSendQueue);
+       }
+       return b;
 }
-
 /**********************************************************
 DPC implementation, common for both NDIS
 Parameters:
        context
 ***********************************************************/
-void ParaNdis_DPCWorkBody(PARANDIS_ADAPTER *pContext)
+ULONG ParaNdis_DPCWorkBody(PARANDIS_ADAPTER *pContext)
 {
-       int nRestartResult = 2, nLoop = 0;
-       LONG interruptStatus;
+       ULONG stillRequiresProcessing = 0;
+       ULONG interruptSources;
        DEBUG_ENTRY(5);
-       NdisAcquireSpinLock(&pContext->DPCLock);
-       ParaNdis_DebugHistory(pContext, hopDPC, NULL, 1, 
pContext->InterruptStatus, 0);
-       if (pContext->bEnableInterruptHandlingDPC)
-       {
-               pContext->bDPCInactive = FALSE;
-               interruptStatus = 
InterlockedExchange(&pContext->InterruptStatus, 0);
-#ifdef VIRTIO_SIGNAL_ERROR
-               if (interruptStatus & 4)
-               {
-                       DPrintf(0, ("[%s] ERROR signaled by hardware!!!!!", 
__FUNCTION__));
-               }
-#endif
-               if (interruptStatus & 2)
-               {
-                       if (pContext->bLinkDetectSupported) 
ParaNdis_ReportLinkStatus(pContext);
-               }
-               ParaNdis_ProcessTx(pContext, TRUE);
-               while (nRestartResult)
+       ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)1, 0, 0, 0);
+       if (pContext->bEnableInterruptHandlingDPC)      
+       {
+               InterlockedIncrement(&pContext->counterDPCInside);
+               if (pContext->bEnableInterruptHandlingDPC)
                {
-                       UINT n = ParaNdis_ProcessRxPath(pContext);
-                       if (nRestartResult == 1 && !n)
+                       InterlockedExchange(&pContext->bDPCInactive, 0);
+                       interruptSources = 
InterlockedExchange(&pContext->InterruptStatus, 0);
+                       if ((interruptSources & isControl) && 
pContext->bLinkDetectSupported)
+                       {
+                               ParaNdis_ReportLinkStatus(pContext);
+                       }
+                       if (interruptSources & isTransmit)
                        {
-                               DPrintf(0, ("[%s] Rx restarted by mistake", 
__FUNCTION__));
+                               ParaNdis_ProcessTx(pContext, TRUE);
                        }
-                       NdisAcquireSpinLock(&pContext->ReceiveLock);
-                       nRestartResult = 
!pContext->NetReceiveQueue->vq_ops->restart(pContext->NetReceiveQueue);
-                       NdisReleaseSpinLock(&pContext->ReceiveLock);
-                       DPrintf(nRestartResult ? 2 : 6, ("[%s] queue 
restarted%s", __FUNCTION__, nRestartResult ? "(Rerun)" : ""));
-                       ++nLoop;
-                       if (nRestartResult && pContext->InterruptStatus)
+                       if (interruptSources & isReceive)
                        {
-                               DPrintf(2, ("[%s] another dpc already 
scheduled(%d)", __FUNCTION__, nLoop));
-                               break;
+                               int nRestartResult = 2, nLoop = 0;
+                               while (nRestartResult)
+                               {
+                                       UINT n = 
ParaNdis_ProcessRxPath(pContext);
+
+                                       
NdisAcquireSpinLock(&pContext->ReceiveLock);
+                                       nRestartResult = 
ParaNdis_SynchronizeWithInterrupt(
+                                               pContext, 
pContext->ulRxMessage, RestartQueueSynchronously, isReceive); 
+                                       
NdisReleaseSpinLock(&pContext->ReceiveLock);
+                                       DPrintf(nRestartResult ? 2 : 6, ("[%s] 
queue restarted%s", __FUNCTION__, nRestartResult ? "(Rerun)" : "(Done)"));
+                                       
+                                       ++nLoop;
+                                       if (nLoop > MAX_RX_LOOPS)
+                                       {
+                                               DPrintf(0, ("[%s] Breaking Rx 
loop on %d-th operation", __FUNCTION__, nLoop));
+                                               break;
+                                       }
+                               }
+                               if (nRestartResult) stillRequiresProcessing |= 
isReceive;
                        }
-                       if (nLoop == 1000)
+
+                       if (interruptSources & isTransmit)
                        {
-                               DPrintf(0, ("[%s] Too many (%d) Rx restarts, 
prevent infinite loop", __FUNCTION__, nLoop));
-                               break;
+                               NdisAcquireSpinLock(&pContext->SendLock);
+                               if (ParaNdis_SynchronizeWithInterrupt(pContext, 
pContext->ulTxMessage, RestartQueueSynchronously, isTransmit)) 
+                                       stillRequiresProcessing |= isTransmit;
+                               NdisReleaseSpinLock(&pContext->SendLock);
                        }
                }
+               InterlockedDecrement(&pContext->counterDPCInside);
+               ParaNdis_DebugHistory(pContext, hopDPC, NULL, 
stillRequiresProcessing, pContext->nofFreeHardwareBuffers, 
pContext->nofFreeTxDescriptors);
        }
-       ParaNdis_DebugHistory(pContext, hopDPC, NULL, 0, 
pContext->nofFreeHardwareBuffers, pContext->nofFreeTxDescriptors);
-       NdisReleaseSpinLock(&pContext->DPCLock);
-
-       ParaNdis_SyncInterruptEnable(pContext);
+       return stillRequiresProcessing;
 }
 
 /**********************************************************
@@ -1790,47 +1816,31 @@ static BOOLEAN CheckRunningDpc(PARANDIS_ADAPTER 
*pContext)
 {
        BOOLEAN bStopped;
        BOOLEAN bReportHang = FALSE;
-       NdisAcquireSpinLock(&pContext->DPCLock);
-       bStopped = pContext->bDPCInactive;
-       pContext->bDPCInactive = TRUE;
-       NdisReleaseSpinLock(&pContext->DPCLock);
+       bStopped = 0 != InterlockedExchange(&pContext->bDPCInactive, TRUE);
 
        if (bStopped)
        {
                pContext->nDetectedInactivity++;
                if (pContext->nEnableDPCChecker)
                {
-                       DPrintf(0, ("[%s] - NO ACTIVITY!", __FUNCTION__));
-                       if (!pContext->Limits.nPrintDiagnostic) 
PrintStatistics(pContext);
-                       if (pContext->nEnableDPCChecker > 1)
+                       if (pContext->NetTxPacketsToReturn)
                        {
-                               int isrStatus1, isrStatus2;
-                               isrStatus1 = 
VirtIODeviceISR(&pContext->IODevice);
-                               isrStatus2 = 
VirtIODeviceISR(&pContext->IODevice);
-                               if (isrStatus1 || isrStatus2)
+                               DPrintf(0, ("[%s] - NO ACTIVITY!", 
__FUNCTION__));
+                               if (!pContext->Limits.nPrintDiagnostic) 
PrintStatistics(pContext);
+                               if (pContext->nEnableDPCChecker > 1)
                                {
-                                       DPrintf(0, ("WARNING: Interrupt status 
%d=>%d", isrStatus1, isrStatus2));
+                                       int isrStatus1, isrStatus2;
+                                       isrStatus1 = 
VirtIODeviceISR(&pContext->IODevice);
+                                       isrStatus2 = 
VirtIODeviceISR(&pContext->IODevice);
+                                       if (isrStatus1 || isrStatus2)
+                                       {
+                                               DPrintf(0, ("WARNING: Interrupt 
status %d=>%d", isrStatus1, isrStatus2));
+                                       }
                                }
+                               // simulateDPC
+                               InterlockedOr(&pContext->InterruptStatus, 
isAny);                       
+                               ParaNdis_DPCWorkBody(pContext);
                        }
-                       // simulateDPC
-                       ParaNdis_DPCWorkBody(pContext);
-               }
-               else
-               {
-                       // this works only without scatter-gather...
-                       // TODO: provide some kind of detection also for SG case
-                       NdisAcquireSpinLock(&pContext->SendLock);
-                       if (pContext->NetTxPacketsToReturn && 
!pContext->nofFreeTxDescriptors)
-                       {
-                               DPrintf(0, ("[%s] - Tx path does not transfer 
data!", __FUNCTION__));
-                               bReportHang = TRUE;
-                               pContext->nDetectedStoppedTx++;
-                               // TODO: remove it when the problem solved
-                               // just to be able to make breakpoint or dump 
in QEMU
-                               // when such a problem happens
-                               WriteVirtIODeviceByte(pContext->IODevice.addr + 
VIRTIO_PCI_ISR, 1);
-                       }
-                       NdisReleaseSpinLock(&pContext->SendLock);
                }
        }
        else
@@ -1838,6 +1848,18 @@ static BOOLEAN CheckRunningDpc(PARANDIS_ADAPTER 
*pContext)
                pContext->nDetectedInactivity = 0;
        }
 
+       NdisAcquireSpinLock(&pContext->SendLock);
+       if (pContext->nofFreeHardwareBuffers != 
pContext->maxFreeHardwareBuffers)
+       {
+               if (pContext->nDetectedStoppedTx++ > 1)
+               {
+                       DPrintf(0, ("[%s] - Suspicious Tx inactivity (%d)!", 
__FUNCTION__, pContext->nofFreeHardwareBuffers));
+                       //bReportHang = TRUE;
+                       WriteVirtIODeviceByte(pContext->IODevice.addr + 
VIRTIO_PCI_ISR, 0);
+               }
+       }
+       NdisReleaseSpinLock(&pContext->SendLock);
+
 
        if (pContext->Limits.nPrintDiagnostic &&
                ++pContext->Counters.nPrintDiagnostic >= 
pContext->Limits.nPrintDiagnostic)
@@ -1881,13 +1903,13 @@ u32 ReadVirtIODeviceRegister(ULONG_PTR ulRegister)
 
        NdisRawReadPortUlong(ulRegister, &ulValue);
 
-       DPrintf(6, ("%s> R[%x] = %x\n", __FUNCTION__, (ULONG)ulRegister, 
ulValue) );
+       DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__, (ULONG)ulRegister, ulValue) );
        return ulValue;
 }
 
 void WriteVirtIODeviceRegister(ULONG_PTR ulRegister, u32 ulValue)
 {
-       DPrintf(6, ("%s> R[%x] = %x\n", __FUNCTION__, (ULONG)ulRegister, 
ulValue) );
+       DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__, (ULONG)ulRegister, ulValue) );
 
        NdisRawWritePortUlong(ulRegister, ulValue);
 }
@@ -1898,14 +1920,14 @@ u8 ReadVirtIODeviceByte(ULONG_PTR ulRegister)
 
        NdisRawReadPortUchar(ulRegister, &bValue);
 
-       DPrintf(6, ("%s> R[%x] = %x\n", __FUNCTION__, (ULONG)ulRegister, 
bValue) );
+       DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__, (ULONG)ulRegister, bValue) );
 
        return bValue;
 }
 
 void WriteVirtIODeviceByte(ULONG_PTR ulRegister, u8 bValue)
 {
-       DPrintf(6, ("%s> R[%x] = %x\n", __FUNCTION__, (ULONG)ulRegister, 
bValue) );
+       DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__, (ULONG)ulRegister, bValue) );
 
        NdisRawWritePortUchar(ulRegister, bValue);
 }
@@ -1916,7 +1938,7 @@ u16 ReadVirtIODeviceWord(ULONG_PTR ulRegister)
 
        NdisRawReadPortUshort(ulRegister, &wValue);
 
-       DPrintf(6, ("%s> R[%x] = %x\n", __FUNCTION__, (ULONG)ulRegister, 
wValue) );
+       DPrintf(6, ("[%s]R[%x]=%x\n", __FUNCTION__, (ULONG)ulRegister, wValue) 
);
 
        return wValue;
 }
@@ -1980,7 +2002,7 @@ NDIS_STATUS ParaNdis_SetMulticastList(
                if (length)
                        NdisMoveMemory(pContext->MulticastList, Buffer, length);
                pContext->MulticastListSize = length;
-               DPrintf(0, ("[%s] New multicast list of %d bytes", 
__FUNCTION__, length));
+               DPrintf(1, ("[%s] New multicast list of %d bytes", 
__FUNCTION__, length));
                *pBytesRead = length;
                status = NDIS_STATUS_SUCCESS;
        }
@@ -1988,16 +2010,19 @@ NDIS_STATUS ParaNdis_SetMulticastList(
 }
 
 /**********************************************************
-
+Callable from synchronized routine or interrupt handler
+to enable or disable Rx and/or Tx interrupt generation
 Parameters:
-Return value:
+       context
+       interruptSource - isReceive, isTransmit
+       b - 1/0 enable/disable
 ***********************************************************/
-VOID ParaNdis_VirtIOEnableInterrupt(
-       PARANDIS_ADAPTER *pContext,
-       BOOLEAN bEnable)
+VOID ParaNdis_VirtIOEnableIrqSynchronized(PARANDIS_ADAPTER *pContext, ULONG 
interruptSource, BOOLEAN b)
 {
-       
pContext->NetSendQueue->vq_ops->enable_interrupt(pContext->NetSendQueue, 
bEnable);
-       
pContext->NetReceiveQueue->vq_ops->enable_interrupt(pContext->NetReceiveQueue, 
bEnable);
+       if (interruptSource & isTransmit)
+               
pContext->NetSendQueue->vq_ops->enable_interrupt(pContext->NetSendQueue, b);
+       if (interruptSource & isReceive)
+               
pContext->NetReceiveQueue->vq_ops->enable_interrupt(pContext->NetReceiveQueue, 
b);
 }
 
 /**********************************************************
@@ -2060,6 +2085,7 @@ VOID ParaNdis_PowerOn(PARANDIS_ADAPTER *pContext)
 
        VirtIODeviceRenewVirtualQueue(pContext->NetReceiveQueue);
        VirtIODeviceRenewVirtualQueue(pContext->NetSendQueue);
+       ParaNdis_RestoreDeviceConfigurationAfterReset(pContext);
 
        InitializeListHead(&TempList);
        /* submit all the receive buffers */
@@ -2109,9 +2135,7 @@ VOID ParaNdis_PowerOff(PARANDIS_ADAPTER *pContext)
        ParaNdis_Suspend(pContext);
        pContext->powerState = NetDeviceStateD3;
 
-       NdisAcquireSpinLock(&pContext->DPCLock);
-       pContext->bEnableInterruptHandlingDPC = FALSE;
-       NdisReleaseSpinLock(&pContext->DPCLock);
+       PreventDPCServicing(pContext);
 
        /*******************************************************************
                shutdown queues to have all the receive buffers under our 
control
@@ -2143,5 +2167,12 @@ VOID ParaNdis_PowerOff(PARANDIS_ADAPTER *pContext)
        ParaNdis_DebugHistory(pContext, hopPowerOff, NULL, 0, 0, 0);
 }
 
+void ParaNdis_CallOnBugCheck(PARANDIS_ADAPTER *pContext)
+{
+       if (pContext->AdapterResources.ulIOAddress)
+       {
+               WriteVirtIODeviceByte(pContext->IODevice.addr + VIRTIO_PCI_ISR, 
1);
+       }
+}
 
 
diff --git a/NetKVM/Common/ParaNdis-Debug.c b/NetKVM/Common/ParaNdis-Debug.c
index 86b9cae..ad3d56c 100644
--- a/NetKVM/Common/ParaNdis-Debug.c
+++ b/NetKVM/Common/ParaNdis-Debug.c
@@ -272,6 +272,7 @@ static UINT FillDataOnBugCheck()
                pSave->nofReadyTxBuffers = p->nofFreeHardwareBuffers;
                pSave->LastInterruptTimeStamp = p->LastInterruptTimeStamp;
                pSave->LastTxCompletionTimeStamp = p->LastTxCompletionTimeStamp;
+               ParaNdis_CallOnBugCheck(p);
                ++n;
        }
        return n;
diff --git a/NetKVM/Common/ndis56common.h b/NetKVM/Common/ndis56common.h
index 3fd23a8..d8a25af 100644
--- a/NetKVM/Common/ndis56common.h
+++ b/NetKVM/Common/ndis56common.h
@@ -54,9 +54,6 @@
 #error "Something is wrong with our versioning"
 #endif
 
-//define to start really using MSI-X interrupt in Vista+
-//#define VIRTIO_USE_MSIX_INTERRUPT
-
 //define to see when the status register is unreadable(see 
ParaNdis_ResetVirtIONetDevice)
 //#define VIRTIO_RESET_VERIFY
 
@@ -65,8 +62,10 @@
 
 // define if qemu supports logging to static IO port for synchronization
 // of driver output with qemu printouts; in this case define the port number
-//#define VIRTIO_DBG_USE_IOPORT        0x99
+// #define VIRTIO_DBG_USE_IOPORT       0x99
 
+// to be set to real limit later 
+#define MAX_RX_LOOPS   1000
 
 /* The feature bitmap for virtio net */
 #define VIRTIO_NET_F_CSUM      0       /* Host handles pkts w/ partial csum */
@@ -96,6 +95,17 @@
 #define PARANDIS_MIN_LSO_SEGMENTS                      2
 #define PARANDIS_MAX_LSO_SIZE                          0xF000
 
+typedef enum _tagInterruptSource 
+{ 
+       isReceive  = 0x01, 
+       isTransmit = 0x02, 
+       isControl  = 0x04,
+       isUnknown  = 0x08,
+       isBothTransmitReceive = isReceive | isTransmit, 
+       isAny      = isReceive | isTransmit | isControl | isUnknown,
+       isDisable  = 0x80
+}tInterruptSource;
+
 static const ULONG PARANDIS_PACKET_FILTERS =
        NDIS_PACKET_TYPE_DIRECTED |
        NDIS_PACKET_TYPE_MULTICAST |
@@ -242,7 +252,6 @@ typedef struct _tagPARANDIS_ADAPTER
        LARGE_INTEGER                   LastTxCompletionTimeStamp;
        LARGE_INTEGER                   LastInterruptTimeStamp;
        BOOLEAN                                 bConnected;
-       BOOLEAN                                 bDPCInactive;
        BOOLEAN                                 bEnableInterruptHandlingDPC;
        BOOLEAN                                 bEnableInterruptChecking;
        BOOLEAN                                 bDoInterruptRecovery;
@@ -260,6 +269,8 @@ typedef struct _tagPARANDIS_ADAPTER
        BOOLEAN                                 bSurprizeRemoved;
        BOOLEAN                                 bUsingMSIX;
        NDIS_DEVICE_POWER_STATE powerState;
+       LONG                                    counterDPCInside;
+       LONG                                    bDPCInactive;
        LONG                                    InterruptStatus;
        ULONG                                   ulPriorityVlanSetting;
        ULONG                                   VlanId;
@@ -289,7 +300,6 @@ typedef struct _tagPARANDIS_ADAPTER
        NDIS_SPIN_LOCK                  ReceiveLock;
        };
 #endif
-       NDIS_SPIN_LOCK                  DPCLock;
        NDIS_STATISTICS_INFO    Statistics;
        tOurCounters                    Counters;
        tOurCounters                    Limits;
@@ -324,13 +334,17 @@ typedef struct _tagPARANDIS_ADAPTER
        LONG                                    NetTxPacketsToReturn;
        /* total of Rx buffer in turnaround */
        UINT                                    NetMaxReceiveBuffers;
-       tPacketIndicationType   *pBatchOfPackets;
-       UINT                                    maxPacketsInBatch;
        struct VirtIOBufferDescriptor *sgTxGatherTable;
        UINT                                    nPnpEventIndex;
        NDIS_DEVICE_PNP_EVENT   PnpEvents[16];
        tOffloadSettings                Offload;
        NDIS_OFFLOAD_PARAMETERS InitialOffloadParameters;
+       // we keep these members common for XP and Vista
+       // for XP and non-MSI case of Vista they are set to zero
+       ULONG                                           ulRxMessage;
+       ULONG                                           ulTxMessage;
+       ULONG                                           ulControlMessage;
+
 #if NDIS60_MINIPORT
 // Vista +
        PIO_INTERRUPT_MESSAGE_INFO      pMSIXInfoTable;
@@ -354,6 +368,7 @@ typedef struct _tagPARANDIS_ADAPTER
        LIST_ENTRY                                      TxWaitingList;
        NDIS_EVENT                                      HaltEvent;
        NDIS_TIMER                                      ConnectTimer;
+       NDIS_TIMER                                      DPCPostProcessTimer;
        BOOLEAN                                         bDmaInitialized;
 #endif
 }PARANDIS_ADAPTER, *PPARANDIS_ADAPTER;
@@ -365,6 +380,13 @@ typedef struct _tagCopyPacketResult
        enum tCopyPacketError { cpeOK, cpeNoBuffer, cpeInternalError, 
cpeTooLarge } error;
 }tCopyPacketResult;
 
+typedef struct _tagSynchronizedContext
+{
+       PARANDIS_ADAPTER *pContext;
+       ULONG                    Parameter;
+}tSynchronizedContext;
+
+typedef BOOLEAN (*tSynchronizedProcedure)(tSynchronizedContext *context);
 
 /**********************************************************
 LAZZY release procedure returns buffers to VirtIO
@@ -430,13 +452,7 @@ void ParaNdis_VirtIONetReuseRecvBuffer(
 UINT ParaNdis_VirtIONetReleaseTransmitBuffers(
        PARANDIS_ADAPTER *pContext);
 
-void ParaNdis_DPCWorkBody(
-       PARANDIS_ADAPTER *pContext);
-
-BOOLEAN ParaNdis_MiniportSynchronizeInterruptEnable(
-       IN PVOID SynchronizeContext);
-
-void ParaNdis_SyncInterruptEnable(
+ULONG ParaNdis_DPCWorkBody(
        PARANDIS_ADAPTER *pContext);
 
 NDIS_STATUS ParaNdis_SetMulticastList(
@@ -446,9 +462,10 @@ NDIS_STATUS ParaNdis_SetMulticastList(
        PUINT pBytesRead,
        PUINT pBytesNeeded);
 
-VOID ParaNdis_VirtIOEnableInterrupt(
+VOID ParaNdis_VirtIOEnableIrqSynchronized(
        PARANDIS_ADAPTER *pContext,
-       BOOLEAN bEnable);
+       ULONG interruptSource,
+       BOOLEAN b);
 
 VOID ParaNdis_OnPnPEvent(
        PARANDIS_ADAPTER *pContext,
@@ -458,7 +475,8 @@ VOID ParaNdis_OnPnPEvent(
 
 BOOLEAN ParaNdis_OnInterrupt(
        PARANDIS_ADAPTER *pContext,
-       BOOLEAN *pRunDpc);
+       BOOLEAN *pRunDpc,
+       ULONG knownInterruptSources);
 
 VOID ParaNdis_OnShutdown(
        PARANDIS_ADAPTER *pContext);
@@ -532,6 +550,8 @@ tCopyPacketResult ParaNdis_DoSubmitPacket(PARANDIS_ADAPTER 
*pContext, tTxOperati
 
 void ParaNdis_ResetOffloadSettings(PARANDIS_ADAPTER *pContext, 
tOffloadSettingsFlags *pDest, PULONG from);
 
+void ParaNdis_CallOnBugCheck(PARANDIS_ADAPTER *pContext);
+
 /*****************************************************
 Procedures to implement for NDIS specific implementation
 ******************************************************/
@@ -558,6 +578,7 @@ tPacketIndicationType ParaNdis_IndicateReceivedPacket(
 
 VOID ParaNdis_IndicateReceivedBatch(
        PARANDIS_ADAPTER *pContext,
+       tPacketIndicationType *pBatch,
        ULONG nofPackets);
 
 
@@ -584,6 +605,12 @@ BOOLEAN ParaNdis_SetTimer(
        NDIS_HANDLE timer,
        LONG millies);
 
+BOOLEAN ParaNdis_SynchronizeWithInterrupt(
+       PARANDIS_ADAPTER *pContext,
+       ULONG messageId,
+       tSynchronizedProcedure procedure,
+       ULONG parameter);
+
 VOID ParaNdis_Suspend(
        PARANDIS_ADAPTER *pContext);
 
@@ -635,6 +662,9 @@ void ParaNdis_IndicateConnect(
        BOOLEAN bConnected,
        BOOLEAN bForce);
 
+void ParaNdis_RestoreDeviceConfigurationAfterReset(
+       PARANDIS_ADAPTER *pContext);
+
 #endif //-OFFLOAD_UNIT_TEST
 
 typedef enum _tagppResult
diff --git a/NetKVM/wlh/ParaNdis6-Driver.c b/NetKVM/wlh/ParaNdis6-Driver.c
index 1ceaef6..9e7a06a 100644
--- a/NetKVM/wlh/ParaNdis6-Driver.c
+++ b/NetKVM/wlh/ParaNdis6-Driver.c
@@ -16,6 +16,11 @@
 
 //#define NO_VISTA_POWER_MANAGEMENT
 
+//by default printouts from resource filtering are invisible
+//change it to 2 or smaller to make it visible always 
+ULONG bDisableMSI = FALSE;
+LONG resourceFilterLevel = 3;
+
 #ifdef WPP_EVENT_TRACING
 #include "ParaNdis6-Driver.tmh"
 #endif
@@ -141,66 +146,18 @@ static VOID ConnectTimerCallback(
        ParaNdis_ReportLinkStatus(pContext);
 }
 
-#define VISTA_RECOVERY_CANCEL_TIMER                                            
1
-#define VISTA_RECOVERY_RUN_DPC                                                 
2
-#define VISTA_RECOVERY_INFO_ONLY_SECOND_READ                   4
-
-
-static UCHAR MiniportSynchronizeInterruptProcedure(PVOID  SynchronizeContext)
-{
-       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)SynchronizeContext;
-       BOOLEAN b1;
-       UCHAR val = ParaNdis_OnInterrupt(pContext, &b1);
-       if (val)
-       {
-               // we read the interrupt, in any case run the DRC
-               val = VISTA_RECOVERY_RUN_DPC;
-               b1 = !VirtIODeviceISR(&pContext->IODevice);
-               // if we read it again, it does not mean anything
-               if (b1) val |= VISTA_RECOVERY_INFO_ONLY_SECOND_READ;
-       }
-       else
-       {
-               // we did not read the interrupt
-               val = (pContext->ulIrqReceived > 1) ? 
VISTA_RECOVERY_CANCEL_TIMER : 0;
-       }
-       return val;
-}
-
-
-
 /**********************************************************
 This is timer procedure for Interrupt recovery timer
 ***********************************************************/
-static VOID InteruptRecoveryTimerCallback(
+static VOID InterruptRecoveryTimerCallback(
        IN PVOID  SystemSpecific1,
        IN PVOID  FunctionContext,
        IN PVOID  SystemSpecific2,
        IN PVOID  SystemSpecific3
        )
 {
-       UCHAR val;
        PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)FunctionContext;
-       val = NdisMSynchronizeWithInterruptEx(
-               pContext->InterruptHandle,
-               0,
-               MiniportSynchronizeInterruptProcedure,
-               pContext);
-       if (val & VISTA_RECOVERY_RUN_DPC)
-               ParaNdis_DPCWorkBody(pContext);
-       /* this does not happen and as such, not related to the problem
-       if (val == VISTA_RECOVERY_RUN_DPC)
-       {
-               DPrintf(0, ("[%s] The interrupt was still set", __FUNCTION__));
-       }
-       */
-       if (~val & VISTA_RECOVERY_CANCEL_TIMER)
-               ParaNdis_SetTimer(pContext->InterruptRecoveryTimer, 15);
-       else
-       {
-               DPrintf(0, ("[%s] Cancelled", __FUNCTION__));
-       }
-       DEBUG_EXIT_STATUS(5, val);
+       ParaNdis6_OnInterruptRecoveryTimer(pContext);
 }
 
 
@@ -223,7 +180,7 @@ static NDIS_STATUS CreateTimers(PARANDIS_ADAPTER *pContext)
        status = NdisAllocateTimerObject(pContext->MiniportHandle, &tch, 
&pContext->ConnectTimer);
        if (status == NDIS_STATUS_SUCCESS)
        {
-               tch.TimerFunction = InteruptRecoveryTimerCallback;
+               tch.TimerFunction = InterruptRecoveryTimerCallback;
                status = NdisAllocateTimerObject(pContext->MiniportHandle, 
&tch, &pContext->InterruptRecoveryTimer);
        }
        DEBUG_EXIT_STATUS(2, status);
@@ -413,7 +370,10 @@ static NDIS_STATUS ParaNdis6_Initialize(
                if (pContext->ulMilliesToConnect)
                        ParaNdis_SetTimer(pContext->ConnectTimer, 
pContext->ulMilliesToConnect);
                if (pContext->bDoInterruptRecovery)
-                       ParaNdis_SetTimer(pContext->InterruptRecoveryTimer, 
15); //15 mSec is the recovery timeout
+               {
+                       //200 mSec for first shot of recovery circuit
+                       ParaNdis_SetTimer(pContext->InterruptRecoveryTimer, 
200); 
+               }
        }
        DEBUG_EXIT_STATUS(status ? 0 : 2, status);
        return status;
@@ -834,8 +794,9 @@ static PIO_RESOURCE_REQUIREMENTS_LIST 
ParseFilterResourceIrp(
        BOOLEAN bRemoveMSIResources)
 {
        tRRLData newRRLData;
+       ULONG nRemoved = 0;
        PIO_RESOURCE_REQUIREMENTS_LIST newPrrl = NULL;
-       DPrintf(0, ("[%s]%s", __FUNCTION__, bRemoveMSIResources ? "(Remove MSI 
resources...)" : ""));
+       DPrintf(resourceFilterLevel, ("[%s]%s", __FUNCTION__, 
bRemoveMSIResources ? "(Remove MSI resources...)" : ""));
        if (MiniportAddDeviceContext && prrl) newPrrl = 
(PIO_RESOURCE_REQUIREMENTS_LIST)NdisAllocateMemoryWithTagPriority(
                        MiniportAddDeviceContext,
                        prrl->ListSize,
@@ -846,7 +807,7 @@ static PIO_RESOURCE_REQUIREMENTS_LIST 
ParseFilterResourceIrp(
        {
                ULONG n, offset;
                PVOID p = &prrl->List[0];
-               DPrintf(0, ("[%s] %d bytes, %d lists", __FUNCTION__, 
prrl->ListSize, prrl->AlternativeLists));
+               DPrintf(resourceFilterLevel, ("[%s] %d bytes, %d lists", 
__FUNCTION__, prrl->ListSize, prrl->AlternativeLists));
                offset = RtlPointerToOffset(prrl, p);
                for (n = 0; n < prrl->AlternativeLists && offset < 
prrl->ListSize; ++n)
                {
@@ -855,7 +816,7 @@ static PIO_RESOURCE_REQUIREMENTS_LIST 
ParseFilterResourceIrp(
                        if ((offset + sizeof(*pior)) < prrl->ListSize)
                        {
                                IO_RESOURCE_DESCRIPTOR *pd = 
&pior->Descriptors[0];
-                               DPrintf(0, ("[%s]+%d %d:%d descriptors follow", 
__FUNCTION__, offset, n, pior->Count));
+                               DPrintf(resourceFilterLevel, ("[%s]+%d %d:%d 
descriptors follow", __FUNCTION__, offset, n, pior->Count));
                                offset += RtlPointerToOffset(p, pd);
                                AddNewResourceList(&newRRLData, pior);
                                for (nDesc = 0; nDesc < pior->Count; ++nDesc)
@@ -863,10 +824,11 @@ static PIO_RESOURCE_REQUIREMENTS_LIST 
ParseFilterResourceIrp(
                                        BOOLEAN bRemove = FALSE;
                                        if ((offset + sizeof(*pd)) <= 
prrl->ListSize)
                                        {
-                                               DPrintf(0, ("[%s]+%d %d: type 
%d, flags %X, option %X",
-                                                       __FUNCTION__, offset, 
nDesc, pd->Type, pd->Flags, pd->Option));
+                                               DPrintf(resourceFilterLevel, 
("[%s]+%d %d: type %d, flags %X, option %X", __FUNCTION__, offset, nDesc, 
pd->Type, pd->Flags, pd->Option));
                                                if (pd->Type == 
CmResourceTypeInterrupt)
                                                {
+                                                       
+                                                       //DPrintf(1, ("    
policy %d, affinity %X", pd->u.Interrupt.AffinityPolicy, 
pd->u.Interrupt.TargetedProcessors));
                                                        if (pd->Flags & 
CM_RESOURCE_INTERRUPT_MESSAGE)
                                                        {
                                                                bRemove = 
bRemoveMSIResources;
@@ -882,6 +844,7 @@ static PIO_RESOURCE_REQUIREMENTS_LIST 
ParseFilterResourceIrp(
                                                        }
                                                }
                                                if (!bRemove) 
AddNewResourceDescriptor(&newRRLData, pd);
+                                               else nRemoved++;
                                        }
                                        offset += sizeof(*pd);
                                        pd = (IO_RESOURCE_DESCRIPTOR 
*)RtlOffsetToPointer(prrl, offset);
@@ -891,7 +854,10 @@ static PIO_RESOURCE_REQUIREMENTS_LIST 
ParseFilterResourceIrp(
                        }
                }
        }
-
+       if (bRemoveMSIResources && nRemoved)
+       {
+               DPrintf(0, ("[%s] %d resources removed", __FUNCTION__, 
nRemoved));
+       }
        return newPrrl;
 }
 
@@ -907,12 +873,8 @@ we just enumerate allocated resources and do not modify 
them.
 *******************************************************************/
 static NDIS_STATUS ParaNdis6_FilterResource(IN NDIS_HANDLE  
MiniportAddDeviceContext, IN PIRP  Irp)
 {
-       BOOLEAN bRemoveMSI = FALSE;
        PIO_RESOURCE_REQUIREMENTS_LIST prrl = 
(PIO_RESOURCE_REQUIREMENTS_LIST)(PVOID)Irp->IoStatus.Information;
-#if !defined(VIRTIO_USE_MSIX_INTERRUPT)
-       bRemoveMSI = TRUE;
-#endif
-       if (bRemoveMSI)
+       if (bDisableMSI)
        {
                // traverse the resource requirements list, clean up all the 
MSI resources
                PIO_RESOURCE_REQUIREMENTS_LIST newPrrl = 
ParseFilterResourceIrp(MiniportAddDeviceContext, prrl, TRUE);
@@ -920,8 +882,8 @@ static NDIS_STATUS ParaNdis6_FilterResource(IN NDIS_HANDLE  
MiniportAddDeviceCon
                {
                        Irp->IoStatus.Information = (ULONG_PTR)newPrrl;
                        NdisFreeMemory(prrl, 0, 0);
-                       DPrintf(0, ("[%s] Reparsing resources using new 
requirements...", __FUNCTION__));
-                       // just parse and print after MSI cleanup, this time do 
not remove amything and do not reallocate the list
+                       DPrintf(resourceFilterLevel, ("[%s] Reparsing resources 
after filtering...", __FUNCTION__));
+                       // just parse and print after MSI cleanup, this time do 
not remove anything and do not reallocate the list
                        ParseFilterResourceIrp(NULL, newPrrl, FALSE);
                }
        }
@@ -957,6 +919,61 @@ static NDIS_STATUS ParaNdis6_SetOptions(IN  NDIS_HANDLE 
NdisDriverHandle, IN  ND
        return status;
 }
 
+static NDIS_STATUS ReadGlobalConfigurationEntry(NDIS_HANDLE cfg, const char 
*_name, PULONG pValue)
+{
+       NDIS_STATUS status;
+       PNDIS_CONFIGURATION_PARAMETER pParam = NULL;
+       NDIS_STRING name;
+       const char *statusName;
+       NDIS_PARAMETER_TYPE ParameterType = NdisParameterInteger;
+       NdisInitializeString(&name, (PUCHAR)_name);
+       NdisReadConfiguration(
+               &status,
+               &pParam,
+               cfg,
+               &name,
+               ParameterType);
+       if (status == NDIS_STATUS_SUCCESS)
+       {
+               *pValue = pParam->ParameterData.IntegerData;
+               statusName = "value";
+       }
+       else
+       {
+               statusName = "nothing";
+       }
+       DPrintf(2, ("[%s] %s read for %s - 0x%x", __FUNCTION__, statusName, 
_name, *pValue));
+       NdisFreeString(name);
+       return status;
+}
+
+static void RetrieveDriverConfiguration()
+{
+       NDIS_CONFIGURATION_OBJECT co;
+       NDIS_HANDLE cfg, params;
+       NDIS_STATUS status;
+       DEBUG_ENTRY(2);
+       co.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+       co.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+       co.Header.Size = sizeof(co);
+       co.Flags = 0;
+       co.NdisHandle = DriverHandle;
+       status = NdisOpenConfigurationEx(&co, &cfg);
+       if (status == NDIS_STATUS_SUCCESS)
+       {
+               NDIS_STRING paramsName;
+               NdisInitializeString(&paramsName, (PUCHAR)"Parameters");
+               NdisOpenConfigurationKeyByName(&status, cfg, &paramsName, 
&params);
+               if (status == NDIS_STATUS_SUCCESS)
+               {
+                       ReadGlobalConfigurationEntry(params, "DisableMSI", 
&bDisableMSI);
+                       ReadGlobalConfigurationEntry(params, "EarlyDebug", 
(PULONG)&resourceFilterLevel);
+                       NdisCloseConfiguration(params);
+               }
+               NdisCloseConfiguration(cfg);
+       }
+}
+
 /**********************************************************
 Driver entry point:
 Register miniport driver
@@ -1028,6 +1045,10 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, 
PUNICODE_STRING pRegistryPath
                        NULL,
                        KE_PROCESSOR_CHANGE_ADD_EXISTING);
        }
+       if (status == NDIS_STATUS_SUCCESS)
+       {
+               RetrieveDriverConfiguration();
+       }
        DEBUG_EXIT_STATUS(status ? 0 : 4, status);
        return status;
 }
diff --git a/NetKVM/wlh/ParaNdis6-Impl.c b/NetKVM/wlh/ParaNdis6-Impl.c
index d781fd8..7a74a08 100644
--- a/NetKVM/wlh/ParaNdis6-Impl.c
+++ b/NetKVM/wlh/ParaNdis6-Impl.c
@@ -175,6 +175,18 @@ VOID ParaNdis_FreePhysicalMemory(
                pAddresses->Physical);
 }
 
+BOOLEAN ParaNdis_SynchronizeWithInterrupt(
+       PARANDIS_ADAPTER *pContext,
+       ULONG messageId,
+       tSynchronizedProcedure procedure,
+       ULONG parameter)
+{
+       tSynchronizedContext SyncContext;
+       SyncContext.pContext  = pContext;
+       SyncContext.Parameter = parameter;
+       return NdisMSynchronizeWithInterruptEx(pContext->InterruptHandle, 
messageId, procedure, &SyncContext);
+}
+
 /**********************************************************
 NDIS-required procedure for hardware interrupt registration
 Parameters:
@@ -183,7 +195,7 @@ Parameters:
 static VOID MiniportDisableInterruptEx(IN PVOID MiniportInterruptContext)
 {
        DEBUG_ENTRY(0);
-       ParaNdis_VirtIOEnableInterrupt((PARANDIS_ADAPTER 
*)MiniportInterruptContext, FALSE);
+       ParaNdis_VirtIOEnableIrqSynchronized((PARANDIS_ADAPTER 
*)MiniportInterruptContext, isAny, FALSE);
 }
 
 /**********************************************************
@@ -194,7 +206,7 @@ Parameters:
 static VOID MiniportEnableInterruptEx(IN PVOID MiniportInterruptContext)
 {
        DEBUG_ENTRY(0);
-       ParaNdis_VirtIOEnableInterrupt((PARANDIS_ADAPTER 
*)MiniportInterruptContext, TRUE);
+       ParaNdis_VirtIOEnableIrqSynchronized((PARANDIS_ADAPTER 
*)MiniportInterruptContext, isAny, TRUE);
 }
 
 /**********************************************************
@@ -214,13 +226,21 @@ static BOOLEAN MiniportInterrupt(
 {
        PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER 
*)MiniportInterruptContext;
        BOOLEAN b;
-       b = ParaNdis_OnInterrupt(pContext, QueueDefaultInterruptDpc);
+       b = ParaNdis_OnInterrupt(pContext, QueueDefaultInterruptDpc, isAny);
        *TargetProcessors = 0;
        pContext->ulIrqReceived += b;
-
        return b;
 }
 
+static ULONG MessageToInterruptSource(PARANDIS_ADAPTER *pContext, ULONG  
MessageId)
+{
+       ULONG interruptSource = 0;
+       if (MessageId == pContext->ulRxMessage) interruptSource |= isReceive;   
+       if (MessageId == pContext->ulTxMessage) interruptSource |= isTransmit;  
+       if (MessageId == pContext->ulControlMessage) interruptSource |= 
isControl;
+       return interruptSource;
+}
+
 /**********************************************************
 NDIS-required procedure for MSI hardware interrupt handling
 Parameters:
@@ -238,24 +258,15 @@ static BOOLEAN MiniportMSIInterrupt(
     OUT PULONG  TargetProcessors
     )
 {
-       BOOLEAN b = MiniportInterrupt(MiniportInterruptContext, 
QueueDefaultInterruptDpc, TargetProcessors);
+       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER 
*)MiniportInterruptContext;
+       BOOLEAN b;
+       ULONG interruptSource = MessageToInterruptSource(pContext, MessageId);
+       b = ParaNdis_OnInterrupt(pContext, QueueDefaultInterruptDpc, 
interruptSource);
+       pContext->ulIrqReceived += b;
        return b;
 }
 
 /**********************************************************
-Syncronize interrupt enable from DPC
-Parameters:
-       context
-***********************************************************/
-void ParaNdis_SyncInterruptEnable(PARANDIS_ADAPTER *pContext)
-{
-       NdisMSynchronizeWithInterruptEx(pContext->InterruptHandle,
-                                                                       0,
-                                                                       
ParaNdis_MiniportSynchronizeInterruptEnable,
-                                                                       
pContext);
-}
-
-/**********************************************************
 NDIS-required procedure for DPC handling
 Parameters:
        PVOID  MiniportInterruptContext (Adapter context)
@@ -268,8 +279,15 @@ static VOID MiniportInterruptDPC(
     )
 {
        PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER 
*)MiniportInterruptContext;
-       DEBUG_ENTRY(3);
-       ParaNdis_DPCWorkBody(pContext);
+       ULONG requiresProcessing;
+       DEBUG_ENTRY(5);
+       requiresProcessing = ParaNdis_DPCWorkBody(pContext);
+       if (requiresProcessing)
+       {
+               DPrintf(4, ("[%s] Queued additional DPC for %d", __FUNCTION__,  
requiresProcessing));
+               InterlockedOr(&pContext->InterruptStatus, requiresProcessing);
+               NdisMQueueDpc(pContext->InterruptHandle, 0, 1 << 
KeGetCurrentProcessorNumber(), pContext);
+       }
 }
 
 /**********************************************************
@@ -287,8 +305,15 @@ static VOID MiniportMSIInterruptDpc(
     )
 {
        PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER 
*)MiniportInterruptContext;
-       DPrintf(0, ("[%s] (Message %d)", __FUNCTION__, MessageId));
-       ParaNdis_DPCWorkBody(pContext);
+       ULONG interruptSource = MessageToInterruptSource(pContext, MessageId);
+       DPrintf(5, ("[%s] (Message %d, source %d)", __FUNCTION__, MessageId, 
interruptSource));
+       interruptSource = ParaNdis_DPCWorkBody(pContext);
+       if (interruptSource)
+       {
+               DPrintf(4, ("[%s] Queued additional DPC for %d", __FUNCTION__, 
interruptSource));
+               InterlockedOr(&pContext->InterruptStatus, interruptSource);
+               NdisMQueueDpc(pContext->InterruptHandle, MessageId, 1 << 
KeGetCurrentProcessorNumber(), pContext);
+       }
 }
 
 static VOID MiniportDisableMSIInterrupt(
@@ -296,8 +321,10 @@ static VOID MiniportDisableMSIInterrupt(
     IN ULONG  MessageId
     )
 {
-       DEBUG_ENTRY(0);
-       ParaNdis_VirtIOEnableInterrupt((PARANDIS_ADAPTER 
*)MiniportInterruptContext, FALSE);
+       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER 
*)MiniportInterruptContext;
+       ULONG interruptSource = MessageToInterruptSource(pContext, MessageId);
+       DPrintf(0, ("[%s] (Message %d)", __FUNCTION__, MessageId));
+       ParaNdis_VirtIOEnableIrqSynchronized(pContext, interruptSource, FALSE);
 }
 
 static VOID MiniportEnableMSIInterrupt(
@@ -305,8 +332,10 @@ static VOID MiniportEnableMSIInterrupt(
     IN ULONG  MessageId
     )
 {
-       DEBUG_ENTRY(0);
-       ParaNdis_VirtIOEnableInterrupt((PARANDIS_ADAPTER 
*)MiniportInterruptContext, TRUE);
+       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER 
*)MiniportInterruptContext;
+       ULONG interruptSource = MessageToInterruptSource(pContext, MessageId);
+       DPrintf(0, ("[%s] (Message %d)", __FUNCTION__, MessageId));
+       ParaNdis_VirtIOEnableIrqSynchronized(pContext, interruptSource, TRUE);
 }
 
 
@@ -327,32 +356,83 @@ static VOID SharedMemAllocateCompleteHandler(
 
 }
 
-static NDIS_STATUS SetInterruptMessage(PARANDIS_ADAPTER *pContext, UINT 
queueIndex, ULONG messageData)
+static NDIS_STATUS SetInterruptMessage(PARANDIS_ADAPTER *pContext, UINT 
queueIndex)
 {
        NDIS_STATUS status = NDIS_STATUS_SUCCESS;
-       ULONG val = messageData - 1;
+       ULONG val;
+       ULONG  messageIndex = queueIndex < 
pContext->pMSIXInfoTable->MessageCount ?
+               queueIndex : (pContext->pMSIXInfoTable->MessageCount - 1);
+       PULONG pMessage = NULL;
        switch (queueIndex)
        {
-       case 0: case 1: // queue interrupt:
+       case 0: // Rx queue interrupt:
+               WriteVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_QUEUE_SEL, (u16)queueIndex);
+               WriteVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG + 2, (u16)messageIndex);
+               val = ReadVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG + 2);
+               pMessage = &pContext->ulRxMessage;
+               break;
+       case 1: // Tx queue interrupt:
                WriteVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_QUEUE_SEL, (u16)queueIndex);
-               WriteVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG + 2, (u16)messageData);
+               WriteVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG + 2, (u16)messageIndex);
                val = ReadVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG + 2);
+               pMessage = &pContext->ulTxMessage;
                break;
        case 2: // config interrupt
-               WriteVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG, (u16)messageData);
+               WriteVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG, (u16)messageIndex);
                val = ReadVirtIODeviceWord(pContext->IODevice.addr + 
VIRTIO_PCI_CONFIG);
+               pMessage = &pContext->ulControlMessage;
                break;
        default:
                break;
        }
-       if (val != messageData)
+
+       if (val != messageIndex)
        {
-               DPrintf(0, ("[%s] ERROR: Wrong MSI-X message for 
q%d(w%X,r%X)!", __FUNCTION__, queueIndex, messageData, val));
+               DPrintf(0, ("[%s] ERROR: Wrong MSI-X message for 
q%d(w%X,r%X)!", __FUNCTION__, queueIndex, messageIndex, val));
                status = NDIS_STATUS_DEVICE_FAILED;
        }
+       if (pMessage) *pMessage = messageIndex;
+       return status;
+}
+
+static NDIS_STATUS ConfigureMSIXVectors(PARANDIS_ADAPTER *pContext)
+{
+       NDIS_STATUS status = NDIS_STATUS_RESOURCES;
+       UINT i;
+       PIO_INTERRUPT_MESSAGE_INFO pTable = pContext->pMSIXInfoTable;
+       if (pTable && pTable->MessageCount)
+       {
+               status = NDIS_STATUS_SUCCESS;
+               DPrintf(0, ("[%s] Using MSIX interrupts (%d messages, irql %d)",
+                       __FUNCTION__, pTable->MessageCount, 
pTable->UnifiedIrql));
+               for (i = 0; i < pContext->pMSIXInfoTable->MessageCount; ++i)
+               {
+                       DPrintf(0, ("[%s] MSIX message%d=%08X=>%I64X",
+                               __FUNCTION__, i,
+                               pTable->MessageInfo[i].MessageData,
+                               pTable->MessageInfo[i].MessageAddress));
+               }
+               for (i = 0; i < 3 && status == NDIS_STATUS_SUCCESS; ++i)
+               {
+                       status = SetInterruptMessage(pContext, i);
+               }
+       }
+       if (status == NDIS_STATUS_SUCCESS)
+       {
+               DPrintf(0, ("[%s] Using message %d for RX queue", __FUNCTION__, 
pContext->ulRxMessage));
+               DPrintf(0, ("[%s] Using message %d for TX queue", __FUNCTION__, 
pContext->ulTxMessage));
+               DPrintf(0, ("[%s] Using message %d for controls", __FUNCTION__, 
pContext->ulControlMessage));
+       }
        return status;
 }
 
+void ParaNdis_RestoreDeviceConfigurationAfterReset(
+       PARANDIS_ADAPTER *pContext)
+{
+       ConfigureMSIXVectors(pContext);
+}
+
+
 /**********************************************************
 NDIS6-related final initialization:
        Installing interrupt handler
@@ -378,7 +458,6 @@ NDIS_STATUS 
ParaNdis_FinishSpecificInitialization(PARANDIS_ADAPTER *pContext)
        mic.EnableInterruptHandler  = MiniportEnableInterruptEx;
        mic.InterruptDpcHandler = MiniportInterruptDPC;
        mic.InterruptHandler = MiniportInterrupt;
-#ifdef VIRTIO_USE_MSIX_INTERRUPT
        if (pContext->bUsingMSIX)
        {
                mic.MsiSupported = TRUE;
@@ -388,7 +467,6 @@ NDIS_STATUS 
ParaNdis_FinishSpecificInitialization(PARANDIS_ADAPTER *pContext)
                mic.MessageInterruptHandler = MiniportMSIInterrupt;
                mic.MessageInterruptDpcHandler = MiniportMSIInterruptDpc;
        }
-#endif
        PoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
        PoolParams.Header.Size = sizeof(PoolParams);
        PoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
@@ -434,28 +512,8 @@ NDIS_STATUS 
ParaNdis_FinishSpecificInitialization(PARANDIS_ADAPTER *pContext)
        {
                if (NDIS_CONNECT_MESSAGE_BASED == mic.InterruptType)
                {
-                       UINT i;
-                       DPrintf(0, ("[%s] Using MSIX interrupts (%d messages, 
irql %d)",
-                               __FUNCTION__, 
mic.MessageInfoTable->MessageCount, mic.MessageInfoTable->UnifiedIrql));
-                       for (i = 0; mic.MessageInfoTable && i < 
mic.MessageInfoTable->MessageCount; ++i)
-                       {
-                               DPrintf(0, ("[%s] MSIX message%d=%08X=>%I64X",
-                                       __FUNCTION__, i,
-                                       
mic.MessageInfoTable->MessageInfo[i].MessageData,
-                                       
mic.MessageInfoTable->MessageInfo[i].MessageAddress));
-                       }
-                       status = SetInterruptMessage(pContext, 0, 0);
-                       if (NDIS_STATUS_SUCCESS == status)
-                       {
-                               i = mic.MessageInfoTable->MessageCount > 1 ? 1 
: 0;
-                               status = SetInterruptMessage(pContext, 1, i);
-                       }
-                       if (NDIS_STATUS_SUCCESS == status)
-                       {
-                               i = mic.MessageInfoTable->MessageCount > 2 ? 2 
: 0;
-                               status = SetInterruptMessage(pContext, 2, i);
-                       }
                        pContext->pMSIXInfoTable = mic.MessageInfoTable;
+                       status = ConfigureMSIXVectors(pContext);
                        //pContext->bDoInterruptRecovery = FALSE;
                }
                else if (pContext->bUsingMSIX)
@@ -661,21 +719,22 @@ tPacketIndicationType ParaNdis_IndicateReceivedPacket(
 
 VOID ParaNdis_IndicateReceivedBatch(
        PARANDIS_ADAPTER *pContext,
+       tPacketIndicationType *pBatch,
        ULONG nofPackets)
 {
        ULONG i;
-       PNET_BUFFER_LIST pPrev = pContext->pBatchOfPackets[0];
+       PNET_BUFFER_LIST pPrev = pBatch[0];
        NET_BUFFER_LIST_NEXT_NBL(pPrev) = NULL;
        for (i = 1; i < nofPackets; ++i)
        {
-               PNET_BUFFER_LIST pNBL = pContext->pBatchOfPackets[i];
+               PNET_BUFFER_LIST pNBL = pBatch[i];
                NET_BUFFER_LIST_NEXT_NBL(pPrev) = pNBL;
                NET_BUFFER_LIST_NEXT_NBL(pNBL)  = NULL;
                pPrev = pNBL;
        }
        NdisMIndicateReceiveNetBufferLists(
                pContext->MiniportHandle,
-               pContext->pBatchOfPackets[0],
+               pBatch[0],
                0,
                nofPackets,
                0);
@@ -1936,4 +1995,56 @@ VOID ParaNdis6_CancelSendNetBufferLists(
        DEBUG_EXIT_STATUS(0, nCancelled);
 }
 
+#define VISTA_RECOVERY_CANCEL_TIMER                                            
1
+#define VISTA_RECOVERY_RUN_DPC                                                 
2
+#define VISTA_RECOVERY_INFO_ONLY_SECOND_READ                   4
+
+
+static UCHAR MiniportSyncRecoveryProcedure(PVOID  SynchronizeContext)
+{
+       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)SynchronizeContext;
+       BOOLEAN b;
+       UCHAR val = 0;
+       if (pContext->ulIrqReceived)
+       {
+               val = VISTA_RECOVERY_CANCEL_TIMER;
+       }
+       else
+       {
+               b = ParaNdis_OnInterrupt(pContext, &b, isAny);
+               if (b)
+               {
+                       // we read the interrupt, in any case run the DRC
+                       val = VISTA_RECOVERY_RUN_DPC;
+                       b = !VirtIODeviceISR(&pContext->IODevice);
+                       // if we read it again, it does not mean anything
+                       if (b) val |= VISTA_RECOVERY_INFO_ONLY_SECOND_READ;
+               }
+       }
+       return val;
+}
+
+
+VOID ParaNdis6_OnInterruptRecoveryTimer(PARANDIS_ADAPTER *pContext)
+{
+       UCHAR val;
+       val = NdisMSynchronizeWithInterruptEx(
+               pContext->InterruptHandle,
+               0,
+               MiniportSyncRecoveryProcedure,
+               pContext);
+       if (val & VISTA_RECOVERY_RUN_DPC)
+       {
+               InterlockedOr(&pContext->InterruptStatus, isAny);
+               ParaNdis_DPCWorkBody(pContext);
+       }
+       if (~val & VISTA_RECOVERY_CANCEL_TIMER)
+               ParaNdis_SetTimer(pContext->InterruptRecoveryTimer, 15);
+       else
+       {
+               DPrintf(0, ("[%s] Cancelled", __FUNCTION__));
+       }
+       DEBUG_EXIT_STATUS(5, val);
+}
+
 #endif // NDIS60_MINIPORT
diff --git a/NetKVM/wlh/ParaNdis6-Oid.c b/NetKVM/wlh/ParaNdis6-Oid.c
index 35a7d2b..e71e80c 100644
--- a/NetKVM/wlh/ParaNdis6-Oid.c
+++ b/NetKVM/wlh/ParaNdis6-Oid.c
@@ -490,7 +490,7 @@ NDIS_STATUS ParaNdis_OnSetPower(PARANDIS_ADAPTER *pContext, 
tOidDesc *pOid)
 
 static void DumpOffloadStructure(NDIS_OFFLOAD *po, LPCSTR message)
 {
-       int level = 0;
+       int level = 1;
        ULONG *pul;
        DPrintf(level, ("[%s](%s)", __FUNCTION__, message));
        pul = (ULONG *)&po->Checksum.IPv4Transmit;
diff --git a/NetKVM/wlh/ParaNdis6.h b/NetKVM/wlh/ParaNdis6.h
index 9deaddb..3c1fa7f 100644
--- a/NetKVM/wlh/ParaNdis6.h
+++ b/NetKVM/wlh/ParaNdis6.h
@@ -59,6 +59,9 @@ NDIS_STATUS ParaNdis6_ReceivePauseRestart(
        ONPAUSECOMPLETEPROC Callback
        );
 
+VOID ParaNdis6_OnInterruptRecoveryTimer(
+       PARANDIS_ADAPTER *pContext);
+
 
 /* returns number of buffers that have been sent */
 UINT ParaNdis6_CopyDataFromSingleNBL(PARANDIS_ADAPTER *pContext, 
PNET_BUFFER_LIST pNBL);
diff --git a/NetKVM/wlh/netkvm.inf b/NetKVM/wlh/netkvm.inf
index e0f1846..8143375 100644
--- a/NetKVM/wlh/netkvm.inf
+++ b/NetKVM/wlh/netkvm.inf
@@ -27,12 +27,12 @@ DriverPackageDisplayName = %kvmnet6.DeviceDesc%
 AddReg          = kvmnet6.EnableMSI
 
 [kvmnet6.EnableMSI]
-HKR, "Interrupt Management",, 0x00000010
-HKR, "Interrupt Management\MessageSignaledInterruptProperties",, 0x00000010
+;HKR, "Interrupt Management",, 0x00000010
+;HKR, "Interrupt Management\MessageSignaledInterruptProperties",, 0x00000010
 HKR, "Interrupt Management\MessageSignaledInterruptProperties",        
MSISupported, 0x00010001, 1
 HKR, "Interrupt Management\MessageSignaledInterruptProperties", 
MessageNumberLimit, 0x00010001, 4
-HKR, "Interrupt Management\Affinity Policy",, 0x00000010
-HKR, "Interrupt Management\Affinity Policy", DevicePolicy, 0x00010001, 1
+;HKR, "Interrupt Management\Affinity Policy",, 0x00000010
+HKR, "Interrupt Management\Affinity Policy", DevicePolicy, 0x00010001, 0
 HKR, "Interrupt Management\Affinity Policy", DevicePriority, 0x00010001, 2
 
 
@@ -250,7 +250,9 @@ HKR, , EventMessageFile, 0x00020000, 
"%%SystemRoot%%\System32\netevent.dll"
 HKR, , TypesSupported,   0x00010001, 7
 
 [TextModeFlags.Reg]
-HKR, , TextModeFlags,    0x00010001, 0x0001
+HKR,,TextModeFlags,0x00010001, 0x0001
+HKR,Parameters,DisableMSI,,"0" 
+HKR,Parameters,EarlyDebug,,"3" 
 
 [SourceDisksNames]
 1 = %DiskId1%,,,""
diff --git a/NetKVM/wxp/ParaNdis5-Driver.c b/NetKVM/wxp/ParaNdis5-Driver.c
index 12aeeef..160f579 100644
--- a/NetKVM/wxp/ParaNdis5-Driver.c
+++ b/NetKVM/wxp/ParaNdis5-Driver.c
@@ -22,8 +22,6 @@
 static NDIS_HANDLE             DriverHandle;
 static ULONG                   gID = 0;
 
-static DRIVER_UNLOAD ParaVirtualNICUnload;
-
 /******************************************************
 Unload handler, only responsibility is cleanup WPP
 *******************************************************/
@@ -322,6 +320,7 @@ static VOID ParaNdis5_Halt(
                NdisSetEvent(&pContext->HaltEvent);
        WaitHaltEvent(pContext, "Receive");
        ParaNdis_CleanupContext(pContext);
+       NdisCancelTimer(&pContext->DPCPostProcessTimer, &bUnused);
        ParaNdis_DebugHistory(pContext, hopHalt, NULL, 0, 0, 0);
        ParaNdis_DebugRegisterMiniport(pContext, FALSE);
        NdisFreeMemory(pContext, 0, 0);
@@ -339,18 +338,6 @@ static BOOLEAN ParaNdis5_CheckForHang(IN NDIS_HANDLE 
MiniportAdapterContext)
        return ParaNdis_CheckForHang(pContext);
 }
 
-
-
-/*************************************************************
-Required NDIS procedure, just calls regular (Common) DPC processing
-*************************************************************/
-static VOID ParaNdis5_HandleDPC(IN NDIS_HANDLE MiniportAdapterContext)
-{
-       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
-       DEBUG_ENTRY(7);
-       ParaNdis_DPCWorkBody(pContext);
-}
-
 /*************************************************************
 Required NDIS procedure
 Responsible for hardware interrupt handling
@@ -362,7 +349,7 @@ static VOID ParaNdis5_MiniportISR(OUT PBOOLEAN 
InterruptRecognized,
        PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
        BOOLEAN b;
        *QueueMiniportHandleInterrupt = FALSE;
-       b = ParaNdis_OnInterrupt(pContext, QueueMiniportHandleInterrupt);
+       b = ParaNdis_OnInterrupt(pContext, QueueMiniportHandleInterrupt, isAny);
        *InterruptRecognized = b;
        DEBUG_EXIT_STATUS(7, (ULONG)b);
 }
diff --git a/NetKVM/wxp/ParaNdis5-Impl.c b/NetKVM/wxp/ParaNdis5-Impl.c
index 0808811..1e4a401 100644
--- a/NetKVM/wxp/ParaNdis5-Impl.c
+++ b/NetKVM/wxp/ParaNdis5-Impl.c
@@ -158,6 +158,29 @@ BOOLEAN ParaNdis_InitialAllocatePhysicalMemory(
        return pAddresses->Virtual != NULL;
 }
 
+/**********************************************************
+Callback of timer for pending events cleanup after regular DPC processing
+Parameters:
+       context (on FunctionContext)
+       all the rest are irrelevant
+***********************************************************/
+static VOID OnDPCPostProcessTimer(
+       IN PVOID  SystemSpecific1,
+       IN PVOID  FunctionContext,
+       IN PVOID  SystemSpecific2,
+       IN PVOID  SystemSpecific3
+       )
+{
+       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)FunctionContext;
+       ULONG requiresProcessing;
+       requiresProcessing = ParaNdis_DPCWorkBody(pContext);
+       if (requiresProcessing)
+       {
+               // we need to request additional DPC
+               InterlockedOr(&pContext->InterruptStatus, requiresProcessing);
+               NdisSetTimer(&pContext->DPCPostProcessTimer, 10);
+       }
+}
 
 /**********************************************************
 NDIS5 implementation of shared memory freeing
@@ -205,6 +228,7 @@ NDIS_STATUS ParaNdis_FinishSpecificInitialization(
        InitializeListHead(&pContext->SendQueue);
        InitializeListHead(&pContext->TxWaitingList);
        NdisInitializeTimer(&pContext->ConnectTimer, OnConnectTimer, pContext);
+       NdisInitializeTimer(&pContext->DPCPostProcessTimer, 
OnDPCPostProcessTimer, pContext);
 
        status = NdisMRegisterInterrupt(
                &pContext->Interrupt,
@@ -466,11 +490,12 @@ tPacketIndicationType ParaNdis_IndicateReceivedPacket(
 
 VOID ParaNdis_IndicateReceivedBatch(
        PARANDIS_ADAPTER *pContext,
+       tPacketIndicationType *pBatch,
        ULONG nofPackets)
 {
        NdisMIndicateReceivePacket(
                pContext->MiniportHandle,
-               pContext->pBatchOfPackets,
+               pBatch,
                nofPackets);
 }
 
@@ -1237,18 +1262,6 @@ NDIS_STATUS ParaNdis5_StopSend(PARANDIS_ADAPTER 
*pContext, BOOLEAN bStop, ONPAUS
 }
 
 /**********************************************************
-Syncronize interrupt enable from DPC
-Parameters:
-       context
-***********************************************************/
-void ParaNdis_SyncInterruptEnable(PARANDIS_ADAPTER *pContext)
-{
-       NdisMSynchronizeWithInterrupt(&pContext->Interrupt,
-                                                                 
ParaNdis_MiniportSynchronizeInterruptEnable,
-                                                                 pContext);
-}
-
-/**********************************************************
 Pause or resume receive operation:
 Parameters:
        context
@@ -1291,5 +1304,38 @@ NDIS_STATUS ParaNdis5_StopReceive(
        return status;
 }
 
+/*************************************************************
+Required NDIS procedure, spawns regular (Common) DPC processing
+*************************************************************/
+VOID ParaNdis5_HandleDPC(IN NDIS_HANDLE MiniportAdapterContext)
+{
+       PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
+       ULONG requiresProcessing;
+       BOOLEAN unused;
+       DEBUG_ENTRY(7);
+       // we do not need the timer, as DPC will do all the job
+       // this is not a problem if the timer procedure is already running, 
+       // we need to do our job anyway
+       NdisCancelTimer(&pContext->DPCPostProcessTimer, &unused);
+       requiresProcessing = ParaNdis_DPCWorkBody(pContext);
+       if (requiresProcessing)
+       {
+               // we need to request additional DPC
+               InterlockedOr(&pContext->InterruptStatus, requiresProcessing);
+               NdisSetTimer(&pContext->DPCPostProcessTimer, 10);
+       }
+}
+
+BOOLEAN ParaNdis_SynchronizeWithInterrupt(
+       PARANDIS_ADAPTER *pContext,
+       ULONG messageId,
+       tSynchronizedProcedure procedure,
+       ULONG parameter)
+{
+       tSynchronizedContext SyncContext;
+       SyncContext.pContext  = pContext;
+       SyncContext.Parameter = parameter;
+       return NdisMSynchronizeWithInterrupt(&pContext->Interrupt, procedure, 
&SyncContext);
+}
 
 #endif //defined(NDIS51_MINIPORT) || defined(NDIS50_MINIPORT)
diff --git a/NetKVM/wxp/ParaNdis5.h b/NetKVM/wxp/ParaNdis5.h
index 43d347a..f02563b 100644
--- a/NetKVM/wxp/ParaNdis5.h
+++ b/NetKVM/wxp/ParaNdis5.h
@@ -54,6 +54,8 @@ NDIS_STATUS ParaNdis5_StopReceive(
        BOOLEAN bStop,
        ONPAUSECOMPLETEPROC Callback
        );
+VOID ParaNdis5_HandleDPC(
+       IN NDIS_HANDLE MiniportAdapterContext);
 
 typedef struct _tagPowerWorkItem
 {
--
To unsubscribe from this list: send the line "unsubscribe kvm-commits" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to