Changeset 54315 in vbox for trunk/src/VBox/HostDrivers
- Timestamp:
- Feb 19, 2015 9:33:21 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 98390
- Location:
- trunk/src/VBox/HostDrivers/Support
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrv.c
r54313 r54315 179 179 RTCPUID idCpu, uint8_t idApic, uint64_t iTick); 180 180 static void supdrvGipInitCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS); 181 static int supdrvMeasure TscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster);181 static int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt); 182 182 static int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker); 183 183 static int supdrvIOCtl_ResumeSuspendedKbds(void); … … 6051 6051 { 6052 6052 pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Measuring; 6053 rc = RTSemEventSignal(pDevExt->hTscDeltaEvent); 6053 rc = RTSemEventSignal(pDevExt->hTscDeltaEvent); /* (Safe on windows as long as spinlock isn't IRQ safe.) */ 6054 6054 if (RT_FAILURE(rc)) 6055 6055 return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "RTSemEventSignal", rc); … … 6070 6070 do 6071 6071 { 6072 rc = supdrvMeasure TscDeltas(pDevExt, NULL /* pidxMaster */);6072 rc = supdrvMeasureInitialTscDeltas(pDevExt); 6073 6073 if ( RT_SUCCESS(rc) 6074 6074 || ( RT_FAILURE(rc) … … 6092 6092 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu]; 6093 6093 if ( pGipCpuWorker->i64TSCDelta == INT64_MAX 6094 && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->i dCpu))6094 && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet)) 6095 6095 { 6096 6096 rc |= supdrvMeasureTscDeltaOne(pDevExt, iCpu); … … 6108 6108 6109 6109 case kTscDeltaThreadState_Terminating: 6110 pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Destroyed; 6110 6111 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 6111 6112 return VINF_SUCCESS; … … 6125 6126 * 6126 6127 * @returns VINF_SUCCESS on success, VERR_TIMEOUT if it doesn't respond in time, 6127 * other error code on internal error.6128 * other error code on internal error. 6128 6129 * 6129 6130 * @param pThis Pointer to the grant service instance data. … … 6769 6770 do 6770 6771 { 6771 rc = supdrvMeasure TscDeltas(pDevExt, NULL /* pidxMaster */);6772 rc = supdrvMeasureInitialTscDeltas(pDevExt); 6772 6773 if ( rc != VERR_TRY_AGAIN 6773 6774 && rc != VERR_CPU_OFFLINE) … … 6826 6827 } 6827 6828 else 6828 OSDBGPRINT(("supdrvGipCreate: supdrvMeasure TscDeltas failed. rc=%Rrc\n", rc));6829 OSDBGPRINT(("supdrvGipCreate: supdrvMeasureInitialTscDeltas failed. rc=%Rrc\n", rc)); 6829 6830 } 6830 6831 else … … 7002 7003 * @param idCpu The CPU ID. 7003 7004 */ 7004 static uint32_t supdrvGip CpuIndexFromCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu)7005 static uint32_t supdrvGipFindOrAllocCpuIndexForCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu) 7005 7006 { 7006 7007 uint32_t i, cTries; … … 7030 7031 7031 7032 /** 7033 * Finds the GIP CPU index corresponding to @a idCpu. 7034 * 7035 * @returns GIP CPU array index, UINT32_MAX if not found. 7036 * @param pGip The GIP. 7037 * @param idCpu The CPU ID. 7038 */ 7039 static uint32_t supdrvGipFindCpuIndexForCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu) 7040 { 7041 uint32_t i; 7042 for (i = 0; i < pGip->cCpus; i++) 7043 if (pGip->aCPUs[i].idCpu == idCpu) 7044 return i; 7045 return UINT32_MAX; 7046 } 7047 7048 7049 /** 7032 7050 * The calling CPU should be accounted as online, update GIP accordingly. 7033 7051 * 7034 * This is used by supdrvGip MpEvent as well as the supdrvGipCreate.7052 * This is used by supdrvGipCreate() as well as supdrvGipMpEvent(). 7035 7053 * 7036 7054 * @param pDevExt The device extension. … … 7072 7090 */ 7073 7091 u64NanoTS = RTTimeSystemNanoTS() - pGip->u32UpdateIntervalNS; 7074 i = supdrvGip CpuIndexFromCpuId(pGip, idCpu);7092 i = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu); 7075 7093 supdrvGipInitCpu(pDevExt, pGip, &pGip->aCPUs[i], u64NanoTS); 7076 7094 idApic = ASMGetApicId(); … … 7091 7109 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 7092 7110 { 7093 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, i dCpu);7111 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, iCpuSet); 7094 7112 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 7095 7113 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); … … 7153 7171 ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX); 7154 7172 /* Remove this CPU from the set of CPUs that we have obtained the TSC deltas. */ 7155 RTCpuSetDel(&pDevExt->TscDeltaObtainedCpuSet, i dCpu);7173 RTCpuSetDel(&pDevExt->TscDeltaObtainedCpuSet, iCpuSet); 7156 7174 } 7157 7175 … … 7210 7228 { 7211 7229 /* 7212 * Find a new GIP master.7230 * The GIP master is going offline, find a new one. 7213 7231 */ 7214 7232 bool fIgnored; 7215 7233 unsigned i; 7216 int64_t iTSCDelta;7217 uint32_t idxNewGipMaster;7218 7234 RTCPUID idNewGipMaster = NIL_RTCPUID; 7219 7235 RTCPUSET OnlineCpus; … … 7234 7250 ASMAtomicCmpXchgSize(&pDevExt->idGipMaster, idNewGipMaster, idGipMaster, fIgnored); 7235 7251 NOREF(fIgnored); 7236 7237 /* 7238 * Adjust all the TSC deltas against the new GIP master. 7239 */ 7240 /** @todo this needs fixing, we cannot dynamically re-adjust the base unless 7241 * GIP isn't mapped and no other consumers of TSC-deltas. Basically, 7242 * we need to adjust the master's own TSC-delta (can be non-zero) 7243 * while computing the deltas. */ 7244 if (pGip) 7245 { 7246 idxNewGipMaster = supdrvGipCpuIndexFromCpuId(pGip, idNewGipMaster); 7247 iTSCDelta = pGip->aCPUs[idxNewGipMaster].i64TSCDelta; 7248 Assert(iTSCDelta != INT64_MAX); 7249 for (i = 0; i < pGip->cCpus; i++) 7250 { 7251 PSUPGIPCPU pGipCpu = &pGip->aCPUs[i]; 7252 int64_t iWorkerDelta = pGipCpu->i64TSCDelta; 7253 if (iWorkerDelta != INT64_MAX) 7254 iWorkerDelta -= iTSCDelta; 7255 ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, iWorkerDelta); 7256 } 7257 Assert(pGip->aCPUs[idxNewGipMaster].i64TSCDelta == 0); 7258 } 7259 } 7260 } 7261 } 7262 7263 7264 /** 7265 * Callback used by supdrvMeasureTscDeltas() to read the TSC on two CPUs and 7266 * compute the delta between them. 7252 } 7253 } 7254 } 7255 7256 7257 /** 7258 * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs 7259 * and compute the delta between them. 7267 7260 * 7268 7261 * @param idCpu The CPU we are current scheduled on. 7269 7262 * @param pvUser1 Opaque pointer to the device instance data. 7270 * @param pvUser2 Opaque pointer to the worker Cpu Id.7263 * @param pvUser2 Pointer to the SUPGIPCPU entry of the worker CPU. 7271 7264 * 7272 7265 * @remarks Measuring TSC deltas between the CPUs is tricky because we need to … … 7297 7290 static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 7298 7291 { 7299 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser1; 7300 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 7301 uint32_t *pidWorker = (uint32_t *)pvUser2; 7302 RTCPUID idMaster = ASMAtomicUoReadU32(&pDevExt->idTscDeltaInitiator); 7303 unsigned idxMaster = supdrvGipCpuIndexFromCpuId(pGip, idMaster); 7304 unsigned idxWorker = supdrvGipCpuIndexFromCpuId(pGip, *pidWorker); 7305 PSUPGIPCPU pGipCpuMaster = &pGip->aCPUs[idxMaster]; 7306 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[idxWorker]; 7307 int cTriesLeft = 12; 7292 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser1; 7293 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 7294 PSUPGIPCPU pGipCpuWorker = (PSUPGIPCPU)pvUser2; 7295 uint32_t idWorker = pGipCpuWorker->idCpu; 7296 RTCPUID idMaster = ASMAtomicUoReadU32(&pDevExt->idTscDeltaInitiator); 7297 unsigned idxMaster = supdrvGipFindCpuIndexForCpuId(pGip, idMaster); 7298 PSUPGIPCPU pGipCpuMaster = &pGip->aCPUs[idxMaster]; 7299 int cTriesLeft; 7308 7300 7309 7301 if ( idCpu != idMaster 7310 && idCpu != *pidWorker)7302 && idCpu != idWorker) 7311 7303 return; 7312 7304 … … 7359 7351 } 7360 7352 7353 /* 7354 * ... 7355 */ 7361 7356 Assert(pGipCpuWorker->i64TSCDelta == INT64_MAX); 7357 cTriesLeft = 12; 7362 7358 while (cTriesLeft-- > 0) 7363 7359 { … … 7397 7393 if (pGipCpuWorker->u64TSCSample != GIP_TSC_DELTA_RSVD) 7398 7394 { 7399 int64_t iDelta = pGipCpuWorker->u64TSCSample - pGipCpuMaster->u64TSCSample; 7395 int64_t iDelta = pGipCpuWorker->u64TSCSample 7396 - (pGipCpuMaster->u64TSCSample - pGipCpuMaster->i64TSCDelta); 7397 /** @todo r=bird: Why isn't this code using absolute values? Guess it mostly works fine because 7398 * the detection code is biased thowards positive deltas (see tstSupTscDelta.cpp output) ... */ 7400 7399 if (iDelta < pGipCpuWorker->i64TSCDelta) 7401 7400 pGipCpuWorker->i64TSCDelta = iDelta; … … 7464 7463 if (idCpu == idMaster) 7465 7464 { 7466 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->i dCpu);7467 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->i dCpu);7465 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet); 7466 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet); 7468 7467 } 7469 7468 else 7470 7469 { 7471 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->i dCpu);7472 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->i dCpu);7470 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet); 7471 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet); 7473 7472 } 7474 7473 break; … … 7529 7528 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 7530 7529 7530 /* 7531 * Don't attempt measuring the delta for the GIP master. 7532 */ 7531 7533 if (pGipCpuWorker->idCpu == idMaster) 7532 7534 { 7533 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, 0); 7535 if (pGipCpuWorker->i64TSCDelta == INT64_MAX) /* This shouldn't happen, but just in case. */ 7536 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, 0); 7534 7537 return VINF_SUCCESS; 7535 7538 } … … 7550 7553 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX); 7551 7554 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); 7552 rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pDevExt, &pGipCpuWorker->idCpu);7555 rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pDevExt, pGipCpuWorker); 7553 7556 if (RT_SUCCESS(rc)) 7554 7557 { … … 7587 7590 7588 7591 /** 7589 * Measures the TSC deltas between CPUs. 7590 * 7592 * Performs the initial measurements of the TSC deltas between CPUs. 7593 * 7594 * This is called by supdrvGipCreate or triggered by it if threaded. 7595 * 7596 * @returns VBox status code. 7591 7597 * @param pDevExt Pointer to the device instance data. 7592 * @param pidxMaster Where to store the index of the chosen master TSC if we 7593 * managed to determine the TSC deltas successfully. 7594 * Optional, can be NULL. 7595 * 7596 * @returns VBox status code. 7598 * 7597 7599 * @remarks Must be called only after supdrvGipInitOnCpu() as this function uses 7598 7600 * idCpu, GIP's online CPU set which are populated in 7599 7601 * supdrvGipInitOnCpu(). 7600 7602 */ 7601 static int supdrvMeasure TscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster)7603 static int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt) 7602 7604 { 7603 7605 PSUPGIPCPU pGipCpuMaster; … … 7607 7609 int rc = VINF_SUCCESS; 7608 7610 uint32_t cMpOnOffEvents = ASMAtomicReadU32(&pDevExt->cMpOnOffEvents); 7609 uint32_t cOnlineCpus = pGip->cOnlineCpus;7610 7611 7611 7612 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); … … 7638 7639 ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpuMaster->idCpu); 7639 7640 7640 AssertReturn(cOnlineCpus > 0, VERR_INTERNAL_ERROR_5); 7641 /* 7642 * If there is only a single CPU online we have nothing to do. 7643 */ 7641 7644 if (pGip->cOnlineCpus <= 1) 7642 7645 { 7643 if (pidxMaster) 7644 *pidxMaster = idxMaster; 7646 AssertReturn(pGip->cOnlineCpus > 0, VERR_INTERNAL_ERROR_5); 7645 7647 return VINF_SUCCESS; 7646 7648 } 7647 7649 7650 /* 7651 * Loop thru the GIP CPU array and get deltas for each CPU (except the master). 7652 */ 7648 7653 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 7649 7654 { 7650 7655 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu]; 7651 7656 if ( iCpu != idxMaster 7652 && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->i dCpu))7657 && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet)) 7653 7658 { 7654 7659 rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu); … … 7669 7674 } 7670 7675 7671 if ( RT_SUCCESS(rc)7672 && !pGipCpuMaster->i64TSCDelta7673 && pidxMaster)7674 {7675 *pidxMaster = idxMaster;7676 }7677 7676 return rc; 7678 7677 } … … 8267 8266 if (RT_UNLIKELY(iTick == 1)) 8268 8267 { 8269 iCpu = supdrvGip CpuIndexFromCpuId(pGip, idCpu);8268 iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu); 8270 8269 if (pGip->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_OFFLINE) 8271 8270 supdrvGipMpEventOnline(pDevExt, idCpu); … … 8375 8374 * thread. Check if anyone uses/needs fAsync before implementing this. */ 8376 8375 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 8377 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->i dCpu);8376 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet); 8378 8377 if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening 8379 8378 || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring) -
trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
r54306 r54315 251 251 /** Uninitialized/invalid value. */ 252 252 kTscDeltaThreadState_Invalid = 0, 253 /** The thread is being created. */ 253 /** The thread is being created. 254 * Next state: Listening, Butchered, Terminating */ 254 255 kTscDeltaThreadState_Creating, 255 /** The thread is listening for events. */ 256 /** The thread is listening for events. 257 * Previous state: Creating, Measuring 258 * Next state: WaitAndMeasure, Butchered, Terminated */ 256 259 kTscDeltaThreadState_Listening, 257 /** The thread is sleeping before starting a measurement. */ 260 /** The thread is sleeping before starting a measurement. 261 * Previous state: Listening, Measuring 262 * Next state: Measuring, Butchered, Terminating 263 * @remarks The thread won't enter this state on its own, it is put into this 264 * state by the GIP timer, the CPU online callback and by the 265 * SUP_IOCTL_TSC_DELTA_MEASURE code. */ 258 266 kTscDeltaThreadState_WaitAndMeasure, 259 /** The thread is currently servicing a measurement request. */ 267 /** The thread is currently servicing a measurement request. 268 * Previous state: WaitAndMeasure 269 * Next state: Listening, WaitAndMeasure, Terminate */ 260 270 kTscDeltaThreadState_Measuring, 261 /** The thread is terminating. */ 271 /** The thread is terminating. 272 * @remarks The thread won't enter this state on its own, is put into this state 273 * by supdrvTscDeltaTerm. */ 262 274 kTscDeltaThreadState_Terminating, 263 /** The thread is butchered due to an unexpected error. */ 275 /** The thread is butchered due to an unexpected error. 276 * Previous State: Creating, Listening, WaitAndMeasure */ 264 277 kTscDeltaThreadState_Butchered, 265 /** The thread is destroyed. */ 278 /** The thread is destroyed (final). 279 * Previous state: Terminating */ 266 280 kTscDeltaThreadState_Destroyed, 267 281 /** The usual 32-bit blowup hack. */ 268 282 kTscDeltaThreadState_32BitHack = 0x7fffffff 269 } SUPDRVTSCDELTATHREADSTATE , *PSUPDRVTSCDELTATHREADSTATE;270 #endif 283 } SUPDRVTSCDELTATHREADSTATE; 284 #endif /* SUPDRV_USE_TSC_DELTA_THREAD */ 271 285 272 286 /** … … 650 664 uint32_t u32SystemTimerGranularityGrant; 651 665 /** The CPU id of the GIP master. 652 * This CPU is responsible for the updating the common GIP data. */ 666 * This CPU is responsible for the updating the common GIP data and it is 667 * the one used to calculate TSC deltas relative to. 668 * (The initial master will have a 0 zero value, but it it goes offline the 669 * new master may have a non-zero value.) */ 653 670 RTCPUID volatile idGipMaster; 654 671
Note:
See TracChangeset
for help on using the changeset viewer.