public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH 0/5] UefiCpuPkg/MpInitLib: Add support for multiple MP_HAND_OFF HOBs
@ 2024-02-15  9:31 Gerd Hoffmann
  2024-02-15  9:31 ` [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob() Gerd Hoffmann
                   ` (4 more replies)
  0 siblings, 5 replies; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-15  9:31 UTC (permalink / raw)
  To: devel; +Cc: Oliver Steffen, Ray Ni, Laszlo Ersek, Rahul Kumar, Gerd Hoffmann

Needed to boot guests with thousands of vcpus.

Gerd Hoffmann (5):
  UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob()
  UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber()
  UefiCpuPkg/MpInitLib: Add support for multiple HOBs to
    SwitchApContext()
  UefiCpuPkg/MpInitLib: Add support for multiple HOBs to
    MpInitLibInitialize
  UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData()

 UefiCpuPkg/Library/MpInitLib/MpLib.h    |  14 ++-
 UefiCpuPkg/Library/MpInitLib/MpLib.c    | 133 ++++++++++++++++--------
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c |  48 +++++----
 3 files changed, 127 insertions(+), 68 deletions(-)

-- 
2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115497): https://edk2.groups.io/g/devel/message/115497
Mute This Topic: https://groups.io/mt/104369842/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob()
  2024-02-15  9:31 [edk2-devel] [PATCH 0/5] UefiCpuPkg/MpInitLib: Add support for multiple MP_HAND_OFF HOBs Gerd Hoffmann
