summaryrefslogtreecommitdiff
path: root/UefiCpuPkg
diff options
context:
space:
mode:
authorJeff Fan <jeff.fan@intel.com>2015-07-15 03:43:12 +0000
committervanjeff <vanjeff@Edk2>2015-07-15 03:43:12 +0000
commit60ca9e8c185b0711895665113493a531ca645b69 (patch)
treed1c48a22e59ef16ff0e114e9e0947c0cdebde31f /UefiCpuPkg
parentbf55f5b2749d575ea54a02d08cad4abf39abbbb8 (diff)
downloadedk2-platforms-60ca9e8c185b0711895665113493a531ca645b69.tar.xz
UefiCpuPkg/CpuMpPei: Implementation of PeiStartupAllAPs ()
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18008 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'UefiCpuPkg')
-rw-r--r--UefiCpuPkg/CpuMpPei/CpuMpPei.c14
-rw-r--r--UefiCpuPkg/CpuMpPei/CpuMpPei.h34
-rw-r--r--UefiCpuPkg/CpuMpPei/PeiMpServices.c183
-rw-r--r--UefiCpuPkg/CpuMpPei/PeiMpServices.h77
4 files changed, 308 insertions, 0 deletions
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index d218313b0d..bfcf816829 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -133,6 +133,8 @@ ApCFunction (
)
{
PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN ProcessorNumber;
+ EFI_AP_PROCEDURE Procedure;
UINTN BistData;
PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
@@ -148,6 +150,18 @@ ApCFunction (
//
MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
MicrocodeDetect ();
+ } else {
+ //
+ // Execute AP function if AP is not disabled
+ //
+ GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
+ if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&
+ (PeiCpuMpData->ApFunction != 0)) {
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;
+ Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;
+ Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
+ }
}
//
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 8e83dc717c..ed6cf05986 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -154,6 +154,25 @@ AsmInitializeGdt (
/**
+ This function will be called by BSP to wakeup AP.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param ApicId Apic ID for the processor to be waked
+ @param Procedure The function to be invoked by AP
+ @param ProcedureArgument The argument to be passed into AP function
+**/
+VOID
+WakeUpAP (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINT32 ApicId,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+
+/**
Get CPU MP Data pointer from the Guided HOB.
@return Pointer to Pointer to PEI CPU MP Data
@@ -164,6 +183,21 @@ GetMpHobData (
);
/**
+ Find the current Processor number by APIC ID.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
Collects BIST data from PPI.
This function collects BIST data from Sec Platform Information2 PPI
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index 6b54396ca5..a4bc26a420 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -315,6 +315,189 @@ PeiGetProcessorInfo (
}
/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking requests only. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If the timeout specified by TimeoutInMicroSeconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Ppi does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. PEI services and Ppis may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroSeconds expires.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] Procedure A pointer to the function to be run on enabled APs of
+ the system.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute the function
+ specified by Procedure one by one, in ascending order
+ of processor handle number. If FALSE, then all the
+ enabled APs execute the function specified by Procedure
+ simultaneously.
+ @param[in] TimeoutInMicroSeconds
+ Indicates the time limit in microseconds for APs to
+ return from Procedure, for blocking mode only. Zero
+ means infinity. If the timeout expires before all APs
+ return from Procedure, then Procedure on the failed APs
+ is terminated. All enabled APs are available for next
+ function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
+ timeout expires in blocking mode, BSP returns
+ EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before the
+ timeout expired.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before all
+ enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupAllAPs (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN UINTN TimeoutInMicroSeconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN ProcessorNumber;
+ UINTN Index;
+ UINTN CallerNumber;
+ BOOLEAN HasEnabledAp;
+ BOOLEAN HasEnabledIdleAp;
+ volatile UINT32 *FinishedCount;
+ EFI_STATUS Status;
+ UINTN WaitCountIndex;
+ UINTN WaitCountNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = PeiCpuMpData->CpuCount;
+
+ HasEnabledAp = FALSE;
+ HasEnabledIdleAp = FALSE;
+ for (Index = 0; Index < ProcessorNumber; Index ++) {
+ if (Index == CallerNumber) {
+ //
+ // Skip BSP
+ //
+ continue;
+ }
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) {
+ HasEnabledAp = TRUE;
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateBusy) {
+ HasEnabledIdleAp = TRUE;
+ }
+ }
+ }
+ if (!HasEnabledAp) {
+ //
+ // If no enabled AP exists, return EFI_NOT_STARTED.
+ //
+ return EFI_NOT_STARTED;
+ }
+ if (!HasEnabledIdleAp) {
+ //
+ // If any enabled APs are busy, return EFI_NOT_READY.
+ //
+ return EFI_NOT_READY;
+ }
+
+ WaitCountNumber = TimeoutInMicroSeconds / CPU_CHECK_AP_INTERVAL + 1;
+ WaitCountIndex = 0;
+ FinishedCount = &PeiCpuMpData->FinishedCount;
+ if (!SingleThread) {
+ WakeUpAP (PeiCpuMpData, TRUE, 0, Procedure, ProcedureArgument);
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroSeconds == 0) {
+ while (*FinishedCount < ProcessorNumber - 1) {
+ CpuPause ();
+ }
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_TIMEOUT;
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= ProcessorNumber - 1) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+ } else {
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (Index == CallerNumber) {
+ continue;
+ }
+ WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[Index].ApicId, Procedure, ProcedureArgument);
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroSeconds == 0) {
+ while (*FinishedCount < 1) {
+ CpuPause ();
+ }
+ } else {
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= 1) {
+ break;
+ }
+ }
+ if (WaitCountIndex == WaitCountNumber) {
+ Status = EFI_TIMEOUT;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
This return the handle number for the calling processor. This service may be
called from the BSP and APs.
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
index e5d27a37cc..d217a66147 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -17,6 +17,9 @@
#include "CpuMpPei.h"
+
+#define CPU_CHECK_AP_INTERVAL 0x100 // 100 microseconds
+
/**
This service retrieves the number of logical processor in the platform
and the number of those logical processors that are enabled on this boot.
@@ -95,6 +98,80 @@ PeiGetProcessorInfo (
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
);
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking requests only. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If the timeout specified by TimeoutInMicroSeconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Ppi does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. PEI services and Ppis may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroSeconds expires.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] Procedure A pointer to the function to be run on enabled APs of
+ the system.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute the function
+ specified by Procedure one by one, in ascending order
+ of processor handle number. If FALSE, then all the
+ enabled APs execute the function specified by Procedure
+ simultaneously.
+ @param[in] TimeoutInMicroSeconds
+ Indicates the time limit in microseconds for APs to
+ return from Procedure, for blocking mode only. Zero
+ means infinity. If the timeout expires before all APs
+ return from Procedure, then Procedure on the failed APs
+ is terminated. All enabled APs are available for next
+ function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
+ timeout expires in blocking mode, BSP returns
+ EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before the
+ timeout expired.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before all
+ enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupAllAPs (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN UINTN TimeoutInMicroSeconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+
/**
This return the handle number for the calling processor. This service may be