Index: /trunk/src/VBox/Devices/Audio/DevHDA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 87862)
+++ /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 87863)
@@ -1152,49 +1152,4 @@
 }
 
-#ifdef IN_RING3
-/**
- * Returns the current maximum value the wall clock counter can be set to.
- *
- * This maximum value depends on all currently handled HDA streams and their own current timing.
- *
- * @return  Current maximum value the wall clock counter can be set to.
- * @param   pThis               The shared HDA device state.
- * @param   pThisCC             The ring-3 HDA device state.
- *
- * @remark  Does not actually set the wall clock counter.
- *
- * @todo r=bird: This function is in the wrong file.
- */
-static uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC)
-{
-    const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
-    const uint64_t u64FrontAbsWalClk  = pThisCC->SinkFront.pStreamShared
-                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period)  : 0;
-# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-#  error "Implement me!"
-# endif
-    const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared
-                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;
-# ifdef VBOX_WITH_HDA_MIC_IN
-    const uint64_t u64MicInAbsWalClk  = pThisCC->SinkMicIn.pStreamShared
-                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period)  : 0;
-# endif
-
-    uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);
-# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-#  error "Implement me!"
-# endif
-    u64WalClkNew          = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);
-# ifdef VBOX_WITH_HDA_MIC_IN
-    u64WalClkNew          = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);
-# endif
-
-    Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n",
-              u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew));
-
-    return u64WalClkNew;
-}
-#endif /* IN_RING3 */
-
 static VBOXSTRICTRC hdaRegReadWALCLK(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 {
@@ -1522,22 +1477,4 @@
 static VBOXSTRICTRC hdaRegWriteSDSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-#ifdef IN_RING3
-    const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, STS, iReg);
-    AssertReturn(uSD < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
-    PHDASTATER3 const  pThisCC       = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
-    PHDASTREAM const   pStreamShared = &pThis->aStreams[uSD];
-
-    /* We only need to take the virtual-sync lock if we want to call
-       PDMDevHlpTimerGet or hdaR3TimerSet later.  Only precondition for that
-       is that we've got a non-zero ticks-per-transfer value. */
-    uint64_t const cTransferTicks = pStreamShared->State.cTransferTicks;
-    if (cTransferTicks)
-    {
-        DEVHDA_UNLOCK(pDevIns, pThis);
-        DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStreamShared, VINF_IOM_R3_MMIO_WRITE);
-    }
-
-    hdaStreamLock(pStreamShared);
-
     uint32_t v = HDA_REG_IND(pThis, iReg);
 
@@ -1545,91 +1482,7 @@
     HDA_REG_IND(pThis, iReg) &= ~(u32Value & v);
 
-/** @todo r=bird: Check if we couldn't this stuff involving hdaR3StreamPeriodLock
- *  and IRQs after PDMDevHlpTimerUnlockClock. */
-
-    /*
-     * ...
-     */
-    /* Some guests tend to write SDnSTS even if the stream is not running.
-     * So make sure to check if the RUN bit is set first. */
-    const bool fRunning = pStreamShared->State.fRunning;
-
-    Log3Func(("[SD%RU8] fRunning=%RTbool %R[sdsts]\n", uSD, fRunning, v));
-
-    PHDASTREAMPERIOD pPeriod = &pStreamShared->State.Period;
-    if (hdaR3StreamPeriodNeedsInterrupt(pPeriod))
-        hdaR3StreamPeriodReleaseInterrupt(pPeriod);
-    if (hdaR3StreamPeriodIsComplete(pPeriod))
-    {
-        /* Make sure to try to update the WALCLK register if a period is complete.
-         * Use the maximum WALCLK value all (active) streams agree to. */
-        const uint64_t uWalClkMax = hdaR3WalClkGetMax(pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3));
-        if (uWalClkMax > hdaWalClkGetCurrent(pThis))
-            hdaR3WalClkSet(pThis, pThisCC, uWalClkMax, false /* fForce */);
-
-        hdaR3StreamPeriodEnd(pPeriod);
-
-        if (fRunning)
-            hdaR3StreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis) /* Use current wall clock time */);
-    }
-
     HDA_PROCESS_INTERRUPT(pDevIns, pThis);
 
