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

Reply via email to