Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan <jeff....@intel.com> CC: Feng Tian <feng.t...@intel.com> CC: Jiewen Yao <jiewen....@intel.com> CC: Michael Kinney <michael.d.kin...@intel.com> --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 14 +++ UefiCpuPkg/CpuMpPei/CpuMpPei.h | 34 +++++++ UefiCpuPkg/CpuMpPei/PeiMpServices.c | 188 ++++++++++++++++++++++++++++++++++++ UefiCpuPkg/CpuMpPei/PeiMpServices.h | 82 ++++++++++++++++ 4 files changed, 318 insertions(+)
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index d218313..bfcf816 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 8e83dc7..ed6cf05 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 6eff772..50145b3 100644 --- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c +++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c @@ -319,6 +319,194 @@ 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 General purpose services available to every PEIM. + @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. See type + EFI_AP_PROCEDURE. + @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] TimeoutInMicrosecsond 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 4ac5d93..71f5a04 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. @@ -99,6 +102,85 @@ 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 General purpose services available to every PEIM. + @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. See type + EFI_AP_PROCEDURE. + @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] TimeoutInMicrosecsond 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 -- 1.9.5.msysgit.0 ------------------------------------------------------------------------------ Don't Limit Your Business. Reach for the Cloud. GigeNET's Cloud Solutions provide you with the tools and support that you need to offload your IT needs and focus on growing your business. Configured For All Businesses. Start Your Cloud Today. https://www.gigenetcloud.com/ _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel