From: Jeff Fan Date: Wed, 15 Jul 2015 03:43:12 +0000 (+0000) Subject: UefiCpuPkg/CpuMpPei: Implementation of PeiStartupAllAPs () X-Git-Tag: edk2-stable201903~9270 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=60ca9e8c185b0711895665113493a531ca645b69 UefiCpuPkg/CpuMpPei: Implementation of PeiStartupAllAPs () Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18008 6f19259b-4bc3-4df7-8a09-765794883524 --- 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 @@ -153,6 +153,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. @@ -163,6 +182,21 @@ GetMpHobData ( VOID ); +/** + 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. 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 @@ -314,6 +314,189 @@ PeiGetProcessorInfo ( return EFI_SUCCESS; } +/** + 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