Changeset 87863 in vbox
- Timestamp:
- Feb 24, 2021 5:25:23 PM (4 years ago)
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 4 edited
-
DevHDA.cpp (modified) (4 diffs)
-
DevHDACommon.cpp (modified) (1 diff)
-
DevHDACommon.h (modified) (1 diff)
-
HDAStream.cpp (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r87861 r87863 1152 1152 } 1153 1153 1154 #ifdef IN_RING31155 /**1156 * Returns the current maximum value the wall clock counter can be set to.1157 *1158 * This maximum value depends on all currently handled HDA streams and their own current timing.1159 *1160 * @return Current maximum value the wall clock counter can be set to.1161 * @param pThis The shared HDA device state.1162 * @param pThisCC The ring-3 HDA device state.1163 *1164 * @remark Does not actually set the wall clock counter.1165 *1166 * @todo r=bird: This function is in the wrong file.1167 */1168 static uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC)1169 {1170 const uint64_t u64WalClkCur = ASMAtomicReadU64(&pThis->u64WalClk);1171 const uint64_t u64FrontAbsWalClk = pThisCC->SinkFront.pStreamShared1172 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period) : 0;1173 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND1174 # error "Implement me!"1175 # endif1176 const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared1177 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;1178 # ifdef VBOX_WITH_HDA_MIC_IN1179 const uint64_t u64MicInAbsWalClk = pThisCC->SinkMicIn.pStreamShared1180 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period) : 0;1181 # endif1182 1183 uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);1184 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND1185 # error "Implement me!"1186 # endif1187 u64WalClkNew = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);1188 # ifdef VBOX_WITH_HDA_MIC_IN1189 u64WalClkNew = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);1190 # endif1191 1192 Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n",1193 u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew));1194 1195 return u64WalClkNew;1196 }1197 #endif /* IN_RING3 */1198 1199 1154 static VBOXSTRICTRC hdaRegReadWALCLK(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) 1200 1155 { … … 1522 1477 static VBOXSTRICTRC hdaRegWriteSDSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) 1523 1478 { 1524 #ifdef IN_RING31525 const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, STS, iReg);1526 AssertReturn(uSD < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */1527 PHDASTATER3 const pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);1528 PHDASTREAM const pStreamShared = &pThis->aStreams[uSD];1529 1530 /* We only need to take the virtual-sync lock if we want to call1531 PDMDevHlpTimerGet or hdaR3TimerSet later. Only precondition for that1532 is that we've got a non-zero ticks-per-transfer value. */1533 uint64_t const cTransferTicks = pStreamShared->State.cTransferTicks;1534 if (cTransferTicks)1535 {1536 DEVHDA_UNLOCK(pDevIns, pThis);1537 DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStreamShared, VINF_IOM_R3_MMIO_WRITE);1538 }1539 1540 hdaStreamLock(pStreamShared);1541 1542 1479 uint32_t v = HDA_REG_IND(pThis, iReg); 1543 1480 … … 1545 1482 HDA_REG_IND(pThis, iReg) &= ~(u32Value & v); 1546 1483 1547 /** @todo r=bird: Check if we couldn't this stuff involving hdaR3StreamPeriodLock1548 * and IRQs after PDMDevHlpTimerUnlockClock. */1549 1550 /*1551 * ...1552 */1553 /* Some guests tend to write SDnSTS even if the stream is not running.1554 * So make sure to check if the RUN bit is set first. */1555 const bool fRunning = pStreamShared->State.fRunning;1556 1557 Log3Func(("[SD%RU8] fRunning=%RTbool %R[sdsts]\n", uSD, fRunning, v));1558 1559 PHDASTREAMPERIOD pPeriod = &pStreamShared->State.Period;1560 if (hdaR3StreamPeriodNeedsInterrupt(pPeriod))1561 hdaR3StreamPeriodReleaseInterrupt(pPeriod);1562 if (hdaR3StreamPeriodIsComplete(pPeriod))1563 {1564 /* Make sure to try to update the WALCLK register if a period is complete.1565 * Use the maximum WALCLK value all (active) streams agree to. */1566 const uint64_t uWalClkMax = hdaR3WalClkGetMax(pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3));1567 if (uWalClkMax > hdaWalClkGetCurrent(pThis))1568 hdaR3WalClkSet(pThis, pThisCC, uWalClkMax, false /* fForce */);1569 1570 hdaR3StreamPeriodEnd(pPeriod);1571 1572 if (fRunning)1573 hdaR3StreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis) /* Use current wall clock time */);1574 }1575 1576 1484 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 1577 1485 1578 /*1579 * ...1580 */1581 uint64_t cTicksToNext = pStreamShared->State.cTransferTicks;1582 if (cTicksToNext) /* Only do any calculations if the stream currently is set up for transfers. */1583 {1584 const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);1585 if (!pStreamShared->State.tsTransferLast)1586 pStreamShared->State.tsTransferLast = tsNow;1587 Assert(tsNow >= pStreamShared->State.tsTransferLast);1588 1589 const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast;1590 1591 Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksToNext=%RU64\n",1592 uSD, cTicksElapsed, cTicksToNext));1593 1594 if (cTicksElapsed <= cTicksToNext)1595 cTicksToNext = cTicksToNext - cTicksElapsed;1596 else /* Catch up. */1597 {1598 Log3Func(("[SD%RU8] Warning: Lagging behind (%RU64 ticks elapsed, maximum allowed is %RU64)\n",1599 uSD, cTicksElapsed, cTicksToNext));1600 1601 LogRelMax2(128, ("HDA: Stream #%RU8 interrupt lagging behind (expected %RU64us, got %RU64us, %RU8 pending interrupts), trying to catch up ...\n",1602 uSD, cTicksToNext / 1000, cTicksElapsed / 1000, pStreamShared->State.cTransferPendingInterrupts));1603 1604 cTicksToNext = pStreamShared->State.cbTransferSize * pStreamShared->State.cTicksPerByte;1605 }1606 1607 Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", uSD, cTicksToNext));1608 1609 /* Reset processed data counter. */1610 pStreamShared->State.tsTransferNext = tsNow + cTicksToNext;1611 1612 /* Only re-arm the timer if there were pending transfer interrupts left1613 * -- it could happen that we land in here if a guest writes to SDnSTS1614 * unconditionally. */1615 if (pStreamShared->State.cTransferPendingInterrupts)1616 {1617 pStreamShared->State.cTransferPendingInterrupts--;1618 1619 /* Re-arm the timer. */1620 LogFunc(("[SD%RU8] Timer set\n", uSD));1621 hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext,1622 true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/);1623 }1624 }1625 1626 if (cTransferTicks)1627 PDMDevHlpTimerUnlockClock(pDevIns, pStreamShared->hTimer); /* Caller will unlock pThis->CritSect. */1628 hdaStreamUnlock(pStreamShared);1629 1486 return VINF_SUCCESS; 1630 #else /* !IN_RING3 */1631 RT_NOREF(pDevIns, pThis, iReg, u32Value);1632 return VINF_IOM_R3_MMIO_WRITE;1633 #endif /* !IN_RING3 */1634 1487 } 1635 1488 … … 2812 2665 const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow); 2813 2666 2814 Log3Func(("[SD%RU8] fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", uSD, fSinkActive, fTimerScheduled)); 2815 2816 if (!fTimerScheduled) 2817 { 2818 if (!pStreamShared->State.tsTransferLast) /* Never did a transfer before? Initialize with current time. */ 2819 pStreamShared->State.tsTransferLast = tsNow; 2820 2821 Assert(tsNow >= pStreamShared->State.tsTransferLast); 2822 2823 /* How many ticks have passed since the last transfer? */ 2824 const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast; 2825 2826 uint64_t cTicksToNext; 2827 if (cTicksElapsed == 0) /* We just ran in the same timing slot? */ 2828 { 2829 /* Schedule a transfer at the next regular timing slot. */ 2830 cTicksToNext = pStreamShared->State.cTransferTicks; 2831 } 2832 else 2833 { 2834 /* Some time since the last transfer has passed already; take this into account. */ 2835 if (pStreamShared->State.cTransferTicks >= cTicksElapsed) 2836 { 2837 cTicksToNext = pStreamShared->State.cTransferTicks - cTicksElapsed; 2838 } 2839 else /* Catch up as soon as possible. */ 2840 cTicksToNext = 0; 2841 } 2842 2843 Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferLast=%RU64, cTicksElapsed=%RU64 -> cTicksToNext=%RU64\n", 2844 uSD, tsNow, pStreamShared->State.tsTransferLast, cTicksElapsed, cTicksToNext)); 2845 2846 /* Note: cTicksToNext can be 0, which means we have to run *now*. */ 2847 hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext, 2848 true /*fForce*/, 0 /* tsNow */); 2849 } 2667 uint64_t tsTransferNext = 0; 2668 if (fTimerScheduled) 2669 { 2670 Assert(pStreamShared->State.tsTransferNext); /* Make sure that a new transfer timestamp is set. */ 2671 tsTransferNext = pStreamShared->State.tsTransferNext; 2672 } 2673 else /* Schedule at the precalculated rate. */ 2674 tsTransferNext = tsNow + pStreamShared->State.cTransferTicks; 2675 2676 Log3Func(("[SD%RU8] fSinksActive=%RTbool, fTimerScheduled=%RTbool, tsTransferNext=%RU64 (in %RU64)\n", 2677 uSD, fSinkActive, fTimerScheduled, tsTransferNext, tsTransferNext - tsNow)); 2678 2679 /* Note: tsTransferNext can be 0, which means we have to run *now*. */ 2680 hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext, 2681 true /*fForce*/, tsNow); 2850 2682 } 2851 2683 else -
trunk/src/VBox/Devices/Audio/DevHDACommon.cpp
r87328 r87863 129 129 return &pStream->State.Period; 130 130 return NULL; 131 } 132 133 /** 134 * Returns the current maximum value the wall clock counter can be set to. 135 * 136 * This maximum value depends on all currently handled HDA streams and their own current timing. 137 * 138 * @return Current maximum value the wall clock counter can be set to. 139 * @param pThis The shared HDA device state. 140 * @param pThisCC The ring-3 HDA device state. 141 * 142 * @remark Does not actually set the wall clock counter. 143 * 144 */ 145 uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC) 146 { 147 const uint64_t u64WalClkCur = ASMAtomicReadU64(&pThis->u64WalClk); 148 const uint64_t u64FrontAbsWalClk = pThisCC->SinkFront.pStreamShared 149 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period) : 0; 150 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 151 # error "Implement me!" 152 # endif 153 const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared 154 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0; 155 # ifdef VBOX_WITH_HDA_MIC_IN 156 const uint64_t u64MicInAbsWalClk = pThisCC->SinkMicIn.pStreamShared 157 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period) : 0; 158 # endif 159 160 uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk); 161 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 162 # error "Implement me!" 163 # endif 164 u64WalClkNew = RT_MAX(u64WalClkNew, u64LineInAbsWalClk); 165 # ifdef VBOX_WITH_HDA_MIC_IN 166 u64WalClkNew = RT_MAX(u64WalClkNew, u64MicInAbsWalClk); 167 # endif 168 169 Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n", 170 u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew)); 171 172 return u64WalClkNew; 131 173 } 132 174 -
trunk/src/VBox/Devices/Audio/DevHDACommon.h
r87758 r87863 633 633 uint64_t hdaWalClkGetCurrent(PHDASTATE pThis); 634 634 #ifdef IN_RING3 635 uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC); 635 636 bool hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce); 636 637 #endif -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r87836 r87863 694 694 * Second, initialize the registers. 695 695 */ 696 HDA_STREAM_REG(pThis, STS, uSD) = HDA_SDSTS_FIFORDY; 696 /* See 6.2.33: Clear on reset. */ 697 HDA_STREAM_REG(pThis, STS, uSD) = 0; 697 698 /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20 698 699 * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */ … … 1189 1190 */ 1190 1191 bool fInterruptSent = false; 1192 1193 /* Set the FIFORDY bit on the stream while doing the transfer. */ 1194 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY; 1191 1195 1192 1196 while (cbLeft) … … 1465 1469 if (!fInterruptSent) 1466 1470 { 1467 pStreamShared->State.cTransferPendingInterrupts ++;1471 pStreamShared->State.cTransferPendingInterrupts = 1; 1468 1472 1469 1473 AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32, … … 1513 1517 break; 1514 1518 } 1519 1520 /* Remove the FIFORDY bit again. */ 1521 HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY; 1515 1522 1516 1523 /* Sanity. */ … … 1544 1551 */ 1545 1552 const bool fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, 1546 hdaWalClkGetCurrent(pThis) 1547 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 1548 cbProcessed 1549 / pStreamR3->State.Mapping.cbFrameSize), 1553 RT_MIN( hdaWalClkGetCurrent(pThis) 1554 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 1555 cbProcessed 1556 / pStreamR3->State.Mapping.cbFrameSize), 1557 hdaR3WalClkGetMax(pThis, pThisCC)), 1550 1558 false /* fForce */); 1551 1559 RT_NOREF(fWalClkSet); 1552 1560 } 1553 1561 1554 /* Does the period have any interrupts outstanding? */ 1555 if (!pStreamShared->State.cTransferPendingInterrupts) 1556 { 1557 /* No, set relative timer ticks for the next transfer to happen. 1558 * This must happen at a constant rate. */ 1559 tsTransferNext = tsNow + pStreamShared->State.cTransferTicks; 1560 } 1562 /* Set the next transfer timing slot. 1563 * This must happen at a constant rate. */ 1564 tsTransferNext = tsNow + pStreamShared->State.cTransferTicks; 1561 1565 1562 1566 /* If we need to do another transfer, (re-)arm the device timer. */ 1563 1567 if (tsTransferNext) /* Can be 0 if no next transfer is needed. */ 1564 1568 { 1565 Log3Func(("[SD%RU8] Scheduling timer @ %RU64 \n", uSD, tsTransferNext));1569 Log3Func(("[SD%RU8] Scheduling timer @ %RU64 (in %RU64 ticks)\n", uSD, tsTransferNext, tsTransferNext - tsNow)); 1566 1570 1567 1571 /* Make sure to assign next transfer timestamp before setting the timer. */ 1572 Assert(tsTransferNext > tsNow); 1568 1573 pStreamShared->State.tsTransferNext = tsTransferNext; 1569 1574 … … 1573 1578 } 1574 1579 1580 /* Always update this timestamp, no matter what pStreamShared->State.tsTransferNext is. */ 1575 1581 pStreamShared->State.tsTransferLast = tsNow; 1576 1582 … … 1738 1744 if (cbSinkReadable) 1739 1745 { 1740 uint8_t *pabFIFO = pStreamShared->abFIFO; 1746 void *pvFIFO = &pStreamShared->abFIFO[0]; 1747 uint32_t cbFIFO = (uint32_t)sizeof(pStreamShared->abFIFO); 1741 1748 1742 1749 while (cbSinkReadable) … … 1744 1751 uint32_t cbRead; 1745 1752 rc2 = AudioMixerSinkRead(pSink, AUDMIXOP_COPY, 1746 p abFIFO, RT_MIN(cbSinkReadable, (uint32_t)sizeof(pStreamShared->abFIFO)), &cbRead);1753 pvFIFO, RT_MIN(cbSinkReadable, cbFIFO), &cbRead); 1747 1754 AssertRCBreak(rc2); 1748 1755 1749 1756 if (!cbRead) 1750 1757 { 1751 #ifdef HDA_STRICT1752 1758 AssertMsgFailed(("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbSinkReadable)); 1753 #endif1754 1759 break; 1755 1760 } … … 1757 1762 /* Write (guest input) data to the stream which was read from stream's sink before. */ 1758 1763 uint32_t cbWritten; 1759 rc2 = hdaR3StreamWrite(pStreamR3, p abFIFO, cbRead, &cbWritten);1764 rc2 = hdaR3StreamWrite(pStreamR3, pvFIFO, cbRead, &cbWritten); 1760 1765 AssertRCBreak(rc2); 1761 1766 AssertBreak(cbWritten > 0); /* Should never happen, as we know how much we can write. */
Note:
See TracChangeset
for help on using the changeset viewer.