@ 2024-02-15  9:31 ` Gerd Hoffmann
  2024-02-19  2:34   ` Ni, Ray
  2024-02-19 11:18   ` Laszlo Ersek
  2024-02-15  9:31 ` [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber() Gerd Hoffmann
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-15  9:31 UTC (permalink / raw)
  To: devel; +Cc: Oliver Steffen, Ray Ni, Laszlo Ersek, Rahul Kumar, Gerd Hoffmann

This allows to specify which HOB should be returned in case multiple
MP_HAND_OFF HOBs are present in the system.

Also add the function prototype to the MpLib.h header file.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.h | 12 ++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c | 20 +++++++++++++-------
 2 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index a96a6389c17d..7e409cceaddf 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -485,6 +485,18 @@ SwitchApContext (
   IN MP_HAND_OFF  *MpHandOff
   );
 
+/**
+  Get pointer to MP_HAND_OFF GUIDed HOB, starting with ProcessorIndex
+
+  @param[in] ProcessorIndex.
+
+  @return  The pointer to MP_HAND_OFF structure.
+**/
+MP_HAND_OFF *
+GetMpHandOffHob (
+  IN UINT32  ProcessorIndex
+  );
+
 /**
   Get available EfiBootServicesCode memory below 4GB by specified size.
 
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index cdfb570e61a0..e0a2366073a7 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1961,25 +1961,31 @@ SwitchApContext (
 }
 
 /**
-  Get pointer to MP_HAND_OFF GUIDed HOB.
+  Get pointer to MP_HAND_OFF GUIDed HOB, starting with ProcessorIndex
+
+  @param[in] ProcessorIndex.
 
   @return  The pointer to MP_HAND_OFF structure.
 **/
 MP_HAND_OFF *
 GetMpHandOffHob (
-  VOID
+  IN UINT32  ProcessorIndex
   )
 {
   EFI_HOB_GUID_TYPE  *GuidHob;
   MP_HAND_OFF        *MpHandOff;
 
-  MpHandOff = NULL;
-  GuidHob   = GetFirstGuidHob (&mMpHandOffGuid);
-  if (GuidHob != NULL) {
+  for (GuidHob = GetFirstGuidHob (&mMpHandOffGuid);
+       GuidHob != NULL;
+       GuidHob = GetNextGuidHob (&mMpHandOffGuid, GET_NEXT_HOB (GuidHob)))
+  {
     MpHandOff = (MP_HAND_OFF *)GET_GUID_HOB_DATA (GuidHob);
+    if (MpHandOff->ProcessorIndex == ProcessorIndex) {
+      return MpHandOff;
+    }
   }
 
-  return MpHandOff;
+  return NULL;
 }
 
 /**
@@ -2020,7 +2026,7 @@ MpInitLibInitialize (
   UINTN                    BackupBufferAddr;
   UINTN                    ApIdtBase;
 
-  MpHandOff = GetMpHandOffHob ();
+  MpHandOff = GetMpHandOffHob (0);
   if (MpHandOff == NULL) {
     MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
   } else {
-- 
2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115496): https://edk2.groups.io/g/devel/message/115496
Mute This Topic: https://groups.io/mt/104369841/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber()
  2024-02-15  9:31 [edk2-devel] [PATCH 0/5] UefiCpuPkg/MpInitLib: Add support for multiple MP_HAND_OFF HOBs Gerd Hoffmann
  2024-02-15  9:31 ` [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob() Gerd Hoffmann
@ 2024-02-15  9:31 ` Gerd Hoffmann
  2024-02-19  2:41   ` Ni, Ray
  2024-02-19 11:18   ` Laszlo Ersek
  2024-02-15  9:31 ` [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext() Gerd Hoffmann
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-15  9:31 UTC (permalink / raw)
  To: devel; +Cc: Oliver Steffen, Ray Ni, Laszlo Ersek, Rahul Kumar, Gerd Hoffmann

Remove the MpHandOff parameter.  This is not useful in case multiple
HOBs are present in the system.  The function will use GetMpHandOffHob()
to loop over all HOBs instead.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index e0a2366073a7..8e6cf50ed171 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1894,26 +1894,32 @@ CheckAllAPs (
 /**
   This function Get BspNumber.
 
-  @param[in] MpHandOff        Pointer to MpHandOff
   @return                     BspNumber
 **/
 UINT32
 GetBspNumber (
-  IN CONST MP_HAND_OFF  *MpHandOff
+  VOID
   )
 {
-  UINT32  ApicId;
-  UINT32  BspNumber;
-  UINT32  Index;
+  UINT32       ApicId;
+  UINT32       BspNumber;
+  UINT32       Index;
+  MP_HAND_OFF  *MpHandOff;
 
   //
   // Get the processor number for the BSP
   //
   BspNumber = MAX_UINT32;
   ApicId    = GetInitialApicId ();
-  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
-    if (MpHandOff->Info[Index].ApicId == ApicId) {
-      BspNumber = Index;
+
+  for (MpHandOff = GetMpHandOffHob (0);
+       MpHandOff != NULL;
+       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
+  {
+    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
+      if (MpHandOff->Info[Index].ApicId == ApicId) {
+        BspNumber = MpHandOff->ProcessorIndex + Index;
+      }
     }
   }
 
@@ -1941,7 +1947,7 @@ SwitchApContext (
   UINTN   Index;
   UINT32  BspNumber;
 
-  BspNumber = GetBspNumber (MpHandOff);
+  BspNumber = GetBspNumber ();
 
   for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
     if (Index != BspNumber) {
@@ -2191,7 +2197,7 @@ MpInitLibInitialize (
     }
 
     CpuMpData->CpuCount  = MpHandOff->CpuCount;
-    CpuMpData->BspNumber = GetBspNumber (MpHandOff);
+    CpuMpData->BspNumber = GetBspNumber ();
     CpuInfoInHob         = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
     for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
       InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
-- 
2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115499): https://edk2.groups.io/g/devel/message/115499
Mute This Topic: https://groups.io/mt/104369845/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext()
  2024-02-15  9:31 [edk2-devel] [PATCH 0/5] UefiCpuPkg/MpInitLib: Add support for multiple MP_HAND_OFF HOBs Gerd Hoffmann
  2024-02-15  9:31 ` [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob() Gerd Hoffmann
  2024-02-15  9:31 ` [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber() Gerd Hoffmann
@ 2024-02-15  9:31 ` Gerd Hoffmann
  2024-02-19  2:43   ` Ni, Ray
  2024-02-19 11:25   ` Laszlo Ersek
  2024-02-15  9:31 ` [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize Gerd Hoffmann
  2024-02-15  9:31 ` [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData() Gerd Hoffmann
  4 siblings, 2 replies; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-15  9:31 UTC (permalink / raw)
  To: devel; +Cc: Oliver Steffen, Ray Ni, Laszlo Ersek, Rahul Kumar, Gerd Hoffmann

Remove the MpHandOff parameter.  This is not useful in case multiple
HOBs are present in the system.  The function will use GetMpHandOffHob()
to loop over all HOBs instead.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.h |  2 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.c | 35 +++++++++++++++++-----------
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 7e409cceaddf..a141a95b45ea 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -482,7 +482,7 @@ GetWakeupBuffer (
 **/
 VOID
 SwitchApContext (
-  IN MP_HAND_OFF  *MpHandOff
+  VOID
   );
 
 /**
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 8e6cf50ed171..35f47d3b1289 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1936,32 +1936,41 @@ GetBspNumber (
   begin running the procedure called SwitchContextPerAp.
   This procedure allows the AP to switch to another section of
   memory and continue its loop there.
-
-  @param[in] MpHandOff  Pointer to MP hand-off data structure.
 **/
 VOID
 SwitchApContext (
-  IN MP_HAND_OFF  *MpHandOff
+  VOID
   )
 {
-  UINTN   Index;
-  UINT32  BspNumber;
+  UINTN        Index;
+  UINT32       BspNumber;
+  MP_HAND_OFF  *MpHandOff;
 
   BspNumber = GetBspNumber ();
 
-  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
-    if (Index != BspNumber) {
-      *(UINTN *)(UINTN)MpHandOff->Info[Index].StartupProcedureAddress = (UINTN)SwitchContextPerAp;
-      *(UINT32 *)(UINTN)MpHandOff->Info[Index].StartupSignalAddress   = MpHandOff->StartupSignalValue;
+  for (MpHandOff = GetMpHandOffHob (0);
+       MpHandOff != NULL;
+       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
+  {
+    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
+      if (MpHandOff->ProcessorIndex + Index != BspNumber) {
+        *(UINTN *)(UINTN)MpHandOff->Info[Index].StartupProcedureAddress = (UINTN)SwitchContextPerAp;
+        *(UINT32 *)(UINTN)MpHandOff->Info[Index].StartupSignalAddress   = MpHandOff->StartupSignalValue;
+      }
     }
   }
 
   //
   // Wait all APs waken up if this is not the 1st broadcast of SIPI
   //
-  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
-    if (Index != BspNumber) {
-      WaitApWakeup ((UINT32 *)(UINTN)(MpHandOff->Info[Index].StartupSignalAddress));
+  for (MpHandOff = GetMpHandOffHob (0);
+       MpHandOff != NULL;
+       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
+  {
+    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
+      if (MpHandOff->ProcessorIndex + Index != BspNumber) {
+        WaitApWakeup ((UINT32 *)(UINTN)(MpHandOff->Info[Index].StartupSignalAddress));
+      }
     }
   }
 }
@@ -2226,7 +2235,7 @@ MpInitLibInitialize (
       // enables the APs to switch to a different memory section and continue their
       // looping process there.
       //
-      SwitchApContext (MpHandOff);
+      SwitchApContext ();
       //
       // Wait for all APs finished initialization
       //
-- 
2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115500): https://edk2.groups.io/g/devel/message/115500
Mute This Topic: https://groups.io/mt/104369847/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize
  2024-02-15  9:31 [edk2-devel] [PATCH 0/5] UefiCpuPkg/MpInitLib: Add support for multiple MP_HAND_OFF HOBs Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2024-02-15  9:31 ` [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext() Gerd Hoffmann
@ 2024-02-15  9:31 ` Gerd Hoffmann
  2024-02-19  2:57   ` Ni, Ray
  2024-02-19 11:56   ` Laszlo Ersek
  2024-02-15  9:31 ` [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData() Gerd Hoffmann
  4 siblings, 2 replies; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-15  9:31 UTC (permalink / raw)
  To: devel; +Cc: Oliver Steffen, Ray Ni, Laszlo Ersek, Rahul Kumar, Gerd Hoffmann

Loop over all MP_HAND_OFF HOBs instead of expecting a single HOB
covering all CPUs in the system.

Add a new HaveMpHandOff variable to track whenever MP_HAND_OFF HOBs are
present, using the MpHandOff pointer for that does not work because the
variable will be NULL after looping over all HOBs.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.c | 54 +++++++++++++++++++---------
 1 file changed, 37 insertions(+), 17 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 35f47d3b1289..1547b7e74a1a 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -2023,6 +2023,7 @@ MpInitLibInitialize (
   )
 {
   MP_HAND_OFF              *MpHandOff;
+  BOOLEAN                  HaveMpHandOff;
   CPU_INFO_IN_HOB          *CpuInfoInHob;
   UINT32                   MaxLogicalProcessorNumber;
   UINT32                   ApStackSize;
@@ -2035,17 +2036,29 @@ MpInitLibInitialize (
   CPU_MP_DATA              *CpuMpData;
   UINT8                    ApLoopMode;
   UINT8                    *MonitorBuffer;
-  UINTN                    Index;
+  UINTN                    Index, HobIndex;
   UINTN                    ApResetVectorSizeBelow1Mb;
   UINTN                    ApResetVectorSizeAbove1Mb;
   UINTN                    BackupBufferAddr;
   UINTN                    ApIdtBase;
 
-  MpHandOff = GetMpHandOffHob (0);
-  if (MpHandOff == NULL) {
+  MaxLogicalProcessorNumber = 0;
+  HaveMpHandOff             = FALSE;
+
+  while ((MpHandOff = GetMpHandOffHob (MaxLogicalProcessorNumber)) != 0) {
+    DEBUG ((
+      DEBUG_INFO,
+      "%a: ProcessorIndex=%u CpuCount=%u\n",
+      __func__,
+      MpHandOff->ProcessorIndex,
+      MpHandOff->CpuCount
+      ));
+    MaxLogicalProcessorNumber += MpHandOff->CpuCount;
+    HaveMpHandOff              = TRUE;
+  }
+
+  if (!HaveMpHandOff) {
     MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
-  } else {
-    MaxLogicalProcessorNumber = MpHandOff->CpuCount;
   }
 
   ASSERT (MaxLogicalProcessorNumber != 0);
@@ -2189,7 +2202,7 @@ MpInitLibInitialize (
   //
   ProgramVirtualWireMode ();
 
-  if (MpHandOff == NULL) {
+  if (!HaveMpHandOff) {
     if (MaxLogicalProcessorNumber > 1) {
       //
       // Wakeup all APs and calculate the processor count in system
@@ -2205,19 +2218,26 @@ MpInitLibInitialize (
       AmdSevUpdateCpuMpData (CpuMpData);
     }
 
-    CpuMpData->CpuCount  = MpHandOff->CpuCount;
+    CpuMpData->CpuCount  = MaxLogicalProcessorNumber;
     CpuMpData->BspNumber = GetBspNumber ();
     CpuInfoInHob         = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
-    for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
-      InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
-      CpuMpData->CpuData[Index].CpuHealthy = (MpHandOff->Info[Index].Health == 0) ? TRUE : FALSE;
-      CpuMpData->CpuData[Index].ApFunction = 0;
-      CpuInfoInHob[Index].InitialApicId    = MpHandOff->Info[Index].ApicId;
-      CpuInfoInHob[Index].ApTopOfStack     = CpuMpData->Buffer + (Index + 1) * CpuMpData->CpuApStackSize;
-      CpuInfoInHob[Index].ApicId           = MpHandOff->Info[Index].ApicId;
-      CpuInfoInHob[Index].Health           = MpHandOff->Info[Index].Health;
+    for (MpHandOff = GetMpHandOffHob (0);
+         MpHandOff != NULL;
+         MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
+    {
+      for (HobIndex = 0; HobIndex < MpHandOff->CpuCount; HobIndex++) {
+        Index = MpHandOff->ProcessorIndex + HobIndex;
+        InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
+        CpuMpData->CpuData[Index].CpuHealthy = (MpHandOff->Info[HobIndex].Health == 0) ? TRUE : FALSE;
+        CpuMpData->CpuData[Index].ApFunction = 0;
+        CpuInfoInHob[Index].InitialApicId    = MpHandOff->Info[HobIndex].ApicId;
+        CpuInfoInHob[Index].ApTopOfStack     = CpuMpData->Buffer + (Index + 1) * CpuMpData->CpuApStackSize;
+        CpuInfoInHob[Index].ApicId           = MpHandOff->Info[HobIndex].ApicId;
+        CpuInfoInHob[Index].Health           = MpHandOff->Info[HobIndex].Health;
+      }
     }
 
+    MpHandOff = GetMpHandOffHob (0);
     DEBUG ((DEBUG_INFO, "MpHandOff->WaitLoopExecutionMode: %04d, sizeof (VOID *): %04d\n", MpHandOff->WaitLoopExecutionMode, sizeof (VOID *)));
     if (MpHandOff->WaitLoopExecutionMode == sizeof (VOID *)) {
       ASSERT (CpuMpData->ApLoopMode != ApInHltLoop);
@@ -2284,7 +2304,7 @@ MpInitLibInitialize (
   // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
   //
   if (CpuMpData->CpuCount > 1) {
-    if (MpHandOff != NULL) {
+    if (HaveMpHandOff) {
       //
       // Only needs to use this flag for DXE phase to update the wake up
       // buffer. Wakeup buffer allocated in PEI phase is no longer valid
@@ -2301,7 +2321,7 @@ MpInitLibInitialize (
       CpuPause ();
     }
 
-    if (MpHandOff != NULL) {
+    if (HaveMpHandOff) {
       CpuMpData->InitFlag = ApInitDone;
     }
 
-- 
2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115498): https://edk2.groups.io/g/devel/message/115498
Mute This Topic: https://groups.io/mt/104369843/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData()
  2024-02-15  9:31 [edk2-devel] [PATCH 0/5] UefiCpuPkg/MpInitLib: Add support for multiple MP_HAND_OFF HOBs Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2024-02-15  9:31 ` [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize Gerd Hoffmann
@ 2024-02-15  9:31 ` Gerd Hoffmann
  2024-02-19  3:02   ` Ni, Ray
  2024-02-19 12:50   ` Laszlo Ersek
  4 siblings, 2 replies; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-15  9:31 UTC (permalink / raw)
  To: devel; +Cc: Oliver Steffen, Ray Ni, Laszlo Ersek, Rahul Kumar, Gerd Hoffmann

Add support for splitting Hand-Off data into multiple HOBs.  This is
required for VMs with thousands of CPUs.  The actual CPU count per HOB
is much smaller (128) for better test coverage.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 48 ++++++++++++++-----------
 1 file changed, 27 insertions(+), 21 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index f80e00edcff3..a5710789c8c3 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -126,35 +126,41 @@ SaveCpuMpData (
   IN CPU_MP_DATA  *CpuMpData
   )
 {
-  UINT64           Data64;
-  UINTN            Index;
-  CPU_INFO_IN_HOB  *CpuInfoInHob;
-  MP_HAND_OFF      *MpHandOff;
-  UINTN            MpHandOffSize;
+  STATIC CONST UINT32  CpusPerHob = 128;
+  UINT64               Data64;
+  UINT32               Index, HobBase;
+  CPU_INFO_IN_HOB      *CpuInfoInHob;
+  MP_HAND_OFF          *MpHandOff;
+  UINTN                MpHandOffSize;
 
   //
   // When APs are in a state that can be waken up by a store operation to a memory address,
   // report the MP_HAND_OFF data for DXE to use.
   //
-  CpuInfoInHob  = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
-  MpHandOffSize = sizeof (MP_HAND_OFF) + sizeof (PROCESSOR_HAND_OFF) * CpuMpData->CpuCount;
-  MpHandOff     = (MP_HAND_OFF *)BuildGuidHob (&mMpHandOffGuid, MpHandOffSize);
-  ASSERT (MpHandOff != NULL);
-  ZeroMem (MpHandOff, MpHandOffSize);
-  MpHandOff->ProcessorIndex = 0;
+  CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
 
-  MpHandOff->CpuCount = CpuMpData->CpuCount;
-  if (CpuMpData->ApLoopMode != ApInHltLoop) {
-    MpHandOff->StartupSignalValue    = MP_HAND_OFF_SIGNAL;
-    MpHandOff->WaitLoopExecutionMode = sizeof (VOID *);
-  }
+  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+    if (Index % CpusPerHob == 0) {
+      MpHandOffSize = sizeof (MP_HAND_OFF) + sizeof (PROCESSOR_HAND_OFF) * CpusPerHob;
+      MpHandOff     = (MP_HAND_OFF *)BuildGuidHob (&mMpHandOffGuid, MpHandOffSize);
+      ASSERT (MpHandOff != NULL);
+      ZeroMem (MpHandOff, MpHandOffSize);
 
-  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
-    MpHandOff->Info[Index].ApicId = CpuInfoInHob[Index].ApicId;
-    MpHandOff->Info[Index].Health = CpuInfoInHob[Index].Health;
+      HobBase                   = Index;
+      MpHandOff->ProcessorIndex = HobBase;
+      MpHandOff->CpuCount       = MIN (CpuMpData->CpuCount - HobBase, CpusPerHob);
+
+      if (CpuMpData->ApLoopMode != ApInHltLoop) {
+        MpHandOff->StartupSignalValue    = MP_HAND_OFF_SIGNAL;
+        MpHandOff->WaitLoopExecutionMode = sizeof (VOID *);
+      }
+    }
+
+    MpHandOff->Info[Index-HobBase].ApicId = CpuInfoInHob[Index].ApicId;
+    MpHandOff->Info[Index-HobBase].Health = CpuInfoInHob[Index].Health;
     if (CpuMpData->ApLoopMode != ApInHltLoop) {
-      MpHandOff->Info[Index].StartupSignalAddress    = (UINT64)(UINTN)CpuMpData->CpuData[Index].StartupApSignal;
-      MpHandOff->Info[Index].StartupProcedureAddress = (UINT64)(UINTN)&CpuMpData->CpuData[Index].ApFunction;
+      MpHandOff->Info[Index-HobBase].StartupSignalAddress    = (UINT64)(UINTN)CpuMpData->CpuData[Index].StartupApSignal;
+      MpHandOff->Info[Index-HobBase].StartupProcedureAddress = (UINT64)(UINTN)&CpuMpData->CpuData[Index].ApFunction;
     }
   }
 
-- 
2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115501): https://edk2.groups.io/g/devel/message/115501
Mute This Topic: https://groups.io/mt/104369848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob() Gerd Hoffmann
@ 2024-02-19  2:34   ` Ni, Ray
  2024-02-19  9:51     ` Gerd Hoffmann
  2024-02-19 11:18   ` Laszlo Ersek
  1 sibling, 1 reply; 21+ messages in thread
From: Ni, Ray @ 2024-02-19  2:34 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Oliver Steffen, Laszlo Ersek, Kumar, Rahul R

>    EFI_HOB_GUID_TYPE  *GuidHob;
>    MP_HAND_OFF        *MpHandOff;
> 
> -  MpHandOff = NULL;
> -  GuidHob   = GetFirstGuidHob (&mMpHandOffGuid);
> -  if (GuidHob != NULL) {
> +  for (GuidHob = GetFirstGuidHob (&mMpHandOffGuid);
> +       GuidHob != NULL;
> +       GuidHob = GetNextGuidHob (&mMpHandOffGuid, GET_NEXT_HOB
> (GuidHob)))
> +  {
>      MpHandOff = (MP_HAND_OFF *)GET_GUID_HOB_DATA (GuidHob);
> +    if (MpHandOff->ProcessorIndex == ProcessorIndex) {
> +      return MpHandOff;
> +    }

Gerd,
The code is doing correctly but I have concerns about the performance impact.

With the prototype GetMpHandOffHob(), callers call it multiple times to enumerate all HOB instances.

But every call is a HOB list enumeration from top of the HOB list which may be slow in a platform
that contains lots of HOB items and the MpHandOff HOB instances happen to be in the very bottom.

How about add another parameter "HobStart" to GetMpHandOffHob()? So that only the first call to
GetMpHandOffHob() is a HOB list enumeration from top, latter calls start from the next HOB of the previous
found MpHandOff HOB instance.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115576): https://edk2.groups.io/g/devel/message/115576
Mute This Topic: https://groups.io/mt/104369841/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber() Gerd Hoffmann
@ 2024-02-19  2:41   ` Ni, Ray
  2024-02-19 11:18   ` Laszlo Ersek
  1 sibling, 0 replies; 21+ messages in thread
From: Ni, Ray @ 2024-02-19  2:41 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Oliver Steffen, Laszlo Ersek, Kumar, Rahul R

Since MpHandOff HOBs are created by the PEI instance of MpInitLib, I am ok that the consumer (DXE instance)
assumes the HOB instances are created in the order of ProcessorIndex.

Please update the patch accordingly with the change of GetMpHandOffHob() I commented to patch #1.

Thanks,
Ray
> -----Original Message-----
> From: Gerd Hoffmann <kraxel@redhat.com>
> Sent: Thursday, February 15, 2024 5:32 PM
> To: devel@edk2.groups.io
> Cc: Oliver Steffen <osteffen@redhat.com>; Ni, Ray <ray.ni@intel.com>; Laszlo
> Ersek <lersek@redhat.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>;
> Gerd Hoffmann <kraxel@redhat.com>
> Subject: [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to
> GetBspNumber()
> 
> Remove the MpHandOff parameter.  This is not useful in case multiple
> HOBs are present in the system.  The function will use GetMpHandOffHob()
> to loop over all HOBs instead.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.c | 26 ++++++++++++++++----------
>  1 file changed, 16 insertions(+), 10 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index e0a2366073a7..8e6cf50ed171 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -1894,26 +1894,32 @@ CheckAllAPs (
>  /**
>    This function Get BspNumber.
> 
> -  @param[in] MpHandOff        Pointer to MpHandOff
>    @return                     BspNumber
>  **/
>  UINT32
>  GetBspNumber (
> -  IN CONST MP_HAND_OFF  *MpHandOff
> +  VOID
>    )
>  {
> -  UINT32  ApicId;
> -  UINT32  BspNumber;
> -  UINT32  Index;
> +  UINT32       ApicId;
> +  UINT32       BspNumber;
> +  UINT32       Index;
> +  MP_HAND_OFF  *MpHandOff;
> 
>    //
>    // Get the processor number for the BSP
>    //
>    BspNumber = MAX_UINT32;
>    ApicId    = GetInitialApicId ();
> -  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> -    if (MpHandOff->Info[Index].ApicId == ApicId) {
> -      BspNumber = Index;
> +
> +  for (MpHandOff = GetMpHandOffHob (0);
> +       MpHandOff != NULL;
> +       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex +
> MpHandOff->CpuCount))
> +  {
> +    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> +      if (MpHandOff->Info[Index].ApicId == ApicId) {
> +        BspNumber = MpHandOff->ProcessorIndex + Index;
> +      }
>      }
>    }
> 
> @@ -1941,7 +1947,7 @@ SwitchApContext (
>    UINTN   Index;
>    UINT32  BspNumber;
> 
> -  BspNumber = GetBspNumber (MpHandOff);
> +  BspNumber = GetBspNumber ();
> 
>    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
>      if (Index != BspNumber) {
> @@ -2191,7 +2197,7 @@ MpInitLibInitialize (
>      }
> 
>      CpuMpData->CpuCount  = MpHandOff->CpuCount;
> -    CpuMpData->BspNumber = GetBspNumber (MpHandOff);
> +    CpuMpData->BspNumber = GetBspNumber ();
>      CpuInfoInHob         = (CPU_INFO_IN_HOB
> *)(UINTN)CpuMpData->CpuInfoInHob;
>      for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
>        InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
> --
> 2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115577): https://edk2.groups.io/g/devel/message/115577
Mute This Topic: https://groups.io/mt/104369845/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext() Gerd Hoffmann
@ 2024-02-19  2:43   ` Ni, Ray
  2024-02-19 11:25   ` Laszlo Ersek
  1 sibling, 0 replies; 21+ messages in thread
From: Ni, Ray @ 2024-02-19  2:43 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Oliver Steffen, Laszlo Ersek, Kumar, Rahul R

SwitchApContext() can cache the first instance of MpHandOffHob so that the second enumeration can avoid searching
for the MpHandOffHob from the top of HOB list.

>  VOID
>  SwitchApContext (
> -  IN MP_HAND_OFF  *MpHandOff
> +  VOID
>    )
>  {
> -  UINTN   Index;
> -  UINT32  BspNumber;
> +  UINTN        Index;
> +  UINT32       BspNumber;
> +  MP_HAND_OFF  *MpHandOff;
> 
>    BspNumber = GetBspNumber ();
> 
> -  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> -    if (Index != BspNumber) {
> -      *(UINTN
> *)(UINTN)MpHandOff->Info[Index].StartupProcedureAddress =
> (UINTN)SwitchContextPerAp;
> -      *(UINT32 *)(UINTN)MpHandOff->Info[Index].StartupSignalAddress
> = MpHandOff->StartupSignalValue;
> +  for (MpHandOff = GetMpHandOffHob (0);
> +       MpHandOff != NULL;
> +       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex +
> MpHandOff->CpuCount))
> +  {
> +    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> +      if (MpHandOff->ProcessorIndex + Index != BspNumber) {
> +        *(UINTN
> *)(UINTN)MpHandOff->Info[Index].StartupProcedureAddress =
> (UINTN)SwitchContextPerAp;
> +        *(UINT32
> *)(UINTN)MpHandOff->Info[Index].StartupSignalAddress   =
> MpHandOff->StartupSignalValue;
> +      }
>      }
>    }
> 
>    //
>    // Wait all APs waken up if this is not the 1st broadcast of SIPI
>    //
> -  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> -    if (Index != BspNumber) {
> -      WaitApWakeup ((UINT32
> *)(UINTN)(MpHandOff->Info[Index].StartupSignalAddress));
> +  for (MpHandOff = GetMpHandOffHob (0);
> +       MpHandOff != NULL;
> +       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex +
> MpHandOff->CpuCount))
> +  {
> +    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> +      if (MpHandOff->ProcessorIndex + Index != BspNumber) {
> +        WaitApWakeup ((UINT32
> *)(UINTN)(MpHandOff->Info[Index].StartupSignalAddress));
> +      }
>      }
>    }
>  }
> @@ -2226,7 +2235,7 @@ MpInitLibInitialize (
>        // enables the APs to switch to a different memory section and
> continue their
>        // looping process there.
>        //
> -      SwitchApContext (MpHandOff);
> +      SwitchApContext ();
>        //
>        // Wait for all APs finished initialization
>        //
> --
> 2.43.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115578): https://edk2.groups.io/g/devel/message/115578
Mute This Topic: https://groups.io/mt/104369847/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize
  2024-02-15  9:31 ` [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize Gerd Hoffmann
@ 2024-02-19  2:57   ` Ni, Ray
  2024-02-19 11:56   ` Laszlo Ersek
  1 sibling, 0 replies; 21+ messages in thread
From: Ni, Ray @ 2024-02-19  2:57 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Oliver Steffen, Laszlo Ersek, Kumar, Rahul R

> -  MpHandOff = GetMpHandOffHob (0);
> -  if (MpHandOff == NULL) {
> +  MaxLogicalProcessorNumber = 0;
> +  HaveMpHandOff             = FALSE;

1. Can we cache the first MpHandOff instance? It can be used as an indicator to replace "HaveMpHandOff",
and also can speed up the HOB enumeration in later logic.

> +
> +  while ((MpHandOff = GetMpHandOffHob
> (MaxLogicalProcessorNumber)) != 0) {

2. Can you use "!= NULL" instead of "!= 0"?

> +    DEBUG ((
> +      DEBUG_INFO,
> +      "%a: ProcessorIndex=%u CpuCount=%u\n",
> +      __func__,
> +      MpHandOff->ProcessorIndex,
> +      MpHandOff->CpuCount
> +      ));


3. can you add an assertion "ASSERT (MaxLogicalProcessorNumber == MpHandOff->ProcessorIndex);"?
It's to ensure no gap or overlap.

> +    MaxLogicalProcessorNumber += MpHandOff->CpuCount;
> +    HaveMpHandOff              = TRUE;
> +  }
> +
> +  if (!HaveMpHandOff) {
4. "HaveMpHandOff == TRUE"  --> "FirstMpHandOff != NULL"

> +      for (HobIndex = 0; HobIndex < MpHandOff->CpuCount; HobIndex++)

5. How about "ProcessorIndexInHob"? "HobIndex" is a bit confusing.
> 
> +    MpHandOff = GetMpHandOffHob (0);
6. All the GetMpHandOffHob(0) can be replaced with "FirstMpHandOff".


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115579): https://edk2.groups.io/g/devel/message/115579
Mute This Topic: https://groups.io/mt/104369843/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData() Gerd Hoffmann
@ 2024-02-19  3:02   ` Ni, Ray
  2024-02-19 12:50   ` Laszlo Ersek
  1 sibling, 0 replies; 21+ messages in thread
From: Ni, Ray @ 2024-02-19  3:02 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Oliver Steffen, Laszlo Ersek, Kumar, Rahul R

> +  STATIC CONST UINT32  CpusPerHob = 128;

1. Can you refer to https://github.com/tianocore/edk2/blob/9979c887ef54023c9e262242db02c92d11b7f1e5/UefiCpuPkg/CpuMpPei/CpuMpPei.c#L572 to avoid
hardcode 128?
The MP_HAND_OFF structure change may cause 128 an invalid value.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115580): https://edk2.groups.io/g/devel/message/115580
Mute This Topic: https://groups.io/mt/104369848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob()
  2024-02-19  2:34   ` Ni, Ray
@ 2024-02-19  9:51     ` Gerd Hoffmann
  2024-02-20  3:42       ` Ni, Ray
  0 siblings, 1 reply; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-19  9:51 UTC (permalink / raw)
  To: Ni, Ray; +Cc: devel@edk2.groups.io, Oliver Steffen, Laszlo Ersek,
	Kumar, Rahul R

On Mon, Feb 19, 2024 at 02:34:42AM +0000, Ni, Ray wrote:
> > +  for (GuidHob = GetFirstGuidHob (&mMpHandOffGuid);
> > +       GuidHob != NULL;
> > +       GuidHob = GetNextGuidHob (&mMpHandOffGuid, GET_NEXT_HOB
> > (GuidHob)))
> > +  {
> >      MpHandOff = (MP_HAND_OFF *)GET_GUID_HOB_DATA (GuidHob);
> > +    if (MpHandOff->ProcessorIndex == ProcessorIndex) {
> > +      return MpHandOff;
> > +    }
> 
> Gerd,
> The code is doing correctly but I have concerns about the performance impact.
> 
> With the prototype GetMpHandOffHob(), callers call it multiple times to enumerate all HOB instances.
> 
> But every call is a HOB list enumeration from top of the HOB list which may be slow in a platform
> that contains lots of HOB items and the MpHandOff HOB instances happen to be in the very bottom.
> 
> How about add another parameter "HobStart" to GetMpHandOffHob()? So that only the first call to
> GetMpHandOffHob() is a HOB list enumeration from top, latter calls start from the next HOB of the previous
> found MpHandOff HOB instance.

That will only work if the HOBs are returned in ProcessorIndex order.

That happens to be the case in my testing; the HOBs are returned in the
same order they are created by patch #5 of this series.

Is that behavior guaranteed?  MdePkg/Include/Library/HobLib.h doesn't
say anything about the ordering.

take care,
  Gerd



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115588): https://edk2.groups.io/g/devel/message/115588
Mute This Topic: https://groups.io/mt/104369841/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber() Gerd Hoffmann
  2024-02-19  2:41   ` Ni, Ray
@ 2024-02-19 11:18   ` Laszlo Ersek
  2024-02-19 11:37     ` Gerd Hoffmann
  1 sibling, 1 reply; 21+ messages in thread
From: Laszlo Ersek @ 2024-02-19 11:18 UTC (permalink / raw)
  To: devel, kraxel; +Cc: Oliver Steffen, Ray Ni, Rahul Kumar

On 2/15/24 10:31, Gerd Hoffmann wrote:
> Remove the MpHandOff parameter.  This is not useful in case multiple
> HOBs are present in the system.  The function will use GetMpHandOffHob()
> to loop over all HOBs instead.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.c | 26 ++++++++++++++++----------
>  1 file changed, 16 insertions(+), 10 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index e0a2366073a7..8e6cf50ed171 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -1894,26 +1894,32 @@ CheckAllAPs (
>  /**
>    This function Get BspNumber.
>  
> -  @param[in] MpHandOff        Pointer to MpHandOff
>    @return                     BspNumber
>  **/
>  UINT32
>  GetBspNumber (
> -  IN CONST MP_HAND_OFF  *MpHandOff
> +  VOID
>    )
>  {
> -  UINT32  ApicId;
> -  UINT32  BspNumber;
> -  UINT32  Index;
> +  UINT32       ApicId;
> +  UINT32       BspNumber;
> +  UINT32       Index;
> +  MP_HAND_OFF  *MpHandOff;
>  
>    //
>    // Get the processor number for the BSP
>    //
>    BspNumber = MAX_UINT32;
>    ApicId    = GetInitialApicId ();
> -  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> -    if (MpHandOff->Info[Index].ApicId == ApicId) {
> -      BspNumber = Index;
> +
> +  for (MpHandOff = GetMpHandOffHob (0);
> +       MpHandOff != NULL;
> +       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
> +  {
> +    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> +      if (MpHandOff->Info[Index].ApicId == ApicId) {
> +        BspNumber = MpHandOff->ProcessorIndex + Index;
> +      }
>      }
>    }
>  

(I'm missing the larger picture here -- is this related to the problem
-- too many CPUs to fit their infos into a single HOB -- that Pawel
worked on for a while?

"UefiCpuPkg/Library/MpInitLib/MpHandOff.h" was created in commit
8bb018afaf2a ("UefiCpuPkg: Create MpHandOff.", 2023-07-11); I don't have
memories from that time frame. Either way, I do have a question /
observation here:)

The outer loop is suboptimal, IMO, to just open-coding another HOB scan
-- this approach looks quadratic, even though it could be linear. More
or less, as proposed, we call GetMpHandOffHob() for each MP_HAND_OFF
HOB, which will scan n/2 HOBs on average. (Even if the GUID HOB list is
sorted by ProcessorIndex, we'll scan 1 + 2 + 3 +... HOBs.) But if we
open-coded GetFirstGuidHob() and GetNextGuidHob() here, then a single
scan would suffice.

Laszlo

> @@ -1941,7 +1947,7 @@ SwitchApContext (
>    UINTN   Index;
>    UINT32  BspNumber;
>  
> -  BspNumber = GetBspNumber (MpHandOff);
> +  BspNumber = GetBspNumber ();
>  
>    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
>      if (Index != BspNumber) {
> @@ -2191,7 +2197,7 @@ MpInitLibInitialize (
>      }
>  
>      CpuMpData->CpuCount  = MpHandOff->CpuCount;
> -    CpuMpData->BspNumber = GetBspNumber (MpHandOff);
> +    CpuMpData->BspNumber = GetBspNumber ();
>      CpuInfoInHob         = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
>      for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
>        InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115590): https://edk2.groups.io/g/devel/message/115590
Mute This Topic: https://groups.io/mt/104369845/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob() Gerd Hoffmann
  2024-02-19  2:34   ` Ni, Ray
@ 2024-02-19 11:18   ` Laszlo Ersek
  1 sibling, 0 replies; 21+ messages in thread
From: Laszlo Ersek @ 2024-02-19 11:18 UTC (permalink / raw)
  To: devel, kraxel; +Cc: Oliver Steffen, Ray Ni, Rahul Kumar

On 2/15/24 10:31, Gerd Hoffmann wrote:
> This allows to specify which HOB should be returned in case multiple
> MP_HAND_OFF HOBs are present in the system.
> 
> Also add the function prototype to the MpLib.h header file.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.h | 12 ++++++++++++
>  UefiCpuPkg/Library/MpInitLib/MpLib.c | 20 +++++++++++++-------
>  2 files changed, 25 insertions(+), 7 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> index a96a6389c17d..7e409cceaddf 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> @@ -485,6 +485,18 @@ SwitchApContext (
>    IN MP_HAND_OFF  *MpHandOff
>    );
>  
> +/**
> +  Get pointer to MP_HAND_OFF GUIDed HOB, starting with ProcessorIndex
> +
> +  @param[in] ProcessorIndex.
> +
> +  @return  The pointer to MP_HAND_OFF structure.
> +**/
> +MP_HAND_OFF *
> +GetMpHandOffHob (
> +  IN UINT32  ProcessorIndex
> +  );
> +
>  /**
>    Get available EfiBootServicesCode memory below 4GB by specified size.
>  
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index cdfb570e61a0..e0a2366073a7 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -1961,25 +1961,31 @@ SwitchApContext (
>  }
>  
>  /**
> -  Get pointer to MP_HAND_OFF GUIDed HOB.
> +  Get pointer to MP_HAND_OFF GUIDed HOB, starting with ProcessorIndex
> +
> +  @param[in] ProcessorIndex.
>  
>    @return  The pointer to MP_HAND_OFF structure.
>  **/
>  MP_HAND_OFF *
>  GetMpHandOffHob (
> -  VOID
> +  IN UINT32  ProcessorIndex
>    )
>  {
>    EFI_HOB_GUID_TYPE  *GuidHob;
>    MP_HAND_OFF        *MpHandOff;
>  
> -  MpHandOff = NULL;
> -  GuidHob   = GetFirstGuidHob (&mMpHandOffGuid);
> -  if (GuidHob != NULL) {
> +  for (GuidHob = GetFirstGuidHob (&mMpHandOffGuid);
> +       GuidHob != NULL;
> +       GuidHob = GetNextGuidHob (&mMpHandOffGuid, GET_NEXT_HOB (GuidHob)))
> +  {
>      MpHandOff = (MP_HAND_OFF *)GET_GUID_HOB_DATA (GuidHob);
> +    if (MpHandOff->ProcessorIndex == ProcessorIndex) {
> +      return MpHandOff;
> +    }
>    }
>  
> -  return MpHandOff;
> +  return NULL;
>  }
>  
>  /**
> @@ -2020,7 +2026,7 @@ MpInitLibInitialize (
>    UINTN                    BackupBufferAddr;
>    UINTN                    ApIdtBase;
>  
> -  MpHandOff = GetMpHandOffHob ();
> +  MpHandOff = GetMpHandOffHob (0);
>    if (MpHandOff == NULL) {
>      MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
>    } else {

Seems to do what it says on the tin; not sure what it's going to be good
for, though.

Reviewed-by: Laszlo Ersek <lersek@redhat.com>



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115591): https://edk2.groups.io/g/devel/message/115591
Mute This Topic: https://groups.io/mt/104369841/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext() Gerd Hoffmann
  2024-02-19  2:43   ` Ni, Ray
@ 2024-02-19 11:25   ` Laszlo Ersek
  1 sibling, 0 replies; 21+ messages in thread
From: Laszlo Ersek @ 2024-02-19 11:25 UTC (permalink / raw)
  To: devel, kraxel; +Cc: Oliver Steffen, Ray Ni, Rahul Kumar

On 2/15/24 10:31, Gerd Hoffmann wrote:
> Remove the MpHandOff parameter.  This is not useful in case multiple
> HOBs are present in the system.  The function will use GetMpHandOffHob()
> to loop over all HOBs instead.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.h |  2 +-
>  UefiCpuPkg/Library/MpInitLib/MpLib.c | 35 +++++++++++++++++-----------
>  2 files changed, 23 insertions(+), 14 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> index 7e409cceaddf..a141a95b45ea 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> @@ -482,7 +482,7 @@ GetWakeupBuffer (
>  **/
>  VOID
>  SwitchApContext (
> -  IN MP_HAND_OFF  *MpHandOff
> +  VOID
>    );
>  
>  /**
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index 8e6cf50ed171..35f47d3b1289 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -1936,32 +1936,41 @@ GetBspNumber (
>    begin running the procedure called SwitchContextPerAp.
>    This procedure allows the AP to switch to another section of
>    memory and continue its loop there.
> -
> -  @param[in] MpHandOff  Pointer to MP hand-off data structure.
>  **/
>  VOID
>  SwitchApContext (
> -  IN MP_HAND_OFF  *MpHandOff
> +  VOID
>    )
>  {
> -  UINTN   Index;
> -  UINT32  BspNumber;
> +  UINTN        Index;
> +  UINT32       BspNumber;
> +  MP_HAND_OFF  *MpHandOff;
>  
>    BspNumber = GetBspNumber ();
>  
> -  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> -    if (Index != BspNumber) {
> -      *(UINTN *)(UINTN)MpHandOff->Info[Index].StartupProcedureAddress = (UINTN)SwitchContextPerAp;
> -      *(UINT32 *)(UINTN)MpHandOff->Info[Index].StartupSignalAddress   = MpHandOff->StartupSignalValue;
> +  for (MpHandOff = GetMpHandOffHob (0);
> +       MpHandOff != NULL;
> +       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
> +  {
> +    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> +      if (MpHandOff->ProcessorIndex + Index != BspNumber) {
> +        *(UINTN *)(UINTN)MpHandOff->Info[Index].StartupProcedureAddress = (UINTN)SwitchContextPerAp;
> +        *(UINT32 *)(UINTN)MpHandOff->Info[Index].StartupSignalAddress   = MpHandOff->StartupSignalValue;
> +      }
>      }
>    }
>  
>    //
>    // Wait all APs waken up if this is not the 1st broadcast of SIPI
>    //
> -  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> -    if (Index != BspNumber) {
> -      WaitApWakeup ((UINT32 *)(UINTN)(MpHandOff->Info[Index].StartupSignalAddress));
> +  for (MpHandOff = GetMpHandOffHob (0);
> +       MpHandOff != NULL;
> +       MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
> +  {
> +    for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> +      if (MpHandOff->ProcessorIndex + Index != BspNumber) {
> +        WaitApWakeup ((UINT32 *)(UINTN)(MpHandOff->Info[Index].StartupSignalAddress));
> +      }
>      }
>    }
>  }
> @@ -2226,7 +2235,7 @@ MpInitLibInitialize (
>        // enables the APs to switch to a different memory section and continue their
>        // looping process there.
>        //
> -      SwitchApContext (MpHandOff);
> +      SwitchApContext ();
>        //
>        // Wait for all APs finished initialization
>        //

Same comment as under the previous patch. We could just iterate with
MpHandOff over the GUID HOB list in the outer loops, and perform the
proper actions upon

  MpHandOff->ProcessorIndex + Index != BspNumber

in the inner loop.

It is not necessary for us to ask for the HOBs in any particular
sequence, so we shouldn't pay the O(n) lookup price for every HOB in turn.

Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115592): https://edk2.groups.io/g/devel/message/115592
Mute This Topic: https://groups.io/mt/104369847/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber()
  2024-02-19 11:18   ` Laszlo Ersek
@ 2024-02-19 11:37     ` Gerd Hoffmann
  2024-02-19 20:02       ` Laszlo Ersek
  0 siblings, 1 reply; 21+ messages in thread
From: Gerd Hoffmann @ 2024-02-19 11:37 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: devel, Oliver Steffen, Ray Ni, Rahul Kumar

  Hi,

> (I'm missing the larger picture here -- is this related to the problem
> -- too many CPUs to fit their infos into a single HOB -- that Pawel
> worked on for a while?

Different HOB, but similar underlying problem.

At least the HOB structure already has the fields needed to allow
splitting the information into multiple HOBs, even though the current
code doesn't actually do that (which is fixed by this series).

> The outer loop is suboptimal, IMO, to just open-coding another HOB scan
> -- this approach looks quadratic, even though it could be linear. More
> or less, as proposed, we call GetMpHandOffHob() for each MP_HAND_OFF
> HOB, which will scan n/2 HOBs on average. (Even if the GUID HOB list is
> sorted by ProcessorIndex, we'll scan 1 + 2 + 3 +... HOBs.) But if we
> open-coded GetFirstGuidHob() and GetNextGuidHob() here, then a single
> scan would suffice.

Ray raised performance concerns too.

Does HobLib provides any ordering guarantees?  Specifically in case the
HOBs are returned in the same order they are created (which implies they
are sorted by ProcessorIndex because patch #5 creates them in that
order) this can certainly be optimized.

take care,
  Gerd



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115593): https://edk2.groups.io/g/devel/message/115593
Mute This Topic: https://groups.io/mt/104369845/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize
  2024-02-15  9:31 ` [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize Gerd Hoffmann
  2024-02-19  2:57   ` Ni, Ray
@ 2024-02-19 11:56   ` Laszlo Ersek
  1 sibling, 0 replies; 21+ messages in thread
From: Laszlo Ersek @ 2024-02-19 11:56 UTC (permalink / raw)
  To: devel, kraxel; +Cc: Oliver Steffen, Ray Ni, Rahul Kumar

On 2/15/24 10:31, Gerd Hoffmann wrote:
> Loop over all MP_HAND_OFF HOBs instead of expecting a single HOB
> covering all CPUs in the system.
> 
> Add a new HaveMpHandOff variable to track whenever MP_HAND_OFF HOBs are
> present, using the MpHandOff pointer for that does not work because the
> variable will be NULL after looping over all HOBs.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.c | 54 +++++++++++++++++++---------
>  1 file changed, 37 insertions(+), 17 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index 35f47d3b1289..1547b7e74a1a 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -2023,6 +2023,7 @@ MpInitLibInitialize (
>    )
>  {
>    MP_HAND_OFF              *MpHandOff;
> +  BOOLEAN                  HaveMpHandOff;
>    CPU_INFO_IN_HOB          *CpuInfoInHob;
>    UINT32                   MaxLogicalProcessorNumber;
>    UINT32                   ApStackSize;
> @@ -2035,17 +2036,29 @@ MpInitLibInitialize (
>    CPU_MP_DATA              *CpuMpData;
>    UINT8                    ApLoopMode;
>    UINT8                    *MonitorBuffer;
> -  UINTN                    Index;
> +  UINTN                    Index, HobIndex;
>    UINTN                    ApResetVectorSizeBelow1Mb;
>    UINTN                    ApResetVectorSizeAbove1Mb;
>    UINTN                    BackupBufferAddr;
>    UINTN                    ApIdtBase;
>  
> -  MpHandOff = GetMpHandOffHob (0);
> -  if (MpHandOff == NULL) {
> +  MaxLogicalProcessorNumber = 0;
> +  HaveMpHandOff             = FALSE;
> +
> +  while ((MpHandOff = GetMpHandOffHob (MaxLogicalProcessorNumber)) != 0) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "%a: ProcessorIndex=%u CpuCount=%u\n",
> +      __func__,
> +      MpHandOff->ProcessorIndex,
> +      MpHandOff->CpuCount
> +      ));
> +    MaxLogicalProcessorNumber += MpHandOff->CpuCount;
> +    HaveMpHandOff              = TRUE;
> +  }
> +
> +  if (!HaveMpHandOff) {
>      MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
> -  } else {
> -    MaxLogicalProcessorNumber = MpHandOff->CpuCount;
>    }
>  
>    ASSERT (MaxLogicalProcessorNumber != 0);

How about:

- just looping over the GUID HOBs, summing their CpuCount fields,

- replacing the HaveMpHandOff variable with the sum being nonzero, after
the loop

(One extra assertion, on top, could be: while iterating over the GUID
HOB list, also perform a maximum search for (MpHandOff->ProcessorIndex +
MpHandOff->CpuCount), and after the loop, check that the maximum found
like this equals the sum of CpuCount fields. But this is really an extra.)

In other words -- again, I don't see any need for going through the HOBs
in a particular order, just for summing their CpuCount fields.


> @@ -2189,7 +2202,7 @@ MpInitLibInitialize (
>    //
>    ProgramVirtualWireMode ();
>  
> -  if (MpHandOff == NULL) {
> +  if (!HaveMpHandOff) {
>      if (MaxLogicalProcessorNumber > 1) {
>        //
>        // Wakeup all APs and calculate the processor count in system
> @@ -2205,19 +2218,26 @@ MpInitLibInitialize (
>        AmdSevUpdateCpuMpData (CpuMpData);
>      }

Hm, okay, considering this code, I do agree we need the "HaveMpHandOff"
variable. Because, at this point, MaxLogicalProcessorNumber will be
nonzero, regardless of how we calculated it it.

>  
> -    CpuMpData->CpuCount  = MpHandOff->CpuCount;
> +    CpuMpData->CpuCount  = MaxLogicalProcessorNumber;
>      CpuMpData->BspNumber = GetBspNumber ();
>      CpuInfoInHob         = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
> -    for (Index = 0; Index < CpuMpData->CpuCount; Index++) {

This original code here is a bit confused. Namely, after briefly
auditing MpInitLibInitialize(), it seems like "Index" should always have
been UINT32; making it UINTN is a confusing and unneeded generality.
(But, if you disagree with my claim, please say so.)

And the new variable HobIndex should be UINT32 too.

> -      InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
> -      CpuMpData->CpuData[Index].CpuHealthy = (MpHandOff->Info[Index].Health == 0) ? TRUE : FALSE;

Comment on the pre-patch code:

  Predicate ? TRUE : FALSE

is poor style.

> -      CpuMpData->CpuData[Index].ApFunction = 0;
> -      CpuInfoInHob[Index].InitialApicId    = MpHandOff->Info[Index].ApicId;
> -      CpuInfoInHob[Index].ApTopOfStack     = CpuMpData->Buffer + (Index + 1) * CpuMpData->CpuApStackSize;
> -      CpuInfoInHob[Index].ApicId           = MpHandOff->Info[Index].ApicId;
> -      CpuInfoInHob[Index].Health           = MpHandOff->Info[Index].Health;
> +    for (MpHandOff = GetMpHandOffHob (0);
> +         MpHandOff != NULL;
> +         MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + MpHandOff->CpuCount))
> +    {
> +      for (HobIndex = 0; HobIndex < MpHandOff->CpuCount; HobIndex++) {
> +        Index = MpHandOff->ProcessorIndex + HobIndex;
> +        InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
> +        CpuMpData->CpuData[Index].CpuHealthy = (MpHandOff->Info[HobIndex].Health == 0) ? TRUE : FALSE;
> +        CpuMpData->CpuData[Index].ApFunction = 0;
> +        CpuInfoInHob[Index].InitialApicId    = MpHandOff->Info[HobIndex].ApicId;
> +        CpuInfoInHob[Index].ApTopOfStack     = CpuMpData->Buffer + (Index + 1) * CpuMpData->CpuApStackSize;
> +        CpuInfoInHob[Index].ApicId           = MpHandOff->Info[HobIndex].ApicId;
> +        CpuInfoInHob[Index].Health           = MpHandOff->Info[HobIndex].Health;
> +      }
>      }

Same observation as before: we don't need to *dicate* the HOB order for
these nested loops, we can (and should) just process the HOBs in
whatever order they appear. That makes the outer loop linear, rather
than quadratic.

>  
> +    MpHandOff = GetMpHandOffHob (0);
>      DEBUG ((DEBUG_INFO, "MpHandOff->WaitLoopExecutionMode: %04d, sizeof (VOID *): %04d\n", MpHandOff->WaitLoopExecutionMode, sizeof (VOID *)));
>      if (MpHandOff->WaitLoopExecutionMode == sizeof (VOID *)) {
>        ASSERT (CpuMpData->ApLoopMode != ApInHltLoop);

This indicates that a refactoring -- "normalization" -- of the
MP_HAND_OFF structure is necessary.

Namely, each MP_HAND_OFF HOB contains a WaitLoopExecutionMode field, but
their values are expected to be identical. And here you have to use one
of the HOBs (doesn't matter which one) for getting that value.

The WaitLoopExecutionMode field should be a singleton, regardless of how
many MP_HAND_OFF HOBs exist. It could be a separate GUID HOB, or perhaps
(for simplicity?) a dynamic UINT32 PCD.

... In fact, the same seems to apply to the StartupSignalValue field.
That field is only ever set to MP_HAND_OFF_SIGNAL, and that setting only
depends on "CpuMpData->ApLoopMode". Therefore both WaitLoopExecutionMode
and StartupSignalValue are singletons, and should not be duplicated;
they should be "normalized out" to dynamic PCDs or a separate (unique)
GUID HOB.

> @@ -2284,7 +2304,7 @@ MpInitLibInitialize (
>    // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
>    //
>    if (CpuMpData->CpuCount > 1) {
> -    if (MpHandOff != NULL) {
> +    if (HaveMpHandOff) {
>        //
>        // Only needs to use this flag for DXE phase to update the wake up
>        // buffer. Wakeup buffer allocated in PEI phase is no longer valid
> @@ -2301,7 +2321,7 @@ MpInitLibInitialize (
>        CpuPause ();
>      }
>  
> -    if (MpHandOff != NULL) {
> +    if (HaveMpHandOff) {
>        CpuMpData->InitFlag = ApInitDone;
>      }
>  

Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115594): https://edk2.groups.io/g/devel/message/115594
Mute This Topic: https://groups.io/mt/104369843/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData()
  2024-02-15  9:31 ` [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData() Gerd Hoffmann
  2024-02-19  3:02   ` Ni, Ray
@ 2024-02-19 12:50   ` Laszlo Ersek
  2024-02-20  7:35     ` Ni, Ray
  1 sibling, 1 reply; 21+ messages in thread
From: Laszlo Ersek @ 2024-02-19 12:50 UTC (permalink / raw)
  To: devel, kraxel; +Cc: Oliver Steffen, Ray Ni, Rahul Kumar

On 2/15/24 10:31, Gerd Hoffmann wrote:
> Add support for splitting Hand-Off data into multiple HOBs.  This is
> required for VMs with thousands of CPUs.  The actual CPU count per HOB
> is much smaller (128) for better test coverage.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 48 ++++++++++++++-----------
>  1 file changed, 27 insertions(+), 21 deletions(-)
>
> diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
> index f80e00edcff3..a5710789c8c3 100644
> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
> @@ -126,35 +126,41 @@ SaveCpuMpData (
>    IN CPU_MP_DATA  *CpuMpData
>    )
>  {
> -  UINT64           Data64;
> -  UINTN            Index;
> -  CPU_INFO_IN_HOB  *CpuInfoInHob;
> -  MP_HAND_OFF      *MpHandOff;
> -  UINTN            MpHandOffSize;
> +  STATIC CONST UINT32  CpusPerHob = 128;

This should be a fixed-at-build PCD. Easy to modify on the build command
line, for test coverage, but for production builds, it should be as
large as possible.

In fact, the code should determine how many CPU entries fit in a single
HOB [*], and the PCD should be checked against it:

- PCD == 0: use the maximum
- PCD > maximum: assert
- otherwise: use the PCD as chunking factor

[*] See BuildGuidHob() in "MdePkg/Library/PeiHobLib/HobLib.c":

|   //
|   // Make sure that data length is not too long.
|   //
|   ASSERT (DataLength <= (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)));

So the max permitted payload size is 0xFFE0 bytes, if I count right.

  CpusPerHob = (0xFFE0 - sizeof (MP_HAND_OFF)) / sizeof (PROCESSOR_HAND_OFF);


> +  UINT64               Data64;
> +  UINT32               Index, HobBase;
> +  CPU_INFO_IN_HOB      *CpuInfoInHob;
> +  MP_HAND_OFF          *MpHandOff;
> +  UINTN                MpHandOffSize;
>
>    //
>    // When APs are in a state that can be waken up by a store operation to a memory address,
>    // report the MP_HAND_OFF data for DXE to use.
>    //
> -  CpuInfoInHob  = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
> -  MpHandOffSize = sizeof (MP_HAND_OFF) + sizeof (PROCESSOR_HAND_OFF) * CpuMpData->CpuCount;
> -  MpHandOff     = (MP_HAND_OFF *)BuildGuidHob (&mMpHandOffGuid, MpHandOffSize);
> -  ASSERT (MpHandOff != NULL);
> -  ZeroMem (MpHandOff, MpHandOffSize);
> -  MpHandOff->ProcessorIndex = 0;
> +  CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
>
> -  MpHandOff->CpuCount = CpuMpData->CpuCount;
> -  if (CpuMpData->ApLoopMode != ApInHltLoop) {
> -    MpHandOff->StartupSignalValue    = MP_HAND_OFF_SIGNAL;
> -    MpHandOff->WaitLoopExecutionMode = sizeof (VOID *);
> -  }
> +  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
> +    if (Index % CpusPerHob == 0) {
> +      MpHandOffSize = sizeof (MP_HAND_OFF) + sizeof (PROCESSOR_HAND_OFF) * CpusPerHob;

I don't like that the last HOB will only be partially filled in, most of
the time. Especially the max chunking factor -- which strives to create
HOBs that are approximately 64KB in size -- might waste ~32KB on
average, using a flat multiplication like the above.

How about:

  UINT32              FreeInHob;
  PROCESSOR_HAND_OFF  *Info;

  FreeInHob = 0;
  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
    if (FreeInHob == 0) {
      FreeInHob     = MIN (CpusPerHob, CpuMpData->CpuCount - Index);
      MpHandOffSize = sizeof *MpHandOff + FreeInHob * sizeof *Info;
      MpHandOff     = BuildGuidHob (&mMpHandOffGuid, MpHandOffSize);
      ASSERT (MpHandOff != NULL);
      ZeroMem (MpHandOff, MpHandOffSize);
      MpHandOff->ProcessorIndex = Index;
      MpHandOff->CpuCount       = FreeInHob;
      Info                      = MpHandOff->Info;
    }

    Info->ApicId = CpuInfoInHob[Index].ApicId;
    Info->Health = CpuInfoInHob[Index].Health;
    if (CpuMpData->ApLoopMode != ApInHltLoop) {
      Info->StartupSignalAddress    = (UINT64)(UINTN)CpuMpData->CpuData[Index].StartupApSignal;
      Info->StartupProcedureAddress = (UINT64)(UINTN)&CpuMpData->CpuData[Index].ApFunction;
    }

    Info++;
    FreeInHob--;
  }

And then "HobBase" becomes superfluous. (Well, having a HobBase that
carries information between iterations of the loop, versus an Info
pointer, is conceptually the same; it's just that the Info pointer
allows for shorter expressions.)

The UINTN -> UINT32 type change for Index looks fine, however.

> +      MpHandOff     = (MP_HAND_OFF *)BuildGuidHob (&mMpHandOffGuid, MpHandOffSize);
> +      ASSERT (MpHandOff != NULL);
> +      ZeroMem (MpHandOff, MpHandOffSize);
>
> -  for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
> -    MpHandOff->Info[Index].ApicId = CpuInfoInHob[Index].ApicId;
> -    MpHandOff->Info[Index].Health = CpuInfoInHob[Index].Health;
> +      HobBase                   = Index;
> +      MpHandOff->ProcessorIndex = HobBase;
> +      MpHandOff->CpuCount       = MIN (CpuMpData->CpuCount - HobBase, CpusPerHob);

Yes, the MIN() here is my key point, but I think we should also let it
control the allocation!

> +
> +      if (CpuMpData->ApLoopMode != ApInHltLoop) {
> +        MpHandOff->StartupSignalValue    = MP_HAND_OFF_SIGNAL;
> +        MpHandOff->WaitLoopExecutionMode = sizeof (VOID *);
> +      }
> +    }

As noted elsewhere, these fields don't belong in the loop (they don't
belong to MP_HAND_OFF, going forward); the two of them together should
form a new singleton structure.

> +
> +    MpHandOff->Info[Index-HobBase].ApicId = CpuInfoInHob[Index].ApicId;
> +    MpHandOff->Info[Index-HobBase].Health = CpuInfoInHob[Index].Health;
>      if (CpuMpData->ApLoopMode != ApInHltLoop) {
> -      MpHandOff->Info[Index].StartupSignalAddress    = (UINT64)(UINTN)CpuMpData->CpuData[Index].StartupApSignal;
> -      MpHandOff->Info[Index].StartupProcedureAddress = (UINT64)(UINTN)&CpuMpData->CpuData[Index].ApFunction;
> +      MpHandOff->Info[Index-HobBase].StartupSignalAddress    = (UINT64)(UINTN)CpuMpData->CpuData[Index].StartupApSignal;
> +      MpHandOff->Info[Index-HobBase].StartupProcedureAddress = (UINT64)(UINTN)&CpuMpData->CpuData[Index].ApFunction;
>      }
>    }
>

Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115595): https://edk2.groups.io/g/devel/message/115595
Mute This Topic: https://groups.io/mt/104369848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber()
  2024-02-19 11:37     ` Gerd Hoffmann
@ 2024-02-19 20:02       ` Laszlo Ersek
  0 siblings, 0 replies; 21+ messages in thread
From: Laszlo Ersek @ 2024-02-19 20:02 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: devel, Oliver Steffen, Ray Ni, Rahul Kumar

On 2/19/24 12:37, Gerd Hoffmann wrote:
>   Hi,
> 
>> (I'm missing the larger picture here -- is this related to the problem
>> -- too many CPUs to fit their infos into a single HOB -- that Pawel
>> worked on for a while?
> 
> Different HOB, but similar underlying problem.
> 
> At least the HOB structure already has the fields needed to allow
> splitting the information into multiple HOBs, even though the current
> code doesn't actually do that (which is fixed by this series).
> 
>> The outer loop is suboptimal, IMO, to just open-coding another HOB scan
>> -- this approach looks quadratic, even though it could be linear. More
>> or less, as proposed, we call GetMpHandOffHob() for each MP_HAND_OFF
>> HOB, which will scan n/2 HOBs on average. (Even if the GUID HOB list is
>> sorted by ProcessorIndex, we'll scan 1 + 2 + 3 +... HOBs.) But if we
>> open-coded GetFirstGuidHob() and GetNextGuidHob() here, then a single
>> scan would suffice.
> 
> Ray raised performance concerns too.
> 
> Does HobLib provides any ordering guarantees?  Specifically in case the
> HOBs are returned in the same order they are created (which implies they
> are sorted by ProcessorIndex because patch #5 creates them in that
> order) this can certainly be optimized.

I don't think there are ordering guarantees, but my larger point in
review is that the order does not matter. I see no reason for addressing
HOBs in increasing processor index order. No loop over the HOBs that
I've seen touched by this patch set seems to depend on the visiting
order of HOBs. So the outer loops that advance with
GetMpHandOffHob(ProcessorIndex) should be rewritable with get-next-GUID-HOB.

Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115596): https://edk2.groups.io/g/devel/message/115596
Mute This Topic: https://groups.io/mt/104369845/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob()
  2024-02-19  9:51     ` Gerd Hoffmann
@ 2024-02-20  3:42       ` Ni, Ray
  0 siblings, 0 replies; 21+ messages in thread
From: Ni, Ray @ 2024-02-20  3:42 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel@edk2.groups.io, Oliver Steffen, Laszlo Ersek,
	Kumar, Rahul R

> 
> That will only work if the HOBs are returned in ProcessorIndex order.
> 
> That happens to be the case in my testing; the HOBs are returned in the
> same order they are created by patch #5 of this series.
> 
> Is that behavior guaranteed?  MdePkg/Include/Library/HobLib.h doesn't
> say anything about the ordering.

The HOB item order follows when it's created.
The HOB structure implicitly guarantees it.

I am aware that in a production server UEFI firmware, the number of HOB items is huge.
Enumerating the HOB list multiple times is a big cost.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115619): https://edk2.groups.io/g/devel/message/115619
Mute This Topic: https://groups.io/mt/104369841/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData()
  2024-02-19 12:50   ` Laszlo Ersek
@ 2024-02-20  7:35     ` Ni, Ray
  0 siblings, 0 replies; 21+ messages in thread
From: Ni, Ray @ 2024-02-20  7:35 UTC (permalink / raw)
  To: devel@edk2.groups.io, lersek@redhat.com, kraxel@redhat.com
  Cc: Oliver Steffen, Kumar, Rahul R

> 
> > +
> > +      if (CpuMpData->ApLoopMode != ApInHltLoop) {
> > +        MpHandOff->StartupSignalValue    = MP_HAND_OFF_SIGNAL;
> > +        MpHandOff->WaitLoopExecutionMode = sizeof (VOID *);
> > +      }
> > +    }
> 
> As noted elsewhere, these fields don't belong in the loop (they don't
> belong to MP_HAND_OFF, going forward); the two of them together should
> form a new singleton structure.
> 

I agree the StartupSignalValue and WaitLoopExecutionMode are duplicated fields
if multiple MP_HAND_OFF instances are created.

I am ok to leave them as duplicates in this patch series.



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115638): https://edk2.groups.io/g/devel/message/115638
Mute This Topic: https://groups.io/mt/104369848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2024-02-20  7:35 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-15  9:31 [edk2-devel] [PATCH 0/5] UefiCpuPkg/MpInitLib: Add support for multiple MP_HAND_OFF HOBs Gerd Hoffmann
2024-02-15  9:31 ` [edk2-devel] [PATCH 1/5] UefiCpuPkg/MpInitLib: Add ProcessorIndex argument to GetMpHandOffHob() Gerd Hoffmann
2024-02-19  2:34   ` Ni, Ray
2024-02-19  9:51     ` Gerd Hoffmann
2024-02-20  3:42       ` Ni, Ray
2024-02-19 11:18   ` Laszlo Ersek
2024-02-15  9:31 ` [edk2-devel] [PATCH 2/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to GetBspNumber() Gerd Hoffmann
2024-02-19  2:41   ` Ni, Ray
2024-02-19 11:18   ` Laszlo Ersek
2024-02-19 11:37     ` Gerd Hoffmann
2024-02-19 20:02       ` Laszlo Ersek
2024-02-15  9:31 ` [edk2-devel] [PATCH 3/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SwitchApContext() Gerd Hoffmann
2024-02-19  2:43   ` Ni, Ray
2024-02-19 11:25   ` Laszlo Ersek
2024-02-15  9:31 ` [edk2-devel] [PATCH 4/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to MpInitLibInitialize Gerd Hoffmann
2024-02-19  2:57   ` Ni, Ray
2024-02-19 11:56   ` Laszlo Ersek
2024-02-15  9:31 ` [edk2-devel] [PATCH 5/5] UefiCpuPkg/MpInitLib: Add support for multiple HOBs to SaveCpuMpData() Gerd Hoffmann
2024-02-19  3:02   ` Ni, Ray
2024-02-19 12:50   ` Laszlo Ersek
2024-02-20  7:35     ` Ni, Ray

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox