Add a new sleeping state for APs, when no procedure execution,
put AP to sleep. when need to execute procedure, only need to
wake up this AP by sent SIPI.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Chen Fan <chen.fan.f...@cn.fujitsu.com>
---
 UefiCpuPkg/CpuDxe/CpuMp.c | 61 +++++++++++++++++++++++++++++++++++++++++++----
 UefiCpuPkg/CpuDxe/CpuMp.h |  3 ++-
 2 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c
index 25c9091..0d6c4ec 100644
--- a/UefiCpuPkg/CpuDxe/CpuMp.c
+++ b/UefiCpuPkg/CpuDxe/CpuMp.c
@@ -298,6 +298,13 @@ CheckAndUpdateAllAPsToIdleState (
           SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],
                           mMpSystemData.Procedure,
                           mMpSystemData.ProcedureArgument);
+          //
+          // If this AP previous state is blocked, we should
+          // wake up this AP by sent a SIPI. and avoid
+          // re-involve the sleeping state. we must call
+          // SetApProcedure() first.
+          //
+          ResetProcessorToIdleState (&mMpSystemData.CpuDatas[NextNumber]);
         }
       }
 
@@ -343,7 +350,8 @@ ResetAllFailedAPs (
     }
 
     CpuState = GetApState (CpuData);
-    if (CpuState != CpuStateIdle) {
+    if (CpuState != CpuStateIdle &&
+        CpuState != CpuStateSleeping) {
       if (mMpSystemData.FailedList != NULL) {
         (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;
       }
@@ -615,6 +623,7 @@ StartupAllAPs (
   CPU_DATA_BLOCK        *CpuData;
   UINTN                 Number;
   CPU_STATE             APInitialState;
+  CPU_STATE             CpuState;
 
   CpuData = NULL;
 
@@ -655,7 +664,9 @@ StartupAllAPs (
       continue;
     }
 
-    if (GetApState (CpuData) != CpuStateIdle) {
+    CpuState = GetApState (CpuData);
+    if (CpuState != CpuStateIdle &&
+        CpuState != CpuStateSleeping) {
       return EFI_NOT_READY;
     }
   }
@@ -694,13 +705,24 @@ StartupAllAPs (
     // state 1 by 1, until the previous 1 finished its task
     // if not "SingleThread", all APs are put to ready state from the beginning
     //
-    if (GetApState (CpuData) == CpuStateIdle) {
+    CpuState = GetApState (CpuData);
+    if (CpuState == CpuStateIdle ||
+        CpuState == CpuStateSleeping) {
       mMpSystemData.StartCount++;
 
       SetApState (CpuData, APInitialState);
 
       if (APInitialState == CpuStateReady) {
         SetApProcedure (CpuData, Procedure, ProcedureArgument);
+        //
+        // If this AP previous state is Sleeping, we should
+        // wake up this AP by sent a SIPI. and avoid
+        // re-involve the sleeping state. we must call
+        // SetApProcedure() first.
+        //
+        if (CpuState == CpuStateSleeping) {
+          ResetProcessorToIdleState (CpuData);
+        }
       }
 
       if (SingleThread) {
@@ -847,6 +869,7 @@ StartupThisAP (
   )
 {
   CPU_DATA_BLOCK        *CpuData;
+  CPU_STATE             CpuState;
 
   CpuData = NULL;
 
@@ -877,13 +900,24 @@ StartupThisAP (
     return EFI_INVALID_PARAMETER;
   }
 
-  if (GetApState (CpuData) != CpuStateIdle) {
+  CpuState = GetApState (CpuData);
+  if (CpuState != CpuStateIdle &&
+      CpuState != CpuStateSleeping) {
     return EFI_NOT_READY;
   }
 
   SetApState (CpuData, CpuStateReady);
 
   SetApProcedure (CpuData, Procedure, ProcedureArgument);
+  //
+  // If this AP previous state is Sleeping, we should
+  // wake up this AP by sent a SIPI. and avoid
+  // re-involve the sleeping state. we must call
+  // SetApProcedure() first.
+  //
+  if (CpuState == CpuStateSleeping) {
+    ResetProcessorToIdleState (CpuData);
+  }
 
   CpuData->Timeout = TimeoutInMicroseconds;
   CpuData->WaitEvent = WaitEvent;
@@ -1021,6 +1055,7 @@ EnableDisableAP (
 {
   CPU_DATA_BLOCK *CpuData;
   BOOLEAN        TempStopCheckState;
+  CPU_STATE      CpuState;
 
   CpuData = NULL;
   TempStopCheckState = FALSE;
@@ -1046,7 +1081,9 @@ EnableDisableAP (
     return EFI_INVALID_PARAMETER;
   }
 
-  if (GetApState (CpuData) != CpuStateIdle) {
+  CpuState = GetApState (CpuData);
+  if (CpuState != CpuStateIdle &&
+      CpuState != CpuStateSleeping) {
     return EFI_UNSUPPORTED;
   }
 
@@ -1201,6 +1238,20 @@ ProcessorToIdleState (
       CpuData->Procedure = NULL;
       CpuData->State = CpuStateFinished;
       ReleaseMpSpinLock (CpuData);
+    } else {
+      //
+      // if no procedure to execution, we simply put AP
+      // into sleeping state, and waiting BSP sent SIPI.
+      //
+      GetMpSpinLock (CpuData);
+      if (CpuData->State == CpuStateIdle) {
+          CpuData->State = CpuStateSleeping;
+      }
+      ReleaseMpSpinLock (CpuData);
+    }
+
+    if (GetApState (CpuData) == CpuStateSleeping) {
+      CpuSleep ();
     }
 
     CpuPause ();
diff --git a/UefiCpuPkg/CpuDxe/CpuMp.h b/UefiCpuPkg/CpuDxe/CpuMp.h
index a6478c0..cb3460f 100644
--- a/UefiCpuPkg/CpuDxe/CpuMp.h
+++ b/UefiCpuPkg/CpuDxe/CpuMp.h
@@ -80,7 +80,8 @@ typedef enum {
   CpuStateBlocked,
   CpuStateReady,
   CpuStateBusy,
-  CpuStateFinished
+  CpuStateFinished,
+  CpuStateSleeping
 } CPU_STATE;
 
 /**
-- 
1.9.3


------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the 
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to