VirtualBox

Changeset 89861 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Jun 23, 2021 2:23:42 PM (4 years ago)
Author:
vboxsync
Message:

DevHda: Do LPIB updates more often. Experimental code for doing DMA work on LPIB read (disabled). bugref:9890

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

Legend:

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

    r89856 r89861  
    10351035{
    10361036    RT_NOREF(pDevIns);
    1037 
    1038     const uint8_t  uSD     = HDA_SD_NUM_FROM_REG(pThis, LPIB, iReg);
    1039     const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, uSD);
    1040     *pu32Value = u32LPIB;
    1041     LogFlowFunc(("[SD%RU8] LPIB=%RU32, CBL=%RU32\n", uSD, u32LPIB, HDA_STREAM_REG(pThis, CBL, uSD)));
    1042 
     1037    uint8_t const  uSD   = HDA_SD_NUM_FROM_REG(pThis, LPIB, iReg);
     1038    uint32_t const uLPIB = HDA_STREAM_REG(pThis, LPIB, uSD);
     1039
     1040#ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     1041    /*
     1042     * Should we consider doing DMA work while we're here?  That would require
     1043     * the stream to have the DMA engine enabled and be an output stream.
     1044     */
     1045    if (   (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_RUN)
     1046        && hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT
     1047        && uSD < RT_ELEMENTS(pThis->aStreams) /* paranoia */)
     1048    {
     1049        PHDASTREAM const pStreamShared = &pThis->aStreams[uSD];
     1050        Assert(pStreamShared->u8SD == uSD);
     1051        if (pStreamShared->State.fRunning /* should be same as HDA_SDCTL_RUN, but doesn't hurt to check twice */)
     1052        {
     1053            /*
     1054             * Calculate where the DMA engine should be according to the clock, if we can.
     1055             */
     1056            uint32_t const idxSched = pStreamShared->State.idxSchedule;
     1057            if (idxSched < RT_MIN(RT_ELEMENTS(pStreamShared->State.aSchedule), pStreamShared->State.cSchedule))
     1058            {
     1059                uint32_t const cbPeriod = pStreamShared->State.aSchedule[idxSched].cbPeriod;
     1060                uint32_t const cbFrame  = PDMAudioPropsFrameSize(&pStreamShared->State.Cfg.Props);
     1061                if (cbPeriod > cbFrame)
     1062                {
     1063                    AssertMsg(pStreamShared->State.cbDmaTotal < cbPeriod, ("%#x vs %#x\n", pStreamShared->State.cbDmaTotal, cbPeriod));
     1064                    uint64_t const tsTransferNext = pStreamShared->State.tsTransferNext;
     1065                    uint64_t const tsNow          = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
     1066                    uint32_t       cbFuture;
     1067                    if (tsNow < tsTransferNext)
     1068                    {
     1069                        /** @todo ASSUMES nanosecond clock ticks, need to make this
     1070                         *        resolution independent. */
     1071                        cbFuture = PDMAudioPropsNanoToBytes(&pStreamShared->State.Cfg.Props, tsTransferNext - tsNow);
     1072                        cbFuture = RT_MIN(cbFuture, cbPeriod - cbFrame);
     1073                    }
     1074                    else
     1075                    {
     1076                        /* We've hit/overshot the timer deadline.  Return to ring-3 if we're
     1077                           not already there to increase the chance that we'll help expidite
     1078                           the timer.  If we're already in ring-3, do all but the last frame. */
     1079# ifndef IN_RING3
     1080                        LogFunc(("[SD%RU8] DMA period expired: tsNow=%RU64 >= tsTransferNext=%RU64 -> VINF_IOM_R3_MMIO_READ\n",
     1081                                 tsNow, tsTransferNext));
     1082                        return VINF_IOM_R3_MMIO_READ;
     1083# else
     1084                        cbFuture = cbPeriod - cbFrame;
     1085                        LogFunc(("[SD%RU8] DMA period expired: tsNow=%RU64 >= tsTransferNext=%RU64 -> cbFuture=%#x (cbPeriod=%#x - cbFrame=%#x)\n",
     1086                                 tsNow, tsTransferNext, cbFuture, cbPeriod, cbFrame));
     1087# endif
     1088                    }
     1089                    uint32_t const offNow = PDMAudioPropsFloorBytesToFrame(&pStreamShared->State.Cfg.Props, cbPeriod - cbFuture);
     1090
     1091                    /*
     1092                     * Should we transfer a little?  Minimum is 64 bytes (semi-random,
     1093                     * suspect real hardware might be doing some cache aligned stuff,
     1094                     * which might soon get complicated if you take unaligned buffers
     1095                     * into consideration and which cache line size (128 bytes is just
     1096                     * as likely as 64 or 32 bytes)).
     1097                     */
     1098                    uint32_t cbDmaTotal = pStreamShared->State.cbDmaTotal;
     1099                    if (cbDmaTotal + 64 <= offNow)
     1100                    {
     1101                        VBOXSTRICTRC rcStrict = hdaStreamDoOnAccessDmaOutput(pDevIns, pThis, pStreamShared, offNow - cbDmaTotal);
     1102
     1103                        /* LPIB is updated by hdaStreamDoOnAccessDmaOutput, so get the new value. */
     1104                        uint32_t const uNewLpib = HDA_STREAM_REG(pThis, LPIB, uSD);
     1105                        *pu32Value = uNewLpib;
     1106
     1107                        LogFlowFunc(("[SD%RU8] LPIB=%#RX32 (CBL=%#RX32 PrevLPIB=%#x offNow=%#x) rcStrict=%Rrc\n", uSD,
     1108                                     uNewLpib, HDA_STREAM_REG(pThis, CBL, uSD), uLPIB, offNow, VBOXSTRICTRC_VAL(rcStrict) ));
     1109                        return rcStrict;
     1110                    }
     1111
     1112                    /*
     1113                     * Do nothing, just return LPIB as it is.
     1114                     */
     1115                    LogFlowFunc(("[SD%RU8] Skipping DMA transfer: cbDmaTotal=%#x offNow=%#x\n", uSD, cbDmaTotal, offNow));
     1116                }
     1117                else
     1118                    LogFunc(("[SD%RU8] cbPeriod=%#x <= cbFrame=%#x!!\n", uSD, cbPeriod, cbFrame));
     1119            }
     1120            else
     1121                LogFunc(("[SD%RU8] idxSched=%u cSchedule=%u!!\n", uSD, idxSched, pStreamShared->State.cSchedule));
     1122        }
     1123        else
     1124            LogFunc(("[SD%RU8] fRunning=0 SDnCTL=%#x!!\n", uSD, HDA_STREAM_REG(pThis, CTL, uSD) ));
     1125    }
     1126#endif /* VBOX_HDA_WITH_ON_REG_ACCESS_DMA */
     1127
     1128    LogFlowFunc(("[SD%RU8] LPIB=%#RX32 (CBL=%#RX32 CTL=%#RX32)\n",
     1129                 uSD, uLPIB, HDA_STREAM_REG(pThis, CBL, uSD), HDA_STREAM_REG(pThis, CTL, uSD) ));
     1130    *pu32Value = uLPIB;
    10431131    return VINF_SUCCESS;
    10441132}
     
    39834071                rc = pHlp->pfnSSMGetMem(pSSM, pvBuf, cbBuf);
    39844072                AssertRCReturn(rc, rc);
    3985                 pStreamR3->State.offWrite = cbCircBufUsed;
     4073                pStreamShared->State.offWrite = cbCircBufUsed;
    39864074
    39874075                RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbBuf);
     
    49655053    for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
    49665054    {
    4967         /* We need the first timer in ring-0 to calculate the wall clock (WALCLK) time. */
    49685055        rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, (void *)(uintptr_t)i,
    4969                                   TMTIMER_FLAGS_NO_CRIT_SECT | (i == 0 ? TMTIMER_FLAGS_RING0 : TMTIMER_FLAGS_NO_RING0),
    4970                                   s_apszNames[i], &pThis->aStreams[i].hTimer);
     5056                                  TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, s_apszNames[i], &pThis->aStreams[i].hTimer);
    49715057        AssertRCReturn(rc, rc);
    49725058
     
    50625148    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn,               STAMTYPE_PROFILE, "Input",             STAMUNIT_TICKS_PER_CALL, "Profiling input.");
    50635149    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut,              STAMTYPE_PROFILE, "Output",            STAMUNIT_TICKS_PER_CALL, "Profiling output.");
    5064     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead,        STAMTYPE_COUNTER, "BytesRead"   ,      STAMUNIT_BYTES,          "Bytes read from HDA emulation.");
    5065     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten,     STAMTYPE_COUNTER, "BytesWritten",      STAMUNIT_BYTES,          "Bytes written to HDA emulation.");
     5150    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead,        STAMTYPE_COUNTER, "BytesRead"   ,      STAMUNIT_BYTES,          "Bytes read (DMA) from the guest.");
     5151    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten,     STAMTYPE_COUNTER, "BytesWritten",      STAMUNIT_BYTES,          "Bytes written (DMA) to the guest.");
     5152#  ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     5153    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatAccessDmaOutput,  STAMTYPE_COUNTER, "AccessDmaOutput",   STAMUNIT_COUNT,          "Number of on-register-access DMA sub-transfers we've made.");
     5154    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatAccessDmaOutputToR3,STAMTYPE_COUNTER, "AccessDmaOutputToR3", STAMUNIT_COUNT,      "Number of time the on-register-access DMA forced a ring-3 return.");
     5155#  endif
    50665156
    50675157    AssertCompile(RT_ELEMENTS(g_aHdaRegMap)              == HDA_NUM_REGS);
     
    51105200                               "DMA transfer period skipped because of BCIS pending.", "Stream%u/DMASkippedPendingBCIS", idxStream);
    51115201
    5112         PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5202        PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
    51135203                               "Virtual internal buffer read position.",    "Stream%u/offRead", idxStream);
    5114         PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5204        PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
    51155205                               "Virtual internal buffer write position.",   "Stream%u/offWrite", idxStream);
    51165206        PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.cbTransferSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
  • trunk/src/VBox/Devices/Audio/DevHda.h

    r89638 r89861  
    146146    HDACODEC                Codec;
    147147
     148#ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     149    STAMCOUNTER             StatAccessDmaOutput;
     150    STAMCOUNTER             StatAccessDmaOutputToR3;
     151#endif
    148152#ifdef VBOX_WITH_STATISTICS
    149153    STAMPROFILE             StatIn;
  • trunk/src/VBox/Devices/Audio/DevHdaStream.cpp

    r89859 r89861  
    4040#endif
    4141
    42 #ifdef IN_RING3 /* whole file */
    43 
    4442
    4543/*********************************************************************************************************************************
    4644*   Internal Functions                                                                                                           *
    4745*********************************************************************************************************************************/
    48 static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB);
    49 static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
    50                                  PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
    51 
    52 
     46static void     hdaStreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB);
     47#ifdef IN_RING3
     48# ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     49static void     hdaR3StreamFlushDmaBounceBufferOutput(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
     50# endif
     51static uint32_t hdaR3StreamHandleDmaBufferOverrun(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink,
     52                                                  uint32_t cbNeeded, uint64_t nsNow,
     53                                                  const char *pszCaller, uint32_t const cbStreamFree);
     54static void     hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
     55                                     PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
     56#endif
     57
     58
     59#ifdef IN_RING3
    5360
    5461/**
     
    687694
    688695    /* Set I/O scheduling hint for the backends. */
    689     /** @todo r=bird: This is in the 'Device' portion, yet it's used by the
    690      *        audio driver.  You would think stuff in the 'Device' part is
    691      *        private to the device. */
     696    /** @todo r=bird: derive this from the schedule instead of using the
     697     *        uTimerIoHz, as that's almost pure non-sense now. */
    692698    pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz;
    693699    LogRel2(("HDA: Stream #%RU8 set scheduling hint for the backends to %RU32ms\n", uSD, pCfg->Device.cMsSchedulingHint));
     
    695701
    696702    /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
    697     hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));
     703    /** @todo r=bird: We use LPIB as-is here, so if it's not zero we have to
     704     *        locate the right place in the schedule and whatnot... */
     705    if (HDA_STREAM_REG(pThis, LPIB, uSD) != 0)
     706        LogRel2(("HDA: Warning! Stream #%RU8 is set up with LPIB=%#RX32 instead of zero!\n", uSD, HDA_STREAM_REG(pThis, LPIB, uSD)));
     707    hdaStreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));
    698708
    699709# ifdef LOG_ENABLED
     
    714724        pStreamR3->State.StatDmaBufUsed = 0;
    715725    }
    716     pStreamR3->State.offWrite = 0;
    717     pStreamR3->State.offRead  = 0;
     726    pStreamShared->State.offWrite = 0;
     727    pStreamShared->State.offRead  = 0;
    718728
    719729    /*
     
    878888    if (pStreamR3->State.pCircBuf)
    879889        RTCircBufReset(pStreamR3->State.pCircBuf);
    880     pStreamR3->State.offWrite = 0;
    881     pStreamR3->State.offRead  = 0;
     890    pStreamShared->State.offWrite = 0;
     891    pStreamShared->State.offRead  = 0;
    882892
    883893# ifdef DEBUG
     
    10231033}
    10241034
    1025 
    1026 # if 0 /* Not used atm. */
    1027 static uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStreamShared)
    1028 {
    1029     return HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD);
    1030 }
    1031 # endif
     1035#endif /* IN_RING3 */
    10321036
    10331037/**
     
    10401044 * @param   uLPIB               Absolute position (in bytes) to set current read / write position to.
    10411045 */
    1042 static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB)
     1046static void hdaStreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB)
    10431047{
    10441048    AssertPtrReturnVoid(pStreamShared);
     
    10531057    if (pThis->fDMAPosition)
    10541058    {
     1059        /*
     1060         * Linux switched to using the position buffers some time during 2.6.x.
     1061         * 2.6.12 used LPIB, 2.6.17 defaulted to DMA position buffers, between
     1062         * the two version things were being changing quite a bit.
     1063         *
     1064         * Since 2.6.17, they will treat a zero DMA position value during the first
     1065         * period/IRQ as reason to fall back to LPIB mode (see azx_position_ok in
     1066         * 2.6.27+, and azx_pcm_pointer before that).  They later also added
     1067         * UINT32_MAX to the values causing same.
     1068         *
     1069         * Since 2.6.35 azx_position_ok will read the wall clock register before
     1070         * determining the position.
     1071         */
    10551072        int rc2 = PDMDevHlpPCIPhysWrite(pDevIns,
    10561073                                        pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)),
     
    10711088 * @param   cbToAdd             Position (in bytes) to add to the current read / write position.
    10721089 */
    1073 static void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t cbToAdd)
     1090static void hdaStreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t cbToAdd)
    10741091{
    10751092    if (cbToAdd) /* No need to update anything if 0. */
     
    10861103                uNewLpid %= uCBL;
    10871104#endif
    1088             hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, uNewLpid);
     1105            hdaStreamSetPositionAbs(pStreamShared, pDevIns, pThis, uNewLpid);
    10891106        }
    10901107    }
    10911108}
     1109
     1110#ifdef IN_RING3
    10921111
    10931112/**
     
    11211140}
    11221141
     1142#endif /* IN_RING3 */
     1143
    11231144/**
    11241145 * Get the current address and number of bytes left in the current BDLE.
     
    11281149 * @param   pcbLeft         The number of bytes left at the returned address.
    11291150 */
    1130 DECLINLINE(RTGCPHYS) hdaR3StreamDmaBufGet(PHDASTREAM pStreamShared, uint32_t *pcbLeft)
     1151DECLINLINE(RTGCPHYS) hdaStreamDmaBufGet(PHDASTREAM pStreamShared, uint32_t *pcbLeft)
    11311152{
    11321153    uint8_t        idxBdle    = pStreamShared->State.idxCurBdle;
     
    11471168 * @param   pStreamShared   The stream to check.
    11481169 */
    1149 DECLINLINE(RTGCPHYS) hdaR3StreamDmaBufGetSize(PHDASTREAM pStreamShared)
     1170DECLINLINE(RTGCPHYS) hdaStreamDmaBufGetSize(PHDASTREAM pStreamShared)
    11501171{
    11511172    uint8_t idxBdle = pStreamShared->State.idxCurBdle;
     
    11611182 * @param   pStreamShared   The stream to check.
    11621183 */
    1163 DECLINLINE(bool) hdaR3StreamDmaBufIsComplete(PHDASTREAM pStreamShared)
     1184DECLINLINE(bool) hdaStreamDmaBufIsComplete(PHDASTREAM pStreamShared)
    11641185{
    11651186    uint8_t const  idxBdle    = pStreamShared->State.idxCurBdle;
     
    11791200 * @param   pStreamShared   The stream to check.
    11801201 */
    1181 DECLINLINE(bool) hdaR3StreamDmaBufNeedsIrq(PHDASTREAM pStreamShared)
     1202DECLINLINE(bool) hdaStreamDmaBufNeedsIrq(PHDASTREAM pStreamShared)
    11821203{
    11831204    uint8_t const idxBdle = pStreamShared->State.idxCurBdle;
     
    11911212 * @param   pStreamShared   The stream which DMA engine is to be updated.
    11921213 */
    1193 DECLINLINE(void) hdaR3StreamDmaBufAdvanceToNext(PHDASTREAM pStreamShared)
     1214DECLINLINE(void) hdaStreamDmaBufAdvanceToNext(PHDASTREAM pStreamShared)
    11941215{
    11951216    uint8_t idxBdle = pStreamShared->State.idxCurBdle;
     
    12031224    pStreamShared->State.offCurBdle = 0;
    12041225}
     1226
     1227#ifdef IN_RING3
    12051228
    12061229/**
     
    13071330}
    13081331
     1332#endif /* IN_RING3 */
     1333
    13091334/**
    13101335 * Completes a BDLE at the end of a DMA loop iteration, if possible.
    13111336 *
     1337 * @retval  true if buffer completed and new loaded.
     1338 * @retval  false if buffer not completed.
    13121339 * @param   pDevIns         The device instance.
    13131340 * @param   pThis           The shared HDA device state.
     
    13151342 * @param   pszFunction     The function name (for logging).
    13161343 */
    1317 DECLINLINE(void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis,
    1318                                                      PHDASTREAM pStreamShared, const char *pszFunction)
     1344DECLINLINE(bool) hdaStreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis,
     1345                                                   PHDASTREAM pStreamShared, const char *pszFunction)
    13191346{
    13201347    RT_NOREF(pszFunction);
     
    13231350     * Is the buffer descriptor complete.
    13241351     */
    1325     if (hdaR3StreamDmaBufIsComplete(pStreamShared))
     1352    if (hdaStreamDmaBufIsComplete(pStreamShared))
    13261353    {
    13271354        Log3(("%s: [SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x\n", pszFunction, pStreamShared->u8SD,
     
    13301357              pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags));
    13311358
     1359#if 0 /* Moved to the transfer loops */
    13321360        /*
    13331361         * Update the stream's current position.
     
    13391367         *                      Not doing this at the right time will result in ugly sound crackles!
    13401368         */
    1341         hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaR3StreamDmaBufGetSize(pStreamShared));
     1369        hdaStreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaStreamDmaBufGetSize(pStreamShared));
     1370#endif
    13421371
    13431372        /* Does the current BDLE require an interrupt to be sent? */
    1344         if (hdaR3StreamDmaBufNeedsIrq(pStreamShared))
     1373        if (hdaStreamDmaBufNeedsIrq(pStreamShared))
    13451374        {
    13461375            /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL
     
    13631392         * Advance to the next BDLE.
    13641393         */
    1365         hdaR3StreamDmaBufAdvanceToNext(pStreamShared);
    1366     }
    1367     else
    1368         Log3(("%s: [SD%RU8] Not completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x: off=%#RX32\n", pszFunction, pStreamShared->u8SD,
    1369               pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
    1370               pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
    1371               pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, pStreamShared->State.offCurBdle));
    1372 }
     1394        hdaStreamDmaBufAdvanceToNext(pStreamShared);
     1395        return true;
     1396    }
     1397
     1398    Log3(("%s: [SD%RU8] Incomplete BDLE%u %#RX64 LB %#RX32 fFlags=%#x: off=%#RX32\n", pszFunction, pStreamShared->u8SD,
     1399          pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
     1400          pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
     1401          pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, pStreamShared->State.offCurBdle));
     1402    return false;
     1403}
     1404
     1405#ifdef IN_RING3
    13731406
    13741407/**
     
    13961429 */
    13971430static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
    1398                                   PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs)
     1431                                  PHDASTREAMR3 pStreamR3, uint32_t const cbToConsume, bool fWriteSilence, uint64_t tsNowNs)
    13991432{
    14001433    uint8_t const uSD = pStreamShared->u8SD;
     
    14291462         */
    14301463        uint32_t cbChunk = 0;
    1431         RTGCPHYS GCPhys  = hdaR3StreamDmaBufGet(pStreamShared, &cbChunk);
     1464        RTGCPHYS GCPhys  = hdaStreamDmaBufGet(pStreamShared, &cbChunk);
    14321465
    14331466        /* If we're writing silence.  */
     1467        uint32_t cbWritten = 0;
    14341468        if (!fWriteSilence)
    14351469        {
     
    14621496
    14631497# ifdef VBOX_WITH_DTRACE
    1464                 VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBufSrc, pStreamR3->State.offRead);
     1498                VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBufSrc, pStreamShared->State.offRead);
    14651499# endif
    1466                 pStreamR3->State.offRead += cbBufSrc;
     1500                pStreamShared->State.offRead += cbBufSrc;
    14671501                RTCircBufReleaseReadBlock(pCircBuf, cbBufSrc);
    1468                 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufSrc);
     1502                STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbBufSrc);
    14691503
    14701504                /* advance */
    14711505                cbChunk                         -= (uint32_t)cbBufSrc;
     1506                cbWritten                       += (uint32_t)cbBufSrc;
    14721507                GCPhys                          +=           cbBufSrc;
    1473                 cbLeft                          -= (uint32_t)cbBufSrc;
    14741508                pStreamShared->State.offCurBdle += (uint32_t)cbBufSrc;
    14751509            }
     
    15081542                uint32_t cFrames = PDMAudioPropsBytesToFrames(pGuestProps, RT_MIN(cbGuest, sizeof(abBounce) - cbBounce));
    15091543
    1510                 size_t cbBufSrc = PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFrames);
    15111544                cbGuest  = PDMAudioPropsFramesToBytes(pGuestProps, cFrames);
    15121545                PDMAudioPropsClearBuffer(pGuestProps, &abBounce[cbBounce], cbGuest, cFrames);
     
    15171550                int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, abBounce, cbGuestActual);
    15181551                AssertRC(rc2);
    1519                 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbGuestActual);
     1552                STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbGuestActual);
    15201553
    15211554                /* advance */
    1522                 cbLeft                          -= (uint32_t)cbBufSrc;
     1555                cbWritten                       += cbGuestActual;
    15231556                cbChunk                         -= cbGuestActual;
    15241557                GCPhys                          += cbGuestActual;
     
    15311564                Log5Func((" loop1: GCPhys=%RGp cbGuestActual=%#x cbBounce=%#x cFrames=%#x\n", GCPhys, cbGuestActual, cbBounce, cFrames));
    15321565            }
    1533             Log5Func(("loop0: GCPhys=%RGp cbBounce=%#x cbLeft=%#x\n", GCPhys, cbBounce, cbLeft));
     1566            Log5Func(("loop0: GCPhys=%RGp cbBounce=%#x cbLeft=%#x\n", GCPhys, cbBounce, cbLeft - cbWritten));
    15341567        }
    15351568
     1569        cbLeft -= cbWritten;
    15361570        STAM_PROFILE_STOP(&pThis->StatIn, a);
    15371571
    15381572        /*
    15391573         * Complete the buffer if necessary (common with the output DMA code).
     1574         *
     1575         * Must update the DMA position before we do this as the buffer IRQ may
     1576         * fire on another vCPU and run in parallel to us, although it is very
     1577         * unlikely it can make much progress as long as we're sitting on the
     1578         * lock, it could still read the DMA position (Linux won't, as it reads
     1579         * WALCLK and possibly SDnSTS before the DMA position).
    15401580         */
    1541         hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaInput");
     1581        hdaStreamSetPositionAdd(pStreamShared, pDevIns, pThis, cbWritten);
     1582        hdaStreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaInput");
    15421583    }
    15431584
     
    15541595     */
    15551596    Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
    1556               uSD, cbToConsume, pStreamShared->State.cbTransferSize, pStreamR3->State.offRead - cbToConsume,
     1597              uSD, cbToConsume, pStreamShared->State.cbTransferSize, pStreamShared->State.offRead - cbToConsume,
    15571598              pStreamShared->State.cTransferPendingInterrupts));
    15581599}
     
    15631604 * buffer.
    15641605 *
     1606 * @param   pStreamShared   HDA stream to update (shared).
    15651607 * @param   pStreamR3       HDA stream to update (ring-3 bits).
    15661608 * @param   pSink           The mixer sink to pull from.
    15671609 */
    1568 static void hdaR3StreamPullFromMixer(PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink)
     1610static void hdaR3StreamPullFromMixer(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink)
    15691611{
    15701612# ifdef LOG_ENABLED
    1571     uint64_t const offWriteOld = pStreamR3->State.offWrite;
     1613    uint64_t const offWriteOld = pStreamShared->State.offWrite;
    15721614# endif
    1573     pStreamR3->State.offWrite = AudioMixerSinkTransferToCircBuf(pSink,
    1574                                                                 pStreamR3->State.pCircBuf,
    1575                                                                 pStreamR3->State.offWrite,
    1576                                                                 pStreamR3->u8SD,
    1577                                                                 pStreamR3->Dbg.Runtime.fEnabled
    1578                                                                 ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
     1615    pStreamShared->State.offWrite = AudioMixerSinkTransferToCircBuf(pSink,
     1616                                                                    pStreamR3->State.pCircBuf,
     1617                                                                    pStreamShared->State.offWrite,
     1618                                                                    pStreamR3->u8SD,
     1619                                                                    pStreamR3->Dbg.Runtime.fEnabled
     1620                                                                    ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
    15791621
    15801622    Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
    1581               pStreamR3->State.offWrite - offWriteOld, pStreamR3->State.offWrite));
     1623              pStreamShared->State.offWrite - offWriteOld, pStreamShared->State.offWrite));
    15821624
    15831625    /* Update buffer stats. */
     
    16051647 */
    16061648static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
    1607                                    PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs)
     1649                                   PHDASTREAMR3 pStreamR3, uint32_t const cbToProduce, uint64_t tsNowNs)
    16081650{
    16091651    uint8_t const uSD = pStreamShared->u8SD;
     
    16291671    PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf;
    16301672    uint32_t   cbLeft   = cbToProduce;
     1673# ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     1674    Assert(cbLeft <= pStreamShared->State.cbTransferSize); /* a little pointless with the DMA'ing on LPIB read. */
     1675# else
    16311676    Assert(cbLeft == pStreamShared->State.cbTransferSize);
     1677# endif
    16321678    Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft));
    16331679
     
    16401686         */
    16411687        uint32_t cbChunk = 0;
    1642         RTGCPHYS GCPhys  = hdaR3StreamDmaBufGet(pStreamShared, &cbChunk);
     1688        RTGCPHYS GCPhys  = hdaStreamDmaBufGet(pStreamShared, &cbChunk);
    16431689
    16441690        /* Need to diverge if the BDLEs contain misaligned entries.  */
     1691        uint32_t cbRead  = 0;
    16451692# if 0
    16461693        if (/** @todo pStreamShared->State.fFrameAlignedBuffers */)
     
    16751722
    16761723# ifdef VBOX_WITH_DTRACE
    1677                 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBufDst, pStreamR3->State.offWrite);
     1724                VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBufDst, pStreamShared->State.offWrite);
    16781725# endif
    1679                 pStreamR3->State.offWrite += cbBufDst;
     1726                pStreamShared->State.offWrite  += cbBufDst;
    16801727                RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst);
    16811728                STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufDst);
     
    16831730                /* advance */
    16841731                cbChunk                         -= (uint32_t)cbBufDst;
     1732                cbRead                          += (uint32_t)cbBufDst;
    16851733                GCPhys                          +=           cbBufDst;
    1686                 cbLeft                          -= (uint32_t)cbBufDst;
    16871734                pStreamShared->State.offCurBdle += (uint32_t)cbBufDst;
    16881735            }
     
    17791826# endif
    17801827
     1828        cbLeft -= cbRead;
    17811829        STAM_PROFILE_STOP(&pThis->StatOut, a);
    17821830
    17831831        /*
    1784          * Complete the buffer if necessary (common with the output DMA code).
     1832         * Complete the buffer if necessary (common with the input DMA code).
     1833         *
     1834         * Must update the DMA position before we do this as the buffer IRQ may
     1835         * fire on another vCPU and run in parallel to us, although it is very
     1836         * unlikely it can make much progress as long as we're sitting on the
     1837         * lock, it could still read the DMA position (Linux won't, as it reads
     1838         * WALCLK and possibly SDnSTS before the DMA position).
    17851839         */
    1786         hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaOutput");
     1840        hdaStreamSetPositionAdd(pStreamShared, pDevIns, pThis, cbRead);
     1841        hdaStreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaOutput");
    17871842    }
    17881843
     
    18011856     */
    18021857    Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
    1803               uSD, cbToProduce, pStreamShared->State.cbTransferSize, pStreamR3->State.offWrite - cbToProduce,
     1858              uSD, cbToProduce, pStreamShared->State.cbTransferSize, pStreamShared->State.offWrite - cbToProduce,
    18041859              pStreamShared->State.cTransferPendingInterrupts));
    18051860}
    18061861
     1862#endif /* IN_RING3 */
     1863
     1864#ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     1865/**
     1866 * Do DMA output transfer on LPIB register access.
     1867 *
     1868 * @returns VINF_SUCCESS or VINF_IOM_R3_MMIO_READ.
     1869 * @param   pDevIns         The device instance.
     1870 * @param   pThis           The shared instance data.
     1871 * @param   pStreamShared   The shared stream data.
     1872 * @param   cbToTransfer    How much to transfer.
     1873 */
     1874VBOXSTRICTRC hdaStreamDoOnAccessDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint32_t cbToTransfer)
     1875{
     1876    AssertReturn(cbToTransfer > 0, VINF_SUCCESS);
     1877    int rc = VINF_SUCCESS;
     1878
     1879    /*
     1880     * Check if we're exceeding the available buffer, go to ring-3 to
     1881     * handle that (we would perhaps always take this path when in ring-3).
     1882     */
     1883    uint32_t cbDma = pStreamShared->State.cbDma;
     1884    ASMCompilerBarrier();
     1885    if (   cbDma                >= sizeof(pStreamShared->State.abDma) /* paranoia */
     1886        || cbToTransfer         >= sizeof(pStreamShared->State.abDma) /* paranoia */
     1887        || cbDma + cbToTransfer >  sizeof(pStreamShared->State.abDma))
     1888    {
     1889# ifndef IN_RING3
     1890        STAM_REL_COUNTER_INC(&pThis->StatAccessDmaOutputToR3);
     1891        LogFlowFunc(("[SD%RU8] out of DMA buffer space (%#x, need %#x) -> VINF_IOM_R3_MMIO_READ\n",
     1892                     pStreamShared->u8SD, sizeof(pStreamShared->State.abDma) - pStreamShared->State.cbDma, cbToTransfer));
     1893        return VINF_IOM_R3_MMIO_READ;
     1894# else  /* IN_RING3 */
     1895        /*
     1896         * Flush the bounce buffer, then do direct transfers to the
     1897         * internal DMA buffer (updates LPIB).
     1898         */
     1899        PHDASTATER3 const       pThisCC       = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
     1900        uintptr_t const         idxStream     = pStreamShared->u8SD;
     1901        AssertReturn(idxStream < RT_ELEMENTS(pThisCC->aStreams), VERR_INTERNAL_ERROR_4);
     1902        PHDASTREAMR3 const      pStreamR3     = &pThisCC->aStreams[idxStream];
     1903
     1904        hdaR3StreamFlushDmaBounceBufferOutput(pStreamShared, pStreamR3);
     1905
     1906        uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
     1907        if (cbStreamFree >= cbToTransfer)
     1908        { /* likely */ }
     1909        else
     1910        {
     1911            PAUDMIXSINK pSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
     1912            if (pSink)
     1913                cbStreamFree = hdaR3StreamHandleDmaBufferOverrun(pStreamShared, pStreamR3, pSink, cbToTransfer, RTTimeNanoTS(),
     1914                                                                 "hdaStreamDoOnAccessDmaOutput", cbStreamFree);
     1915            else
     1916            {
     1917                LogFunc(("[SD%RU8] No sink and insufficient internal DMA buffer space (%#x) - won't do anything\n",
     1918                         pStreamShared->u8SD, cbStreamFree));
     1919                return VINF_SUCCESS;
     1920            }
     1921            cbToTransfer = RT_MIN(cbToTransfer, cbStreamFree);
     1922            if (cbToTransfer < PDMAudioPropsFrameSize(&pStreamShared->State.Cfg.Props))
     1923            {
     1924                LogFunc(("[SD%RU8] No internal DMA buffer space (%#x) - won't do anything\n", pStreamShared->u8SD, cbStreamFree));
     1925                return VINF_SUCCESS;
     1926            }
     1927        }
     1928        hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, cbToTransfer, RTTimeNanoTS());
     1929        pStreamShared->State.cbDmaTotal += cbToTransfer;
     1930# endif /* IN_RING3 */
     1931    }
     1932    else
     1933    {
     1934        /*
     1935         * Transfer into the DMA bounce buffer.
     1936         */
     1937        LogFlowFunc(("[SD%RU8] Transfering %#x bytes to DMA bounce buffer (cbDma=%#x cbDmaTotal=%#x) (%p/%u)\n",
     1938                     pStreamShared->u8SD, cbToTransfer, cbDma, pStreamShared->State.cbDmaTotal, pStreamShared, pStreamShared->u8SD));
     1939        uint32_t cbLeft = cbToTransfer;
     1940        do
     1941        {
     1942            uint32_t cbChunk = 0;
     1943            RTGCPHYS GCPhys  = hdaStreamDmaBufGet(pStreamShared, &cbChunk);
     1944
     1945            bool fMustAdvanceBuffer;
     1946            if (cbLeft < cbChunk)
     1947            {
     1948                fMustAdvanceBuffer = false;
     1949                cbChunk            = cbLeft;
     1950            }
     1951            else
     1952                fMustAdvanceBuffer = true;
     1953
     1954            /* Read the guest data directly into the DMA bounce buffer. */
     1955            int rc2 = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &pStreamShared->State.abDma[cbDma], cbChunk);
     1956            AssertRC(rc2);
     1957
     1958            /* We update offWrite and StatBytesRead here even if we haven't moved the data
     1959               to the internal DMA buffer yet, because we want the dtrace even to fire here. */
     1960# ifdef VBOX_WITH_DTRACE
     1961            VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)pStreamShared->u8SD, cbChunk, pStreamShared->State.offWrite);
     1962# endif
     1963            pStreamShared->State.offWrite   += cbChunk;
     1964            STAM_COUNTER_ADD(&pThis->StatBytesRead, cbChunk);
     1965
     1966            /* advance */
     1967            pStreamShared->State.offCurBdle += cbChunk;
     1968            pStreamShared->State.cbDmaTotal += cbChunk;
     1969            cbDma                           += cbChunk;
     1970            pStreamShared->State.cbDma       = cbDma;
     1971            cbLeft                          -= cbChunk;
     1972            Log6Func(("cbLeft=%#x cbDma=%#x cbDmaTotal=%#x offCurBdle=%#x idxCurBdle=%#x (%p/%u)\n",
     1973                      cbLeft, cbDma, pStreamShared->State.cbDmaTotal, pStreamShared->State.offCurBdle,
     1974                      pStreamShared->State.idxCurBdle, pStreamShared, pStreamShared->u8SD));
     1975
     1976            /* Next buffer. */
     1977            bool fAdvanced = hdaStreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaStreamDoOnAccessDmaOutput");
     1978            AssertMsgStmt(fMustAdvanceBuffer == fAdvanced, ("%d %d\n", fMustAdvanceBuffer, fAdvanced), rc = VERR_INTERNAL_ERROR_3);
     1979        } while (cbLeft > 0);
     1980
     1981        /*
     1982         * Advance LPIB.
     1983         */
     1984        hdaStreamSetPositionAdd(pStreamShared, pDevIns, pThis, cbToTransfer - cbLeft);
     1985    }
     1986
     1987# ifdef VBOX_STRICT
     1988    uint32_t       idxSched = pStreamShared->State.idxSchedule;
     1989    AssertStmt(idxSched < RT_MIN(RT_ELEMENTS(pStreamShared->State.aSchedule), pStreamShared->State.cSchedule), idxSched = 0);
     1990    uint32_t const cbPeriod = pStreamShared->State.aSchedule[idxSched].cbPeriod;
     1991    AssertMsg(pStreamShared->State.cbDmaTotal < cbPeriod, ("%#x vs %#x\n", pStreamShared->State.cbDmaTotal, cbPeriod));
     1992# endif
     1993
     1994    STAM_REL_COUNTER_INC(&pThis->StatAccessDmaOutput);
     1995    return rc;
     1996}
     1997#endif /* VBOX_HDA_WITH_ON_REG_ACCESS_DMA */
     1998
     1999
     2000#ifdef IN_RING3
    18072001
    18082002/**
     
    18172011{
    18182012# ifdef LOG_ENABLED
    1819     uint64_t const offReadOld = pStreamR3->State.offRead;
     2013    uint64_t const offReadOld = pStreamShared->State.offRead;
    18202014# endif
    1821     pStreamR3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink,
    1822                                                                  pStreamR3->State.pCircBuf,
    1823                                                                  pStreamR3->State.offRead,
    1824                                                                  pStreamR3->u8SD,
    1825                                                                  pStreamR3->Dbg.Runtime.fEnabled
    1826                                                                  ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
     2015    pStreamShared->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink,
     2016                                                                     pStreamR3->State.pCircBuf,
     2017                                                                     pStreamShared->State.offRead,
     2018                                                                     pStreamR3->u8SD,
     2019                                                                     pStreamR3->Dbg.Runtime.fEnabled
     2020                                                                     ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
    18272021
    18282022    Assert(nsNow >= pStreamShared->State.tsLastReadNs);
    18292023    Log3Func(("[SD%RU8] nsDeltaLastRead=%RI64 transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
    1830               nsNow - pStreamShared->State.tsLastReadNs, pStreamR3->State.offRead - offReadOld, pStreamR3->State.offRead));
     2024              nsNow - pStreamShared->State.tsLastReadNs, pStreamShared->State.offRead - offReadOld, pStreamShared->State.offRead));
    18312025    RT_NOREF(pStreamShared, nsNow);
    18322026
     
    18342028    pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
    18352029}
     2030
     2031
     2032/**
     2033 * Deals with a DMA buffer overrun.
     2034 *
     2035 * Makes sure we return with @a cbNeeded bytes of free space in pCircBuf.
     2036 *
     2037 * @returns Number of bytes free in the internal DMA buffer.
     2038 * @param   pStreamShared   The shared data for the HDA stream.
     2039 * @param   pStreamR3       The ring-3 data for the HDA stream.
     2040 * @param   pSink           The mixer sink (valid).
     2041 * @param   cbNeeded        How much space we need (in bytes).
     2042 * @param   nsNow           Current RTNanoTimeTS() timestamp.
     2043 * @param   cbStreamFree    The current amount of free buffer space.
     2044 * @param   pszCaller       The caller (for logging).
     2045 */
     2046static uint32_t hdaR3StreamHandleDmaBufferOverrun(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink,
     2047                                                  uint32_t cbNeeded, uint64_t nsNow,
     2048                                                  const char *pszCaller, uint32_t const cbStreamFree)
     2049{
     2050    STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
     2051    Log(("%s: Warning! Stream #%u has insufficient space free: %#x bytes, need %#x.  Will try move data out of the buffer...\n",
     2052         pszCaller, pStreamShared->u8SD, cbStreamFree, cbNeeded));
     2053    RT_NOREF(pszCaller, cbStreamFree);
     2054
     2055    int rc = AudioMixerSinkTryLock(pSink);
     2056    if (RT_SUCCESS(rc))
     2057    {
     2058        hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, nsNow);
     2059        AudioMixerSinkUpdate(pSink, 0, 0);
     2060        AudioMixerSinkUnlock(pSink);
     2061    }
     2062    else
     2063        RTThreadYield();
     2064
     2065    uint32_t const cbRet = hdaR3StreamGetFree(pStreamR3);
     2066    Log(("%s: Gained %u bytes.\n", pszCaller, cbRet - cbStreamFree));
     2067    if (cbRet >= cbNeeded)
     2068        return cbRet;
     2069
     2070    /*
     2071     * Unable to make sufficient space.  Drop the whole buffer content.
     2072     *
     2073     * This is needed in order to keep the device emulation running at a
     2074     * constant rate, at the cost of losing valid (but too much) data.
     2075     */
     2076    STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
     2077    LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data (%s)\n",
     2078             pStreamShared->u8SD, hdaR3StreamGetUsed(pStreamR3), pszCaller));
     2079# ifdef HDA_STRICT
     2080    AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));
     2081# endif
     2082/**
     2083 *
     2084 * @todo r=bird: I don't think RTCircBufReset is entirely safe w/o
     2085 * owning the AIO lock.  See the note in the documentation about it not being
     2086 * multi-threading aware (safe).   Wish I'd verified this code much earlier.
     2087 * Sigh^3!
     2088 *
     2089 */
     2090    RTCircBufReset(pStreamR3->State.pCircBuf);
     2091    pStreamShared->State.offWrite = 0;
     2092    pStreamShared->State.offRead  = 0;
     2093    return hdaR3StreamGetFree(pStreamR3);
     2094}
     2095
     2096
     2097# ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     2098/**
     2099 * Flushes the DMA bounce buffer content to the internal DMA buffer.
     2100 *
     2101 * @param   pStreamShared   The shared data of the stream to have its DMA bounce
     2102 *                          buffer flushed.
     2103 * @param   pStreamR3       The ring-3 stream data for same.
     2104 */
     2105static void hdaR3StreamFlushDmaBounceBufferOutput(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
     2106{
     2107    uint32_t cbDma = pStreamShared->State.cbDma;
     2108    LogFlowFunc(("cbDma=%#x\n", cbDma));
     2109    if (cbDma)
     2110    {
     2111        AssertReturnVoid(cbDma <= sizeof(pStreamShared->State.abDma));
     2112        PRTCIRCBUF const pCircBuf = pStreamR3->State.pCircBuf;
     2113        if (pCircBuf)
     2114        {
     2115            uint32_t offDma = 0;
     2116            while (offDma < cbDma)
     2117            {
     2118                uint32_t const cbSrcLeft = cbDma - offDma;
     2119
     2120                /*
     2121                 * Grab a chunk of the internal DMA buffer.
     2122                 */
     2123                void  *pvBufDst = NULL;
     2124                size_t cbBufDst = 0;
     2125                RTCircBufAcquireWriteBlock(pCircBuf, cbSrcLeft, &pvBufDst, &cbBufDst);
     2126                if (cbBufDst > 0)
     2127                { /* likely */ }
     2128                else
     2129                {
     2130                    /* We've got buffering trouble. */
     2131                    RTCircBufReleaseWriteBlock(pCircBuf, 0);
     2132
     2133                    PAUDMIXSINK pSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
     2134                    if (pSink)
     2135                        hdaR3StreamHandleDmaBufferOverrun(pStreamShared, pStreamR3, pSink, cbSrcLeft, RTTimeNanoTS(),
     2136                                                          "hdaR3StreamFlushDmaBounceBufferOutput", 0 /*cbStreamFree*/);
     2137                    else
     2138                    {
     2139                        LogFunc(("Stream #%u has no sink. Dropping the rest of the data\n", pStreamR3->u8SD));
     2140                        break;
     2141                    }
     2142
     2143                    RTCircBufAcquireWriteBlock(pCircBuf, cbSrcLeft, &pvBufDst, &cbBufDst);
     2144                    AssertBreakStmt(cbBufDst, RTCircBufReleaseWriteBlock(pCircBuf, 0));
     2145                }
     2146
     2147                /*
     2148                 * Copy the samples into it and write it to the debug file if open.
     2149                 *
     2150                 * We do not fire the dtrace probe here nor update offRead as that was
     2151                 * done already (not sure that was a good idea?).
     2152                 */
     2153                memcpy(pvBufDst, &pStreamShared->State.abDma[offDma], cbBufDst);
     2154
     2155                if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
     2156                { /* likely */ }
     2157                else
     2158                    AudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufDst, cbBufDst, 0 /* fFlags */);
     2159
     2160                RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst);
     2161
     2162                offDma += (uint32_t)cbBufDst;
     2163            }
     2164        }
     2165
     2166        /*
     2167         * Mark the buffer empty.
     2168         */
     2169        pStreamShared->State.cbDma = 0;
     2170    }
     2171}
     2172# endif /* VBOX_HDA_WITH_ON_REG_ACCESS_DMA */
    18362173
    18372174
     
    19442281    uint32_t       idxSched = pStreamShared->State.idxSchedule;
    19452282    AssertStmt(idxSched < RT_MIN(RT_ELEMENTS(pStreamShared->State.aSchedule), pStreamShared->State.cSchedule), idxSched = 0);
    1946     uint32_t const cbPeriod = pStreamShared->State.aSchedule[idxSched].cbPeriod;
     2283    uint32_t       cbPeriod = pStreamShared->State.aSchedule[idxSched].cbPeriod;
    19472284
    19482285    /*
     
    19512288    if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT)
    19522289    {
     2290# ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     2291        /* Subtract already transferred bytes and flush the DMA bounce buffer. */
     2292        uint32_t cbDmaTotal = pStreamShared->State.cbDmaTotal;
     2293        if (cbDmaTotal > 0)
     2294        {
     2295            AssertStmt(cbDmaTotal < cbPeriod, cbDmaTotal = cbPeriod);
     2296            cbPeriod -= cbDmaTotal;
     2297            pStreamShared->State.cbDmaTotal = 0;
     2298            hdaR3StreamFlushDmaBounceBufferOutput(pStreamShared, pStreamR3);
     2299        }
     2300        else
     2301            Assert(pStreamShared->State.cbDma == 0);
     2302# endif
     2303
    19532304        /*
    19542305         * Check how much room we have in our DMA buffer.  There should be at
     
    19592310        { /* likely */ }
    19602311        else
    1961         {
    1962             STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
    1963             Log(("hdaR3StreamUpdateDma: Warning! Stream #%u has insufficient space free: %u bytes, need %u.  Will try move data out of the buffer...\n",
    1964                  pStreamShared->u8SD, cbStreamFree, cbPeriod));
    1965             int rc = AudioMixerSinkTryLock(pSink);
    1966             if (RT_SUCCESS(rc))
    1967             {
    1968                 hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
    1969                 AudioMixerSinkUpdate(pSink, 0, 0);
    1970                 AudioMixerSinkUnlock(pSink);
    1971             }
    1972             else
    1973                 RTThreadYield();
    1974             Log(("hdaR3StreamUpdateDma: Gained %u bytes.\n", hdaR3StreamGetFree(pStreamR3) - cbStreamFree));
    1975 
    1976             cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    1977             if (cbStreamFree < cbPeriod)
    1978             {
    1979                 /* Unable to make sufficient space.  Drop the whole buffer content.
    1980                  * This is needed in order to keep the device emulation running at a constant rate,
    1981                  * at the cost of losing valid (but too much) data. */
    1982                 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
    1983                 LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n",
    1984                          pStreamShared->u8SD, hdaR3StreamGetUsed(pStreamR3)));
    1985 # ifdef HDA_STRICT
    1986                 AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));
    1987 # endif
    1988                 RTCircBufReset(pStreamR3->State.pCircBuf);
    1989                 pStreamR3->State.offWrite = 0;
    1990                 pStreamR3->State.offRead  = 0;
    1991                 cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    1992             }
    1993         }
     2312            cbStreamFree = hdaR3StreamHandleDmaBufferOverrun(pStreamShared, pStreamR3, pSink, cbPeriod, tsNowNs,
     2313                                                             "hdaR3StreamUpdateDma", cbStreamFree);
    19942314
    19952315        /*
    19962316         * Do the DMA transfer.
    19972317         */
    1998         uint64_t const offWriteBefore = pStreamR3->State.offWrite;
     2318        uint64_t const offWriteBefore = pStreamShared->State.offWrite;
    19992319        hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
    20002320
     
    20122332        bool fKickAioThread;
    20132333        if (!pStreamShared->State.tsAioDelayEnd)
    2014             fKickAioThread = pStreamR3->State.offWrite > offWriteBefore
     2334            fKickAioThread = pStreamShared->State.offWrite > offWriteBefore
    20152335                          || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2;
    20162336        else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd)
     
    21012421            {
    21022422                AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod);
    2103                 hdaR3StreamPullFromMixer(pStreamR3, pSink);
     2423                hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
    21042424                AudioMixerSinkUnlock(pSink);
    21052425            }
     
    21222442                    if (cbStreamUsed < cbPeriod)
    21232443                    {
    2124                         hdaR3StreamPullFromMixer(pStreamR3, pSink);
     2444                        hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
    21252445                        cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
    21262446                        while (cbStreamUsed < cbPeriod)
     
    22092529    {
    22102530        Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN);
    2211         hdaR3StreamPullFromMixer(pStreamR3, pSink);
     2531        hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
    22122532    }
    22132533}
  • trunk/src/VBox/Devices/Audio/DevHdaStream.h

    r89853 r89861  
    111111     * @note This is used for wall clock (WALCLK) calculations.  */
    112112    uint64_t volatile       tsTransferLast;
     113    /** The stream's current configuration (matches SDnFMT). */
     114    PDMAUDIOSTREAMCFG       Cfg;
     115    /** Timestamp (real time, in ns) of last DMA transfer. */
     116    uint64_t                tsLastTransferNs;
     117    /** Timestamp (real time, in ns) of last stream read (to backends).
     118     *  When running in async I/O mode, this differs from \a tsLastTransferNs,
     119     *  because reading / processing will be done in a separate stream. */
     120    uint64_t                tsLastReadNs;
     121
     122    /** This is set to the timer clock time when the msInitialDelay period is over.
     123     * Once reached, this is set to zero to avoid unnecessary time queries. */
     124    uint64_t                tsAioDelayEnd;
     125    /** The start time for the playback (on the timer clock). */
     126    uint64_t                tsStart;
     127
     128    /** @name DMA engine
     129     * @{ */
    113130    /** Timestamp (absolute, in timer ticks) of the next DMA data transfer.
    114131     *  Next for determining the next scheduling window.
     
    119136    /** The size of an average transfer. */
    120137    uint32_t                cbAvgTransfer;
    121     /** The stream's current configuration (matches SDnFMT). */
    122     PDMAUDIOSTREAMCFG       Cfg;
    123     /** Timestamp (real time, in ns) of last DMA transfer. */
    124     uint64_t                tsLastTransferNs;
    125     /** Timestamp (real time, in ns) of last stream read (to backends).
    126      *  When running in async I/O mode, this differs from \a tsLastTransferNs,
    127      *  because reading / processing will be done in a separate stream. */
    128     uint64_t                tsLastReadNs;
    129 
    130     /** This is set to the timer clock time when the msInitialDelay period is over.
    131      * Once reached, this is set to zero to avoid unnecessary time queries. */
    132     uint64_t                tsAioDelayEnd;
    133     /** The start time for the playback (on the timer clock). */
    134     uint64_t                tsStart;
    135 
    136     /** @name DMA engine
    137      * @{ */
     138
     139    /** Current circular buffer read offset (for tracing & logging). */
     140    uint64_t                offRead;
     141    /** Current circular buffer write offset (for tracing & logging). */
     142    uint64_t                offWrite;
     143
    138144    /** The offset into the current BDLE. */
    139145    uint32_t                offCurBdle;
     
    181187        uint8_t             abPadding[2];
    182188    }                       aSchedule[512+8];
     189
     190#ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
     191    /** Number of valid bytes in abDma.
     192     * @note Volatile to prevent the compiler from re-reading it after we've
     193     *       validated the value in ring-0. */
     194    uint32_t volatile       cbDma;
     195    /** Total number of bytes going via abDma this timer period. */
     196    uint32_t                cbDmaTotal;
     197    /** DMA bounce buffer for ring-0 register reads (LPIB). */
     198    uint8_t                 abDma[2048 - 8];
     199#endif
    183200    /** @} */
    184201} HDASTREAMSTATE;
    185 AssertCompileSizeAlignment(HDASTREAMSTATE, 8);
     202AssertCompileSizeAlignment(HDASTREAMSTATE, 16);
    186203AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 8);
    187204AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 16);
     
    236253    TMTIMERHANDLE               hTimer;
    237254
     255#if 0
    238256    /** Pad the structure size to a 64 byte alignment. */
    239257    uint64_t                    au64Padding1[2];
     258#endif
    240259} HDASTREAM;
    241260AssertCompileMemberAlignment(HDASTREAM, State.aBdl, 16);
     
    265284        /** Circular buffer (FIFO) for holding DMA'ed data. */
    266285        R3PTRTYPE(PRTCIRCBUF)   pCircBuf;
    267         /** Current circular buffer read offset (for tracing & logging). */
    268         uint64_t                offRead;
    269         /** Current circular buffer write offset (for tracing & logging). */
    270         uint64_t                offWrite;
    271286#ifdef HDA_USE_DMA_ACCESS_HANDLER
    272287        /** List of DMA handlers. */
     
    296311        STAMPROFILE             StatReset;
    297312        STAMPROFILE             StatStop;
    298         STAMPROFILE             StatUnusedPadding;
    299313    } State;
    300314    /** Debug bits. */
    301315    HDASTREAMDEBUG              Dbg;
    302     uint64_t                    au64Alignment[1+4];
     316    uint64_t                    au64Alignment[3];
    303317} HDASTREAMR3;
    304318AssertCompileSizeAlignment(HDASTREAMR3, 64);
    305319/** Pointer to an HDA stream (SDI / SDO).  */
    306320typedef HDASTREAMR3 *PHDASTREAMR3;
     321
     322/** @name Stream functions (all contexts).
     323 * @{
     324 */
     325VBOXSTRICTRC        hdaStreamDoOnAccessDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
     326                                                 uint32_t cbToTransfer);
     327/** @} */
    307328
    308329#ifdef IN_RING3
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