mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg/MpInitLib: wait no longer than necessary for initial AP startup
Sometimes a platform knows exactly how many CPUs it has at boot. It should be able to - set PcdCpuMaxLogicalProcessorNumber dynamically to this number, - set PcdCpuApInitTimeOutInMicroSeconds to a very long time (for example MAX_UINT32, approx. 71 minutes), - and expect that MpInitLib wait exactly as long as necessary for all APs to report in. Other platforms should be able to continue setting a reasonably large upper bound on supported CPUs, and waiting for a reasonable, fixed amount of time for all APs to report in. Add this functionality. The TimedWaitForApFinish() function will return when all APs have reported in, or the timeout has expired -- whichever happens first. (Accessing these PCDs dynamically is safe. The PEI and DXE phase instances of this library are restricted to PEIM and DXE_DRIVER client modules, thus the PCD accesses cannot be linked into runtime code.) Cc: Igor Mammedov <imammedo@redhat.com> Cc: Jeff Fan <jeff.fan@intel.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=116 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com>
This commit is contained in:
parent
2b2efe33ea
commit
6e1987f19a
|
@ -683,6 +683,21 @@ FillExchangeInfoData (
|
||||||
AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
|
AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper function that waits until the finished AP count reaches the specified
|
||||||
|
limit, or the specified timeout elapses (whichever comes first).
|
||||||
|
|
||||||
|
@param[in] CpuMpData Pointer to CPU MP Data.
|
||||||
|
@param[in] FinishedApLimit The number of finished APs to wait for.
|
||||||
|
@param[in] TimeLimit The number of microseconds to wait for.
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
TimedWaitForApFinish (
|
||||||
|
IN CPU_MP_DATA *CpuMpData,
|
||||||
|
IN UINT32 FinishedApLimit,
|
||||||
|
IN UINT32 TimeLimit
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function will be called by BSP to wakeup AP.
|
This function will be called by BSP to wakeup AP.
|
||||||
|
|
||||||
|
@ -748,7 +763,11 @@ WakeUpAP (
|
||||||
//
|
//
|
||||||
// Wait for all potential APs waken up in one specified period
|
// Wait for all potential APs waken up in one specified period
|
||||||
//
|
//
|
||||||
MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));
|
TimedWaitForApFinish (
|
||||||
|
CpuMpData,
|
||||||
|
PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
|
||||||
|
PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// Wait all APs waken up if this is not the 1st broadcast of SIPI
|
// Wait all APs waken up if this is not the 1st broadcast of SIPI
|
||||||
|
@ -894,6 +913,58 @@ CheckTimeout (
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper function that waits until the finished AP count reaches the specified
|
||||||
|
limit, or the specified timeout elapses (whichever comes first).
|
||||||
|
|
||||||
|
@param[in] CpuMpData Pointer to CPU MP Data.
|
||||||
|
@param[in] FinishedApLimit The number of finished APs to wait for.
|
||||||
|
@param[in] TimeLimit The number of microseconds to wait for.
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
TimedWaitForApFinish (
|
||||||
|
IN CPU_MP_DATA *CpuMpData,
|
||||||
|
IN UINT32 FinishedApLimit,
|
||||||
|
IN UINT32 TimeLimit
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
|
||||||
|
// "infinity", so check for (TimeLimit == 0) explicitly.
|
||||||
|
//
|
||||||
|
if (TimeLimit == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CpuMpData->TotalTime = 0;
|
||||||
|
CpuMpData->ExpectedTime = CalculateTimeout (
|
||||||
|
TimeLimit,
|
||||||
|
&CpuMpData->CurrentTime
|
||||||
|
);
|
||||||
|
while (CpuMpData->FinishedCount < FinishedApLimit &&
|
||||||
|
!CheckTimeout (
|
||||||
|
&CpuMpData->CurrentTime,
|
||||||
|
&CpuMpData->TotalTime,
|
||||||
|
CpuMpData->ExpectedTime
|
||||||
|
)) {
|
||||||
|
CpuPause ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CpuMpData->FinishedCount >= FinishedApLimit) {
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_VERBOSE,
|
||||||
|
"%a: reached FinishedApLimit=%u in %Lu microseconds\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
FinishedApLimit,
|
||||||
|
DivU64x64Remainder (
|
||||||
|
MultU64x32 (CpuMpData->TotalTime, 1000000),
|
||||||
|
GetPerformanceCounterProperties (NULL, NULL),
|
||||||
|
NULL
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reset an AP to Idle state.
|
Reset an AP to Idle state.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue