VirtualBox

Changeset 41502 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
May 30, 2012 5:15:22 PM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
78261
Message:

e1000: Optional RXD prefetching, proper handling of empty TX descriptors (#6217)

File:
1 edited

Legend:

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

    r41431 r41502  
    8484 * E1K_WITH_TX_CS protects e1kXmitPending with a critical section.
    8585 */
    86 #define E1K_WITH_TX_CS 1
     86#define E1K_WITH_TX_CS
    8787/*
    8888 * E1K_WITH_TXD_CACHE causes E1000 to fetch multiple TX descriptors in a
     
    9292 * to allocating their buffers (see #5582).
    9393 */
    94 #define E1K_WITH_TXD_CACHE 1
     94#define E1K_WITH_TXD_CACHE
     95/*
     96 * E1K_WITH_RXD_CACHE causes E1000 to fetch multiple RX descriptors in a
     97 * single physical memory read (or two if it wraps around the end of RX
     98 * descriptor ring). Intel's packet driver for DOS needs this option in
     99 * order to work properly (see #6217).
     100 */
     101#define E1K_WITH_RXD_CACHE
    95102/* End of Options ************************************************************/
    96103
     
    104111#define E1K_TXD_CACHE_SIZE 32u
    105112#endif /* E1K_WITH_TXD_CACHE */
     113
     114#ifdef E1K_WITH_RXD_CACHE
     115/*
     116 * E1K_RXD_CACHE_SIZE specifies the maximum number of RX descriptors stored
     117 * in the state structure. It limits the amount of descriptors loaded in one
     118 * batch read. For example, XP guest adds 15 RX descriptors at a time.
     119 */
     120#define E1K_RXD_CACHE_SIZE 16u
     121#endif /* E1K_WITH_RXD_CACHE */
    106122
    107123#include <iprt/crc.h>
     
    10771093    /** EMT: Gets signalled when more RX descriptors become available. */
    10781094    RTSEMEVENT  hEventMoreRxDescAvail;
     1095#ifdef E1K_WITH_RXD_CACHE
     1096    /** RX: Fetched RX descriptors. */
     1097    E1KRXDESC   aRxDescriptors[E1K_RXD_CACHE_SIZE];
     1098    /** RX: Actual number of fetched RX descriptors. */
     1099    uint32_t    nRxDFetched;
     1100    /** RX: Index in cache of RX descriptor being processed. */
     1101    uint32_t    iRxDCurrent;
     1102#endif /* E1K_WITH_RXD_CACHE */
    10791103
    10801104    /** TX: Context used for TCP segmentation packets. */
     
    15521576    if (pState->pDrvR3)
    15531577        pState->pDrvR3->pfnSetPromiscuousMode(pState->pDrvR3, false);
     1578
     1579#ifdef E1K_WITH_TXD_CACHE
     1580    int rc = e1kCsTxEnter(pState, VERR_SEM_BUSY);
     1581    if (RT_LIKELY(rc == VINF_SUCCESS))
     1582    {
     1583        pState->nTxDFetched  = 0;
     1584        pState->iTxDCurrent  = 0;
     1585        pState->fGSO         = false;
     1586        pState->cbTxAlloc    = 0;
     1587        e1kCsTxLeave(pState);
     1588    }
     1589#endif /* E1K_WITH_TXD_CACHE */
     1590#ifdef E1K_WITH_RXD_CACHE
     1591    rc = e1kCsRxEnter(pState, VERR_SEM_BUSY);
     1592    if (RT_LIKELY(rc == VINF_SUCCESS))
     1593    {
     1594        pState->iRxDCurrent = pState->nRxDFetched = 0;
     1595        e1kCsRxLeave(pState);
     1596    }
     1597#endif /* E1K_WITH_RXD_CACHE */
    15541598}
    15551599
     
    18401884}
    18411885
     1886#ifdef E1K_WITH_RXD_CACHE
     1887/**
     1888 * Return the number of RX descriptor that belong to the hardware.
     1889 *
     1890 * @returns the number of available descriptors in RX ring.
     1891 * @param   pState      The device state structure.
     1892 * @thread  ???
     1893 */
     1894DECLINLINE(uint32_t) e1kGetRxLen(E1KSTATE* pState)
     1895{
     1896    /**
     1897     *  Make sure RDT won't change during computation. EMT may modify RDT at
     1898     *  any moment.
     1899     */
     1900    uint32_t rdt = RDT;
     1901    return (RDH > rdt ? RDLEN/sizeof(E1KRXDESC) : 0) + rdt - RDH;
     1902}
     1903
     1904DECLINLINE(unsigned) e1kRxDInCache(E1KSTATE* pState)
     1905{
     1906    return pState->nRxDFetched > pState->iRxDCurrent ?
     1907        pState->nRxDFetched - pState->iRxDCurrent : 0;
     1908}
     1909
     1910DECLINLINE(unsigned) e1kRxDIsCacheEmpty(E1KSTATE* pState)
     1911{
     1912    return pState->iRxDCurrent >= pState->nRxDFetched;
     1913}
     1914
     1915/**
     1916 * Load receive descriptors from guest memory. The caller needs to be in Rx
     1917 * critical section.
     1918 *
     1919 * We need two physical reads in case the tail wrapped around the end of RX
     1920 * descriptor ring.
     1921 *
     1922 * @returns the actual number of descriptors fetched.
     1923 * @param   pState      The device state structure.
     1924 * @param   pDesc       Pointer to descriptor union.
     1925 * @param   addr        Physical address in guest context.
     1926 * @thread  EMT, RX
     1927 */
     1928DECLINLINE(unsigned) e1kRxDPrefetch(E1KSTATE* pState)
     1929{
     1930    /* We've already loaded pState->nRxDFetched descriptors past RDH. */
     1931    unsigned nDescsAvailable    = e1kGetRxLen(pState) - e1kRxDInCache(pState);
     1932    unsigned nDescsToFetch      = RT_MIN(nDescsAvailable, E1K_RXD_CACHE_SIZE - pState->nRxDFetched);
     1933    unsigned nDescsTotal        = RDLEN / sizeof(E1KRXDESC);
     1934    Assert(nDescsTotal != 0);
     1935    if (nDescsTotal == 0)
     1936        return 0;
     1937    unsigned nFirstNotLoaded    = (RDH + e1kRxDInCache(pState)) % nDescsTotal;
     1938    unsigned nDescsInSingleRead = RT_MIN(nDescsToFetch, nDescsTotal - nFirstNotLoaded);
     1939    E1kLog3(("%s e1kRxDPrefetch: nDescsAvailable=%u nDescsToFetch=%u "
     1940             "nDescsTotal=%u nFirstNotLoaded=0x%x nDescsInSingleRead=%u\n",
     1941             INSTANCE(pState), nDescsAvailable, nDescsToFetch, nDescsTotal,
     1942             nFirstNotLoaded, nDescsInSingleRead));
     1943    if (nDescsToFetch == 0)
     1944        return 0;
     1945    E1KRXDESC* pFirstEmptyDesc = &pState->aRxDescriptors[pState->nRxDFetched];
     1946    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
     1947                      ((uint64_t)RDBAH << 32) + RDBAL + nFirstNotLoaded * sizeof(E1KRXDESC),
     1948                      pFirstEmptyDesc, nDescsInSingleRead * sizeof(E1KRXDESC));
     1949    E1kLog3(("%s Fetched %u RX descriptors at %08x%08x(0x%x), RDLEN=%08x, RDH=%08x, RDT=%08x\n",
     1950             INSTANCE(pState), nDescsInSingleRead,
     1951             RDBAH, RDBAL + RDH * sizeof(E1KRXDESC),
     1952             nFirstNotLoaded, RDLEN, RDH, RDT));
     1953    if (nDescsToFetch > nDescsInSingleRead)
     1954    {
     1955        PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
     1956                          ((uint64_t)RDBAH << 32) + RDBAL,
     1957                          pFirstEmptyDesc + nDescsInSingleRead,
     1958                          (nDescsToFetch - nDescsInSingleRead) * sizeof(E1KRXDESC));
     1959        E1kLog3(("%s Fetched %u RX descriptors at %08x%08x\n",
     1960                 INSTANCE(pState), nDescsToFetch - nDescsInSingleRead,
     1961                 RDBAH, RDBAL));
     1962    }
     1963    pState->nRxDFetched += nDescsToFetch;
     1964    return nDescsToFetch;
     1965}
     1966
     1967DECLINLINE(E1KRXDESC*) e1kRxDGet(E1KSTATE* pState)
     1968{
     1969    /* Check the cache first. */
     1970    if (pState->iRxDCurrent < pState->nRxDFetched)
     1971        return &pState->aRxDescriptors[pState->iRxDCurrent++];
     1972    /* Cache is empty, reset it and check if we can fetch more. */
     1973    pState->iRxDCurrent = pState->nRxDFetched = 0;
     1974    if (e1kRxDPrefetch(pState))
     1975        return &pState->aRxDescriptors[pState->iRxDCurrent++];
     1976    /* Out of Rx descriptors. */
     1977    return NULL;
     1978}
     1979#endif /* E1K_WITH_RXD_CACHE */
     1980
    18421981/**
    18431982 * Advance the head pointer of the receive descriptor queue.
     
    18782017}
    18792018
     2019#ifndef E1K_WITH_RXD_CACHE
    18802020/**
    18812021 * Store a fragment of received packet that fits into the next available RX
     
    19262066    STAM_PROFILE_ADV_STOP(&pState->StatReceiveStore, a);
    19272067}
     2068#else /* E1K_WITH_RXD_CACHE */
     2069/**
     2070 * Store a fragment of received packet at the specifed address.
     2071 *
     2072 * @param   pState          The device state structure.
     2073 * @param   pDesc           The next available RX descriptor.
     2074 * @param   pvBuf           The fragment.
     2075 * @param   cb              The size of the fragment.
     2076 */
     2077static DECLCALLBACK(void) e1kStoreRxFragment(E1KSTATE *pState, E1KRXDESC *pDesc, const void *pvBuf, size_t cb)
     2078{
     2079    STAM_PROFILE_ADV_START(&pState->StatReceiveStore, a);
     2080    E1kLog2(("%s e1kStoreRxFragment: store fragment of %04X at %016LX, EOP=%d\n",
     2081             INSTANCE(pState), cb, pDesc->u64BufAddr, pDesc->status.fEOP));
     2082    PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns), pDesc->u64BufAddr, pvBuf, cb);
     2083    pDesc->u16Length = (uint16_t)cb;                        Assert(pDesc->u16Length == cb);
     2084    STAM_PROFILE_ADV_STOP(&pState->StatReceiveStore, a);
     2085}
     2086#endif /* E1K_WITH_RXD_CACHE */
    19282087
    19292088/**
     
    20962255    E1K_INC_ISTAT_CNT(pState->uStatRxFrm);
    20972256
     2257#ifdef E1K_WITH_RXD_CACHE
     2258    while (cb > 0)
     2259    {
     2260        E1KRXDESC *pDesc = e1kRxDGet(pState);
     2261
     2262        if (pDesc == NULL)
     2263        {
     2264            E1kLog(("%s Out of receive buffers, dropping the packet "
     2265                    "(cb=%u, in_cache=%u, RDH=%x RDT=%x)\n",
     2266                    INSTANCE(pState), cb, e1kRxDInCache(pState), RDH, RDT));
     2267            break;
     2268        }
     2269#else /* !E1K_WITH_RXD_CACHE */
    20982270    if (RDH == RDT)
    20992271    {
    2100         E1kLog(("%s Out of receive buffers, dropping the packet",
     2272        E1kLog(("%s Out of receive buffers, dropping the packet\n",
    21012273                INSTANCE(pState)));
    21022274    }
     
    21052277    {
    21062278        /* Load the descriptor pointed by head */
    2107         E1KRXDESC desc;
     2279        E1KRXDESC desc, *pDesc = &desc;
    21082280        PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
    21092281                          &desc, sizeof(desc));
    2110         if (desc.u64BufAddr)
     2282#endif /* !E1K_WITH_RXD_CACHE */
     2283        if (pDesc->u64BufAddr)
    21112284        {
    21122285            /* Update descriptor */
    2113             desc.status        = status;
    2114             desc.u16Checksum   = checksum;
    2115             desc.status.fDD    = true;
     2286            pDesc->status        = status;
     2287            pDesc->u16Checksum   = checksum;
     2288            pDesc->status.fDD    = true;
    21162289
    21172290            /*
     
    21192292             * with EMT in e1kRegWriteRDT when the write is to an unallocated
    21202293             * page or has an access handler associated with it.
    2121              * Note that it is safe to leave the critical section here since e1kRegWriteRDT()
    2122              * modifies RDT only.
     2294             * Note that it is safe to leave the critical section here since
     2295             * e1kRegWriteRDT() never modifies RDH. It never touches already
     2296             * fetched RxD cache entries either.
    21232297             */
    21242298            if (cb > pState->u16RxBSize)
    21252299            {
    2126                 desc.status.fEOP = false;
     2300                pDesc->status.fEOP = false;
    21272301                e1kCsRxLeave(pState);
    2128                 e1kStoreRxFragment(pState, &desc, ptr, pState->u16RxBSize);
     2302                e1kStoreRxFragment(pState, pDesc, ptr, pState->u16RxBSize);
    21292303                rc = e1kCsRxEnter(pState, VERR_SEM_BUSY);
    21302304                if (RT_UNLIKELY(rc != VINF_SUCCESS))
     
    21352309            else
    21362310            {
    2137                 desc.status.fEOP = true;
     2311                pDesc->status.fEOP = true;
    21382312                e1kCsRxLeave(pState);
    2139                 e1kStoreRxFragment(pState, &desc, ptr, cb);
     2313                e1kStoreRxFragment(pState, pDesc, ptr, cb);
     2314#ifdef E1K_WITH_RXD_CACHE
     2315                rc = e1kCsRxEnter(pState, VERR_SEM_BUSY);
     2316                if (RT_UNLIKELY(rc != VINF_SUCCESS))
     2317                    return rc;
     2318                cb = 0;
     2319#else /* !E1K_WITH_RXD_CACHE */
    21402320                pState->led.Actual.s.fReading = 0;
    21412321                return VINF_SUCCESS;
     2322#endif /* !E1K_WITH_RXD_CACHE */
    21422323            }
    2143             /* Note: RDH is advanced by e1kStoreRxFragment! */
    2144         }
     2324            /*
     2325             * Note: RDH is advanced by e1kStoreRxFragment if E1K_WITH_RXD_CACHE
     2326             * is not defined.
     2327             */
     2328        }
     2329#ifndef E1K_WITH_RXD_CACHE
    21452330        else
    21462331        {
    2147             desc.status.fDD = true;
    2148             PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
    2149                                e1kDescAddr(RDBAH, RDBAL, RDH),
    2150                                            &desc, sizeof(desc));
    2151             e1kAdvanceRDH(pState);
    2152         }
     2332#endif /* !E1K_WITH_RXD_CACHE */
     2333        /* Write back the descriptor. */
     2334        pDesc->status.fDD = true;
     2335        PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
     2336                           e1kDescAddr(RDBAH, RDBAL, RDH),
     2337                           pDesc, sizeof(E1KRXDESC));
     2338        e1kAdvanceRDH(pState);
     2339        e1kPrintRDesc(pState, pDesc);
     2340#ifndef E1K_WITH_RXD_CACHE
     2341        }
     2342#endif /* !E1K_WITH_RXD_CACHE */
    21532343    }
    21542344
     
    21592349
    21602350    e1kCsRxLeave(pState);
     2351#ifdef E1K_WITH_RXD_CACHE
     2352    /* Complete packet has been stored -- it is time to let the guest know. */
     2353# ifdef E1K_USE_RX_TIMERS
     2354    if (RDTR)
     2355    {
     2356        /* Arm the timer to fire in RDTR usec (discard .024) */
     2357        e1kArmTimer(pState, pState->CTX_SUFF(pRIDTimer), RDTR);
     2358        /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
     2359        if (RADV != 0 && !TMTimerIsActive(pState->CTX_SUFF(pRADTimer)))
     2360            e1kArmTimer(pState, pState->CTX_SUFF(pRADTimer), RADV);
     2361    }
     2362    else
     2363    {
     2364# endif /* E1K_USE_RX_TIMERS */
     2365        /* 0 delay means immediate interrupt */
     2366        E1K_INC_ISTAT_CNT(pState->uStatIntRx);
     2367        e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_RXT0);
     2368# ifdef E1K_USE_RX_TIMERS
     2369    }
     2370# endif /* E1K_USE_RX_TIMERS */
     2371#endif /* E1K_WITH_RXD_CACHE */
    21612372
    21622373    return VINF_SUCCESS;
     
    26982909        E1kLog(("%s e1kRegWriteRDT\n",  INSTANCE(pState)));
    26992910        rc = e1kRegWriteDefault(pState, offset, index, value);
     2911#ifdef E1K_WITH_RXD_CACHE
     2912        /*
     2913         * We need to fetch descriptors now as RDT may go whole circle
     2914         * before we attempt to store a received packet. For example,
     2915         * Intel's DOS drivers use 2 (!) RX descriptors with the total ring
     2916         * size being only 8 descriptors! Note that we fetch descriptors
     2917         * only when the cache is empty to reduce the number of memory reads
     2918         * in case of frequent RDT writes. Don't fetch anything when the
     2919         * receiver is disabled either as RDH, RDT, RDLEN can be in some
     2920         * messed up state.
     2921         * Note that despite the cache may seem empty, meaning that there are
     2922         * no more available descriptors in it, it may still be used by RX
     2923         * thread which has not yet written the last descriptor back but has
     2924         * temporarily released the RX lock in order to write the packet body
     2925         * to descriptor's buffer. At this point we still going to do prefetch
     2926         * but it won't actually fetch anything if there are no unused slots in
     2927         * our "empty" cache (nRxDFetched==E1K_RXD_CACHE_SIZE). We must not
     2928         * reset the cache here even if it appears empty. It will be reset at
     2929         * a later point in e1kRxDGet().
     2930         */
     2931        if (e1kRxDIsCacheEmpty(pState) && (RCTL & RCTL_EN))
     2932            e1kRxDPrefetch(pState);
     2933#endif /* E1K_WITH_RXD_CACHE */
    27002934        e1kCsRxLeave(pState);
    27012935        if (RT_SUCCESS(rc))
     
    31723406    if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
    31733407    {
    3174         Assert(pState->cbTxAlloc != 0);
    31753408        if (pState->cbTxAlloc == 0)
    3176             return VERR_NET_IO_ERROR;
     3409        {
     3410            /* Zero packet, no need for the buffer */
     3411            return VINF_SUCCESS;
     3412        }
    31773413
    31783414        PPDMINETWORKUP pDrv = pState->CTX_SUFF(pDrv);
     
    32573493DECLINLINE(unsigned) e1kTxDLoadMore(E1KSTATE* pState)
    32583494{
     3495    Assert(pState->iTxDCurrent == 0);
    32593496    /* We've already loaded pState->nTxDFetched descriptors past TDH. */
    32603497    unsigned nDescsAvailable    = e1kGetTxLen(pState) - pState->nTxDFetched;
     
    42614498        case E1K_DTYP_DATA:
    42624499        {
    4263             if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
    4264             {
    4265                 E1kLog2(("% Empty data descriptor, skipped.\n", INSTANCE(pState)));
    4266                 /** @todo Same as legacy when !TSE. See below. */
    4267                 break;
    4268             }
    42694500            STAM_COUNTER_INC(pDesc->data.cmd.fTSE?
    42704501                             &pState->StatTxDescTSEData:
    42714502                             &pState->StatTxDescData);
    42724503            E1K_INC_ISTAT_CNT(pState->uStatDescDat);
    4273 
    4274             /*
    4275              * Add the descriptor data to the frame.  If the frame is complete,
    4276              * transmit it and reset the u16TxPktLen field.
    4277              */
    4278             if (e1kXmitIsGsoBuf(pState->CTX_SUFF(pTxSg)))
     4504            STAM_PROFILE_ADV_START(&pState->CTX_SUFF_Z(StatTransmit), a);
     4505            if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
    42794506            {
    4280                 STAM_COUNTER_INC(&pState->StatTxPathGSO);
    4281                 bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
    4282                 if (pDesc->data.cmd.fEOP)
     4507                E1kLog2(("% Empty data descriptor, skipped.\n", INSTANCE(pState)));
     4508            }
     4509            else
     4510            {
     4511                /*
     4512                 * Add the descriptor data to the frame.  If the frame is complete,
     4513                 * transmit it and reset the u16TxPktLen field.
     4514                 */
     4515                if (e1kXmitIsGsoBuf(pState->CTX_SUFF(pTxSg)))
    42834516                {
    4284                     if (   fRc
    4285                         && pState->CTX_SUFF(pTxSg)
    4286                         && pState->CTX_SUFF(pTxSg)->cbUsed == (size_t)pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN)
     4517                    STAM_COUNTER_INC(&pState->StatTxPathGSO);
     4518                    bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
     4519                    if (pDesc->data.cmd.fEOP)
    42874520                    {
     4521                        if (   fRc
     4522                            && pState->CTX_SUFF(pTxSg)
     4523                            && pState->CTX_SUFF(pTxSg)->cbUsed == (size_t)pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN)
     4524                        {
     4525                            e1kTransmitFrame(pState, fOnWorkerThread);
     4526                            E1K_INC_CNT32(TSCTC);
     4527                        }
     4528                        else
     4529                        {
     4530                            if (fRc)
     4531                                E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , INSTANCE(pState),
     4532                                        pState->CTX_SUFF(pTxSg), pState->CTX_SUFF(pTxSg) ? pState->CTX_SUFF(pTxSg)->cbUsed : 0,
     4533                                        pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN));
     4534                            e1kXmitFreeBuf(pState);
     4535                            E1K_INC_CNT32(TSCTFC);
     4536                        }
     4537                        pState->u16TxPktLen = 0;
     4538                    }
     4539                }
     4540                else if (!pDesc->data.cmd.fTSE)
     4541                {
     4542                    STAM_COUNTER_INC(&pState->StatTxPathRegular);
     4543                    bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
     4544                    if (pDesc->data.cmd.fEOP)
     4545                    {
     4546                        if (fRc && pState->CTX_SUFF(pTxSg))
     4547                        {
     4548                            Assert(pState->CTX_SUFF(pTxSg)->cSegs == 1);
     4549                            if (pState->fIPcsum)
     4550                                e1kInsertChecksum(pState, (uint8_t *)pState->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pState->u16TxPktLen,
     4551                                                  pState->contextNormal.ip.u8CSO,
     4552                                                  pState->contextNormal.ip.u8CSS,
     4553                                                  pState->contextNormal.ip.u16CSE);
     4554                            if (pState->fTCPcsum)
     4555                                e1kInsertChecksum(pState, (uint8_t *)pState->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pState->u16TxPktLen,
     4556                                                  pState->contextNormal.tu.u8CSO,
     4557                                                  pState->contextNormal.tu.u8CSS,
     4558                                                  pState->contextNormal.tu.u16CSE);
     4559                            e1kTransmitFrame(pState, fOnWorkerThread);
     4560                        }
     4561                        else
     4562                            e1kXmitFreeBuf(pState);
     4563                        pState->u16TxPktLen = 0;
     4564                    }
     4565                }
     4566                else
     4567                {
     4568                    STAM_COUNTER_INC(&pState->StatTxPathFallback);
     4569                    rc = e1kFallbackAddToFrame(pState, pDesc, fOnWorkerThread);
     4570                }
     4571            }
     4572            e1kDescReport(pState, pDesc, addr);
     4573            STAM_PROFILE_ADV_STOP(&pState->CTX_SUFF_Z(StatTransmit), a);
     4574            break;
     4575        }
     4576
     4577        case E1K_DTYP_LEGACY:
     4578            STAM_COUNTER_INC(&pState->StatTxDescLegacy);
     4579            STAM_PROFILE_ADV_START(&pState->CTX_SUFF_Z(StatTransmit), a);
     4580            if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
     4581            {
     4582                E1kLog(("%s Empty legacy descriptor, skipped.\n", INSTANCE(pState)));
     4583            }
     4584            else
     4585            {
     4586                /* Add fragment to frame. */
     4587                if (e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
     4588                {
     4589                    E1K_INC_ISTAT_CNT(pState->uStatDescLeg);
     4590
     4591                    /* Last fragment: Transmit and reset the packet storage counter.  */
     4592                    if (pDesc->legacy.cmd.fEOP)
     4593                    {
     4594                        if (pDesc->legacy.cmd.fIC)
     4595                        {
     4596                            e1kInsertChecksum(pState,
     4597                                              (uint8_t *)pState->CTX_SUFF(pTxSg)->aSegs[0].pvSeg,
     4598                                              pState->u16TxPktLen,
     4599                                              pDesc->legacy.cmd.u8CSO,
     4600                                              pDesc->legacy.dw3.u8CSS,
     4601                                              0);
     4602                        }
    42884603                        e1kTransmitFrame(pState, fOnWorkerThread);
    4289                         E1K_INC_CNT32(TSCTC);
     4604                        pState->u16TxPktLen = 0;
    42904605                    }
    4291                     else
    4292                     {
    4293                         if (fRc)
    4294                            E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , INSTANCE(pState),
    4295                                    pState->CTX_SUFF(pTxSg), pState->CTX_SUFF(pTxSg) ? pState->CTX_SUFF(pTxSg)->cbUsed : 0,
    4296                                    pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN));
    4297                         e1kXmitFreeBuf(pState);
    4298                         E1K_INC_CNT32(TSCTFC);
    4299                     }
     4606                }
     4607                /* Last fragment + failure: free the buffer and reset the storage counter. */
     4608                else if (pDesc->legacy.cmd.fEOP)
     4609                {
     4610                    e1kXmitFreeBuf(pState);
    43004611                    pState->u16TxPktLen = 0;
    43014612                }
    43024613            }
    4303             else if (!pDesc->data.cmd.fTSE)
    4304             {
    4305                 STAM_COUNTER_INC(&pState->StatTxPathRegular);
    4306                 bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
    4307                 if (pDesc->data.cmd.fEOP)
    4308                 {
    4309                     if (fRc && pState->CTX_SUFF(pTxSg))
    4310                     {
    4311                         Assert(pState->CTX_SUFF(pTxSg)->cSegs == 1);
    4312                         if (pState->fIPcsum)
    4313                             e1kInsertChecksum(pState, (uint8_t *)pState->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pState->u16TxPktLen,
    4314                                               pState->contextNormal.ip.u8CSO,
    4315                                               pState->contextNormal.ip.u8CSS,
    4316                                               pState->contextNormal.ip.u16CSE);
    4317                         if (pState->fTCPcsum)
    4318                             e1kInsertChecksum(pState, (uint8_t *)pState->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pState->u16TxPktLen,
    4319                                               pState->contextNormal.tu.u8CSO,
    4320                                               pState->contextNormal.tu.u8CSS,
    4321                                               pState->contextNormal.tu.u16CSE);
    4322                         e1kTransmitFrame(pState, fOnWorkerThread);
    4323                     }
    4324                     else
    4325                         e1kXmitFreeBuf(pState);
    4326                     pState->u16TxPktLen = 0;
    4327                 }
    4328             }
    4329             else
    4330             {
    4331                 STAM_COUNTER_INC(&pState->StatTxPathFallback);
    4332                 rc = e1kFallbackAddToFrame(pState, pDesc, fOnWorkerThread);
    4333             }
    4334 
    4335             e1kDescReport(pState, pDesc, addr);
    4336             STAM_PROFILE_ADV_STOP(&pState->CTX_SUFF_Z(StatTransmit), a);
    4337             break;
    4338         }
    4339 
    4340         case E1K_DTYP_LEGACY:
    4341             if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
    4342             {
    4343                 E1kLog(("%s Empty legacy descriptor, skipped.\n", INSTANCE(pState)));
    4344                 /** @todo 3.3.3, Length/Buffer Address: RS set -> write DD when processing. */
    4345                 break;
    4346             }
    4347             STAM_COUNTER_INC(&pState->StatTxDescLegacy);
    4348             STAM_PROFILE_ADV_START(&pState->CTX_SUFF_Z(StatTransmit), a);
    4349 
    4350             /* Add fragment to frame. */
    4351             if (e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
    4352             {
    4353                 E1K_INC_ISTAT_CNT(pState->uStatDescLeg);
    4354 
    4355                 /* Last fragment: Transmit and reset the packet storage counter.  */
    4356                 if (pDesc->legacy.cmd.fEOP)
    4357                 {
    4358                     if (pDesc->legacy.cmd.fIC)
    4359                     {
    4360                         e1kInsertChecksum(pState,
    4361                                           (uint8_t *)pState->CTX_SUFF(pTxSg)->aSegs[0].pvSeg,
    4362                                           pState->u16TxPktLen,
    4363                                           pDesc->legacy.cmd.u8CSO,
    4364                                           pDesc->legacy.dw3.u8CSS,
    4365                                           0);
    4366                     }
    4367                     e1kTransmitFrame(pState, fOnWorkerThread);
    4368                     pState->u16TxPktLen = 0;
    4369                 }
    4370             }
    4371             /* Last fragment + failure: free the buffer and reset the storage counter. */
    4372             else if (pDesc->legacy.cmd.fEOP)
    4373             {
    4374                 e1kXmitFreeBuf(pState);
    4375                 pState->u16TxPktLen = 0;
    4376             }
    4377 
    43784614            e1kDescReport(pState, pDesc, addr);
    43794615            STAM_PROFILE_ADV_STOP(&pState->CTX_SUFF_Z(StatTransmit), a);
     
    44414677                continue;
    44424678            case E1K_DTYP_LEGACY:
     4679                /* Skip empty descriptors. */
     4680                if (!pDesc->legacy.u64BufAddr || !pDesc->legacy.cmd.u16Length)
     4681                    break;
    44434682                cbPacket += pDesc->legacy.cmd.u16Length;
    44444683                pState->fGSO = false;
    44454684                break;
    44464685            case E1K_DTYP_DATA:
     4686                /* Skip empty descriptors. */
     4687                if (!pDesc->data.u64BufAddr || !pDesc->data.cmd.u20DTALEN)
     4688                    break;
    44474689                if (cbPacket == 0)
    44484690                {
     
    44964738    }
    44974739
     4740    if (cbPacket == 0 && pState->nTxDFetched - pState->iTxDCurrent > 0)
     4741    {
     4742        /* All descriptors were empty, we need to process them as a dummy packet */
     4743        LogFlow(("%s e1kLocateTxPacket: RET true cbTxAlloc=%d, zero packet!\n",
     4744                 INSTANCE(pState), pState->cbTxAlloc));
     4745        return true;
     4746    }
    44984747    LogFlow(("%s e1kLocateTxPacket: RET false cbTxAlloc=%d\n",
    44994748             INSTANCE(pState), pState->cbTxAlloc));
     
    55375786static int e1kCanReceive(E1KSTATE *pState)
    55385787{
     5788#ifndef E1K_WITH_RXD_CACHE
    55395789    size_t cb;
    55405790
     
    55665816    e1kCsRxLeave(pState);
    55675817    return cb > 0 ? VINF_SUCCESS : VERR_NET_NO_BUFFER_SPACE;
     5818#else /* E1K_WITH_RXD_CACHE */
     5819    int rc = VINF_SUCCESS;
     5820
     5821    if (RT_UNLIKELY(e1kCsRxEnter(pState, VERR_SEM_BUSY) != VINF_SUCCESS))
     5822        return VERR_NET_NO_BUFFER_SPACE;
     5823
     5824    if (RT_UNLIKELY(RDLEN == sizeof(E1KRXDESC)))
     5825    {
     5826        E1KRXDESC desc;
     5827        PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
     5828                          &desc, sizeof(desc));
     5829        if (desc.status.fDD)
     5830            rc = VERR_NET_NO_BUFFER_SPACE;
     5831    }
     5832    else if (e1kRxDIsCacheEmpty(pState) && RDH == RDT)
     5833    {
     5834        /* Cache is empty, so is the RX ring. */
     5835        rc = VERR_NET_NO_BUFFER_SPACE;
     5836    }
     5837    E1kLog2(("%s e1kCanReceive: at exit in_cache=%d RDH=%d RDT=%d RDLEN=%d"
     5838             " u16RxBSize=%d rc=%Rrc\n", INSTANCE(pState),
     5839             e1kRxDInCache(pState), RDH, RDT, RDLEN, pState->u16RxBSize, rc));
     5840
     5841    e1kCsRxLeave(pState);
     5842    return rc;
     5843#endif /* E1K_WITH_RXD_CACHE */
    55685844}
    55695845
     
    61926468        else
    61936469            pState->nTxDFetched = 0;
     6470        /*
     6471         * @todo: Perhaps we should not store TXD cache as the entries can be
     6472         * simply fetched again from guest's memory. Or can't they?
     6473         */
    61946474#endif /* E1K_WITH_TXD_CACHE */
     6475#ifdef E1K_WITH_RXD_CACHE
     6476        /*
     6477         * There is no point in storing the RX descriptor cache in the saved
     6478         * state, we just need to make sure it is empty.
     6479         */
     6480        pState->iRxDCurrent = pState->nRxDFetched = 0;
     6481#endif /* E1K_WITH_RXD_CACHE */
    61956482        /* derived state  */
    61966483        e1kSetupGsoCtx(&pState->GsoCtx, &pState->contextTSE);
     
    63746661    pState->fLocked      = false;
    63756662    pState->u64AckedAt   = 0;
    6376 #ifdef E1K_WITH_TXD_CACHE
    6377     int rc = e1kCsTxEnter(pState, VERR_SEM_BUSY);
    6378     if (RT_LIKELY(rc == VINF_SUCCESS))
    6379     {
    6380         pState->nTxDFetched  = 0;
    6381         pState->iTxDCurrent  = 0;
    6382         pState->fGSO         = false;
    6383         pState->cbTxAlloc    = 0;
    6384         e1kCsTxLeave(pState);
    6385     }
    6386 #endif /* E1K_WITH_TXD_CACHE */
    63876663    e1kHardReset(pState);
    63886664}
Note: See TracChangeset for help on using the changeset viewer.

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