Index: /trunk/src/VBox/Devices/Network/DevPCNet.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/DevPCNet.cpp	(revision 302)
+++ /trunk/src/VBox/Devices/Network/DevPCNet.cpp	(revision 303)
@@ -72,5 +72,5 @@
 
 /* Enable this to catch writes to the ring descriptors instead of using excessive polling */
-//#define PCNET_NO_POLLING
+/* #define PCNET_NO_POLLING */
 
 /* Enable to handle frequent io reads in the guest context */
@@ -120,9 +120,10 @@
 {
     PCIDEVICE                           PciDev;
+#ifndef PCNET_NO_POLLING
     /** Poll timer (address for host context) */
     PTMTIMERHC                          pTimerPollHC;
     /** Poll timer (address for guest context) */
     PTMTIMERGC                          pTimerPollGC;
-
+#endif
     /** Register Address Pointer */
     uint32_t                            u32RAP;
@@ -217,4 +218,15 @@
     PDMCRITSECT                         CritSect;
 
+#ifdef PCNET_NO_POLLING
+    RTGCPHYS                            TRDAPhysOld;
+    uint32_t                            cbTRDAOld;
+
+    RTGCPHYS                            RDRAPhysOld;
+    uint32_t                            cbRDRAOld;
+
+    DECLGCCALLBACKMEMBER(int, pfnEMInterpretInstructionGC, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
+    DECLR0CALLBACKMEMBER(int, pfnEMInterpretInstructionR0, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
+#endif
+
     bool                                fGCEnabled;
     bool                                fR0Enabled;
@@ -247,5 +259,14 @@
     STAMCOUNTER                         StatTXRingWrite;
     STAMCOUNTER                         StatRingWriteHC;
+    STAMCOUNTER                         StatRingWriteR0;
     STAMCOUNTER                         StatRingWriteGC;
+
+    STAMCOUNTER                         StatRingWriteFailedHC;
+    STAMCOUNTER                         StatRingWriteFailedR0;
+    STAMCOUNTER                         StatRingWriteFailedGC;
+
+    STAMCOUNTER                         StatRingWriteOutsideRangeHC;
+    STAMCOUNTER                         StatRingWriteOutsideRangeR0;
+    STAMCOUNTER                         StatRingWriteOutsideRangeGC;
 # endif
 #endif /* VBOX_WITH_STATISTICS */
@@ -921,6 +942,6 @@
                                   RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
 #ifndef IN_RING3
-DECLEXPORT(int) pcnetHandleRingWriteGC(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
-                                       RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
+DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
+                                     RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
 #endif
 __END_DECLS
@@ -933,4 +954,5 @@
 static void     pcnetPollRxTx(PCNetState *pData);
 static void     pcnetPollTimer(PCNetState *pData);
+static void     pcnetUpdateIrq(PCNetState *pData);
 static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP);
 static int      pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val);
@@ -951,12 +973,36 @@
  * @param   pvUser      User argument.
  */
-DECLEXPORT(int) pcnetHandleRingWriteGC(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
-                                       RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
-{
-    PPDMDEVINS  pDevIns = (PPDMDEVINS)pvUser;
-    PCNetState *pData   = PDMINS2DATA(pDevIns, PCNetState *);
+DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
+                                     RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
+{
+    PCNetState *pData   = (PCNetState *)pvUser;
 
     Log(("#%d pcnetHandleRingWriteGC: write to %08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, GCPhysFault));
-    STAM_COUNTER_INC(&CTXSUFF(pData->StatRingWrite)); NOREF(pData);
+
+    uint32_t cb;
+    int rc = CTXALLSUFF(pData->pfnEMInterpretInstruction)(pVM, pRegFrame, pvFault, &cb);
+    if (VBOX_SUCCESS(rc) && cb)
+    {
+        if (GCPhysFault >= pData->GCTDRA && GCPhysFault + cb < pcnetTdraAddr(pData, 0))
+        {
+            int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
+            if (VBOX_SUCCESS(rc))
+            {
+                STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWrite)); ;
+
+                /* Check if we can do something now */
+                pcnetPollRxTx(pData);
+
+                PDMCritSectLeave(&pData->CritSect);
+                return VINF_SUCCESS;
+            }
+        }
+        else
+        {
+            STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteOutsideRange)); ;
+            return VINF_SUCCESS;    /* outside of the ring range */
+        }
+    }
+    STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteFailed)); ;
     return VINF_IOM_HC_MMIO_WRITE; /* handle in ring3 */
 }
@@ -1003,5 +1049,6 @@
         AssertReleaseRC(rc);
         /* Check if we can do something now */
-        pcnetPollTimer(pData);
+        pcnetPollRxTx(pData);
+        pcnetUpdateIrq(pData);
         PDMCritSectLeave(&pData->CritSect);
     }
@@ -1143,14 +1190,16 @@
 #ifdef IN_RING3
 #ifdef PCNET_NO_POLLING
