Reviewed-by: Jeff Fan <jeff....@intel.com> Thanks!
-----Original Message----- From: Laszlo Ersek [mailto:ler...@redhat.com] Sent: Monday, November 28, 2016 9:09 PM To: edk2-devel-01 Cc: Igor Mammedov; Fan, Jeff; Justen, Jordan L; Kinney, Michael D Subject: [PATCH v3 1/2] UefiCpuPkg/MpInitLib: wait no longer than necessary for initial AP startup Sometimes a platform knows exactly how many CPUs it has at boot. It should be able to - set PcdCpuMaxLogicalProcessorNumber dynamically to this number, - set PcdCpuApInitTimeOutInMicroSeconds to a very long time (for example MAX_UINT32, approx. 71 minutes), - and expect that MpInitLib wait exactly as long as necessary for all APs to report in. Other platforms should be able to continue setting a reasonably large upper bound on supported CPUs, and waiting for a reasonable, fixed amount of time for all APs to report in. Add this functionality. The TimedWaitForApFinish() function will return when all APs have reported in, or the timeout has expired -- whichever happens first. (Accessing these PCDs dynamically is safe. The PEI and DXE phase instances of this library are restricted to PEIM and DXE_DRIVER client modules, thus the PCD accesses cannot be linked into runtime code.) Cc: Igor Mammedov <imamm...@redhat.com> Cc: Jeff Fan <jeff....@intel.com> Cc: Jordan Justen <jordan.l.jus...@intel.com> Cc: Michael Kinney <michael.d.kin...@intel.com> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=116 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <ler...@redhat.com> --- Notes: v3: - preserve original behavior for PcdCpuApInitTimeOutInMicroSeconds==0 [Jeff] UefiCpuPkg/Library/MpInitLib/MpLib.c | 73 +++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 15dbfa1e7d6c..ed22ce67782e 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -684,6 +684,21 @@ FillExchangeInfoData ( } /** + Helper function that waits until the finished AP count reaches the + specified limit, or the specified timeout elapses (whichever comes first). + + @param[in] CpuMpData Pointer to CPU MP Data. + @param[in] FinishedApLimit The number of finished APs to wait for. + @param[in] TimeLimit The number of microseconds to wait for. +**/ +VOID +TimedWaitForApFinish ( + IN CPU_MP_DATA *CpuMpData, + IN UINT32 FinishedApLimit, + IN UINT32 TimeLimit + ); + +/** This function will be called by BSP to wakeup AP. @param[in] CpuMpData Pointer to CPU MP Data @@ -748,7 +763,11 @@ WakeUpAP ( // // Wait for all potential APs waken up in one specified period // - MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds)); + TimedWaitForApFinish ( + CpuMpData, + PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1, + PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds) + ); } else { // // Wait all APs waken up if this is not the 1st broadcast of SIPI @@ -895,6 +914,58 @@ CheckTimeout ( } /** + Helper function that waits until the finished AP count reaches the + specified limit, or the specified timeout elapses (whichever comes first). + + @param[in] CpuMpData Pointer to CPU MP Data. + @param[in] FinishedApLimit The number of finished APs to wait for. + @param[in] TimeLimit The number of microseconds to wait for. +**/ +VOID +TimedWaitForApFinish ( + IN CPU_MP_DATA *CpuMpData, + IN UINT32 FinishedApLimit, + IN UINT32 TimeLimit + ) +{ + // + // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0 + // "infinity", so check for (TimeLimit == 0) explicitly. + // + if (TimeLimit == 0) { + return; + } + + CpuMpData->TotalTime = 0; + CpuMpData->ExpectedTime = CalculateTimeout ( + TimeLimit, + &CpuMpData->CurrentTime + ); + while (CpuMpData->FinishedCount < FinishedApLimit && + !CheckTimeout ( + &CpuMpData->CurrentTime, + &CpuMpData->TotalTime, + CpuMpData->ExpectedTime + )) { + CpuPause (); + } + + if (CpuMpData->FinishedCount >= FinishedApLimit) { + DEBUG (( + DEBUG_VERBOSE, + "%a: reached FinishedApLimit=%u in %Lu microseconds\n", + __FUNCTION__, + FinishedApLimit, + DivU64x64Remainder ( + MultU64x32 (CpuMpData->TotalTime, 1000000), + GetPerformanceCounterProperties (NULL, NULL), + NULL + ) + )); + } +} + +/** Reset an AP to Idle state. Any task being executed by the AP will be aborted and the AP -- 2.9.2 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel