VirtualBox

Changeset 41046 in vbox for trunk/src/VBox/Devices/Network


Ignore:
Timestamp:
Apr 24, 2012 12:38:07 PM (13 years ago)
Author:
vboxsync
Message:

E1000: Fixed fetching of incomplete packets. TX critical section (#5582)

File:
1 edited

Legend:

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

    r41034 r41046  
    8181 */
    8282//#define E1K_WITH_MSI
     83/*
     84 * E1K_WITH_TX_CS protects e1kXmitPending with a critical section.
     85 */
     86#define E1K_WITH_TX_CS 1
    8387/*
    8488 * E1K_WITH_TXD_CACHE causes E1000 to fetch multiple TX descriptors in a
     
    10101014    PDMCRITSECT cs;                  /**< Critical section - what is it protecting? */
    10111015    PDMCRITSECT csRx;                                     /**< RX Critical section. */
    1012 //    PDMCRITSECT csTx;                                     /**< TX Critical section. */
     1016#ifdef E1K_WITH_TX_CS
     1017    PDMCRITSECT csTx;                                     /**< TX Critical section. */
     1018#endif /* E1K_WITH_TX_CS */
    10131019    /** Base address of memory-mapped registers. */
    10141020    RTGCPHYS    addrMMReg;
     
    14881494#define e1kCsRxLeave(ps) PDMCritSectLeave(&ps->csRx)
    14891495
     1496#ifndef E1K_WITH_TX_CS
    14901497#define e1kCsTxEnter(ps, rc) VINF_SUCCESS
    14911498#define e1kCsTxLeave(ps) do { } while (0)
    1492 //# define e1kCsTxEnter(ps, rc) PDMCritSectEnter(&ps->csTx, rc)
    1493 //# define e1kCsTxLeave(ps) PDMCritSectLeave(&ps->csTx)
     1499#else /* E1K_WITH_TX_CS */
     1500# define e1kCsTxEnter(ps, rc) PDMCritSectEnter(&ps->csTx, rc)
     1501# define e1kCsTxLeave(ps) PDMCritSectLeave(&ps->csTx)
     1502#endif /* E1K_WITH_TX_CS */
    14941503
    14951504#ifdef IN_RING3
     
    32243233DECLINLINE(unsigned) e1kTxDLoadMore(E1KSTATE* pState)
    32253234{
    3226     unsigned nDescsAvailable = e1kGetTxLen(pState);
    3227     unsigned nDescsToFetch = RT_MIN(nDescsAvailable, E1K_TXD_CACHE_SIZE - pState->nTxDFetched);
    3228     /*
    3229      * It is safe to use TDLEN and TDH in the following expression since TDLEN
    3230      * is set during init and never changes after that, and TDH is advanced in
    3231      * the loop we are being called from.
    3232      */
    3233     unsigned nDescsInSingleRead = RT_MIN(nDescsToFetch, TDLEN / sizeof(E1KTXDESC) - TDH);
     3235    /* We've already loaded pState->nTxDFetched descriptors past TDH. */
     3236    unsigned nDescsAvailable    = e1kGetTxLen(pState) - pState->nTxDFetched;
     3237    unsigned nDescsToFetch      = RT_MIN(nDescsAvailable, E1K_TXD_CACHE_SIZE - pState->nTxDFetched);
     3238    unsigned nDescsTotal        = TDLEN / sizeof(E1KTXDESC);
     3239    unsigned nFirstNotLoaded    = (TDH + pState->nTxDFetched) % nDescsTotal;
     3240    unsigned nDescsInSingleRead = RT_MIN(nDescsToFetch, nDescsTotal - nFirstNotLoaded);
     3241    E1kLog3(("%s e1kTxDLoadMore: nDescsAvailable=%u nDescsToFetch=%u "
     3242             "nDescsTotal=%u nFirstNotLoaded=0x%x nDescsInSingleRead=%u\n",
     3243             INSTANCE(pState), nDescsAvailable, nDescsToFetch, nDescsTotal,
     3244             nFirstNotLoaded, nDescsInSingleRead));
    32343245    if (nDescsToFetch == 0)
    32353246        return 0;
    32363247    E1KTXDESC* pFirstEmptyDesc = &pState->aTxDescriptors[pState->nTxDFetched];
    32373248    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    3238                       ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(E1KTXDESC),
     3249                      ((uint64_t)TDBAH << 32) + TDBAL + nFirstNotLoaded * sizeof(E1KTXDESC),
    32393250                      pFirstEmptyDesc, nDescsInSingleRead * sizeof(E1KTXDESC));
    3240     E1kLog3(("%s Fetched %u TX descriptors at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
    3241              INSTANCE(pState), nDescsInSingleRead, TDBAH, TDBAL + TDH * sizeof(E1KTXDESC), TDLEN, TDH, TDT));
     3251    E1kLog3(("%s Fetched %u TX descriptors at %08x%08x(0x%x), TDLEN=%08x, TDH=%08x, TDT=%08x\n",
     3252             INSTANCE(pState), nDescsInSingleRead,
     3253             TDBAH, TDBAL + TDH * sizeof(E1KTXDESC),
     3254             nFirstNotLoaded, TDLEN, TDH, TDT));
    32423255    if (nDescsToFetch > nDescsInSingleRead)
    32433256    {
     
    32463259                          pFirstEmptyDesc + nDescsInSingleRead,
    32473260                          (nDescsToFetch - nDescsInSingleRead) * sizeof(E1KTXDESC));
    3248         E1kLog3(("%s Fetched %u TX descriptors at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
     3261        E1kLog3(("%s Fetched %u TX descriptors at %08x%08x\n",
    32493262                 INSTANCE(pState), nDescsToFetch - nDescsInSingleRead,
    3250                  TDBAH, TDBAL, TDLEN, TDH, TDT));
     3263                 TDBAH, TDBAL));
    32513264    }
    32523265    pState->nTxDFetched += nDescsToFetch;
     
    45134526    int rc = VINF_SUCCESS;
    45144527
     4528    /* Check if transmitter is enabled. */
     4529    if (!(TCTL & TCTL_EN))
     4530        return VINF_SUCCESS;
    45154531    /*
    45164532     * Grab the xmit lock of the driver as well as the E1K device state.
     
    45234539            return rc;
    45244540    }
    4525     //rc = e1kCsTxEnter(pState, VERR_SEM_BUSY);
     4541    rc = e1kCsTxEnter(pState, VERR_SEM_BUSY);
    45264542    if (RT_LIKELY(rc == VINF_SUCCESS))
    45274543    {
     
    45564572        /// @todo: uncomment: pState->uStatIntTXQE++;
    45574573        /// @todo: uncomment: e1kRaiseInterrupt(pState, ICR_TXQE);
    4558         //e1kCsTxLeave(pState);
     4574        e1kCsTxLeave(pState);
    45594575    }
    45604576
     
    45854601    int rc = VINF_SUCCESS;
    45864602
     4603    /* Check if transmitter is enabled. */
     4604    if (!(TCTL & TCTL_EN))
     4605        return VINF_SUCCESS;
    45874606    /*
    45884607     * Grab the xmit lock of the driver as well as the E1K device state.
     
    46004619     * Note! Do not process descriptors in locked state
    46014620     */
    4602     STAM_PROFILE_ADV_START(&pState->CTX_SUFF_Z(StatTransmit), a);
    4603     while (!pState->fLocked && e1kTxDLazyLoad(pState))
    4604     {
    4605         while (e1kLocateTxPacket(pState))
    4606         {
    4607             /* Found a complete packet, allocate it. */
    4608             rc = e1kXmitAllocBuf(pState, pState->fGSO);
    4609             /* If we're out of bandwidth we'll come back later. */
    4610             if (RT_FAILURE(rc))
     4621    rc = e1kCsTxEnter(pState, VERR_SEM_BUSY);
     4622    if (RT_LIKELY(rc == VINF_SUCCESS))
     4623    {
     4624        STAM_PROFILE_ADV_START(&pState->CTX_SUFF_Z(StatTransmit), a);
     4625        /*
     4626         * fIncomplete is set whenever we try to fetch additional descriptors
     4627         * for an incomplete packet. If fail to locate a complete packet on
     4628         * the next iteration we need to reset the cache or we risk to get
     4629         * stuck in this loop forever.
     4630         */
     4631        bool fIncomplete = false;
     4632        while (!pState->fLocked && e1kTxDLazyLoad(pState))
     4633        {
     4634            while (e1kLocateTxPacket(pState))
     4635            {
     4636                fIncomplete = false;
     4637                /* Found a complete packet, allocate it. */
     4638                rc = e1kXmitAllocBuf(pState, pState->fGSO);
     4639                /* If we're out of bandwidth we'll come back later. */
     4640                if (RT_FAILURE(rc))
     4641                    goto out;
     4642                /* Copy the packet to allocated buffer and send it. */
     4643                rc = e1kXmitPacket(pState, fOnWorkerThread);
     4644                /* If we're out of bandwidth we'll come back later. */
     4645                if (RT_FAILURE(rc))
     4646                    goto out;
     4647            }
     4648            uint8_t u8Remain = pState->nTxDFetched - pState->iTxDCurrent;
     4649            if (RT_UNLIKELY(fIncomplete))
     4650            {
     4651                /*
     4652                 * The descriptor cache is full, but we were unable to find
     4653                 * a complete packet in it. Drop the cache and hope that
     4654                 * the guest driver can recover from network card error.
     4655                 */
     4656                LogRel(("%s No complete packets in%s TxD cache! "
     4657                      "Fetched=%d, current=%d, TX len=%d.\n",
     4658                      INSTANCE(pState),
     4659                      u8Remain == E1K_TXD_CACHE_SIZE ? " full" : "",
     4660                      pState->nTxDFetched, pState->iTxDCurrent,
     4661                      e1kGetTxLen(pState)));
     4662                Log4(("%s No complete packets in%s TxD cache! "
     4663                      "Fetched=%d, current=%d, TX len=%d. Dump follows:\n",
     4664                      INSTANCE(pState),
     4665                      u8Remain == E1K_TXD_CACHE_SIZE ? " full" : "",
     4666                      pState->nTxDFetched, pState->iTxDCurrent,
     4667                      e1kGetTxLen(pState)));
     4668                e1kDumpTxDCache(pState);
     4669                pState->iTxDCurrent = pState->nTxDFetched = 0;
     4670                rc = VERR_NET_IO_ERROR;
    46114671                goto out;
    4612             /* Copy the packet to allocated buffer and send it. */
    4613             rc = e1kXmitPacket(pState, fOnWorkerThread);
    4614             /* If we're out of bandwidth we'll come back later. */
    4615             if (RT_FAILURE(rc))
    4616                 goto out;
    4617         }
    4618         uint8_t u8Remain = pState->nTxDFetched - pState->iTxDCurrent;
    4619         if (RT_UNLIKELY(u8Remain == E1K_TXD_CACHE_SIZE))
    4620         {
    4621             /*
    4622              * The descriptor cache is full, but we were unable to find
    4623              * a complete packet in it. Drop the cache and hope that
    4624              * the guest driver can recover from network card error.
    4625              */
    4626             Log4(("%s No complete packets in full TxD cache! "
    4627                   "Fetched=%d, TX len=%d. Dump follows:\n",
    4628                   INSTANCE(pState), pState->nTxDFetched, e1kGetTxLen(pState)));
    4629             e1kDumpTxDCache(pState);
    4630             pState->nTxDFetched = 0;
    4631             rc = VERR_NET_IO_ERROR;
    4632             goto out;
    4633         }
    4634         if (u8Remain > 0)
    4635         {
    4636             /*
    4637              * A packet was partially fetched. Move incomplete packet to
    4638              * the beginning of cache buffer, then load more descriptors.
    4639              */
    4640             memmove(pState->aTxDescriptors,
    4641                     &pState->aTxDescriptors[pState->iTxDCurrent],
    4642                     u8Remain * sizeof(E1KTXDESC));
    4643             pState->nTxDFetched = u8Remain;
    4644             e1kTxDLoadMore(pState);
    4645         }
    4646         else
    4647             pState->nTxDFetched = 0;
    4648         pState->iTxDCurrent = 0;
    4649     }
    4650     if (!pState->fLocked && GET_BITS(TXDCTL, LWTHRESH) == 0)
    4651     {
    4652         E1kLog2(("%s Out of transmit descriptors, raise ICR.TXD_LOW\n",
    4653                  INSTANCE(pState)));
    4654         e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_TXD_LOW);
    4655     }
    4656 
     4672            }
     4673            if (u8Remain > 0)
     4674            {
     4675                Log4(("%s Incomplete packet at %d. Already fetched %d, "
     4676                      "%d more are available\n",
     4677                      INSTANCE(pState), pState->iTxDCurrent, u8Remain,
     4678                      e1kGetTxLen(pState) - u8Remain));
     4679                     
     4680                /*
     4681                 * A packet was partially fetched. Move incomplete packet to
     4682                 * the beginning of cache buffer, then load more descriptors.
     4683                 */
     4684                memmove(pState->aTxDescriptors,
     4685                        &pState->aTxDescriptors[pState->iTxDCurrent],
     4686                        u8Remain * sizeof(E1KTXDESC));
     4687                pState->nTxDFetched = u8Remain;
     4688                e1kTxDLoadMore(pState);
     4689                fIncomplete = true;
     4690            }
     4691            else
     4692                pState->nTxDFetched = 0;
     4693            pState->iTxDCurrent = 0;
     4694        }
     4695        if (!pState->fLocked && GET_BITS(TXDCTL, LWTHRESH) == 0)
     4696        {
     4697            E1kLog2(("%s Out of transmit descriptors, raise ICR.TXD_LOW\n",
     4698                     INSTANCE(pState)));
     4699            e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_TXD_LOW);
     4700        }
    46574701out:
    4658     STAM_PROFILE_ADV_STOP(&pState->CTX_SUFF_Z(StatTransmit), a);
    4659 
    4660     /// @todo: uncomment: pState->uStatIntTXQE++;
    4661     /// @todo: uncomment: e1kRaiseInterrupt(pState, ICR_TXQE);
     4702        STAM_PROFILE_ADV_STOP(&pState->CTX_SUFF_Z(StatTransmit), a);
     4703
     4704        /// @todo: uncomment: pState->uStatIntTXQE++;
     4705        /// @todo: uncomment: e1kRaiseInterrupt(pState, ICR_TXQE);
     4706
     4707        e1kCsTxLeave(pState);
     4708    }
     4709
    46624710
    46634711    /*
     
    47274775static int e1kRegWriteTDT(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
    47284776{
    4729     int rc = e1kCsTxEnter(pState, VINF_IOM_R3_MMIO_WRITE);
    4730     if (RT_UNLIKELY(rc != VINF_SUCCESS))
    4731         return rc;
    4732     rc = e1kRegWriteDefault(pState, offset, index, value);
     4777    int rc = e1kRegWriteDefault(pState, offset, index, value);
    47334778
    47344779    /* All descriptors starting with head and not including tail belong to us. */
     
    47434788        E1kLog(("%s e1kRegWriteTDT: %d descriptors to process\n",
    47444789                 INSTANCE(pState), e1kGetTxLen(pState)));
    4745         e1kCsTxLeave(pState);
    47464790
    47474791        /* Transmit pending packets if possible, defer it if we cannot do it
     
    47604804            if (rc == VERR_TRY_AGAIN)
    47614805                rc = VINF_SUCCESS;
     4806            else if (rc == VERR_SEM_BUSY)
     4807                rc = VINF_IOM_R3_IOPORT_WRITE;
    47624808            AssertRC(rc);
    47634809        }
    47644810    }
    4765     else
    4766         e1kCsTxLeave(pState);
    47674811
    47684812    return rc;
     
    62986342    pState->u64AckedAt   = 0;
    62996343#ifdef E1K_WITH_TXD_CACHE
    6300     pState->nTxDFetched  = 0;
    6301     pState->iTxDCurrent  = 0;
    6302     pState->fGSO         = false;
    6303     pState->cbTxAlloc    = 0;
     6344    int rc = e1kCsTxEnter(pState, VERR_SEM_BUSY);
     6345    if (RT_LIKELY(rc == VINF_SUCCESS))
     6346    {
     6347        pState->nTxDFetched  = 0;
     6348        pState->iTxDCurrent  = 0;
     6349        pState->fGSO         = false;
     6350        pState->cbTxAlloc    = 0;
     6351        e1kCsTxLeave(pState);
     6352    }
    63046353#endif /* E1K_WITH_TXD_CACHE */
    63056354    e1kHardReset(pState);
     
    63756424            pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
    63766425        }
     6426#ifdef E1K_WITH_TX_CS
     6427        PDMR3CritSectDelete(&pState->csTx);
     6428#endif /* E1K_WITH_TX_CS */
    63776429        PDMR3CritSectDelete(&pState->csRx);
    6378         //PDMR3CritSectDelete(&pState->csTx);
    63796430        PDMR3CritSectDelete(&pState->cs);
    63806431    }
     
    67216772    if (RT_FAILURE(rc))
    67226773        return rc;
     6774#ifdef E1K_WITH_TX_CS
     6775    rc = PDMDevHlpCritSectInit(pDevIns, &pState->csTx, RT_SRC_POS, "%sTX", pState->szInstance);
     6776    if (RT_FAILURE(rc))
     6777        return rc;
     6778#endif /* E1K_WITH_TX_CS */
    67236779
    67246780    /* Set PCI config registers */
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