Changeset 28057 in vbox
- Timestamp:
- Apr 7, 2010 5:23:58 PM (15 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/DevE1000.cpp
r28037 r28057 975 975 bool fGCEnabled; 976 976 977 /* All: Device register storage. */977 /** All: Device register storage. */ 978 978 uint32_t auRegs[E1K_NUM_OF_32BIT_REGS]; 979 979 /** TX/RX: Status LED. */ … … 1011 1011 * applicable to the current TSE mode. */ 1012 1012 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]; 1017 1024 /** TX: Number of bytes assembled in TX packet buffer. */ 1018 1025 uint16_t u16TxPktLen; … … 1021 1028 /** TX: TCP/UDP checksum has to be inserted if true. */ 1022 1029 bool fTCPcsum; 1023 /** TX : Number of payload bytes remaining in TSE context. */1030 /** TX TSE fallback: Number of payload bytes remaining in TSE context. */ 1024 1031 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. */ 1026 1033 uint16_t u16HdrRemain; 1027 /** TX : Flags from template header. */1034 /** TX TSE fallback: Flags from template header. */ 1028 1035 uint16_t u16SavedFlags; 1029 /** TX : Partial checksum from template header. */1036 /** TX TSE fallback: Partial checksum from template header. */ 1030 1037 uint32_t u32SavedCsum; 1031 1038 /** ?: Emulated controller type. */ … … 2885 2892 2886 2893 /** 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 */ 2899 DECLINLINE(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 */ 2938 static 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 */ 2976 DECLINLINE(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 */ 3025 DECLINLINE(bool) e1kXmitIsGsoBuf(PDMSCATTERGATHER const *pTxSg) 3026 { 3027 return pTxSg && pTxSg->pvUser /* GSO indicator */; 3028 } 3029 3030 /** 2887 3031 * Load transmit descriptor from guest memory. 2888 3032 * … … 2915 3059 * Transmit complete frame. 2916 3060 * 2917 * @remarks Since we do not have real Ethernet medium between us and NAT (or2918 * a nother 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. 2919 3063 * 2920 3064 * @param pState The device state structure. 2921 * @param pFrame Pointer to the frame buffer.2922 * @param u16FrameLen Length of the frame.2923 3065 * @thread E1000_TX 2924 3066 */ 2925 static void e1kTransmitFrame(E1KSTATE* pState, uint8_t *pFrame, uint16_t u16FrameLen) 2926 { 3067 static 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 2927 3073 /* E1kLog2(("%s <<< Outgoing packet. Dump follows: >>>\n" 2928 3074 "%.*Rhxd\n" 2929 3075 "%s <<<<<<<<<<<<< End of dump >>>>>>>>>>>>\n", 2930 INSTANCE(pState), u16FrameLen, pFrame, INSTANCE(pState)));*/ 3076 INSTANCE(pState), cbFrame, pSg->aSegs[0].pvSeg, INSTANCE(pState)));*/ 3077 2931 3078 #ifdef E1K_LEDS_WITH_MUTEX 2932 3079 if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS)) … … 2941 3088 /* Update the stats */ 2942 3089 E1K_INC_CNT32(TPT); 2943 E1K_ADD_CNT64(TOTL, TOTH, u16FrameLen);3090 E1K_ADD_CNT64(TOTL, TOTH, cbFrame); 2944 3091 E1K_INC_CNT32(GPTC); 2945 if ( e1kIsBroadcast(pFrame))3092 if (pSg && e1kIsBroadcast(pSg->aSegs[0].pvSeg)) 2946 3093 E1K_INC_CNT32(BPTC); 2947 else if ( e1kIsMulticast(pFrame))3094 else if (pSg && e1kIsMulticast(pSg->aSegs[0].pvSeg)) 2948 3095 E1K_INC_CNT32(MPTC); 2949 3096 /* Update octet transmit counter */ 2950 E1K_ADD_CNT64(GOTCL, GOTCH, u16FrameLen);3097 E1K_ADD_CNT64(GOTCL, GOTCH, cbFrame); 2951 3098 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) 2956 3101 E1K_INC_CNT32(PTC64); 2957 else if ( u16FrameLen< 128)3102 else if (cbFrame < 128) 2958 3103 E1K_INC_CNT32(PTC127); 2959 else if ( u16FrameLen< 256)3104 else if (cbFrame < 256) 2960 3105 E1K_INC_CNT32(PTC255); 2961 else if ( u16FrameLen< 512)3106 else if (cbFrame < 512) 2962 3107 E1K_INC_CNT32(PTC511); 2963 else if ( u16FrameLen< 1024)3108 else if (cbFrame < 1024) 2964 3109 E1K_INC_CNT32(PTC1023); 2965 3110 else … … 2968 3113 E1K_INC_ISTAT_CNT(pState->uStatTxFrm); 2969 3114 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) 2990 3126 { 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); 2992 3135 } 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 } 2997 3152 else 2998 3153 rc = VERR_NET_DOWN; 2999 3154 if (RT_FAILURE(rc)) 3000 3155 { 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 } 3005 3159 3006 3160 #ifdef E1K_LEDS_WITH_MUTEX … … 3059 3213 * @thread E1000_TX 3060 3214 */ 3061 static void e1k AddSegment(E1KSTATE* pState, E1KTXDESC* pDesc, uint16_t u16Len, bool fSend)3215 static void e1kFallbackAddSegment(E1KSTATE* pState, RTGCPHYS PhysAddr, uint16_t u16Len, bool fSend) 3062 3216 { 3063 3217 /* TCP header being transmitted */ 3064 3218 struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *) 3065 (pState->aTxPacket + pState->contextTSE.tu.u8CSS);3219 (pState->aTxPacketFallback + pState->contextTSE.tu.u8CSS); 3066 3220 /* IP header being transmitted */ 3067 3221 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)); 3073 3226 Assert(pState->u32PayRemain + pState->u16HdrRemain > 0); 3074 3227 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); 3077 3230 E1kLog3(("%s Dump of the segment:\n" 3078 3231 "%.*Rhxd\n" 3079 3232 "%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))); 3081 3234 pState->u16TxPktLen += u16Len; 3082 E1kLog3(("%s e1k AddSegment: pState->u16TxPktLen=%x\n",3235 E1kLog3(("%s e1kFallbackAddSegment: pState->u16TxPktLen=%x\n", 3083 3236 INSTANCE(pState), pState->u16TxPktLen)); 3084 3237 if (pState->u16HdrRemain > 0) … … 3100 3253 /* Still not */ 3101 3254 pState->u16HdrRemain -= u16Len; 3102 E1kLog3(("%s e1k AddSegment: Header is still incomplete, 0x%x bytes remain.\n",3255 E1kLog3(("%s e1kFallbackAddSegment: Header is still incomplete, 0x%x bytes remain.\n", 3103 3256 INSTANCE(pState), pState->u16HdrRemain)); 3104 3257 return; … … 3113 3266 /* IP Total Length = payload + headers - ethernet header */ 3114 3267 pIpHdr->total_len = htons(pState->u16TxPktLen - pState->contextTSE.ip.u8CSS); 3115 E1kLog3(("%s e1k AddSegment: End of packet, pIpHdr->total_len=%x\n",3268 E1kLog3(("%s e1kFallbackAddSegment: End of packet, pIpHdr->total_len=%x\n", 3116 3269 INSTANCE(pState), ntohs(pIpHdr->total_len))); 3117 3270 /* Update IP Checksum */ 3118 3271 pIpHdr->chksum = 0; 3119 e1kInsertChecksum(pState, pState->aTxPacket , pState->u16TxPktLen,3272 e1kInsertChecksum(pState, pState->aTxPacketFallback, pState->u16TxPktLen, 3120 3273 pState->contextTSE.ip.u8CSO, 3121 3274 pState->contextTSE.ip.u8CSS, … … 3137 3290 pTcpHdr->chksum = csum; 3138 3291 /* Compute final checksum */ 3139 e1kInsertChecksum(pState, pState->aTxPacket , pState->u16TxPktLen,3292 e1kInsertChecksum(pState, pState->aTxPacketFallback, pState->u16TxPktLen, 3140 3293 pState->contextTSE.tu.u8CSO, 3141 3294 pState->contextTSE.tu.u8CSS, 3142 3295 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 3144 3314 /* Update Sequence Number */ 3145 3315 pTcpHdr->seqno = htonl(ntohl(pTcpHdr->seqno) + pState->u16TxPktLen … … 3151 3321 3152 3322 /** 3153 * Add descriptor's buffer to transmit frame.3154 * 3155 * @remarks data.u64BufAddr is used uncoditionally for both data3156 * and legacy descriptors since it is identical to3157 * 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. 3158 3328 * 3159 3329 * @returns true if the frame should be transmitted, false if not. … … 3161 3331 * @param pState The device state structure. 3162 3332 * @param pDesc Pointer to the descriptor to transmit. 3163 * @param u16PartLenLength of descriptor's buffer.3333 * @param cbFragment Length of descriptor's buffer. 3164 3334 * @thread E1000_TX 3165 3335 */ 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) 3336 static 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) 3196 3355 { 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*/); 3199 3359 } 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 */ 3398 static 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)); 3200 3407 return false; 3201 3408 } 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)); 3207 3412 return false; 3208 3413 } 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; 3211 3426 3212 3427 return true; … … 3322 3537 e1kDescReport(pState, pDesc, addr); 3323 3538 break; 3539 3324 3540 case E1K_DTYP_DATA: 3541 { 3325 3542 if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0) 3326 3543 { 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. */ 3328 3546 break; 3329 3547 } … … 3332 3550 &pState->StatTxDescData); 3333 3551 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 */ 3335 3558 if (pState->u16TxPktLen == 0) 3336 3559 { 3337 3560 pState->fIPcsum = pDesc->data.dw3.fIXSM; 3338 3561 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), 3340 3563 pState->fIPcsum ? " IP" : "", 3341 3564 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. */ 3342 3573 } 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)) 3345 3580 { 3346 if (!pDesc->data.cmd.fTSE) 3581 bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN); 3582 if (pDesc->data.cmd.fEOP) 3347 3583 { 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; 3362 3601 } 3363 e1kTransmitFrame(pState, pState->aTxPacket, pState->u16TxPktLen);3364 /* Reset transmit packet storage. */3365 pState->u16TxPktLen = 0;3366 3602 } 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 3367 3631 e1kDescReport(pState, pDesc, addr); 3368 3632 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a); 3369 3633 break; 3634 } 3635 3370 3636 case E1K_DTYP_LEGACY: 3371 3637 if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0) 3372 3638 { 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. */ 3374 3641 break; 3375 3642 } 3376 3643 STAM_COUNTER_INC(&pState->StatTxDescLegacy); 3377 3644 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)) 3379 3655 { 3380 3656 E1K_INC_ISTAT_CNT(pState->uStatDescLeg); 3381 /** @todo Offload processing goes here. */ 3657 3658 /* Last fragment: Transmit and reset the packet storage counter. */ 3382 3659 if (pDesc->legacy.cmd.fEOP) 3383 3660 { 3384 e1kTransmitFrame(pState, pState->aTxPacket, pState->u16TxPktLen);3385 /* Reset transmit packet storage. */3661 /** @todo Offload processing goes here. */ 3662 e1kTransmitFrame(pState); 3386 3663 pState->u16TxPktLen = 0; 3387 3664 } 3388 3665 } 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 3389 3673 e1kDescReport(pState, pDesc, addr); 3390 3674 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a); 3391 3675 break; 3676 3392 3677 default: 3393 3678 E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n", … … 4736 5021 //SSMR3PutBool(pSSM, pState->fIntMaskUsed); 4737 5022 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); 4739 5026 SSMR3PutBool(pSSM, pState->fIPcsum); 4740 5027 SSMR3PutBool(pSSM, pState->fTCPcsum); 4741 5028 SSMR3PutMem(pSSM, &pState->contextTSE, sizeof(pState->contextTSE)); 4742 5029 SSMR3PutMem(pSSM, &pState->contextNormal, sizeof(pState->contextNormal)); 5030 /**@todo GSO requres some more state here. */ 4743 5031 E1kLog(("%s State has been saved\n", INSTANCE(pState))); 4744 5032 return VINF_SUCCESS; … … 4846 5134 //SSMR3GetBool(pSSM, pState->fIntMaskUsed); 4847 5135 SSMR3GetU16(pSSM, &pState->u16TxPktLen); 4848 SSMR3GetMem(pSSM, &pState->aTxPacket [0], pState->u16TxPktLen);5136 SSMR3GetMem(pSSM, &pState->aTxPacketFallback[0], pState->u16TxPktLen); 4849 5137 SSMR3GetBool(pSSM, &pState->fIPcsum); 4850 5138 SSMR3GetBool(pSSM, &pState->fTCPcsum); -
trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
r27844 r28057 1330 1330 GEN_CHECK_OFF(E1KSTATE, contextTSE); 1331 1331 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]); 1333 1333 GEN_CHECK_OFF(E1KSTATE, u16TxPktLen); 1334 1334 GEN_CHECK_OFF(E1KSTATE, fIPcsum);
Note:
See TracChangeset
for help on using the changeset viewer.