UefiCpuPkg/MpInitLib: Check APs Status and update APs status

v3:
  1. Use CamelCase for CheckAndUpdateApsStatus().

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
This commit is contained in:
Jeff Fan 2016-07-21 21:28:16 +08:00
parent e37109bcc7
commit 08085f08ec
4 changed files with 415 additions and 1 deletions

View File

@ -120,6 +120,43 @@ CheckAndUpdateApsStatus (
VOID
)
{
UINTN ProcessorNumber;
EFI_STATUS Status;
CPU_MP_DATA *CpuMpData;
CpuMpData = GetCpuMpData ();
//
// First, check whether pending StartupAllAPs() exists.
//
if (CpuMpData->WaitEvent != NULL) {
Status = CheckAllAPs ();
//
// If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
//
if (Status != EFI_NOT_READY) {
Status = gBS->SignalEvent (CpuMpData->WaitEvent);
CpuMpData->WaitEvent = NULL;
}
}
//
// Second, check whether pending StartupThisAPs() callings exist.
//
for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {
continue;
}
Status = CheckThisAP (ProcessorNumber);
if (Status != EFI_NOT_READY) {
gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);
CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;
}
}
}
/**

View File

@ -901,6 +901,332 @@ WakeUpAP (
}
}
/**
Calculate timeout value and return the current performance counter value.
Calculate the number of performance counter ticks required for a timeout.
If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
as infinity.
@param[in] TimeoutInMicroseconds Timeout value in microseconds.
@param[out] CurrentTime Returns the current value of the performance counter.
@return Expected time stamp counter for timeout.
If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
as infinity.
**/
UINT64
CalculateTimeout (
IN UINTN TimeoutInMicroseconds,
OUT UINT64 *CurrentTime
)
{
//
// Read the current value of the performance counter
//
*CurrentTime = GetPerformanceCounter ();
//
// If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
// as infinity.
//
if (TimeoutInMicroseconds == 0) {
return 0;
}
//
// GetPerformanceCounterProperties () returns the timestamp counter's frequency
// in Hz. So multiply the return value with TimeoutInMicroseconds and then divide
// it by 1,000,000, to get the number of ticks for the timeout value.
//
return DivU64x32 (
MultU64x64 (
GetPerformanceCounterProperties (NULL, NULL),
TimeoutInMicroseconds
),
1000000
);
}
/**
Checks whether timeout expires.
Check whether the number of elapsed performance counter ticks required for
a timeout condition has been reached.
If Timeout is zero, which means infinity, return value is always FALSE.
@param[in, out] PreviousTime On input, the value of the performance counter
when it was last read.
On output, the current value of the performance
counter
@param[in] TotalTime The total amount of elapsed time in performance
counter ticks.
@param[in] Timeout The number of performance counter ticks required
to reach a timeout condition.
@retval TRUE A timeout condition has been reached.
@retval FALSE A timeout condition has not been reached.
**/
BOOLEAN
CheckTimeout (
IN OUT UINT64 *PreviousTime,
IN UINT64 *TotalTime,
IN UINT64 Timeout
)
{
UINT64 Start;
UINT64 End;
UINT64 CurrentTime;
INT64 Delta;
INT64 Cycle;
if (Timeout == 0) {
return FALSE;
}
GetPerformanceCounterProperties (&Start, &End);
Cycle = End - Start;
if (Cycle < 0) {
Cycle = -Cycle;
}
Cycle++;
CurrentTime = GetPerformanceCounter();
Delta = (INT64) (CurrentTime - *PreviousTime);
if (Start > End) {
Delta = -Delta;
}
if (Delta < 0) {
Delta += Cycle;
}
*TotalTime += Delta;
*PreviousTime = CurrentTime;
if (*TotalTime > Timeout) {
return TRUE;
}
return FALSE;
}
/**
Reset an AP to Idle state.
Any task being executed by the AP will be aborted and the AP
will be waiting for a new task in Wait-For-SIPI state.
@param[in] ProcessorNumber The handle number of processor.
**/
VOID
ResetProcessorToIdleState (
IN UINTN ProcessorNumber
)
{
CPU_MP_DATA *CpuMpData;
CpuMpData = GetCpuMpData ();
WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL);
SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
}
/**
Searches for the next waiting AP.
Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
@param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
@retval EFI_SUCCESS The next waiting AP has been found.
@retval EFI_NOT_FOUND No waiting AP exists.
**/
EFI_STATUS
GetNextWaitingProcessorNumber (
OUT UINTN *NextProcessorNumber
)
{
UINTN ProcessorNumber;
CPU_MP_DATA *CpuMpData;
CpuMpData = GetCpuMpData ();
for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
*NextProcessorNumber = ProcessorNumber;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/** Checks status of specified AP.
This function checks whether the specified AP has finished the task assigned
by StartupThisAP(), and whether timeout expires.
@param[in] ProcessorNumber The handle number of processor.
@retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
@retval EFI_TIMEOUT The timeout expires.
@retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
**/
EFI_STATUS
CheckThisAP (
IN UINTN ProcessorNumber
)
{
CPU_MP_DATA *CpuMpData;
CPU_AP_DATA *CpuData;
CpuMpData = GetCpuMpData ();
CpuData = &CpuMpData->CpuData[ProcessorNumber];
//
// Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
// Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
// value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
//
//
// If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
//
if (GetApState(CpuData) == CpuStateFinished) {
if (CpuData->Finished != NULL) {
*(CpuData->Finished) = TRUE;
}
SetApState (CpuData, CpuStateIdle);
return EFI_SUCCESS;
} else {
//
// If timeout expires for StartupThisAP(), report timeout.
//
if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
if (CpuData->Finished != NULL) {
*(CpuData->Finished) = FALSE;
}
//
// Reset failed AP to idle state
//
ResetProcessorToIdleState (ProcessorNumber);
return EFI_TIMEOUT;
}
}
return EFI_NOT_READY;
}
/**
Checks status of all APs.
This function checks whether all APs have finished task assigned by StartupAllAPs(),
and whether timeout expires.
@retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
@retval EFI_TIMEOUT The timeout expires.
@retval EFI_NOT_READY APs have not finished task and timeout has not expired.
**/
EFI_STATUS
CheckAllAPs (
VOID
)
{
UINTN ProcessorNumber;
UINTN NextProcessorNumber;
UINTN ListIndex;
EFI_STATUS Status;
CPU_MP_DATA *CpuMpData;
CPU_AP_DATA *CpuData;
CpuMpData = GetCpuMpData ();
NextProcessorNumber = 0;
//
// Go through all APs that are responsible for the StartupAllAPs().
//
for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
continue;
}
CpuData = &CpuMpData->CpuData[ProcessorNumber];
//
// Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
// Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
// value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
//
if (GetApState(CpuData) == CpuStateFinished) {
CpuMpData->RunningCount ++;
CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
SetApState(CpuData, CpuStateIdle);
//
// If in Single Thread mode, then search for the next waiting AP for execution.
//
if (CpuMpData->SingleThread) {
Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
if (!EFI_ERROR (Status)) {
WakeUpAP (
CpuMpData,
FALSE,
(UINT32) NextProcessorNumber,
CpuMpData->Procedure,
CpuMpData->ProcArguments
);
}
}
}
}
//
// If all APs finish, return EFI_SUCCESS.
//
if (CpuMpData->RunningCount == CpuMpData->StartCount) {
return EFI_SUCCESS;
}
//
// If timeout expires, report timeout.
//
if (CheckTimeout (
&CpuMpData->CurrentTime,
&CpuMpData->TotalTime,
CpuMpData->ExpectedTime)
) {
//
// If FailedCpuList is not NULL, record all failed APs in it.
//
if (CpuMpData->FailedCpuList != NULL) {
*CpuMpData->FailedCpuList =
AllocatePool ((CpuMpData->StartCount - CpuMpData->FinishedCount + 1) * sizeof (UINTN));
ASSERT (*CpuMpData->FailedCpuList != NULL);
}
ListIndex = 0;
for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
//
// Check whether this processor is responsible for StartupAllAPs().
//
if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
//
// Reset failed APs to idle state
//
ResetProcessorToIdleState (ProcessorNumber);
CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
if (CpuMpData->FailedCpuList != NULL) {
(*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;
}
}
}
if (CpuMpData->FailedCpuList != NULL) {
(*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;
}
return EFI_TIMEOUT;
}
return EFI_NOT_READY;
}
/**
MP Initialize Library initialization.

View File

@ -394,7 +394,47 @@ CPU_MP_DATA *
GetCpuMpDataFromGuidedHob (
VOID
);
/** Checks status of specified AP.
This function checks whether the specified AP has finished the task assigned
by StartupThisAP(), and whether timeout expires.
@param[in] ProcessorNumber The handle number of processor.
@retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
@retval EFI_TIMEOUT The timeout expires.
@retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
**/
EFI_STATUS
CheckThisAP (
IN UINTN ProcessorNumber
);
/**
Checks status of all APs.
This function checks whether all APs have finished task assigned by StartupAllAPs(),
and whether timeout expires.
@retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
@retval EFI_TIMEOUT The timeout expires.
@retval EFI_NOT_READY APs have not finished task and timeout has not expired.
**/
EFI_STATUS
CheckAllAPs (
VOID
);
/**
Checks APs status and updates APs status if needed.
**/
VOID
CheckAndUpdateApsStatus (
VOID
);
/**
Detect whether specified processor can find matching microcode patch and load it.

View File

@ -336,6 +336,17 @@ FreeResetVector (
}
}
/**
Checks APs status and updates APs status if needed.
**/
VOID
CheckAndUpdateApsStatus (
VOID
)
{
}
/**
Initialize global data for MP support.