From patchwork Mon Nov 28 13:08:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 84395 Delivered-To: patch@linaro.org Received: by 10.140.20.101 with SMTP id 92csp1125283qgi; Mon, 28 Nov 2016 05:08:49 -0800 (PST) X-Received: by 10.84.202.163 with SMTP id x32mr49506174pld.44.1480338529330; Mon, 28 Nov 2016 05:08:49 -0800 (PST) Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id o20si55089853pgn.236.2016.11.28.05.08.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 28 Nov 2016 05:08:49 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 0D99181DC7; Mon, 28 Nov 2016 05:08:49 -0800 (PST) X-Original-To: edk2-devel@ml01.01.org Delivered-To: edk2-devel@ml01.01.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 05BFC81DC7 for ; Mon, 28 Nov 2016 05:08:47 -0800 (PST) Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6E11081F01; Mon, 28 Nov 2016 13:08:46 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-107.phx2.redhat.com [10.3.116.107]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uASD8gEs005458; Mon, 28 Nov 2016 08:08:44 -0500 From: Laszlo Ersek To: edk2-devel-01 Date: Mon, 28 Nov 2016 14:08:38 +0100 Message-Id: <20161128130839.9160-2-lersek@redhat.com> In-Reply-To: <20161128130839.9160-1-lersek@redhat.com> References: <20161128130839.9160-1-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Mon, 28 Nov 2016 13:08:46 +0000 (UTC) Subject: [edk2] [PATCH v3 1/2] UefiCpuPkg/MpInitLib: wait no longer than necessary for initial AP startup 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: , Cc: Michael Kinney , Jeff Fan , Jordan Justen MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" 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 Cc: Jeff Fan Cc: Jordan Justen Cc: Michael Kinney Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=116 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- Notes: v3: - preserve original behavior for PcdCpuApInitTimeOutInMicroSeconds==0 [Jeff] UefiCpuPkg/Library/MpInitLib/MpLib.c | 73 +++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) -- 2.9.2 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel 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