third_party/virtualbox/src/VBox/Devices/Network/DevE1000.cpp
/**
 * Process Transmit Descriptor.
 *
 * E1000 supports three types of transmit descriptors:
 * - legacy   data descriptors of older format (context-less).
 * - data     the same as legacy but providing new offloading capabilities.
 * - context  sets up the context for following data descriptors.
 *
 * @param   pThis          The device state structure.
 * @param   pDesc           Pointer to descriptor union.
 * @param   addr            Physical address of descriptor in guest memory.
 * @param   fOnWorkerThread Whether we're on a worker thread or an EMT.
 * @param   cbPacketSize    Size of the packet as previously computed.
 * @thread  E1000_TX
 */
Process Transmit Descriptor.
E1000 supports three types of transmit descriptors:
- legacy   data descriptors of older format (context-less).
- data     the same as legacy but providing new offloading capabilities.
- context  sets up the context for following data descriptors.

@param   pThis          The device state structure.
@param   pDesc           Pointer to descriptor union.
@param   addr            Physical address of descriptor in guest memory.
@param   fOnWorkerThread Whether we're on a worker thread or an EMT.
@param   cbPacketSize    Size of the packet as previously computed.
Process Transmit Descriptor . E1000 supports three types of transmit descriptors : - legacy data descriptors of older format ( context - less ) . - data the same as legacy but providing new offloading capabilities . - context sets up the context for following data descriptors . @param pThis The device state structure . @param pDesc Pointer to descriptor union . @param addr Physical address of descriptor in guest memory . @param fOnWorkerThread Whether we ' re on a worker thread or an EMT . @param cbPacketSize Size of the packet as previously computed .
static int e1kXmitDesc(PE1KSTATE pThis, E1KTXDESC *pDesc, RTGCPHYS addr,
                       bool fOnWorkerThread)
{
    int rc = VINF_SUCCESS;
    e1kPrintTDesc(pThis, pDesc, "vvv");
    if (pDesc->legacy.dw3.fDD)
    {
        E1kLog(("%s e1kXmitDesc: skipping bad descriptor ^^^\n", pThis->szPrf));
        e1kDescReport(pThis, pDesc, addr);
        return VINF_SUCCESS;
    }
    if (pThis->fTidEnabled)
        TMTimerStop(pThis->CTX_SUFF(pTIDTimer));
    switch (e1kGetDescType(pDesc))
    {
        case E1K_DTYP_CONTEXT:
            E1K_INC_ISTAT_CNT(pThis->uStatDescCtx);
            e1kDescReport(pThis, pDesc, addr);
            break;
        case E1K_DTYP_DATA:
        {
            STAM_COUNTER_INC(pDesc->data.cmd.fTSE?
                             &pThis->StatTxDescTSEData:
                             &pThis->StatTxDescData);
            E1K_INC_ISTAT_CNT(pThis->uStatDescDat);
            STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
            if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
            {
                E1kLog2(("% Empty data descriptor, skipped.\n", pThis->szPrf));
                if (pDesc->data.cmd.fEOP)
                {
                    e1kTransmitFrame(pThis, fOnWorkerThread);
                    pThis->u16TxPktLen = 0;
                }
            }
            else
            {
                if (e1kXmitIsGsoBuf(pThis->CTX_SUFF(pTxSg)))
                {
                    STAM_COUNTER_INC(&pThis->StatTxPathGSO);
                    bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
                    if (pDesc->data.cmd.fEOP)
                    {
                        if (   fRc
                            && pThis->CTX_SUFF(pTxSg)
                            && pThis->CTX_SUFF(pTxSg)->cbUsed == (size_t)pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN)
                        {
                            e1kTransmitFrame(pThis, fOnWorkerThread);
                            E1K_INC_CNT32(TSCTC);
                        }
                        else
                        {
                            if (fRc)
                                E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , pThis->szPrf,
                                        pThis->CTX_SUFF(pTxSg), pThis->CTX_SUFF(pTxSg) ? pThis->CTX_SUFF(pTxSg)->cbUsed : 0,
                                        pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN));
                            e1kXmitFreeBuf(pThis);
                            E1K_INC_CNT32(TSCTFC);
                        }
                        pThis->u16TxPktLen = 0;
                    }
                }
                else if (!pDesc->data.cmd.fTSE)
                {
                    STAM_COUNTER_INC(&pThis->StatTxPathRegular);
                    bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
                    if (pDesc->data.cmd.fEOP)
                    {
                        if (fRc && pThis->CTX_SUFF(pTxSg))
                        {
                            Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
                            if (pThis->fIPcsum)
                                e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
                                                  pThis->contextNormal.ip.u8CSO,
                                                  pThis->contextNormal.ip.u8CSS,
                                                  pThis->contextNormal.ip.u16CSE);
                            if (pThis->fTCPcsum)
                                e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
                                                  pThis->contextNormal.tu.u8CSO,
                                                  pThis->contextNormal.tu.u8CSS,
                                                  pThis->contextNormal.tu.u16CSE);
                            e1kTransmitFrame(pThis, fOnWorkerThread);
                        }
                        else
                            e1kXmitFreeBuf(pThis);
                        pThis->u16TxPktLen = 0;
                    }
                }
                else
                {
                    STAM_COUNTER_INC(&pThis->StatTxPathFallback);
                    rc = e1kFallbackAddToFrame(pThis, pDesc, fOnWorkerThread);
                }
            }
            e1kDescReport(pThis, pDesc, addr);
            STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
            break;
        }
        case E1K_DTYP_LEGACY:
            STAM_COUNTER_INC(&pThis->StatTxDescLegacy);
            STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
            if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
            {
                E1kLog(("%s Empty legacy descriptor, skipped.\n", pThis->szPrf));
            }
            else
            {
                if (e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
                {
                    E1K_INC_ISTAT_CNT(pThis->uStatDescLeg);
                    if (pDesc->legacy.cmd.fEOP)
                    {
                        if (pDesc->legacy.cmd.fIC)
                        {
                            e1kInsertChecksum(pThis,
                                              (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg,
                                              pThis->u16TxPktLen,
                                              pDesc->legacy.cmd.u8CSO,
                                              pDesc->legacy.dw3.u8CSS,
                                              0);
                        }
                        e1kTransmitFrame(pThis, fOnWorkerThread);
                        pThis->u16TxPktLen = 0;
                    }
                }
                else if (pDesc->legacy.cmd.fEOP)
                {
                    e1kXmitFreeBuf(pThis);
                    pThis->u16TxPktLen = 0;
                }
            }
            e1kDescReport(pThis, pDesc, addr);
            STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
            break;
        default:
            E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n",
                    pThis->szPrf, e1kGetDescType(pDesc)));
            break;
    }
    return rc;
}
static int e1kXmitDesc ( PE1KSTATE pThis , E1KTXDESC * pDesc , RTGCPHYS addr , bool fOnWorkerThread ) { int rc = VINF_SUCCESS ; e1kPrintTDesc ( pThis , pDesc , " " ) ; if ( pDesc -> legacy . dw3 . fDD ) { E1kLog ( ( " \n " , pThis -> szPrf ) ) ; e1kDescReport ( pThis , pDesc , addr ) ; return VINF_SUCCESS ; } if ( pThis -> fTidEnabled ) TMTimerStop ( pThis -> CTX_SUFF ( pTIDTimer ) ) ; switch ( e1kGetDescType ( pDesc ) ) { case E1K_DTYP_CONTEXT : E1K_INC_ISTAT_CNT ( pThis -> uStatDescCtx ) ; e1kDescReport ( pThis , pDesc , addr ) ; break ; case E1K_DTYP_DATA : { STAM_COUNTER_INC ( pDesc -> data . cmd . fTSE ? & pThis -> StatTxDescTSEData : & pThis -> StatTxDescData ) ; E1K_INC_ISTAT_CNT ( pThis -> uStatDescDat ) ; STAM_PROFILE_ADV_START ( & pThis -> CTX_SUFF_Z ( StatTransmit ) , a ) ; if ( pDesc -> data . cmd . u20DTALEN == 0 || pDesc -> data . u64BufAddr == 0 ) { E1kLog2 ( ( " \n " , pThis -> szPrf ) ) ; if ( pDesc -> data . cmd . fEOP ) { e1kTransmitFrame ( pThis , fOnWorkerThread ) ; pThis -> u16TxPktLen = 0 ; } } else { if ( e1kXmitIsGsoBuf ( pThis -> CTX_SUFF ( pTxSg ) ) ) { STAM_COUNTER_INC ( & pThis -> StatTxPathGSO ) ; bool fRc = e1kAddToFrame ( pThis , pDesc -> data . u64BufAddr , pDesc -> data . cmd . u20DTALEN ) ; if ( pDesc -> data . cmd . fEOP ) { if ( fRc && pThis -> CTX_SUFF ( pTxSg ) && pThis -> CTX_SUFF ( pTxSg ) -> cbUsed == ( size_t ) pThis -> contextTSE . dw3 . u8HDRLEN + pThis -> contextTSE . dw2 . u20PAYLEN ) { e1kTransmitFrame ( pThis , fOnWorkerThread ) ; E1K_INC_CNT32 ( TSCTC ) ; } else { if ( fRc ) E1kLog ( ( " \n " , pThis -> szPrf , pThis -> CTX_SUFF ( pTxSg ) , pThis -> CTX_SUFF ( pTxSg ) ? pThis -> CTX_SUFF ( pTxSg ) -> cbUsed : 0 , pThis -> contextTSE . dw3 . u8HDRLEN + pThis -> contextTSE . dw2 . u20PAYLEN ) ) ; e1kXmitFreeBuf ( pThis ) ; E1K_INC_CNT32 ( TSCTFC ) ; } pThis -> u16TxPktLen = 0 ; } } else if ( ! pDesc -> data . cmd . fTSE ) { STAM_COUNTER_INC ( & pThis -> StatTxPathRegular ) ; bool fRc = e1kAddToFrame ( pThis , pDesc -> data . u64BufAddr , pDesc -> data . cmd . u20DTALEN ) ; if ( pDesc -> data . cmd . fEOP ) { if ( fRc && pThis -> CTX_SUFF ( pTxSg ) ) { Assert ( pThis -> CTX_SUFF ( pTxSg ) -> cSegs == 1 ) ; if ( pThis -> fIPcsum ) e1kInsertChecksum ( pThis , ( uint8_t * ) pThis -> CTX_SUFF ( pTxSg ) -> aSegs [ 0 ] . pvSeg , pThis -> u16TxPktLen , pThis -> contextNormal . ip . u8CSO , pThis -> contextNormal . ip . u8CSS , pThis -> contextNormal . ip . u16CSE ) ; if ( pThis -> fTCPcsum ) e1kInsertChecksum ( pThis , ( uint8_t * ) pThis -> CTX_SUFF ( pTxSg ) -> aSegs [ 0 ] . pvSeg , pThis -> u16TxPktLen , pThis -> contextNormal . tu . u8CSO , pThis -> contextNormal . tu . u8CSS , pThis -> contextNormal . tu . u16CSE ) ; e1kTransmitFrame ( pThis , fOnWorkerThread ) ; } else e1kXmitFreeBuf ( pThis ) ; pThis -> u16TxPktLen = 0 ; } } else { STAM_COUNTER_INC ( & pThis -> StatTxPathFallback ) ; rc = e1kFallbackAddToFrame ( pThis , pDesc , fOnWorkerThread ) ; } } e1kDescReport ( pThis , pDesc , addr ) ; STAM_PROFILE_ADV_STOP ( & pThis -> CTX_SUFF_Z ( StatTransmit ) , a ) ; break ; } case E1K_DTYP_LEGACY : STAM_COUNTER_INC ( & pThis -> StatTxDescLegacy ) ; STAM_PROFILE_ADV_START ( & pThis -> CTX_SUFF_Z ( StatTransmit ) , a ) ; if ( pDesc -> legacy . cmd . u16Length == 0 || pDesc -> legacy . u64BufAddr == 0 ) { E1kLog ( ( " \n " , pThis -> szPrf ) ) ; } else { if ( e1kAddToFrame ( pThis , pDesc -> data . u64BufAddr , pDesc -> legacy . cmd . u16Length ) ) { E1K_INC_ISTAT_CNT ( pThis -> uStatDescLeg ) ; if ( pDesc -> legacy . cmd . fEOP ) { if ( pDesc -> legacy . cmd . fIC ) { e1kInsertChecksum ( pThis , ( uint8_t * ) pThis -> CTX_SUFF ( pTxSg ) -> aSegs [ 0 ] . pvSeg , pThis -> u16TxPktLen , pDesc -> legacy . cmd . u8CSO , pDesc -> legacy . dw3 . u8CSS , 0 ) ; } e1kTransmitFrame ( pThis , fOnWorkerThread ) ; pThis -> u16TxPktLen = 0 ; } } else if ( pDesc -> legacy . cmd . fEOP ) { e1kXmitFreeBuf ( pThis ) ; pThis -> u16TxPktLen = 0 ; } } e1kDescReport ( pThis , pDesc , addr ) ; STAM_PROFILE_ADV_STOP ( & pThis -> CTX_SUFF_Z ( StatTransmit ) , a ) ; break ; default : E1kLog ( ( " \n " , pThis -> szPrf , e1kGetDescType ( pDesc ) ) ) ; break ; } return rc ; }
Process Transmit Descriptor.
Process Transmit Descriptor .
//#ifdef E1K_USE_TX_TIMERS //#endif /* E1K_USE_TX_TIMERS */ /* The caller have already updated the context */ /*
                 * Add the descriptor data to the frame.  If the frame is complete,
                 * transmit it and reset the u16TxPktLen field.
                 */ /* Add fragment to frame. */ /* Last fragment: Transmit and reset the packet storage counter.  */ /* Last fragment + failure: free the buffer and reset the storage counter. */