VirtualBox

Changeset 87863 in vbox


Ignore:
Timestamp:
Feb 24, 2021 5:25:23 PM (4 years ago)
Author:
vboxsync
Message:

Audio/HDA: Experimental change to lower more DPC calls within the guest by avoiding re-scheduling to R3 when the guest acknowledges an interrupt via hdaRegWriteSDSTS(). Only tested on Ubuntu 20.10, Win7 + Win10 20H2 so far. ticketoem2ref:36

Location:
trunk/src/VBox/Devices/Audio
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevHDA.cpp

    r87861 r87863  
    11521152}
    11531153
    1154 #ifdef IN_RING3
    1155 /**
    1156  * Returns the current maximum value the wall clock counter can be set to.
    1157  *
    1158  * This maximum value depends on all currently handled HDA streams and their own current timing.
    1159  *
    1160  * @return  Current maximum value the wall clock counter can be set to.
    1161  * @param   pThis               The shared HDA device state.
    1162  * @param   pThisCC             The ring-3 HDA device state.
    1163  *
    1164  * @remark  Does not actually set the wall clock counter.
    1165  *
    1166  * @todo r=bird: This function is in the wrong file.
    1167  */
    1168 static uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC)
    1169 {
    1170     const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
    1171     const uint64_t u64FrontAbsWalClk  = pThisCC->SinkFront.pStreamShared
    1172                                       ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period)  : 0;
    1173 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    1174 #  error "Implement me!"
    1175 # endif
    1176     const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared
    1177                                       ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;
    1178 # ifdef VBOX_WITH_HDA_MIC_IN
    1179     const uint64_t u64MicInAbsWalClk  = pThisCC->SinkMicIn.pStreamShared
    1180                                       ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period)  : 0;
    1181 # endif
    1182 
    1183     uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);
    1184 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    1185 #  error "Implement me!"
    1186 # endif
    1187     u64WalClkNew          = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);
    1188 # ifdef VBOX_WITH_HDA_MIC_IN
    1189     u64WalClkNew          = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);
    1190 # endif
    1191 
    1192     Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n",
    1193               u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew));
    1194 
    1195     return u64WalClkNew;
    1196 }
    1197 #endif /* IN_RING3 */
    1198 
    11991154static VBOXSTRICTRC hdaRegReadWALCLK(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
    12001155{
     
    15221477static VBOXSTRICTRC hdaRegWriteSDSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
    15231478{
    1524 #ifdef IN_RING3
    1525     const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, STS, iReg);
    1526     AssertReturn(uSD < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
    1527     PHDASTATER3 const  pThisCC       = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
    1528     PHDASTREAM const   pStreamShared = &pThis->aStreams[uSD];
    1529 
    1530     /* We only need to take the virtual-sync lock if we want to call
    1531        PDMDevHlpTimerGet or hdaR3TimerSet later.  Only precondition for that
    1532        is that we've got a non-zero ticks-per-transfer value. */
    1533     uint64_t const cTransferTicks = pStreamShared->State.cTransferTicks;
    1534     if (cTransferTicks)
    1535     {
    1536         DEVHDA_UNLOCK(pDevIns, pThis);
    1537         DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStreamShared, VINF_IOM_R3_MMIO_WRITE);
    1538     }
    1539 
    1540     hdaStreamLock(pStreamShared);
    1541 
    15421479    uint32_t v = HDA_REG_IND(pThis, iReg);
    15431480
     
    15451482    HDA_REG_IND(pThis, iReg) &= ~(u32Value & v);
    15461483
    1547 /** @todo r=bird: Check if we couldn't this stuff involving hdaR3StreamPeriodLock
    1548  *  and IRQs after PDMDevHlpTimerUnlockClock. */
    1549 
    1550     /*
    1551      * ...
    1552      */
    1553     /* Some guests tend to write SDnSTS even if the stream is not running.
    1554      * So make sure to check if the RUN bit is set first. */
    1555     const bool fRunning = pStreamShared->State.fRunning;
    1556 
    1557     Log3Func(("[SD%RU8] fRunning=%RTbool %R[sdsts]\n", uSD, fRunning, v));
    1558 
    1559     PHDASTREAMPERIOD pPeriod = &pStreamShared->State.Period;
    1560     if (hdaR3StreamPeriodNeedsInterrupt(pPeriod))
    1561         hdaR3StreamPeriodReleaseInterrupt(pPeriod);
    1562     if (hdaR3StreamPeriodIsComplete(pPeriod))
    1563     {
    1564         /* Make sure to try to update the WALCLK register if a period is complete.
    1565          * Use the maximum WALCLK value all (active) streams agree to. */
    1566         const uint64_t uWalClkMax = hdaR3WalClkGetMax(pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3));
    1567         if (uWalClkMax > hdaWalClkGetCurrent(pThis))
    1568             hdaR3WalClkSet(pThis, pThisCC, uWalClkMax, false /* fForce */);
    1569 
    1570         hdaR3StreamPeriodEnd(pPeriod);
    1571 
    1572         if (fRunning)
    1573             hdaR3StreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis) /* Use current wall clock time */);
    1574     }
    1575 
    15761484    HDA_PROCESS_INTERRUPT(pDevIns, pThis);
    15771485
    1578     /*
    1579      * ...
    1580      */
    1581     uint64_t cTicksToNext = pStreamShared->State.cTransferTicks;
    1582     if (cTicksToNext) /* Only do any calculations if the stream currently is set up for transfers. */
    1583     {
    1584         const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
    1585         if (!pStreamShared->State.tsTransferLast)
    1586             pStreamShared->State.tsTransferLast = tsNow;
    1587         Assert(tsNow >= pStreamShared->State.tsTransferLast);
    1588 
    1589         const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast;
    1590 
    1591         Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksToNext=%RU64\n",
    1592                   uSD, cTicksElapsed, cTicksToNext));
    1593 
    1594         if (cTicksElapsed <= cTicksToNext)
    1595             cTicksToNext = cTicksToNext - cTicksElapsed;
    1596         else /* Catch up. */
    1597         {
    1598             Log3Func(("[SD%RU8] Warning: Lagging behind (%RU64 ticks elapsed, maximum allowed is %RU64)\n",
    1599                      uSD, cTicksElapsed, cTicksToNext));
    1600 
    1601             LogRelMax2(128, ("HDA: Stream #%RU8 interrupt lagging behind (expected %RU64us, got %RU64us, %RU8 pending interrupts), trying to catch up ...\n",
    1602                              uSD, cTicksToNext / 1000,  cTicksElapsed / 1000, pStreamShared->State.cTransferPendingInterrupts));
    1603 
    1604             cTicksToNext = pStreamShared->State.cbTransferSize * pStreamShared->State.cTicksPerByte;
    1605         }
    1606 
    1607         Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", uSD, cTicksToNext));
    1608 
    1609         /* Reset processed data counter. */
    1610         pStreamShared->State.tsTransferNext = tsNow + cTicksToNext;
    1611 
    1612         /* Only re-arm the timer if there were pending transfer interrupts left
    1613          *  -- it could happen that we land in here if a guest writes to SDnSTS
    1614          * unconditionally. */
    1615         if (pStreamShared->State.cTransferPendingInterrupts)
    1616         {
    1617             pStreamShared->State.cTransferPendingInterrupts--;
    1618 
    1619             /* Re-arm the timer. */
    1620             LogFunc(("[SD%RU8] Timer set\n", uSD));
    1621             hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext,
    1622                           true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/);
    1623         }
    1624     }
    1625 
    1626     if (cTransferTicks)
    1627         PDMDevHlpTimerUnlockClock(pDevIns, pStreamShared->hTimer); /* Caller will unlock pThis->CritSect. */
    1628     hdaStreamUnlock(pStreamShared);
    16291486    return VINF_SUCCESS;
    1630 #else  /* !IN_RING3 */
    1631     RT_NOREF(pDevIns, pThis, iReg, u32Value);
    1632     return VINF_IOM_R3_MMIO_WRITE;
    1633 #endif /* !IN_RING3 */
    16341487}
    16351488
     
    28122665        const bool     fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow);
    28132666
    2814         Log3Func(("[SD%RU8] fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", uSD, fSinkActive, fTimerScheduled));
    2815 
    2816         if (!fTimerScheduled)
    2817         {
    2818             if (!pStreamShared->State.tsTransferLast) /* Never did a transfer before? Initialize with current time. */
    2819                 pStreamShared->State.tsTransferLast = tsNow;
    2820 
    2821             Assert(tsNow >= pStreamShared->State.tsTransferLast);
    2822 
    2823             /* How many ticks have passed since the last transfer? */
    2824             const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast;
    2825 
    2826             uint64_t cTicksToNext;
    2827             if (cTicksElapsed == 0) /* We just ran in the same timing slot? */
    2828             {
    2829                 /* Schedule a transfer at the next regular timing slot. */
    2830                 cTicksToNext = pStreamShared->State.cTransferTicks;
    2831             }
    2832             else
    2833             {
    2834                 /* Some time since the last transfer has passed already; take this into account. */
    2835                 if (pStreamShared->State.cTransferTicks >= cTicksElapsed)
    2836                 {
    2837                     cTicksToNext = pStreamShared->State.cTransferTicks - cTicksElapsed;
    2838                 }
    2839                 else /* Catch up as soon as possible. */
    2840                     cTicksToNext = 0;
    2841             }
    2842 
    2843             Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferLast=%RU64, cTicksElapsed=%RU64 -> cTicksToNext=%RU64\n",
    2844                       uSD, tsNow, pStreamShared->State.tsTransferLast, cTicksElapsed, cTicksToNext));
    2845 
    2846             /* Note: cTicksToNext can be 0, which means we have to run *now*. */
    2847             hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext,
    2848                           true /*fForce*/, 0 /* tsNow */);
    2849         }
     2667        uint64_t tsTransferNext  = 0;
     2668        if (fTimerScheduled)
     2669        {
     2670            Assert(pStreamShared->State.tsTransferNext); /* Make sure that a new transfer timestamp is set. */
     2671            tsTransferNext = pStreamShared->State.tsTransferNext;
     2672        }
     2673        else /* Schedule at the precalculated rate. */
     2674            tsTransferNext = tsNow + pStreamShared->State.cTransferTicks;
     2675
     2676        Log3Func(("[SD%RU8] fSinksActive=%RTbool, fTimerScheduled=%RTbool, tsTransferNext=%RU64 (in %RU64)\n",
     2677                  uSD, fSinkActive, fTimerScheduled, tsTransferNext, tsTransferNext - tsNow));
     2678
     2679        /* Note: tsTransferNext can be 0, which means we have to run *now*. */
     2680        hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext,
     2681                      true /*fForce*/, tsNow);
    28502682    }
    28512683    else
  • trunk/src/VBox/Devices/Audio/DevHDACommon.cpp

    r87328 r87863  
    129129        return &pStream->State.Period;
    130130    return NULL;
     131}
     132
     133/**
     134 * Returns the current maximum value the wall clock counter can be set to.
     135 *
     136 * This maximum value depends on all currently handled HDA streams and their own current timing.
     137 *
     138 * @return  Current maximum value the wall clock counter can be set to.
     139 * @param   pThis               The shared HDA device state.
     140 * @param   pThisCC             The ring-3 HDA device state.
     141 *
     142 * @remark  Does not actually set the wall clock counter.
     143 *
     144 */
     145uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC)
     146{
     147    const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
     148    const uint64_t u64FrontAbsWalClk  = pThisCC->SinkFront.pStreamShared
     149                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period)  : 0;
     150# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
     151#  error "Implement me!"
     152# endif
     153    const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared
     154                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;
     155# ifdef VBOX_WITH_HDA_MIC_IN
     156    const uint64_t u64MicInAbsWalClk  = pThisCC->SinkMicIn.pStreamShared
     157                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period)  : 0;
     158# endif
     159
     160    uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);
     161# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
     162#  error "Implement me!"
     163# endif
     164    u64WalClkNew          = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);
     165# ifdef VBOX_WITH_HDA_MIC_IN
     166    u64WalClkNew          = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);
     167# endif
     168
     169    Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n",
     170              u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew));
     171
     172    return u64WalClkNew;
    131173}
    132174
  • trunk/src/VBox/Devices/Audio/DevHDACommon.h

    r87758 r87863  
    633633uint64_t      hdaWalClkGetCurrent(PHDASTATE pThis);
    634634#ifdef IN_RING3
     635uint64_t      hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC);
    635636bool          hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce);
    636637#endif
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r87836 r87863  
    694694     * Second, initialize the registers.
    695695     */
    696     HDA_STREAM_REG(pThis, STS,   uSD) = HDA_SDSTS_FIFORDY;
     696    /* See 6.2.33: Clear on reset. */
     697    HDA_STREAM_REG(pThis, STS,   uSD) = 0;
    697698    /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
    698699     * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
     
    11891190     */
    11901191    bool fInterruptSent = false;
     1192
     1193    /* Set the FIFORDY bit on the stream while doing the transfer. */
     1194    HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY;
    11911195
    11921196    while (cbLeft)
     
    14651469                    if (!fInterruptSent)
    14661470                    {
    1467                         pStreamShared->State.cTransferPendingInterrupts++;
     1471                        pStreamShared->State.cTransferPendingInterrupts = 1;
    14681472
    14691473                        AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32,
     
    15131517            break;
    15141518    }
     1519
     1520    /* Remove the FIFORDY bit again. */
     1521    HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY;
    15151522
    15161523    /* Sanity. */
     
    15441551         */
    15451552        const bool fWalClkSet = hdaR3WalClkSet(pThis, pThisCC,
    1546                                                  hdaWalClkGetCurrent(pThis)
    1547                                                + hdaR3StreamPeriodFramesToWalClk(pPeriod,
    1548                                                                                    cbProcessed
    1549                                                                                  / pStreamR3->State.Mapping.cbFrameSize),
     1553                                               RT_MIN(  hdaWalClkGetCurrent(pThis)
     1554                                                      + hdaR3StreamPeriodFramesToWalClk(pPeriod,
     1555                                                                                          cbProcessed
     1556                                                                                        / pStreamR3->State.Mapping.cbFrameSize),
     1557                                                      hdaR3WalClkGetMax(pThis, pThisCC)),
    15501558                                               false /* fForce */);
    15511559        RT_NOREF(fWalClkSet);
    15521560    }
    15531561
    1554     /* Does the period have any interrupts outstanding? */
    1555     if (!pStreamShared->State.cTransferPendingInterrupts)
    1556     {
    1557         /* No, set relative timer ticks for the next transfer to happen.
    1558          * This must happen at a constant rate. */
    1559         tsTransferNext = tsNow + pStreamShared->State.cTransferTicks;
    1560     }
     1562    /* Set the next transfer timing slot.
     1563     * This must happen at a constant rate. */
     1564     tsTransferNext = tsNow + pStreamShared->State.cTransferTicks;
    15611565
    15621566    /* If we need to do another transfer, (re-)arm the device timer.  */
    15631567    if (tsTransferNext) /* Can be 0 if no next transfer is needed. */
    15641568    {
    1565         Log3Func(("[SD%RU8] Scheduling timer @ %RU64\n", uSD, tsTransferNext));
     1569        Log3Func(("[SD%RU8] Scheduling timer @ %RU64 (in %RU64 ticks)\n", uSD, tsTransferNext, tsTransferNext - tsNow));
    15661570
    15671571        /* Make sure to assign next transfer timestamp before setting the timer. */
     1572        Assert(tsTransferNext > tsNow);
    15681573        pStreamShared->State.tsTransferNext = tsTransferNext;
    15691574
     
    15731578    }
    15741579
     1580    /* Always update this timestamp, no matter what pStreamShared->State.tsTransferNext is. */
    15751581    pStreamShared->State.tsTransferLast = tsNow;
    15761582
     
    17381744            if (cbSinkReadable)
    17391745            {
    1740                 uint8_t *pabFIFO = pStreamShared->abFIFO;
     1746                void    *pvFIFO = &pStreamShared->abFIFO[0];
     1747                uint32_t cbFIFO = (uint32_t)sizeof(pStreamShared->abFIFO);
    17411748
    17421749                while (cbSinkReadable)
     
    17441751                    uint32_t cbRead;
    17451752                    rc2 = AudioMixerSinkRead(pSink, AUDMIXOP_COPY,
    1746                                              pabFIFO, RT_MIN(cbSinkReadable, (uint32_t)sizeof(pStreamShared->abFIFO)), &cbRead);
     1753                                             pvFIFO, RT_MIN(cbSinkReadable, cbFIFO), &cbRead);
    17471754                    AssertRCBreak(rc2);
    17481755
    17491756                    if (!cbRead)
    17501757                    {
    1751 #ifdef HDA_STRICT
    17521758                        AssertMsgFailed(("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbSinkReadable));
    1753 #endif
    17541759                        break;
    17551760                    }
     
    17571762                    /* Write (guest input) data to the stream which was read from stream's sink before. */
    17581763                    uint32_t cbWritten;
    1759                     rc2 = hdaR3StreamWrite(pStreamR3, pabFIFO, cbRead, &cbWritten);
     1764                    rc2 = hdaR3StreamWrite(pStreamR3, pvFIFO, cbRead, &cbWritten);
    17601765                    AssertRCBreak(rc2);
    17611766                    AssertBreak(cbWritten > 0); /* Should never happen, as we know how much we can write. */
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