Changeset 52725 in vbox for trunk/src/VBox/HostDrivers/Support
- Timestamp:
- Sep 12, 2014 2:03:14 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrv.c
r52621 r52725 167 167 RTCPUID idCpu, uint8_t idApic, uint64_t iTick); 168 168 static void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS); 169 static int supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, uint32_t *pidxMaster); 169 static int supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster); 170 static int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker); 170 171 static int supdrvIOCtl_ResumeSuspendedKbds(void); 171 172 … … 5644 5645 do 5645 5646 { 5646 rc = supdrvMeasureTscDeltas(pDevExt, pGip,NULL /* pidxMaster */);5647 rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */); 5647 5648 if (rc == VERR_TRY_AGAIN) 5648 5649 { … … 5655 5656 if (RT_SUCCESS(rc)) 5656 5657 { 5657 #if 05658 unsigned iCpu;5659 SUPR0Printf("cTries=%u\n", cTries);5660 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)5661 SUPR0Printf("Cpu[%3u].delta=%ld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta);5662 #endif5663 5664 5658 /* 5665 5659 * Create the timer. … … 5938 5932 } 5939 5933 5934 /* Reset the TSC delta, we will recalculate it lazily. */ 5935 ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX); 5936 5940 5937 /* commit it */ 5941 5938 ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_OFFLINE); … … 5980 5977 supdrvGipMpEventOffline(pDevExt, idCpu); 5981 5978 break; 5982 5983 5979 } 5984 5980 } … … 5997 5993 bool fIgnored; 5998 5994 unsigned i; 5995 int64_t iTSCDelta; 5996 uint32_t idxNewGipMaster; 5999 5997 RTCPUID idNewGipMaster = NIL_RTCPUID; 6000 5998 RTCPUSET OnlineCpus; … … 6004 6002 { 6005 6003 RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i); 6006 if ( 6007 && 6004 if ( RTCpuSetIsMember(&OnlineCpus, idCurCpu) 6005 && idCurCpu != idGipMaster) 6008 6006 { 6009 6007 idNewGipMaster = idCurCpu; … … 6015 6013 ASMAtomicCmpXchgSize(&pDevExt->idGipMaster, idNewGipMaster, idGipMaster, fIgnored); 6016 6014 NOREF(fIgnored); 6015 6016 /* 6017 * Adjust all the TSC deltas against the new GIP master. 6018 */ 6019 if (pGip) 6020 { 6021 idxNewGipMaster = supdrvGipCpuIndexFromCpuId(pGip, idNewGipMaster); 6022 iTSCDelta = pGip->aCPUs[idxNewGipMaster].i64TSCDelta; 6023 Assert(iTSCDelta != UINT64_MAX); 6024 for (i = 0; i < pGip->cCpus; i++) 6025 { 6026 PSUPGIPCPU pGipCpu = &pGip->aCPUs[i]; 6027 int64_t iWorkerDelta = pGipCpu->i64TSCDelta; 6028 if (iWorkerDelta != INT64_MAX) 6029 iWorkerDelta -= iTSCDelta; 6030 ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, iWorkerDelta); 6031 } 6032 Assert(pGip->aCPUs[idxNewGipMaster].i64TSCDelta == 0); 6033 } 6017 6034 } 6018 6035 } … … 6043 6060 * earlier. 6044 6061 */ 6045 static DECLCALLBACK(void) supdrv DetermineTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)6062 static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 6046 6063 { 6047 6064 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser1; … … 6053 6070 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[idxWorker]; 6054 6071 uint64_t uMinCmpReadTime = UINT64_MAX; 6055 int cTriesLeft = 8;6072 int cTriesLeft = 12; 6056 6073 6057 6074 if ( idCpu != idMaster … … 6111 6128 for (i = 0; i < GIP_TSC_DELTA_LOOPS; i++) 6112 6129 { 6130 ASMCompilerBarrier(); 6113 6131 if (idCpu == idMaster) 6114 6132 { … … 6226 6244 6227 6245 /** 6246 * Measures the TSC delta between the master GIP CPU and one specified worker 6247 * CPU. 6248 * 6249 * @returns VBox status code. 6250 * @param pDevExt Pointer to the device instance data. 6251 * @param idxWorker The index of the worker CPU from the GIP's array of 6252 * CPUs. 6253 * 6254 * @remarks This can be called with preemption disabled! 6255 */ 6256 static int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker) 6257 { 6258 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 6259 RTCPUID idMaster = pDevExt->idGipMaster; 6260 uint32_t idxMaster = supdrvGipCpuIndexFromCpuId(pGip, idMaster); 6261 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[idxWorker]; 6262 int rc = VERR_CPU_OFFLINE; 6263 6264 if (idxWorker == idxMaster) 6265 { 6266 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, 0); 6267 return VINF_SUCCESS; 6268 } 6269 6270 /* Set the master TSC as the initiator. */ 6271 while (ASMAtomicCmpXchgU32(&g_idTscDeltaInitiator, idMaster, NIL_RTCPUID) == false) 6272 ASMNopPause(); 6273 6274 if (RTCpuSetIsMember(&pGip->OnlineCpuSet, pGipCpuWorker->idCpu)) 6275 { 6276 /* Fire TSC-read workers on all CPUs but only synchronize between master and one worker to ease memory contention. */ 6277 ASMAtomicWriteU32(&g_pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); 6278 rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pGip, &pGipCpuWorker->idCpu); 6279 if (RT_SUCCESS(rc)) 6280 { 6281 if (RT_UNLIKELY(pGipCpuWorker->i64TSCDelta == INT64_MAX)) 6282 rc = VERR_UNRESOLVED_ERROR; 6283 } 6284 } 6285 6286 ASMAtomicWriteU32(&g_idTscDeltaInitiator, NIL_RTCPUID); 6287 return rc; 6288 } 6289 6290 6291 /** 6228 6292 * Measures the TSC deltas between CPUs. 6229 6293 * 6230 6294 * @param pDevExt Pointer to the device instance data. 6231 * @param pGip Pointer to the GIP.6232 6295 * @param pidxMaster Where to store the index of the chosen master TSC if we 6233 6296 * managed to determine the TSC deltas successfully. … … 6239 6302 * supdrvGipInitOnCpu(). 6240 6303 */ 6241 static int supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip,uint32_t *pidxMaster)6304 static int supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster) 6242 6305 { 6243 6306 PSUPGIPCPU pGipCpuMaster; 6244 6307 unsigned iCpu; 6308 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 6309 uint32_t idxMaster = UINT32_MAX; 6310 int rc = VINF_SUCCESS; 6245 6311 uint32_t cMpOnOffEvents = ASMAtomicReadU32(&g_cMpOnOffEvents); 6246 6312 uint32_t cOnlineCpus = pGip->cOnlineCpus; 6247 6313 6248 /* Pick the first CPU which is online as the master TSC. */ 6249 uint32_t idxMaster = UINT32_MAX; 6314 /* 6315 * Pick the first CPU online as the master TSC and make it the new GIP master. 6316 * . 6317 * Technically we can simply use "idGipMaster" but doing this gives us master as CPU 0 . 6318 * in most cases making it nicer/easier for comparisons. It is safe to update the GIP 6319 * master as this point since the sync/async timer isn't created yet. 6320 */ 6250 6321 supdrvClearTscSamples(pGip, true /* fClearDeltas */); 6251 6322 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) … … 6259 6330 } 6260 6331 } 6332 AssertReturn(idxMaster != UINT32_MAX, VERR_CPU_NOT_FOUND); 6333 pGipCpuMaster = &pGip->aCPUs[idxMaster]; 6334 ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpuMaster->idCpu); 6335 6261 6336 AssertReturn(cOnlineCpus > 0, VERR_INTERNAL_ERROR_5); 6262 AssertReturn(idxMaster != UINT32_MAX, VERR_CPU_NOT_FOUND);6263 6264 6337 if (pGip->cOnlineCpus <= 1) 6265 6338 { … … 6269 6342 } 6270 6343 6271 /* Pick the master TSC as the initiator. */6272 pGipCpuMaster = &pGip->aCPUs[idxMaster];6273 ASMAtomicWriteU32(&g_idTscDeltaInitiator, pGipCpuMaster->idCpu);6274 6275 6344 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 6276 6345 { … … 6279 6348 && RTCpuSetIsMember(&pGip->OnlineCpuSet, pGipCpuWorker->idCpu)) 6280 6349 { 6281 int rc; 6282 6283 /* Fire TSC-read workers on all CPUs but only synchronize between master and one worker to memory contention. */ 6284 ASMAtomicWriteU32(&g_pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); 6285 rc = RTMpOnAll(supdrvDetermineTscDeltaCallback, pGip, &pGipCpuWorker->idCpu); 6350 rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu); 6286 6351 if (RT_FAILURE(rc)) 6287 6352 { 6288 SUPR0Printf("supdrvMeasureTscDeltas: RTMpOnAll failed. rc=%d\n", rc); 6289 return rc; 6290 } 6291 6292 if (RT_UNLIKELY(pGipCpuWorker->i64TSCDelta == INT64_MAX)) 6293 { 6294 SUPR0Printf("Failed to measure TSC deltas for CPU[%u] idCpu=%u\n", iCpu, pGipCpuWorker->idCpu); 6295 return VERR_UNRESOLVED_ERROR; 6353 SUPR0Printf("supdrvMeasureTscDeltaOne failed. rc=%d CPU[%u].idCpu=%u Master[%u].idCpu=%u\n", rc, iCpu, 6354 pGipCpuWorker->idCpu, idxMaster, pDevExt->idGipMaster, pGipCpuMaster->idCpu); 6355 break; 6296 6356 } 6297 6357 … … 6299 6359 { 6300 6360 SUPR0Printf("One or more CPUs transitioned between online & offline states. I are confused, retrying...\n"); 6301 return VERR_TRY_AGAIN; 6302 } 6303 } 6304 } 6305 6306 ASMAtomicWriteU32(&g_idTscDeltaInitiator, NIL_RTCPUID); 6307 6308 if (RT_LIKELY(!pGipCpuMaster->i64TSCDelta)) 6309 { 6310 if (pidxMaster) 6311 *pidxMaster = idxMaster; 6312 return VINF_SUCCESS; 6313 } 6314 return VERR_INTERNAL_ERROR_4; 6361 rc = VERR_TRY_AGAIN; 6362 break; 6363 } 6364 } 6365 } 6366 6367 if ( RT_SUCCESS(rc) 6368 && !pGipCpuMaster->i64TSCDelta 6369 && pidxMaster) 6370 { 6371 *pidxMaster = idxMaster; 6372 } 6373 return rc; 6315 6374 } 6316 6375
Note:
See TracChangeset
for help on using the changeset viewer.