VirtualBox

Ignore:
Timestamp:
Mar 30, 2010 9:02:49 PM (15 years ago)
Author:
vboxsync
Message:

DevPCNet.cpp: Use the buffered network driver interface.

File:
1 edited

Legend:

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

    r27825 r27844  
    5050 * THE SOFTWARE.
    5151 */
     52#define VBOX_WITH_TX_THREAD_IN_NET_DEVICES 1 //debug, bird, remove
    5253
    5354/*******************************************************************************
     
    158159    uint64_t                            u64LastPoll;
    159160
    160     /** Size of current send frame */
    161     uint32_t                            cbSendFrame;
    162 #if HC_ARCH_BITS == 64
    163     uint32_t                            Alignment3;
    164 #endif
    165     /** Buffer address of current send frame */
    166     R3PTRTYPE(uint8_t *)                pvSendFrame;
    167     /** The xmit buffer. */
    168     uint8_t                             abSendBuf[4096];
     161    /** The loopback transmit buffer (avoid stack allocations). */
     162    uint8_t                             abLoopBuf[4096];
    169163    /** The recv buffer. */
    170164    uint8_t                             abRecvBuf[4096];
    171165
    172     /** Pending send packet counter. */
    173     uint32_t                            cPendingSends;
     166    /** Unused / padding. */
     167    uint32_t                            u32Unused;
    174168
    175169    /** Size of a RX/TX descriptor (8 or 16 bytes according to SWSTYLE */
     
    201195    PTMTIMERR3                          pTimerRestore;
    202196    /** Pointer to the connector of the attached network driver. */
    203     R3PTRTYPE(PPDMINETWORKUP)    pDrv;
     197    R3PTRTYPE(PPDMINETWORKUP)           pDrvR3;
    204198    /** Pointer to the attached network driver. */
    205199    R3PTRTYPE(PPDMIBASE)                pDrvBase;
     
    233227    R3PTRTYPE(PPDMILEDCONNECTORS)       pLedsConnector;
    234228
     229#ifdef VBOX_WITH_TX_THREAD_IN_NET_DEVICES
    235230    /** Async send thread */
    236231    RTSEMEVENT                          hSendEventSem;
    237232    /** The Async send thread. */
    238233    PPDMTHREAD                          pSendThread;
     234#endif
    239235
    240236    /** Access critical section. */
     
    292288    STAMPROFILEADV                      StatReceive;
    293289    STAMPROFILEADV                      StatTransmit;
    294     STAMPROFILEADV                      StatTransmitSend;
     290    STAMCOUNTER                         StatTransmitCase1;
     291    STAMCOUNTER                         StatTransmitCase2;
     292    STAMPROFILE                         StatTransmitSend;
    295293    STAMPROFILEADV                      StatTdtePollGC;
    296294    STAMPROFILEADV                      StatTdtePollHC;
     
    617615DECLINLINE(bool) pcnetIsLinkUp(PCNetState *pThis)
    618616{
    619     return pThis->pDrv && !pThis->fLinkTempDown && pThis->fLinkUp;
     617    return pThis->pDrvR3 && !pThis->fLinkTempDown && pThis->fLinkUp;
    620618}
    621619
     
    15981596    pThis->fSignalRxMiss = (cbRxBuffers == 0 || cbRxBuffers >= 32*_1K);
    15991597
    1600     if (pThis->pDrv)
    1601         pThis->pDrv->pfnSetPromiscuousMode(pThis->pDrv, CSR_PROM(pThis));
     1598    if (pThis->pDrvR3)
     1599        pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, CSR_PROM(pThis));
    16021600
    16031601    CSR_RCVRC(pThis) = CSR_RCVRL(pThis);
     
    20632061
    20642062    /* Clear counter .*/
    2065     ASMAtomicAndU32(&pThis->cPendingSends, 0);
     2063#ifndef VBOX_WITH_TX_THREAD_IN_NET_DEVICES
     2064    int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
     2065    AssertReleaseRC(rc);
     2066
     2067    pcnetAsyncTransmit(pThis, false /*fOnWorkerThread*/);
     2068
     2069    PDMCritSectLeave(&pThis->CritSect);
     2070#else
    20662071    int rc = RTSemEventSignal(pThis->hSendEventSem);
    20672072    AssertRC(rc);
     2073#endif
    20682074    return true;
    20692075}
     
    20712077
    20722078/**
    2073  * Scraps the top frame.
    2074  * This is done as a precaution against mess left over by on
    2075  */
    2076 DECLINLINE(void) pcnetXmitScrapFrame(PCNetState *pThis)
    2077 {
    2078     pThis->pvSendFrame = NULL;
    2079     pThis->cbSendFrame = 0;
    2080 }
    2081 
    2082 
    2083 /**
    2084  * Reads the first part of a frame
    2085  */
    2086 DECLINLINE(void) pcnetXmitRead1st(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
     2079 * Allocates a scatter/gather buffer for a transfer.
     2080 *
     2081 * @returns See PPDMINETWORKUP::pfnAllocBuf.
     2082 * @param   pThis       The device instance.
     2083 * @param   cbMin       The minimum buffer size.
     2084 * @param   fLoopback   Set if we're in loopback mode.
     2085 * @param   pSgLoop     Pointer to stack storage for the loopback SG.
     2086 * @param   ppSgBuf     Where to return the SG buffer descriptor on success.
     2087 *                      Always set.
     2088 */
     2089DECLINLINE(int) pcnetXmitAllocBuf(PCNetState *pThis, size_t cbMin, bool fLoopback,
     2090                                  PPDMSCATTERGATHER pSgLoop, PPPDMSCATTERGATHER ppSgBuf)
     2091{
     2092    int rc;
     2093
     2094    if (RT_UNLIKELY(fLoopback)) /* hope that loopback mode is rare */
     2095    {
     2096        pSgLoop->fFlags      = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
     2097        pSgLoop->cbUsed      = 0;
     2098        pSgLoop->cbAvailable = sizeof(pThis->abLoopBuf);
     2099        pSgLoop->pvAllocator = pThis;
     2100        pSgLoop->pvUser      = NULL;
     2101        pSgLoop->cSegs       = 1;
     2102        pSgLoop->aSegs[0].cbSeg = sizeof(pThis->abLoopBuf);
     2103        pSgLoop->aSegs[0].pvSeg = pThis->abLoopBuf;
     2104        *ppSgBuf = pSgLoop;
     2105        rc = VINF_SUCCESS;
     2106    }
     2107    else
     2108    {
     2109        PPDMINETWORKUP pDrv = pThis->pDrvR3;
     2110        if (RT_LIKELY(pDrv))
     2111        {
     2112            rc = pDrv->pfnAllocBuf(pDrv, cbMin, ppSgBuf);
     2113            AssertMsg(rc == VINF_SUCCESS || rc == VERR_TRY_AGAIN || rc == VERR_NET_DOWN || rc == VERR_NO_MEMORY, ("%Rrc\n", rc));
     2114            if (RT_FAILURE(rc))
     2115                *ppSgBuf = NULL;
     2116        }
     2117        else
     2118        {
     2119            rc = VERR_NET_DOWN;
     2120            *ppSgBuf = NULL;
     2121        }
     2122    }
     2123    return rc;
     2124}
     2125
     2126
     2127/**
     2128 * Frees an unsent buffer.
     2129 *
     2130 * @param   pThis           The device instance.
     2131 * @param   fLoopback       Set if we're in loopback mode.
     2132 * @param   pSgBuf          The SG to free.  Can be NULL.
     2133 */
     2134DECLINLINE(void) pcnetXmitFreeBuf(PCNetState *pThis, bool fLoopback, PPDMSCATTERGATHER pSgBuf)
     2135{
     2136    if (pSgBuf)
     2137    {
     2138        if (RT_UNLIKELY(fLoopback))
     2139            pSgBuf->pvAllocator = NULL;
     2140        else
     2141        {
     2142            PPDMINETWORKUP pDrv = pThis->pDrvR3;
     2143            if (RT_LIKELY(pDrv))
     2144                pDrv->pfnFreeBuf(pDrv, pSgBuf);
     2145        }
     2146    }
     2147}
     2148
     2149
     2150/**
     2151 * Sends the scatter/gather buffer.
     2152 *
     2153 * Wrapper around PDMINETWORKUP::pfnSendBuf, so check it out for the fine print.
     2154 *
     2155 * @returns See PDMINETWORKUP::pfnSendBuf.
     2156 * @param   pThis           The device instance.
     2157 * @param   fLoopback       Set if we're in loopback mode.
     2158 * @param   pSgBuf          The SG to send.
     2159 * @param   fOnWorkerThread Set if we're being called on a work thread.  Clear
     2160 *                          if an EMT.
     2161 */
     2162DECLINLINE(int) pcnetXmitSendBuf(PCNetState *pThis, bool fLoopback, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
     2163{
     2164    int rc;
     2165    STAM_REL_COUNTER_ADD(&pThis->StatTransmitBytes, pSgBuf->cbUsed);
     2166    if (RT_UNLIKELY(fLoopback)) /* hope that loopback mode is rare */
     2167    {
     2168        Assert(pSgBuf->pvAllocator == (void *)pThis);
     2169        pThis->Led.Asserted.s.fReading = pThis->Led.Actual.s.fReading = 1;
     2170        if (HOST_IS_OWNER(CSR_CRST(pThis)))
     2171            pcnetRdtePoll(pThis);
     2172
     2173        pcnetReceiveNoSync(pThis, pThis->abLoopBuf, pSgBuf->cbUsed);
     2174        pThis->Led.Actual.s.fReading = 0;
     2175        rc = VINF_SUCCESS;
     2176    }
     2177    else
     2178    {
     2179        /** @todo We used to leave the critsect here, not sure if that's necessary any
     2180         *        longer.  If we could avoid that we could cache a bit more info in
     2181         *        the loop and make it part of the driver<->device contract, saving
     2182         *        critsect mess down in DrvIntNet. */
     2183        STAM_PROFILE_START(&pThis->StatTransmitSend, a);
     2184        if (pSgBuf->cbUsed > 70) /* unqualified guess */
     2185            pThis->Led.Asserted.s.fWriting = pThis->Led.Actual.s.fWriting = 1;
     2186
     2187        PPDMINETWORKUP pDrv = pThis->pDrvR3;
     2188        if (RT_LIKELY(pDrv))
     2189        {
     2190            rc = pDrv->pfnSendBuf(pDrv, pSgBuf, fOnWorkerThread);
     2191            AssertMsg(rc == VINF_SUCCESS || rc == VERR_NET_DOWN || rc == VERR_NET_NO_BUFFER_SPACE, ("%Rrc\n", rc));
     2192        }
     2193        else
     2194            rc = VERR_NET_DOWN;
     2195
     2196        pThis->Led.Actual.s.fWriting = 0;
     2197        STAM_PROFILE_STOP(&pThis->StatTransmitSend, a);
     2198    }
     2199    return rc;
     2200}
     2201
     2202
     2203/**
     2204 * pcnetXmitRead1st worker that handles the unlikely + slower segmented code
     2205 * path.
     2206 */
     2207static void pcnetXmitRead1stSlow(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, unsigned cbFrame,
     2208                                 PPDMSCATTERGATHER pSgBuf)
     2209{
     2210    AssertFailed(); /* This path is not suppost to be taken atm */
     2211
     2212    pSgBuf->cbUsed = cbFrame;
     2213    for (uint32_t iSeg = 0; ; iSeg++)
     2214    {
     2215        Assert(iSeg < pSgBuf->cSegs);
     2216        size_t cbRead = RT_MIN(cbFrame, pSgBuf->aSegs[iSeg].cbSeg);
     2217        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pSgBuf->aSegs[iSeg].pvSeg, cbRead);
     2218        cbFrame -= cbRead;
     2219        if (!cbFrame)
     2220            return;
     2221        GCPhysFrame += cbRead;
     2222    }
     2223}
     2224
     2225
     2226/**
     2227 * pcnetXmitSgReadMore worker that handles the unlikely + slower segmented code
     2228 * path.
     2229 */
     2230static void pcnetXmitReadMoreSlow(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, unsigned cbFrame,
     2231                                  PPDMSCATTERGATHER pSgBuf)
     2232{
     2233    AssertFailed(); /* This path is not suppost to be taken atm */
     2234
     2235    /* Find the segment which we'll put the next byte into. */
     2236    size_t      off    = pSgBuf->cbUsed;
     2237    size_t      offSeg = 0;
     2238    uint32_t    iSeg   = 0;
     2239    while (offSeg + pSgBuf->aSegs[iSeg].cbSeg <= off)
     2240    {
     2241        offSeg += pSgBuf->aSegs[iSeg].cbSeg;
     2242        iSeg++;
     2243        Assert(iSeg < pSgBuf->cSegs);
     2244    }
     2245
     2246    /* Commit before we start copying so we can decrement cbFrame. */
     2247    pSgBuf->cbUsed = off + cbFrame;
     2248
     2249    /* Deal with the first segment if we at an offset into it. */
     2250    if (off != offSeg)
     2251    {
     2252        size_t offIntoSeg = off - offSeg;
     2253        size_t cbRead     = RT_MIN(pSgBuf->aSegs[iSeg].cbSeg - offIntoSeg, cbFrame);
     2254        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame,
     2255                          (uint8_t *)pSgBuf->aSegs[iSeg].pvSeg + offIntoSeg, cbRead);
     2256        cbFrame -= cbRead;
     2257        if (!cbFrame)
     2258            return;
     2259        GCPhysFrame += cbRead;
     2260        iSeg++;
     2261    }
     2262
     2263    /* For the remainder, we've got whole segments. */
     2264    for (;; iSeg++)
     2265    {
     2266        Assert(iSeg < pSgBuf->cSegs);
     2267
     2268        size_t cbRead = RT_MIN(pSgBuf->aSegs[iSeg].cbSeg, cbFrame);
     2269        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pSgBuf->aSegs[iSeg].pvSeg, cbRead);
     2270        cbFrame -= cbRead;
     2271        if (!cbFrame)
     2272            return;
     2273        GCPhysFrame += cbFrame;
     2274    }
     2275}
     2276
     2277
     2278/**
     2279 * Reads the first part of a frame into the scatter gather buffer.
     2280 */
     2281DECLINLINE(void) pcnetXmitRead1st(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame,
     2282                                  PPDMSCATTERGATHER pSgBuf)
    20872283{
    20882284    Assert(PDMCritSectIsOwner(&pThis->CritSect));
    2089     Assert(cbFrame < sizeof(pThis->abSendBuf));
    2090 
    2091     pThis->pvSendFrame = pThis->abSendBuf;
    2092     PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pThis->pvSendFrame, cbFrame);
    2093     pThis->cbSendFrame = cbFrame;
    2094 }
    2095 
     2285    Assert(pSgBuf->cbAvailable >= cbFrame);
     2286
     2287    if (RT_LIKELY(pSgBuf->aSegs[0].cbSeg >= cbFrame)) /* justification: all drivers returns a single segment atm. */
     2288    {
     2289        pSgBuf->cbUsed = cbFrame;
     2290        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pSgBuf->aSegs[0].pvSeg, cbFrame);
     2291    }
     2292    else
     2293        pcnetXmitRead1stSlow(pThis, GCPhysFrame, cbFrame, pSgBuf);
     2294}
    20962295
    20972296/**
    20982297 * Reads more into the current frame.
    20992298 */
    2100 DECLINLINE(void) pcnetXmitReadMore(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
    2101 {
    2102     Assert(pThis->cbSendFrame + cbFrame <= MAX_FRAME);
    2103     PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pThis->pvSendFrame + pThis->cbSendFrame, cbFrame);
    2104     pThis->cbSendFrame += cbFrame;
    2105 }
    2106 
    2107 
    2108 /**
    2109  * Completes the current frame.
    2110  * If we've reached the maxium number of frames, they will be flushed.
    2111  */
    2112 DECLINLINE(int) pcnetXmitCompleteFrame(PCNetState *pThis)
    2113 {
    2114     /* Don't hold the critical section while transmitting data. */
    2115     /** @note also avoids deadlocks with NAT as it can call us right back. */
    2116     PDMCritSectLeave(&pThis->CritSect);
    2117 
    2118     STAM_PROFILE_ADV_START(&pThis->StatTransmitSend, a);
    2119     if (pThis->cbSendFrame > 70) /* unqualified guess */
    2120         pThis->Led.Asserted.s.fWriting = pThis->Led.Actual.s.fWriting = 1;
    2121 
    2122     pThis->pDrv->pfnSendDeprecated(pThis->pDrv, pThis->pvSendFrame, pThis->cbSendFrame);
    2123     STAM_REL_COUNTER_ADD(&pThis->StatTransmitBytes, pThis->cbSendFrame);
    2124     pThis->Led.Actual.s.fWriting = 0;
    2125     STAM_PROFILE_ADV_STOP(&pThis->StatTransmitSend, a);
    2126 
    2127     return PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
     2299DECLINLINE(void) pcnetXmitReadMore(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame,
     2300                                   PPDMSCATTERGATHER pSgBuf)
     2301{
     2302    size_t off = pSgBuf->cbUsed;
     2303    Assert(pSgBuf->cbAvailable >= cbFrame + off);
     2304
     2305    if (RT_LIKELY(pSgBuf->aSegs[0].cbSeg >= cbFrame + off))
     2306    {
     2307        pSgBuf->cbUsed = cbFrame + off;
     2308        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame,
     2309                          (uint8_t *)pSgBuf->aSegs[0].pvSeg + off, cbFrame);
     2310    }
     2311    else
     2312        pcnetXmitReadMoreSlow(pThis, GCPhysFrame, cbFrame, pSgBuf);
    21282313}
    21292314
     
    21582343
    21592344/**
    2160  * Transmit a loopback frame.
    2161  */
    2162 DECLINLINE(void) pcnetXmitLoopbackFrame(PCNetState *pThis)
    2163 {
    2164     pThis->Led.Asserted.s.fReading = pThis->Led.Actual.s.fReading = 1;
    2165     if (HOST_IS_OWNER(CSR_CRST(pThis)))
    2166         pcnetRdtePoll(pThis);
    2167 
    2168     Assert(pThis->pvSendFrame);
    2169     pcnetReceiveNoSync(pThis, (const uint8_t *)pThis->pvSendFrame, pThis->cbSendFrame);
    2170     pcnetXmitScrapFrame(pThis);
    2171     pThis->Led.Actual.s.fReading = 0;
    2172 }
    2173 
    2174 /**
    21752345 * Flushes queued frames.
    21762346 */
     
    22132383    pcnetXmitFlushFrames(pThis);
    22142384#else
    2215 # if 1
    22162385    PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pXmitQueue));
    22172386    if (RT_UNLIKELY(pItem))
    22182387        PDMQueueInsert(pThis->CTX_SUFF(pXmitQueue), pItem);
    2219 # else
    2220     if (ASMAtomicIncU32(&pThis->cPendingSends) < 16)
    2221     {
    2222         PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pXmitQueue));
    2223         if (RT_UNLIKELY(pItem))
    2224             PDMQueueInsert(pThis->CTX_SUFF(pXmitQueue), pItem);
    2225     }
    2226     else
    2227         PDMQueueFlush(pThis->CTX_SUFF(pXmitQueue));
    2228 # endif
    22292388#endif
    22302389}
     
    22332392
    22342393/**
    2235  * Try to transmit frames
    2236  */
    2237 static int pcnetAsyncTransmit(PCNetState *pThis)
    2238 {
    2239     unsigned cFlushIrq = 0;
    2240 
     2394 * Actually try transmit frames.
     2395 *
     2396 * @threads TX or EMT.
     2397 */
     2398static int pcnetAsyncTransmit(PCNetState *pThis, bool fOnWorkerThread)
     2399{
    22412400    Assert(PDMCritSectIsOwner(&pThis->CritSect));
    22422401
     2402    /*
     2403     * Just cleard transmit demand if the transmitter is off.
     2404     */
    22432405    if (RT_UNLIKELY(!CSR_TXON(pThis)))
    22442406    {
     
    22502412     * Iterate the transmit descriptors.
    22512413     */
     2414    int         rc;
     2415    unsigned    cFlushIrq = 0;
    22522416    STAM_PROFILE_ADV_START(&pThis->StatTransmit, a);
    22532417    do
     
    22702434        PRINT_TMD(&tmd);
    22712435#endif
    2272         pcnetXmitScrapFrame(pThis);
     2436        bool const          fLoopback = CSR_LOOP(pThis);
     2437        PDMSCATTERGATHER    SgLoop;
     2438        PPDMSCATTERGATHER   pSgBuf;
    22732439
    22742440        /*
     
    22782444        {
    22792445            const unsigned cb = 4096 - tmd.tmd1.bcnt;
    2280             Log(("#%d pcnetTransmit: stp&enp: cb=%d xmtrc=%#x\n", PCNET_INST_NR, cb, CSR_XMTRC(pThis)));
    2281 
    2282             if (RT_LIKELY(pcnetIsLinkUp(pThis) || CSR_LOOP(pThis)))
     2446            Log(("#%d pcnetAsyncTransmit: stp&enp: cb=%d xmtrc=%#x\n", PCNET_INST_NR, cb, CSR_XMTRC(pThis)));
     2447            STAM_COUNTER_INC(&pThis->StatTransmitCase1);
     2448
     2449            if (RT_LIKELY(pcnetIsLinkUp(pThis) || fLoopback))
    22832450            {
    22842451                /* From the manual: ``A zero length buffer is acceptable as
     
    22882455                if (RT_LIKELY(cb <= MAX_FRAME))
    22892456                {
    2290                     pcnetXmitRead1st(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb);
    2291                     if (CSR_LOOP(pThis))
    2292                         pcnetXmitLoopbackFrame(pThis);
    2293                     else
     2457                    rc = pcnetXmitAllocBuf(pThis, cb, fLoopback, &SgLoop, &pSgBuf);
     2458                    if (RT_SUCCESS(rc))
    22942459                    {
    2295                         int rc = pcnetXmitCompleteFrame(pThis);
    2296                         AssertRCReturn(rc, rc);
     2460                        pcnetXmitRead1st(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb, pSgBuf);
     2461                        rc = pcnetXmitSendBuf(pThis, fLoopback, pSgBuf, fOnWorkerThread);
    22972462                    }
     2463                    else if (rc == VERR_TRY_AGAIN)
     2464                    {
     2465                        STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
     2466                        return VINF_SUCCESS;
     2467                    }
     2468                    if (RT_FAILURE(rc))
     2469                        pcnetXmitFailTMDLinkDown(pThis, &tmd);
    22982470                }
    22992471                else if (cb == 4096)
     
    23372509        else if (tmd.tmd1.stp)
    23382510        {
     2511            STAM_COUNTER_INC(&pThis->StatTransmitCase2);
     2512
    23392513            /*
    23402514             * Read TMDs until end-of-packet or tdte poll fails (underflow).
     2515             *
     2516             * We allocate a maximum sized buffer here since we do not wish to
     2517             * waste time finding out how much space we actually need even if
     2518             * we could reliably do that on SMP guests.
    23412519             */
    2342             bool fDropFrame = false;
    23432520            unsigned cb = 4096 - tmd.tmd1.bcnt;
    2344             pcnetXmitRead1st(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb);
     2521            rc = pcnetXmitAllocBuf(pThis, RT_MAX(MAX_FRAME, cb), fLoopback, &SgLoop, &pSgBuf);
     2522            if (rc == VERR_TRY_AGAIN)
     2523            {
     2524                STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
     2525                return VINF_SUCCESS;
     2526            }
     2527
     2528            bool fDropFrame = RT_FAILURE(rc);
     2529            if (!fDropFrame)
     2530                pcnetXmitRead1st(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb, pSgBuf);
     2531
    23452532            for (;;)
    23462533            {
     
    23492536                 */
    23502537#ifdef LOG_ENABLED
    2351                 const uint32_t iStart = CSR_XMTRC(pThis);
     2538                const uint32_t iStart        = CSR_XMTRC(pThis);
    23522539#endif
    23532540                const uint32_t GCPhysPrevTmd = PHYSADDR(pThis, CSR_CXDA(pThis));
     
    23682555                        pThis->aCSR[0] &= ~0x0010;   /* clear TXON */
    23692556                    pcnetTmdStorePassHost(pThis, &tmd, GCPhysPrevTmd);
    2370                     AssertMsgFailed(("pcnetTransmit: Underflow!!!\n"));
     2557                    AssertMsgFailed(("pcnetAsyncTransmit: Underflow!!!\n"));
     2558                    pcnetXmitFreeBuf(pThis, fLoopback, pSgBuf);
    23712559                    break;
    23722560                }
     
    23762564
    23772565                /*
    2378                  * The next tdm.
     2566                 * The next tmd.
    23792567                 */
    23802568#ifdef VBOX_WITH_STATISTICS
     
    23832571                pcnetTmdLoad(pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)), false);
    23842572                cb = 4096 - tmd.tmd1.bcnt;
    2385                 if (    pThis->cbSendFrame + cb < MAX_FRAME
    2386                     &&  !fDropFrame)
    2387                     pcnetXmitReadMore(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb);
     2573                if (   !fDropFrame
     2574                    && pSgBuf->cbUsed + cb <= MAX_FRAME) /** @todo this used to be ... + cb < MAX_FRAME. */
     2575                    pcnetXmitReadMore(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb, pSgBuf);
    23882576                else
    23892577                {
    2390                     AssertMsg(fDropFrame, ("pcnetTransmit: Frame is too big!!! %d bytes\n",
    2391                                 pThis->cbSendFrame + cb));
     2578                    AssertMsg(fDropFrame, ("pcnetAsyncTransmit: Frame is too big!!! %d bytes\n", pSgBuf->cbUsed + cb));
    23922579                    fDropFrame = true;
    23932580                }
     2581
     2582                /*
     2583                 * Done already?
     2584                 */
    23942585                if (tmd.tmd1.enp)
    23952586                {
    2396                     Log(("#%d pcnetTransmit: stp: cb=%d xmtrc=%#x-%#x\n", PCNET_INST_NR,
    2397                                 pThis->cbSendFrame, iStart, CSR_XMTRC(pThis)));
    2398                     if (pcnetIsLinkUp(pThis) && !fDropFrame)
     2587                    Log(("#%d pcnetAsyncTransmit: stp: cb=%d xmtrc=%#x-%#x\n", PCNET_INST_NR,
     2588                         pSgBuf ? pSgBuf->cbUsed : 0, iStart, CSR_XMTRC(pThis)));
     2589                    if (!fDropFrame && (pcnetIsLinkUp(pThis) || fLoopback))
    23992590                    {
    2400                         int rc = pcnetXmitCompleteFrame(pThis);
    2401                         AssertRCReturn(rc, rc);
     2591                        rc = pcnetXmitSendBuf(pThis, fLoopback, pSgBuf, fOnWorkerThread);
     2592                        fDropFrame = RT_FAILURE(rc);
    24022593                    }
    2403                     else if (CSR_LOOP(pThis) && !fDropFrame)
    2404                         pcnetXmitLoopbackFrame(pThis);
    24052594                    else
    2406                     {
    2407                         if (!fDropFrame)
    2408                             pcnetXmitFailTMDLinkDown(pThis, &tmd);
    2409                         pcnetXmitScrapFrame(pThis);
    2410                     }
     2595                        pcnetXmitFreeBuf(pThis, fLoopback, pSgBuf);
     2596                    if (fDropFrame)
     2597                        pcnetXmitFailTMDLinkDown(pThis, &tmd);
    24112598
    24122599                    /* Write back the TMD, pass it to the host */
     
    24202607                    break;
    24212608                }
    2422             }
     2609            } /* the loop */
    24232610        }
    24242611        else
     
    24292616             */
    24302617            /** @todo according to the specs we're supposed to clear the own bit and move on to the next one. */
    2431             Log(("#%d pcnetTransmit: guest is giving us shit!\n", PCNET_INST_NR));
     2618            Log(("#%d pcnetAsyncTransmit: guest is giving us shit!\n", PCNET_INST_NR));
    24322619            break;
    24332620        }
     
    24612648}
    24622649
     2650#ifdef VBOX_WITH_TX_THREAD_IN_NET_DEVICES
    24632651
    24642652/**
     
    25102698        if (pThread->enmState == PDMTHREADSTATE_RUNNING)
    25112699        {
    2512             rc = pcnetAsyncTransmit(pThis);
     2700            rc = pcnetAsyncTransmit(pThis, true /*fOnWorkerThread*/);
    25132701            AssertReleaseRC(rc);
    25142702        }
     
    25352723}
    25362724
     2725# endif /* VBOX_WITH_TX_THREAD_IN_NET_DEVICES*/
    25372726#endif /* IN_RING3 */
    25382727
     
    27452934            }
    27462935        case 15: /* Mode */
    2747             if ((pThis->aCSR[15] & 0x8000) != (uint16_t)(val & 0x8000) && pThis->pDrv)
     2936            if ((pThis->aCSR[15] & 0x8000) != (uint16_t)(val & 0x8000) && pThis->pDrvR3)
    27482937            {
    27492938                Log(("#%d: promiscuous mode changed to %d\n", PCNET_INST_NR, !!(val & 0x8000)));
     
    27522941#else
    27532942                /* check for promiscuous mode change */
    2754                 if (pThis->pDrv)
    2755                     pThis->pDrv->pfnSetPromiscuousMode(pThis->pDrv, !!(val & 0x8000));
     2943                if (pThis->pDrvR3)
     2944                    pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, !!(val & 0x8000));
    27562945#endif
    27572946            }
     
    30783267            val = pThis->aBCR[u32RAP] & ~0x8000;
    30793268            /* Clear LNKSTE if we're not connected or if we've just loaded a VM state. */
    3080             if (!pThis->pDrv || pThis->fLinkTempDown || !pThis->fLinkUp)
     3269            if (!pThis->pDrvR3 || pThis->fLinkTempDown || !pThis->fLinkUp)
    30813270            {
    30823271                if (u32RAP == 4)
     
    43824571
    43834572        /* update promiscuous mode. */
    4384         if (pThis->pDrv)
    4385             pThis->pDrv->pfnSetPromiscuousMode(pThis->pDrv, CSR_PROM(pThis));
     4573        if (pThis->pDrvR3)
     4574            pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, CSR_PROM(pThis));
    43864575
    43874576#ifdef PCNET_NO_POLLING
     
    46324821        }
    46334822        Assert(!PDMCritSectIsOwner(&pThis->CritSect));
    4634         if (pThis->pDrv)
    4635             pThis->pDrv->pfnNotifyLinkChanged(pThis->pDrv, enmState);
     4823        if (pThis->pDrvR3)
     4824            pThis->pDrvR3->pfnNotifyLinkChanged(pThis->pDrvR3, enmState);
    46364825    }
    46374826    return VINF_SUCCESS;
     
    46964885     */
    46974886    pThis->pDrvBase = NULL;
    4698     pThis->pDrv = NULL;
     4887    pThis->pDrvR3 = NULL;
    46994888
    47004889    PDMCritSectLeave(&pThis->CritSect);
     
    47394928#endif
    47404929        }
    4741         pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
    4742         AssertMsgStmt(pThis->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
     4930        pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
     4931        AssertMsgStmt(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"),
    47434932                      rc = VERR_PDM_MISSING_INTERFACE_BELOW);
    47444933    }
     
    48615050    Assert(RT_ELEMENTS(pThis->aBCR) == BCR_MAX_RAP);
    48625051    Assert(RT_ELEMENTS(pThis->aMII) == MII_MAX_REG);
    4863     Assert(sizeof(pThis->abSendBuf) == RT_ALIGN_Z(sizeof(pThis->abSendBuf), 16));
     5052    Assert(sizeof(pThis->abLoopBuf) == RT_ALIGN_Z(sizeof(pThis->abLoopBuf), 16));
    48645053
    48655054    /*
     
    51165305#endif
    51175306        }
    5118         pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
    5119         AssertMsgReturn(pThis->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
     5307        pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
     5308        AssertMsgReturn(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"),
    51205309                        VERR_PDM_MISSING_INTERFACE_BELOW);
    51215310    }
     
    51305319    pcnetHardReset(pThis);
    51315320
     5321#ifdef VBOX_WITH_TX_THREAD_IN_NET_DEVICES
    51325322    /* Create send queue for the async send thread. */
    51335323    rc = RTSemEventCreate(&pThis->hSendEventSem);
     
    51375327    rc = PDMDevHlpThreadCreate(pDevIns, &pThis->pSendThread, pThis, pcnetAsyncSendThread, pcnetAsyncSendThreadWakeUp, 0, RTTHREADTYPE_IO, "PCNET_TX");
    51385328    AssertRCReturn(rc, rc);
     5329#endif
    51395330
    51405331#ifdef VBOX_WITH_STATISTICS
     
    51565347    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes,       STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,          "Amount of data received",            "/Devices/PCNet%d/ReceiveBytes", iInstance);
    51575348#ifdef VBOX_WITH_STATISTICS
     5349    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitCase1,      STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Single descriptor transmit",         "/Devices/PCNet%d/Transmit/Case1", iInstance);
     5350    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitCase2,      STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Multi descriptor transmit",          "/Devices/PCNet%d/Transmit/Case2", iInstance);
    51585351    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmit,           STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC",          "/Devices/PCNet%d/Transmit/Total", iInstance);
    51595352#endif
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