mirror of https://github.com/acidanthera/audk.git
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:
parent
e37109bcc7
commit
08085f08ec
|
@ -120,6 +120,43 @@ CheckAndUpdateApsStatus (
|
||||||
VOID
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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.
|
MP Initialize Library initialization.
|
||||||
|
|
||||||
|
|
|
@ -395,6 +395,46 @@ GetCpuMpDataFromGuidedHob (
|
||||||
VOID
|
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.
|
Detect whether specified processor can find matching microcode patch and load it.
|
||||||
|
|
||||||
|
|
|
@ -336,6 +336,17 @@ FreeResetVector (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks APs status and updates APs status if needed.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
CheckAndUpdateApsStatus (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initialize global data for MP support.
|
Initialize global data for MP support.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue