third_party/virtualbox/src/VBox/Devices/Network/DevE1000.cpp
/**
 * Transmit pending descriptors.
 *
 * @returns VBox status code.  VERR_TRY_AGAIN is returned if we're busy.
 *
 * @param   pThis              The E1000 state.
 * @param   fOnWorkerThread     Whether we're on a worker thread or on an EMT.
 */
Transmit pending descriptors.
@returns VBox status code.  VERR_TRY_AGAIN is returned if we're busy.

@param   pThis              The E1000 state.
@param   fOnWorkerThread     Whether we're on a worker thread or on an EMT.
Transmit pending descriptors . @returns VBox status code . VERR_TRY_AGAIN is returned if we ' re busy . @param pThis The E1000 state . @param fOnWorkerThread Whether we ' re on a worker thread or on an EMT .
static int e1kXmitPending(PE1KSTATE pThis, bool fOnWorkerThread)
{
    int rc = VINF_SUCCESS;
    if (!(TCTL & TCTL_EN))
        return VINF_SUCCESS;
    PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
    if (pDrv)
    {
        rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread);
        if (RT_FAILURE(rc))
            return rc;
    }
    rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
    if (RT_LIKELY(rc == VINF_SUCCESS))
    {
        STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
        bool fIncomplete = false;
        while (!pThis->fLocked && e1kTxDLazyLoad(pThis))
        {
            while (e1kLocateTxPacket(pThis))
            {
                fIncomplete = false;
                rc = e1kXmitAllocBuf(pThis, pThis->fGSO);
                if (RT_FAILURE(rc))
                    goto out;
                rc = e1kXmitPacket(pThis, fOnWorkerThread);
                if (RT_FAILURE(rc))
                    goto out;
            }
            uint8_t u8Remain = pThis->nTxDFetched - pThis->iTxDCurrent;
            if (RT_UNLIKELY(fIncomplete))
            {
                static bool fTxDCacheDumped = false;
                LogRel(("%s No complete packets in%s TxD cache! "
                      "Fetched=%d, current=%d, TX len=%d.\n",
                      pThis->szPrf,
                      u8Remain == E1K_TXD_CACHE_SIZE ? " full" : "",
                      pThis->nTxDFetched, pThis->iTxDCurrent,
                      e1kGetTxLen(pThis)));
                if (!fTxDCacheDumped)
                {
                    fTxDCacheDumped = true;
                    e1kDumpTxDCache(pThis);
                }
                pThis->iTxDCurrent = pThis->nTxDFetched = 0;
# ifdef IN_RING3
                rc = VERR_NET_INCOMPLETE_TX_PACKET;
# else 
                rc = VINF_IOM_R3_MMIO_WRITE;
# endif 
                goto out;
            }
            if (u8Remain > 0)
            {
                Log4(("%s Incomplete packet at %d. Already fetched %d, "
                      "%d more are available\n",
                      pThis->szPrf, pThis->iTxDCurrent, u8Remain,
                      e1kGetTxLen(pThis) - u8Remain));
                memmove(pThis->aTxDescriptors,
                        &pThis->aTxDescriptors[pThis->iTxDCurrent],
                        u8Remain * sizeof(E1KTXDESC));
                pThis->iTxDCurrent = 0;
                pThis->nTxDFetched = u8Remain;
                e1kTxDLoadMore(pThis);
                fIncomplete = true;
            }
            else
                pThis->nTxDFetched = 0;
            pThis->iTxDCurrent = 0;
        }
        if (!pThis->fLocked && GET_BITS(TXDCTL, LWTHRESH) == 0)
        {
            E1kLog2(("%s Out of transmit descriptors, raise ICR.TXD_LOW\n",
                     pThis->szPrf));
            e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXD_LOW);
        }
out:
        STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
        e1kCsTxLeave(pThis);
    }
    if (pDrv)
        pDrv->pfnEndXmit(pDrv);
    return rc;
}
static int e1kXmitPending ( PE1KSTATE pThis , bool fOnWorkerThread ) { int rc = VINF_SUCCESS ; if ( ! ( TCTL & TCTL_EN ) ) return VINF_SUCCESS ; PPDMINETWORKUP pDrv = pThis -> CTX_SUFF ( pDrv ) ; if ( pDrv ) { rc = pDrv -> pfnBeginXmit ( pDrv , fOnWorkerThread ) ; if ( RT_FAILURE ( rc ) ) return rc ; } rc = e1kCsTxEnter ( pThis , VERR_SEM_BUSY ) ; if ( RT_LIKELY ( rc == VINF_SUCCESS ) ) { STAM_PROFILE_ADV_START ( & pThis -> CTX_SUFF_Z ( StatTransmit ) , a ) ; bool fIncomplete = false ; while ( ! pThis -> fLocked && e1kTxDLazyLoad ( pThis ) ) { while ( e1kLocateTxPacket ( pThis ) ) { fIncomplete = false ; rc = e1kXmitAllocBuf ( pThis , pThis -> fGSO ) ; if ( RT_FAILURE ( rc ) ) goto out ; rc = e1kXmitPacket ( pThis , fOnWorkerThread ) ; if ( RT_FAILURE ( rc ) ) goto out ; } uint8_t u8Remain = pThis -> nTxDFetched - pThis -> iTxDCurrent ; if ( RT_UNLIKELY ( fIncomplete ) ) { static bool fTxDCacheDumped = false ; LogRel ( ( " " " \n " , pThis -> szPrf , u8Remain == E1K_TXD_CACHE_SIZE ? " " : " " , pThis -> nTxDFetched , pThis -> iTxDCurrent , e1kGetTxLen ( pThis ) ) ) ; if ( ! fTxDCacheDumped ) { fTxDCacheDumped = true ; e1kDumpTxDCache ( pThis ) ; } pThis -> iTxDCurrent = pThis -> nTxDFetched = 0 ; # ifdef IN_RING3 rc = VERR_NET_INCOMPLETE_TX_PACKET ; # else rc = VINF_IOM_R3_MMIO_WRITE ; # endif goto out ; } if ( u8Remain > 0 ) { Log4 ( ( " " " \n " , pThis -> szPrf , pThis -> iTxDCurrent , u8Remain , e1kGetTxLen ( pThis ) - u8Remain ) ) ; memmove ( pThis -> aTxDescriptors , & pThis -> aTxDescriptors [ pThis -> iTxDCurrent ] , u8Remain * sizeof ( E1KTXDESC ) ) ; pThis -> iTxDCurrent = 0 ; pThis -> nTxDFetched = u8Remain ; e1kTxDLoadMore ( pThis ) ; fIncomplete = true ; } else pThis -> nTxDFetched = 0 ; pThis -> iTxDCurrent = 0 ; } if ( ! pThis -> fLocked && GET_BITS ( TXDCTL , LWTHRESH ) == 0 ) { E1kLog2 ( ( " \n " , pThis -> szPrf ) ) ; e1kRaiseInterrupt ( pThis , VERR_SEM_BUSY , ICR_TXD_LOW ) ; } out : STAM_PROFILE_ADV_STOP ( & pThis -> CTX_SUFF_Z ( StatTransmit ) , a ) ; e1kCsTxLeave ( pThis ) ; } if ( pDrv ) pDrv -> pfnEndXmit ( pDrv ) ; return rc ; }
Transmit pending descriptors.
Transmit pending descriptors .
/* Check if transmitter is enabled. */ /*
     * Grab the xmit lock of the driver as well as the E1K device state.
     */ /*
     * Process all pending descriptors.
     * Note! Do not process descriptors in locked state
     */ /*
         * fIncomplete is set whenever we try to fetch additional descriptors
         * for an incomplete packet. If fail to locate a complete packet on
         * the next iteration we need to reset the cache or we risk to get
         * stuck in this loop forever.
         */ /* Found a complete packet, allocate it. */ /* If we're out of bandwidth we'll come back later. */ /* Copy the packet to allocated buffer and send it. */ /* If we're out of bandwidth we'll come back later. */ /*
                 * 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.
                 */ /*
                 * Returning an error at this point means Guru in R0
                 * (see @bugref{6428}).
                 */ /* !IN_RING3 */ /* !IN_RING3 */ /*
                 * A packet was partially fetched. Move incomplete packet to
                 * the beginning of cache buffer, then load more descriptors.
                 */ /// @todo uncomment: pThis->uStatIntTXQE++; /// @todo uncomment: e1kRaiseInterrupt(pThis, ICR_TXQE); /*
     * Release the lock.
     */