-static void pcnetUpdateRingHandlers(PCNetState *pData,
-                                    RTGCPHYS oldrdra, uint16_t oldrcvrl,
-                                    RTGCPHYS oldtdra, uint16_t oldxmtrl)
+static void pcnetUpdateRingHandlers(PCNetState *pData)
 {
     PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
+
+    Log(("pcnetUpdateRingHandlers TD %VGp size %x -> %VGp size %x\n", pData->TRDAPhysOld, pData->cbTRDAOld, pData->GCTDRA, pcnetTdraAddr(pData, 0)));
+    Log(("pcnetUpdateRingHandlers RX %VGp size %x -> %VGp size %x\n", pData->RDRAPhysOld, pData->cbRDRAOld, pData->GCRDRA, pcnetRdraAddr(pData, 0)));
+
 #if 0
-    if (oldrdra != 0 && pData->GCRDRA != oldrdra)
+    if (pData->RDRAPhysOld != 0 && pData->GCRDRA != pData->RDRAPhysOld)
         PGMHandlerPhysicalDeregister(pDevIns->pDevHlp->pfnGetVM(pDevIns),
-                                     oldrdra & ~PAGE_OFFSET_MASK);
-    if (   oldtdra != 0 && pData->GCTDRA != oldtdra
+                                     pData->RDRAPhysOld & ~PAGE_OFFSET_MASK);
+    if (   pData->TRDAPhysOld != 0 && pData->GCTDRA != pData->TRDAPhysOld
         && (pData->GCRDRA & ~PAGE_OFFSET_MASK) != (pData->GCTDRA & ~PAGE_OFFSET_MASK))
 #endif
@@ -1164,18 +1213,23 @@
                                           RT_ALIGN(pcnetRdraAddr(pData, 0), PAGE_SIZE) - 1,
                                           pcnetHandleRingWrite, pDevIns,
-                                          g_DevicePCNet.szR0Mod, "pcnetHandleRingWriteGC",
+                                          g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
                                           pData->pDevInsHC->pvInstanceDataHC,
-                                          g_DevicePCNet.szGCMod, "pcnetHandleRingWriteGC",
+                                          g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
                                           pData->pDevInsHC->pvInstanceDataGC,
                                           "PCNet receive ring write access handler");
         AssertRC(rc);
-    }
-#endif
-    if (pData->GCTDRA != oldtdra || CSR_XMTRL(pData) != oldxmtrl)
-    {
-        if (oldtdra != 0)
+
+        pData->RDRAPhysOld = pData->GCRDRA;
+        pData->cbRDRAOld   = pcnetRdraAddr(pData, 0);
+    }
+#endif
+    if (pData->GCTDRA != pData->TRDAPhysOld || CSR_XMTRL(pData) != pData->cbTRDAOld)
+    {
+        if (pData->TRDAPhysOld != 0)
             PGMHandlerPhysicalDeregister(pDevIns->pDevHlp->pfnGetVM(pDevIns),
-                                         oldtdra & ~PAGE_OFFSET_MASK);
+                                         pData->TRDAPhysOld & ~PAGE_OFFSET_MASK);
+
         int rc;
+
         rc = PGMR3HandlerPhysicalRegister(pDevIns->pDevHlp->pfnGetVM(pDevIns),
                                           PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
@@ -1183,10 +1237,13 @@
                                           RT_ALIGN(pcnetTdraAddr(pData, 0), PAGE_SIZE) - 1,
                                           pcnetHandleRingWrite, pDevIns,
-                                          g_DevicePCNet.szR0Mod, "pcnetHandleRingWriteGC",
+                                          g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
                                           pData->pDevInsHC->pvInstanceDataHC,
-                                          g_DevicePCNet.szGCMod, "pcnetHandleRingWriteGC",
+                                          g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
                                           pData->pDevInsHC->pvInstanceDataGC,
                                           "PCNet transmit ring write access handler");
         AssertRC(rc);
+
+        pData->TRDAPhysOld = pData->GCTDRA;
+        pData->cbTRDAOld   = pcnetTdraAddr(pData, 0);
     }
 }
@@ -1196,8 +1253,4 @@
 {
     PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
-#ifdef PCNET_NO_POLLING
-    RTGCPHYS oldrdra  = pData->GCRDRA,    oldtdra  = pData->GCTDRA;
-    uint16_t oldrcvrl = CSR_RCVRL(pData), oldxmtrl = CSR_XMTRL(pData);
-#endif
     Log(("#%d pcnetInit: init_addr=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
          PHYSADDR(pData, CSR_IADR(pData))));
@@ -1249,5 +1302,5 @@
 
 #ifdef PCNET_NO_POLLING
-    pcnetUpdateRingHandlers(pData, oldrdra, oldrcvrl, oldtdra, oldxmtrl);
+    pcnetUpdateRingHandlers(pData);
 #endif
 
@@ -2085,4 +2138,7 @@
          * but so far I have not seen any guest depending on these values. The 2ms
          * interval is the default polling interval of the PCNet card (65536/33MHz). */
+#ifdef PCNET_NO_POLLING
+        pcnetPollRxTx(pData);
+#else
         uint64_t u64Now = TMTimerGet(pData->CTXSUFF(pTimerPoll));
         if (RT_UNLIKELY(u64Now - pData->u64LastPoll > 200000))
@@ -2095,4 +2151,5 @@
             TMTimerSet(pData->CTXSUFF(pTimerPoll),
                        TMTimerGet(pData->CTXSUFF(pTimerPoll)) + 2000000);
+#endif
     }
     STAM_PROFILE_ADV_STOP(&pData->StatPollTimer, a);