-    /*
-     * ...
-     */
-    uint64_t cTicksToNext = pStreamShared->State.cTransferTicks;
-    if (cTicksToNext) /* Only do any calculations if the stream currently is set up for transfers. */
-    {
-        const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
-        if (!pStreamShared->State.tsTransferLast)
-            pStreamShared->State.tsTransferLast = tsNow;
-        Assert(tsNow >= pStreamShared->State.tsTransferLast);
-
-        const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast;
-
-        Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksToNext=%RU64\n",
-                  uSD, cTicksElapsed, cTicksToNext));
-
-        if (cTicksElapsed <= cTicksToNext)
-            cTicksToNext = cTicksToNext - cTicksElapsed;
-        else /* Catch up. */
-        {
-            Log3Func(("[SD%RU8] Warning: Lagging behind (%RU64 ticks elapsed, maximum allowed is %RU64)\n",
-                     uSD, cTicksElapsed, cTicksToNext));
-
-            LogRelMax2(128, ("HDA: Stream #%RU8 interrupt lagging behind (expected %RU64us, got %RU64us, %RU8 pending interrupts), trying to catch up ...\n",
-                             uSD, cTicksToNext / 1000,  cTicksElapsed / 1000, pStreamShared->State.cTransferPendingInterrupts));
-
-            cTicksToNext = pStreamShared->State.cbTransferSize * pStreamShared->State.cTicksPerByte;
-        }
-
-        Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", uSD, cTicksToNext));
-
-        /* Reset processed data counter. */
-        pStreamShared->State.tsTransferNext = tsNow + cTicksToNext;
-
-        /* Only re-arm the timer if there were pending transfer interrupts left
-         *  -- it could happen that we land in here if a guest writes to SDnSTS
-         * unconditionally. */
-        if (pStreamShared->State.cTransferPendingInterrupts)
-        {
-            pStreamShared->State.cTransferPendingInterrupts--;
-
-            /* Re-arm the timer. */
-            LogFunc(("[SD%RU8] Timer set\n", uSD));
-            hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext,
-                          true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/);
-        }
-    }
-
-    if (cTransferTicks)
-        PDMDevHlpTimerUnlockClock(pDevIns, pStreamShared->hTimer); /* Caller will unlock pThis->CritSect. */
-    hdaStreamUnlock(pStreamShared);
     return VINF_SUCCESS;
-#else  /* !IN_RING3 */
-    RT_NOREF(pDevIns, pThis, iReg, u32Value);
-    return VINF_IOM_R3_MMIO_WRITE;
-#endif /* !IN_RING3 */
 }
 
@@ -2812,40 +2665,19 @@
         const bool     fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow);
 
