Index: /trunk/src/VBox/Devices/Network/DevE1000.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/DevE1000.cpp	(revision 41028)
+++ /trunk/src/VBox/Devices/Network/DevE1000.cpp	(revision 41029)
@@ -88,5 +88,5 @@
  * to allocating their buffers (see #5582).
  */
-//#define E1K_WITH_TXD_CACHE 1
+#define E1K_WITH_TXD_CACHE 1
 /* End of Options ************************************************************/
 
@@ -98,5 +98,5 @@
  * TSE packet.
  */
-#define E1K_TXD_CACHE_SIZE 16u
+#define E1K_TXD_CACHE_SIZE 18u
 #endif /* E1K_WITH_TXD_CACHE */
 
@@ -132,4 +132,5 @@
 #  define E1kLog2(a)              LogRel(a)
 #  define E1kLog3(a)              LogRel(a)
+#  define E1kLogX(a)              LogRel(a)
 //#  define E1kLog3(a)              do {} while (0)
 # else
@@ -137,4 +138,5 @@
 #  define E1kLog2(a)              do {} while (0)
 #  define E1kLog3(a)              do {} while (0)
+#  define E1kLogX(a)              do {} while (0)
 # endif
 #else
@@ -142,4 +144,5 @@
 #  define E1kLog2(a)              Log2(a)
 #  define E1kLog3(a)              Log3(a)
+#  define E1kLogX(x, a)           LogIt(LOG_INSTANCE, x, LOG_GROUP, a)
 //#  define E1kLog(a)               do {} while (0)
 //#  define E1kLog2(a)              do {} while (0)
@@ -1066,13 +1069,13 @@
     E1KTXCTX    contextNormal;
 #ifdef E1K_WITH_TXD_CACHE
-    /** EMT/TX: Fetched TX descriptors. */
+    /** TX: Fetched TX descriptors. */
     E1KTXDESC   aTxDescriptors[E1K_TXD_CACHE_SIZE];
-    /** EMT/TX: Actual number of fetched TX descriptors. */
+    /** TX: Actual number of fetched TX descriptors. */
     uint8_t     nTxDFetched;
-    /** EMT/TX: Index in cache of TX descriptor being processed. */
+    /** TX: Index in cache of TX descriptor being processed. */
     uint8_t     iTxDCurrent;
-    /** EMT/TX: Will this frame be sent as GSO. */
+    /** TX: Will this frame be sent as GSO. */
     bool        fGSO;
-    /** EMT/TX: Number of bytes in next packet. */
+    /** TX: Number of bytes in next packet. */
     uint32_t    cbTxAlloc;
 
@@ -1647,15 +1650,16 @@
  * @thread  E1000_TX
  */
-static void e1kPrintTDesc(E1KSTATE* pState, E1KTXDESC* pDesc, const char* cszDir)
+static void e1kPrintTDesc(E1KSTATE* pState, E1KTXDESC* pDesc, const char* cszDir,
+                          unsigned uLevel = RTLOGGRPFLAGS_LEVEL_2)
 {
     switch (e1kGetDescType(pDesc))
     {
         case E1K_DTYP_CONTEXT:
-            E1kLog2(("%s %s Context Transmit Descriptor %s\n",
+            E1kLogX(uLevel, ("%s %s Context Transmit Descriptor %s\n",
                     INSTANCE(pState), cszDir, cszDir));
-            E1kLog2(("        IPCSS=%02X IPCSO=%02X IPCSE=%04X TUCSS=%02X TUCSO=%02X TUCSE=%04X\n",
+            E1kLogX(uLevel, ("        IPCSS=%02X IPCSO=%02X IPCSE=%04X TUCSS=%02X TUCSO=%02X TUCSE=%04X\n",
                     pDesc->context.ip.u8CSS, pDesc->context.ip.u8CSO, pDesc->context.ip.u16CSE,
                     pDesc->context.tu.u8CSS, pDesc->context.tu.u8CSO, pDesc->context.tu.u16CSE));
-            E1kLog2(("        TUCMD:%s%s%s %s %s PAYLEN=%04x HDRLEN=%04x MSS=%04x STA: %s\n",
+            E1kLogX(uLevel, ("        TUCMD:%s%s%s %s %s PAYLEN=%04x HDRLEN=%04x MSS=%04x STA: %s\n",
                     pDesc->context.dw2.fIDE ? " IDE":"",
                     pDesc->context.dw2.fRS  ? " RS" :"",
@@ -1669,10 +1673,10 @@
             break;
         case E1K_DTYP_DATA:
-            E1kLog2(("%s %s Data Transmit Descriptor (%d bytes) %s\n",
+            E1kLogX(uLevel, ("%s %s Data Transmit Descriptor (%d bytes) %s\n",
                     INSTANCE(pState), cszDir, pDesc->data.cmd.u20DTALEN, cszDir));
-            E1kLog2(("        Address=%16LX DTALEN=%05X\n",
+            E1kLogX(uLevel, ("        Address=%16LX DTALEN=%05X\n",
                     pDesc->data.u64BufAddr,
                     pDesc->data.cmd.u20DTALEN));
-            E1kLog2(("        DCMD:%s%s%s%s%s%s STA:%s%s%s POPTS:%s%s SPECIAL:%s VLAN=%03x PRI=%x\n",
+            E1kLogX(uLevel, ("        DCMD:%s%s%s%s%s%s STA:%s%s%s POPTS:%s%s SPECIAL:%s VLAN=%03x PRI=%x\n",
                     pDesc->data.cmd.fIDE ? " IDE" :"",
                     pDesc->data.cmd.fVLE ? " VLE" :"",
@@ -1691,10 +1695,10 @@
             break;
         case E1K_DTYP_LEGACY:
-            E1kLog2(("%s %s Legacy Transmit Descriptor (%d bytes) %s\n",
+            E1kLogX(uLevel, ("%s %s Legacy Transmit Descriptor (%d bytes) %s\n",
                     INSTANCE(pState), cszDir, pDesc->legacy.cmd.u16Length, cszDir));
-            E1kLog2(("        Address=%16LX DTALEN=%05X\n",
+            E1kLogX(uLevel, ("        Address=%16LX DTALEN=%05X\n",
                     pDesc->data.u64BufAddr,
                     pDesc->legacy.cmd.u16Length));
-            E1kLog2(("        CMD:%s%s%s%s%s%s STA:%s%s%s CSO=%02x CSS=%02x SPECIAL:%s VLAN=%03x PRI=%x\n",
+            E1kLogX(uLevel, ("        CMD:%s%s%s%s%s%s STA:%s%s%s CSO=%02x CSS=%02x SPECIAL:%s VLAN=%03x PRI=%x\n",
                     pDesc->legacy.cmd.fIDE ? " IDE" :"",
                     pDesc->legacy.cmd.fVLE ? " VLE" :"",
@@ -4513,34 +4517,39 @@
             return rc;
     }
-    /*
-     * Process all pending descriptors.
-     * Note! Do not process descriptors in locked state
-     */
-    while (TDH != TDT && !pState->fLocked)
-    {
-        E1KTXDESC desc;
-        E1kLog3(("%s About to process new TX descriptor at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
-                 INSTANCE(pState), TDBAH, TDBAL + TDH * sizeof(desc), TDLEN, TDH, TDT));
-
-        e1kLoadDesc(pState, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc));
-        rc = e1kXmitDesc(pState, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc), fOnWorkerThread);
-        /* If we failed to transmit descriptor we will try it again later */
-        if (RT_FAILURE(rc))
-            break;
-        if (++TDH * sizeof(desc) >= TDLEN)
-            TDH = 0;
-
-        if (e1kGetTxLen(pState) <= GET_BITS(TXDCTL, LWTHRESH)*8)
-        {
-            E1kLog2(("%s Low on transmit descriptors, raise ICR.TXD_LOW, len=%x thresh=%x\n",
-                     INSTANCE(pState), e1kGetTxLen(pState), GET_BITS(TXDCTL, LWTHRESH)*8));
-            e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_TXD_LOW);
-        }
-
-        STAM_PROFILE_ADV_STOP(&pState->CTX_SUFF_Z(StatTransmit), a);
-    }
-
-    /// @todo: uncomment: pState->uStatIntTXQE++;
-    /// @todo: uncomment: e1kRaiseInterrupt(pState, ICR_TXQE);
+    //rc = e1kCsTxEnter(pState, VERR_SEM_BUSY);
+    if (RT_LIKELY(rc == VINF_SUCCESS))
+    {
+        /*
+         * Process all pending descriptors.
+         * Note! Do not process descriptors in locked state
+         */
+        while (TDH != TDT && !pState->fLocked)
+        {
+            E1KTXDESC desc;
+            E1kLog3(("%s About to process new TX descriptor at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
+                     INSTANCE(pState), TDBAH, TDBAL + TDH * sizeof(desc), TDLEN, TDH, TDT));
+            
+            e1kLoadDesc(pState, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc));
+            rc = e1kXmitDesc(pState, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc), fOnWorkerThread);
+            /* If we failed to transmit descriptor we will try it again later */
+            if (RT_FAILURE(rc))
+                break;
+            if (++TDH * sizeof(desc) >= TDLEN)
+                TDH = 0;
+
+            if (e1kGetTxLen(pState) <= GET_BITS(TXDCTL, LWTHRESH)*8)
+            {
+                E1kLog2(("%s Low on transmit descriptors, raise ICR.TXD_LOW, len=%x thresh=%x\n",
+                         INSTANCE(pState), e1kGetTxLen(pState), GET_BITS(TXDCTL, LWTHRESH)*8));
+                e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_TXD_LOW);
+            }
+
+            STAM_PROFILE_ADV_STOP(&pState->CTX_SUFF_Z(StatTransmit), a);
+        }
+
+        /// @todo: uncomment: pState->uStatIntTXQE++;
+        /// @todo: uncomment: e1kRaiseInterrupt(pState, ICR_TXQE);
+        //e1kCsTxLeave(pState);
+    }
 
     /*
@@ -4552,4 +4561,10 @@
 }
 #else /* E1K_WITH_TXD_CACHE */
+static void e1kDumpTxDCache(E1KSTATE *pState)
+{
+    for (int i = 0; i < pState->nTxDFetched; ++i)
+        e1kPrintTDesc(pState, &pState->aTxDescriptors[i], "***", RTLOGGRPFLAGS_LEVEL_4);
+}
+
 /**
  * Transmit pending descriptors.
@@ -4596,4 +4611,19 @@
         }
         uint8_t u8Remain = pState->nTxDFetched - pState->iTxDCurrent;
+        if (RT_UNLIKELY(u8Remain == E1K_TXD_CACHE_SIZE))
+        {
+            /*
+             * The descriptor cache is full, but we were unable to find
+             * a complete packet in it. Drop the cache and hope that
+             * the guest driver can recover from network card error.
+             */
+            Log4(("%s No complete packets in full TxD cache! "
+                  "Fetched=%d, TX len=%d. Dump follows:\n",
+                  INSTANCE(pState), pState->nTxDFetched, e1kGetTxLen(pState)));
+            e1kDumpTxDCache(pState);
+            pState->nTxDFetched = 0;
+            rc = VERR_NET_IO_ERROR;
+            goto out;
+        }
         if (u8Remain > 0)
         {
@@ -4705,5 +4735,5 @@
     {
         E1kLogRel(("E1000: TDT write: %d descriptors to process\n", e1kGetTxLen(pState)));
-        E1kLog(("%s e1kRegWriteTDT: %d descriptors to process, waking up E1000_TX thread\n",
+        E1kLog(("%s e1kRegWriteTDT: %d descriptors to process\n",
                  INSTANCE(pState), e1kGetTxLen(pState)));
         e1kCsTxLeave(pState);
