VirtualBox

Ignore:
Timestamp:
Mar 2, 2015 2:42:45 PM (10 years ago)
Author:
vboxsync
Message:

HostDrivers/Support: Host suspend/resume now recomputes TSC-deltas for all CPUs.

Location:
trunk/src/VBox/HostDrivers/Support
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp

    r54551 r54578  
    126126static DECLCALLBACK(void)   supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
    127127static void                 supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz);
     128static void                 supdrvTscResetSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas);
    128129#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    129130static int                  supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt);
    130131static void                 supdrvTscDeltaTerm(PSUPDRVDEVEXT pDevExt);
    131 static void                 supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt);
     132static void                 supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt, bool fForceAll);
    132133#else
    133134static int                  supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt);
     
    861862static DECLCALLBACK(void) supdrvGipPowerNotificationCallback(RTPOWEREVENT enmEvent, void *pvUser)
    862863{
    863     PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
    864 
    865     /*
    866      * If the TSC frequency refinement timer we need to cancel it so it doesn't screw
    867      * up the frequency after a long suspend.
    868      */
    869     if (   enmEvent == RTPOWEREVENT_SUSPEND
    870         || enmEvent == RTPOWEREVENT_RESUME)
     864    PSUPDRVDEVEXT      pDevExt = (PSUPDRVDEVEXT)pvUser;
     865    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     866
     867    /*
     868     * If the TSC frequency refinement timer is running, we need to cancel it so it
     869     * doesn't screw up the frequency after a long suspend.
     870     *
     871     * Recalculate all TSC-deltas on host resume as it may have changed, seen
     872     * on Windows 7 running on the Dell Optiplex Intel Core i5-3570.
     873     */
     874    if (enmEvent == RTPOWEREVENT_RESUME)
     875    {
     876        ASMAtomicWriteBool(&pDevExt->fInvTscRefinePowerEvent, true);
     877        if (   RT_LIKELY(pGip)
     878            && pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
     879        {
     880#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     881            supdrvTscDeltaThreadStartMeasurement(pDevExt, true /* fForceAll */);
     882#else
     883            RTCpuSetCopy(&pDevExt->TscDeltaCpuSet, &pGip->OnlineCpuSet);
     884            supdrvMeasureInitialTscDeltas(pDevExt);
     885#endif
     886        }
     887    }
     888    else if (enmEvent == RTPOWEREVENT_SUSPEND)
    871889        ASMAtomicWriteBool(&pDevExt->fInvTscRefinePowerEvent, true);
    872890}
     
    13881406                {
    13891407#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    1390                     supdrvTscDeltaThreadStartMeasurement(pDevExt);
     1408                    supdrvTscDeltaThreadStartMeasurement(pDevExt, false /* fForceAll */);
    13911409#else
    13921410                    uint32_t iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
     
    18241842                    && !supdrvOSGetForcedAsyncTscMode(pDevExt)))
    18251843    {
    1826         /* Basically, invariant Windows boxes, should never be detected as async (i.e. TSC-deltas should be 0). */
    1827         OSDBGPRINT(("supdrvGipCreate: The TSC-deltas should be normalized by the host OS, but verifying shows it's not!\n"));
     1844        OSDBGPRINT(("supdrvGipCreate: Host-OS/user claims the TSC-deltas are zero but we detected async. TSC! Bad.\n"));
    18281845        return VERR_INTERNAL_ERROR_2;
    18291846    }
     1847
     1848    /* It doesn't make sense to do TSC-delta detection on systems we detect as async. */
     1849    AssertReturn(   pGip->u32Mode != SUPGIPMODE_ASYNC_TSC
     1850                 || pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED, VERR_INTERNAL_ERROR_3);
    18301851
    18311852    /*
     
    18571878        RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet);
    18581879#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    1859         if (   pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED
    1860             && pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     1880        if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    18611881            rc = supdrvTscDeltaThreadInit(pDevExt);
    18621882#endif
     
    18741894                {
    18751895#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    1876                     supdrvTscDeltaThreadStartMeasurement(pDevExt);
     1896                    supdrvTscDeltaThreadStartMeasurement(pDevExt, true /* fForceAll */);
    18771897#else
    18781898                    uint16_t iCpu;
     
    26002620    /** @} */
    26012621
    2602     /** Padding to make sure the uVar1 is in its own cache line. */
     2622    /** Padding to make sure the worker variables live is in its own cache line. */
    26032623    uint64_t                    au64CacheLinePaddingBetween[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
    26042624
     
    38573877
    38583878/**
    3859  * Clears TSC delta related variables.
    3860  *
    3861  * Clears all TSC samples as well as the delta synchronization variable on the
    3862  * all the per-CPU structs.  Optionally also clears the per-cpu deltas too.
    3863  *
    3864  * @param   pDevExt         Pointer to the device instance data.
    3865  * @param   fClearDeltas    Whether the deltas are also to be cleared.
    3866  */
    3867 static void supdrvClearTscSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas)
     3879 * Resets the TSC-delta related TSC samples and optionally the deltas
     3880 * themselves.
     3881 *
     3882 * @param   pDevExt             Pointer to the device instance data.
     3883 * @param   fResetTscDeltas     Whether the TSC-deltas are also to be reset.
     3884 *
     3885 * @remarks This might be called while holding a spinlock!
     3886 */
     3887static void supdrvTscResetSamples(PSUPDRVDEVEXT pDevExt, bool fResetTscDeltas)
    38683888{
    38693889    unsigned iCpu;
     
    38733893        PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu];
    38743894        ASMAtomicWriteU64(&pGipCpu->u64TSCSample, GIP_TSC_DELTA_RSVD);
    3875         if (fClearDeltas)
     3895        if (fResetTscDeltas)
     3896        {
     3897            RTCpuSetDelByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpu->iCpuSet);
    38763898            ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, INT64_MAX);
    3877     }
    3878 }
    3879 
    3880 
    3881 /**
    3882  * Performs the initial measurements of the TSC deltas between CPUs.
    3883  *
    3884  * This is called by supdrvGipCreate or triggered by it if threaded.
     3899        }
     3900    }
     3901}
     3902
     3903
     3904/**
     3905 * Picks an online CPU as the master TSC for TSC-delta computations.
    38853906 *
    38863907 * @returns VBox status code.
    3887  * @param   pDevExt     Pointer to the device instance data.
    3888  *
    3889  * @remarks Must be called only after supdrvGipInitOnCpu() as this function uses
    3890  *          idCpu, GIP's online CPU set which are populated in
    3891  *          supdrvGipInitOnCpu().
    3892  */
    3893 static int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt)
    3894 {
    3895     PSUPGIPCPU pGipCpuMaster;
    3896     unsigned   iCpu;
    3897     unsigned   iOddEven;
    3898     PSUPGLOBALINFOPAGE pGip   = pDevExt->pGip;
    3899     uint32_t   idxMaster      = UINT32_MAX;
    3900     int        rc             = VINF_SUCCESS;
    3901     uint32_t   cMpOnOffEvents = ASMAtomicReadU32(&pDevExt->cMpOnOffEvents);
    3902 
    3903     Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
    3904 
     3908 * @param   pDevExt         Pointer to the device instance data.
     3909 * @param   pidxMaster      Where to store the CPU array index of the chosen
     3910 *                          master. Optional, can be NULL.
     3911 */
     3912static int supdrvTscPickMaster(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster)
     3913{
    39053914    /*
    39063915     * Pick the first CPU online as the master TSC and make it the new GIP master based
     
    39113920     * master as this point since the sync/async timer isn't created yet.
    39123921     */
    3913     supdrvClearTscSamples(pDevExt, true /* fClearDeltas */);
     3922    unsigned iCpu;
     3923    uint32_t idxMaster = UINT32_MAX;
     3924    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    39143925    for (iCpu = 0; iCpu < RT_ELEMENTS(pGip->aiCpuFromApicId); iCpu++)
    39153926    {
     
    39223933                idxMaster = idxCpu;
    39233934                pGipCpu->i64TSCDelta = GIP_TSC_DELTA_INITIAL_MASTER_VALUE;
    3924                 break;
     3935                ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpu->idCpu);
     3936                if (pidxMaster)
     3937                    *pidxMaster = idxMaster;
     3938                return VINF_SUCCESS;
    39253939            }
    39263940        }
    39273941    }
    3928     AssertReturn(idxMaster != UINT32_MAX, VERR_CPU_NOT_FOUND);
     3942    return VERR_CPU_OFFLINE;
     3943}
     3944
     3945
     3946/**
     3947 * Performs the initial measurements of the TSC deltas between CPUs.
     3948 *
     3949 * This is called by supdrvGipCreate(), supdrvGipPowerNotificationCallback() or
     3950 * triggered by it if threaded.
     3951 *
     3952 * @returns VBox status code.
     3953 * @param   pDevExt     Pointer to the device instance data.
     3954 *
     3955 * @remarks Must be called only after supdrvGipInitOnCpu() as this function uses
     3956 *          idCpu, GIP's online CPU set which are populated in
     3957 *          supdrvGipInitOnCpu().
     3958 */
     3959static int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt)
     3960{
     3961    PSUPGIPCPU pGipCpuMaster;
     3962    unsigned   iCpu;
     3963    unsigned   iOddEven;
     3964    PSUPGLOBALINFOPAGE pGip   = pDevExt->pGip;
     3965    uint32_t   idxMaster      = UINT32_MAX;
     3966    uint32_t   cMpOnOffEvents = ASMAtomicReadU32(&pDevExt->cMpOnOffEvents);
     3967
     3968    Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
     3969    supdrvTscResetSamples(pDevExt, true /* fClearDeltas */);
     3970    int rc = supdrvTscPickMaster(pDevExt, &idxMaster);
     3971    if (RT_FAILURE(rc))
     3972    {
     3973        SUPR0Printf("Failed to pick a CPU master for TSC-delta measurements rc=%Rrc\n", rc);
     3974        return rc;
     3975    }
     3976    AssertReturn(idxMaster < pGip->cCpus, VERR_INVALID_CPU_INDEX);
    39293977    pGipCpuMaster = &pGip->aCPUs[idxMaster];
    3930     ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpuMaster->idCpu);
    39313978
    39323979    /*
     
    40084055{
    40094056    PSUPDRVDEVEXT     pDevExt = (PSUPDRVDEVEXT)pvUser;
    4010     bool              fInitialMeasurement = true;
    40114057    uint32_t          cConsecutiveTimeouts = 0;
    40124058    int               rc = VERR_INTERNAL_ERROR_2;
     
    40684114            {
    40694115                cConsecutiveTimeouts = 0;
    4070                 if (fInitialMeasurement)
     4116                if (pDevExt->fTscThreadRecomputeAllDeltas)
    40714117                {
    40724118                    int cTries = 8;
    40734119                    int cMsWaitPerTry = 10;
    4074                     fInitialMeasurement = false;
     4120                    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     4121                    Assert(pGip);
    40754122                    do
    40764123                    {
     4124                        RTCpuSetCopy(&pDevExt->TscDeltaCpuSet, &pGip->OnlineCpuSet);
    40774125                        rc = supdrvMeasureInitialTscDeltas(pDevExt);
    40784126                        if (   RT_SUCCESS(rc)
     
    40854133                        RTThreadSleep(cMsWaitPerTry);
    40864134                    } while (cTries-- > 0);
     4135                    pDevExt->fTscThreadRecomputeAllDeltas = false;
    40874136                }
    40884137                else
     
    41074156                            {
    41084157                                /*
    4109                                  * The thread/someone must've called SUPR0TscDeltaMeasureBySetIndex,
     4158                                 * The thread/someone must've called SUPR0TscDeltaMeasureBySetIndex(),
    41104159                                 * mark the delta as fine to get the timer thread off our back.
    41114160                                 */
     
    41204169                    pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Listening;
    41214170                RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    4122                 Assert(rc != VERR_NOT_AVAILABLE);   /* VERR_NOT_AVAILABLE is used as the initial value. */
     4171                Assert(rc != VERR_NOT_AVAILABLE);  /* VERR_NOT_AVAILABLE is used as init value, see supdrvTscDeltaThreadInit(). */
    41234172                ASMAtomicWriteS32(&pDevExt->rcTscDelta, rc);
    41244173                break;
     
    42144263 *
    42154264 * @param   pDevExt     Pointer to the device instance data.
    4216  */
    4217 static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt)
    4218 {
    4219     if (RT_LIKELY(pDevExt->hTscDeltaThread != NIL_RTTHREAD))
     4265 * @param   fForceAll   Force re-calculating TSC-deltas on all CPUs.
     4266 */
     4267static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt, bool fForceAll)
     4268{
     4269    if (pDevExt->hTscDeltaThread != NIL_RTTHREAD)
    42204270    {
    42214271        RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
     
    42244274        {
    42254275            pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
    4226         }
     4276            if (fForceAll)
     4277                pDevExt->fTscThreadRecomputeAllDeltas = true;
     4278        }
     4279        else if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_WaitAndMeasure
     4280                 && fForceAll)
     4281            pDevExt->fTscThreadRecomputeAllDeltas = true;
    42274282        RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    42284283        RTThreadUserSignal(pDevExt->hTscDeltaThread);
  • trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h

    r54448 r54578  
    747747    /** Whether the TSC-delta measurement was successful. */
    748748    int32_t volatile                rcTscDelta;
     749    /** Tell the thread we want TSC-deltas for all CPUs with retries. */
     750    bool                            fTscThreadRecomputeAllDeltas;
    749751    /** @} */
    750752#endif
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