public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "PierreGondois" <pierre.gondois@arm.com>
To: devel@edk2.groups.io
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>,
	Thomas Abraham <thomas.abraham@arm.com>,
	Sami Mujawar <sami.mujawar@arm.com>
Subject: [PATCH v1 3/3] Platform/ARM: Juno: Generate _CPC objects for JunoR2
Date: Fri,  5 May 2023 15:18:30 +0200	[thread overview]
Message-ID: <20230505131830.1310792-4-Pierre.Gondois@arm.com> (raw)
In-Reply-To: <20230505131830.1310792-1-Pierre.Gondois@arm.com>

From: Pierre Gondois <pierre.gondois@arm.com>

The SsdtCpuTopologyGenerator can generate _CPC objects.
This is done by querying the SCP for the relevant performance
state information through SCMI. CM_ARM_CPC_INFO are then populated
and used to generate _CPC objects in the Ssdt Cpu topology.

Use the ArmScmiInfoLib and add the handling to generate _CPC
information.

Note that using _CPC is only possible if SCP is correctly tuned
to advertise performance levels on an abstract and unified scale.
A basic check is done to prevent the _CPC generation otherwise.

The following performance level values where used for testing:
- little CPUs OPPs: [181, 322, 383] * 1000
- big CPUs OPPs: [512, 833, 1024] * 1024

Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 .../ConfigurationManager.c                    | 237 +++++++++++++++++-
 .../ConfigurationManager.h                    |  10 +
 .../ConfigurationManagerDxe.inf               |   1 +
 3 files changed, 245 insertions(+), 3 deletions(-)

diff --git a/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.c b/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.c
index 2b881e61be50..971efc17c8f7 100644
--- a/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.c
+++ b/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.c
@@ -14,6 +14,7 @@
 #include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
 #include <IndustryStandard/SerialPortConsoleRedirectionTable.h>
 #include <Library/ArmLib.h>
+#include <Library/ArmScmiInfoLib.h>
 #include <Library/DebugLib.h>
 #include <Library/IoLib.h>
 #include <Library/PcdLib.h>
@@ -756,6 +757,8 @@ EDKII_PLATFORM_REPOSITORY_INFO ArmJunoPlatformRepositoryInfo = {
       4,
     },
   },
