VirtualBox

Changeset 28057 in vbox


Ignore:
Timestamp:
Apr 7, 2010 5:23:58 PM (15 years ago)
Author:
vboxsync
Message:

DevE1000: Generate GSO frames.

Location:
trunk/src/VBox/Devices
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevE1000.cpp

    r28037 r28057  
    975975    bool        fGCEnabled;
    976976
    977     /* All: Device register storage. */
     977    /** All: Device register storage. */
    978978    uint32_t    auRegs[E1K_NUM_OF_32BIT_REGS];
    979979    /** TX/RX: Status LED. */
     
    10111011     *  applicable to the current TSE mode. */
    10121012    PDMNETWORKGSO GsoCtx;
    1013 #if 1 /** @todo bird/buffering: change this to a 240 bytes buffer of the headers when TSE=1. */
    1014     /** TX: Transmit packet buffer. */
    1015     uint8_t     aTxPacket[E1K_MAX_TX_PKT_SIZE];
    1016 #endif
     1013    /** The scatter / gather buffer used for the current outgoing packet. */
     1014    R3PTRTYPE(PPDMSCATTERGATHER) pTxSgR3;
     1015    /** Scratch space for holding the loopback / fallback scatter / gather
     1016     *  descriptor. */
     1017    union
     1018    {
     1019        PDMSCATTERGATHER    Sg;
     1020        uint8_t             padding[8 * sizeof(RTUINTPTR)];
     1021    }           uTxFallback;
     1022    /** TX: Transmit packet buffer use for TSE fallback and loopback. */
     1023    uint8_t     aTxPacketFallback[E1K_MAX_TX_PKT_SIZE];
    10171024    /** TX: Number of bytes assembled in TX packet buffer. */
    10181025    uint16_t    u16TxPktLen;
     
    10211028    /** TX: TCP/UDP checksum has to be inserted if true. */
    10221029    bool        fTCPcsum;
    1023     /** TX: Number of payload bytes remaining in TSE context. */
     1030    /** TX TSE fallback: Number of payload bytes remaining in TSE context. */
    10241031    uint32_t    u32PayRemain;
    1025     /** TX: Number of header bytes remaining in TSE context. */
     1032    /** TX TSE fallback: Number of header bytes remaining in TSE context. */
    10261033    uint16_t    u16HdrRemain;
    1027     /** TX: Flags from template header. */
     1034    /** TX TSE fallback: Flags from template header. */
    10281035    uint16_t    u16SavedFlags;
    1029     /** TX: Partial checksum from template header. */
     1036    /** TX TSE fallback: Partial checksum from template header. */
    10301037    uint32_t    u32SavedCsum;
    10311038    /** ?: Emulated controller type. */
     
    28852892
    28862893/**
     2894 * Checks if we can use GSO processing for the current TSE frame.
     2895 *
     2896 * @param   pGso                The GSO context.
     2897 * @param   pData               The first data descriptor of the frame.
     2898 */
     2899DECLINLINE(bool) e1kCanDoGso(PCPDMNETWORKGSO pGso, E1KTXDAT const *pData)
     2900{
     2901//return false; /** @todo remove this before comitting */
     2902    if (!pData->cmd.fTSE)
     2903        return false;
     2904    if (pData->cmd.fVLE) /** @todo VLAN tagging. */
     2905        return false;
     2906
     2907    switch ((PDMNETWORKGSOTYPE)pGso->u8Type)
     2908    {
     2909        case PDMNETWORKGSOTYPE_IPV4_TCP:
     2910        case PDMNETWORKGSOTYPE_IPV4_UDP:
     2911            if (!pData->dw3.fIXSM)
     2912                return false;
     2913            if (!pData->dw3.fTXSM)
     2914                return false;
     2915            /** @todo what more check should we perform here? Ethernet frame type? */
     2916            return true;
     2917
     2918        case PDMNETWORKGSOTYPE_IPV6_TCP:
     2919        case PDMNETWORKGSOTYPE_IPV6_UDP:
     2920            if (pData->dw3.fIXSM)
     2921                return false;
     2922            if (!pData->dw3.fTXSM)
     2923                return false;
     2924            /** @todo what more check should we perform here? Ethernet frame type? */
     2925            return true;
     2926
     2927        default:
     2928            Assert(pGso->u8Type == PDMNETWORKGSOTYPE_INVALID);
     2929            return false;
     2930    }
     2931}
     2932
     2933/**
     2934 * Frees the current xmit buffer.
     2935 *
     2936 * @param   pState              The device state structure.
     2937 */
     2938static void e1kXmitFreeBuf(E1KSTATE *pState)
     2939{
     2940    PPDMSCATTERGATHER pSg = pState->pTxSgR3;
     2941    if (pSg)
     2942    {
     2943        pState->pTxSgR3 = NULL;
     2944
     2945        if (pSg->pvAllocator != pState)
     2946        {
     2947            PPDMINETWORKUP pDrv = pState->pDrv;
     2948            if (pDrv)
     2949                pDrv->pfnFreeBuf(pDrv, pSg);
     2950        }
     2951        else
     2952        {
     2953            /* loopback */
     2954            AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
     2955            Assert(pSg->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3));
     2956            pSg->fFlags = 0;
     2957            pSg->pvAllocator = NULL;
     2958        }
     2959    }
     2960}
     2961
     2962/**
     2963 * Allocates a xmit buffer.
     2964 *
     2965 * Presently this will always return a buffer.  Later on we'll have a
     2966 * out-of-buffer mechanism in place where the driver calls us back when buffers
     2967 * becomes available.
     2968 *
     2969 * @returns See PDMINETWORKUP::pfnAllocBuf.
     2970 * @param   pState              The device state structure.
     2971 * @param   cbMin               The minimum frame size.
     2972 * @param   fExactSize          Whether cbMin is exact or if we have to max it
     2973 *                              out to the max MTU size.
     2974 * @param   fGso                Whether this is a GSO frame or not.
     2975 */
     2976DECLINLINE(int) e1kXmitAllocBuf(E1KSTATE *pState, size_t cbMin, bool fExactSize, bool fGso)
     2977{
     2978    /* Adjust cbMin if necessary. */
     2979    if (!fExactSize)
     2980        cbMin = RT_MAX(cbMin, E1K_MAX_TX_PKT_SIZE);
     2981
     2982    /* Deal with existing buffer (descriptor screw up, reset, etc). */
     2983    if (RT_UNLIKELY(pState->pTxSgR3))
     2984        e1kXmitFreeBuf(pState);
     2985    Assert(pState->pTxSgR3 == NULL);
     2986
     2987    /*
     2988     * Allocate the buffe.r
     2989     */
     2990    PPDMSCATTERGATHER pSg;
     2991    if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
     2992    {
     2993        PPDMINETWORKUP pDrv = pState->pDrv;
     2994        if (RT_UNLIKELY(!pDrv))
     2995            return VERR_NET_DOWN;
     2996        int rc = pDrv->pfnAllocBuf(pDrv, cbMin, fGso ? &pState->GsoCtx : NULL, &pSg);
     2997        if (RT_FAILURE(rc))
     2998            return rc;
     2999    }
     3000    else
     3001    {
     3002        /* Create a loopback using the fallback buffer and preallocated SG. */
     3003        AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
     3004        pSg = &pState->uTxFallback.Sg;
     3005        pSg->fFlags      = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3;
     3006        pSg->cbUsed      = 0;
     3007        pSg->cbAvailable = 0;
     3008        pSg->pvAllocator = pState;
     3009        pSg->pvUser      = NULL; /* No GSO here. */
     3010        pSg->cSegs       = 1;
     3011        pSg->aSegs[0].pvSeg = pState->aTxPacketFallback;
     3012        pSg->aSegs[0].cbSeg = sizeof(pState->aTxPacketFallback);
     3013    }
     3014
     3015    pState->pTxSgR3 = pSg;
     3016    return VINF_SUCCESS;
     3017}
     3018
     3019/**
     3020 * Checks if it's a GSO buffer or not.
     3021 *
     3022 * @returns true / false.
     3023 * @param   pTxSg               The scatter / gather buffer.
     3024 */
     3025DECLINLINE(bool) e1kXmitIsGsoBuf(PDMSCATTERGATHER const *pTxSg)
     3026{
     3027    return pTxSg && pTxSg->pvUser /* GSO indicator */;
     3028}
     3029
     3030/**
    28873031 * Load transmit descriptor from guest memory.
    28883032 *
     
    29153059 * Transmit complete frame.
    29163060 *
    2917  * @remarks Since we do not have real Ethernet medium between us and NAT (or
    2918  *          another connector) there is no need for padding and FCS.
     3061 * @remarks We skip the FCS since we're not responsible for sending anything to
     3062 *          a real ethernet wire.
    29193063 *
    29203064 * @param   pState      The device state structure.
    2921  * @param   pFrame      Pointer to the frame buffer.
    2922  * @param   u16FrameLen Length of the frame.
    29233065 * @thread  E1000_TX
    29243066 */
    2925 static void e1kTransmitFrame(E1KSTATE* pState, uint8_t *pFrame, uint16_t u16FrameLen)
    2926 {
     3067static void e1kTransmitFrame(E1KSTATE* pState)
     3068{
     3069    PPDMSCATTERGATHER   pSg     = pState->pTxSgR3;
     3070    uint32_t const      cbFrame = pSg ? (size_t)pSg->cbUsed : 0;
     3071    Assert(!pSg || pSg->cSegs == 1);
     3072
    29273073/*    E1kLog2(("%s <<< Outgoing packet. Dump follows: >>>\n"
    29283074            "%.*Rhxd\n"
    29293075            "%s <<<<<<<<<<<<< End of dump >>>>>>>>>>>>\n",
    2930             INSTANCE(pState), u16FrameLen, pFrame, INSTANCE(pState)));*/
     3076            INSTANCE(pState), cbFrame, pSg->aSegs[0].pvSeg, INSTANCE(pState)));*/
     3077
    29313078#ifdef E1K_LEDS_WITH_MUTEX
    29323079    if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
     
    29413088    /* Update the stats */
    29423089    E1K_INC_CNT32(TPT);
    2943     E1K_ADD_CNT64(TOTL, TOTH, u16FrameLen);
     3090    E1K_ADD_CNT64(TOTL, TOTH, cbFrame);
    29443091    E1K_INC_CNT32(GPTC);
    2945     if (e1kIsBroadcast(pFrame))
     3092    if (pSg && e1kIsBroadcast(pSg->aSegs[0].pvSeg))
    29463093        E1K_INC_CNT32(BPTC);
    2947     else if (e1kIsMulticast(pFrame))
     3094    else if (pSg && e1kIsMulticast(pSg->aSegs[0].pvSeg))
    29483095        E1K_INC_CNT32(MPTC);
    29493096    /* Update octet transmit counter */
    2950     E1K_ADD_CNT64(GOTCL, GOTCH, u16FrameLen);
     3097    E1K_ADD_CNT64(GOTCL, GOTCH, cbFrame);
    29513098    if (pState->pDrv)
    2952     {
    2953         STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, u16FrameLen);
    2954     }
    2955     if (u16FrameLen == 64)
     3099        STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, cbFrame);
     3100    if (cbFrame == 64)
    29563101        E1K_INC_CNT32(PTC64);
    2957     else if (u16FrameLen < 128)
     3102    else if (cbFrame < 128)
    29583103        E1K_INC_CNT32(PTC127);
    2959     else if (u16FrameLen < 256)
     3104    else if (cbFrame < 256)
    29603105        E1K_INC_CNT32(PTC255);
    2961     else if (u16FrameLen < 512)
     3106    else if (cbFrame < 512)
    29623107        E1K_INC_CNT32(PTC511);
    2963     else if (u16FrameLen < 1024)
     3108    else if (cbFrame < 1024)
    29643109        E1K_INC_CNT32(PTC1023);
    29653110    else
     
    29683113    E1K_INC_ISTAT_CNT(pState->uStatTxFrm);
    29693114
    2970     e1kPacketDump(pState, pFrame, u16FrameLen, "--> Outgoing");
    2971 
    2972 
    2973     int rc = VINF_SUCCESS;
    2974     if (GET_BITS(RCTL, LBM) == RCTL_LBM_TCVR)
    2975     {
    2976         E1KRXDST status;
    2977         status.fPIF = true;
    2978         /* Loopback mode */
    2979         e1kHandleRxPacket(pState, pFrame, u16FrameLen, status);
    2980     }
    2981     else if (pState->pDrv)
    2982     {
    2983         /* Release critical section to avoid deadlock in CanReceive */
    2984         //e1kCsLeave(pState);
    2985         e1kMutexRelease(pState);
    2986         STAM_PROFILE_START(&pState->StatTransmitSend, a);
    2987         rc = pState->pDrv->pfnSendDeprecated(pState->pDrv, pFrame, u16FrameLen);
    2988         STAM_PROFILE_STOP(&pState->StatTransmitSend, a);
    2989         if (rc != VINF_SUCCESS)
     3115    /*
     3116     * Dump and send the packet.
     3117     */
     3118    int rc = VERR_NET_DOWN;
     3119    if (pSg && pSg->pvAllocator != pState)
     3120    {
     3121        e1kPacketDump(pState, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Outgoing");
     3122
     3123        pState->pTxSgR3 = NULL;
     3124        PPDMINETWORKUP pDrv = pState->pDrv;
     3125        if (pDrv)
    29903126        {
    2991             E1kLogRel(("E1000: ERROR! pfnSend returned %Rrc\n", rc));
     3127            /* Release critical section to avoid deadlock in CanReceive */
     3128            //e1kCsLeave(pState);
     3129            e1kMutexRelease(pState);
     3130            STAM_PROFILE_START(&pState->StatTransmitSend, a);
     3131            rc = pDrv->pfnSendBuf(pDrv, pSg, true /*fOnWorkerThread*/);
     3132            STAM_PROFILE_STOP(&pState->StatTransmitSend, a);
     3133            e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
     3134            //e1kCsEnter(pState, RT_SRC_POS);
    29923135        }
    2993         e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
    2994         //e1kCsEnter(pState, RT_SRC_POS);
    2995     }
    2996 #if 0  /** @todo bird/buf: error handling. */
     3136    }
     3137    else if (pSg)
     3138    {
     3139        Assert(pSg->aSegs[0].pvSeg == pState->aTxPacketFallback);
     3140        e1kPacketDump(pState, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Loopback");
     3141
     3142        /** @todo do we actually need to check that we're in loopback mode here? */
     3143        if (GET_BITS(RCTL, LBM) == RCTL_LBM_TCVR)
     3144        {
     3145            E1KRXDST status;
     3146            status.fPIF = true;
     3147            e1kHandleRxPacket(pState, pSg->aSegs[0].pvSeg, cbFrame, status);
     3148            rc = VINF_SUCCESS;
     3149        }
     3150        e1kXmitFreeBuf(pState);
     3151    }
    29973152    else
    29983153        rc = VERR_NET_DOWN;
    29993154    if (RT_FAILURE(rc))
    30003155    {
    3001         /** @todo handle VERR_NET_DOWN and VERR_NET_NO_BUFFER_SPACE. Signal error. */
    3002         ;
    3003     }
    3004 #endif
     3156        E1kLogRel(("E1000: ERROR! pfnSend returned %Rrc\n", rc));
     3157        /** @todo handle VERR_NET_DOWN and VERR_NET_NO_BUFFER_SPACE. Signal error ? */
     3158    }
    30053159
    30063160#ifdef E1K_LEDS_WITH_MUTEX
     
    30593213 * @thread  E1000_TX
    30603214 */
    3061 static void e1kAddSegment(E1KSTATE* pState, E1KTXDESC* pDesc, uint16_t u16Len, bool fSend)
     3215static void e1kFallbackAddSegment(E1KSTATE* pState, RTGCPHYS PhysAddr, uint16_t u16Len, bool fSend)
    30623216{
    30633217    /* TCP header being transmitted */
    30643218    struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
    3065             (pState->aTxPacket + pState->contextTSE.tu.u8CSS);
     3219            (pState->aTxPacketFallback + pState->contextTSE.tu.u8CSS);
    30663220    /* IP header being transmitted */
    30673221    struct E1kIpHeader *pIpHdr = (struct E1kIpHeader *)
    3068             (pState->aTxPacket + pState->contextTSE.ip.u8CSS);
    3069 
    3070     E1kLog3(("%s e1kAddSegment: Length=%x, remaining payload=%x, header=%x, send=%s\n",
    3071              INSTANCE(pState), u16Len, pState->u32PayRemain, pState->u16HdrRemain,
    3072              fSend ? "true" : "false"));
     3222            (pState->aTxPacketFallback + pState->contextTSE.ip.u8CSS);
     3223
     3224    E1kLog3(("%s e1kFallbackAddSegment: Length=%x, remaining payload=%x, header=%x, send=%RTbool\n",
     3225             INSTANCE(pState), u16Len, pState->u32PayRemain, pState->u16HdrRemain, fSend));
    30733226    Assert(pState->u32PayRemain + pState->u16HdrRemain > 0);
    30743227
    3075     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), pDesc->data.u64BufAddr,
    3076                       pState->aTxPacket + pState->u16TxPktLen, u16Len);
     3228    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), PhysAddr,
     3229                      pState->aTxPacketFallback + pState->u16TxPktLen, u16Len);
    30773230    E1kLog3(("%s Dump of the segment:\n"
    30783231            "%.*Rhxd\n"
    30793232            "%s --- End of dump ---\n",
    3080             INSTANCE(pState), u16Len, pState->aTxPacket + pState->u16TxPktLen, INSTANCE(pState)));
     3233            INSTANCE(pState), u16Len, pState->aTxPacketFallback + pState->u16TxPktLen, INSTANCE(pState)));
    30813234    pState->u16TxPktLen += u16Len;
    3082     E1kLog3(("%s e1kAddSegment: pState->u16TxPktLen=%x\n",
     3235    E1kLog3(("%s e1kFallbackAddSegment: pState->u16TxPktLen=%x\n",
    30833236            INSTANCE(pState), pState->u16TxPktLen));
    30843237    if (pState->u16HdrRemain > 0)
     
    31003253            /* Still not */
    31013254            pState->u16HdrRemain -= u16Len;
    3102             E1kLog3(("%s e1kAddSegment: Header is still incomplete, 0x%x bytes remain.\n",
     3255            E1kLog3(("%s e1kFallbackAddSegment: Header is still incomplete, 0x%x bytes remain.\n",
    31033256                    INSTANCE(pState), pState->u16HdrRemain));
    31043257            return;
     
    31133266        /* IP Total Length = payload + headers - ethernet header */
    31143267        pIpHdr->total_len = htons(pState->u16TxPktLen - pState->contextTSE.ip.u8CSS);
    3115         E1kLog3(("%s e1kAddSegment: End of packet, pIpHdr->total_len=%x\n",
     3268        E1kLog3(("%s e1kFallbackAddSegment: End of packet, pIpHdr->total_len=%x\n",
    31163269                INSTANCE(pState), ntohs(pIpHdr->total_len)));
    31173270        /* Update IP Checksum */
    31183271        pIpHdr->chksum = 0;
    3119         e1kInsertChecksum(pState, pState->aTxPacket, pState->u16TxPktLen,
     3272        e1kInsertChecksum(pState, pState->aTxPacketFallback, pState->u16TxPktLen,
    31203273                          pState->contextTSE.ip.u8CSO,
    31213274                          pState->contextTSE.ip.u8CSS,
     
    31373290        pTcpHdr->chksum = csum;
    31383291        /* Compute final checksum */
    3139         e1kInsertChecksum(pState, pState->aTxPacket, pState->u16TxPktLen,
     3292        e1kInsertChecksum(pState, pState->aTxPacketFallback, pState->u16TxPktLen,
    31403293                          pState->contextTSE.tu.u8CSO,
    31413294                          pState->contextTSE.tu.u8CSS,
    31423295                          pState->contextTSE.tu.u16CSE);
    3143         e1kTransmitFrame(pState, pState->aTxPacket, pState->u16TxPktLen);
     3296
     3297        /*
     3298         * Transmit it. If we've use the SG already, allocate a new one before
     3299         * we copy of the data.
     3300         */
     3301        if (!pState->pTxSgR3)
     3302            e1kXmitAllocBuf(pState, pState->u16TxPktLen, true /*fExactSize*/, false /*fGso*/);
     3303        if (pState->pTxSgR3)
     3304        {
     3305            Assert(pState->u16TxPktLen <= pState->pTxSgR3->cbAvailable);
     3306            Assert(pState->pTxSgR3->cSegs == 1);
     3307            if (pState->pTxSgR3->aSegs[0].pvSeg != pState->aTxPacketFallback)
     3308                memcpy(pState->pTxSgR3->aSegs[0].pvSeg, pState->aTxPacketFallback, pState->u16TxPktLen);
     3309            pState->pTxSgR3->cbUsed         = pState->u16TxPktLen;
     3310            pState->pTxSgR3->aSegs[0].cbSeg = pState->u16TxPktLen;
     3311        }
     3312        e1kTransmitFrame(pState);
     3313
    31443314        /* Update Sequence Number */
    31453315        pTcpHdr->seqno = htonl(ntohl(pTcpHdr->seqno) + pState->u16TxPktLen
     
    31513321
    31523322/**
    3153  * Add descriptor's buffer to transmit frame.
    3154  *
    3155  * @remarks data.u64BufAddr is used uncoditionally for both data
    3156  *          and legacy descriptors since it is identical to
    3157  *          legacy.u64BufAddr.
     3323 * TCP segmentation offloading fallback: Add descriptor's buffer to transmit
     3324 * frame.
     3325 *
     3326 * We construct the frame in the fallback buffer first and the copy it to the SG
     3327 * buffer before passing it down to the network driver code.
    31583328 *
    31593329 * @returns true if the frame should be transmitted, false if not.
     
    31613331 * @param   pState      The device state structure.
    31623332 * @param   pDesc       Pointer to the descriptor to transmit.
    3163  * @param   u16PartLen  Length of descriptor's buffer.
     3333 * @param   cbFragment  Length of descriptor's buffer.
    31643334 * @thread  E1000_TX
    31653335 */
    3166 static bool e1kAddToFrame(E1KSTATE* pState, E1KTXDESC* pDesc, uint32_t u32PartLen)
    3167 {
    3168     if (e1kGetDescType(pDesc) == E1K_DTYP_DATA && pDesc->data.cmd.fTSE)
    3169     {
    3170         uint16_t u16MaxPktLen = pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw3.u16MSS;
    3171         Assert(u16MaxPktLen != 0);
    3172         Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);
    3173 
    3174         do {
    3175             /* Calculate how many bytes have left in this TCP segment */
    3176             uint32_t uLen = u16MaxPktLen - pState->u16TxPktLen;
    3177             if (uLen > u32PartLen)
    3178             {
    3179                 /* This descriptor fits completely into current segment */
    3180                 uLen = u32PartLen;
    3181                 e1kAddSegment(pState, pDesc, uLen, pDesc->data.cmd.fEOP);
    3182             }
    3183             else
    3184             {
    3185                 e1kAddSegment(pState, pDesc, uLen, true);
    3186                 /*
    3187                  * Rewind the packet tail pointer to the beginning of payload,
    3188                  * so we continue writing right beyond the header.
    3189                  */
    3190                 pState->u16TxPktLen = pState->contextTSE.dw3.u8HDRLEN;
    3191             }
    3192             pDesc->data.u64BufAddr += uLen;
    3193             u32PartLen -= uLen;
    3194         } while (u32PartLen > 0);
    3195         if (pDesc->data.cmd.fEOP)
     3336static bool e1kFallbackAddToFrame(E1KSTATE* pState, E1KTXDESC* pDesc, uint32_t cbFragment)
     3337{
     3338    PPDMSCATTERGATHER pTxSg = pState->pTxSgR3;
     3339    Assert(e1kGetDescType(pDesc) == E1K_DTYP_DATA);
     3340    Assert(pDesc->data.cmd.fTSE);
     3341    Assert(!e1kXmitIsGsoBuf(pTxSg));
     3342
     3343    uint16_t u16MaxPktLen = pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw3.u16MSS;
     3344    Assert(u16MaxPktLen != 0);
     3345    Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);
     3346
     3347    /*
     3348     * Carve out segments.
     3349     */
     3350    do
     3351    {
     3352        /* Calculate how many bytes we have left in this TCP segment */
     3353        uint32_t cb = u16MaxPktLen - pState->u16TxPktLen;
     3354        if (cb > cbFragment)
    31963355        {
    3197             /* End of packet, next segment will contain header. */
    3198             pState->u16TxPktLen = 0;
     3356            /* This descriptor fits completely into current segment */
     3357            cb = cbFragment;
     3358            e1kFallbackAddSegment(pState, pDesc->data.u64BufAddr, cb, pDesc->data.cmd.fEOP /*fSend*/);
    31993359        }
     3360        else
     3361        {
     3362            e1kFallbackAddSegment(pState, pDesc->data.u64BufAddr, cb, true /*fSend*/);
     3363            /*
     3364             * Rewind the packet tail pointer to the beginning of payload,
     3365             * so we continue writing right beyond the header.
     3366             */
     3367            pState->u16TxPktLen = pState->contextTSE.dw3.u8HDRLEN;
     3368        }
     3369
     3370        pDesc->data.u64BufAddr += cb;
     3371        cbFragment             -= cb;
     3372    } while (cbFragment > 0);
     3373
     3374    if (pDesc->data.cmd.fEOP)
     3375    {
     3376        /* End of packet, next segment will contain header. */
     3377        pState->u16TxPktLen = 0;
     3378        e1kXmitFreeBuf(pState);
     3379    }
     3380
     3381    return false;
     3382}
     3383
     3384
     3385/**
     3386 * Add descriptor's buffer to transmit frame.
     3387 *
     3388 * This deals with GSO and normal frames, e1kFallbackAddToFrame deals with the
     3389 * TSE frames we cannot handle as GSO.
     3390 *
     3391 * @returns true on success, false on failure.
     3392 *
     3393 * @param   pThis       The device state structure.
     3394 * @param   PhysAddr    The physical address of the descriptor buffer.
     3395 * @param   cbFragment  Length of descriptor's buffer.
     3396 * @thread  E1000_TX
     3397 */
     3398static bool e1kAddToFrame(E1KSTATE *pThis, RTGCPHYS PhysAddr, uint32_t cbFragment)
     3399{
     3400    PPDMSCATTERGATHER   pTxSg    = pThis->pTxSgR3;
     3401    bool const          fGso     = e1kXmitIsGsoBuf(pTxSg);
     3402    uint32_t const      cbNewPkt = cbFragment + pThis->u16TxPktLen;
     3403
     3404    if (RT_UNLIKELY( !fGso && cbNewPkt > E1K_MAX_TX_PKT_SIZE ))
     3405    {
     3406        E1kLog(("%s Transmit packet is too large: %u > %u(max)\n", INSTANCE(pThis), cbNewPkt, E1K_MAX_TX_PKT_SIZE));
    32003407        return false;
    32013408    }
    3202 
    3203     if (u32PartLen + pState->u16TxPktLen > E1K_MAX_TX_PKT_SIZE)
    3204     {
    3205         E1kLog(("%s Transmit packet is too large: %d > %d(max)\n",
    3206                 INSTANCE(pState), u32PartLen + pState->u16TxPktLen, E1K_MAX_TX_PKT_SIZE));
     3409    if (RT_UNLIKELY( fGso && cbNewPkt > pTxSg->cbAvailable ))
     3410    {
     3411        E1kLog(("%s Transmit packet is too large: %u > %u(max)/GSO\n", INSTANCE(pThis), cbNewPkt, pTxSg->cbAvailable));
    32073412        return false;
    32083413    }
    3209     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), pDesc->data.u64BufAddr, pState->aTxPacket + pState->u16TxPktLen, u32PartLen);
    3210     pState->u16TxPktLen += u32PartLen;
     3414
     3415    if (RT_LIKELY(pTxSg))
     3416    {
     3417        Assert(pTxSg->cSegs == 1);
     3418        Assert(pTxSg->cbUsed == pThis->u16TxPktLen);
     3419
     3420        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
     3421                          (uint8_t *)pTxSg->aSegs[0].pvSeg + pThis->u16TxPktLen, cbFragment);
     3422
     3423        pTxSg->cbUsed = cbNewPkt;
     3424    }
     3425    pThis->u16TxPktLen = cbNewPkt;
    32113426
    32123427    return true;
     
    33223537            e1kDescReport(pState, pDesc, addr);
    33233538            break;
     3539
    33243540        case E1K_DTYP_DATA:
     3541        {
    33253542            if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
    33263543            {
    3327                 E1kLog2(("% Empty descriptor, skipped.\n", INSTANCE(pState)));
     3544                E1kLog2(("% Empty data descriptor, skipped.\n", INSTANCE(pState)));
     3545                /** @todo Same as legacy when !TSE. See below. */
    33283546                break;
    33293547            }
     
    33323550                             &pState->StatTxDescData);
    33333551            STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
    3334             /* IXSM and TXSM options are valid in the first fragment only */
     3552            E1K_INC_ISTAT_CNT(pState->uStatDescDat);
     3553
     3554            /*
     3555             * First fragment: Allocate new buffer and save the IXSM and TXSM
     3556             * packet options as these are only valid in the first fragment.
     3557             */
    33353558            if (pState->u16TxPktLen == 0)
    33363559            {
    33373560                pState->fIPcsum  = pDesc->data.dw3.fIXSM;
    33383561                pState->fTCPcsum = pDesc->data.dw3.fTXSM;
    3339                 E1kLog2(("%s Saving checksum flags:%s%s\n", INSTANCE(pState),
     3562                E1kLog2(("%s Saving checksum flags:%s%s; \n", INSTANCE(pState),
    33403563                         pState->fIPcsum ? " IP" : "",
    33413564                         pState->fTCPcsum ? " TCP/UDP" : ""));
     3565                if (e1kCanDoGso(&pState->GsoCtx, &pDesc->data))
     3566                    e1kXmitAllocBuf(pState, pState->contextTSE.dw2.u20PAYLEN + pState->contextTSE.dw3.u8HDRLEN,
     3567                                    true /*fExactSize*/, true /*fGso*/);
     3568                else
     3569                    e1kXmitAllocBuf(pState, pState->contextTSE.dw3.u16MSS + pState->contextTSE.dw3.u8HDRLEN,
     3570                                    pDesc->data.cmd.fTSE  /*fExactSize*/, false /*fGso*/);
     3571                /** @todo Is there any way to indicating errors other than collisions? Like
     3572                 *        VERR_NET_DOWN. */
    33423573            }
    3343             E1K_INC_ISTAT_CNT(pState->uStatDescDat);
    3344             if (e1kAddToFrame(pState, pDesc, pDesc->data.cmd.u20DTALEN) && pDesc->data.cmd.fEOP)
     3574
     3575            /*
     3576             * Add the descriptor data to the frame.  If the frame is complete,
     3577             * transmit it and reset the u16TxPktLen field.
     3578             */
     3579            if (e1kXmitIsGsoBuf(pState->pTxSgR3))
    33453580            {
    3346                 if (!pDesc->data.cmd.fTSE)
     3581                bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
     3582                if (pDesc->data.cmd.fEOP)
    33473583                {
    3348                     /*
    3349                      * We only insert checksums here if this packet was not segmented,
    3350                      * otherwise it has already been taken care of by e1kAddSegment().
    3351                      */
    3352                     if (pState->fIPcsum)
    3353                         e1kInsertChecksum(pState, pState->aTxPacket, pState->u16TxPktLen,
    3354                                           pState->contextNormal.ip.u8CSO,
    3355                                           pState->contextNormal.ip.u8CSS,
    3356                                           pState->contextNormal.ip.u16CSE);
    3357                     if (pState->fTCPcsum)
    3358                         e1kInsertChecksum(pState, pState->aTxPacket, pState->u16TxPktLen,
    3359                                           pState->contextNormal.tu.u8CSO,
    3360                                           pState->contextNormal.tu.u8CSS,
    3361                                           pState->contextNormal.tu.u16CSE);
     3584                    if (   fRc
     3585                        && pState->pTxSgR3
     3586                        && pState->pTxSgR3->cbUsed == (size_t)pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN)
     3587                    {
     3588                        e1kTransmitFrame(pState);
     3589                        E1K_INC_CNT32(TSCTC);
     3590                    }
     3591                    else
     3592                    {
     3593                        if (fRc)
     3594                           E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , INSTANCE(pState),
     3595                                   pState->pTxSgR3, pState->pTxSgR3 ? pState->pTxSgR3->cbUsed : 0,
     3596                                   pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN));
     3597                        e1kXmitFreeBuf(pState);
     3598                        E1K_INC_CNT32(TSCTFC);
     3599                    }
     3600                    pState->u16TxPktLen = 0;
    33623601                }
    3363                 e1kTransmitFrame(pState, pState->aTxPacket, pState->u16TxPktLen);
    3364                 /* Reset transmit packet storage. */
    3365                 pState->u16TxPktLen = 0;
    33663602            }
     3603            else if (!pDesc->data.cmd.fTSE)
     3604            {
     3605                bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
     3606                if (pDesc->data.cmd.fEOP)
     3607                {
     3608                    if (fRc && pState->pTxSgR3)
     3609                    {
     3610                        Assert(pState->pTxSgR3->cSegs == 1);
     3611                        if (pState->fIPcsum)
     3612                            e1kInsertChecksum(pState, (uint8_t *)pState->pTxSgR3->aSegs[0].pvSeg, pState->u16TxPktLen,
     3613                                              pState->contextNormal.ip.u8CSO,
     3614                                              pState->contextNormal.ip.u8CSS,
     3615                                              pState->contextNormal.ip.u16CSE);
     3616                        if (pState->fTCPcsum)
     3617                            e1kInsertChecksum(pState, (uint8_t *)pState->pTxSgR3->aSegs[0].pvSeg, pState->u16TxPktLen,
     3618                                              pState->contextNormal.tu.u8CSO,
     3619                                              pState->contextNormal.tu.u8CSS,
     3620                                              pState->contextNormal.tu.u16CSE);
     3621                        e1kTransmitFrame(pState);
     3622                    }
     3623                    else
     3624                        e1kXmitFreeBuf(pState);
     3625                    pState->u16TxPktLen = 0;
     3626                }
     3627            }
     3628            else
     3629                e1kFallbackAddToFrame(pState, pDesc, pDesc->data.cmd.u20DTALEN);
     3630
    33673631            e1kDescReport(pState, pDesc, addr);
    33683632            STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
    33693633            break;
     3634        }
     3635
    33703636        case E1K_DTYP_LEGACY:
    33713637            if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
    33723638            {
    3373                 E1kLog(("%s Empty descriptor, skipped.\n", INSTANCE(pState)));
     3639                E1kLog(("%s Empty legacy descriptor, skipped.\n", INSTANCE(pState)));
     3640                /** @todo 3.3.3, Length/Buffer Address: RS set -> write DD when processing. */
    33743641                break;
    33753642            }
    33763643            STAM_COUNTER_INC(&pState->StatTxDescLegacy);
    33773644            STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
    3378             if (e1kAddToFrame(pState, pDesc, pDesc->legacy.cmd.u16Length))
     3645
     3646            /* First fragment: allocate new buffer. */
     3647            if (pState->u16TxPktLen == 0)
     3648                /** @todo reset status bits? */
     3649                e1kXmitAllocBuf(pState, pDesc->legacy.cmd.u16Length, pDesc->legacy.cmd.fEOP, false /*fGso*/);
     3650                /** @todo Is there any way to indicating errors other than collisions? Like
     3651                 *        VERR_NET_DOWN. */
     3652
     3653            /* Add fragment to frame. */
     3654            if (e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
    33793655            {
    33803656                E1K_INC_ISTAT_CNT(pState->uStatDescLeg);
    3381                 /** @todo Offload processing goes here. */
     3657
     3658                /* Last fragment: Transmit and reset the packet storage counter.  */
    33823659                if (pDesc->legacy.cmd.fEOP)
    33833660                {
    3384                     e1kTransmitFrame(pState, pState->aTxPacket, pState->u16TxPktLen);
    3385                     /* Reset transmit packet storage. */
     3661                    /** @todo Offload processing goes here. */
     3662                    e1kTransmitFrame(pState);
    33863663                    pState->u16TxPktLen = 0;
    33873664                }
    33883665            }
     3666            /* Last fragment + failure: free the buffer and reset the storage counter. */
     3667            else if (pDesc->legacy.cmd.fEOP)
     3668            {
     3669                e1kXmitFreeBuf(pState);
     3670                pState->u16TxPktLen = 0;
     3671            }
     3672
    33893673            e1kDescReport(pState, pDesc, addr);
    33903674            STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
    33913675            break;
     3676
    33923677        default:
    33933678            E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n",
     
    47365021    //SSMR3PutBool(pSSM, pState->fIntMaskUsed);
    47375022    SSMR3PutU16(pSSM, pState->u16TxPktLen);
    4738     SSMR3PutMem(pSSM, pState->aTxPacket, pState->u16TxPktLen);
     5023/** @todo State wrt to the TSE buffer is incomplete, so little point in
     5024 *        saving this actually. */
     5025    SSMR3PutMem(pSSM, pState->aTxPacketFallback, pState->u16TxPktLen);
    47395026    SSMR3PutBool(pSSM, pState->fIPcsum);
    47405027    SSMR3PutBool(pSSM, pState->fTCPcsum);
    47415028    SSMR3PutMem(pSSM, &pState->contextTSE, sizeof(pState->contextTSE));
    47425029    SSMR3PutMem(pSSM, &pState->contextNormal, sizeof(pState->contextNormal));
     5030/**@todo GSO requres some more state here. */
    47435031    E1kLog(("%s State has been saved\n", INSTANCE(pState)));
    47445032    return VINF_SUCCESS;
     
    48465134        //SSMR3GetBool(pSSM, pState->fIntMaskUsed);
    48475135        SSMR3GetU16(pSSM, &pState->u16TxPktLen);
    4848         SSMR3GetMem(pSSM, &pState->aTxPacket[0], pState->u16TxPktLen);
     5136        SSMR3GetMem(pSSM, &pState->aTxPacketFallback[0], pState->u16TxPktLen);
    48495137        SSMR3GetBool(pSSM, &pState->fIPcsum);
    48505138        SSMR3GetBool(pSSM, &pState->fTCPcsum);
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r27844 r28057  
    13301330    GEN_CHECK_OFF(E1KSTATE, contextTSE);
    13311331    GEN_CHECK_OFF(E1KSTATE, contextNormal);
    1332     GEN_CHECK_OFF(E1KSTATE, aTxPacket[E1K_MAX_TX_PKT_SIZE]);
     1332    GEN_CHECK_OFF(E1KSTATE, aTxPacketFallback[E1K_MAX_TX_PKT_SIZE]);
    13331333    GEN_CHECK_OFF(E1KSTATE, u16TxPktLen);
    13341334    GEN_CHECK_OFF(E1KSTATE, fIPcsum);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette