Changeset 89861 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Jun 23, 2021 2:23:42 PM (4 years ago)
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHda.cpp
r89856 r89861 1035 1035 { 1036 1036 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; 1043 1131 return VINF_SUCCESS; 1044 1132 } … … 3983 4071 rc = pHlp->pfnSSMGetMem(pSSM, pvBuf, cbBuf); 3984 4072 AssertRCReturn(rc, rc); 3985 pStream R3->State.offWrite = cbCircBufUsed;4073 pStreamShared->State.offWrite = cbCircBufUsed; 3986 4074 3987 4075 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbBuf); … … 4965 5053 for (size_t i = 0; i < HDA_MAX_STREAMS; i++) 4966 5054 { 4967 /* We need the first timer in ring-0 to calculate the wall clock (WALCLK) time. */4968 5055 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); 4971 5057 AssertRCReturn(rc, rc); 4972 5058 … … 5062 5148 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "Input", STAMUNIT_TICKS_PER_CALL, "Profiling input."); 5063 5149 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 5066 5156 5067 5157 AssertCompile(RT_ELEMENTS(g_aHdaRegMap) == HDA_NUM_REGS); … … 5110 5200 "DMA transfer period skipped because of BCIS pending.", "Stream%u/DMASkippedPendingBCIS", idxStream); 5111 5201 5112 PDMDevHlpSTAMRegisterF(pDevIns, &pThis CC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,5202 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES, 5113 5203 "Virtual internal buffer read position.", "Stream%u/offRead", idxStream); 5114 PDMDevHlpSTAMRegisterF(pDevIns, &pThis CC->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,5204 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES, 5115 5205 "Virtual internal buffer write position.", "Stream%u/offWrite", idxStream); 5116 5206 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.cbTransferSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES, -
trunk/src/VBox/Devices/Audio/DevHda.h
r89638 r89861 146 146 HDACODEC Codec; 147 147 148 #ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA 149 STAMCOUNTER StatAccessDmaOutput; 150 STAMCOUNTER StatAccessDmaOutputToR3; 151 #endif 148 152 #ifdef VBOX_WITH_STATISTICS 149 153 STAMPROFILE StatIn; -
trunk/src/VBox/Devices/Audio/DevHdaStream.cpp
r89859 r89861 40 40 #endif 41 41 42 #ifdef IN_RING3 /* whole file */43 44 42 45 43 /********************************************************************************************************************************* 46 44 * Internal Functions * 47 45 *********************************************************************************************************************************/ 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 46 static void hdaStreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB); 47 #ifdef IN_RING3 48 # ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA 49 static void hdaR3StreamFlushDmaBounceBufferOutput(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3); 50 # endif 51 static uint32_t hdaR3StreamHandleDmaBufferOverrun(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink, 52 uint32_t cbNeeded, uint64_t nsNow, 53 const char *pszCaller, uint32_t const cbStreamFree); 54 static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, 55 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3); 56 #endif 57 58 59 #ifdef IN_RING3 53 60 54 61 /** … … 687 694 688 695 /* 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. */ 692 698 pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz; 693 699 LogRel2(("HDA: Stream #%RU8 set scheduling hint for the backends to %RU32ms\n", uSD, pCfg->Device.cMsSchedulingHint)); … … 695 701 696 702 /* 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)); 698 708 699 709 # ifdef LOG_ENABLED … … 714 724 pStreamR3->State.StatDmaBufUsed = 0; 715 725 } 716 pStream R3->State.offWrite = 0;717 pStream R3->State.offRead = 0;726 pStreamShared->State.offWrite = 0; 727 pStreamShared->State.offRead = 0; 718 728 719 729 /* … … 878 888 if (pStreamR3->State.pCircBuf) 879 889 RTCircBufReset(pStreamR3->State.pCircBuf); 880 pStream R3->State.offWrite = 0;881 pStream R3->State.offRead = 0;890 pStreamShared->State.offWrite = 0; 891 pStreamShared->State.offRead = 0; 882 892 883 893 # ifdef DEBUG … … 1023 1033 } 1024 1034 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 */ 1032 1036 1033 1037 /** … … 1040 1044 * @param uLPIB Absolute position (in bytes) to set current read / write position to. 1041 1045 */ 1042 static void hda R3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB)1046 static void hdaStreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB) 1043 1047 { 1044 1048 AssertPtrReturnVoid(pStreamShared); … … 1053 1057 if (pThis->fDMAPosition) 1054 1058 { 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 */ 1055 1072 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, 1056 1073 pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)), … … 1071 1088 * @param cbToAdd Position (in bytes) to add to the current read / write position. 1072 1089 */ 1073 static void hda R3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t cbToAdd)1090 static void hdaStreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t cbToAdd) 1074 1091 { 1075 1092 if (cbToAdd) /* No need to update anything if 0. */ … … 1086 1103 uNewLpid %= uCBL; 1087 1104 #endif 1088 hda R3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, uNewLpid);1105 hdaStreamSetPositionAbs(pStreamShared, pDevIns, pThis, uNewLpid); 1089 1106 } 1090 1107 } 1091 1108 } 1109 1110 #ifdef IN_RING3 1092 1111 1093 1112 /** … … 1121 1140 } 1122 1141 1142 #endif /* IN_RING3 */ 1143 1123 1144 /** 1124 1145 * Get the current address and number of bytes left in the current BDLE. … … 1128 1149 * @param pcbLeft The number of bytes left at the returned address. 1129 1150 */ 1130 DECLINLINE(RTGCPHYS) hda R3StreamDmaBufGet(PHDASTREAM pStreamShared, uint32_t *pcbLeft)1151 DECLINLINE(RTGCPHYS) hdaStreamDmaBufGet(PHDASTREAM pStreamShared, uint32_t *pcbLeft) 1131 1152 { 1132 1153 uint8_t idxBdle = pStreamShared->State.idxCurBdle; … … 1147 1168 * @param pStreamShared The stream to check. 1148 1169 */ 1149 DECLINLINE(RTGCPHYS) hda R3StreamDmaBufGetSize(PHDASTREAM pStreamShared)1170 DECLINLINE(RTGCPHYS) hdaStreamDmaBufGetSize(PHDASTREAM pStreamShared) 1150 1171 { 1151 1172 uint8_t idxBdle = pStreamShared->State.idxCurBdle; … … 1161 1182 * @param pStreamShared The stream to check. 1162 1183 */ 1163 DECLINLINE(bool) hda R3StreamDmaBufIsComplete(PHDASTREAM pStreamShared)1184 DECLINLINE(bool) hdaStreamDmaBufIsComplete(PHDASTREAM pStreamShared) 1164 1185 { 1165 1186 uint8_t const idxBdle = pStreamShared->State.idxCurBdle; … … 1179 1200 * @param pStreamShared The stream to check. 1180 1201 */ 1181 DECLINLINE(bool) hda R3StreamDmaBufNeedsIrq(PHDASTREAM pStreamShared)1202 DECLINLINE(bool) hdaStreamDmaBufNeedsIrq(PHDASTREAM pStreamShared) 1182 1203 { 1183 1204 uint8_t const idxBdle = pStreamShared->State.idxCurBdle; … … 1191 1212 * @param pStreamShared The stream which DMA engine is to be updated. 1192 1213 */ 1193 DECLINLINE(void) hda R3StreamDmaBufAdvanceToNext(PHDASTREAM pStreamShared)1214 DECLINLINE(void) hdaStreamDmaBufAdvanceToNext(PHDASTREAM pStreamShared) 1194 1215 { 1195 1216 uint8_t idxBdle = pStreamShared->State.idxCurBdle; … … 1203 1224 pStreamShared->State.offCurBdle = 0; 1204 1225 } 1226 1227 #ifdef IN_RING3 1205 1228 1206 1229 /** … … 1307 1330 } 1308 1331 1332 #endif /* IN_RING3 */ 1333 1309 1334 /** 1310 1335 * Completes a BDLE at the end of a DMA loop iteration, if possible. 1311 1336 * 1337 * @retval true if buffer completed and new loaded. 1338 * @retval false if buffer not completed. 1312 1339 * @param pDevIns The device instance. 1313 1340 * @param pThis The shared HDA device state. … … 1315 1342 * @param pszFunction The function name (for logging). 1316 1343 */ 1317 DECLINLINE( void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis,1318 1344 DECLINLINE(bool) hdaStreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis, 1345 PHDASTREAM pStreamShared, const char *pszFunction) 1319 1346 { 1320 1347 RT_NOREF(pszFunction); … … 1323 1350 * Is the buffer descriptor complete. 1324 1351 */ 1325 if (hda R3StreamDmaBufIsComplete(pStreamShared))1352 if (hdaStreamDmaBufIsComplete(pStreamShared)) 1326 1353 { 1327 1354 Log3(("%s: [SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x\n", pszFunction, pStreamShared->u8SD, … … 1330 1357 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags)); 1331 1358 1359 #if 0 /* Moved to the transfer loops */ 1332 1360 /* 1333 1361 * Update the stream's current position. … … 1339 1367 * Not doing this at the right time will result in ugly sound crackles! 1340 1368 */ 1341 hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaR3StreamDmaBufGetSize(pStreamShared)); 1369 hdaStreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaStreamDmaBufGetSize(pStreamShared)); 1370 #endif 1342 1371 1343 1372 /* Does the current BDLE require an interrupt to be sent? */ 1344 if (hda R3StreamDmaBufNeedsIrq(pStreamShared))1373 if (hdaStreamDmaBufNeedsIrq(pStreamShared)) 1345 1374 { 1346 1375 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL … … 1363 1392 * Advance to the next BDLE. 1364 1393 */ 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 1373 1406 1374 1407 /** … … 1396 1429 */ 1397 1430 static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, 1398 PHDASTREAMR3 pStreamR3, uint32_t c bToConsume, bool fWriteSilence, uint64_t tsNowNs)1431 PHDASTREAMR3 pStreamR3, uint32_t const cbToConsume, bool fWriteSilence, uint64_t tsNowNs) 1399 1432 { 1400 1433 uint8_t const uSD = pStreamShared->u8SD; … … 1429 1462 */ 1430 1463 uint32_t cbChunk = 0; 1431 RTGCPHYS GCPhys = hda R3StreamDmaBufGet(pStreamShared, &cbChunk);1464 RTGCPHYS GCPhys = hdaStreamDmaBufGet(pStreamShared, &cbChunk); 1432 1465 1433 1466 /* If we're writing silence. */ 1467 uint32_t cbWritten = 0; 1434 1468 if (!fWriteSilence) 1435 1469 { … … 1462 1496 1463 1497 # ifdef VBOX_WITH_DTRACE 1464 VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBufSrc, pStream R3->State.offRead);1498 VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBufSrc, pStreamShared->State.offRead); 1465 1499 # endif 1466 pStream R3->State.offRead += cbBufSrc;1500 pStreamShared->State.offRead += cbBufSrc; 1467 1501 RTCircBufReleaseReadBlock(pCircBuf, cbBufSrc); 1468 STAM_COUNTER_ADD(&pThis->StatBytes Read, cbBufSrc);1502 STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbBufSrc); 1469 1503 1470 1504 /* advance */ 1471 1505 cbChunk -= (uint32_t)cbBufSrc; 1506 cbWritten += (uint32_t)cbBufSrc; 1472 1507 GCPhys += cbBufSrc; 1473 cbLeft -= (uint32_t)cbBufSrc;1474 1508 pStreamShared->State.offCurBdle += (uint32_t)cbBufSrc; 1475 1509 } … … 1508 1542 uint32_t cFrames = PDMAudioPropsBytesToFrames(pGuestProps, RT_MIN(cbGuest, sizeof(abBounce) - cbBounce)); 1509 1543 1510 size_t cbBufSrc = PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFrames);1511 1544 cbGuest = PDMAudioPropsFramesToBytes(pGuestProps, cFrames); 1512 1545 PDMAudioPropsClearBuffer(pGuestProps, &abBounce[cbBounce], cbGuest, cFrames); … … 1517 1550 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, abBounce, cbGuestActual); 1518 1551 AssertRC(rc2); 1519 STAM_COUNTER_ADD(&pThis->StatBytes Read, cbGuestActual);1552 STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbGuestActual); 1520 1553 1521 1554 /* advance */ 1522 cb Left -= (uint32_t)cbBufSrc;1555 cbWritten += cbGuestActual; 1523 1556 cbChunk -= cbGuestActual; 1524 1557 GCPhys += cbGuestActual; … … 1531 1564 Log5Func((" loop1: GCPhys=%RGp cbGuestActual=%#x cbBounce=%#x cFrames=%#x\n", GCPhys, cbGuestActual, cbBounce, cFrames)); 1532 1565 } 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)); 1534 1567 } 1535 1568 1569 cbLeft -= cbWritten; 1536 1570 STAM_PROFILE_STOP(&pThis->StatIn, a); 1537 1571 1538 1572 /* 1539 1573 * 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). 1540 1580 */ 1541 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaInput"); 1581 hdaStreamSetPositionAdd(pStreamShared, pDevIns, pThis, cbWritten); 1582 hdaStreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaInput"); 1542 1583 } 1543 1584 … … 1554 1595 */ 1555 1596 Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n", 1556 uSD, cbToConsume, pStreamShared->State.cbTransferSize, pStream R3->State.offRead - cbToConsume,1597 uSD, cbToConsume, pStreamShared->State.cbTransferSize, pStreamShared->State.offRead - cbToConsume, 1557 1598 pStreamShared->State.cTransferPendingInterrupts)); 1558 1599 } … … 1563 1604 * buffer. 1564 1605 * 1606 * @param pStreamShared HDA stream to update (shared). 1565 1607 * @param pStreamR3 HDA stream to update (ring-3 bits). 1566 1608 * @param pSink The mixer sink to pull from. 1567 1609 */ 1568 static void hdaR3StreamPullFromMixer(PHDASTREAM R3 pStreamR3, PAUDMIXSINK pSink)1610 static void hdaR3StreamPullFromMixer(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink) 1569 1611 { 1570 1612 # ifdef LOG_ENABLED 1571 uint64_t const offWriteOld = pStream R3->State.offWrite;1613 uint64_t const offWriteOld = pStreamShared->State.offWrite; 1572 1614 # endif 1573 pStream R3->State.offWrite = AudioMixerSinkTransferToCircBuf(pSink,1574 pStreamR3->State.pCircBuf,1575 pStreamR3->State.offWrite,1576 pStreamR3->u8SD,1577 pStreamR3->Dbg.Runtime.fEnabled1578 ? 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); 1579 1621 1580 1622 Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD, 1581 pStream R3->State.offWrite - offWriteOld, pStreamR3->State.offWrite));1623 pStreamShared->State.offWrite - offWriteOld, pStreamShared->State.offWrite)); 1582 1624 1583 1625 /* Update buffer stats. */ … … 1605 1647 */ 1606 1648 static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, 1607 PHDASTREAMR3 pStreamR3, uint32_t c bToProduce, uint64_t tsNowNs)1649 PHDASTREAMR3 pStreamR3, uint32_t const cbToProduce, uint64_t tsNowNs) 1608 1650 { 1609 1651 uint8_t const uSD = pStreamShared->u8SD; … … 1629 1671 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf; 1630 1672 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 1631 1676 Assert(cbLeft == pStreamShared->State.cbTransferSize); 1677 # endif 1632 1678 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft)); 1633 1679 … … 1640 1686 */ 1641 1687 uint32_t cbChunk = 0; 1642 RTGCPHYS GCPhys = hda R3StreamDmaBufGet(pStreamShared, &cbChunk);1688 RTGCPHYS GCPhys = hdaStreamDmaBufGet(pStreamShared, &cbChunk); 1643 1689 1644 1690 /* Need to diverge if the BDLEs contain misaligned entries. */ 1691 uint32_t cbRead = 0; 1645 1692 # if 0 1646 1693 if (/** @todo pStreamShared->State.fFrameAlignedBuffers */) … … 1675 1722 1676 1723 # ifdef VBOX_WITH_DTRACE 1677 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBufDst, pStream R3->State.offWrite);1724 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBufDst, pStreamShared->State.offWrite); 1678 1725 # endif 1679 pStream R3->State.offWrite+= cbBufDst;1726 pStreamShared->State.offWrite += cbBufDst; 1680 1727 RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst); 1681 1728 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufDst); … … 1683 1730 /* advance */ 1684 1731 cbChunk -= (uint32_t)cbBufDst; 1732 cbRead += (uint32_t)cbBufDst; 1685 1733 GCPhys += cbBufDst; 1686 cbLeft -= (uint32_t)cbBufDst;1687 1734 pStreamShared->State.offCurBdle += (uint32_t)cbBufDst; 1688 1735 } … … 1779 1826 # endif 1780 1827 1828 cbLeft -= cbRead; 1781 1829 STAM_PROFILE_STOP(&pThis->StatOut, a); 1782 1830 1783 1831 /* 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). 1785 1839 */ 1786 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaOutput"); 1840 hdaStreamSetPositionAdd(pStreamShared, pDevIns, pThis, cbRead); 1841 hdaStreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaOutput"); 1787 1842 } 1788 1843 … … 1801 1856 */ 1802 1857 Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n", 1803 uSD, cbToProduce, pStreamShared->State.cbTransferSize, pStream R3->State.offWrite - cbToProduce,1858 uSD, cbToProduce, pStreamShared->State.cbTransferSize, pStreamShared->State.offWrite - cbToProduce, 1804 1859 pStreamShared->State.cTransferPendingInterrupts)); 1805 1860 } 1806 1861 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 */ 1874 VBOXSTRICTRC 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 1807 2001 1808 2002 /** … … 1817 2011 { 1818 2012 # ifdef LOG_ENABLED 1819 uint64_t const offReadOld = pStream R3->State.offRead;2013 uint64_t const offReadOld = pStreamShared->State.offRead; 1820 2014 # endif 1821 pStream R3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink,1822 pStreamR3->State.pCircBuf,1823 pStreamR3->State.offRead,1824 pStreamR3->u8SD,1825 pStreamR3->Dbg.Runtime.fEnabled1826 ? 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); 1827 2021 1828 2022 Assert(nsNow >= pStreamShared->State.tsLastReadNs); 1829 2023 Log3Func(("[SD%RU8] nsDeltaLastRead=%RI64 transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD, 1830 nsNow - pStreamShared->State.tsLastReadNs, pStream R3->State.offRead - offReadOld, pStreamR3->State.offRead));2024 nsNow - pStreamShared->State.tsLastReadNs, pStreamShared->State.offRead - offReadOld, pStreamShared->State.offRead)); 1831 2025 RT_NOREF(pStreamShared, nsNow); 1832 2026 … … 1834 2028 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf); 1835 2029 } 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 */ 2046 static 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 */ 2105 static 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 */ 1836 2173 1837 2174 … … 1944 2281 uint32_t idxSched = pStreamShared->State.idxSchedule; 1945 2282 AssertStmt(idxSched < RT_MIN(RT_ELEMENTS(pStreamShared->State.aSchedule), pStreamShared->State.cSchedule), idxSched = 0); 1946 uint32_t constcbPeriod = pStreamShared->State.aSchedule[idxSched].cbPeriod;2283 uint32_t cbPeriod = pStreamShared->State.aSchedule[idxSched].cbPeriod; 1947 2284 1948 2285 /* … … 1951 2288 if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) 1952 2289 { 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 1953 2304 /* 1954 2305 * Check how much room we have in our DMA buffer. There should be at … … 1959 2310 { /* likely */ } 1960 2311 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); 1994 2314 1995 2315 /* 1996 2316 * Do the DMA transfer. 1997 2317 */ 1998 uint64_t const offWriteBefore = pStream R3->State.offWrite;2318 uint64_t const offWriteBefore = pStreamShared->State.offWrite; 1999 2319 hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs); 2000 2320 … … 2012 2332 bool fKickAioThread; 2013 2333 if (!pStreamShared->State.tsAioDelayEnd) 2014 fKickAioThread = pStream R3->State.offWrite > offWriteBefore2334 fKickAioThread = pStreamShared->State.offWrite > offWriteBefore 2015 2335 || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2; 2016 2336 else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd) … … 2101 2421 { 2102 2422 AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod); 2103 hdaR3StreamPullFromMixer(pStream R3, pSink);2423 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2104 2424 AudioMixerSinkUnlock(pSink); 2105 2425 } … … 2122 2442 if (cbStreamUsed < cbPeriod) 2123 2443 { 2124 hdaR3StreamPullFromMixer(pStream R3, pSink);2444 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2125 2445 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2126 2446 while (cbStreamUsed < cbPeriod) … … 2209 2529 { 2210 2530 Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN); 2211 hdaR3StreamPullFromMixer(pStream R3, pSink);2531 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2212 2532 } 2213 2533 } -
trunk/src/VBox/Devices/Audio/DevHdaStream.h
r89853 r89861 111 111 * @note This is used for wall clock (WALCLK) calculations. */ 112 112 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 * @{ */ 113 130 /** Timestamp (absolute, in timer ticks) of the next DMA data transfer. 114 131 * Next for determining the next scheduling window. … … 119 136 /** The size of an average transfer. */ 120 137 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 138 144 /** The offset into the current BDLE. */ 139 145 uint32_t offCurBdle; … … 181 187 uint8_t abPadding[2]; 182 188 } 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 183 200 /** @} */ 184 201 } HDASTREAMSTATE; 185 AssertCompileSizeAlignment(HDASTREAMSTATE, 8);202 AssertCompileSizeAlignment(HDASTREAMSTATE, 16); 186 203 AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 8); 187 204 AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 16); … … 236 253 TMTIMERHANDLE hTimer; 237 254 255 #if 0 238 256 /** Pad the structure size to a 64 byte alignment. */ 239 257 uint64_t au64Padding1[2]; 258 #endif 240 259 } HDASTREAM; 241 260 AssertCompileMemberAlignment(HDASTREAM, State.aBdl, 16); … … 265 284 /** Circular buffer (FIFO) for holding DMA'ed data. */ 266 285 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;271 286 #ifdef HDA_USE_DMA_ACCESS_HANDLER 272 287 /** List of DMA handlers. */ … … 296 311 STAMPROFILE StatReset; 297 312 STAMPROFILE StatStop; 298 STAMPROFILE StatUnusedPadding;299 313 } State; 300 314 /** Debug bits. */ 301 315 HDASTREAMDEBUG Dbg; 302 uint64_t au64Alignment[ 1+4];316 uint64_t au64Alignment[3]; 303 317 } HDASTREAMR3; 304 318 AssertCompileSizeAlignment(HDASTREAMR3, 64); 305 319 /** Pointer to an HDA stream (SDI / SDO). */ 306 320 typedef HDASTREAMR3 *PHDASTREAMR3; 321 322 /** @name Stream functions (all contexts). 323 * @{ 324 */ 325 VBOXSTRICTRC hdaStreamDoOnAccessDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, 326 uint32_t cbToTransfer); 327 /** @} */ 307 328 308 329 #ifdef IN_RING3
Note:
See TracChangeset
for help on using the changeset viewer.