Changeset 54578 in vbox for trunk/src/VBox/HostDrivers/Support
- Timestamp:
- Mar 2, 2015 2:42:45 PM (10 years ago)
- Location:
- trunk/src/VBox/HostDrivers/Support
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp
r54551 r54578 126 126 static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 127 127 static void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz); 128 static void supdrvTscResetSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas); 128 129 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 129 130 static int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt); 130 131 static void supdrvTscDeltaTerm(PSUPDRVDEVEXT pDevExt); 131 static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt );132 static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt, bool fForceAll); 132 133 #else 133 134 static int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt); … … 861 862 static DECLCALLBACK(void) supdrvGipPowerNotificationCallback(RTPOWEREVENT enmEvent, void *pvUser) 862 863 { 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) 871 889 ASMAtomicWriteBool(&pDevExt->fInvTscRefinePowerEvent, true); 872 890 } … … 1388 1406 { 1389 1407 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1390 supdrvTscDeltaThreadStartMeasurement(pDevExt );1408 supdrvTscDeltaThreadStartMeasurement(pDevExt, false /* fForceAll */); 1391 1409 #else 1392 1410 uint32_t iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu); … … 1824 1842 && !supdrvOSGetForcedAsyncTscMode(pDevExt))) 1825 1843 { 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")); 1828 1845 return VERR_INTERNAL_ERROR_2; 1829 1846 } 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); 1830 1851 1831 1852 /* … … 1857 1878 RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet); 1858 1879 #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) 1861 1881 rc = supdrvTscDeltaThreadInit(pDevExt); 1862 1882 #endif … … 1874 1894 { 1875 1895 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1876 supdrvTscDeltaThreadStartMeasurement(pDevExt );1896 supdrvTscDeltaThreadStartMeasurement(pDevExt, true /* fForceAll */); 1877 1897 #else 1878 1898 uint16_t iCpu; … … 2600 2620 /** @} */ 2601 2621 2602 /** Padding to make sure the uVar1is in its own cache line. */2622 /** Padding to make sure the worker variables live is in its own cache line. */ 2603 2623 uint64_t au64CacheLinePaddingBetween[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)]; 2604 2624 … … 3857 3877 3858 3878 /** 3859 * Clears TSC delta related variables.3860 * 3861 * Clears all TSC samples as well as the delta synchronization variable on the3862 * 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 supdrv ClearTscSamples(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 */ 3887 static void supdrvTscResetSamples(PSUPDRVDEVEXT pDevExt, bool fResetTscDeltas) 3868 3888 { 3869 3889 unsigned iCpu; … … 3873 3893 PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu]; 3874 3894 ASMAtomicWriteU64(&pGipCpu->u64TSCSample, GIP_TSC_DELTA_RSVD); 3875 if (fClearDeltas) 3895 if (fResetTscDeltas) 3896 { 3897 RTCpuSetDelByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpu->iCpuSet); 3876 3898 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. 3885 3906 * 3886 3907 * @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 */ 3912 static int supdrvTscPickMaster(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster) 3913 { 3905 3914 /* 3906 3915 * Pick the first CPU online as the master TSC and make it the new GIP master based … … 3911 3920 * master as this point since the sync/async timer isn't created yet. 3912 3921 */ 3913 supdrvClearTscSamples(pDevExt, true /* fClearDeltas */); 3922 unsigned iCpu; 3923 uint32_t idxMaster = UINT32_MAX; 3924 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 3914 3925 for (iCpu = 0; iCpu < RT_ELEMENTS(pGip->aiCpuFromApicId); iCpu++) 3915 3926 { … … 3922 3933 idxMaster = idxCpu; 3923 3934 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; 3925 3939 } 3926 3940 } 3927 3941 } 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 */ 3959 static 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); 3929 3977 pGipCpuMaster = &pGip->aCPUs[idxMaster]; 3930 ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpuMaster->idCpu);3931 3978 3932 3979 /* … … 4008 4055 { 4009 4056 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser; 4010 bool fInitialMeasurement = true;4011 4057 uint32_t cConsecutiveTimeouts = 0; 4012 4058 int rc = VERR_INTERNAL_ERROR_2; … … 4068 4114 { 4069 4115 cConsecutiveTimeouts = 0; 4070 if ( fInitialMeasurement)4116 if (pDevExt->fTscThreadRecomputeAllDeltas) 4071 4117 { 4072 4118 int cTries = 8; 4073 4119 int cMsWaitPerTry = 10; 4074 fInitialMeasurement = false; 4120 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 4121 Assert(pGip); 4075 4122 do 4076 4123 { 4124 RTCpuSetCopy(&pDevExt->TscDeltaCpuSet, &pGip->OnlineCpuSet); 4077 4125 rc = supdrvMeasureInitialTscDeltas(pDevExt); 4078 4126 if ( RT_SUCCESS(rc) … … 4085 4133 RTThreadSleep(cMsWaitPerTry); 4086 4134 } while (cTries-- > 0); 4135 pDevExt->fTscThreadRecomputeAllDeltas = false; 4087 4136 } 4088 4137 else … … 4107 4156 { 4108 4157 /* 4109 * The thread/someone must've called SUPR0TscDeltaMeasureBySetIndex ,4158 * The thread/someone must've called SUPR0TscDeltaMeasureBySetIndex(), 4110 4159 * mark the delta as fine to get the timer thread off our back. 4111 4160 */ … … 4120 4169 pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Listening; 4121 4170 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(). */ 4123 4172 ASMAtomicWriteS32(&pDevExt->rcTscDelta, rc); 4124 4173 break; … … 4214 4263 * 4215 4264 * @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 */ 4267 static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt, bool fForceAll) 4268 { 4269 if (pDevExt->hTscDeltaThread != NIL_RTTHREAD) 4220 4270 { 4221 4271 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); … … 4224 4274 { 4225 4275 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; 4227 4282 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 4228 4283 RTThreadUserSignal(pDevExt->hTscDeltaThread); -
trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
r54448 r54578 747 747 /** Whether the TSC-delta measurement was successful. */ 748 748 int32_t volatile rcTscDelta; 749 /** Tell the thread we want TSC-deltas for all CPUs with retries. */ 750 bool fTscThreadRecomputeAllDeltas; 749 751 /** @} */ 750 752 #endif
Note:
See TracChangeset
for help on using the changeset viewer.