Changeset 67410 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Jun 14, 2017 2:48:16 PM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 116135
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r67400 r67410 104 104 105 105 /** Default timer frequency (in Hz). */ 106 #define HDA_TIMER_HZ 100106 #define HDA_TIMER_HZ 200 107 107 108 108 /** … … 789 789 #endif 790 790 } HDADRIVER; 791 792 #ifdef DEBUG 793 /** @todo Make STAM values out of this? */ 794 typedef struct HDASTATEDBGINFO 795 { 796 /** Timestamp (in ns) of the last timer callback (hdaTimer). 797 * Used to calculate the time actually elapsed between two timer callbacks. */ 798 uint64_t tsTimerLastCalledNs; 799 /** IRQ debugging information. */ 800 struct 801 { 802 /** Timestamp (in ns) of last processed (asserted / deasserted) IRQ. */ 803 uint64_t tsProcessedLastNs; 804 /** Timestamp (in ns) of last asserted IRQ. */ 805 uint64_t tsAssertedNs; 806 /** How many IRQs have been asserted already. */ 807 uint64_t cAsserted; 808 /** Accumulated elapsed time (in ns) of all IRQ being asserted. */ 809 uint64_t tsAssertedTotalNs; 810 /** Timestamp (in ns) of last deasserted IRQ. */ 811 uint64_t tsDeassertedNs; 812 /** How many IRQs have been deasserted already. */ 813 uint64_t cDeasserted; 814 /** Accumulated elapsed time (in ns) of all IRQ being deasserted. */ 815 uint64_t tsDeassertedTotalNs; 816 } IRQ; 817 } HDASTATEDBGINFO, *PHDASTATEDBGINFO; 818 #endif 791 819 792 820 /** … … 853 881 /** The current timer expire time (in timer ticks). */ 854 882 uint64_t tsTimerExpire; 855 /** Timestamp of the last timer callback (hdaTimer).856 * Used to calculate the time actually elapsed between two timer callbacks. */857 uint64_t uTimerTS;858 uint64_t uTimerMS;859 883 #endif 860 884 #ifdef VBOX_WITH_STATISTICS … … 894 918 /** Response Interrupt Count (RINTCNT). */ 895 919 uint8_t u8RespIntCnt; 920 /** Current IRQ level. */ 921 uint8_t u8IRQL; 896 922 /** Padding for alignment. */ 897 uint8_t au8Padding2[7]; 923 uint8_t au8Padding2[6]; 924 #ifdef DEBUG 925 HDASTATEDBGINFO Dbg; 926 #endif 898 927 } HDASTATE; 899 928 /** Pointer to the ICH Intel HD Audio Controller state. */ … … 937 966 static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 938 967 static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 939 static int hdaRegWriteINTCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);940 968 static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 941 969 static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); … … 1149 1177 { 0x00018, 0x00002, 0x0000FFFF, 0x00000000, HDA_RD_FLAG_NONE, hdaRegReadU16 , hdaRegWriteU16 , HDA_REG_IDX(OUTSTRMPAY) }, /* Output Stream Payload Capability */ 1150 1178 { 0x0001A, 0x00002, 0x0000FFFF, 0x00000000, HDA_RD_FLAG_NONE, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(INSTRMPAY) }, /* Input Stream Payload Capability */ 1151 { 0x00020, 0x00004, 0xC00000FF, 0xC00000FF, HDA_RD_FLAG_NONE, hdaRegReadU32 , hdaRegWrite INTCTL, HDA_REG_IDX(INTCTL) }, /* Interrupt Control */1179 { 0x00020, 0x00004, 0xC00000FF, 0xC00000FF, HDA_RD_FLAG_NONE, hdaRegReadU32 , hdaRegWriteU32 , HDA_REG_IDX(INTCTL) }, /* Interrupt Control */ 1152 1180 { 0x00024, 0x00004, 0xC00000FF, 0x00000000, HDA_RD_FLAG_NONE, hdaRegReadU32 , hdaRegWriteUnimpl , HDA_REG_IDX(INTSTS) }, /* Interrupt Status */ 1153 1181 { 0x00030, 0x00004, 0xFFFFFFFF, 0x00000000, HDA_RD_FLAG_NONE, hdaRegReadWALCLK, hdaRegWriteUnimpl , HDA_REG_IDX_NOMEM(WALCLK) }, /* Wall Clock Counter */ … … 1455 1483 #endif /* IN_RING3 */ 1456 1484 1457 1458 static void hdaUpdateINTSTS(PHDASTATE pThis) 1485 static uint32_t hdaGetINTSTS(PHDASTATE pThis) 1459 1486 { 1460 1487 uint32_t intSts = 0; 1461 1488 1462 /* Check controller interrupts (RIRB, STATEST) */1489 /* Check controller interrupts (RIRB, STATEST). */ 1463 1490 if ( (HDA_REG(pThis, RIRBSTS) & HDA_REG(pThis, RIRBCTL) & (HDA_RIRBCTL_ROIC | HDA_RIRBCTL_RINTCTL)) 1464 /* SDIN State Change Status Flags (SCSF) */1491 /* SDIN State Change Status Flags (SCSF). */ 1465 1492 || (HDA_REG(pThis, STATESTS) & HDA_STATESTS_SCSF_MASK)) 1466 1493 { 1467 intSts |= HDA_INTSTS_CIS; /* Set the Controller Interrupt Status (CIS). */ 1494 intSts |= HDA_INTSTS_CIS; /* Set the Controller Interrupt Status (CIS). */ 1495 } 1496 1497 if (HDA_REG(pThis, STATESTS) & HDA_REG(pThis, WAKEEN)) 1498 { 1499 intSts |= HDA_INTSTS_CIS; /* Touch Controller Interrupt Status (CIS). */ 1468 1500 } 1469 1501 1470 1502 /* For each stream, check if any interrupt status bit is set and enabled. */ 1471 for ( int iStrm = 0; iStrm < 8; ++iStrm)1503 for (uint8_t iStrm = 0; iStrm < HDA_MAX_STREAMS; ++iStrm) 1472 1504 { 1473 1505 if (HDA_STREAM_REG(pThis, STS, iStrm) & HDA_STREAM_REG(pThis, CTL, iStrm) & (HDA_SDCTL_DEIE | HDA_SDCTL_FEIE | HDA_SDCTL_IOCE)) … … 1479 1511 1480 1512 if (intSts) 1481 intSts |= HDA_INTSTS_GIS; /* Set the Global Interrupt Status (GIS). */ 1482 1483 HDA_REG(pThis, INTSTS) = intSts; 1484 Log3Func(("INTSTS=%x\n", intSts)); 1485 } 1486 1487 /* Update INTSTS register and the hardware interrupt signal. This function must be called 1488 * after changing any interrupt status or enable bits. 1489 */ 1490 static int hdaUpdateInterrupt(PHDASTATE pThis) 1491 { 1492 hdaUpdateINTSTS(pThis); 1493 1494 int iLevel = 0; 1513 intSts |= HDA_INTSTS_GIS; /* Set the Global Interrupt Status (GIS). */ 1514 1515 Log3Func(("-> 0x%x\n", intSts)); 1516 1517 return intSts; 1518 } 1519 1520 #ifndef DEBUG 1521 static int hdaProcessInterrupt(PHDASTATE pThis) 1522 #else 1523 static int hdaProcessInterrupt(PHDASTATE pThis, const char *pszSource) 1524 #endif 1525 { 1526 HDA_REG(pThis, INTSTS) = hdaGetINTSTS(pThis); 1527 1528 Log3Func(("IRQL=%RU8\n", pThis->u8IRQL)); 1495 1529 1496 1530 /* NB: It is possible to have GIS set even when CIE/SIEn are all zero; the GIS bit does … … 1499 1533 1500 1534 /* If global interrupt enable (GIE) is set, check if any enabled interrupts are set. */ 1501 if (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE) 1502 if (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK)) 1503 iLevel = 1; 1504 1505 Log3Func(("INTCTL=%x, INTSTS=%x, Level=%d\n", HDA_REG(pThis, INTCTL), HDA_REG(pThis, INTSTS), iLevel)); 1506 1507 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, iLevel); 1535 if ( (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE) 1536 && (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK))) 1537 { 1538 if (!pThis->u8IRQL) 1539 { 1540 #ifdef DEBUG 1541 if (!pThis->Dbg.IRQ.tsProcessedLastNs) 1542 pThis->Dbg.IRQ.tsProcessedLastNs = RTTimeNanoTS(); 1543 1544 const uint64_t tsLastElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsProcessedLastNs; 1545 1546 if (!pThis->Dbg.IRQ.tsAssertedNs) 1547 pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS(); 1548 1549 const uint64_t tsAssertedElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsAssertedNs; 1550 1551 pThis->Dbg.IRQ.cAsserted++; 1552 pThis->Dbg.IRQ.tsAssertedTotalNs += tsAssertedElapsedNs; 1553 1554 const uint64_t avgAssertedUs = (pThis->Dbg.IRQ.tsAssertedTotalNs / pThis->Dbg.IRQ.cAsserted) / 1000; 1555 1556 if (avgAssertedUs > (1000 / HDA_TIMER_HZ) /* ms */ * 1000) /* Exceeds time slot? */ 1557 Log3Func(("Asserted (%s): %zuus elapsed (%zuus on average) -- %zuus alternation delay\n", 1558 pszSource, tsAssertedElapsedNs / 1000, 1559 avgAssertedUs, 1560 (pThis->Dbg.IRQ.tsDeassertedNs - pThis->Dbg.IRQ.tsAssertedNs) / 1000)); 1561 #endif 1562 Log3Func(("Asserted (%s): %RU64us between alternation (WALCLK=%RU64)\n", 1563 pszSource, tsLastElapsedNs / 1000, pThis->u64WalClk)); 1564 1565 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 1 /* Assert */); 1566 pThis->u8IRQL = 1; 1567 1568 #ifdef DEBUG 1569 pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS(); 1570 pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsAssertedNs; 1571 #endif 1572 } 1573 } 1574 else 1575 { 1576 if (pThis->u8IRQL) 1577 { 1578 #ifdef DEBUG 1579 if (!pThis->Dbg.IRQ.tsProcessedLastNs) 1580 pThis->Dbg.IRQ.tsProcessedLastNs = RTTimeNanoTS(); 1581 1582 const uint64_t tsLastElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsProcessedLastNs; 1583 1584 if (!pThis->Dbg.IRQ.tsDeassertedNs) 1585 pThis->Dbg.IRQ.tsDeassertedNs = RTTimeNanoTS(); 1586 1587 const uint64_t tsDeassertedElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsDeassertedNs; 1588 1589 pThis->Dbg.IRQ.cDeasserted++; 1590 pThis->Dbg.IRQ.tsDeassertedTotalNs += tsDeassertedElapsedNs; 1591 1592 const uint64_t avgDeassertedUs = (pThis->Dbg.IRQ.tsDeassertedTotalNs / pThis->Dbg.IRQ.cDeasserted) / 1000; 1593 1594 if (avgDeassertedUs > (1000 / HDA_TIMER_HZ) /* ms */ * 1000) /* Exceeds time slot? */ 1595 Log3Func(("Deasserted (%s): %zuus elapsed (%zuus on average)\n", 1596 pszSource, tsDeassertedElapsedNs / 1000, avgDeassertedUs)); 1597 1598 Log3Func(("Deasserted (%s): %RU64us between alternation (WALCLK=%RU64)\n", 1599 pszSource, tsLastElapsedNs / 1000, pThis->u64WalClk)); 1600 #endif 1601 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0 /* Deassert */); 1602 pThis->u8IRQL = 0; 1603 1604 #ifdef DEBUG 1605 pThis->Dbg.IRQ.tsDeassertedNs = RTTimeNanoTS(); 1606 pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsDeassertedNs; 1607 #endif 1608 } 1609 } 1508 1610 1509 1611 return VINF_SUCCESS; … … 1724 1826 rc = hdaCmdSync(pThis, false); 1725 1827 1726 Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP))); 1727 1728 HDA_REG(pThis, RIRBSTS) |= HDA_RIRBSTS_RINTFL; 1729 1730 pThis->u8RespIntCnt = 0; 1731 rc = hdaUpdateInterrupt(pThis); 1828 Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", 1829 HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP))); 1830 1831 if (HDA_REG(pThis, RIRBCTL) & HDA_RIRBCTL_ROIC) /* Response Interrupt Control (ROIC) enabled? */ 1832 { 1833 if (pThis->u8RespIntCnt) 1834 { 1835 pThis->u8RespIntCnt = 0; 1836 1837 HDA_REG(pThis, RIRBSTS) |= HDA_RIRBSTS_RINTFL; 1838 1839 #ifndef DEBUG 1840 rc = hdaProcessInterrupt(pThis); 1841 #else 1842 rc = hdaProcessInterrupt(pThis, __FUNCTION__); 1843 #endif 1844 } 1845 } 1732 1846 1733 1847 if (RT_FAILURE(rc)) … … 1921 2035 } 1922 2036 2037 if (fEnable) 2038 { 2039 /* Begin a new period for this stream. */ 2040 int rc2 = hdaStreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */); 2041 AssertRC(rc2); 2042 } 2043 else 2044 { 2045 /* Reset the period. */ 2046 hdaStreamPeriodReset(&pStream->State.Period); 2047 } 2048 1923 2049 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1924 2050 hdaStreamAsyncIOUnlock(pStream); … … 2191 2317 HDA_REG(pThis, STATESTS) &= ~(v & nv); /* Write of 1 clears corresponding bit. */ 2192 2318 2193 return hdaUpdateInterrupt(pThis); 2194 } 2195 2196 static int hdaRegWriteINTCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) 2197 { 2198 RT_NOREF(iReg); 2199 2200 int rc; 2201 2202 HDA_REG(pThis, INTCTL) = u32Value; 2203 2204 rc = hdaUpdateInterrupt(pThis); 2205 2206 return rc; 2319 return VINF_SUCCESS; 2207 2320 } 2208 2321 … … 2455 2568 } 2456 2569 2570 #ifdef IN_RING3 2571 /** 2572 * Reschedules pending interrupts for all audio streams which have complete 2573 * audio periods but did not have the chance to issue their (pending) interrupts yet. 2574 * 2575 * @param pThis The HDA device state. 2576 */ 2577 static void hdaReschedulePendingInterrupts(PHDASTATE pThis) 2578 { 2579 bool fInterrupt = false; 2580 2581 for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i) 2582 { 2583 PHDASTREAM pStream = hdaStreamGetFromSD(pThis, i); 2584 2585 if ( hdaStreamPeriodIsComplete (&pStream->State.Period) 2586 && hdaStreamPeriodNeedsInterrupt(&pStream->State.Period) 2587 && hdaWalClkSet(pThis, hdaStreamPeriodGetAbsElapsedWalClk(&pStream->State.Period), false /* fForce */)) 2588 { 2589 fInterrupt = true; 2590 break; 2591 } 2592 } 2593 2594 LogFunc(("fInterrupt=%RTbool\n", fInterrupt)); 2595 2596 if (fInterrupt) 2597 { 2598 #ifndef DEBUG 2599 hdaProcessInterrupt(pThis); 2600 #else 2601 hdaProcessInterrupt(pThis, __FUNCTION__); 2602 #endif 2603 } 2604 } 2605 #endif 2606 2457 2607 static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) 2458 2608 { … … 2553 2703 2554 2704 hdaStreamEnable(pThis, pStream, fRun /* fEnable */); 2705 2706 if (!fRun) 2707 { 2708 /* Make sure to (re-)schedule outstanding (delayed) interrupts. */ 2709 hdaReschedulePendingInterrupts(pThis); 2710 } 2555 2711 } 2556 2712 } … … 2558 2714 int rc2 = hdaRegWriteU24(pThis, iReg, u32Value); 2559 2715 AssertRC(rc2); 2560 2561 /* Make sure to handle interrupts here as well. */2562 hdaUpdateInterrupt(pThis);2563 2716 2564 2717 return VINF_SUCCESS; /* Always return success to the MMIO handler. */ … … 2571 2724 static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) 2572 2725 { 2726 #ifdef IN_RING3 2573 2727 uint32_t v = HDA_REG_IND(pThis, iReg); 2728 2729 PHDASTREAM pStream = hdaStreamGetFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, STS, iReg)); 2730 if (!pStream) 2731 { 2732 AssertMsgFailed(("[SD%RU8]: Warning: Writing SDSTS on non-attached stream (0x%x)\n", 2733 HDA_SD_NUM_FROM_REG(pThis, STS, iReg), u32Value)); 2734 return hdaRegWriteU16(pThis, iReg, u32Value); 2735 } 2574 2736 2575 2737 /* Clear (zero) FIFOE, DESE and BCIS bits when writing 1 to it (6.2.33). */ 2576 2738 HDA_REG_IND(pThis, iReg) &= ~(u32Value & v); 2577 2739 2578 LogFunc(("SDSTS 0x%x -> 0x%x\n", v, HDA_REG_IND(pThis, iReg))); 2579 2580 hdaUpdateInterrupt(pThis); 2581 return VINF_SUCCESS; /* Always return success to the MMIO handler. */ 2740 /* Some guests tend to write SDnSTS even if the stream is not running. 2741 * So make sure to check if the RUN bit is set first. */ 2742 const bool fInRun = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_SDCTL_RUN); 2743 2744 Log3Func(("[SD%RU8] fRun=%RTbool %R[sdsts]\n", pStream->u8SD, fInRun, v)); 2745 2746 PHDASTREAMPERIOD pPeriod = &pStream->State.Period; 2747 2748 if (hdaStreamPeriodLock(pPeriod)) 2749 { 2750 const bool fNeedsInterrupt = hdaStreamPeriodNeedsInterrupt(pPeriod); 2751 if (fNeedsInterrupt) 2752 hdaStreamPeriodReleaseInterrupt(pPeriod); 2753 2754 if (hdaStreamPeriodIsComplete(pPeriod)) 2755 { 2756 hdaStreamPeriodEnd(pPeriod); 2757 2758 if (fInRun) 2759 hdaStreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis) /* Use current wall clock time */); 2760 } 2761 2762 hdaStreamPeriodUnlock(pPeriod); /* Unlock before processing interrupt. */ 2763 2764 if (fNeedsInterrupt) 2765 { 2766 #ifndef DEBUG 2767 hdaProcessInterrupt(pThis); 2768 #else 2769 hdaProcessInterrupt(pThis, __FUNCTION__); 2770 #endif 2771 } 2772 } 2773 2774 return VINF_SUCCESS; 2775 #else /* IN_RING3 */ 2776 RT_NOREF(pThis, iReg, u32Value); 2777 return VINF_IOM_R3_MMIO_WRITE; 2778 #endif /* !IN_RING3 */ 2582 2779 } 2583 2780 … … 3268 3465 HDA_REG(pThis, RIRBSTS) &= ~(v & u32Value); 3269 3466 3270 return hdaUpdateInterrupt(pThis); 3467 #ifndef DEBUG 3468 return hdaProcessInterrupt(pThis); 3469 #else 3470 return hdaProcessInterrupt(pThis, __FUNCTION__); 3471 #endif 3271 3472 } 3272 3473 … … 4174 4375 4175 4376 /* Update current time timestamp. */ 4176 pThis-> uTimerTS = TMTimerGet(pThis->pTimer);4377 pThis->tsTimerExpire = TMTimerGet(pThis->pTimer) + pThis->cTimerTicks; 4177 4378 4178 4379 /* Start transfers. */ … … 4192 4393 /* Set timer flag. */ 4193 4394 ASMAtomicXchgBool(&pThis->fTimerActive, false); 4395 4396 /* 4397 * Stop the timer, if any. 4398 */ 4399 if ( pThis->pTimer 4400 && TMTimerIsActive(pThis->pTimer)) 4401 { 4402 int rc2 = TMTimerStop(pThis->pTimer); 4403 AssertRC(rc2); 4404 } 4194 4405 } 4195 4406 … … 4228 4439 4229 4440 STAM_PROFILE_START(&pThis->StatTimer, a); 4230 4231 uint64_t cTicksNow = TMTimerGet(pThis->pTimer);4232 4233 /* Update current time timestamp. */4234 pThis->uTimerTS = cTicksNow;4235 4441 4236 4442 /* Flag indicating whether to kick the timer again for a … … 4255 4461 } 4256 4462 4257 pThis->uTimerMS = RTTimeMilliTS();4258 4259 4463 if ( ASMAtomicReadBool(&pThis->fTimerActive) 4260 4464 || fKickTimer) 4261 4465 { 4262 4466 /* Kick the timer again. */ 4263 uint64_t cTicks = pThis->cTimerTicks; 4264 /** @todo adjust cTicks down by now much cbOutMin represents. */ 4265 TMTimerSet(pThis->pTimer, cTicksNow + cTicks); 4467 pThis->tsTimerExpire += pThis->cTimerTicks; 4468 TMTimerSet(pThis->pTimer, pThis->tsTimerExpire); 4266 4469 } 4267 4470 else … … 4692 4895 Log3Func(("[SD%RU8]: BCIS set\n", pStream->u8SD)); 4693 4896 4694 hdaUpdateInterrupt(pThis); 4897 #ifndef DEBUG 4898 hdaProcessInterrupt(pThis); 4899 #else 4900 hdaProcessInterrupt(pThis, __FUNCTION__); 4901 #endif 4695 4902 } 4696 4903 … … 7253 7460 if (RT_SUCCESS(rc)) 7254 7461 { 7255 /* Create the emulation timer. */ 7256 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, hdaTimer, pThis, 7462 /* Create the emulation timer. 7463 * 7464 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's HDA driver 7465 * relies on exact (virtual) DMA timing and uses DMA Position Buffers 7466 * instead of the LPIB registers. 7467 */ 7468 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaTimer, pThis, 7257 7469 TMTIMER_FLAGS_NO_CRIT_SECT, "DevHDA", &pThis->pTimer); 7258 7470 AssertRCReturn(rc, rc); … … 7261 7473 { 7262 7474 pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz; 7263 pThis->uTimerTS = TMTimerGet(pThis->pTimer);7264 7475 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz)); 7265 7476 }
Note:
See TracChangeset
for help on using the changeset viewer.