VirtualBox

Changeset 88162 in vbox for trunk


Ignore:
Timestamp:
Mar 17, 2021 4:44:17 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143311
Message:

DevHDA: Put common DMA code into helper functions to reduce code duplication. bugref:9890

File:
1 edited

Legend:

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

    r88160 r88162  
    11401140
    11411141/**
     1142 * Common do-DMA prologue code.
     1143 *
     1144 * @retval  true if DMA processing can take place
     1145 * @retval  false if caller should return immediately.
     1146 * @param   pDevIns         The device instance.
     1147 * @param   pThis           The shared HDA device state.
     1148 * @param   pStreamShared   HDA stream to update (shared).
     1149 * @param   uSD             The stream ID (for asserting).
     1150 * @param   tsNowNs         The current RTTimeNano() value.
     1151 * @param   pszFunction     The function name (for logging).
     1152 */
     1153DECLINLINE(bool) hdaR3StreamDoDmaPrologue(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint8_t uSD,
     1154                                          uint64_t tsNowNs, const char *pszFunction)
     1155{
     1156    RT_NOREF(uSD, pszFunction);
     1157
     1158    /*
     1159     * Check if we should skip town...
     1160     */
     1161    /* Stream not running (anymore)? */
     1162    if (pStreamShared->State.fRunning)
     1163    { /* likely */ }
     1164    else
     1165    {
     1166        Log3(("%s: [SD%RU8] Not running, skipping transfer\n", pszFunction, uSD));
     1167        return false;
     1168    }
     1169
     1170    if (!(HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS))
     1171    { /* likely */ }
     1172    else
     1173    {
     1174        Log3(("%s: [SD%RU8] BCIS bit set, skipping transfer\n", pszFunction, uSD));
     1175#ifdef HDA_STRICT
     1176        /* Timing emulation bug or guest is misbehaving -- let me know. */
     1177        AssertMsgFailed(("%s: BCIS bit for stream #%RU8 still set when it shouldn't\n", pszFunction, uSD));
     1178#endif
     1179        return false;
     1180    }
     1181
     1182    /*
     1183     * Stream sanity checks.
     1184     */
     1185    /* Register sanity checks. */
     1186    Assert(uSD < HDA_MAX_STREAMS);
     1187    Assert(pStreamShared->u64BDLBase);
     1188    Assert(pStreamShared->u32CBL);
     1189    Assert(pStreamShared->u8FIFOS);
     1190
     1191    /* State sanity checks. */
     1192    Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false);
     1193    Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning));
     1194
     1195    /*
     1196     * Some timestamp stuff for logging/debugging.
     1197     */
     1198    /*const uint64_t tsNowNs = RTTimeNanoTS();*/
     1199    Log3(("%s: [SD%RU8] tsDeltaNs=%'RU64 ns\n", pszFunction, uSD, tsNowNs - pStreamShared->State.tsLastTransferNs));
     1200    pStreamShared->State.tsLastTransferNs = tsNowNs;
     1201    pStreamShared->State.tsTransferLast   = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
     1202
     1203    /*
     1204     * Set the FIFORDY bit on the stream while doing the transfer.
     1205     */
     1206    /** @todo r=bird: I don't get the HDA_SDSTS_FIFORDY logic.  Unless we're
     1207     *        assuming SMP guest and that it can get stream registers while we're
     1208     *        here.  Only it cannot do the later because we're sitting on the big
     1209     *        HDA device lock, see assertions in hdaR3Timer().  So, this is an
     1210     *        pointless guesture given that we clear it again after the loop. */
     1211    HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY;
     1212
     1213    return true;
     1214}
     1215
     1216/**
     1217 * Common do-DMA epilogue.
     1218 *
     1219 * @param   pThis           The shared HDA device state.
     1220 * @param   pThisCC         The ring-3 HDA device state.
     1221 * @param   pStreamShared   HDA stream to update (shared).
     1222 * @param   cbProcessed     The number of bytes processed.
     1223 */
     1224DECLINLINE(void) hdaR3StreamDoDmaEpilogue(PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared, uint32_t cbProcessed)
     1225{
     1226    /*
     1227     * Clear the (pointless) FIFORDY bit again.
     1228     */
     1229    HDA_STREAM_REG(pThis, STS, pStreamShared->u8SD) &= ~HDA_SDSTS_FIFORDY;
     1230
     1231    /*
     1232     * Try updating the wall clock.
     1233     *
     1234     * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register
     1235     *         in order to determine the correct timing of the sound device. Other guests
     1236     *         like Windows 7 + 10 (or even more exotic ones like Haiku) will completely
     1237     *         ignore this.
     1238     *
     1239     * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic
     1240     *         fashion) this *will* upset guest device drivers and will completely fuck up the
     1241     *         sound output. Running VLC on the guest will tell!
     1242     */
     1243    uint32_t const cFramesProcessed = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbProcessed);
     1244    /** @todo this needs to go, but we need it for hdaR3WalClkGetMax below. */
     1245    hdaR3StreamPeriodInc(&pStreamShared->State.Period,
     1246                         RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period)));
     1247
     1248    uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, cFramesProcessed);
     1249    uint64_t const uWallNew   = hdaWalClkGetCurrent(pThis) + cWallTicks;
     1250    uint64_t const uWallMax   = hdaR3WalClkGetMax(pThis, pThisCC);
     1251    bool const     fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, RT_MIN(uWallNew, uWallMax), false /* fForce */);
     1252    RT_NOREF(fWalClkSet);
     1253}
     1254
     1255/**
     1256 * Completes a BDLE at the end of a DMA loop iteration, if possible.
     1257 *
     1258 * @param   pDevIns         The device instance.
     1259 * @param   pThis           The shared HDA device state.
     1260 * @param   pThisCC         The ring-3 HDA device state.
     1261 * @param   pStreamShared   HDA stream to update (shared).
     1262 * @param   pStreamR3       HDA stream to update (ring-3).
     1263 * @param   pszFunction     The function name (for logging).
     1264 */
     1265DECLINLINE(void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
     1266                                                     PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, const char *pszFunction)
     1267{
     1268    RT_NOREF(pszFunction);
     1269
     1270    /*
     1271     * Is the buffer descriptor complete.
     1272     */
     1273    if (hdaR3StreamDmaBufIsComplete(pStreamShared))
     1274    {
     1275        Log3(("%s: [SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x\n", pszFunction, pStreamShared->u8SD,
     1276              pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
     1277              pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
     1278              pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags));
     1279
     1280        /* Make sure to also update the wall clock when a BDLE is complete.
     1281         * Needed for Windows 10 guests. */
     1282        /** @todo there is a rounding error here.   */
     1283        hdaR3WalClkSet(pThis, pThisCC,
     1284                         hdaWalClkGetCurrent(pThis)
     1285                       + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period,
     1286                                                           hdaR3StreamDmaBufGetSize(pStreamShared)
     1287                                                         / pStreamR3->State.Mapping.cbGuestFrame),
     1288                       false /* fForce */);
     1289
     1290        /*
     1291         * Update the stream's current position.
     1292         *
     1293         * Do this as accurate and close to the actual data transfer as possible.
     1294         * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
     1295         *
     1296         * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated!
     1297         *                      Not doing this at the right time will result in ugly sound crackles!
     1298         */
     1299        hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaR3StreamDmaBufGetSize(pStreamShared));
     1300
     1301        /* Does the current BDLE require an interrupt to be sent? */
     1302        if (hdaR3StreamDmaBufNeedsIrq(pStreamShared))
     1303        {
     1304            /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL
     1305               register is set we need to generate an interrupt. */
     1306            if (HDA_STREAM_REG(pThis, CTL, pStreamShared->u8SD) & HDA_SDCTL_IOCE)
     1307            {
     1308                /* Assert the interrupt before actually fetching the next BDLE below. */
     1309                pStreamShared->State.cTransferPendingInterrupts = 1;
     1310                Log3(("%s: [SD%RU8] Scheduling interrupt\n", pszFunction, pStreamShared->u8SD));
     1311
     1312                /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
     1313                 * ending / beginning of a period. */
     1314                /** @todo r=bird: What does the above comment mean? */
     1315                HDA_STREAM_REG(pThis, STS, pStreamShared->u8SD) |= HDA_SDSTS_BCIS;
     1316                HDA_PROCESS_INTERRUPT(pDevIns, pThis);
     1317            }
     1318        }
     1319
     1320        /*
     1321         * Advance to the next BDLE.
     1322         */
     1323        hdaR3StreamDmaBufAdvanceToNext(pStreamShared);
     1324    }
     1325    else
     1326        Log3(("%s: [SD%RU8] Not completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x: off=%#RX32\n", pszFunction, pStreamShared->u8SD,
     1327              pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
     1328              pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
     1329              pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, pStreamShared->State.offCurBdle));
     1330}
     1331
     1332/**
    11421333 * Does DMA transfer for an HDA input stream.
    11431334 *
     
    11451336 * guest memory.
    11461337 *
    1147  * @returns IPRT status code.
    11481338 * @param   pDevIns             The device instance.
    11491339 * @param   pThis               The shared HDA device state.
     
    11641354 * @remarks Caller owns the stream lock.
    11651355 */
    1166 static int hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
    1167                                  PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs)
     1356static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
     1357                                  PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs)
    11681358{
    11691359    uint8_t const uSD = pStreamShared->u8SD;
    11701360    LogFlowFunc(("ENTER - #%u cbToConsume=%#x%s\n", uSD, cbToConsume, fWriteSilence ? " silence" : ""));
    11711361
    1172 
    1173     /*
    1174      * Check if we should skip town...
    1175      */
    1176 
    1177     /* Stream not running (anymore)? */
    1178     if (pStreamShared->State.fRunning)
     1362    /*
     1363     * Common prologue.
     1364     */
     1365    if (hdaR3StreamDoDmaPrologue(pDevIns, pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaInput"))
    11791366    { /* likely */ }
    11801367    else
    1181     {
    1182         Log3Func(("[SD%RU8] Not running, skipping transfer\n", uSD));
    1183         return VINF_SUCCESS;
    1184     }
    1185 
    1186     if (!(HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS))
    1187     { /* likely */ }
    1188     else
    1189     {
    1190         Log3Func(("[SD%RU8] BCIS bit set, skipping transfer\n", uSD));
    1191 #ifdef HDA_STRICT
    1192         /* Timing emulation bug or guest is misbehaving -- let me know. */
    1193         AssertMsgFailed(("BCIS bit for stream #%RU8 still set when it shouldn't\n", uSD));
    1194 #endif
    1195         return VINF_SUCCESS;
    1196     }
    1197 
    1198     /*
    1199      * Stream sanity checks.
    1200      */
    1201     /* Register sanity checks. */
    1202     Assert(uSD < HDA_MAX_STREAMS);
    1203     Assert(pStreamShared->u64BDLBase);
    1204     Assert(pStreamShared->u32CBL);
    1205     Assert(pStreamShared->u8FIFOS);
    1206 
    1207     /* State sanity checks. */
    1208     Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false);
    1209     Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning));
    1210 
    1211     /*
    1212      * Some timestamp stuff for logging/debugging.
    1213      */
    1214     /*const uint64_t tsNowNs = RTTimeNanoTS();*/
    1215     Log3Func(("[SD%RU8] tsDeltaNs=%'RU64 ns\n", uSD, tsNowNs - pStreamShared->State.tsLastTransferNs));
    1216     pStreamShared->State.tsLastTransferNs = tsNowNs;
    1217     pStreamShared->State.tsTransferLast   = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
    1218 
    1219     /*
    1220      * Set the FIFORDY bit on the stream while doing the transfer.
    1221      */
    1222     /** @todo r=bird: I don't get the HDA_SDSTS_FIFORDY logic.  Unless we're
    1223      *        assuming SMP guest and that it can get stream registers while we're
    1224      *        here.  Only it cannot do the later because we're sitting on the big
    1225      *        HDA device lock, see assertions in hdaR3Timer().  So, this is an
    1226      *        pointless guesture given that we clear it again after the loop. */
    1227     HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY;
     1368        return;
    12281369
    12291370    /*
     
    13931534
    13941535        /*
    1395          * Is the buffer descriptor complete.
     1536         * Complete the buffer if necessary (common with the output DMA code).
    13961537         */
    1397         if (hdaR3StreamDmaBufIsComplete(pStreamShared))
    1398         {
    1399             Log3Func(("[SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x\n",
    1400                       uSD, pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
    1401                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
    1402                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags));
    1403 
    1404             /* Make sure to also update the wall clock when a BDLE is complete.
    1405              * Needed for Windows 10 guests. */
    1406             /** @todo there is a rounding error here.   */
    1407             hdaR3WalClkSet(pThis, pThisCC,
    1408                              hdaWalClkGetCurrent(pThis)
    1409                            + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period,
    1410                                                                hdaR3StreamDmaBufGetSize(pStreamShared)
    1411                                                              / pStreamR3->State.Mapping.cbGuestFrame),
    1412                            false /* fForce */);
    1413 
    1414             /*
    1415              * Update the stream's current position.
    1416              *
    1417              * Do this as accurate and close to the actual data transfer as possible.
    1418              * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
    1419              *
    1420              * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated!
    1421              *                      Not doing this at the right time will result in ugly sound crackles!
    1422              */
    1423             hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaR3StreamDmaBufGetSize(pStreamShared));
    1424 
    1425             /* Does the current BDLE require an interrupt to be sent? */
    1426             if (hdaR3StreamDmaBufNeedsIrq(pStreamShared))
    1427             {
    1428                 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL
    1429                    register is set we need to generate an interrupt. */
    1430                 if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE)
    1431                 {
    1432                     /* Assert the interrupt before actually fetching the next BDLE below. */
    1433                     pStreamShared->State.cTransferPendingInterrupts = 1;
    1434                     Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD));
    1435 
    1436                     /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
    1437                      * ending / beginning of a period. */
    1438                     /** @todo r=bird: What does the above comment mean? */
    1439                     HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS;
    1440                     HDA_PROCESS_INTERRUPT(pDevIns, pThis);
    1441                 }
    1442             }
    1443 
    1444             /*
    1445              * Advance to the next BDLE.
    1446              */
    1447             hdaR3StreamDmaBufAdvanceToNext(pStreamShared);
    1448         }
    1449         else
    1450             Log3Func(("[SD%RU8] Not completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x: off=%#RX32\n",
    1451                       uSD, pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
    1452                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
    1453                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, pStreamShared->State.offCurBdle));
     1538        hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, "hdaR3StreamDoDmaInput");
    14541539    }
    14551540
     
    14581543
    14591544    /*
    1460      * Clear the (pointless) FIFORDY bit again.
    1461      */
    1462     HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY;
    1463 
    1464     /*
    1465      * Try updating the wall clock.
    1466      *
    1467      * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register
    1468      *         in order to determine the correct timing of the sound device. Other guests
    1469      *         like Windows 7 + 10 (or even more exotic ones like Haiku) will completely
    1470      *         ignore this.
    1471      *
    1472      * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic
    1473      *         fashion) this *will* upset guest device drivers and will completely fuck up the
    1474      *         sound output. Running VLC on the guest will tell!
    1475      */
    1476     uint32_t const cFramesProcessed = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbToConsume);
    1477     /** @todo this needs to go, but we need it for hdaR3WalClkGetMax below. */
    1478     hdaR3StreamPeriodInc(&pStreamShared->State.Period,
    1479                          RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period)));
    1480 
    1481     uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, cFramesProcessed);
    1482     uint64_t const uWallNew   = hdaWalClkGetCurrent(pThis) + cWallTicks;
    1483     uint64_t const uWallMax   = hdaR3WalClkGetMax(pThis, pThisCC);
    1484     bool const     fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, RT_MIN(uWallNew, uWallMax), false /* fForce */);
    1485     RT_NOREF(fWalClkSet);
     1545     * Common epilogue.
     1546     */
     1547    hdaR3StreamDoDmaEpilogue(pThis, pThisCC, pStreamShared, cbToConsume);
    14861548
    14871549    /*
    14881550     * Log and leave.
    14891551     */
    1490     Log3Func(("[SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
     1552    Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
    14911553              uSD, cbToConsume, pStreamShared->State.cbTransferSize, pStreamR3->State.offRead - cbToConsume,
    14921554              pStreamShared->State.cTransferPendingInterrupts));
    1493     return VINF_SUCCESS;
    14941555}
    14951556
     
    15751636 * internal DMA buffer.
    15761637 *
    1577  * @returns IPRT status code.
    15781638 * @param   pDevIns             The device instance.
    15791639 * @param   pThis               The shared HDA device state.
     
    15891649 * @remarks Caller owns the stream lock.
    15901650 */
    1591 static int hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
    1592                                   PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs)
     1651static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
     1652                                   PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs)
    15931653{
    15941654    uint8_t const uSD = pStreamShared->u8SD;
    15951655    LogFlowFunc(("ENTER - #%u cbToProduce=%#x\n", uSD, cbToProduce));
    15961656
    1597 
    1598     /*
    1599      * Check if we should skip town...
    1600      */
    1601 
    1602     /* Stream not running (anymore)? */
    1603     if (pStreamShared->State.fRunning)
     1657    /*
     1658     * Common prologue.
     1659     */
     1660    if (hdaR3StreamDoDmaPrologue(pDevIns, pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaOutput"))
    16041661    { /* likely */ }
    16051662    else
    1606     {
    1607         Log3Func(("[SD%RU8] Not running, skipping transfer\n", uSD));
    1608         return VINF_SUCCESS;
    1609     }
    1610 
    1611     if (!(HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS))
    1612     { /* likely */ }
    1613     else
    1614     {
    1615         Log3Func(("[SD%RU8] BCIS bit set, skipping transfer\n", uSD));
    1616 #ifdef HDA_STRICT
    1617         /* Timing emulation bug or guest is misbehaving -- let me know. */
    1618         AssertMsgFailed(("BCIS bit for stream #%RU8 still set when it shouldn't\n", uSD));
    1619 #endif
    1620         return VINF_SUCCESS;
    1621     }
    1622 
    1623     /*
    1624      * Stream sanity checks.
    1625      */
    1626     /* Register sanity checks. */
    1627     Assert(uSD < HDA_MAX_STREAMS);
    1628     Assert(pStreamShared->u64BDLBase);
    1629     Assert(pStreamShared->u32CBL);
    1630     Assert(pStreamShared->u8FIFOS);
    1631 
    1632     /* State sanity checks. */
    1633     Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false);
    1634     Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning));
    1635 
    1636     /*
    1637      * Some timestamp stuff for logging/debugging.
    1638      */
    1639     /*const uint64_t tsNowNs = RTTimeNanoTS();*/
    1640     Log3Func(("[SD%RU8] tsDeltaNs=%'RU64 ns\n", uSD, tsNowNs - pStreamShared->State.tsLastTransferNs));
    1641     pStreamShared->State.tsLastTransferNs = tsNowNs;
    1642     pStreamShared->State.tsTransferLast   = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
    1643 
    1644     /*
    1645      * Set the FIFORDY bit on the stream while doing the transfer.
    1646      */
    1647     /** @todo r=bird: I don't get the HDA_SDSTS_FIFORDY logic.  Unless we're
    1648      *        assuming SMP guest and that it can get stream registers while we're
    1649      *        here.  Only it cannot do the later because we're sitting on the big
    1650      *        HDA device lock, see assertions in hdaR3Timer().  So, this is an
    1651      *        pointless guesture given that we clear it again after the loop. */
    1652     HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY;
     1663        return;
    16531664
    16541665    /*
     
    18081819
    18091820        /*
    1810          * Is the buffer descriptor complete.
     1821         * Complete the buffer if necessary (common with the output DMA code).
    18111822         */
    1812         if (hdaR3StreamDmaBufIsComplete(pStreamShared))
    1813         {
    1814             Log3Func(("[SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x\n", uSD, pStreamShared->State.idxCurBdle,
    1815                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
    1816                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
    1817                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags));
    1818 
    1819             /* Make sure to also update the wall clock when a BDLE is complete.
    1820              * Needed for Windows 10 guests. */
    1821             /** @todo there is a rounding error here.   */
    1822             hdaR3WalClkSet(pThis, pThisCC,
    1823                              hdaWalClkGetCurrent(pThis)
    1824                            + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period,
    1825                                                                hdaR3StreamDmaBufGetSize(pStreamShared)
    1826                                                              / pStreamR3->State.Mapping.cbGuestFrame),
    1827                            false /* fForce */);
    1828 
    1829             /*
    1830              * Update the stream's current position.
    1831              *
    1832              * Do this as accurate and close to the actual data transfer as possible.
    1833              * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
    1834              *
    1835              * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated!
    1836              *                      Not doing this at the right time will result in ugly sound crackles!
    1837              */
    1838             hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaR3StreamDmaBufGetSize(pStreamShared));
    1839 
    1840             /* Does the current BDLE require an interrupt to be sent? */
    1841             if (hdaR3StreamDmaBufNeedsIrq(pStreamShared))
    1842             {
    1843                 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL
    1844                    register is set we need to generate an interrupt. */
    1845                 if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE)
    1846                 {
    1847                     /* Assert the interrupt before actually fetching the next BDLE below. */
    1848                     pStreamShared->State.cTransferPendingInterrupts = 1;
    1849                     Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD));
    1850 
    1851                     /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
    1852                      * ending / beginning of a period. */
    1853                     /** @todo r=bird: What does the above comment mean? */
    1854                     HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS;
    1855                     HDA_PROCESS_INTERRUPT(pDevIns, pThis);
    1856                 }
    1857             }
    1858 
    1859             /*
    1860              * Advance to the next BDLE.
    1861              */
    1862             hdaR3StreamDmaBufAdvanceToNext(pStreamShared);
    1863         }
    1864         else
    1865             Log3Func(("[SD%RU8] Not completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x: off=%#RX32\n",
    1866                       uSD, pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
    1867                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
    1868                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, pStreamShared->State.offCurBdle));
     1823        hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, "hdaR3StreamDoDmaOutput");
    18691824    }
    18701825
     
    18731828
    18741829    /*
    1875      * Clear the (pointless) FIFORDY bit again.
    1876      */
    1877     HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY;
    1878 
    1879     /*
    1880      * Try updating the wall clock.
    1881      *
    1882      * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register
    1883      *         in order to determine the correct timing of the sound device. Other guests
    1884      *         like Windows 7 + 10 (or even more exotic ones like Haiku) will completely
    1885      *         ignore this.
    1886      *
    1887      * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic
    1888      *         fashion) this *will* upset guest device drivers and will completely fuck up the
    1889      *         sound output. Running VLC on the guest will tell!
    1890      */
    1891     uint32_t const cFramesProcessed = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbToProduce);
    1892     /** @todo this needs to go, but we need it for hdaR3WalClkGetMax below. */
    1893     hdaR3StreamPeriodInc(&pStreamShared->State.Period,
    1894                          RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period)));
    1895 
    1896     uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, cFramesProcessed);
    1897     uint64_t const uWallNew   = hdaWalClkGetCurrent(pThis) + cWallTicks;
    1898     uint64_t const uWallMax   = hdaR3WalClkGetMax(pThis, pThisCC);
    1899     bool const     fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, RT_MIN(uWallNew, uWallMax), false /* fForce */);
    1900     RT_NOREF(fWalClkSet);
     1830     * Common epilogue.
     1831     */
     1832    hdaR3StreamDoDmaEpilogue(pThis, pThisCC, pStreamShared, cbToProduce);
    19011833
    19021834    /*
    19031835     * Log and leave.
    19041836     */
    1905     Log3Func(("[SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
     1837    Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
    19061838              uSD, cbToProduce, pStreamShared->State.cbTransferSize, pStreamR3->State.offWrite - cbToProduce,
    19071839              pStreamShared->State.cTransferPendingInterrupts));
    1908 
    1909     LogFlowFuncLeave();
    1910     return VINF_SUCCESS;
    1911 }
    1912 
     1840}
    19131841
    19141842/**
     
    21522080
    21532081            uint64_t const offWriteBefore = pStreamR3->State.offWrite;
    2154             rc2 = hdaR3StreamDoDmaOutput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
    2155             AssertRC(rc2);
     2082            hdaR3StreamDoDmaOutput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
    21562083
    21572084# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     
    23512278# endif
    23522279
    2353                 rc2 = hdaR3StreamDoDmaInput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3,
    2354                                             RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs);
    2355                 AssertRC(rc2);
     2280                hdaR3StreamDoDmaInput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3,
     2281                                      RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs);
    23562282
    23572283# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
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