@@ -3432,5 +3489,9 @@
     SSMR3PutMem(pSSMHandle, &pData->MacConfigured, sizeof(pData->MacConfigured));
     SSMR3PutBool(pSSMHandle, pData->fAm79C973);
+#ifdef PCNET_NO_POLLING
+    return VINF_SUCCESS;
+#else
     return TMR3TimerSave(pData->CTXSUFF(pTimerPoll), pSSMHandle);
+#endif
 }
 
@@ -3466,5 +3527,7 @@
     Assert(!memcmp(&Mac, &pData->MacConfigured, sizeof(Mac)));
     SSMR3GetBool(pSSMHandle, &pData->fAm79C973);
+#ifndef PCNET_NO_POLLING
     TMR3TimerLoad(pData->CTXSUFF(pTimerPoll), pSSMHandle);
+#endif
 
     pData->iLog2DescSize = BCR_SWSTYLE(pData)
@@ -3708,7 +3771,11 @@
     PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
     pData->pDevInsGC     = PDMDEVINS_2_GCPTR(pDevIns);
-    pData->pTimerPollGC  = TMTimerGCPtr(pData->pTimerPollHC);
     pData->pXmitQueueGC  = PDMQueueGCPtr(pData->pXmitQueueHC);
     pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
+#ifdef PCNET_NO_POLLING
+    *(RTHCUINTPTR *)&pData->pfnEMInterpretInstructionGC += offDelta;
+#else
+    pData->pTimerPollGC  = TMTimerGCPtr(pData->pTimerPollHC);
+#endif
 }
 
@@ -3873,4 +3940,20 @@
         return rc;
 
+#ifdef PCNET_NO_POLLING
+    rc = PDMR3GetSymbolR0Lazy(pDevIns->pDevHlp->pfnGetVM(pDevIns), NULL, "EMInterpretInstruction", (void **)&pData->pfnEMInterpretInstructionR0);
+    if (VBOX_SUCCESS(rc))
+    {
+        /*
+         * Resolve the GC handler.
+         */
+        RTGCPTR pfnHandlerGC;
+        rc = PDMR3GetSymbolGCLazy(pDevIns->pDevHlp->pfnGetVM(pDevIns), NULL, "EMInterpretInstruction", (RTGCPTR *)&pData->pfnEMInterpretInstructionGC);
+    }
+    if (VBOX_FAILURE(rc))
+    {
+        AssertMsgFailed(("PDMR3GetSymbolGCLazy -> %Vrc\n", rc));
+        return rc;
+    }
+#else
     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimer,
                                 "PCNet Poll Timer", &pData->pTimerPollHC);
@@ -3880,4 +3963,5 @@
         return rc;
     }
+#endif
     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerRestore,
                                 "PCNet Restore Timer", &pData->pTimerRestore);
@@ -3996,6 +4080,13 @@
     PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRCVRingWrite,       STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of receive ring writes",          "/Devices/PCNet%d/Ring/RCVWrites", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTXRingWrite,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of transmit ring writes",         "/Devices/PCNet%d/Ring/TXWrites", iInstance);
-    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteHC,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored ring page writes",   "/Devices/PCNet%d/Ring/HCWrites", iInstance);
-    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteGC,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored ring page writes",   "/Devices/PCNet%d/Ring/GCWrites", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteHC,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored ring page writes",   "/Devices/PCNet%d/Ring/HC/Writes", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteR0,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored ring page writes",   "/Devices/PCNet%d/Ring/R0/Writes", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteGC,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored ring page writes",   "/Devices/PCNet%d/Ring/GC/Writes", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedHC,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of failed ring page writes",   "/Devices/PCNet%d/Ring/HC/Failed", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedR0,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of failed ring page writes",   "/Devices/PCNet%d/Ring/R0/Failed", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedGC,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of failed ring page writes",   "/Devices/PCNet%d/Ring/GC/Failed", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeHC,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored writes outside ring range",   "/Devices/PCNet%d/Ring/HC/Outside", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeR0,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored writes outside ring range",   "/Devices/PCNet%d/Ring/R0/Outside", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeGC,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Nr of monitored writes outside ring range",   "/Devices/PCNet%d/Ring/GC/Outside", iInstance);
 # endif /* PCNET_NO_POLLING */
 #endif