-        Log3Func(("[SD%RU8] fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", uSD, fSinkActive, fTimerScheduled));
-
-        if (!fTimerScheduled)
-        {
-            if (!pStreamShared->State.tsTransferLast) /* Never did a transfer before? Initialize with current time. */
-                pStreamShared->State.tsTransferLast = tsNow;
-
-            Assert(tsNow >= pStreamShared->State.tsTransferLast);
-
-            /* How many ticks have passed since the last transfer? */
-            const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast;
-
-            uint64_t cTicksToNext;
-            if (cTicksElapsed == 0) /* We just ran in the same timing slot? */
-            {
-                /* Schedule a transfer at the next regular timing slot. */
-                cTicksToNext = pStreamShared->State.cTransferTicks;
-            }
-            else
-            {
-                /* Some time since the last transfer has passed already; take this into account. */
-                if (pStreamShared->State.cTransferTicks >= cTicksElapsed)
-                {
-                    cTicksToNext = pStreamShared->State.cTransferTicks - cTicksElapsed;
-                }
-                else /* Catch up as soon as possible. */
-                    cTicksToNext = 0;
-            }
-
-            Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferLast=%RU64, cTicksElapsed=%RU64 -> cTicksToNext=%RU64\n",
-                      uSD, tsNow, pStreamShared->State.tsTransferLast, cTicksElapsed, cTicksToNext));
-
-            /* Note: cTicksToNext can be 0, which means we have to run *now*. */
-            hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext,
-                          true /*fForce*/, 0 /* tsNow */);
-        }
+        uint64_t tsTransferNext  = 0;
+        if (fTimerScheduled)
+        {
+            Assert(pStreamShared->State.tsTransferNext); /* Make sure that a new transfer timestamp is set. */
+            tsTransferNext = pStreamShared->State.tsTransferNext;
+        }
+        else /* Schedule at the precalculated rate. */
+            tsTransferNext = tsNow + pStreamShared->State.cTransferTicks;
+
+        Log3Func(("[SD%RU8] fSinksActive=%RTbool, fTimerScheduled=%RTbool, tsTransferNext=%RU64 (in %RU64)\n",
+                  uSD, fSinkActive, fTimerScheduled, tsTransferNext, tsTransferNext - tsNow));
+
+        /* Note: tsTransferNext can be 0, which means we have to run *now*. */
+        hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext,
+                      true /*fForce*/, tsNow);
     }
     else
Index: /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp	(revision 87862)
+++ /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp	(revision 87863)
@@ -129,4 +129,46 @@
         return &pStream->State.Period;
     return NULL;
+}
+
+/**
+ * Returns the current maximum value the wall clock counter can be set to.
+ *
+ * This maximum value depends on all currently handled HDA streams and their own current timing.
+ *
+ * @return  Current maximum value the wall clock counter can be set to.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
+ *
+ * @remark  Does not actually set the wall clock counter.
+ *
+ */
+uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC)
+{
+    const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
+    const uint64_t u64FrontAbsWalClk  = pThisCC->SinkFront.pStreamShared
+                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period)  : 0;
+# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+#  error "Implement me!"
+# endif
+    const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared
+                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;
+# ifdef VBOX_WITH_HDA_MIC_IN
+    const uint64_t u64MicInAbsWalClk  = pThisCC->SinkMicIn.pStreamShared
+                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period)  : 0;
+# endif
+
+    uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);
+# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+#  error "Implement me!"
+# endif
+    u64WalClkNew          = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);
+# ifdef VBOX_WITH_HDA_MIC_IN
+    u64WalClkNew          = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);
+# endif
+
+    Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n",
+              u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew));
+
+    return u64WalClkNew;
 }
 
Index: /trunk/src/VBox/Devices/Audio/DevHDACommon.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 87862)
+++ /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 87863)
@@ -633,4 +633,5 @@
 uint64_t      hdaWalClkGetCurrent(PHDASTATE pThis);
 #ifdef IN_RING3
+uint64_t      hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC);
 bool          hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce);
 #endif
Index: /trunk/src/VBox/Devices/Audio/HDAStream.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 87862)
+++ /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 87863)
@@ -694,5 +694,6 @@
      * Second, initialize the registers.
      */
-    HDA_STREAM_REG(pThis, STS,   uSD) = HDA_SDSTS_FIFORDY;
+    /* See 6.2.33: Clear on reset. */
+    HDA_STREAM_REG(pThis, STS,   uSD) = 0;
     /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
      * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
@@ -1189,4 +1190,7 @@
      */
     bool fInterruptSent = false;
+
+    /* Set the FIFORDY bit on the stream while doing the transfer. */
+    HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY;
 
     while (cbLeft)
@@ -1465,5 +1469,5 @@
                     if (!fInterruptSent)
                     {
-                        pStreamShared->State.cTransferPendingInterrupts++;
+                        pStreamShared->State.cTransferPendingInterrupts = 1;
 
                         AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32,
@@ -1513,4 +1517,7 @@
             break;
     }
+
+    /* Remove the FIFORDY bit again. */
+    HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY;
 
     /* Sanity. */
@@ -1544,26 +1551,24 @@
          */
         const bool fWalClkSet = hdaR3WalClkSet(pThis, pThisCC,
-                                                 hdaWalClkGetCurrent(pThis)
-                                               + hdaR3StreamPeriodFramesToWalClk(pPeriod,
-                                                                                   cbProcessed
-                                                                                 / pStreamR3->State.Mapping.cbFrameSize),
+                                               RT_MIN(  hdaWalClkGetCurrent(pThis)
+                                                      + hdaR3StreamPeriodFramesToWalClk(pPeriod,
+                                                                                          cbProcessed
+                                                                                        / pStreamR3->State.Mapping.cbFrameSize),
+                                                      hdaR3WalClkGetMax(pThis, pThisCC)),
                                                false /* fForce */);
         RT_NOREF(fWalClkSet);
     }
 
-    /* Does the period have any interrupts outstanding? */
-    if (!pStreamShared->State.cTransferPendingInterrupts)
-    {
-        /* No, set relative timer ticks for the next transfer to happen.
-         * This must happen at a constant rate. */
-        tsTransferNext = tsNow + pStreamShared->State.cTransferTicks;
-    }
+    /* Set the next transfer timing slot.
+     * This must happen at a constant rate. */
+     tsTransferNext = tsNow + pStreamShared->State.cTransferTicks;
 
     /* If we need to do another transfer, (re-)arm the device timer.  */
     if (tsTransferNext) /* Can be 0 if no next transfer is needed. */
     {
-        Log3Func(("[SD%RU8] Scheduling timer @ %RU64\n", uSD, tsTransferNext));
+        Log3Func(("[SD%RU8] Scheduling timer @ %RU64 (in %RU64 ticks)\n", uSD, tsTransferNext, tsTransferNext - tsNow));
 
         /* Make sure to assign next transfer timestamp before setting the timer. */
+        Assert(tsTransferNext > tsNow);
         pStreamShared->State.tsTransferNext = tsTransferNext;
 
@@ -1573,4 +1578,5 @@
     }
 
+    /* Always update this timestamp, no matter what pStreamShared->State.tsTransferNext is. */
     pStreamShared->State.tsTransferLast = tsNow;
 
@@ -1738,5 +1744,6 @@
             if (cbSinkReadable)
             {
-                uint8_t *pabFIFO = pStreamShared->abFIFO;
+                void    *pvFIFO = &pStreamShared->abFIFO[0];
+                uint32_t cbFIFO = (uint32_t)sizeof(pStreamShared->abFIFO);
 
                 while (cbSinkReadable)
@@ -1744,12 +1751,10 @@
                     uint32_t cbRead;
                     rc2 = AudioMixerSinkRead(pSink, AUDMIXOP_COPY,
-                                             pabFIFO, RT_MIN(cbSinkReadable, (uint32_t)sizeof(pStreamShared->abFIFO)), &cbRead);
+                                             pvFIFO, RT_MIN(cbSinkReadable, cbFIFO), &cbRead);
                     AssertRCBreak(rc2);
 
                     if (!cbRead)
                     {
-#ifdef HDA_STRICT
                         AssertMsgFailed(("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbSinkReadable));
-#endif
                         break;
                     }
@@ -1757,5 +1762,5 @@
                     /* Write (guest input) data to the stream which was read from stream's sink before. */
                     uint32_t cbWritten;
-                    rc2 = hdaR3StreamWrite(pStreamR3, pabFIFO, cbRead, &cbWritten);
+                    rc2 = hdaR3StreamWrite(pStreamR3, pvFIFO, cbRead, &cbWritten);
                     AssertRCBreak(rc2);
                     AssertBreak(cbWritten > 0); /* Should never happen, as we know how much we can write. */