+  { // CPC info, dynamically populated.
+  },
 };
 
 /** A helper function for returning the Configuration Manager Objects.
@@ -1212,6 +1215,60 @@ GetPsdInfo (
   return EFI_SUCCESS;
 }
 
+/** Return Cpc Info.
+
+  @param [in]      This           Pointer to the Configuration Manager Protocol.
+  @param [in]      CmObjectId     The Object ID of the CM object requested
+  @param [in]      SearchToken    A unique token for identifying the requested
+                                  CM_ARM_PCI_INTERRUPT_MAP_INFO object.
+  @param [in, out] CmObject       Pointer to the Configuration Manager Object
+                                  descriptor describing the requested Object.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_NOT_FOUND           The required object information is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetCpcInfo (
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST This,
+  IN  CONST CM_OBJECT_ID                                  CmObjectId,
+  IN  CONST CM_OBJECT_TOKEN                               SearchToken,
+  IN  OUT   CM_OBJ_DESCRIPTOR                     * CONST CmObject
+  )
+{
+  EDKII_PLATFORM_REPOSITORY_INFO  * PlatformRepo;
+  UINT32                            TotalObjCount;
+  UINT32                            ObjIndex;
+
+  if ((This == NULL) || (CmObject == NULL)) {
+    ASSERT (This != NULL);
+    ASSERT (CmObject != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PlatformRepo = This->PlatRepoInfo;
+
+  if (PlatformRepo->JunoRevision != JUNO_REVISION_R2) {
+    /* Only support _CPC generation on Juno R2 for now. */
+    return EFI_UNSUPPORTED;
+  }
+
+  TotalObjCount = ARRAY_SIZE (PlatformRepo->CpcInfo);
+
+  for (ObjIndex = 0; ObjIndex < TotalObjCount; ObjIndex++) {
+    if (SearchToken == (CM_OBJECT_TOKEN)&PlatformRepo->CpcInfo[ObjIndex]) {
+      CmObject->ObjectId = CmObjectId;
+      CmObject->Size = sizeof (PlatformRepo->CpcInfo[ObjIndex]);
+      CmObject->Data = (VOID*)&PlatformRepo->CpcInfo[ObjIndex];
+      CmObject->Count = 1;
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
 /** Return a list of Configuration Manager object references pointed to by the
     given input token.
 
@@ -1621,6 +1678,19 @@ GetArmNameSpaceObject (
                  );
       break;
 
+    case EArmObjCpcInfo:
+      Status = HandleCmObjectRefByToken (
+                 This,
+                 CmObjectId,
+                 PlatformRepo->CpcInfo,
+                 sizeof (PlatformRepo->CpcInfo),
+                 ARRAY_SIZE (PlatformRepo->CpcInfo),
+                 Token,
+                 GetCpcInfo,
+                 CmObject
+                 );
+      break;
+
     default: {
       Status = EFI_NOT_FOUND;
       DEBUG ((
@@ -1776,6 +1846,150 @@ EDKII_CONFIGURATION_MANAGER_PROTOCOL ArmJunoPlatformConfigManagerProtocol = {
   &ArmJunoPlatformRepositoryInfo
 };
 
+/** Clear Cpc information.
+
+  If populating _CPC information fails, remove GicC tokens pointing
+  to Cpc CmObj to avoid creating corrupted _CPC objects.
+
+  @param [in] PlatformRepo   Platfom Info repository.
+
+  @retval EFI_SUCCESS   Success.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ClearCpcInfo (
+  EDKII_PLATFORM_REPOSITORY_INFO  *PlatformRepo
+  )
+{
+  CM_ARM_GICC_INFO  *GicCInfo;
+
+  GicCInfo = (CM_ARM_GICC_INFO*)&PlatformRepo->GicCInfo;
+
+  GicCInfo[0].CpcToken = CM_NULL_TOKEN;
+  GicCInfo[1].CpcToken = CM_NULL_TOKEN;
+  GicCInfo[2].CpcToken = CM_NULL_TOKEN;
+  GicCInfo[3].CpcToken = CM_NULL_TOKEN;
+  GicCInfo[4].CpcToken = CM_NULL_TOKEN;
+  GicCInfo[5].CpcToken = CM_NULL_TOKEN;
+
+  return EFI_SUCCESS;
+}
+
+/** Use the SCMI protocol to populate CPC objects dynamically.
+
+  @param [in] PlatformRepo   Platfom Info repository.
+  @param [in] DomainId       Id of the DVFS domain to probe.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_UNSUPPORTED         Not supported.
+  @retval !(EFI_SUCCESS)          An error occured.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PopulateCpcInfo (
+  EDKII_PLATFORM_REPOSITORY_INFO  *PlatformRepo,
+  IN  UINT32                      DomainId
+  )
+{
+  EFI_STATUS          Status;
+  CM_ARM_GICC_INFO    *GicCInfo;
+  AML_CPC_INFO        *CpcInfo;
+
+  if ((PlatformRepo == NULL)  ||
+      ((DomainId != PSD_BIG_DOMAIN_ID) &&
+       (DomainId != PSD_LITTLE_DOMAIN_ID))) {
+    Status = EFI_INVALID_PARAMETER;
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  if (PlatformRepo->JunoRevision != JUNO_REVISION_R2) {
+    /* Available frequencies are different on Juno R[0|1|2]. _CPC was
+     * only tested on Juno R2, so only enable support for this version.
+     */
+    return EFI_UNSUPPORTED;
+  }
+
+  CpcInfo = &PlatformRepo->CpcInfo[DomainId];
+  GicCInfo = (CM_ARM_GICC_INFO*)&PlatformRepo->GicCInfo;
+
+  Status = ArmScmiInfoGetFastChannel (
+              PlatformRepo->PsdInfo[DomainId].Domain,
+              CpcInfo
+              );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  /* CPPC must advertise performances on a 'continuous, abstract, unit-less
+     performance scale', i.e. CPU performances on an asymmetric platform
+     nust be represented on a unified scale.
+     CPU performance values are obtained from SCP through SCMI and advertised
+     to the OS via the _CPC objects. SCP currently maps performance requests
+     to frequency requests.
+     Thus, SCP must be modified to  advertise (and correctly handle)
+     performance values on a unified scale.
+
+     Check that SCP is using a unified scale by checking that the advertised
+     lowest/nominal frequencies are not the default ones.
+   */
+  if (((DomainId == PSD_BIG_DOMAIN_ID) &&
+       (CpcInfo->LowestPerformanceInteger == HZ_TO_KHZ(JUNO_R2_BIG_LOWEST_FREQ)) &&
+       (CpcInfo->NominalPerformanceInteger == HZ_TO_KHZ(JUNO_R2_BIG_NOMINAL_FREQ))) ||
+      ((DomainId == PSD_LITTLE_DOMAIN_ID) &&
+       (CpcInfo->LowestPerformanceInteger == HZ_TO_KHZ(JUNO_R2_LITTLE_LOWEST_FREQ)) &&
+       (CpcInfo->NominalPerformanceInteger == HZ_TO_KHZ(JUNO_R2_LITTLE_NOMINAL_FREQ)))) {
+    return EFI_UNSUPPORTED;
+  }
+
+  // Juno R2's lowest/nominal frequencies.
+  // Nominal frequency != Highest frequency.
+  if (DomainId == PSD_BIG_DOMAIN_ID) {
+    CpcInfo->LowestFrequencyInteger = JUNO_R2_BIG_LOWEST_FREQ;
+    CpcInfo->NominalFrequencyInteger = JUNO_R2_BIG_NOMINAL_FREQ;
+  } else {
+    CpcInfo->LowestFrequencyInteger = JUNO_R2_LITTLE_LOWEST_FREQ;
+    CpcInfo->NominalFrequencyInteger = JUNO_R2_LITTLE_NOMINAL_FREQ;
+  }
+
+  // The mapping Psd -> CPUs is available here.
+  if (DomainId == PSD_BIG_DOMAIN_ID) {
+    GicCInfo[0].CpcToken = (CM_OBJECT_TOKEN)CpcInfo;
+    GicCInfo[1].CpcToken = (CM_OBJECT_TOKEN)CpcInfo;
+  } else {
+    GicCInfo[2].CpcToken = (CM_OBJECT_TOKEN)CpcInfo;
+    GicCInfo[3].CpcToken = (CM_OBJECT_TOKEN)CpcInfo;
+    GicCInfo[4].CpcToken = (CM_OBJECT_TOKEN)CpcInfo;
+    GicCInfo[5].CpcToken = (CM_OBJECT_TOKEN)CpcInfo;
+  }
+
+  /*
+    Arm advises to use FFH to the following registers which uses AMU counters:
+     - ReferencePerformanceCounterRegister
+     - DeliveredPerformanceCounterRegister
+    Cf. Arm Functional Fixed Hardware Specification
+    s3.2 Performance management and Collaborative Processor Performance Control
+
+    Since, AMU is not supported by the Juno, clear these registers.
+   */
+  CpcInfo->ReferencePerformanceCounterRegister.AddressSpaceId = EFI_ACPI_6_4_SYSTEM_MEMORY;
+  CpcInfo->ReferencePerformanceCounterRegister.RegisterBitWidth = 0;
+  CpcInfo->ReferencePerformanceCounterRegister.RegisterBitOffset = 0;
+  CpcInfo->ReferencePerformanceCounterRegister.AccessSize = 0;
+  CpcInfo->ReferencePerformanceCounterRegister.Address = 0;
+
+  CpcInfo->DeliveredPerformanceCounterRegister.AddressSpaceId = EFI_ACPI_6_4_SYSTEM_MEMORY;
+  CpcInfo->DeliveredPerformanceCounterRegister.RegisterBitWidth = 0;
+  CpcInfo->DeliveredPerformanceCounterRegister.RegisterBitOffset = 0;
+  CpcInfo->DeliveredPerformanceCounterRegister.AccessSize = 0;
+  CpcInfo->DeliveredPerformanceCounterRegister.Address = 0;
+
+  return Status;
+}
+
 /**
   Entrypoint of Configuration Manager Dxe.
 
@@ -1795,6 +2009,8 @@ ConfigurationManagerDxeInitialize (
   )
 {
   EFI_STATUS  Status;
+  UINT32      Index;
+  BOOLEAN     CpcFailed;
 
   Status = gBS->InstallProtocolInterface (
                   &ImageHandle,
@@ -1809,7 +2025,7 @@ ConfigurationManagerDxeInitialize (
       " Status = %r\n",
       Status
       ));
-    goto error_handler;
+    return Status;
   }
 
   Status = InitializePlatformRepository (
@@ -1824,6 +2040,21 @@ ConfigurationManagerDxeInitialize (
       ));
   }
 
-error_handler:
-  return Status;
+  CpcFailed = FALSE;
+  for (Index = 0; Index < PSD_DOMAIN_COUNT; Index++) {
+    Status = PopulateCpcInfo (&ArmJunoPlatformRepositoryInfo, Index);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "WARN: Could not populate _CPC.\n"));
+      CpcFailed = TRUE;
+      break;
+    }
+  }
+
+  if (CpcFailed) {
+    // _CPC information is not mandatory and SCP might not support some
+    // SCMI requests. Failing should not prevent from booting.
+    ClearCpcInfo (&ArmJunoPlatformRepositoryInfo);
+  }
+
+  return EFI_SUCCESS;
 }
diff --git a/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.h b/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.h
index 4082a6f059a5..4c4643b56c96 100644
--- a/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.h
+++ b/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManager.h
@@ -211,6 +211,13 @@ typedef EFI_STATUS (*CM_OBJECT_HANDLER_PROC) (
 #define PSD_LITTLE_DOMAIN_ID    1
 #define PSD_DOMAIN_COUNT        2
 
+/* JUNO R2 frequency values, in KHz. */
+#define JUNO_R2_BIG_LOWEST_FREQ        (600000)
+#define JUNO_R2_BIG_NOMINAL_FREQ      (1000000)
+#define JUNO_R2_LITTLE_LOWEST_FREQ     (450000)
+#define JUNO_R2_LITTLE_NOMINAL_FREQ    (800000)
+#define HZ_TO_KHZ(Freq)                 (Freq * 1000)
+
 /** A structure describing the platform configuration
     manager repository information
 */
@@ -301,6 +308,9 @@ typedef struct PlatformRepositoryInfo {
   // Power domains
   CM_ARM_PSD_INFO                       PsdInfo[PSD_DOMAIN_COUNT];
 
+  // Cpc info (1 for each PSD domain)
+  CM_ARM_CPC_INFO                       CpcInfo[PSD_DOMAIN_COUNT];
+
   /// Juno Board Revision
   UINT32                                JunoRevision;
 } EDKII_PLATFORM_REPOSITORY_INFO;
diff --git a/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManagerDxe.inf b/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManagerDxe.inf
index 91bffe8d5d82..688996549337 100644
--- a/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManagerDxe.inf
+++ b/Platform/ARM/JunoPkg/ConfigurationManager/ConfigurationManagerDxe/ConfigurationManagerDxe.inf
@@ -35,6 +35,7 @@ [Packages]
 
 [LibraryClasses]
   ArmPlatformLib
+  ArmScmiInfoLib
   PrintLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
-- 
2.25.1


      parent reply	other threads:[~2023-05-05 13:18 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-05 13:18 [PATCH v1 0/3] Platform/ARM: Enable _CPC/_PSD generation on Juno-r2 PierreGondois
2023-05-05 13:18 ` [PATCH v1 1/3] Platform/ARM: Juno: Fix typo PierreGondois
2023-05-05 13:18 ` [PATCH v1 2/3] Platform/ARM: Juno: Generate _PSD objects PierreGondois
2023-05-05 13:18 ` PierreGondois [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230505131830.1310792-4-Pierre.Gondois@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox