VirtualBox

Changeset 89664 in vbox


Ignore:
Timestamp:
Jun 14, 2021 12:01:16 AM (3 years ago)
Author:
vboxsync
Message:

DevIchAc97: Changed ichac97R3StreamTransferUpdate to actually take the uTimerHz into account rather than just talking about it. This should prevent guests occasionally throwing big buffers at us causing trouble with DMA buffer size, timer scheduling and backend underuns/overruns. bugref:9890

File:
1 edited

Legend:

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

    r89661 r89664  
    848848                  RT_BOOL(pRegs->bd.ctl_len & AC97_BD_BUP),
    849849                  RT_BOOL(pRegs->bd.ctl_len & AC97_BD_IOC)));
     850    /** @todo r=bird: Several of the specificiation states that zero length BDL
     851     *        entries are okay, as long as they aren't at the head or end.  We
     852     *        should simply skip up to 30 empty ones, because otherwise the timer
     853     *        locking falls flat on its face. */
    850854}
    851855
     
    16791683}
    16801684
    1681 /**
    1682  * Calculates and returns the ticks for a specified amount of bytes.
    1683  *
    1684  * @returns Calculated ticks
    1685  * @param   pDevIns             The device instance.
    1686  * @param   pStream             AC'97 stream to calculate ticks for (shared).
    1687  * @param   pStreamCC           AC'97 stream to calculate ticks for (ring-3).
    1688  * @param   cbBytes             Bytes to calculate ticks for.
    1689  */
    1690 static uint64_t ichac97R3StreamTransferCalcNext(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, uint32_t cbBytes)
    1691 {
    1692     if (!cbBytes)
    1693         return 0;
    1694 
    1695     /** @todo r=bird: Why use microseconds when the timer clock has been using
    1696      *        nanosecond resolution since early 2005? */
    1697     const uint64_t usBytes        = PDMAudioPropsBytesToMicro(&pStreamCC->State.Cfg.Props, cbBytes);
    1698     const uint64_t cTransferTicks = PDMDevHlpTimerFromMicro(pDevIns, pStream->hTimer, usBytes);
    1699 
    1700     Log3Func(("[SD%RU8] Timer %uHz, cbBytes=%RU32 -> usBytes=%RU64, cTransferTicks=%RU64\n",
    1701               pStream->u8SD, pStreamCC->State.uTimerHz, cbBytes, usBytes, cTransferTicks));
    1702 
    1703     return cTransferTicks;
    1704 }
    17051685
    17061686/**
     
    17101690 * @param   pStream             The AC'97 stream to update (shared).
    17111691 * @param   pStreamCC           The AC'97 stream to update (ring-3).
    1712  * @param   cbBytes             Bytes to update next transfer for.
    1713  */
    1714 static void ichac97R3StreamTransferUpdate(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, uint32_t cbBytes)
    1715 {
    1716     if (!cbBytes)
    1717         return;
    1718 
    1719     /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
    1720      * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */
    1721     pStreamCC->State.cbTransferChunk = cbBytes;
    1722 
    1723     /* Update the transfer ticks. */
    1724     pStreamCC->State.cTransferTicks = ichac97R3StreamTransferCalcNext(pDevIns, pStream, pStreamCC,
    1725                                                                       pStreamCC->State.cbTransferChunk);
    1726     Assert(pStreamCC->State.cTransferTicks); /* Paranoia. */
     1692 */
     1693static void ichac97R3StreamTransferUpdate(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
     1694{
     1695    /*
     1696     * Get the number of bytes left in the current buffer.
     1697     *
     1698     * This isn't entirely optimal iff the current entry doesn't have IOC set, in
     1699     * that case we should use the number of bytes to the next IOC.  Unfortuantely,
     1700     * it seems the spec doesn't allow us to prefetch more than one BDLE, so we
     1701     * probably cannot look ahead without violating that restriction.  This is
     1702     * probably a purely theoretical problem at this point.
     1703     */
     1704    uint32_t const cbLeftInBdle = pStream->Regs.picb * PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props);
     1705    if (cbLeftInBdle > 0) /** @todo r=bird: see todo about this in ichac97R3StreamFetchBDLE. */
     1706    {
     1707        /*
     1708         * Since the buffer can be up to 0xfffe samples long (frame aligning stereo
     1709         * prevents 0xffff), which translates to 743ms at a 44.1kHz rate, we must
     1710         * also take the nominal timer frequency into account here so we keep
     1711         * moving data at a steady rate.  (In theory, I think the guest can even
     1712         * set up just one buffer and anticipate where we are in the buffer
     1713         * processing when it writes/reads from it.  Linux seems to be doing such
     1714         * configs when not playing or something.)
     1715         */
     1716        uint32_t const cbMaxPerHz = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props, RT_NS_1SEC / pStreamCC->State.uTimerHz);
     1717
     1718        if (cbLeftInBdle <= cbMaxPerHz)
     1719            pStreamCC->State.cbTransferChunk = cbLeftInBdle;
     1720        /* Try avoid leaving a very short period at the end of a buffer. */
     1721        else if (cbLeftInBdle >= cbMaxPerHz + cbMaxPerHz / 2)
     1722            pStreamCC->State.cbTransferChunk = cbMaxPerHz;
     1723        else
     1724            pStreamCC->State.cbTransferChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbLeftInBdle / 2);
     1725
     1726        /*
     1727         * Translate the chunk size to timer ticks.
     1728         */
     1729        uint64_t const cNsXferChunk     = PDMAudioPropsBytesToNano(&pStreamCC->State.Cfg.Props, pStreamCC->State.cbTransferChunk);
     1730        pStreamCC->State.cTransferTicks = PDMDevHlpTimerFromNano(pDevIns, pStream->hTimer, cNsXferChunk);
     1731        Assert(pStreamCC->State.cTransferTicks > 0);
     1732
     1733        Log3Func(("[SD%RU8] cbLeftInBdle=%#RX32 cbMaxPerHz=%#RX32 (%RU16Hz) -> cbTransferChunk=%#RX32 cTransferTicks=%RX64\n",
     1734                  pStream->u8SD, cbLeftInBdle, cbMaxPerHz, pStreamCC->State.uTimerHz,
     1735                  pStreamCC->State.cbTransferChunk, pStreamCC->State.cTransferTicks));
     1736    }
    17271737}
    17281738
     
    24872497    Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStream->hTimer));
    24882498
    2489     ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC);
    2490 
    24912499    PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
    24922500    if (pSink && AudioMixerSinkIsActive(pSink))
    24932501    {
    2494         ichac97R3StreamTransferUpdate(pDevIns, pStream, pStreamCC, pStream->Regs.picb << 1); /** @todo r=andy Assumes 16-bit samples. */
     2502        ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC);
     2503
     2504        ichac97R3StreamTransferUpdate(pDevIns, pStream, pStreamCC);
    24952505        ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks);
    24962506    }
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