VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHdaStream.cpp@ 89859

Last change on this file since 89859 was 89859, checked in by vboxsync, 4 years ago

DevHda: Fixed bugtracker link. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 99.5 KB
Line 
1/* $Id: DevHdaStream.cpp 89859 2021-06-23 13:43:28Z vboxsync $ */
2/** @file
3 * Intel HD Audio Controller Emulation - Streams.
4 */
5
6/*
7 * Copyright (C) 2017-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_HDA
23#include <VBox/log.h>
24
25#include <iprt/mem.h>
26#include <iprt/semaphore.h>
27
28#include <VBox/AssertGuest.h>
29#include <VBox/vmm/pdmdev.h>
30#include <VBox/vmm/pdmaudioifs.h>
31#include <VBox/vmm/pdmaudioinline.h>
32
33#include "AudioHlp.h"
34
35#include "DevHda.h"
36#include "DevHdaStream.h"
37
38#ifdef VBOX_WITH_DTRACE
39# include "dtrace/VBoxDD.h"
40#endif
41
42#ifdef IN_RING3 /* whole file */
43
44
45/*********************************************************************************************************************************
46* Internal Functions *
47*********************************************************************************************************************************/
48static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB);
49static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
50 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
51
52
53
54/**
55 * Creates an HDA stream.
56 *
57 * @returns VBox status code.
58 * @param pStreamShared The HDA stream to construct - shared bits.
59 * @param pStreamR3 The HDA stream to construct - ring-3 bits.
60 * @param pThis The shared HDA device instance.
61 * @param pThisCC The ring-3 HDA device instance.
62 * @param uSD Stream descriptor number to assign.
63 */
64int hdaR3StreamConstruct(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PHDASTATE pThis, PHDASTATER3 pThisCC, uint8_t uSD)
65{
66 pStreamR3->u8SD = uSD;
67 pStreamShared->u8SD = uSD;
68 pStreamR3->pMixSink = NULL;
69 pStreamR3->pHDAStateShared = pThis;
70 pStreamR3->pHDAStateR3 = pThisCC;
71 Assert(pStreamShared->hTimer != NIL_TMTIMERHANDLE); /* hdaR3Construct initalized this one already. */
72
73 pStreamShared->State.fInReset = false;
74 pStreamShared->State.fRunning = false;
75# ifdef HDA_USE_DMA_ACCESS_HANDLER
76 RTListInit(&pStreamR3->State.lstDMAHandlers);
77# endif
78
79 AssertPtr(pStreamR3->pHDAStateR3);
80 AssertPtr(pStreamR3->pHDAStateR3->pDevIns);
81
82# ifdef DEBUG
83 int rc = RTCritSectInit(&pStreamR3->Dbg.CritSect);
84 AssertRCReturn(rc, rc);
85# endif
86
87 const bool fIsInput = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN;
88
89 if (fIsInput)
90 {
91 pStreamShared->State.Cfg.enmPath = PDMAUDIOPATH_UNKNOWN;
92 pStreamShared->State.Cfg.enmDir = PDMAUDIODIR_IN;
93 }
94 else
95 {
96 pStreamShared->State.Cfg.enmPath = PDMAUDIOPATH_UNKNOWN;
97 pStreamShared->State.Cfg.enmDir = PDMAUDIODIR_OUT;
98 }
99
100 pStreamR3->Dbg.Runtime.fEnabled = pThisCC->Dbg.fEnabled;
101
102 if (pStreamR3->Dbg.Runtime.fEnabled)
103 {
104 char szFile[64];
105 char szPath[RTPATH_MAX];
106
107 /* pFileStream */
108 if (fIsInput)
109 RTStrPrintf(szFile, sizeof(szFile), "hdaStreamWriteSD%RU8", uSD);
110 else
111 RTStrPrintf(szFile, sizeof(szFile), "hdaStreamReadSD%RU8", uSD);
112
113 int rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile,
114 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);
115 AssertRC(rc2);
116
117 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamR3->Dbg.Runtime.pFileStream);
118 AssertRC(rc2);
119
120 /* pFileDMARaw */
121 if (fIsInput)
122 RTStrPrintf(szFile, sizeof(szFile), "hdaDMARawWriteSD%RU8", uSD);
123 else
124 RTStrPrintf(szFile, sizeof(szFile), "hdaDMARawReadSD%RU8", uSD);
125
126 rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile,
127 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);
128 AssertRC(rc2);
129
130 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamR3->Dbg.Runtime.pFileDMARaw);
131 AssertRC(rc2);
132
133 /* pFileDMAMapped */
134 if (fIsInput)
135 RTStrPrintf(szFile, sizeof(szFile), "hdaDMAWriteMappedSD%RU8", uSD);
136 else
137 RTStrPrintf(szFile, sizeof(szFile), "hdaDMAReadMappedSD%RU8", uSD);
138
139 rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile,
140 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);
141 AssertRC(rc2);
142
143 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamR3->Dbg.Runtime.pFileDMAMapped);
144 AssertRC(rc2);
145
146 /* Delete stale debugging files from a former run. */
147 AudioHlpFileDelete(pStreamR3->Dbg.Runtime.pFileStream);
148 AudioHlpFileDelete(pStreamR3->Dbg.Runtime.pFileDMARaw);
149 AudioHlpFileDelete(pStreamR3->Dbg.Runtime.pFileDMAMapped);
150 }
151
152 return VINF_SUCCESS;
153}
154
155/**
156 * Destroys an HDA stream.
157 *
158 * @param pStreamR3 The HDA stream to destroy - ring-3 bits.
159 */
160void hdaR3StreamDestroy(PHDASTREAMR3 pStreamR3)
161{
162 LogFlowFunc(("[SD%RU8] Destroying ...\n", pStreamR3->u8SD));
163 int rc2;
164
165 if (pStreamR3->State.pAioRegSink)
166 {
167 rc2 = AudioMixerSinkRemoveUpdateJob(pStreamR3->State.pAioRegSink, hdaR3StreamUpdateAsyncIoJob, pStreamR3);
168 AssertRC(rc2);
169 pStreamR3->State.pAioRegSink = NULL;
170 }
171
172 if (pStreamR3->State.pCircBuf)
173 {
174 RTCircBufDestroy(pStreamR3->State.pCircBuf);
175 pStreamR3->State.pCircBuf = NULL;
176 pStreamR3->State.StatDmaBufSize = 0;
177 pStreamR3->State.StatDmaBufUsed = 0;
178 }
179
180# ifdef DEBUG
181 if (RTCritSectIsInitialized(&pStreamR3->Dbg.CritSect))
182 {
183 rc2 = RTCritSectDelete(&pStreamR3->Dbg.CritSect);
184 AssertRC(rc2);
185 }
186# endif
187
188 if (pStreamR3->Dbg.Runtime.fEnabled)
189 {
190 AudioHlpFileDestroy(pStreamR3->Dbg.Runtime.pFileStream);
191 pStreamR3->Dbg.Runtime.pFileStream = NULL;
192
193 AudioHlpFileDestroy(pStreamR3->Dbg.Runtime.pFileDMARaw);
194 pStreamR3->Dbg.Runtime.pFileDMARaw = NULL;
195
196 AudioHlpFileDestroy(pStreamR3->Dbg.Runtime.pFileDMAMapped);
197 pStreamR3->Dbg.Runtime.pFileDMAMapped = NULL;
198 }
199
200 LogFlowFuncLeave();
201}
202
203
204/**
205 * Appends a item to the scheduler.
206 *
207 * @returns VBox status code.
208 * @param pStreamShared The stream which scheduler should be modified.
209 * @param cbCur The period length in guest bytes.
210 * @param cbMaxPeriod The max period in guest bytes.
211 * @param idxLastBdle The last BDLE in the period.
212 * @param pHostProps The host PCM properties.
213 * @param pGuestProps The guest PCM properties.
214 * @param pcbBorrow Where to account for bytes borrowed across buffers
215 * to align scheduling items on frame boundraries.
216 */
217static int hdaR3StreamAddScheduleItem(PHDASTREAM pStreamShared, uint32_t cbCur, uint32_t cbMaxPeriod, uint32_t idxLastBdle,
218 PCPDMAUDIOPCMPROPS pHostProps, PCPDMAUDIOPCMPROPS pGuestProps, uint32_t *pcbBorrow)
219{
220 /* Check that we've got room (shouldn't ever be a problem). */
221 size_t idx = pStreamShared->State.cSchedule;
222 AssertLogRelReturn(idx + 1 < RT_ELEMENTS(pStreamShared->State.aSchedule), VERR_INTERNAL_ERROR_5);
223
224 /* Figure out the BDLE range for this period. */
225 uint32_t const idxFirstBdle = idx == 0 ? 0
226 : RT_MIN((uint32_t)( pStreamShared->State.aSchedule[idx - 1].idxFirst
227 + pStreamShared->State.aSchedule[idx - 1].cEntries),
228 idxLastBdle);
229
230 pStreamShared->State.aSchedule[idx].idxFirst = (uint8_t)idxFirstBdle;
231 pStreamShared->State.aSchedule[idx].cEntries = idxLastBdle >= idxFirstBdle
232 ? idxLastBdle - idxFirstBdle + 1
233 : pStreamShared->State.cBdles - idxFirstBdle + idxLastBdle + 1;
234
235 /* Deal with borrowing due to unaligned IOC buffers. */
236 uint32_t const cbBorrowed = *pcbBorrow;
237 if (cbBorrowed < cbCur)
238 cbCur -= cbBorrowed;
239 else
240 {
241 /* Note. We can probably gloss over this, but it's not a situation a sane guest would put us, so don't bother for now. */
242 ASSERT_GUEST_MSG_FAILED(("#%u: cbBorrow=%#x cbCur=%#x BDLE[%u..%u]\n",
243 pStreamShared->u8SD, cbBorrowed, cbCur, idxFirstBdle, idxLastBdle));
244 LogRelMax(32, ("HDA: Stream #%u has a scheduling error: cbBorrow=%#x cbCur=%#x BDLE[%u..%u]\n",
245 pStreamShared->u8SD, cbBorrowed, cbCur, idxFirstBdle, idxLastBdle));
246 return VERR_OUT_OF_RANGE;
247 }
248
249 uint32_t cbCurAligned = PDMAudioPropsRoundUpBytesToFrame(pGuestProps, cbCur);
250 *pcbBorrow = cbCurAligned - cbCur;
251
252 /* Do we need to split up the period? */
253 if (cbCurAligned <= cbMaxPeriod)
254 {
255 uint32_t cbHost = PDMAudioPropsFramesToBytes(pHostProps, PDMAudioPropsBytesToFrames(pGuestProps, cbCurAligned));
256 pStreamShared->State.aSchedule[idx].cbPeriod = cbHost;
257 pStreamShared->State.aSchedule[idx].cLoops = 1;
258 }
259 else
260 {
261 /* Reduce till we've below the threshold. */
262 uint32_t cbLoop = cbCurAligned;
263 do
264 cbLoop = cbCurAligned / 2;
265 while (cbLoop > cbMaxPeriod);
266 cbLoop = PDMAudioPropsRoundUpBytesToFrame(pGuestProps, cbLoop);
267
268 /* Complete the scheduling item. */
269 uint32_t cbHost = PDMAudioPropsFramesToBytes(pHostProps, PDMAudioPropsBytesToFrames(pGuestProps, cbLoop));
270 pStreamShared->State.aSchedule[idx].cbPeriod = cbHost;
271 pStreamShared->State.aSchedule[idx].cLoops = cbCurAligned / cbLoop;
272
273 /* If there is a remainder, add it as a separate entry (this is
274 why the schedule must be more than twice the size of the BDL).*/
275 cbCurAligned %= cbLoop;
276 if (cbCurAligned)
277 {
278 pStreamShared->State.aSchedule[idx + 1] = pStreamShared->State.aSchedule[idx];
279 idx++;
280 cbHost = PDMAudioPropsFramesToBytes(pHostProps, PDMAudioPropsBytesToFrames(pGuestProps, cbCurAligned));
281 pStreamShared->State.aSchedule[idx].cbPeriod = cbHost;
282 pStreamShared->State.aSchedule[idx].cLoops = 1;
283 }
284 }
285
286 /* Done. */
287 pStreamShared->State.cSchedule = (uint16_t)(idx + 1);
288
289 return VINF_SUCCESS;
290}
291
292/**
293 * Creates the DMA timer schedule for the stream
294 *
295 * This is called from the stream setup code.
296 *
297 * @returns VBox status code.
298 * @param pStreamShared The stream to create a schedule for. The BDL
299 * must be loaded.
300 * @param cSegments Number of BDL segments.
301 * @param cBufferIrqs Number of the BDLEs with IOC=1.
302 * @param cbTotal The total BDL length in guest bytes.
303 * @param cbMaxPeriod Max period in guest bytes. This is in case the
304 * guest want to play the whole "Der Ring des
305 * Nibelungen" cycle in one go.
306 * @param cTimerTicksPerSec The DMA timer frequency.
307 * @param pHostProps The host PCM properties.
308 * @param pGuestProps The guest PCM properties.
309 */
310static int hdaR3StreamCreateSchedule(PHDASTREAM pStreamShared, uint32_t cSegments, uint32_t cBufferIrqs, uint32_t cbTotal,
311 uint32_t cbMaxPeriod, uint64_t cTimerTicksPerSec,
312 PCPDMAUDIOPCMPROPS pHostProps, PCPDMAUDIOPCMPROPS pGuestProps)
313{
314 int rc;
315
316 /*
317 * Reset scheduling state.
318 */
319 RT_ZERO(pStreamShared->State.aSchedule);
320 pStreamShared->State.cSchedule = 0;
321 pStreamShared->State.cSchedulePrologue = 0;
322 pStreamShared->State.idxSchedule = 0;
323 pStreamShared->State.idxScheduleLoop = 0;
324
325 /*
326 * Do the basic schedule compilation.
327 */
328 uint32_t cPotentialPrologue = 0;
329 uint32_t cbBorrow = 0;
330 uint32_t cbCur = 0;
331 uint32_t cbMin = UINT32_MAX;
332 pStreamShared->State.aSchedule[0].idxFirst = 0;
333 for (uint32_t i = 0; i < cSegments; i++)
334 {
335 cbCur += pStreamShared->State.aBdl[i].cb;
336 if (pStreamShared->State.aBdl[i].cb < cbMin)
337 cbMin = pStreamShared->State.aBdl[i].cb;
338 if (pStreamShared->State.aBdl[i].fFlags & HDA_BDLE_F_IOC)
339 {
340 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbCur, cbMaxPeriod, i, pHostProps, pGuestProps, &cbBorrow);
341 ASSERT_GUEST_RC_RETURN(rc, rc);
342
343 if (cPotentialPrologue == 0)
344 cPotentialPrologue = pStreamShared->State.cSchedule;
345 cbCur = 0;
346 }
347 }
348 AssertLogRelMsgReturn(cbBorrow == 0, ("HDA: Internal scheduling error on stream #%u: cbBorrow=%#x cbTotal=%#x cbCur=%#x\n",
349 pStreamShared->u8SD, cbBorrow, cbTotal, cbCur),
350 VERR_INTERNAL_ERROR_3);
351
352 /*
353 * Deal with any loose ends.
354 */
355 if (cbCur && cBufferIrqs == 0)
356 {
357 /*
358 * No IOC. Vista ends up here, typically with three buffers configured.
359 *
360 * The perferred option here is to aim at processing one average BDLE with
361 * each DMA timer period, since that best matches how we update LPIB at
362 * present.
363 *
364 * The second alternative is to divide the whole span up into 3-4 periods
365 * to try increase our chances of keeping ahead of the guest. We may need
366 * to pick this if there are too few buffer descriptor or they are too small.
367 *
368 * However, what we probably should be doing is to do real DMA work whenever
369 * the guest reads a DMA related register (like LPIB) and just do 3-4 DMA
370 * timer periods, however we'll be postponing the DMA timer every time we
371 * return to ring-3 and signal the AIO, so in the end we'd probably not use
372 * the timer callback at all. (This is assuming a small shared per-stream
373 * buffer for keeping the DMA data in and that it's size will force a return
374 * to ring-3 often enough to keep the AIO thread going at a reasonable rate.)
375 */
376 Assert(cbCur == cbTotal);
377
378 /* Match the BDLEs 1:1 if there are 3 or more and that the smallest one
379 is at least 5ms big. */
380 if (cSegments >= 3 && PDMAudioPropsBytesToMilli(pGuestProps, cbMin) >= 5 /*ms*/)
381 {
382 for (uint32_t i = 0; i < cSegments; i++)
383 {
384 rc = hdaR3StreamAddScheduleItem(pStreamShared, pStreamShared->State.aBdl[i].cb, cbMaxPeriod,
385 i, pHostProps, pGuestProps, &cbBorrow);
386 ASSERT_GUEST_RC_RETURN(rc, rc);
387 }
388 }
389 /* Otherwise, just divide the work into 3 or 4 portions and hope for the best.
390 It seems, though, that this only really work for windows vista if we avoid
391 working accross buffer lines. */
392 /** @todo This can be simplified/relaxed/uncluttered if we do DMA work when LPIB
393 * is read, assuming ofc that LPIB is read before each buffer update. */
394 else
395 {
396 uint32_t const cPeriods = cSegments != 3 && PDMAudioPropsBytesToMilli(pGuestProps, cbCur) >= 4 * 5 /*ms*/
397 ? 4 : cSegments != 2 ? 3 : 2;
398 uint32_t const cbPeriod = PDMAudioPropsFloorBytesToFrame(pGuestProps, cbCur / cPeriods);
399 uint32_t iBdle = 0;
400 uint32_t offBdle = 0;
401 for (uint32_t iPeriod = 0; iPeriod < cPeriods; iPeriod++)
402 {
403 if (iPeriod + 1 < cPeriods)
404 {
405 offBdle += cbPeriod;
406 while (iBdle < cSegments && offBdle >= pStreamShared->State.aBdl[iBdle].cb)
407 offBdle -= pStreamShared->State.aBdl[iBdle++].cb;
408 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbPeriod, cbMaxPeriod, offBdle != 0 ? iBdle : iBdle - 1,
409 pHostProps, pGuestProps, &cbBorrow);
410 }
411 else
412 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbCur - iPeriod * cbPeriod, cbMaxPeriod, cSegments - 1,
413 pHostProps, pGuestProps, &cbBorrow);
414 ASSERT_GUEST_RC_RETURN(rc, rc);
415 }
416
417 }
418 Assert(cbBorrow == 0);
419 }
420 else if (cbCur)
421 {
422 /* The last BDLE didn't have IOC set, so we must continue processing
423 from the start till we hit one that has. */
424 uint32_t i;
425 for (i = 0; i < cSegments; i++)
426 {
427 cbCur += pStreamShared->State.aBdl[i].cb;
428 if (pStreamShared->State.aBdl[i].fFlags & HDA_BDLE_F_IOC)
429 break;
430 }
431 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbCur, cbMaxPeriod, i, pHostProps, pGuestProps, &cbBorrow);
432 ASSERT_GUEST_RC_RETURN(rc, rc);
433
434 /* The initial scheduling items covering the wrap around area are
435 considered a prologue and must not repeated later. */
436 Assert(cPotentialPrologue);
437 pStreamShared->State.cSchedulePrologue = (uint8_t)cPotentialPrologue;
438 }
439
440 /*
441 * If there is just one BDLE with IOC set, we have to make sure
442 * we've got at least two periods scheduled, otherwise there is
443 * a very good chance the guest will overwrite the start of the
444 * buffer before we ever get around to reading it.
445 */
446 if (cBufferIrqs == 1)
447 {
448 uint32_t i = pStreamShared->State.cSchedulePrologue;
449 Assert(i < pStreamShared->State.cSchedule);
450 if ( i + 1 == pStreamShared->State.cSchedule
451 && pStreamShared->State.aSchedule[i].cLoops == 1)
452 {
453 uint32_t const cbFirstHalf = PDMAudioPropsFloorBytesToFrame(pHostProps, pStreamShared->State.aSchedule[i].cbPeriod / 2);
454 uint32_t const cbOtherHalf = pStreamShared->State.aSchedule[i].cbPeriod - cbFirstHalf;
455 pStreamShared->State.aSchedule[i].cbPeriod = cbFirstHalf;
456 if (cbFirstHalf == cbOtherHalf)
457 pStreamShared->State.aSchedule[i].cLoops = 2;
458 else
459 {
460 pStreamShared->State.aSchedule[i + 1] = pStreamShared->State.aSchedule[i];
461 pStreamShared->State.aSchedule[i].cbPeriod = cbOtherHalf;
462 pStreamShared->State.cSchedule++;
463 }
464 }
465 }
466
467 /*
468 * Go over the schduling entries and calculate the timer ticks for each period.
469 */
470 LogRel2(("HDA: Stream #%u schedule: %u items, %u prologue\n",
471 pStreamShared->u8SD, pStreamShared->State.cSchedule, pStreamShared->State.cSchedulePrologue));
472 uint64_t const cbHostPerSec = PDMAudioPropsFramesToBytes(pHostProps, pHostProps->uHz);
473 for (uint32_t i = 0; i < pStreamShared->State.cSchedule; i++)
474 {
475 uint64_t const cTicks = ASMMultU64ByU32DivByU32(cTimerTicksPerSec, pStreamShared->State.aSchedule[i].cbPeriod,
476 cbHostPerSec);
477 AssertLogRelMsgReturn((uint32_t)cTicks == cTicks, ("cTicks=%RU64 (%#RX64)\n", cTicks, cTicks), VERR_INTERNAL_ERROR_4);
478 pStreamShared->State.aSchedule[i].cPeriodTicks = RT_MAX((uint32_t)cTicks, 16);
479 LogRel2(("HDA: #%u: %u ticks / %u bytes, %u loops, BDLE%u L %u\n", i, pStreamShared->State.aSchedule[i].cPeriodTicks,
480 pStreamShared->State.aSchedule[i].cbPeriod, pStreamShared->State.aSchedule[i].cLoops,
481 pStreamShared->State.aSchedule[i].idxFirst, pStreamShared->State.aSchedule[i].cEntries));
482 }
483
484 return VINF_SUCCESS;
485}
486
487
488/**
489 * Sets up ((re-)iniitalizes) an HDA stream.
490 *
491 * @returns VBox status code. VINF_NO_CHANGE if the stream does not need
492 * be set-up again because the stream's (hardware) parameters did
493 * not change.
494 * @param pDevIns The device instance.
495 * @param pThis The shared HDA device state (for HW register
496 * parameters).
497 * @param pStreamShared HDA stream to set up, shared portion.
498 * @param pStreamR3 HDA stream to set up, ring-3 portion.
499 * @param uSD Stream descriptor number to assign it.
500 */
501int hdaR3StreamSetUp(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD)
502{
503 /* This must be valid all times. */
504 AssertReturn(uSD < HDA_MAX_STREAMS, VERR_INVALID_PARAMETER);
505
506 /* These member can only change on data corruption, despite what the code does further down (bird). */
507 AssertReturn(pStreamShared->u8SD == uSD, VERR_WRONG_ORDER);
508 AssertReturn(pStreamR3->u8SD == uSD, VERR_WRONG_ORDER);
509
510 const uint64_t u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, uSD),
511 HDA_STREAM_REG(pThis, BDPU, uSD));
512 const uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, uSD);
513 const uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, uSD);
514 const uint8_t u8FIFOS = HDA_STREAM_REG(pThis, FIFOS, uSD) + 1;
515 uint8_t u8FIFOW = hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, uSD));
516 const uint16_t u16FMT = HDA_STREAM_REG(pThis, FMT, uSD);
517
518 /* Is the bare minimum set of registers configured for the stream?
519 * If not, bail out early, as there's nothing to do here for us (yet). */
520 if ( !u64BDLBase
521 || !u16LVI
522 || !u32CBL
523 || !u8FIFOS
524 || !u8FIFOW
525 || !u16FMT)
526 {
527 LogFunc(("[SD%RU8] Registers not set up yet, skipping (re-)initialization\n", uSD));
528 return VINF_SUCCESS;
529 }
530
531 /*
532 * Convert the config to PDM PCM properties and configure the stream.
533 */
534 PPDMAUDIOSTREAMCFG pCfg = &pStreamShared->State.Cfg;
535 int rc = hdaR3SDFMTToPCMProps(u16FMT, &pCfg->Props);
536 if (RT_SUCCESS(rc))
537 pCfg->enmDir = hdaGetDirFromSD(uSD);
538 else
539 {
540 LogRelMax(32, ("HDA: Warning: Format 0x%x for stream #%RU8 not supported\n", HDA_STREAM_REG(pThis, FMT, uSD), uSD));
541 return rc;
542 }
543
544 ASSERT_GUEST_LOGREL_MSG_RETURN( PDMAudioPropsFrameSize(&pCfg->Props) > 0
545 && u32CBL % PDMAudioPropsFrameSize(&pCfg->Props) == 0,
546 ("CBL for stream #%RU8 does not align to frame size (u32CBL=%u cbFrameSize=%u)\n",
547 uSD, u32CBL, PDMAudioPropsFrameSize(&pCfg->Props)),
548 VERR_INVALID_PARAMETER);
549
550 /* Make sure the guest behaves regarding the stream's FIFO. */
551 ASSERT_GUEST_LOGREL_MSG_STMT(u8FIFOW <= u8FIFOS,
552 ("Guest tried setting a bigger FIFOW (%RU8) than FIFOS (%RU8), limiting\n", u8FIFOW, u8FIFOS),
553 u8FIFOW = u8FIFOS /* ASSUMES that u8FIFOS has been validated. */);
554
555 pStreamShared->u8SD = uSD;
556
557 /* Update all register copies so that we later know that something has changed. */
558 pStreamShared->u64BDLBase = u64BDLBase;
559 pStreamShared->u16LVI = u16LVI;
560 pStreamShared->u32CBL = u32CBL;
561 pStreamShared->u8FIFOS = u8FIFOS;
562 pStreamShared->u8FIFOW = u8FIFOW;
563 pStreamShared->u16FMT = u16FMT;
564
565 /* The the stream's name, based on the direction. */
566 switch (pCfg->enmDir)
567 {
568 case PDMAUDIODIR_IN:
569# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
570# error "Implement me!"
571# else
572 pCfg->enmPath = PDMAUDIOPATH_IN_LINE;
573 RTStrCopy(pCfg->szName, sizeof(pCfg->szName), "Line In");
574# endif
575 break;
576
577 case PDMAUDIODIR_OUT:
578 /* Destination(s) will be set in hdaR3AddStreamOut(),
579 * based on the channels / stream layout. */
580 break;
581
582 default:
583 AssertFailedReturn(VERR_NOT_SUPPORTED);
584 break;
585 }
586
587 LogRel2(("HDA: Stream #%RU8 DMA @ 0x%x (%RU32 bytes = %RU64ms total)\n", uSD, pStreamShared->u64BDLBase,
588 pStreamShared->u32CBL, PDMAudioPropsBytesToMilli(&pCfg->Props, pStreamShared->u32CBL)));
589
590 /*
591 * Load the buffer descriptor list.
592 *
593 * Section 3.6.2 states that "the BDL should not be modified unless the RUN
594 * bit is 0", so it should be within the specs to read it once here and not
595 * re-read any BDLEs later.
596 */
597 /* Reset BDL state. */
598 RT_ZERO(pStreamShared->State.aBdl);
599 pStreamShared->State.offCurBdle = 0;
600 pStreamShared->State.idxCurBdle = 0;
601
602 uint32_t /*const*/ cTransferFragments = (pStreamShared->u16LVI & 0xff) + 1;
603 if (cTransferFragments <= 1)
604 LogRel(("HDA: Warning: Stream #%RU8 transfer buffer count invalid: (%RU16)! Buggy guest audio driver!\n", uSD, pStreamShared->u16LVI));
605 AssertLogRelReturn(cTransferFragments <= RT_ELEMENTS(pStreamShared->State.aBdl), VERR_INTERNAL_ERROR_5);
606 pStreamShared->State.cBdles = cTransferFragments;
607
608 /* Load them. */
609 rc = PDMDevHlpPCIPhysRead(pDevIns, u64BDLBase, pStreamShared->State.aBdl,
610 sizeof(pStreamShared->State.aBdl[0]) * cTransferFragments);
611 AssertRC(rc);
612
613 /* Check what we just loaded. Refuse overly large buffer lists. */
614 uint64_t cbTotal = 0;
615 uint32_t cBufferIrqs = 0;
616 for (uint32_t i = 0; i < cTransferFragments; i++)
617 {
618 if (pStreamShared->State.aBdl[i].fFlags & HDA_BDLE_F_IOC)
619 cBufferIrqs++;
620 cbTotal += pStreamShared->State.aBdl[i].cb;
621 }
622 ASSERT_GUEST_STMT_RETURN(cbTotal < _2G,
623 LogRelMax(32, ("HDA: Error: Stream #%u is configured with an insane amount of buffer space - refusing do work with it: %RU64 (%#RX64) bytes.\n",
624 uSD, cbTotal, cbTotal)),
625 VERR_NOT_SUPPORTED);
626 ASSERT_GUEST_STMT_RETURN(cbTotal == u32CBL,
627 LogRelMax(32, ("HDA: Warning: Stream #%u has a mismatch between CBL and configured buffer space: %RU32 (%#RX32) vs %RU64 (%#RX64)\n",
628 uSD, u32CBL, u32CBL, cbTotal, cbTotal)),
629 VERR_NOT_SUPPORTED);
630
631 /*
632 * Create a DMA timer schedule.
633 */
634 /** @todo clean up this, pGuestProps and pHostProps are the same now. */
635 rc = hdaR3StreamCreateSchedule(pStreamShared, cTransferFragments, cBufferIrqs, (uint32_t)cbTotal,
636 PDMAudioPropsMilliToBytes(&pCfg->Props, 100 /** @todo make configurable */),
637 PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer),
638 &pCfg->Props, &pCfg->Props);
639 if (RT_FAILURE(rc))
640 return rc;
641
642 pStreamShared->State.cbTransferSize = pStreamShared->State.aSchedule[0].cbPeriod;
643
644 /*
645 * Calculate the transfer Hz for use in the circular buffer calculation.
646 */
647 uint32_t cbMaxPeriod = 0;
648 uint32_t cbMinPeriod = UINT32_MAX;
649 uint32_t cPeriods = 0;
650 for (uint32_t i = 0; i < pStreamShared->State.cSchedule; i++)
651 {
652 uint32_t cbPeriod = pStreamShared->State.aSchedule[i].cbPeriod;
653 cbMaxPeriod = RT_MAX(cbMaxPeriod, cbPeriod);
654 cbMinPeriod = RT_MIN(cbMinPeriod, cbPeriod);
655 cPeriods += pStreamShared->State.aSchedule[i].cLoops;
656 }
657 uint64_t const cbTransferPerSec = RT_MAX(PDMAudioPropsFramesToBytes(&pCfg->Props, pCfg->Props.uHz),
658 4096 /* zero div prevention: min is 6kHz, picked 4k in case I'm mistaken */);
659 unsigned uTransferHz = cbTransferPerSec * 1000 / cbMaxPeriod;
660 LogRel2(("HDA: Stream #%RU8 needs a %u.%03u Hz timer rate (period: %u..%u host bytes)\n",
661 uSD, uTransferHz / 1000, uTransferHz % 1000, cbMinPeriod, cbMaxPeriod));
662 uTransferHz /= 1000;
663
664 if (uTransferHz > 400) /* Anything above 400 Hz looks fishy -- tell the user. */
665 LogRelMax(32, ("HDA: Warning: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), please re-run with audio debug mode and report a bug\n",
666 uSD, uTransferHz));
667
668 pStreamShared->State.cbAvgTransfer = (uint32_t)(cbTotal + cPeriods - 1) / cPeriods;
669
670 /* For input streams we must determin a pre-buffering requirement.
671 We use the initial delay as a basis here, though we must have at
672 least two max periods worth of data queued up due to the way we
673 work the AIO thread. */
674 pStreamShared->State.fInputPreBuffered = false;
675 pStreamShared->State.cbInputPreBuffer = PDMAudioPropsMilliToBytes(&pCfg->Props, pThis->msInitialDelay);
676 pStreamShared->State.cbInputPreBuffer = RT_MIN(cbMaxPeriod * 2, pStreamShared->State.cbInputPreBuffer);
677
678 /*
679 * Set up data transfer stuff.
680 */
681
682 /* Assign the global device rate to the stream I/O timer as default. */
683 pStreamShared->State.uTimerIoHz = pThis->uTimerHz;
684 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz,
685 ("I/O timer Hz rate for stream #%RU8 is invalid\n", uSD),
686 pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT);
687
688 /* 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. */
692 pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz;
693 LogRel2(("HDA: Stream #%RU8 set scheduling hint for the backends to %RU32ms\n", uSD, pCfg->Device.cMsSchedulingHint));
694
695
696 /* 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));
698
699# ifdef LOG_ENABLED
700 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
701# endif
702
703 /*
704 * Set up internal ring buffer.
705 */
706
707 /* (Re-)Allocate the stream's internal DMA buffer,
708 * based on the timing *and* PCM properties we just got above. */
709 if (pStreamR3->State.pCircBuf)
710 {
711 RTCircBufDestroy(pStreamR3->State.pCircBuf);
712 pStreamR3->State.pCircBuf = NULL;
713 pStreamR3->State.StatDmaBufSize = 0;
714 pStreamR3->State.StatDmaBufUsed = 0;
715 }
716 pStreamR3->State.offWrite = 0;
717 pStreamR3->State.offRead = 0;
718
719 /*
720 * The default internal ring buffer size must be:
721 *
722 * - Large enough for at least three periodic DMA transfers.
723 *
724 * It is critically important that we don't experience underruns
725 * in the DMA OUT code, because it will cause the buffer processing
726 * to get skewed and possibly overlap with what the guest is updating.
727 * At the time of writing (2021-03-05) there is no code for getting
728 * back into sync there.
729 *
730 * - Large enough for at least three I/O scheduling hints.
731 *
732 * We want to lag behind a DMA period or two, but there must be
733 * sufficent space for the AIO thread to get schedule and shuffle
734 * data thru the mixer and onto the host audio hardware.
735 *
736 * - Both above with plenty to spare.
737 *
738 * So, just take the longest of the two periods and multipling it by 6.
739 * We aren't not talking about very large base buffers heres, so size isn't
740 * an issue.
741 *
742 * Note: Use pCfg->Props as PCM properties here, as we only want to store the
743 * samples we actually need, in other words, skipping the interleaved
744 * channels we don't support / need to save space.
745 */
746 uint32_t msCircBuf = RT_MS_1SEC * 6 / RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz);
747 msCircBuf = RT_MAX(msCircBuf, pThis->msInitialDelay + RT_MS_1SEC * 6 / uTransferHz);
748
749 uint32_t cbCircBuf = PDMAudioPropsMilliToBytes(&pCfg->Props, msCircBuf);
750 LogRel2(("HDA: Stream #%RU8 default ring buffer size is %RU32 bytes / %RU64 ms\n",
751 uSD, cbCircBuf, PDMAudioPropsBytesToMilli(&pCfg->Props, cbCircBuf)));
752
753 uint32_t msCircBufCfg = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut;
754 if (msCircBufCfg) /* Anything set via CFGM? */
755 {
756 cbCircBuf = PDMAudioPropsMilliToBytes(&pCfg->Props, msCircBufCfg);
757 LogRel2(("HDA: Stream #%RU8 is using a custom ring buffer size of %RU32 bytes / %RU64 ms\n",
758 uSD, cbCircBuf, PDMAudioPropsBytesToMilli(&pCfg->Props, cbCircBuf)));
759 }
760
761 /* Serious paranoia: */
762 ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf % PDMAudioPropsFrameSize(&pCfg->Props) == 0,
763 ("Ring buffer size (%RU32) for stream #%RU8 not aligned to the (host) frame size (%RU8)\n",
764 cbCircBuf, uSD, PDMAudioPropsFrameSize(&pCfg->Props)),
765 rc = VERR_INVALID_PARAMETER);
766 ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf, ("Ring buffer size for stream #%RU8 is invalid\n", uSD),
767 rc = VERR_INVALID_PARAMETER);
768 if (RT_SUCCESS(rc))
769 {
770 rc = RTCircBufCreate(&pStreamR3->State.pCircBuf, cbCircBuf);
771 if (RT_SUCCESS(rc))
772 {
773 pStreamR3->State.StatDmaBufSize = cbCircBuf;
774
775 /*
776 * Forward the timer frequency hint to TM as well for better accuracy on
777 * systems w/o preemption timers (also good for 'info timers').
778 */
779 PDMDevHlpTimerSetFrequencyHint(pDevIns, pStreamShared->hTimer, uTransferHz);
780 }
781 }
782
783 if (RT_FAILURE(rc))
784 LogRelMax(32, ("HDA: Initializing stream #%RU8 failed with %Rrc\n", uSD, rc));
785
786# ifdef VBOX_WITH_DTRACE
787 VBOXDD_HDA_STREAM_SETUP((uint32_t)uSD, rc, pStreamShared->State.Cfg.Props.uHz,
788 pStreamShared->State.aSchedule[pStreamShared->State.cSchedule - 1].cPeriodTicks,
789 pStreamShared->State.aSchedule[pStreamShared->State.cSchedule - 1].cbPeriod);
790# endif
791 return rc;
792}
793
794/**
795 * Resets an HDA stream.
796 *
797 * @param pThis The shared HDA device state.
798 * @param pThisCC The ring-3 HDA device state.
799 * @param pStreamShared HDA stream to reset (shared).
800 * @param pStreamR3 HDA stream to reset (ring-3).
801 * @param uSD Stream descriptor (SD) number to use for this stream.
802 */
803void hdaR3StreamReset(PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD)
804{
805 LogFunc(("[SD%RU8] Reset\n", uSD));
806
807 /*
808 * Assert some sanity.
809 */
810 AssertPtr(pThis);
811 AssertPtr(pStreamShared);
812 AssertPtr(pStreamR3);
813 Assert(uSD < HDA_MAX_STREAMS);
814 Assert(pStreamShared->u8SD == uSD);
815 Assert(pStreamR3->u8SD == uSD);
816 AssertMsg(!pStreamShared->State.fRunning, ("[SD%RU8] Cannot reset stream while in running state\n", uSD));
817
818 /*
819 * Set reset state.
820 */
821 Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false); /* No nested calls. */
822 ASMAtomicXchgBool(&pStreamShared->State.fInReset, true);
823
824 /*
825 * Second, initialize the registers.
826 */
827 /* See 6.2.33: Clear on reset. */
828 HDA_STREAM_REG(pThis, STS, uSD) = 0;
829 /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
830 * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
831 HDA_STREAM_REG(pThis, CTL, uSD) = HDA_SDCTL_TP | (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_SRST);
832 /* ICH6 defines default values (120 bytes for input and 192 bytes for output descriptors) of FIFO size. 18.2.39. */
833 HDA_STREAM_REG(pThis, FIFOS, uSD) = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? HDA_SDIFIFO_120B : HDA_SDOFIFO_192B;
834 /* See 18.2.38: Always defaults to 0x4 (32 bytes). */
835 HDA_STREAM_REG(pThis, FIFOW, uSD) = HDA_SDFIFOW_32B;
836 HDA_STREAM_REG(pThis, LPIB, uSD) = 0;
837 HDA_STREAM_REG(pThis, CBL, uSD) = 0;
838 HDA_STREAM_REG(pThis, LVI, uSD) = 0;
839 HDA_STREAM_REG(pThis, FMT, uSD) = 0;
840 HDA_STREAM_REG(pThis, BDPU, uSD) = 0;
841 HDA_STREAM_REG(pThis, BDPL, uSD) = 0;
842
843# ifdef HDA_USE_DMA_ACCESS_HANDLER
844 hdaR3StreamUnregisterDMAHandlers(pThis, pStream);
845# endif
846
847 /* Assign the default mixer sink to the stream. */
848 pStreamR3->pMixSink = hdaR3GetDefaultSink(pThisCC, uSD);
849 if (pStreamR3->State.pAioRegSink)
850 {
851 int rc2 = AudioMixerSinkRemoveUpdateJob(pStreamR3->State.pAioRegSink, hdaR3StreamUpdateAsyncIoJob, pStreamR3);
852 AssertRC(rc2);
853 pStreamR3->State.pAioRegSink = NULL;
854 }
855
856 /* Reset transfer stuff. */
857 pStreamShared->State.cTransferPendingInterrupts = 0;
858 pStreamShared->State.tsTransferLast = 0;
859 pStreamShared->State.tsTransferNext = 0;
860
861 /* Initialize timestamps. */
862 pStreamShared->State.tsLastTransferNs = 0;
863 pStreamShared->State.tsLastReadNs = 0;
864 pStreamShared->State.tsAioDelayEnd = UINT64_MAX;
865 pStreamShared->State.tsStart = 0;
866
867 RT_ZERO(pStreamShared->State.aBdl);
868 RT_ZERO(pStreamShared->State.aSchedule);
869 pStreamShared->State.offCurBdle = 0;
870 pStreamShared->State.cBdles = 0;
871 pStreamShared->State.idxCurBdle = 0;
872 pStreamShared->State.cSchedulePrologue = 0;
873 pStreamShared->State.cSchedule = 0;
874 pStreamShared->State.idxSchedule = 0;
875 pStreamShared->State.idxScheduleLoop = 0;
876 pStreamShared->State.fInputPreBuffered = false;
877
878 if (pStreamR3->State.pCircBuf)
879 RTCircBufReset(pStreamR3->State.pCircBuf);
880 pStreamR3->State.offWrite = 0;
881 pStreamR3->State.offRead = 0;
882
883# ifdef DEBUG
884 pStreamR3->Dbg.cReadsTotal = 0;
885 pStreamR3->Dbg.cbReadTotal = 0;
886 pStreamR3->Dbg.tsLastReadNs = 0;
887 pStreamR3->Dbg.cWritesTotal = 0;
888 pStreamR3->Dbg.cbWrittenTotal = 0;
889 pStreamR3->Dbg.cWritesHz = 0;
890 pStreamR3->Dbg.cbWrittenHz = 0;
891 pStreamR3->Dbg.tsWriteSlotBegin = 0;
892# endif
893
894 /* Report that we're done resetting this stream. */
895 HDA_STREAM_REG(pThis, CTL, uSD) = 0;
896
897# ifdef VBOX_WITH_DTRACE
898 VBOXDD_HDA_STREAM_RESET((uint32_t)uSD);
899# endif
900 LogFunc(("[SD%RU8] Reset\n", uSD));
901
902 /* Exit reset mode. */
903 ASMAtomicXchgBool(&pStreamShared->State.fInReset, false);
904}
905
906/**
907 * Enables or disables an HDA audio stream.
908 *
909 * @returns VBox status code.
910 * @param pThis The shared HDA device state.
911 * @param pStreamShared HDA stream to enable or disable - shared bits.
912 * @param pStreamR3 HDA stream to enable or disable - ring-3 bits.
913 * @param fEnable Whether to enable or disble the stream.
914 */
915int hdaR3StreamEnable(PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fEnable)
916{
917 AssertPtr(pStreamR3);
918 AssertPtr(pStreamShared);
919
920 LogFunc(("[SD%RU8] fEnable=%RTbool, pMixSink=%p\n", pStreamShared->u8SD, fEnable, pStreamR3->pMixSink));
921
922 /* First, enable or disable the stream and the stream's sink, if any. */
923 int rc = VINF_SUCCESS;
924 PAUDMIXSINK const pSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
925 if (pSink)
926 {
927 if (fEnable)
928 {
929 if (pStreamR3->State.pAioRegSink != pSink)
930 {
931 if (pStreamR3->State.pAioRegSink)
932 {
933 rc = AudioMixerSinkRemoveUpdateJob(pStreamR3->State.pAioRegSink, hdaR3StreamUpdateAsyncIoJob, pStreamR3);
934 AssertRC(rc);
935 }
936 rc = AudioMixerSinkAddUpdateJob(pSink, hdaR3StreamUpdateAsyncIoJob, pStreamR3,
937 pStreamShared->State.Cfg.Device.cMsSchedulingHint);
938 AssertLogRelRC(rc);
939 pStreamR3->State.pAioRegSink = RT_SUCCESS(rc) ? pSink : NULL;
940 }
941 rc = AudioMixerSinkStart(pSink);
942 }
943 else
944 rc = AudioMixerSinkDrainAndStop(pSink,
945 pStreamR3->State.pCircBuf ? (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf) : 0);
946 }
947 if ( RT_SUCCESS(rc)
948 && fEnable
949 && pStreamR3->Dbg.Runtime.fEnabled)
950 {
951 Assert(AudioHlpPcmPropsAreValid(&pStreamShared->State.Cfg.Props));
952
953 if (fEnable)
954 {
955 if (!AudioHlpFileIsOpen(pStreamR3->Dbg.Runtime.pFileStream))
956 {
957 int rc2 = AudioHlpFileOpen(pStreamR3->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
958 &pStreamShared->State.Cfg.Props);
959 AssertRC(rc2);
960 }
961
962 if (!AudioHlpFileIsOpen(pStreamR3->Dbg.Runtime.pFileDMARaw))
963 {
964 int rc2 = AudioHlpFileOpen(pStreamR3->Dbg.Runtime.pFileDMARaw, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
965 &pStreamShared->State.Cfg.Props);
966 AssertRC(rc2);
967 }
968
969 if (!AudioHlpFileIsOpen(pStreamR3->Dbg.Runtime.pFileDMAMapped))
970 {
971 int rc2 = AudioHlpFileOpen(pStreamR3->Dbg.Runtime.pFileDMAMapped, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
972 &pStreamShared->State.Cfg.Props);
973 AssertRC(rc2);
974 }
975 }
976 }
977
978 if (RT_SUCCESS(rc))
979 {
980 if (fEnable)
981 pStreamShared->State.tsTransferLast = 0; /* Make sure it's not stale and messes up WALCLK calculations. */
982 pStreamShared->State.fRunning = fEnable;
983
984 /*
985 * Set the FIFORDY bit when we start running and clear it when stopping.
986 *
987 * This prevents Linux from timing out in snd_hdac_stream_sync when starting
988 * a stream. Technically, Linux also uses the SSYNC feature there, but we
989 * can get away with just setting the FIFORDY bit for now.
990 */
991 if (fEnable)
992 HDA_STREAM_REG(pThis, STS, pStreamShared->u8SD) |= HDA_SDSTS_FIFORDY;
993 else
994 HDA_STREAM_REG(pThis, STS, pStreamShared->u8SD) &= ~HDA_SDSTS_FIFORDY;
995 }
996
997 LogFunc(("[SD%RU8] rc=%Rrc\n", pStreamShared->u8SD, rc));
998 return rc;
999}
1000
1001/**
1002 * Marks the stream as started.
1003 *
1004 * Used after the stream has been enabled and the DMA timer has been armed.
1005 */
1006void hdaR3StreamMarkStarted(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint64_t tsNow)
1007{
1008 pStreamShared->State.tsLastReadNs = RTTimeNanoTS();
1009 pStreamShared->State.tsStart = tsNow;
1010 pStreamShared->State.tsAioDelayEnd = tsNow + PDMDevHlpTimerFromMilli(pDevIns, pStreamShared->hTimer, pThis->msInitialDelay);
1011 Log3Func(("#%u: tsStart=%RU64 tsAioDelayEnd=%RU64 tsLastReadNs=%RU64\n", pStreamShared->u8SD,
1012 pStreamShared->State.tsStart, pStreamShared->State.tsAioDelayEnd, pStreamShared->State.tsLastReadNs));
1013
1014}
1015
1016/**
1017 * Marks the stream as stopped.
1018 */
1019void hdaR3StreamMarkStopped(PHDASTREAM pStreamShared)
1020{
1021 Log3Func(("#%u\n", pStreamShared->u8SD));
1022 pStreamShared->State.tsAioDelayEnd = UINT64_MAX;
1023}
1024
1025
1026# if 0 /* Not used atm. */
1027static uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStreamShared)
1028{
1029 return HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD);
1030}
1031# endif
1032
1033/**
1034 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
1035 * setting its associated LPIB register and DMA position buffer (if enabled) to an absolute value.
1036 *
1037 * @param pStreamShared HDA stream to update read / write position for (shared).
1038 * @param pDevIns The device instance.
1039 * @param pThis The shared HDA device state.
1040 * @param uLPIB Absolute position (in bytes) to set current read / write position to.
1041 */
1042static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB)
1043{
1044 AssertPtrReturnVoid(pStreamShared);
1045 AssertMsgStmt(uLPIB <= pStreamShared->u32CBL, ("%#x\n", uLPIB), uLPIB = pStreamShared->u32CBL);
1046
1047 Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n", pStreamShared->u8SD, uLPIB, pThis->fDMAPosition));
1048
1049 /* Update LPIB in any case. */
1050 HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = uLPIB;
1051
1052 /* Do we need to tell the current DMA position? */
1053 if (pThis->fDMAPosition)
1054 {
1055 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns,
1056 pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)),
1057 (void *)&uLPIB, sizeof(uint32_t));
1058 AssertRC(rc2);
1059 }
1060}
1061
1062/**
1063 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
1064 * adding a value to its associated LPIB register and DMA position buffer (if enabled).
1065 *
1066 * @note Handles automatic CBL wrap-around.
1067 *
1068 * @param pStreamShared HDA stream to update read / write position for (shared).
1069 * @param pDevIns The device instance.
1070 * @param pThis The shared HDA device state.
1071 * @param cbToAdd Position (in bytes) to add to the current read / write position.
1072 */
1073static void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t cbToAdd)
1074{
1075 if (cbToAdd) /* No need to update anything if 0. */
1076 {
1077 uint32_t const uCBL = pStreamShared->u32CBL;
1078 if (uCBL) /* paranoia */
1079 {
1080 uint32_t uNewLpid = HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + cbToAdd;
1081#if 1 /** @todo r=bird: this is wrong according to the spec */
1082 uNewLpid %= uCBL;
1083#else
1084 /* The spec says it goes to CBL then wraps arpimd to 1, not back to zero. See 3.3.37. */
1085 if (uNewLpid > uCBL)
1086 uNewLpid %= uCBL;
1087#endif
1088 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, uNewLpid);
1089 }
1090 }
1091}
1092
1093/**
1094 * Retrieves the available size of (buffered) audio data (in bytes) of a given HDA stream.
1095 *
1096 * @returns Available data (in bytes).
1097 * @param pStreamR3 HDA stream to retrieve size for (ring-3).
1098 */
1099static uint32_t hdaR3StreamGetUsed(PHDASTREAMR3 pStreamR3)
1100{
1101 AssertPtrReturn(pStreamR3, 0);
1102
1103 if (pStreamR3->State.pCircBuf)
1104 return (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
1105 return 0;
1106}
1107
1108/**
1109 * Retrieves the free size of audio data (in bytes) of a given HDA stream.
1110 *
1111 * @returns Free data (in bytes).
1112 * @param pStreamR3 HDA stream to retrieve size for (ring-3).
1113 */
1114static uint32_t hdaR3StreamGetFree(PHDASTREAMR3 pStreamR3)
1115{
1116 AssertPtrReturn(pStreamR3, 0);
1117
1118 if (pStreamR3->State.pCircBuf)
1119 return (uint32_t)RTCircBufFree(pStreamR3->State.pCircBuf);
1120 return 0;
1121}
1122
1123/**
1124 * Get the current address and number of bytes left in the current BDLE.
1125 *
1126 * @returns The current physical address.
1127 * @param pStreamShared The stream to check.
1128 * @param pcbLeft The number of bytes left at the returned address.
1129 */
1130DECLINLINE(RTGCPHYS) hdaR3StreamDmaBufGet(PHDASTREAM pStreamShared, uint32_t *pcbLeft)
1131{
1132 uint8_t idxBdle = pStreamShared->State.idxCurBdle;
1133 AssertStmt(idxBdle < pStreamShared->State.cBdles, idxBdle = 0);
1134
1135 uint32_t const cbCurBdl = pStreamShared->State.aBdl[idxBdle].cb;
1136 uint32_t offCurBdle = pStreamShared->State.offCurBdle;
1137 AssertStmt(pStreamShared->State.offCurBdle <= cbCurBdl, offCurBdle = cbCurBdl);
1138
1139 *pcbLeft = cbCurBdl - offCurBdle;
1140 return pStreamShared->State.aBdl[idxBdle].GCPhys + offCurBdle;
1141}
1142
1143/**
1144 * Get the size of the current BDLE.
1145 *
1146 * @returns The size (in bytes).
1147 * @param pStreamShared The stream to check.
1148 */
1149DECLINLINE(RTGCPHYS) hdaR3StreamDmaBufGetSize(PHDASTREAM pStreamShared)
1150{
1151 uint8_t idxBdle = pStreamShared->State.idxCurBdle;
1152 AssertStmt(idxBdle < pStreamShared->State.cBdles, idxBdle = 0);
1153 return pStreamShared->State.aBdl[idxBdle].cb;
1154}
1155
1156/**
1157 * Checks if the current BDLE is completed.
1158 *
1159 * @retval true if complete
1160 * @retval false if not.
1161 * @param pStreamShared The stream to check.
1162 */
1163DECLINLINE(bool) hdaR3StreamDmaBufIsComplete(PHDASTREAM pStreamShared)
1164{
1165 uint8_t const idxBdle = pStreamShared->State.idxCurBdle;
1166 AssertReturn(idxBdle < pStreamShared->State.cBdles, true);
1167
1168 uint32_t const cbCurBdl = pStreamShared->State.aBdl[idxBdle].cb;
1169 uint32_t const offCurBdle = pStreamShared->State.offCurBdle;
1170 Assert(offCurBdle <= cbCurBdl);
1171 return offCurBdle >= cbCurBdl;
1172}
1173
1174/**
1175 * Checks if the current BDLE needs a completion IRQ.
1176 *
1177 * @retval true if IRQ is needed.
1178 * @retval false if not.
1179 * @param pStreamShared The stream to check.
1180 */
1181DECLINLINE(bool) hdaR3StreamDmaBufNeedsIrq(PHDASTREAM pStreamShared)
1182{
1183 uint8_t const idxBdle = pStreamShared->State.idxCurBdle;
1184 AssertReturn(idxBdle < pStreamShared->State.cBdles, false);
1185 return (pStreamShared->State.aBdl[idxBdle].fFlags & HDA_BDLE_F_IOC) != 0;
1186}
1187
1188/**
1189 * Advances the DMA engine to the next BDLE.
1190 *
1191 * @param pStreamShared The stream which DMA engine is to be updated.
1192 */
1193DECLINLINE(void) hdaR3StreamDmaBufAdvanceToNext(PHDASTREAM pStreamShared)
1194{
1195 uint8_t idxBdle = pStreamShared->State.idxCurBdle;
1196 Assert(pStreamShared->State.offCurBdle == pStreamShared->State.aBdl[idxBdle].cb);
1197
1198 if (idxBdle < pStreamShared->State.cBdles - 1)
1199 idxBdle++;
1200 else
1201 idxBdle = 0;
1202 pStreamShared->State.idxCurBdle = idxBdle;
1203 pStreamShared->State.offCurBdle = 0;
1204}
1205
1206/**
1207 * Common do-DMA prologue code.
1208 *
1209 * @retval true if DMA processing can take place
1210 * @retval false if caller should return immediately.
1211 * @param pThis The shared HDA device state.
1212 * @param pStreamShared HDA stream to update (shared).
1213 * @param pStreamR3 HDA stream to update (ring-3).
1214 * @param uSD The stream ID (for asserting).
1215 * @param tsNowNs The current RTTimeNano() value.
1216 * @param pszFunction The function name (for logging).
1217 */
1218DECLINLINE(bool) hdaR3StreamDoDmaPrologue(PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD,
1219 uint64_t tsNowNs, const char *pszFunction)
1220{
1221 RT_NOREF(uSD, pszFunction);
1222
1223 /*
1224 * Check if we should skip town...
1225 */
1226 /* Stream not running (anymore)? */
1227 if (pStreamShared->State.fRunning)
1228 { /* likely */ }
1229 else
1230 {
1231 Log3(("%s: [SD%RU8] Not running, skipping transfer\n", pszFunction, uSD));
1232 return false;
1233 }
1234
1235 if (!(HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS))
1236 { /* likely */ }
1237 else
1238 {
1239 /** @todo r=bird: This is a bit fishy. We should make effort the reschedule
1240 * the transfer immediately after the guest clears the interrupt.
1241 * The same fishy code is present in AC'97 with just a little
1242 * explanation as here, see @bugref{9890#c95}.
1243 *
1244 * The reasoning is probably that the developer noticed some windows
1245 * versions don't like having their BCIS interrupts bundled. There were
1246 * comments to that effect elsewhere, probably as a result of a fixed
1247 * uTimerHz approach to DMA scheduling. However, pausing DMA for a
1248 * period isn't going to help us with the host backends, as they don't
1249 * pause and will want samples ASAP. So, we should at least unpause
1250 * DMA as quickly as we possible when BCIS is cleared. We might even
1251 * not skip it iff the DMA work here doesn't involve raising any IOC,
1252 * which is possible although unlikely. */
1253 Log3(("%s: [SD%RU8] BCIS bit set, skipping transfer\n", pszFunction, uSD));
1254 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaSkippedPendingBcis);
1255 Log(("%s: [SD%RU8] BCIS bit set, skipping transfer\n", pszFunction, uSD));
1256# ifdef HDA_STRICT
1257 /* Timing emulation bug or guest is misbehaving -- let me know. */
1258 AssertMsgFailed(("%s: BCIS bit for stream #%RU8 still set when it shouldn't\n", pszFunction, uSD));
1259# endif
1260 return false;
1261 }
1262
1263 /*
1264 * Stream sanity checks.
1265 */
1266 /* Register sanity checks. */
1267 Assert(uSD < HDA_MAX_STREAMS);
1268 Assert(pStreamShared->u64BDLBase);
1269 Assert(pStreamShared->u32CBL);
1270 Assert(pStreamShared->u8FIFOS);
1271
1272 /* State sanity checks. */
1273 Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false);
1274 Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning));
1275
1276 /*
1277 * Some timestamp stuff for logging/debugging.
1278 */
1279 /*const uint64_t tsNowNs = RTTimeNanoTS();*/
1280 Log3(("%s: [SD%RU8] tsDeltaNs=%'RU64 ns\n", pszFunction, uSD, tsNowNs - pStreamShared->State.tsLastTransferNs));
1281 pStreamShared->State.tsLastTransferNs = tsNowNs;
1282
1283 return true;
1284}
1285
1286/**
1287 * Common do-DMA epilogue.
1288 *
1289 * @param pDevIns The device instance.
1290 * @param pStreamShared The HDA stream (shared).
1291 * @param pStreamR3 The HDA stream (ring-3).
1292 */
1293DECLINLINE(void) hdaR3StreamDoDmaEpilogue(PPDMDEVINS pDevIns, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
1294{
1295 /*
1296 * We must update this in the epilogue rather than in the prologue
1297 * as it is used for WALCLK calculation and we must make sure the
1298 * guest doesn't think we've processed the current period till we
1299 * actually have.
1300 */
1301 pStreamShared->State.tsTransferLast = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
1302
1303 /*
1304 * Update the buffer statistics.
1305 */
1306 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
1307}
1308
1309/**
1310 * Completes a BDLE at the end of a DMA loop iteration, if possible.
1311 *
1312 * @param pDevIns The device instance.
1313 * @param pThis The shared HDA device state.
1314 * @param pStreamShared HDA stream to update (shared).
1315 * @param pszFunction The function name (for logging).
1316 */
1317DECLINLINE(void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis,
1318 PHDASTREAM pStreamShared, const char *pszFunction)
1319{
1320 RT_NOREF(pszFunction);
1321
1322 /*
1323 * Is the buffer descriptor complete.
1324 */
1325 if (hdaR3StreamDmaBufIsComplete(pStreamShared))
1326 {
1327 Log3(("%s: [SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x\n", pszFunction, pStreamShared->u8SD,
1328 pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
1329 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
1330 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags));
1331
1332 /*
1333 * Update the stream's current position.
1334 *
1335 * Do this as accurate and close to the actual data transfer as possible.
1336 * All guests rely on this, depending on the mechanism they use (LPIB register or DMA counters).
1337 *
1338 * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated!
1339 * Not doing this at the right time will result in ugly sound crackles!
1340 */
1341 hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, hdaR3StreamDmaBufGetSize(pStreamShared));
1342
1343 /* Does the current BDLE require an interrupt to be sent? */
1344 if (hdaR3StreamDmaBufNeedsIrq(pStreamShared))
1345 {
1346 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL
1347 register is set we need to generate an interrupt. */
1348 if (HDA_STREAM_REG(pThis, CTL, pStreamShared->u8SD) & HDA_SDCTL_IOCE)
1349 {
1350 /* Assert the interrupt before actually fetching the next BDLE below. */
1351 pStreamShared->State.cTransferPendingInterrupts = 1;
1352 Log3(("%s: [SD%RU8] Scheduling interrupt\n", pszFunction, pStreamShared->u8SD));
1353
1354 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
1355 * ending / beginning of a period. */
1356 /** @todo r=bird: What does the above comment mean? */
1357 HDA_STREAM_REG(pThis, STS, pStreamShared->u8SD) |= HDA_SDSTS_BCIS;
1358 HDA_PROCESS_INTERRUPT(pDevIns, pThis);
1359 }
1360 }
1361
1362 /*
1363 * Advance to the next BDLE.
1364 */
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}
1373
1374/**
1375 * Does DMA transfer for an HDA input stream.
1376 *
1377 * Reads audio data from the HDA stream's internal DMA buffer and writing to
1378 * guest memory.
1379 *
1380 * @param pDevIns The device instance.
1381 * @param pThis The shared HDA device state.
1382 * @param pStreamShared HDA stream to update (shared).
1383 * @param pStreamR3 HDA stream to update (ring-3).
1384 * @param cbToConsume The max amount of data to consume from the
1385 * internal DMA buffer. The caller will make sure
1386 * this is always the transfer size fo the current
1387 * period (unless something is seriously wrong).
1388 * @param fWriteSilence Whether to feed the guest silence rather than
1389 * fetching bytes from the internal DMA buffer.
1390 * This is set initially while we pre-buffer a
1391 * little bit of input, so we can better handle
1392 * time catch-ups and other schduling fun.
1393 * @param tsNowNs The current RTTimeNano() value.
1394 *
1395 * @remarks Caller owns the stream lock.
1396 */
1397static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
1398 PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs)
1399{
1400 uint8_t const uSD = pStreamShared->u8SD;
1401 LogFlowFunc(("ENTER - #%u cbToConsume=%#x%s\n", uSD, cbToConsume, fWriteSilence ? " silence" : ""));
1402
1403 /*
1404 * Common prologue.
1405 */
1406 if (hdaR3StreamDoDmaPrologue(pThis, pStreamShared, pStreamR3, uSD, tsNowNs, "hdaR3StreamDoDmaInput"))
1407 { /* likely */ }
1408 else
1409 return;
1410
1411 /*
1412 *
1413 * The DMA copy loop.
1414 *
1415 */
1416 uint8_t abBounce[4096 + 128]; /* Most guest does at most 4KB BDLE. So, 4KB + space for a partial frame to reduce loops. */
1417 uint32_t cbBounce = 0; /* in case of incomplete frames between buffer segments */
1418 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf;
1419 uint32_t cbLeft = cbToConsume;
1420 Assert(cbLeft == pStreamShared->State.cbTransferSize);
1421 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft));
1422
1423 while (cbLeft > 0)
1424 {
1425 STAM_PROFILE_START(&pThis->StatIn, a);
1426
1427 /*
1428 * Figure out how much we can read & write in this iteration.
1429 */
1430 uint32_t cbChunk = 0;
1431 RTGCPHYS GCPhys = hdaR3StreamDmaBufGet(pStreamShared, &cbChunk);
1432
1433 /* If we're writing silence. */
1434 if (!fWriteSilence)
1435 {
1436 if (cbChunk <= cbLeft)
1437 { /* very likely */ }
1438 else
1439 cbChunk = cbLeft;
1440
1441 /*
1442 * Write the host data directly into the guest buffers.
1443 */
1444 while (cbChunk > 0)
1445 {
1446 /* Grab internal DMA buffer space and read into it. */
1447 void /*const*/ *pvBufSrc;
1448 size_t cbBufSrc;
1449 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvBufSrc, &cbBufSrc);
1450 AssertBreakStmt(cbBufSrc, RTCircBufReleaseReadBlock(pCircBuf, 0));
1451
1452 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBufSrc, cbBufSrc);
1453 AssertRC(rc2);
1454
1455# ifdef HDA_DEBUG_SILENCE
1456 fix me if relevant;
1457# endif
1458 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
1459 { /* likely */ }
1460 else
1461 AudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufSrc, cbBufSrc, 0 /* fFlags */);
1462
1463# ifdef VBOX_WITH_DTRACE
1464 VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBufSrc, pStreamR3->State.offRead);
1465# endif
1466 pStreamR3->State.offRead += cbBufSrc;
1467 RTCircBufReleaseReadBlock(pCircBuf, cbBufSrc);
1468 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufSrc);
1469
1470 /* advance */
1471 cbChunk -= (uint32_t)cbBufSrc;
1472 GCPhys += cbBufSrc;
1473 cbLeft -= (uint32_t)cbBufSrc;
1474 pStreamShared->State.offCurBdle += (uint32_t)cbBufSrc;
1475 }
1476 }
1477 /*
1478 * We've got some initial silence to write, or we need to do
1479 * channel mapping. We produce guest output into the bounce buffer,
1480 * which is then copied into guest memory. The bounce buffer may keep
1481 * partial frames there for the next BDLE, if an BDLE isn't frame aligned.
1482 *
1483 * Note! cbLeft is relative to the input (host) frame size.
1484 * cbChunk OTOH is relative to output (guest) size.
1485 */
1486 else
1487 {
1488/** @todo clean up host/guest props distinction, they're the same now w/o the
1489 * mapping done by the mixer rather than us. */
1490 PCPDMAUDIOPCMPROPS pGuestProps = &pStreamShared->State.Cfg.Props;
1491 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft));
1492 uint32_t const cbLeftGuest = PDMAudioPropsFramesToBytes(pGuestProps,
1493 PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props,
1494 cbLeft));
1495 if (cbChunk <= cbLeftGuest)
1496 { /* very likely */ }
1497 else
1498 cbChunk = cbLeftGuest;
1499
1500 /*
1501 * Work till we've covered the chunk.
1502 */
1503 Log5Func(("loop0: GCPhys=%RGp cbChunk=%#x + cbBounce=%#x\n", GCPhys, cbChunk, cbBounce));
1504 while (cbChunk > 0)
1505 {
1506 /* Figure out how much we need to convert into the bounce buffer: */
1507 uint32_t cbGuest = PDMAudioPropsRoundUpBytesToFrame(pGuestProps, cbChunk - cbBounce);
1508 uint32_t cFrames = PDMAudioPropsBytesToFrames(pGuestProps, RT_MIN(cbGuest, sizeof(abBounce) - cbBounce));
1509
1510 size_t cbBufSrc = PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFrames);
1511 cbGuest = PDMAudioPropsFramesToBytes(pGuestProps, cFrames);
1512 PDMAudioPropsClearBuffer(pGuestProps, &abBounce[cbBounce], cbGuest, cFrames);
1513 cbGuest += cbBounce;
1514
1515 /* Write it to the guest buffer. */
1516 uint32_t cbGuestActual = RT_MIN(cbGuest, cbChunk);
1517 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, abBounce, cbGuestActual);
1518 AssertRC(rc2);
1519 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbGuestActual);
1520
1521 /* advance */
1522 cbLeft -= (uint32_t)cbBufSrc;
1523 cbChunk -= cbGuestActual;
1524 GCPhys += cbGuestActual;
1525 pStreamShared->State.offCurBdle += cbGuestActual;
1526
1527 cbBounce = cbGuest - cbGuestActual;
1528 if (cbBounce)
1529 memmove(abBounce, &abBounce[cbGuestActual], cbBounce);
1530
1531 Log5Func((" loop1: GCPhys=%RGp cbGuestActual=%#x cbBounce=%#x cFrames=%#x\n", GCPhys, cbGuestActual, cbBounce, cFrames));
1532 }
1533 Log5Func(("loop0: GCPhys=%RGp cbBounce=%#x cbLeft=%#x\n", GCPhys, cbBounce, cbLeft));
1534 }
1535
1536 STAM_PROFILE_STOP(&pThis->StatIn, a);
1537
1538 /*
1539 * Complete the buffer if necessary (common with the output DMA code).
1540 */
1541 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaInput");
1542 }
1543
1544 Assert(cbLeft == 0); /* There shall be no break statements in the above loop, so cbLeft is always zero here! */
1545 AssertMsg(cbBounce == 0, ("%#x\n", cbBounce));
1546
1547 /*
1548 * Common epilogue.
1549 */
1550 hdaR3StreamDoDmaEpilogue(pDevIns, pStreamShared, pStreamR3);
1551
1552 /*
1553 * Log and leave.
1554 */
1555 Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
1556 uSD, cbToConsume, pStreamShared->State.cbTransferSize, pStreamR3->State.offRead - cbToConsume,
1557 pStreamShared->State.cTransferPendingInterrupts));
1558}
1559
1560
1561/**
1562 * Input streams: Pulls data from the mixer, putting it in the internal DMA
1563 * buffer.
1564 *
1565 * @param pStreamR3 HDA stream to update (ring-3 bits).
1566 * @param pSink The mixer sink to pull from.
1567 */
1568static void hdaR3StreamPullFromMixer(PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink)
1569{
1570# ifdef LOG_ENABLED
1571 uint64_t const offWriteOld = pStreamR3->State.offWrite;
1572# endif
1573 pStreamR3->State.offWrite = AudioMixerSinkTransferToCircBuf(pSink,
1574 pStreamR3->State.pCircBuf,
1575 pStreamR3->State.offWrite,
1576 pStreamR3->u8SD,
1577 pStreamR3->Dbg.Runtime.fEnabled
1578 ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
1579
1580 Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
1581 pStreamR3->State.offWrite - offWriteOld, pStreamR3->State.offWrite));
1582
1583 /* Update buffer stats. */
1584 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
1585}
1586
1587
1588/**
1589 * Does DMA transfer for an HDA output stream.
1590 *
1591 * This transfers one DMA timer period worth of data from the guest and into the
1592 * internal DMA buffer.
1593 *
1594 * @param pDevIns The device instance.
1595 * @param pThis The shared HDA device state.
1596 * @param pStreamShared HDA stream to update (shared).
1597 * @param pStreamR3 HDA stream to update (ring-3).
1598 * @param cbToProduce The max amount of data to produce (i.e. put into
1599 * the circular buffer). Unless something is going
1600 * seriously wrong, this will always be transfer
1601 * size for the current period.
1602 * @param tsNowNs The current RTTimeNano() value.
1603 *
1604 * @remarks Caller owns the stream lock.
1605 */
1606static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
1607 PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs)
1608{
1609 uint8_t const uSD = pStreamShared->u8SD;
1610 LogFlowFunc(("ENTER - #%u cbToProduce=%#x\n", uSD, cbToProduce));
1611
1612 /*
1613 * Common prologue.
1614 */
1615 if (hdaR3StreamDoDmaPrologue(pThis, pStreamShared, pStreamR3, uSD, tsNowNs, "hdaR3StreamDoDmaOutput"))
1616 { /* likely */ }
1617 else
1618 return;
1619
1620 /*
1621 *
1622 * The DMA copy loop.
1623 *
1624 */
1625# if 0
1626 uint8_t abBounce[4096 + 128]; /* Most guest does at most 4KB BDLE. So, 4KB + space for a partial frame to reduce loops. */
1627 uint32_t cbBounce = 0; /* in case of incomplete frames between buffer segments */
1628# endif
1629 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf;
1630 uint32_t cbLeft = cbToProduce;
1631 Assert(cbLeft == pStreamShared->State.cbTransferSize);
1632 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft));
1633
1634 while (cbLeft > 0)
1635 {
1636 STAM_PROFILE_START(&pThis->StatOut, a);
1637
1638 /*
1639 * Figure out how much we can read & write in this iteration.
1640 */
1641 uint32_t cbChunk = 0;
1642 RTGCPHYS GCPhys = hdaR3StreamDmaBufGet(pStreamShared, &cbChunk);
1643
1644 /* Need to diverge if the BDLEs contain misaligned entries. */
1645# if 0
1646 if (/** @todo pStreamShared->State.fFrameAlignedBuffers */)
1647# endif
1648 {
1649 if (cbChunk <= cbLeft)
1650 { /* very likely */ }
1651 else
1652 cbChunk = cbLeft;
1653
1654 /*
1655 * Read the guest data directly into the internal DMA buffer.
1656 */
1657 while (cbChunk > 0)
1658 {
1659 /* Grab internal DMA buffer space and read into it. */
1660 void *pvBufDst;
1661 size_t cbBufDst;
1662 RTCircBufAcquireWriteBlock(pCircBuf, cbChunk, &pvBufDst, &cbBufDst);
1663 AssertBreakStmt(cbBufDst, RTCircBufReleaseWriteBlock(pCircBuf, 0));
1664
1665 int rc2 = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBufDst, cbBufDst);
1666 AssertRC(rc2);
1667
1668# ifdef HDA_DEBUG_SILENCE
1669 fix me if relevant;
1670# endif
1671 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
1672 { /* likely */ }
1673 else
1674 AudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufDst, cbBufDst, 0 /* fFlags */);
1675
1676# ifdef VBOX_WITH_DTRACE
1677 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBufDst, pStreamR3->State.offWrite);
1678# endif
1679 pStreamR3->State.offWrite += cbBufDst;
1680 RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst);
1681 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufDst);
1682
1683 /* advance */
1684 cbChunk -= (uint32_t)cbBufDst;
1685 GCPhys += cbBufDst;
1686 cbLeft -= (uint32_t)cbBufDst;
1687 pStreamShared->State.offCurBdle += (uint32_t)cbBufDst;
1688 }
1689 }
1690# if 0
1691 /*
1692 * Need to map the frame content, so we need to read the guest data
1693 * into a temporary buffer, though the output can be directly written
1694 * into the internal buffer as it is assumed to be frame aligned.
1695 *
1696 * Note! cbLeft is relative to the output frame size.
1697 * cbChunk OTOH is relative to input size.
1698 */
1699 else
1700 {
1701/** @todo clean up host/guest props distinction, they're the same now w/o the
1702 * mapping done by the mixer rather than us. */
1703 PCPDMAUDIOPCMPROPS pGuestProps = &pStreamShared->State.Cfg.Props;
1704 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft));
1705 uint32_t const cbLeftGuest = PDMAudioPropsFramesToBytes(pGuestProps,
1706 PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props,
1707 cbLeft));
1708 if (cbChunk <= cbLeftGuest)
1709 { /* very likely */ }
1710 else
1711 cbChunk = cbLeftGuest;
1712
1713 /*
1714 * Loop till we've covered the chunk.
1715 */
1716 Log5Func(("loop0: GCPhys=%RGp cbChunk=%#x + cbBounce=%#x\n", GCPhys, cbChunk, cbBounce));
1717 while (cbChunk > 0)
1718 {
1719 /* Read into the bounce buffer. */
1720 uint32_t const cbToRead = RT_MIN(cbChunk, sizeof(abBounce) - cbBounce);
1721 int rc2 = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &abBounce[cbBounce], cbToRead);
1722 AssertRC(rc2);
1723 cbBounce += cbToRead;
1724
1725 /* Convert the size to whole frames and a remainder. */
1726 uint32_t cFrames = PDMAudioPropsBytesToFrames(pGuestProps, cbBounce);
1727 uint32_t const cbRemainder = cbBounce - PDMAudioPropsFramesToBytes(pGuestProps, cFrames);
1728 Log5Func((" loop1: GCPhys=%RGp cbToRead=%#x cbBounce=%#x cFrames=%#x\n", GCPhys, cbToRead, cbBounce, cFrames));
1729
1730 /*
1731 * Convert from the bounce buffer and into the internal DMA buffer.
1732 */
1733 uint32_t offBounce = 0;
1734 while (cFrames > 0)
1735 {
1736 void *pvBufDst;
1737 size_t cbBufDst;
1738 RTCircBufAcquireWriteBlock(pCircBuf, PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFrames),
1739 &pvBufDst, &cbBufDst);
1740
1741 uint32_t const cFramesToConvert = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, (uint32_t)cbBufDst);
1742 Assert(PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFramesToConvert) == cbBufDst);
1743 Assert(cFramesToConvert > 0);
1744 Assert(cFramesToConvert <= cFrames);
1745
1746 pStreamR3->State.Mapping.pfnGuestToHost(pvBufDst, &abBounce[offBounce], cFramesToConvert,
1747 &pStreamR3->State.Mapping);
1748 Log5Func((" loop2: offBounce=%#05x cFramesToConvert=%#05x cbBufDst=%#x%s\n",
1749 offBounce, cFramesToConvert, cbBufDst, ASMMemIsZero(pvBufDst, cbBufDst) ? " all zero" : ""));
1750
1751# ifdef HDA_DEBUG_SILENCE
1752 fix me if relevant;
1753# endif
1754 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
1755 { /* likely */ }
1756 else
1757 AudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufDst, cbBufDst, 0 /* fFlags */);
1758
1759 pStreamR3->State.offWrite += cbBufDst;
1760 RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst);
1761 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufDst);
1762
1763 /* advance */
1764 cbLeft -= (uint32_t)cbBufDst;
1765 cFrames -= cFramesToConvert;
1766 offBounce += PDMAudioPropsFramesToBytes(pGuestProps, cFramesToConvert);
1767 }
1768
1769 /* advance */
1770 cbChunk -= cbToRead;
1771 GCPhys += cbToRead;
1772 pStreamShared->State.offCurBdle += cbToRead;
1773 if (cbRemainder)
1774 memmove(&abBounce[0], &abBounce[cbBounce - cbRemainder], cbRemainder);
1775 cbBounce = cbRemainder;
1776 }
1777 Log5Func(("loop0: GCPhys=%RGp cbBounce=%#x cbLeft=%#x\n", GCPhys, cbBounce, cbLeft));
1778 }
1779# endif
1780
1781 STAM_PROFILE_STOP(&pThis->StatOut, a);
1782
1783 /*
1784 * Complete the buffer if necessary (common with the output DMA code).
1785 */
1786 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaOutput");
1787 }
1788
1789 Assert(cbLeft == 0); /* There shall be no break statements in the above loop, so cbLeft is always zero here! */
1790# if 0
1791 AssertMsg(cbBounce == 0, ("%#x\n", cbBounce));
1792# endif
1793
1794 /*
1795 * Common epilogue.
1796 */
1797 hdaR3StreamDoDmaEpilogue(pDevIns, pStreamShared, pStreamR3);
1798
1799 /*
1800 * Log and leave.
1801 */
1802 Log3Func(("LEAVE - [SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n",
1803 uSD, cbToProduce, pStreamShared->State.cbTransferSize, pStreamR3->State.offWrite - cbToProduce,
1804 pStreamShared->State.cTransferPendingInterrupts));
1805}
1806
1807
1808/**
1809 * Output streams: Pushes data to the mixer.
1810 *
1811 * @param pStreamShared HDA stream to update (shared bits).
1812 * @param pStreamR3 HDA stream to update (ring-3 bits).
1813 * @param pSink The mixer sink to push to.
1814 * @param nsNow The current RTTimeNanoTS() value.
1815 */
1816static void hdaR3StreamPushToMixer(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink, uint64_t nsNow)
1817{
1818# ifdef LOG_ENABLED
1819 uint64_t const offReadOld = pStreamR3->State.offRead;
1820# endif
1821 pStreamR3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink,
1822 pStreamR3->State.pCircBuf,
1823 pStreamR3->State.offRead,
1824 pStreamR3->u8SD,
1825 pStreamR3->Dbg.Runtime.fEnabled
1826 ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
1827
1828 Assert(nsNow >= pStreamShared->State.tsLastReadNs);
1829 Log3Func(("[SD%RU8] nsDeltaLastRead=%RI64 transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
1830 nsNow - pStreamShared->State.tsLastReadNs, pStreamR3->State.offRead - offReadOld, pStreamR3->State.offRead));
1831 RT_NOREF(pStreamShared, nsNow);
1832
1833 /* Update buffer stats. */
1834 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
1835}
1836
1837
1838/**
1839 * The stream's main function when called by the timer.
1840 *
1841 * @note This function also will be called without timer invocation when
1842 * starting (enabling) the stream to minimize startup latency.
1843 *
1844 * @returns Current timer time if the timer is enabled, otherwise zero.
1845 * @param pDevIns The device instance.
1846 * @param pThis The shared HDA device state.
1847 * @param pThisCC The ring-3 HDA device state.
1848 * @param pStreamShared HDA stream to update (shared bits).
1849 * @param pStreamR3 HDA stream to update (ring-3 bits).
1850 */
1851uint64_t hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
1852 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
1853{
1854 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
1855 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStreamShared->hTimer));
1856
1857 /* Do the work: */
1858 hdaR3StreamUpdateDma(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
1859
1860 /* Re-arm the timer if the sink is still active: */
1861 if ( pStreamShared->State.fRunning
1862 && pStreamR3->pMixSink
1863 && AudioMixerSinkIsActive(pStreamR3->pMixSink->pMixSink))
1864 {
1865 /* Advance the schduling: */
1866 uint32_t idxSched = pStreamShared->State.idxSchedule;
1867 AssertStmt(idxSched < RT_ELEMENTS(pStreamShared->State.aSchedule), idxSched = 0);
1868 uint32_t idxLoop = pStreamShared->State.idxScheduleLoop + 1;
1869 if (idxLoop >= pStreamShared->State.aSchedule[idxSched].cLoops)
1870 {
1871 idxSched += 1;
1872 if ( idxSched >= pStreamShared->State.cSchedule
1873 || idxSched >= RT_ELEMENTS(pStreamShared->State.aSchedule) /*paranoia^2*/)
1874 {
1875 idxSched = pStreamShared->State.cSchedulePrologue;
1876 AssertStmt(idxSched < RT_ELEMENTS(pStreamShared->State.aSchedule), idxSched = 0);
1877 }
1878 pStreamShared->State.idxSchedule = idxSched;
1879 idxLoop = 0;
1880 }
1881 pStreamShared->State.idxScheduleLoop = (uint16_t)idxLoop;
1882
1883 /* Do the actual timer re-arming. */
1884 uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); /* (For virtual sync this remains the same for the whole callout IIRC) */
1885 uint64_t const tsTransferNext = tsNow + pStreamShared->State.aSchedule[idxSched].cPeriodTicks;
1886 Log3Func(("[SD%RU8] fSinkActive=true, tsTransferNext=%RU64 (in %RU64)\n",
1887 pStreamShared->u8SD, tsTransferNext, tsTransferNext - tsNow));
1888 int rc = PDMDevHlpTimerSet(pDevIns, pStreamShared->hTimer, tsTransferNext);
1889 AssertRC(rc);
1890
1891 /* Some legacy stuff: */
1892 pStreamShared->State.tsTransferNext = tsTransferNext;
1893 pStreamShared->State.cbTransferSize = pStreamShared->State.aSchedule[idxSched].cbPeriod;
1894
1895 return tsNow;
1896 }
1897
1898 Log3Func(("[SD%RU8] fSinkActive=false\n", pStreamShared->u8SD));
1899 return 0;
1900}
1901
1902
1903/**
1904 * Updates a HDA stream by doing DMA transfers.
1905 *
1906 * Will do mixer transfers too to try fix an overrun/underrun situation.
1907 *
1908 * The host sink(s) set the overall pace (bird: no it doesn't, the DMA timer
1909 * does - we just hope like heck it matches the speed at which the *backend*
1910 * host audio driver processes samples).
1911 *
1912 * @param pDevIns The device instance.
1913 * @param pThis The shared HDA device state.
1914 * @param pThisCC The ring-3 HDA device state.
1915 * @param pStreamShared HDA stream to update (shared bits).
1916 * @param pStreamR3 HDA stream to update (ring-3 bits).
1917 */
1918static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
1919 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
1920{
1921 RT_NOREF(pThisCC);
1922 int rc2;
1923
1924 /*
1925 * Make sure we're running and got an active mixer sink.
1926 */
1927 if (RT_LIKELY(pStreamShared->State.fRunning))
1928 { /* likely */ }
1929 else
1930 return;
1931
1932 PAUDMIXSINK pSink = NULL;
1933 if (pStreamR3->pMixSink)
1934 pSink = pStreamR3->pMixSink->pMixSink;
1935 if (RT_LIKELY(AudioMixerSinkIsActive(pSink)))
1936 { /* likely */ }
1937 else
1938 return;
1939
1940 /*
1941 * Get scheduling info common to both input and output streams.
1942 */
1943 const uint64_t tsNowNs = RTTimeNanoTS();
1944 uint32_t idxSched = pStreamShared->State.idxSchedule;
1945 AssertStmt(idxSched < RT_MIN(RT_ELEMENTS(pStreamShared->State.aSchedule), pStreamShared->State.cSchedule), idxSched = 0);
1946 uint32_t const cbPeriod = pStreamShared->State.aSchedule[idxSched].cbPeriod;
1947
1948 /*
1949 * Output streams (SDO).
1950 */
1951 if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT)
1952 {
1953 /*
1954 * Check how much room we have in our DMA buffer. There should be at
1955 * least one period worth of space there or we're in an overflow situation.
1956 */
1957 uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
1958 if (cbStreamFree >= cbPeriod)
1959 { /* likely */ }
1960 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 }
1994
1995 /*
1996 * Do the DMA transfer.
1997 */
1998 uint64_t const offWriteBefore = pStreamR3->State.offWrite;
1999 hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
2000
2001 /*
2002 * Should we push data to down thru the mixer to and to the host drivers?
2003 *
2004 * We initially delay this by pThis->msInitialDelay, but after than we'll
2005 * kick the AIO thread every time we've put more data in the buffer (which is
2006 * every time) as the host audio device needs to get data in a timely manner.
2007 *
2008 * (We used to try only wake up the AIO thread according to pThis->uIoTimer
2009 * and host wall clock, but that meant we would miss a wakup after the DMA
2010 * timer was called a little late or if TM entered into catch-up mode.)
2011 */
2012 bool fKickAioThread;
2013 if (!pStreamShared->State.tsAioDelayEnd)
2014 fKickAioThread = pStreamR3->State.offWrite > offWriteBefore
2015 || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2;
2016 else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd)
2017 {
2018 Log3Func(("Initial delay done: Passed tsAioDelayEnd.\n"));
2019 pStreamShared->State.tsAioDelayEnd = 0;
2020 fKickAioThread = true;
2021 }
2022 else if (hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2)
2023 {
2024 Log3Func(("Initial delay done: Passed running short on buffer.\n"));
2025 pStreamShared->State.tsAioDelayEnd = 0;
2026 fKickAioThread = true;
2027 }
2028 else
2029 {
2030 Log3Func(("Initial delay pending...\n"));
2031 fKickAioThread = false;
2032 }
2033
2034 Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fKickAioThread=%RTbool\n",
2035 (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS,
2036 pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree,
2037 pStreamShared->State.cbAvgTransfer * 2, fKickAioThread));
2038
2039 if (fKickAioThread)
2040 {
2041 /* Notify the async I/O worker thread that there's work to do. */
2042 Log5Func(("Notifying AIO thread\n"));
2043 rc2 = AudioMixerSinkSignalUpdateJob(pSink);
2044 AssertRC(rc2);
2045 /* Update last read timestamp for logging/debugging. */
2046 pStreamShared->State.tsLastReadNs = tsNowNs;
2047 }
2048 }
2049 /*
2050 * Input stream (SDI).
2051 */
2052 else
2053 {
2054 Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN);
2055
2056 /*
2057 * See how much data we've got buffered...
2058 */
2059 bool fWriteSilence = false;
2060 uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
2061 if (pStreamShared->State.fInputPreBuffered && cbStreamUsed >= cbPeriod)
2062 { /*likely*/ }
2063 /*
2064 * Because it may take a while for the input stream to get going (at
2065 * least with pulseaudio), we feed the guest silence till we've
2066 * pre-buffer a reasonable amount of audio.
2067 */
2068 else if (!pStreamShared->State.fInputPreBuffered)
2069 {
2070 if (cbStreamUsed < pStreamShared->State.cbInputPreBuffer)
2071 {
2072 Log3(("hdaR3StreamUpdateDma: Pre-buffering (got %#x out of %#x bytes)...\n",
2073 cbStreamUsed, pStreamShared->State.cbInputPreBuffer));
2074 fWriteSilence = true;
2075 }
2076 else
2077 {
2078 Log3(("hdaR3StreamUpdateDma: Completed pre-buffering (got %#x, needed %#x bytes).\n",
2079 cbStreamUsed, pStreamShared->State.cbInputPreBuffer));
2080 pStreamShared->State.fInputPreBuffered = true;
2081 fWriteSilence = true; /* For now, just do the most conservative thing. */
2082 }
2083 cbStreamUsed = cbPeriod;
2084 }
2085 /*
2086 * When we're low on data, we must really try fetch some ourselves
2087 * as buffer underruns must not happen.
2088 */
2089 else
2090 {
2091 /** @todo We're ending up here to frequently with pulse audio at least (just
2092 * watch the stream stats in the statistcs viewer, and way to often we
2093 * have to inject silence bytes. I suspect part of the problem is
2094 * that the HDA device require a much better latency than what the
2095 * pulse audio is configured for by default (10 ms vs 150ms). */
2096 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
2097 Log(("hdaR3StreamUpdateDma: Warning! Stream #%u has insufficient data available: %u bytes, need %u. Will try move pull more data into the buffer...\n",
2098 pStreamShared->u8SD, cbStreamUsed, cbPeriod));
2099 int rc = AudioMixerSinkTryLock(pSink);
2100 if (RT_SUCCESS(rc))
2101 {
2102 AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod);
2103 hdaR3StreamPullFromMixer(pStreamR3, pSink);
2104 AudioMixerSinkUnlock(pSink);
2105 }
2106 else
2107 RTThreadYield();
2108 Log(("hdaR3StreamUpdateDma: Gained %u bytes.\n", hdaR3StreamGetUsed(pStreamR3) - cbStreamUsed));
2109 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
2110 if (cbStreamUsed < cbPeriod)
2111 {
2112 /* Unable to find sufficient input data by simple prodding.
2113 In order to keep a constant byte stream following thru the DMA
2114 engine into the guest, we will try again and then fall back on
2115 filling the gap with silence. */
2116 uint32_t cbSilence = 0;
2117 do
2118 {
2119 AudioMixerSinkLock(pSink);
2120
2121 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
2122 if (cbStreamUsed < cbPeriod)
2123 {
2124 hdaR3StreamPullFromMixer(pStreamR3, pSink);
2125 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
2126 while (cbStreamUsed < cbPeriod)
2127 {
2128 void *pvDstBuf;
2129 size_t cbDstBuf;
2130 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbPeriod - cbStreamUsed,
2131 &pvDstBuf, &cbDstBuf);
2132 RT_BZERO(pvDstBuf, cbDstBuf);
2133 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbDstBuf);
2134 cbSilence += (uint32_t)cbDstBuf;
2135 cbStreamUsed += (uint32_t)cbDstBuf;
2136 }
2137 }
2138
2139 AudioMixerSinkUnlock(pSink);
2140 } while (cbStreamUsed < cbPeriod);
2141 if (cbSilence > 0)
2142 {
2143 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
2144 STAM_REL_COUNTER_ADD(&pStreamR3->State.StatDmaFlowErrorBytes, cbSilence);
2145 LogRel2(("HDA: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamShared->u8SD,
2146 cbSilence, PDMAudioPropsBytesToMicro(&pStreamShared->State.Cfg.Props, cbSilence)));
2147 }
2148 }
2149 }
2150
2151 /*
2152 * Do the DMA'ing.
2153 */
2154 if (cbStreamUsed)
2155 hdaR3StreamDoDmaInput(pDevIns, pThis, pStreamShared, pStreamR3,
2156 RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs);
2157
2158 /*
2159 * We should always kick the AIO thread.
2160 */
2161 /** @todo This isn't entirely ideal. If we get into an underrun situation,
2162 * we ideally want the AIO thread to run right before the DMA timer
2163 * rather than right after it ran. */
2164 Log5Func(("Notifying AIO thread\n"));
2165 rc2 = AudioMixerSinkSignalUpdateJob(pSink);
2166 AssertRC(rc2);
2167 pStreamShared->State.tsLastReadNs = tsNowNs;
2168 }
2169}
2170
2171
2172/**
2173 * @callback_method_impl{FNAUDMIXSINKUPDATE}
2174 *
2175 * For output streams this moves data from the internal DMA buffer (in which
2176 * hdaR3StreamUpdateDma put it), thru the mixer and to the various backend audio
2177 * devices.
2178 *
2179 * For input streams this pulls data from the backend audio device(s), thru the
2180 * mixer and puts it in the internal DMA buffer ready for hdaR3StreamUpdateDma
2181 * to pump into guest memory.
2182 */
2183DECLCALLBACK(void) hdaR3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser)
2184{
2185 PHDASTATE const pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
2186 PHDASTATER3 const pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2187 PHDASTREAMR3 const pStreamR3 = (PHDASTREAMR3)pvUser;
2188 PHDASTREAM const pStreamShared = &pThis->aStreams[pStreamR3 - &pThisCC->aStreams[0]];
2189 Assert(pStreamR3 - &pThisCC->aStreams[0] == pStreamR3->u8SD);
2190 Assert(pStreamShared->u8SD == pStreamR3->u8SD);
2191 RT_NOREF(pSink);
2192
2193 /*
2194 * Make sure we haven't change sink and that it's still active (it
2195 * should be or we wouldn't have been called).
2196 */
2197 AssertReturnVoid(pStreamR3->pMixSink && pSink == pStreamR3->pMixSink->pMixSink);
2198 AssertReturnVoid(AudioMixerSinkIsActive(pSink));
2199
2200 /*
2201 * Output streams (SDO).
2202 */
2203 if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT)
2204 hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, RTTimeNanoTS());
2205 /*
2206 * Input stream (SDI).
2207 */
2208 else
2209 {
2210 Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN);
2211 hdaR3StreamPullFromMixer(pStreamR3, pSink);
2212 }
2213}
2214
2215
2216# if 0 /* unused - no prototype even */
2217/**
2218 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
2219 * updating its associated LPIB register and DMA position buffer (if enabled).
2220 *
2221 * @returns Set LPIB value.
2222 * @param pDevIns The device instance.
2223 * @param pStream HDA stream to update read / write position for.
2224 * @param u32LPIB New LPIB (position) value to set.
2225 */
2226uint32_t hdaR3StreamUpdateLPIB(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint32_t u32LPIB)
2227{
2228 AssertMsg(u32LPIB <= pStreamShared->u32CBL,
2229 ("[SD%RU8] New LPIB (%RU32) exceeds CBL (%RU32)\n", pStreamShared->u8SD, u32LPIB, pStreamShared->u32CBL));
2230
2231 u32LPIB = RT_MIN(u32LPIB, pStreamShared->u32CBL);
2232
2233 LogFlowFunc(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
2234 pStreamShared->u8SD, u32LPIB, pThis->fDMAPosition));
2235
2236 /* Update LPIB in any case. */
2237 HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = u32LPIB;
2238
2239 /* Do we need to tell the current DMA position? */
2240 if (pThis->fDMAPosition)
2241 {
2242 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns,
2243 pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)),
2244 (void *)&u32LPIB, sizeof(uint32_t));
2245 AssertRC(rc2);
2246 }
2247
2248 return u32LPIB;
2249}
2250# endif
2251
2252# ifdef HDA_USE_DMA_ACCESS_HANDLER
2253/**
2254 * Registers access handlers for a stream's BDLE DMA accesses.
2255 *
2256 * @returns true if registration was successful, false if not.
2257 * @param pStream HDA stream to register BDLE access handlers for.
2258 */
2259bool hdaR3StreamRegisterDMAHandlers(PHDASTREAM pStream)
2260{
2261 /* At least LVI and the BDL base must be set. */
2262 if ( !pStreamShared->u16LVI
2263 || !pStreamShared->u64BDLBase)
2264 {
2265 return false;
2266 }
2267
2268 hdaR3StreamUnregisterDMAHandlers(pStream);
2269
2270 LogFunc(("Registering ...\n"));
2271
2272 int rc = VINF_SUCCESS;
2273
2274 /*
2275 * Create BDLE ranges.
2276 */
2277
2278 struct BDLERANGE
2279 {
2280 RTGCPHYS uAddr;
2281 uint32_t uSize;
2282 } arrRanges[16]; /** @todo Use a define. */
2283
2284 size_t cRanges = 0;
2285
2286 for (uint16_t i = 0; i < pStreamShared->u16LVI + 1; i++)
2287 {
2288 HDABDLE BDLE;
2289 rc = hdaR3BDLEFetch(pDevIns, &BDLE, pStreamShared->u64BDLBase, i /* Index */);
2290 if (RT_FAILURE(rc))
2291 break;
2292
2293 bool fAddRange = true;
2294 BDLERANGE *pRange;
2295
2296 if (cRanges)
2297 {
2298 pRange = &arrRanges[cRanges - 1];
2299
2300 /* Is the current range a direct neighbor of the current BLDE? */
2301 if ((pRange->uAddr + pRange->uSize) == BDLE.Desc.u64BufAddr)
2302 {
2303 /* Expand the current range by the current BDLE's size. */
2304 pRange->uSize += BDLE.Desc.u32BufSize;
2305
2306 /* Adding a new range in this case is not needed anymore. */
2307 fAddRange = false;
2308
2309 LogFunc(("Expanding range %zu by %RU32 (%RU32 total now)\n", cRanges - 1, BDLE.Desc.u32BufSize, pRange->uSize));
2310 }
2311 }
2312
2313 /* Do we need to add a new range? */
2314 if ( fAddRange
2315 && cRanges < RT_ELEMENTS(arrRanges))
2316 {
2317 pRange = &arrRanges[cRanges];
2318
2319 pRange->uAddr = BDLE.Desc.u64BufAddr;
2320 pRange->uSize = BDLE.Desc.u32BufSize;
2321
2322 LogFunc(("Adding range %zu - 0x%x (%RU32)\n", cRanges, pRange->uAddr, pRange->uSize));
2323
2324 cRanges++;
2325 }
2326 }
2327
2328 LogFunc(("%zu ranges total\n", cRanges));
2329
2330 /*
2331 * Register all ranges as DMA access handlers.
2332 */
2333
2334 for (size_t i = 0; i < cRanges; i++)
2335 {
2336 BDLERANGE *pRange = &arrRanges[i];
2337
2338 PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)RTMemAllocZ(sizeof(HDADMAACCESSHANDLER));
2339 if (!pHandler)
2340 {
2341 rc = VERR_NO_MEMORY;
2342 break;
2343 }
2344
2345 RTListAppend(&pStream->State.lstDMAHandlers, &pHandler->Node);
2346
2347 pHandler->pStream = pStream; /* Save a back reference to the owner. */
2348
2349 char szDesc[32];
2350 RTStrPrintf(szDesc, sizeof(szDesc), "HDA[SD%RU8 - RANGE%02zu]", pStream->u8SD, i);
2351
2352 int rc2 = PGMR3HandlerPhysicalTypeRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3), PGMPHYSHANDLERKIND_WRITE,
2353 hdaDMAAccessHandler,
2354 NULL, NULL, NULL,
2355 NULL, NULL, NULL,
2356 szDesc, &pHandler->hAccessHandlerType);
2357 AssertRCBreak(rc2);
2358
2359 pHandler->BDLEAddr = pRange->uAddr;
2360 pHandler->BDLESize = pRange->uSize;
2361
2362 /* Get first and last pages of the BDLE range. */
2363 RTGCPHYS pgFirst = pRange->uAddr & ~PAGE_OFFSET_MASK;
2364 RTGCPHYS pgLast = RT_ALIGN(pgFirst + pRange->uSize, PAGE_SIZE);
2365
2366 /* Calculate the region size (in pages). */
2367 RTGCPHYS regionSize = RT_ALIGN(pgLast - pgFirst, PAGE_SIZE);
2368
2369 pHandler->GCPhysFirst = pgFirst;
2370 pHandler->GCPhysLast = pHandler->GCPhysFirst + (regionSize - 1);
2371
2372 LogFunc((" Registering region '%s': %#RGp - %#RGp (region size: %#zx)\n",
2373 szDesc, pHandler->GCPhysFirst, pHandler->GCPhysLast, regionSize));
2374 LogFunc((" BDLE @ %#RGp - %#RGp (%#RX32)\n",
2375 pHandler->BDLEAddr, pHandler->BDLEAddr + pHandler->BDLESize, pHandler->BDLESize));
2376
2377 rc2 = PGMHandlerPhysicalRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),
2378 pHandler->GCPhysFirst, pHandler->GCPhysLast,
2379 pHandler->hAccessHandlerType, pHandler, NIL_RTR0PTR, NIL_RTRCPTR,
2380 szDesc);
2381 AssertRCBreak(rc2);
2382
2383 pHandler->fRegistered = true;
2384 }
2385
2386 LogFunc(("Registration ended with rc=%Rrc\n", rc));
2387
2388 return RT_SUCCESS(rc);
2389}
2390
2391/**
2392 * Unregisters access handlers of a stream's BDLEs.
2393 *
2394 * @param pStream HDA stream to unregister BDLE access handlers for.
2395 */
2396void hdaR3StreamUnregisterDMAHandlers(PHDASTREAM pStream)
2397{
2398 LogFunc(("\n"));
2399
2400 PHDADMAACCESSHANDLER pHandler, pHandlerNext;
2401 RTListForEachSafe(&pStream->State.lstDMAHandlers, pHandler, pHandlerNext, HDADMAACCESSHANDLER, Node)
2402 {
2403 if (!pHandler->fRegistered) /* Handler not registered? Skip. */
2404 continue;
2405
2406 LogFunc(("Unregistering 0x%x - 0x%x (%zu)\n",
2407 pHandler->GCPhysFirst, pHandler->GCPhysLast, pHandler->GCPhysLast - pHandler->GCPhysFirst));
2408
2409 int rc2 = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),
2410 pHandler->GCPhysFirst);
2411 AssertRC(rc2);
2412
2413 RTListNodeRemove(&pHandler->Node);
2414
2415 RTMemFree(pHandler);
2416 pHandler = NULL;
2417 }
2418
2419 Assert(RTListIsEmpty(&pStream->State.lstDMAHandlers));
2420}
2421
2422# endif /* HDA_USE_DMA_ACCESS_HANDLER */
2423
2424#endif /* IN_RING3 */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette