From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by ml01.01.org (Postfix) with ESMTP id F2EB91A1EDB for ; Tue, 2 Aug 2016 02:00:36 -0700 (PDT) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP; 02 Aug 2016 02:00:37 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.28,459,1464678000"; d="scan'208";a="743019420" Received: from jfan12-desk.ccr.corp.intel.com ([10.239.9.5]) by FMSMGA003.fm.intel.com with ESMTP; 02 Aug 2016 02:00:35 -0700 From: Jeff Fan To: edk2-devel@lists.01.org Cc: Michael Kinney , Feng Tian , Giri P Mudusuru , Laszlo Ersek Date: Tue, 2 Aug 2016 16:59:34 +0800 Message-Id: <1470128388-17960-35-git-send-email-jeff.fan@intel.com> X-Mailer: git-send-email 2.7.4.windows.1 In-Reply-To: <1470128388-17960-1-git-send-email-jeff.fan@intel.com> References: <1470128388-17960-1-git-send-email-jeff.fan@intel.com> Subject: [Patch v5 34/48] UefiCpuPkg/MpInitLib: Implementation of MpInitLibStartupAllAPs() X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Aug 2016 09:00:37 -0000 v4: 1. Simply the internal function StartupAllAPsWorker()'s function header due to it is duplicated with MpInitLibStartupAllAPs(). v3: 1. Use CamelCase for mStopCheckAllApsStatus and CheckAndUpdateApsStatus() Cc: Michael Kinney Cc: Feng Tian Cc: Giri P Mudusuru Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan --- UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 23 ++++- UefiCpuPkg/Library/MpInitLib/MpLib.c | 158 ++++++++++++++++++++++++++++++++ UefiCpuPkg/Library/MpInitLib/MpLib.h | 41 +++++++++ UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 13 ++- 4 files changed, 233 insertions(+), 2 deletions(-) diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c index 75845bd..1043bec 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c @@ -305,7 +305,28 @@ MpInitLibStartupAllAPs ( OUT UINTN **FailedCpuList OPTIONAL ) { - return EFI_UNSUPPORTED; + EFI_STATUS Status; + + // + // Temporarily stop checkAllApsStatus for avoid resource dead-lock. + // + mStopCheckAllApsStatus = TRUE; + + Status = StartupAllAPsWorker ( + Procedure, + SingleThread, + WaitEvent, + TimeoutInMicroseconds, + ProcedureArgument, + FailedCpuList + ); + + // + // Start checkAllApsStatus + // + mStopCheckAllApsStatus = FALSE; + + return Status; } /** diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index c10dcd3..fbe2e8b 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -1720,6 +1720,164 @@ MpInitLibGetNumberOfProcessors ( /** + Worker function to execute a caller provided function on all enabled APs. + + @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] WaitEvent The event created by the caller with CreateEvent() + service. + @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for + APs to return from Procedure, either for + blocking or non-blocking mode. + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] FailedCpuList If all APs finish successfully, then its + content is set to NULL. If not all APs + finish before timeout expires, then its + content is set to address of the buffer + holding handle numbers of the failed APs. + + @retval EFI_SUCCESS In blocking mode, all APs have finished before + the timeout expired. + @retval EFI_SUCCESS In non-blocking mode, function has been dispatched + to all enabled APs. + @retval others Failed to Startup all APs. + +**/ +EFI_STATUS +StartupAllAPsWorker ( + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ) +{ + EFI_STATUS Status; + CPU_MP_DATA *CpuMpData; + UINTN ProcessorCount; + UINTN ProcessorNumber; + UINTN CallerNumber; + CPU_AP_DATA *CpuData; + BOOLEAN HasEnabledAp; + CPU_STATE ApState; + + CpuMpData = GetCpuMpData (); + + if (FailedCpuList != NULL) { + *FailedCpuList = NULL; + } + + if (CpuMpData->CpuCount == 1) { + return EFI_NOT_STARTED; + } + + if (Procedure == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether caller processor is BSP + // + MpInitLibWhoAmI (&CallerNumber); + if (CallerNumber != CpuMpData->BspNumber) { + return EFI_DEVICE_ERROR; + } + + // + // Update AP state + // + CheckAndUpdateApsStatus (); + + ProcessorCount = CpuMpData->CpuCount; + HasEnabledAp = FALSE; + // + // Check whether all enabled APs are idle. + // If any enabled AP is not idle, return EFI_NOT_READY. + // + for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) { + CpuData = &CpuMpData->CpuData[ProcessorNumber]; + if (ProcessorNumber != CpuMpData->BspNumber) { + ApState = GetApState (CpuData); + if (ApState != CpuStateDisabled) { + HasEnabledAp = TRUE; + if (ApState != CpuStateIdle) { + // + // If any enabled APs are busy, return EFI_NOT_READY. + // + return EFI_NOT_READY; + } + } + } + } + + if (!HasEnabledAp) { + // + // If no enabled AP exists, return EFI_NOT_STARTED. + // + return EFI_NOT_STARTED; + } + + CpuMpData->StartCount = 0; + for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) { + CpuData = &CpuMpData->CpuData[ProcessorNumber]; + CpuData->Waiting = FALSE; + if (ProcessorNumber != CpuMpData->BspNumber) { + if (CpuData->State == CpuStateIdle) { + // + // Mark this processor as responsible for current calling. + // + CpuData->Waiting = TRUE; + CpuMpData->StartCount++; + } + } + } + + CpuMpData->Procedure = Procedure; + CpuMpData->ProcArguments = ProcedureArgument; + CpuMpData->SingleThread = SingleThread; + CpuMpData->FinishedCount = 0; + CpuMpData->RunningCount = 0; + CpuMpData->FailedCpuList = FailedCpuList; + CpuMpData->ExpectedTime = CalculateTimeout ( + TimeoutInMicroseconds, + &CpuMpData->CurrentTime + ); + CpuMpData->TotalTime = 0; + CpuMpData->WaitEvent = WaitEvent; + + if (!SingleThread) { + WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument); + } else { + for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) { + if (ProcessorNumber == CallerNumber) { + continue; + } + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument); + break; + } + } + } + + Status = EFI_SUCCESS; + if (WaitEvent == NULL) { + do { + Status = CheckAllAPs (); + } while (Status == EFI_NOT_READY); + } + + return Status; +} + +/** Worker function to let the caller get one enabled AP to execute a caller-provided function. diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index 04ffba5..06af7cc 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -348,6 +348,47 @@ InitMpGlobalData ( ); /** + Worker function to execute a caller provided function on all enabled APs. + + @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] WaitEvent The event created by the caller with CreateEvent() + service. + @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for + APs to return from Procedure, either for + blocking or non-blocking mode. + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] FailedCpuList If all APs finish successfully, then its + content is set to NULL. If not all APs + finish before timeout expires, then its + content is set to address of the buffer + holding handle numbers of the failed APs. + + @retval EFI_SUCCESS In blocking mode, all APs have finished before + the timeout expired. + @retval EFI_SUCCESS In non-blocking mode, function has been dispatched + to all enabled APs. + @retval others Failed to Startup all APs. + +**/ +EFI_STATUS +StartupAllAPsWorker ( + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ); + +/** Worker function to let the caller get one enabled AP to execute a caller-provided function. diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c index 4ea8fa9..5e714ea 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c @@ -453,7 +453,18 @@ MpInitLibStartupAllAPs ( OUT UINTN **FailedCpuList OPTIONAL ) { - return EFI_UNSUPPORTED; + if (WaitEvent != NULL) { + return EFI_UNSUPPORTED; + } + + return StartupAllAPsWorker ( + Procedure, + SingleThread, + NULL, + TimeoutInMicroseconds, + ProcedureArgument, + FailedCpuList + ); } /** -- 2.7.4.windows.1