VirtualBox

Changeset 68712 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Sep 11, 2017 10:06:06 AM (7 years ago)
Author:
vboxsync
Message:

Audio/AC97: Use own device locking instead of default PDM device lock (implicit). This enables more fine-grained locking in combination with TM when handling timer stuff in e.g. the port I/O handlers.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r68499 r68712  
    392392    /** R3 Pointer to the device instance. */
    393393    PPDMDEVINSR3            pDevInsR3;
     394    /** Critical section protecting the AC'97 state. */
     395    PDMCRITSECT             CritSect;
    394396    /** Global Control (Bus Master Control Register). */
    395397    uint32_t                glob_cnt;
     
    411413    /** The timer for pumping data thru the attached LUN drivers. */
    412414    PTMTIMERR3              pTimer;
    413     /** Criticial section for timer. */
    414     RTCRITSECT              csTimer;
    415 # if HC_ARCH_BITS == 32
    416     uint32_t                Padding0;
    417 # endif
    418415    /** Flag indicating whether the timer is active or not. */
    419416    bool                    fTimerActive;
     
    452449} AC97STATE, *PAC97STATE;
    453450
     451/**
     452 * Acquires the AC'97 lock.
     453 */
     454#define DEVAC97_LOCK(a_pThis) \
     455    do { \
     456        int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
     457        AssertRC(rcLock); \
     458    } while (0)
     459
     460/**
     461 * Acquires the AC'97 lock or returns.
     462 */
     463# define DEVAC97_LOCK_RETURN(a_pThis, a_rcBusy) \
     464    do { \
     465        int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, a_rcBusy); \
     466        if (rcLock != VINF_SUCCESS) \
     467        { \
     468            AssertRC(rcLock); \
     469            return rcLock; \
     470        } \
     471    } while (0)
     472
     473/**
     474 * Acquires the AC'97 lock or returns.
     475 */
     476# define DEVAC97_LOCK_RETURN_VOID(a_pThis) \
     477    do { \
     478        int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
     479        if (rcLock != VINF_SUCCESS) \
     480        { \
     481            AssertRC(rcLock); \
     482            return; \
     483        } \
     484    } while (0)
     485
     486/**
     487 * Releases the AC'97 lock.
     488 */
     489#define DEVAC97_UNLOCK(a_pThis) \
     490    do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
     491
     492/**
     493 * Acquires the TM lock and AC'97 lock, returns on failure.
     494 */
     495#define DEVAC97_LOCK_BOTH_RETURN_VOID(a_pThis) \
     496    do { \
     497        int rcLock = TMTimerLock((a_pThis)->pTimer, VERR_IGNORED); \
     498        if (rcLock != VINF_SUCCESS) \
     499        { \
     500            AssertRC(rcLock); \
     501            return; \
     502        } \
     503        rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
     504        if (rcLock != VINF_SUCCESS) \
     505        { \
     506            AssertRC(rcLock); \
     507            TMTimerUnlock((a_pThis)->pTimer); \
     508            return; \
     509        } \
     510    } while (0)
     511
     512/**
     513 * Acquires the TM lock and AC'97 lock, returns on failure.
     514 */
     515#define DEVAC97_LOCK_BOTH_RETURN(a_pThis, a_rcBusy) \
     516    do { \
     517        int rcLock = TMTimerLock((a_pThis)->pTimer, (a_rcBusy)); \
     518        if (rcLock != VINF_SUCCESS) \
     519            return rcLock; \
     520        rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \
     521        if (rcLock != VINF_SUCCESS) \
     522        { \
     523            AssertRC(rcLock); \
     524            TMTimerUnlock((a_pThis)->pTimer); \
     525            return rcLock; \
     526        } \
     527    } while (0)
     528
     529/**
     530 * Releases the AC'97 lock and TM lock.
     531 */
     532#define DEVAC97_UNLOCK_BOTH(a_pThis) \
     533    do { \
     534        PDMCritSectLeave(&(a_pThis)->CritSect); \
     535        TMTimerUnlock((a_pThis)->pTimer); \
     536    } while (0)
     537
    454538#ifdef VBOX_WITH_STATISTICS
    455539AssertCompileMemberAlignment(AC97STATE, StatTimer,        8);
     
    476560static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns);
    477561#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    478 static void               ichac97TimerMaybeStart(PAC97STATE pThis);
    479 static void               ichac97TimerMaybeStop(PAC97STATE pThis);
     562static int                ichac97TimerStart(PAC97STATE pThis);
     563static int                ichac97TimerMaybeStart(PAC97STATE pThis);
     564static int                ichac97TimerStop(PAC97STATE pThis);
     565static int                ichac97TimerMaybeStop(PAC97STATE pThis);
    480566static void               ichac97TimerMain(PAC97STATE pThis);
    481567static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
     
    12131299        }
    12141300
    1215         /* How much (guest output) data is available at the moment for the HDA stream? */
     1301        /* How much (guest output) data is available at the moment for the AC'97 stream? */
    12161302        uint32_t cbUsed = ichac97StreamGetUsed(pStream);
    12171303
     
    19912077#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    19922078/**
     2079 * Starts the internal audio device timer.
     2080 *
     2081 * @return  IPRT status code.
     2082 * @param   pThis               AC'97 state.
     2083 */
     2084static int  ichac97TimerStart(PAC97STATE pThis)
     2085{
     2086    LogFlowFuncEnter();
     2087
     2088    DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
     2089
     2090    AssertPtr(pThis->pTimer);
     2091
     2092    if (!pThis->fTimerActive)
     2093    {
     2094        LogRel2(("AC97: Starting transfers\n"));
     2095
     2096        pThis->fTimerActive = true;
     2097
     2098        /* Start transfers. */
     2099        ichac97TimerMain(pThis);
     2100    }
     2101
     2102    DEVAC97_UNLOCK_BOTH(pThis);
     2103
     2104    return VINF_SUCCESS;
     2105}
     2106
     2107/**
    19932108 * Starts the internal audio device timer (if not started yet).
    19942109 *
     2110 * @return  IPRT status code.
    19952111 * @param   pThis               AC'97 state.
    19962112 */
    1997 static void ichac97TimerMaybeStart(PAC97STATE pThis)
     2113static int ichac97TimerMaybeStart(PAC97STATE pThis)
    19982114{
    19992115    LogFlowFuncEnter();
    20002116
    20012117    if (!pThis->pTimer)
    2002         return;
     2118        return VERR_WRONG_ORDER;
    20032119
    20042120    pThis->cStreamsActive++;
     
    20062122    /* Only start the timer at the first active stream. */
    20072123    if (pThis->cStreamsActive == 1)
    2008     {
    2009         LogRel2(("AC97: Starting transfers\n"));
    2010 
    2011         /* Set timer flag. */
    2012         ASMAtomicXchgBool(&pThis->fTimerActive, true);
    2013 
    2014         /* Update current time timestamp. */
    2015         pThis->uTimerTS = TMTimerGet(pThis->pTimer);
    2016 
    2017         /* Start transfers. */
    2018         ichac97TimerMain(pThis);
    2019     }
     2124        return ichac97TimerStart(pThis);
     2125
     2126    return VINF_SUCCESS;
    20202127}
    20212128
     
    20232130 * Stops the internal audio device timer.
    20242131 *
     2132 * @return  IPRT status code.
    20252133 * @param   pThis               AC'97 state.
    20262134 */
    2027 static void ichac97TimerStop(PAC97STATE pThis)
     2135static int ichac97TimerStop(PAC97STATE pThis)
    20282136{
    20292137    LogFlowFuncEnter();
    20302138
    2031     /* Set timer flag. */
    2032     ASMAtomicXchgBool(&pThis->fTimerActive, false);
     2139    if (!pThis->pTimer) /* Only can happen on device construction time, so no locking needed here. */
     2140        return VINF_SUCCESS;
     2141
     2142    DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
     2143
     2144    if (pThis->fTimerActive)
     2145    {
     2146        LogRel2(("AC97: Stopping transfers ...\n"));
     2147
     2148        pThis->fTimerActive = false;
     2149
     2150        TMTimerStop(pThis->pTimer);
     2151    }
     2152
     2153    DEVAC97_UNLOCK_BOTH(pThis);
     2154
     2155    return VINF_SUCCESS;
    20332156}
    20342157
     
    20382161 * stopped.
    20392162 *
     2163 * @return  IPRT status code.
    20402164 * @param   pThis               AC'97 state.
    20412165 */
    2042 static void ichac97TimerMaybeStop(PAC97STATE pThis)
     2166static int ichac97TimerMaybeStop(PAC97STATE pThis)
    20432167{
    20442168    LogFlowFuncEnter();
    20452169
    20462170    if (!pThis->pTimer)
    2047         return;
     2171        return VERR_WRONG_ORDER;
    20482172
    20492173    if (pThis->cStreamsActive) /* Function can be called mupltiple times. */
     
    20522176
    20532177        if (pThis->cStreamsActive == 0)
    2054             ichac97TimerStop(pThis);
    2055     }
     2178            return ichac97TimerStop(pThis);
     2179    }
     2180
     2181    return VINF_SUCCESS;
    20562182}
    20572183
     
    20592185 * Main routine for the device timer.
    20602186 *
    2061  * @returns IPRT status code.
    20622187 * @param   pThis               AC'97 state.
    20632188 */
     
    20652190{
    20662191    STAM_PROFILE_START(&pThis->StatTimer, a);
     2192
     2193    DEVAC97_LOCK_BOTH_RETURN_VOID(pThis);
    20672194
    20682195    uint64_t cTicksNow = TMTimerGet(pThis->pTimer);
     
    20932220    }
    20942221    else
    2095         LogRel2(("AC97: Stopping transfers\n"));
     2222        LogRel2(("AC97: Stopped transfers\n"));
     2223
     2224    DEVAC97_UNLOCK_BOTH(pThis);
    20962225
    20972226    STAM_PROFILE_STOP(&pThis->StatTimer, a);
     
    21362265 *
    21372266 * For an SDO (output) stream this means reading DMA data from the device to
    2138  * the HDA stream's internal FIFO buffer.
    2139  *
    2140  * For an SDI (input) stream this is reading audio data from the HDA stream's
     2267 * the AC'97 stream's internal FIFO buffer.
     2268 *
     2269 * For an SDI (input) stream this is reading audio data from the AC'97 stream's
    21412270 * internal FIFO buffer and writing it as DMA data to the device.
    21422271 *
     
    23692498{
    23702499    RT_NOREF(pDevIns);
     2500
    23712501    PAC97STATE pThis = (PAC97STATE)pvUser;
     2502
     2503    DEVAC97_LOCK(pThis);
    23722504
    23732505    /* Get the index of the NABMBAR port. */
     
    25192651    }
    25202652
     2653    DEVAC97_UNLOCK(pThis);
     2654
    25212655    return rc;
    25222656}
     
    25382672{
    25392673    RT_NOREF(pDevIns);
    2540     PAC97STATE  pThis   = (PAC97STATE)pvUser;
     2674
     2675    PAC97STATE pThis = (PAC97STATE)pvUser;
     2676
     2677    DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE);
    25412678
    25422679    /* Get the index of the NABMBAR register. */
     
    27052842    }
    27062843
     2844    DEVAC97_UNLOCK_BOTH(pThis);
     2845
    27072846    return VINF_SUCCESS;
    27082847}
     
    27272866    PAC97STATE pThis = (PAC97STATE)pvUser;
    27282867
     2868    DEVAC97_LOCK(pThis);
     2869
    27292870    int rc = VINF_SUCCESS;
    27302871
     
    27692910        }
    27702911    }
     2912
     2913    DEVAC97_UNLOCK(pThis);
    27712914
    27722915    return rc;
     
    27902933    RT_NOREF(pDevIns);
    27912934    PAC97STATE pThis = (PAC97STATE)pvUser;
     2935
     2936    DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE);
    27922937
    27932938    uint32_t uPortIdx = uPort - pThis->IOPortBase[0];
     
    29313076    }
    29323077
     3078    DEVAC97_UNLOCK_BOTH(pThis);
     3079
    29333080    return VINF_SUCCESS;
    29343081}
     
    29423089{
    29433090    RT_NOREF(cb, enmType);
    2944     PAC97STATE  pThis   = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
    2945     RTIOPORT    Port    = (RTIOPORT)GCPhysAddress;
    29463091
    29473092    Assert(enmType == PCI_ADDRESS_SPACE_IO);
     
    29503095    if (iRegion > 1) /* We support 2 regions max. at the moment. */
    29513096        return VERR_INVALID_PARAMETER;
     3097
     3098    PAC97STATE pThis   = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
     3099    RTIOPORT   Port    = (RTIOPORT)GCPhysAddress;
    29523100
    29533101    int rc;
     
    31963344    AudioMixerSinkReset(pThis->pSinkMicIn);
    31973345    AudioMixerSinkReset(pThis->pSinkOut);
     3346
     3347# ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
     3348    /*
     3349     * Stop the timer, if any.
     3350     */
     3351    ichac97TimerStop(pThis);
     3352
     3353    pThis->cStreamsActive = 0;
     3354# endif
    31983355}
    31993356
     
    32183375    Assert(RTListIsEmpty(&pThis->lstDrv));
    32193376
    3220     int rc;
    3221 #ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    3222     rc = RTCritSectDelete(&pThis->csTimer);
    3223 #else
    3224     rc = VINF_SUCCESS;
    3225 #endif
    3226 
    3227     LogFlowFuncLeaveRC(rc);
    3228     return rc;
     3377    return VINF_SUCCESS;
    32293378}
    32303379
     
    34483597
    34493598    /*
     3599     * Use an own critical section for the device instead of the default
     3600     * one provided by PDM. This allows fine-grained locking in combination
     3601     * with TM when timer-specific stuff is being called in e.g. the MMIO handlers.
     3602     */
     3603    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "AC'97");
     3604    AssertRCReturn(rc, rc);
     3605
     3606    rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
     3607    AssertRCReturn(rc, rc);
     3608
     3609    /*
    34503610     * Initialize data (most of it anyway).
    34513611     */
     
    34543614    pThis->IBase.pfnQueryInterface  = ichac97QueryInterface;
    34553615
    3456     /* PCI Device (the assertions will be removed later) */
     3616    /* PCI Device */
    34573617    PCIDevSetVendorId         (&pThis->PciDev, 0x8086); /* 00 ro - intel. */               Assert(pThis->PciDev.abConfig[0x00] == 0x86); Assert(pThis->PciDev.abConfig[0x01] == 0x80);
    34583618    PCIDevSetDeviceId         (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */  Assert(pThis->PciDev.abConfig[0x02] == 0x15); Assert(pThis->PciDev.abConfig[0x03] == 0x24);
     
    36693829    if (RT_SUCCESS(rc))
    36703830    {
    3671         rc = RTCritSectInit(&pThis->csTimer);
    3672         if (RT_SUCCESS(rc))
    3673         {
    3674             /* Create the emulation timer. */
    3675             rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
    3676                                         TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
    3677             AssertRCReturn(rc, rc);
    3678 
    3679             if (RT_SUCCESS(rc))
    3680             {
    3681                 pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
    3682                 pThis->uTimerTS    = TMTimerGet(pThis->pTimer);
    3683                 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
    3684             }
    3685         }
     3831        /* Create the emulation timer.
     3832         *
     3833         * Note:  Use TMCLOCK_VIRTUAL_SYNC here, as the guest's AC'97 driver
     3834         *        relies on exact (virtual) DMA timing and uses DMA Position Buffers
     3835         *        instead of the LPIB registers.
     3836         */
     3837        rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ichac97Timer, pThis,
     3838                                    TMTIMER_FLAGS_NO_CRIT_SECT, "AC'97 Timer", &pThis->pTimer);
     3839        AssertRCReturn(rc, rc);
     3840
     3841        /* Use our own critcal section for the device timer.
     3842         * That way we can control more fine-grained when to lock what. */
     3843        rc = TMR3TimerSetCritSect(pThis->pTimer, &pThis->CritSect);
     3844        AssertRCReturn(rc, rc);
     3845
     3846        pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
     3847        pThis->uTimerTS    = TMTimerGet(pThis->pTimer);
     3848        LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
    36863849    }
    36873850#else /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */
Note: See TracChangeset for help on using the changeset viewer.

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