Date   

[RFC] [PATCH 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL

Rebecca Cran <rebecca@...>
 

Add support for EFI_MP_SERVICES_PROTOCOL during the DXE phase under
AArch64.

Call PSCI_CPU_ON to power on the core, call the supplied procedure and
then call PSCI_CPU_OFF to power off the core.

Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
---
ArmPkg/ArmPkg.dec | 4 +
ArmPkg/ArmPkg.dsc | 4 +
ArmPkg/Drivers/CpuDxe/AArch64/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/Arm/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 +
ArmPkg/Drivers/CpuDxe/CpuDxe.h | 10 +
ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 6 +
ArmPkg/Drivers/CpuDxe/CpuMpInit.c | 604 ++++++++
ArmPkg/Include/Library/MpInitLib.h | 366 +++++
ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S | 61 +
ArmPkg/Library/MpInitLib/DxeMpInitLib.inf | 53 +
ArmPkg/Library/MpInitLib/DxeMpLib.c | 1498 ++++++++++++++++++++
ArmPkg/Library/MpInitLib/InternalMpInitLib.h | 358 +++++
ArmVirtPkg/ArmVirt.dsc.inc | 3 +
14 files changed, 3013 insertions(+)

diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec
index 6ed51edd0340..cd4458de6ec1 100644
--- a/ArmPkg/ArmPkg.dec
+++ b/ArmPkg/ArmPkg.dec
@@ -74,6 +74,10 @@
#
DefaultExceptionHandlerLib|Include/Library/DefaultExceptionHandlerLib.h

+ ## @libraryclass Provides a MP Services interface.
+ #
+ MpInitLib|Include/Library/MpInitLib.h
+
## @libraryclass Provides an interface to query miscellaneous OEM
# information.
#
diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 8abe3713c829..26fb8bb94c07 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -99,6 +99,9 @@
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf

+[LibraryClasses.AARCH64]
+ MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
+
[LibraryClasses.ARM, LibraryClasses.AARCH64]
NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf

@@ -163,4 +166,5 @@
ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf

[Components.AARCH64, Components.ARM]
+ ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c
new file mode 100644
index 000000000000..a4b9e9037100
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c
@@ -0,0 +1,22 @@
+/** @file
+ Architecture specific functions.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <CpuDxe.h>
+
+/** Initializes multi-processor support.
+ *
+**/
+VOID
+ArchInitializeMpSupport (
+ VOID
+ )
+{
+ InitializeMpSupport ();
+}
diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Arch.c b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c
new file mode 100644
index 000000000000..0ded264cd06a
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c
@@ -0,0 +1,22 @@
+/** @file
+ Architecture specific functions.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <CpuDxe.h>
+
+/** Initializes multi-processor support.
+ *
+**/
+VOID
+ArchInitializeMpSupport (
+ VOID
+ )
+{
+ /* Nothing to do - ARM doesn't support EFI_MP_SERVICES_PROTOCOL */
+}
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
index 082ef30fb6c4..db8752f5b54f 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
@@ -279,5 +279,7 @@ CpuDxeInitialize (
);
ASSERT_EFI_ERROR (Status);

+ ArchInitializeMpSupport ();
+
return Status;
}
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
index 4cf3ab258c24..6e7ceafa4436 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
@@ -143,4 +143,14 @@ SetGcdMemorySpaceAttributes (
IN UINT64 Attributes
);

+VOID
+InitializeMpSupport (
+ VOID
+ );
+
+VOID
+ArchInitializeMpSupport (
+ VOID
+ );
+
#endif // CPU_DXE_H_
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
index e5549fc71df7..f4cdb8ab5613 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
@@ -26,10 +26,13 @@
Exception.c

[Sources.ARM]
+ Arm/Arch.c
Arm/Mmu.c

[Sources.AARCH64]
+ AArch64/Arch.c
AArch64/Mmu.c
+ CpuMpInit.c

[Packages]
ArmPkg/ArmPkg.dec
@@ -37,6 +40,9 @@
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec

+[LibraryClasses.AARCH64]
+ MpInitLib
+
[LibraryClasses]
ArmLib
ArmMmuLib
diff --git a/ArmPkg/Drivers/CpuDxe/CpuMpInit.c b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c
new file mode 100644
index 000000000000..5bf4ed12b711
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c
@@ -0,0 +1,604 @@
+/** @file
+ Construct MP Services Protocol.
+
+ The MP Services Protocol provides a generalized way of performing following tasks:
+ - Retrieving information of multi-processor environment and MP-related status of
+ specific processors.
+ - Dispatching user-provided function to APs.
+ - Maintain MP-related processor status.
+
+ The MP Services Protocol must be produced on any system with more than one logical
+ processor.
+
+ The Protocol is available only during boot time.
+
+ MP Services Protocol is hardware-independent. Most of the logic of this protocol
+ is architecturally neutral. It abstracts the multi-processor environment and
+ status of processors, and provides interfaces to retrieve information, maintain,
+ and dispatch.
+
+ MP Services Protocol may be consumed by ACPI module. The ACPI module may use this
+ protocol to retrieve data that are needed for an MP platform and report them to OS.
+ MP Services Protocol may also be used to program and configure processors, such
+ as MTRR synchronization for memory space attributes setting in DXE Services.
+ MP Services Protocol may be used by non-CPU DXE drivers to speed up platform boot
+ by taking advantage of the processing capabilities of the APs, for example, using
+ APs to help test system memory in parallel with other device initialization.
+ Diagnostics applications may also use this protocol for multi-processor.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Protocol provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the
+ EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including
+ the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
+ logical processors that exist in the
+ system, including the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ return MpInitLibGetNumberOfProcessors (
+ This,
+ NumberOfProcessors,
+ NumberOfEnabledProcessors
+ );
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of
+ operation, slot numbers is all considered platform-related information and is
+ not provided by this service.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorNumber The index of the processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information
+ for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ return MpInitLibGetProcessorInfo (
+ This,
+ ProcessorNumber,
+ ProcessorInfoBuffer
+ );
+}
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function
+ specified by Procedure. If any enabled AP is busy, then EFI_NOT_READY is
+ returned immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number.
+ Otherwise, all the enabled APs execute the function specified by Procedure
+ simultaneously.
+
+ If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
+ APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in
+ non-blocking mode, and the BSP returns from this service without waiting for
+ APs. If a non-blocking mode is requested after the UEFI Event
+ EFI_EVENT_GROUP_READY_TO_BOOT is signaled, then EFI_UNSUPPORTED must be
+ returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before all APs
+ return from Procedure, then Procedure on the failed APs is terminated.
+ All enabled APs are always available for further calls to
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+ EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() to make sure that the nature of the
+ code that is executed on the BSP and the dispatched APs is well controlled.
+ The MP Services Protocol does not guarantee that the Procedure function is
+ MP-safe. Hence, the tasks that can be run in parallel are limited to certain
+ independent tasks and well-controlled exclusive code. EFI services and
+ protocols may not be called by APs unless otherwise specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroseconds expires.
+
+ In non-blocking execution mode, BSP is freed to return to the caller and then
+ proceed to the next task without having to wait for APs. The following
+ sequence needs to occur in a non-blocking execution mode:
+
+ -# The caller that intends to use this MP Services Protocol in non-blocking
+ mode creates WaitEvent by calling the EFI CreateEvent() service. The
+ caller invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter
+ WaitEvent is not NULL, then StartupAllAPs() executes in non-blocking
+ mode. It requests the function specified by Procedure to be started on
+ all the enabled APs, and releases the BSP to continue with other tasks.
+ -# The caller can use the CheckEvent() and WaitForEvent() services to check
+ the state of the WaitEvent created in step 1.
+ -# When the APs complete their task or TimeoutInMicroSecondss expires, the
+ MP Service signals WaitEvent by calling the EFI SignalEvent() function.
+ If FailedCpuList is not NULL, its content is available when WaitEvent is
+ signaled. If all APs returned from Procedure prior to the timeout, then
+ FailedCpuList is set to NULL. If not all APs return from Procedure before
+ the timeout, then FailedCpuList is filled in with the list of the failed
+ APs. The buffer is allocated by MP Service Protocol using AllocatePool().
+ It is the caller's responsibility to free the buffer with FreePool()
+ service.
+ -# This invocation of SignalEvent() function informs the caller that invoked
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs
+ completed the specified task or a timeout occurred. The contents of
+ FailedCpuList can be examined to determine which APs did not complete the
+ specified task prior to the timeout.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor
+ handle number. If FALSE, then all the
+ enabled APs execute the function specified
+ by Procedure simultaneously.
+ @param[in] WaitEvent The event created by the caller with
+ CreateEvent() service. If it is NULL,
+ then execute in blocking mode. BSP waits
+ until all APs finish or
+ TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking
+ mode. BSP requests the function specified
+ by Procedure to be started on all the
+ enabled APs, and go on executing
+ immediately. If all return from Procedure,
+ or TimeoutInMicroseconds expires, this
+ event is signaled. The BSP can use the
+ CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
+ for APs to return from Procedure, either
+ for blocking or non-blocking mode. Zero
+ means infinity. If the timeout expires
+ before all APs return from Procedure, then
+ Procedure on the failed APs is terminated.
+ All enabled APs are available for next
+ function assigned by
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored.
+ Otherwise, if all APs finish successfully,
+ then its content is set to NULL. If not
+ all APs finish before timeout expires,
+ then its content is set to address of the
+ buffer holding handle numbers of the
+ failed APs.
+ The buffer is allocated by MP Service
+ Protocol, and it's the caller's
+ responsibility to free the buffer with
+ FreePool() service.
+ In blocking mode, it is ready for
+ consumption when the call returns. In
+ non-blocking mode, it is ready when
+ WaitEvent is signaled. The list of failed
+ CPU is terminated by END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been
+ dispatched to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ return MpInitLibStartupAllAPs (
+ This,
+ Procedure,
+ SingleThread,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
+ is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+ BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
+ is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+ then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+ EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ return MpInitLibStartupThisAP (
+ This,
+ Procedure,
+ ProcessorNumber,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ Finished
+ );
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be
+ performed by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ return MpInitLibSwitchBSP (This, ProcessorNumber, EnableOldBSP);
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system. This service may not be supported
+ after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ return MpInitLibEnableDisableAP (This, ProcessorNumber, EnableAP, HealthFlag);
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ return MpInitLibWhoAmI (This, ProcessorNumber);
+}
+
+EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
+ GetNumberOfProcessors,
+ GetProcessorInfo,
+ StartupAllAPs,
+ StartupThisAP,
+ SwitchBSP,
+ EnableDisableAP,
+ WhoAmI
+};
+
+/** Initialize multi-processor support.
+
+**/
+VOID
+InitializeMpSupport (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ UINTN MaxCpus;
+ EFI_HOB_GENERIC_HEADER *Hob;
+ VOID *HobData;
+ UINTN HobDataSize;
+ ARM_PROCESSOR_TABLE CpuInfo;
+
+ DEBUG ((DEBUG_INFO, "Starting MP services"));
+
+ Hob = GetFirstGuidHob (&gArmMpCoreInfoGuid);
+ if (Hob != NULL) {
+ HobData = GET_GUID_HOB_DATA (Hob);
+ HobDataSize = GET_GUID_HOB_DATA_SIZE (Hob);
+ CpuInfo.ArmCpus = (ARM_CORE_INFO *)HobData;
+ CpuInfo.NumberOfEntries = HobDataSize / sizeof (ARM_CORE_INFO);
+ MaxCpus = CpuInfo.NumberOfEntries;
+ }
+
+ if (MaxCpus == 1) {
+ DEBUG ((DEBUG_WARN, "Trying to use EFI_MP_SERVICES_PROTOCOL on a UP system"));
+ // We are not MP so nothing to do
+ return;
+ }
+
+ MpInitLibInitialize (MaxCpus, &CpuInfo);
+
+ //
+ // Now install the MP services protocol.
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiMpServiceProtocolGuid,
+ &mMpServicesTemplate,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/ArmPkg/Include/Library/MpInitLib.h b/ArmPkg/Include/Library/MpInitLib.h
new file mode 100644
index 000000000000..a4b80c18a9e8
--- /dev/null
+++ b/ArmPkg/Include/Library/MpInitLib.h
@@ -0,0 +1,366 @@
+/** @file
+
+Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2011, Apple Inc. All rights reserved.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_INITLIB_H_
+#define MP_INITLIB_H_
+
+#include <Protocol/Cpu.h>
+#include <Protocol/MpService.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Guid/ArmMpCoreInfo.h>
+
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the
+ EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including
+ the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
+ logical processors that exist in the
+ system, including the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorIndex The index of the processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information
+ for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor
+ handle number. If FALSE, then all the
+ enabled APs execute the function specified
+ by Procedure simultaneously.
+ @param[in] WaitEvent The event created by the caller with
+ CreateEvent() service. If it is NULL,
+ then execute in blocking mode. BSP waits
+ until all APs finish or
+ TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking
+ mode. BSP requests the function specified
+ by Procedure to be started on all the
+ enabled APs, and go on executing
+ immediately. If all return from Procedure,
+ or TimeoutInMicroseconds expires, this
+ event is signaled. The BSP can use the
+ CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
+ for APs to return from Procedure, either
+ for blocking or non-blocking mode. Zero
+ means infinity. If the timeout expires
+ before all APs return from Procedure, then
+ Procedure on the failed APs is terminated.
+ All enabled APs are available for next
+ function assigned by
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored.
+ Otherwise, if all APs finish successfully,
+ then its content is set to NULL. If not
+ all APs finish before timeout expires,
+ then its content is set to address of the
+ buffer holding handle numbers of the
+ failed APs.
+ The buffer is allocated by MP Service
+ Protocol, and it's the caller's
+ responsibility to free the buffer with
+ FreePool() service.
+ In blocking mode, it is ready for
+ consumption when the call returns. In
+ non-blocking mode, it is ready when
+ WaitEvent is signaled. The list of failed
+ CPU is terminated by END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been
+ dispatched to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ );
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be
+ performed by the current BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+/** Initializes the MP Services system data
+
+ @param NumberOfProcessors The number of processors, both BSP and AP.
+ @param CpuInfo CPU information gathered earlier during boot.
+
+**/
+VOID
+MpInitLibInitialize (
+ IN UINTN NumberOfProcessors,
+ IN ARM_PROCESSOR_TABLE *CpuInfo
+ );
+
+
+
+#endif /* MP_INITLIB_H_ */
diff --git a/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S
new file mode 100644
index 000000000000..287db060e594
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S
@@ -0,0 +1,61 @@
+#===============================================================================
+# Copyright (c) 2021 NUVIA Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#===============================================================================
+
+.text
+.align 3
+
+#include <AsmMacroIoLibV8.h>
+#include <IndustryStandard/ArmStdSmc.h>
+
+#include "InternalMpInitLib.h"
+
+GCC_ASM_IMPORT (gApStacksBase)
+GCC_ASM_IMPORT (gProcessorIDs)
+GCC_ASM_IMPORT (ApProcedure)
+GCC_ASM_IMPORT (gApStackSize)
+
+GCC_ASM_EXPORT (ApEntryPoint)
+
+StartupAddr: .8byte ASM_PFX(ApProcedure)
+
+// Entry-point for the AP
+// VOID
+// ApEntryPoint (
+// VOID
+// );
+ASM_PFX(ApEntryPoint):
+ mrs x0, mpidr_el1
+ ldr x1, gProcessorIDs
+ mov x2, 0 // x2 = processor index
+ mov x3, 0 // x3 = address offset
+
+// Find index in gProcessorIDs for current processor
+1:
+ ldr x4, [x1, x3] // x4 = gProcessorIDs + x3
+ cmp x4, 0 // check if we've reached the end of gProcessorIDs
+ beq ProcessorNotFound
+ add x3, x3, 8 // x3 += sizeof (*gProcessorIDs)
+ add x2, x2, 1 // x2++
+ cmp x0, x4 // if mpidr_el1 != *(gProcessorIDs + x3) then loop
+ bne 1b
+ sub x2, x2, 1
+
+// Calculate stack address
+ // x2 contains the index for the current processor
+ ldr x0, gApStacksBase
+ ldr x1, gApStackSize
+ mul x3, x2, x1 // x3 = ProcessorIndex * gApStackSize
+ add x4, x0, x3 // x4 = gApStacksBase + x3
+ add sp, x4, x1 // sp = x4 + gApStackSize
+
+ ldr x0, StartupAddr // ASM_PFX(ApProcedure)
+ blr x0 // doesn't return
+
+ProcessorNotFound:
+// Turn off the processor
+ MOV32 (w0, ARM_SMC_ID_PSCI_CPU_OFF)
+ smc #0
+ b .
diff --git a/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
new file mode 100644
index 000000000000..2275b6cca33a
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -0,0 +1,53 @@
+#/** @file
+#
+# Component description file for the DxeMpInitLib module.
+#
+# Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 1.29
+ BASE_NAME = DxeMpInitLib
+ FILE_GUID = c9ca773c-8ae4-4b74-82fd-f7345503294e
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MpInitLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+
+[Sources.AARCH64]
+ AArch64/MpFuncs.S
+
+[Sources]
+ DxeMpLib.c
+ InternalMpInitLib.h
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ ArmSmcLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ HobLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiMpServiceProtocolGuid
+
+[Guids]
+ gArmMpCoreInfoGuid
diff --git a/ArmPkg/Library/MpInitLib/DxeMpLib.c b/ArmPkg/Library/MpInitLib/DxeMpLib.c
new file mode 100644
index 000000000000..6053db740624
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/DxeMpLib.c
@@ -0,0 +1,1498 @@
+/** @file
+ Construct MP Services Protocol.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+ Portions Copyright (c) 2011, Apple Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Ppi/ArmMpCoreInfo.h>
+#include <Library/ArmLib.h>
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <IndustryStandard/ArmStdSmc.h>
+
+#include "InternalMpInitLib.h"
+
+#define POLL_INTERVAL_US 50000
+
+STATIC CPU_MP_DATA mCpuMpData;
+STATIC BOOLEAN mNonBlockingModeAllowed;
+UINT64 *gApStacksBase;
+UINT64 *gProcessorIDs;
+CONST UINT64 gApStackSize = AP_STACK_SIZE;
+
+/** C entry-point for the AP.
+ This function gets called from the assembly function ApEntryPoint.
+
+**/
+VOID
+ApProcedure (
+ VOID
+ )
+{
+ ARM_SMC_ARGS Args;
+ EFI_AP_PROCEDURE ApProcedure;
+ VOID *ApParameter;
+ UINTN ProcessorIndex;
+
+ MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex);
+
+ /* Fetch the user-supplied procedure and parameter to execute */
+ ApProcedure = mCpuMpData.CpuData[ProcessorIndex].Procedure;
+ ApParameter = mCpuMpData.CpuData[ProcessorIndex].Parameter;
+
+ ApProcedure (ApParameter);
+
+ mCpuMpData.CpuData[ProcessorIndex].State = CpuStateFinished;
+
+ /* Since we're finished with this AP, turn it off */
+ Args.Arg0 = ARM_SMC_ID_PSCI_CPU_OFF;
+ ArmCallSmc (&Args);
+
+ /* Should never be reached */
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+}
+
+/** Turns on the specified core using PSCI and executes the user-supplied
+ function that's been configured via a previous call to SetApProcedure.
+
+ @param ProcessorIndex The index of the core to turn on.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_DEVICE_ERROR The processor could not be turned on.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+DispatchCpu (
+ IN UINTN ProcessorIndex
+ )
+{
+ ARM_SMC_ARGS Args;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ mCpuMpData.CpuData[ProcessorIndex].State = CpuStateBusy;
+
+ /* Turn the AP on */
+ if (sizeof (Args.Arg0) == sizeof (UINT32)) {
+ Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH32;
+ } else {
+ Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH64;
+ }
+ Args.Arg1 = gProcessorIDs[ProcessorIndex];
+ Args.Arg2 = (UINTN)ApEntryPoint;
+
+ ArmCallSmc (&Args);
+
+ if (Args.Arg0 != ARM_SMC_PSCI_RET_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "PSCI_CPU_ON call failed: %d", Args.Arg0));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/** Returns whether the specified processor is the BSP.
+
+ @param[in] ProcessorIndex The index the processor to check.
+
+ @return TRUE if the processor is the BSP, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorBSP (
+ UINTN ProcessorIndex
+ )
+{
+ EFI_PROCESSOR_INFORMATION *CpuInfo;
+
+ CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
+
+ return (CpuInfo->StatusFlag & PROCESSOR_AS_BSP_BIT) != 0;
+}
+
+/** Returns whether the processor executing this function is the BSP.
+
+ @return Whether the current processor is the BSP.
+**/
+STATIC
+BOOLEAN
+IsCurrentProcessorBSP (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorIndex;
+
+ Status = MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return IsProcessorBSP (ProcessorIndex);
+}
+
+/** Get the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP.
+
+ @return The AP status.
+**/
+CPU_STATE
+GetApState (
+ IN CPU_AP_DATA *CpuData
+ )
+{
+ return CpuData->State;
+}
+
+/** Configures the processor context with the user-supplied procedure and
+ argument.
+
+ @param CpuData The processor context.
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+
+**/
+STATIC
+VOID
+SetApProcedure (
+ IN CPU_AP_DATA *CpuData,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument
+ )
+{
+ ASSERT (CpuData != NULL);
+ ASSERT (Procedure != NULL);
+
+ CpuData->Parameter = ProcedureArgument;
+ CpuData->Procedure = Procedure;
+}
+
+/** Returns the index of the next processor that is blocked.
+
+ @param[out] NextNumber The index of the next blocked processor.
+
+ @retval EFI_SUCCESS Successfully found the next blocked processor.
+ @retval EFI_NOT_FOUND There are no blocked processors.
+
+**/
+STATIC
+EFI_STATUS
+GetNextBlockedNumber (
+ OUT UINTN *NextNumber
+ )
+{
+ UINTN Index;
+ CPU_STATE State;
+ CPU_AP_DATA *CpuData;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ State = CpuData->State;
+
+ if (State == CpuStateBlocked) {
+ *NextNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/** Stalls the BSP for the minimum of POLL_INTERVAL_US and Timeout.
+
+ @param[in] Timeout The time limit in microseconds remaining for
+ APs to return from Procedure.
+
+ @retval StallTime Time of execution stall.
+**/
+STATIC
+UINTN
+CalculateAndStallInterval (
+ IN UINTN Timeout
+ )
+{
+ UINTN StallTime;
+
+ if (Timeout < POLL_INTERVAL_US && Timeout != 0) {
+ StallTime = Timeout;
+ } else {
+ StallTime = POLL_INTERVAL_US;
+ }
+
+ gBS->Stall (StallTime);
+
+ return StallTime;
+}
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the
+ EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including
+ the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
+ logical processors that exist in the
+ system, including the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *NumberOfProcessors = mCpuMpData.NumberOfProcessors;
+ *NumberOfEnabledProcessors = mCpuMpData.NumberOfEnabledProcessors;
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorIndex The index of the processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information
+ for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorIndex &= ~CPU_V2_EXTENDED_TOPOLOGY;
+
+ if (ProcessorIndex >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ CopyMem (
+ ProcessorInfoBuffer,
+ &mCpuMpData.CpuData[ProcessorIndex],
+ sizeof (EFI_PROCESSOR_INFORMATION)
+ );
+ return EFI_SUCCESS;
+}
+
+/** Returns whether the specified processor is enabled.
+
+ @param[in] ProcessorIndex The index of the processor to check.
+
+ @return TRUE if the processor is enabled, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorEnabled (
+ UINTN ProcessorIndex
+ )
+{
+ EFI_PROCESSOR_INFORMATION *CpuInfo;
+
+ CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
+
+ return (CpuInfo->StatusFlag & PROCESSOR_ENABLED_BIT) != 0;
+}
+
+/** Returns whether all processors are in the idle state.
+
+ @return Whether all the processors are idle.
+
+**/
+STATIC
+BOOLEAN
+CheckAllCpusReady (
+ VOID
+ )
+{
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/** Sets up the state for the StartupAllAPs function.
+
+ @param SingleThread Whether the APs will execute sequentially.
+
+**/
+STATIC
+VOID
+StartupAllAPsPrepareState (
+ IN BOOLEAN SingleThread
+ )
+{
+ UINTN Index;
+ CPU_STATE APInitialState;
+ CPU_AP_DATA *CpuData;
+
+ mCpuMpData.FinishCount = 0;
+ mCpuMpData.StartCount = 0;
+ mCpuMpData.SingleThread = SingleThread;
+
+ APInitialState = CpuStateReady;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+
+ //
+ // Get APs prepared, and put failing APs into FailedCpuList.
+ // If "SingleThread", only 1 AP will put into ready state, other AP will be
+ // put into ready state 1 by 1, until the previous 1 finished its task.
+ // If not "SingleThread", all APs are put into ready state from the
+ // beginning
+ //
+
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ if (mCpuMpData.FailedList != NULL) {
+ mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index;
+ }
+
+ continue;
+ }
+
+ ASSERT (GetApState (CpuData) == CpuStateIdle);
+ CpuData->State = APInitialState;
+
+ mCpuMpData.StartCount++;
+ if (SingleThread) {
+ APInitialState = CpuStateBlocked;
+ }
+ }
+}
+
+/** Handles execution of StartupAllAPs when a WaitEvent has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param WaitEvent The wait event to be signaled when the work is
+ complete or a timeout has occurred.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsWithWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN EFI_EVENT WaitEvent,
+ IN UINTN TimeoutInMicroseconds
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ if (GetApState (CpuData) == CpuStateReady) {
+ SetApProcedure (CpuData, Procedure, ProcedureArgument);
+ }
+ }
+
+ //
+ // Save data into private data structure, and create timer to poll AP state
+ // before exiting
+ //
+ mCpuMpData.Procedure = Procedure;
+ mCpuMpData.ProcedureArgument = ProcedureArgument;
+ mCpuMpData.WaitEvent = WaitEvent;
+ mCpuMpData.Timeout = TimeoutInMicroseconds;
+ mCpuMpData.TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0);
+ Status = gBS->SetTimer (
+ mCpuMpData.CheckAllAPsEvent,
+ TimerPeriodic,
+ POLL_INTERVAL_US
+ );
+ return Status;
+}
+
+/** Handles execution of StartupAllAPs when no wait event has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+ @param SingleThread Whether the APs will execute sequentially.
+ @param FailedCpuList User-supplied pointer for list of failed CPUs.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsNoWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN UINTN TimeoutInMicroseconds,
+ IN BOOLEAN SingleThread,
+ IN UINTN **FailedCpuList
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN NextIndex;
+ UINTN Timeout;
+ CPU_AP_DATA *CpuData;
+
+ Timeout = TimeoutInMicroseconds;
+
+ while (TRUE) {
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ switch (GetApState (CpuData)) {
+ case CpuStateReady:
+ SetApProcedure (CpuData, Procedure, ProcedureArgument);
+ Status = DispatchCpu (Index);
+ if (EFI_ERROR (Status)) {
+ CpuData->State = CpuStateIdle;
+ Status = EFI_NOT_READY;
+ goto Done;
+ }
+
+ break;
+
+ case CpuStateFinished:
+ mCpuMpData.FinishCount++;
+ if (SingleThread) {
+ Status = GetNextBlockedNumber (&NextIndex);
+ if (!EFI_ERROR (Status)) {
+ mCpuMpData.CpuData[NextIndex].State = CpuStateReady;
+ }
+ }
+
+ CpuData->State = CpuStateIdle;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (mCpuMpData.FinishCount == mCpuMpData.StartCount) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) {
+ Status = EFI_TIMEOUT;
+ goto Done;
+ }
+
+ Timeout -= CalculateAndStallInterval (Timeout);
+ }
+
+Done:
+ if (FailedCpuList != NULL) {
+ if (mCpuMpData.FailedListIndex == 0) {
+ FreePool (*FailedCpuList);
+ *FailedCpuList = NULL;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor
+ handle number. If FALSE, then all the
+ enabled APs execute the function specified
+ by Procedure simultaneously.
+ @param[in] WaitEvent The event created by the caller with
+ CreateEvent() service. If it is NULL,
+ then execute in blocking mode. BSP waits
+ until all APs finish or
+ TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking
+ mode. BSP requests the function specified
+ by Procedure to be started on all the
+ enabled APs, and go on executing
+ immediately. If all return from Procedure,
+ or TimeoutInMicroseconds expires, this
+ event is signaled. The BSP can use the
+ CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
+ for APs to return from Procedure, either
+ for blocking or non-blocking mode. Zero
+ means infinity. If the timeout expires
+ before all APs return from Procedure, then
+ Procedure on the failed APs is terminated.
+ All enabled APs are available for next
+ function assigned by
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored.
+ Otherwise, if all APs finish successfully,
+ then its content is set to NULL. If not
+ all APs finish before timeout expires,
+ then its content is set to address of the
+ buffer holding handle numbers of the
+ failed APs.
+ The buffer is allocated by MP Service
+ Protocol, and it's the caller's
+ responsibility to free the buffer with
+ FreePool() service.
+ In blocking mode, it is ready for
+ consumption when the call returns. In
+ non-blocking mode, it is ready when
+ WaitEvent is signaled. The list of failed
+ CPU is terminated by END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been
+ dispatched to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (mCpuMpData.NumberOfProcessors == 1) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!CheckAllCpusReady ()) {
+ return EFI_NOT_READY;
+ }
+
+ if (FailedCpuList != NULL) {
+ mCpuMpData.FailedList = AllocatePool (
+ (mCpuMpData.NumberOfProcessors + 1) *
+ sizeof (UINTN)
+ );
+ if (mCpuMpData.FailedList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMemN (
+ mCpuMpData.FailedList,
+ (mCpuMpData.NumberOfProcessors + 1) *
+ sizeof (UINTN),
+ END_OF_CPU_LIST
+ );
+ mCpuMpData.FailedListIndex = 0;
+ *FailedCpuList = mCpuMpData.FailedList;
+ }
+
+ StartupAllAPsPrepareState (SingleThread);
+
+ if (WaitEvent != NULL) {
+ Status = StartupAllAPsWithWaitEvent (
+ Procedure,
+ ProcedureArgument,
+ WaitEvent,
+ TimeoutInMicroseconds
+ );
+ } else {
+ Status = StartupAllAPsNoWaitEvent (
+ Procedure,
+ ProcedureArgument,
+ TimeoutInMicroseconds,
+ SingleThread,
+ FailedCpuList
+ );
+ }
+
+ return Status;
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Timeout;
+ CPU_AP_DATA *CpuData;
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ CpuData = &mCpuMpData.CpuData[ProcessorNumber];
+
+ if (IsProcessorBSP (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsProcessorEnabled (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return EFI_NOT_READY;
+ }
+
+ if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Timeout = TimeoutInMicroseconds;
+
+ mCpuMpData.StartCount = 1;
+ mCpuMpData.FinishCount = 0;
+
+ SetApProcedure (
+ CpuData,
+ Procedure,
+ ProcedureArgument
+ );
+
+ Status = DispatchCpu (ProcessorNumber);
+ if (EFI_ERROR (Status)) {
+ CpuData->State = CpuStateIdle;
+ return EFI_NOT_READY;
+ }
+
+ if (WaitEvent != NULL) {
+ // Non Blocking
+ mCpuMpData.WaitEvent = WaitEvent;
+ gBS->SetTimer (
+ CpuData->CheckThisAPEvent,
+ TimerPeriodic,
+ POLL_INTERVAL_US
+ );
+ return EFI_SUCCESS;
+ }
+
+ // Blocking
+ while (TRUE) {
+ if (GetApState (CpuData) == CpuStateFinished) {
+ CpuData->State = CpuStateIdle;
+ break;
+ }
+
+ if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) {
+ return EFI_TIMEOUT;
+ }
+
+ Timeout -= CalculateAndStallInterval (Timeout);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be
+ performed by the current BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+
+ CpuData = &mCpuMpData.CpuData[ProcessorNumber];
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!IsProcessorEnabled (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsProcessorBSP (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ if (IsProcessorBSP (Index)) {
+ break;
+ }
+ }
+
+ ASSERT (Index != mCpuMpData.NumberOfProcessors);
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return EFI_NOT_READY;
+ }
+
+ // Skip for now as we need switch a bunch of stack stuff around and it's
+ // complex. May not be worth it?
+ return EFI_NOT_READY;
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ UINTN StatusFlag;
+ CPU_AP_DATA *CpuData;
+
+ StatusFlag = mCpuMpData.CpuData[ProcessorNumber].Info.StatusFlag;
+ CpuData = &mCpuMpData.CpuData[ProcessorNumber];
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (IsProcessorBSP (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EnableAP) {
+ if (!IsProcessorEnabled (ProcessorNumber)) {
+ mCpuMpData.NumberOfEnabledProcessors++;
+ }
+
+ StatusFlag |= PROCESSOR_ENABLED_BIT;
+ } else {
+ if (IsProcessorEnabled (ProcessorNumber)) {
+ mCpuMpData.NumberOfEnabledProcessors--;
+ }
+
+ StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ }
+
+ if (HealthFlag != NULL) {
+ StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT;
+ StatusFlag |= (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN Index;
+ UINT64 ProcessorId;
+ CPU_AP_DATA *CpuData;
+
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ProcessorId = ArmReadMpidr ();
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (CpuData->Info.ProcessorId == ProcessorId) {
+ break;
+ }
+ }
+
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+}
+
+/** Adds the specified processor the list of failed processors.
+
+ @param ProcessorIndex The processor index to add.
+ @param ApState Processor state.
+
+**/
+STATIC
+VOID
+AddProcessorToFailedList (
+ UINTN ProcessorIndex,
+ CPU_STATE ApState
+ )
+{
+ UINTN Index;
+ BOOLEAN Found;
+
+ Found = FALSE;
+
+ if (ApState == CpuStateIdle) {
+ return;
+ }
+
+ // If we are retrying make sure we don't double count
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ if (mCpuMpData.FailedList[Index] == END_OF_CPU_LIST) {
+ break;
+ }
+
+ if (mCpuMpData.FailedList[ProcessorIndex] == Index) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ /* If the CPU isn't already in the FailedList, add it */
+ if (!Found) {
+ mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index;
+ }
+}
+
+/** Handles the StartupAllAPs case where the timeout has occurred.
+
+**/
+STATIC
+VOID
+ProcessStartupAllAPsTimeout (
+ VOID
+ )
+{
+ CPU_AP_DATA *CpuData;
+ UINTN Index;
+
+ if (mCpuMpData.FailedList == NULL) {
+ return;
+ }
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ AddProcessorToFailedList (Index, GetApState (CpuData));
+ }
+}
+
+/** Updates the status of the APs.
+
+ @param[in] ProcessorIndex The index of the AP to update.
+**/
+STATIC
+VOID
+UpdateApStatus (
+ IN UINTN ProcessorIndex
+ )
+{
+ EFI_STATUS Status;
+ CPU_AP_DATA *CpuData;
+ CPU_AP_DATA *NextCpuData;
+ CPU_STATE State;
+ UINTN NextNumber;
+
+ CpuData = &mCpuMpData.CpuData[ProcessorIndex];
+
+ if (IsProcessorBSP (ProcessorIndex)) {
+ // Skip BSP
+ return;
+ }
+
+ if (!IsProcessorEnabled (ProcessorIndex)) {
+ // Skip Disabled processors
+ return;
+ }
+
+ State = GetApState (CpuData);
+
+ switch (State) {
+ case CpuStateFinished:
+ if (mCpuMpData.SingleThread) {
+ Status = GetNextBlockedNumber (&NextNumber);
+ if (!EFI_ERROR (Status)) {
+ NextCpuData = &mCpuMpData.CpuData[NextNumber];
+
+ NextCpuData->State = CpuStateReady;
+
+ SetApProcedure (
+ NextCpuData,
+ mCpuMpData.Procedure,
+ mCpuMpData.ProcedureArgument
+ );
+ }
+ }
+
+ CpuData->State = CpuStateIdle;
+ mCpuMpData.FinishCount++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ If a timeout is specified in StartupAllAps(), a timer is set, which invokes
+ this procedure periodically to check whether all APs have finished.
+
+ @param[in] Event The WaitEvent the user supplied.
+ @param[in] Context The event context.
+**/
+STATIC
+VOID
+EFIAPI
+CheckAllAPsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+
+ if (mCpuMpData.TimeoutActive) {
+ mCpuMpData.Timeout -= CalculateAndStallInterval (mCpuMpData.Timeout);
+ }
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ UpdateApStatus (Index);
+ }
+
+ if (mCpuMpData.TimeoutActive && mCpuMpData.Timeout == 0) {
+ ProcessStartupAllAPsTimeout ();
+
+ // Force terminal exit
+ mCpuMpData.FinishCount = mCpuMpData.StartCount;
+ }
+
+ if (mCpuMpData.FinishCount != mCpuMpData.StartCount) {
+ return;
+ }
+
+ gBS->SetTimer (
+ mCpuMpData.CheckAllAPsEvent,
+ TimerCancel,
+ 0
+ );
+
+ if (mCpuMpData.FailedListIndex == 0) {
+ if (mCpuMpData.FailedList != NULL) {
+ FreePool (mCpuMpData.FailedList);
+ mCpuMpData.FailedList = NULL;
+ }
+ }
+
+ gBS->SignalEvent (mCpuMpData.WaitEvent);
+}
+
+/** Invoked periodically via a timer to check the state of the processor.
+
+ @param Event The event supplied by the timer expiration.
+ @param Context The processor context.
+
+**/
+STATIC
+VOID
+EFIAPI
+CheckThisAPStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ CPU_AP_DATA *CpuData;
+ CPU_STATE State;
+
+ CpuData = Context;
+ CpuData->TimeTaken += POLL_INTERVAL_US;
+
+ State = GetApState (CpuData);
+
+ if (State == CpuStateFinished) {
+ Status = gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0);
+ ASSERT_EFI_ERROR (Status);
+
+ if (mCpuMpData.WaitEvent != NULL) {
+ Status = gBS->SignalEvent (mCpuMpData.WaitEvent);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ CpuData->State = CpuStateIdle;
+ }
+
+ if (CpuData->TimeTaken > CpuData->Timeout) {
+ if (mCpuMpData.WaitEvent != NULL) {
+ Status = gBS->SignalEvent (mCpuMpData.WaitEvent);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects
+ MP related data.
+
+ @param BSP TRUE if the processor is the BSP.
+ @param Mpidr The MPIDR for the specified processor.
+ @param ProcessorIndex The index of the processor.
+
+ @return EFI_SUCCESS if the data for the processor collected and filled in.
+
+**/
+STATIC
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINTN Mpidr,
+ IN UINTN ProcessorIndex
+ )
+{
+ EFI_PROCESSOR_INFORMATION *CpuInfo;
+
+ CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
+
+ /* The MPIDR passed in may be a pseudo-MPIDR that's missing the bit 31 RES1.
+ * Fix it so it's a proper MPIDR.
+ */
+ CpuInfo->ProcessorId = BIT31 | Mpidr;
+ CpuInfo->StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
+
+ if (BSP) {
+ CpuInfo->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+
+ CpuInfo->Location.Package = GET_CLUSTER_ID (Mpidr);
+ CpuInfo->Location.Core = GET_CORE_ID (Mpidr);
+ CpuInfo->Location.Thread = 0;
+
+ CpuInfo->ExtendedInformation.Location2.Package = 0;
+ CpuInfo->ExtendedInformation.Location2.Module = 0;
+ CpuInfo->ExtendedInformation.Location2.Tile = 0;
+ CpuInfo->ExtendedInformation.Location2.Die = GET_CLUSTER_ID (Mpidr);
+ CpuInfo->ExtendedInformation.Location2.Core = GET_CORE_ID (Mpidr);
+ CpuInfo->ExtendedInformation.Location2.Thread = 0;
+
+ mCpuMpData.CpuData[ProcessorIndex].State = BSP ? CpuStateBusy : CpuStateIdle;
+
+ mCpuMpData.CpuData[ProcessorIndex].Procedure = NULL;
+ mCpuMpData.CpuData[ProcessorIndex].Parameter = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/** Initializes the MP Services system data
+
+ @param NumberOfProcessors The number of processors, both BSP and AP.
+ @param CpuInfo CPU information gathered earlier during boot.
+
+**/
+VOID
+MpInitLibInitialize (
+ IN UINTN NumberOfProcessors,
+ IN ARM_PROCESSOR_TABLE *CpuInfo
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_EVENT ReadyToBootEvent;
+
+ //
+ // Clear the data structure area first.
+ //
+ ZeroMem (&mCpuMpData, sizeof (CPU_MP_DATA));
+ //
+ // First BSP fills and inits all known values, including its own records.
+ //
+ mCpuMpData.NumberOfProcessors = NumberOfProcessors;
+ mCpuMpData.NumberOfEnabledProcessors = NumberOfProcessors;
+
+ mCpuMpData.CpuData = AllocateZeroPool (
+ mCpuMpData.NumberOfProcessors *
+ sizeof (CPU_AP_DATA)
+ );
+ ASSERT (mCpuMpData.CpuData != NULL);
+
+ /* Allocate one extra for the NULL entry at the end */
+ gProcessorIDs = AllocatePool ((mCpuMpData.NumberOfProcessors + 1) * sizeof (UINT64));
+ ASSERT (gProcessorIDs != NULL);
+
+ FillInProcessorInformation (TRUE, CpuInfo->ArmCpus[0].Mpidr, 0);
+ gProcessorIDs[0] = mCpuMpData.CpuData[0].Info.ProcessorId;
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ CheckAllAPsStatus,
+ NULL,
+ &mCpuMpData.CheckAllAPsEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gApStacksBase = AllocatePool (
+ mCpuMpData.NumberOfProcessors *
+ gApStackSize
+ );
+ ASSERT (gApStacksBase != NULL);
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ if (IsProcessorBSP (Index)) {
+ /* Skip BSP */
+ continue;
+ }
+
+ FillInProcessorInformation (FALSE, CpuInfo->ArmCpus[Index].Mpidr, Index);
+
+ gProcessorIDs[Index] = mCpuMpData.CpuData[Index].Info.ProcessorId;
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ CheckThisAPStatus,
+ (VOID *)&mCpuMpData.CpuData[Index],
+ &mCpuMpData.CpuData[Index].CheckThisAPEvent
+ );
+ ASSERT (Status == EFI_SUCCESS);
+ }
+
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ ReadyToBootSignaled,
+ NULL,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gProcessorIDs[Index] = 0;
+}
+
+/**
+ Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is
+ signaled. After this point, non-blocking mode is no longer allowed.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+STATIC
+VOID
+EFIAPI
+ReadyToBootSignaled (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mNonBlockingModeAllowed = FALSE;
+}
+
diff --git a/ArmPkg/Library/MpInitLib/InternalMpInitLib.h b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h
new file mode 100644
index 000000000000..d08bb76246d7
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h
@@ -0,0 +1,358 @@
+/** @file
+
+Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2011, Apple Inc. All rights reserved.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_INTERNAL_INIT_LIB_H_
+#define MP_INTERNAL_INIT_LIB_H_
+
+#include <Protocol/Cpu.h>
+#include <Protocol/MpService.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+
+
+#define AP_STACK_SIZE 0x1000
+
+//
+// Internal Data Structures
+//
+
+//
+// AP state
+//
+// The state transitions for an AP when it process a procedure are:
+// Idle ----> Ready ----> Busy ----> Idle
+// [BSP] [AP] [AP]
+//
+typedef enum {
+ CpuStateIdle,
+ CpuStateReady,
+ CpuStateBlocked,
+ CpuStateBusy,
+ CpuStateFinished,
+ CpuStateDisabled
+} CPU_STATE;
+
+//
+// Define Individual Processor Data block.
+//
+typedef struct {
+ EFI_PROCESSOR_INFORMATION Info;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+ CPU_STATE State;
+ EFI_EVENT CheckThisAPEvent;
+ UINTN Timeout;
+ UINTN TimeTaken;
+} CPU_AP_DATA;
+
+//
+// Define MP data block which consumes individual processor block.
+//
+typedef struct {
+ UINTN NumberOfProcessors;
+ UINTN NumberOfEnabledProcessors;
+ EFI_EVENT CheckAllAPsEvent;
+ EFI_EVENT WaitEvent;
+ UINTN FinishCount;
+ UINTN StartCount;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *ProcedureArgument;
+ BOOLEAN SingleThread;
+ UINTN StartedNumber;
+ CPU_AP_DATA *CpuData;
+ UINTN Timeout;
+ UINTN *FailedList;
+ UINTN FailedListIndex;
+ BOOLEAN TimeoutActive;
+} CPU_MP_DATA;
+
+EFI_STATUS
+EFIAPI
+CpuMpServicesInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+extern EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate;
+
+/** Secondary core entry point.
+
+**/
+VOID ApEntryPoint (
+ VOID
+ );
+
+/** C entry-point for the AP.
+ This function gets called from the assembly function ApEntryPoint.
+**/
+VOID
+ApProcedure (
+ VOID
+ );
+
+/** Turns on the specified core using PSCI and executes the user-supplied
+ function that's been configured via a previous call to SetApProcedure.
+
+ @param ProcessorIndex The index of the core to turn on.
+
+ @retval EFI_SUCCESS The processor was successfully turned on.
+ @retval EFI_DEVICE_ERROR An error occurred turning the processor on.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+DispatchCpu (
+ IN UINTN ProcessorIndex
+ );
+
+/** Returns whether the specified processor is the BSP.
+
+ @param[in] ProcessorIndex The index the processor to check.
+
+ @return TRUE if the processor is the BSP, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorBSP (
+ UINTN ProcessorIndex
+ );
+
+/** Returns whether the processor executing this function is the BSP.
+
+ @return Whether the current processor is the BSP.
+**/
+STATIC
+BOOLEAN
+IsCurrentProcessorBSP (
+ VOID
+ );
+
+/** Returns whether the specified processor is enabled.
+
+ @param[in] ProcessorIndex The index of the processor to check.
+
+ @return TRUE if the processor is enabled, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorEnabled (
+ UINTN ProcessorIndex
+ );
+
+/** Configures the processor context with the user-supplied procedure and
+ argument.
+
+ @param CpuData The processor context.
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+
+**/
+STATIC
+VOID
+SetApProcedure (
+ IN CPU_AP_DATA *CpuData,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument
+ );
+
+/**
+ Get the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
+
+ @return The AP status
+**/
+CPU_STATE
+GetApState (
+ IN CPU_AP_DATA *CpuData
+ );
+
+/** Returns the index of the next processor that is blocked.
+
+ @param[out] NextNumber The index of the next blocked processor.
+
+ @retval EFI_SUCCESS Successfully found the next blocked processor.
+ @retval EFI_NOT_FOUND There are no blocked processors.
+
+**/
+STATIC
+EFI_STATUS
+GetNextBlockedNumber (
+ OUT UINTN *NextNumber
+ );
+
+/** Stalls the BSP for the minimum of gPollInterval and Timeout.
+
+ @param[in] Timeout The time limit in microseconds remaining for
+ APs to return from Procedure.
+
+ @retval StallTime Time of execution stall.
+**/
+STATIC
+UINTN
+CalculateAndStallInterval (
+ IN UINTN Timeout
+ );
+
+/** Returns whether all processors are in the idle state.
+
+ @return Whether all the processors are idle.
+
+**/
+STATIC
+BOOLEAN
+CheckAllCpusReady (
+ VOID
+ );
+
+/** Sets up the state for the StartupAllAPs function.
+
+ @param SingleThread Whether the APs will execute sequentially.
+
+**/
+STATIC
+VOID
+StartupAllAPsPrepareState (
+ IN BOOLEAN SingleThread
+ );
+
+/** Handles execution of StartupAllAPs when a WaitEvent has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param WaitEvent The wait event to be signaled when the work is
+ complete or a timeout has occurred.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsWithWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN EFI_EVENT WaitEvent,
+ IN UINTN TimeoutInMicroseconds
+ );
+
+/** Handles execution of StartupAllAPs when no wait event has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+ @param SingleThread Whether the APs will execute sequentially.
+ @param FailedCpuList User-supplied pointer for list of failed CPUs.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsNoWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN UINTN TimeoutInMicroseconds,
+ IN BOOLEAN SingleThread,
+ IN UINTN **FailedCpuList
+ );
+
+
+/** Adds the specified processor the list of failed processors.
+
+ @param ProcessorIndex The processor index to add.
+ @param ApState Processor state.
+
+**/
+STATIC
+VOID
+AddProcessorToFailedList (
+ UINTN ProcessorIndex,
+ CPU_STATE ApState
+ );
+
+/** Handles the StartupAllAPs case where the timeout has occurred.
+
+**/
+STATIC
+VOID
+ProcessStartupAllAPsTimeout (
+ VOID
+ );
+
+/**
+ If a timeout is specified in StartupAllAps(), a timer is set, which invokes
+ this procedure periodically to check whether all APs have finished.
+
+ @param[in] Event The WaitEvent the user supplied.
+ @param[in] Context The event context.
+**/
+STATIC
+VOID
+EFIAPI
+CheckAllAPsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/** Invoked periodically via a timer to check the state of the processor.
+
+ @param Event The event supplied by the timer expiration.
+ @param Context The processor context.
+
+**/
+STATIC
+VOID
+EFIAPI
+CheckThisAPStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects
+ MP related data.
+
+ @param BSP TRUE if the processor is the BSP.
+ @param Mpidr The MPIDR for the specified processor.
+ @param ProcessorIndex The index of the processor.
+
+ @return EFI_SUCCESS if the data for the processor collected and filled in.
+
+**/
+STATIC
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINTN Mpidr,
+ IN UINTN ProcessorIndex
+ );
+
+/**
+ Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is
+ signaled. After this point, non-blocking mode is no longer allowed.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+STATIC
+VOID
+EFIAPI
+ReadyToBootSignaled (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+
+#endif /* MP_INTERNAL_INIT_LIB_H_ */
diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc
index 5a1598d90ca7..af6e48fd6cfc 100644
--- a/ArmVirtPkg/ArmVirt.dsc.inc
+++ b/ArmVirtPkg/ArmVirt.dsc.inc
@@ -261,6 +261,9 @@
[LibraryClasses.ARM]
ArmSoftFloatLib|ArmPkg/Library/ArmSoftFloatLib/ArmSoftFloatLib.inf

+[LibraryClasses.AARCH64]
+ MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
+
[BuildOptions]
RVCT:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG

--
2.31.1


[RFC] [PATCH 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct

Rebecca Cran <rebecca@...>
 

Remove the ClusterId and CoreId fields in the ARM_CORE_INFO structure in
favor of a new Mpidr field. Update code in
ArmPlatformPkg/PrePeiCore/MainMPCore and ArmPlatformPkg/PrePi/MainMPCore.c
to use the new field and call new macros GET_MPIDR_AFF0 and GET_MPIDR_AFF1
instead.

Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
---
ArmPkg/Include/Guid/ArmMpCoreInfo.h | 3 +--
ArmPkg/Include/Library/ArmLib.h | 4 ++++
ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c | 8 ++++----
ArmPlatformPkg/PrePeiCore/MainMPCore.c | 2 +-
ArmPlatformPkg/PrePi/MainMPCore.c | 2 +-
5 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/ArmPkg/Include/Guid/ArmMpCoreInfo.h b/ArmPkg/Include/Guid/ArmMpCoreInfo.h
index b810767879ae..04c44650ebf5 100644
--- a/ArmPkg/Include/Guid/ArmMpCoreInfo.h
+++ b/ArmPkg/Include/Guid/ArmMpCoreInfo.h
@@ -14,8 +14,7 @@
#define MPIDR_U_BIT_MASK 0x40000000

typedef struct {
- UINT32 ClusterId;
- UINT32 CoreId;
+ UINT64 Mpidr;

// MP Core Mailbox
EFI_PHYSICAL_ADDRESS MailboxSetAddress;
diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h
index 79ea755777a9..d764cc670970 100644
--- a/ArmPkg/Include/Library/ArmLib.h
+++ b/ArmPkg/Include/Library/ArmLib.h
@@ -107,6 +107,10 @@ typedef enum {
#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK)
#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8)
#define GET_MPID(ClusterId, CoreId) (((ClusterId) << 8) | (CoreId))
+#define GET_MPIDR_AFF0(MpId) ((MpId) & ARM_CORE_AFF0)
+#define GET_MPIDR_AFF1(MpId) (((MpId) & ARM_CORE_AFF1) >> 8)
+#define GET_MPIDR_AFF2(MpId) (((MpId) & ARM_CORE_AFF2) >> 16)
+#define GET_MPIDR_AFF3(MpId) (((MpId) & ARM_CORE_AFF3) >> 32)
#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK)

/** Reads the CCSIDR register for the specified cache.
diff --git a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c
index 1cd9ec30a977..6630cb68452c 100644
--- a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c
+++ b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c
@@ -15,7 +15,7 @@
ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
{
// Cluster 0, Core 0
- 0x0, 0x0,
+ 0x0,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
@@ -25,7 +25,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
},
{
// Cluster 0, Core 1
- 0x0, 0x1,
+ 0x1,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
@@ -35,7 +35,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
},
{
// Cluster 0, Core 2
- 0x0, 0x2,
+ 0x2,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
@@ -45,7 +45,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
},
{
// Cluster 0, Core 3
- 0x0, 0x3,
+ 0x3,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
diff --git a/ArmPlatformPkg/PrePeiCore/MainMPCore.c b/ArmPlatformPkg/PrePeiCore/MainMPCore.c
index 859f1adf2078..5f8a268bf664 100644
--- a/ArmPlatformPkg/PrePeiCore/MainMPCore.c
+++ b/ArmPlatformPkg/PrePeiCore/MainMPCore.c
@@ -65,7 +65,7 @@ SecondaryMain (

// Find the core in the ArmCoreTable
for (Index = 0; Index < ArmCoreCount; Index++) {
- if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) {
+ if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) {
break;
}
}
diff --git a/ArmPlatformPkg/PrePi/MainMPCore.c b/ArmPlatformPkg/PrePi/MainMPCore.c
index 091464df2aa9..6497a1ad27fd 100644
--- a/ArmPlatformPkg/PrePi/MainMPCore.c
+++ b/ArmPlatformPkg/PrePi/MainMPCore.c
@@ -64,7 +64,7 @@ SecondaryMain (

// Find the core in the ArmCoreTable
for (Index = 0; Index < ArmCoreCount; Index++) {
- if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) {
+ if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) {
break;
}
}
--
2.31.1


[RFC] [PATCH 0/2] Proposal to add EFI_MP_SERVICES_PROTOCOL support for AARCH64

Rebecca Cran <rebecca@...>
 

I'd like to propose adding EFI_MP_SERVICES_PROTOCOL support for
AARCH64 systems. I've attached two patches to implement support for it
in the DXE phase, based on code in EmulatorPkg and UefiCpuPkg. It's added
under ArmPkg for now, but longer term it should probably be moved into
UefiCpuPkg.

Patch 1/2 is the start of addressing the issue that the Aff0 field of
the MPIDR is no longer guaranteed to be the core, and should be referred
to in a more generic way: for example it could be the thread, with Aff1
being the core and Aff2 the cluster. Clearly much more work is needed
to fully remove that assumption.

Patch 2/2 implements the EFI_MP_SERVICES_PROTOCOL for DXE in Library/MpInitLib.
CpuDxe initializes the MP support, and as a result gains a dependency on
MpInitLib. ArmVirt.dsc.inc needs updated to add the new library, as will
all AARCH64 platforms.

I sent out a patch for MdeModulePkg last week to add a corresponding test
application, MpServicesTest (see https://edk2.groups.io/g/devel/message/80878).

Rebecca Cran (2):
ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO
struct
ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL

ArmPkg/ArmPkg.dec | 4 +
ArmPkg/ArmPkg.dsc | 4 +
ArmPkg/Drivers/CpuDxe/AArch64/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/Arm/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 +
ArmPkg/Drivers/CpuDxe/CpuDxe.h | 10 +
ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 6 +
ArmPkg/Drivers/CpuDxe/CpuMpInit.c | 604 ++++++++
ArmPkg/Include/Guid/ArmMpCoreInfo.h | 3 +-
ArmPkg/Include/Library/ArmLib.h | 4 +
ArmPkg/Include/Library/MpInitLib.h | 366 +++++
ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S | 61 +
ArmPkg/Library/MpInitLib/DxeMpInitLib.inf | 53 +
ArmPkg/Library/MpInitLib/DxeMpLib.c | 1498 ++++++++++++++++++++
ArmPkg/Library/MpInitLib/InternalMpInitLib.h | 358 +++++
ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c | 8 +-
ArmPlatformPkg/PrePeiCore/MainMPCore.c | 2 +-
ArmPlatformPkg/PrePi/MainMPCore.c | 2 +-
ArmVirtPkg/ArmVirt.dsc.inc | 3 +
19 files changed, 3024 insertions(+), 8 deletions(-)
create mode 100644 ArmPkg/Drivers/CpuDxe/AArch64/Arch.c
create mode 100644 ArmPkg/Drivers/CpuDxe/Arm/Arch.c
create mode 100644 ArmPkg/Drivers/CpuDxe/CpuMpInit.c
create mode 100644 ArmPkg/Include/Library/MpInitLib.h
create mode 100644 ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S
create mode 100644 ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
create mode 100644 ArmPkg/Library/MpInitLib/DxeMpLib.c
create mode 100644 ArmPkg/Library/MpInitLib/InternalMpInitLib.h

--
2.31.1


Re: [PATCH V7 1/1] OvmfPkg: Enable TDX in ResetVector

Min Xu
 

On September 24, 2021 6:58 PM, Brijesh Singh wrote:
Hi Min,

On 9/21/21 4:05 AM, Min Xu wrote:
;
; Modified: EAX, EBX, ECX, EDX
;
SetCr3ForPageTables64:
-
- ; Clear the WorkArea header. The SEV probe routines will populate the
- ; work area when detected.
- mov byte[WORK_AREA_GUEST_TYPE], 0
Why you are removing the above block ? The workarea hdr must be initialized
to zero, its not safe to assume that the guest memory is zero'ed in the non-
encrypted case.
Hi, Brijesh
Please see below explanation (It is in the commit message)
- In Main16 entry point, after TransitionFromReal16To32BitFlat,
WORK_AREA_GUEST_TYPE is cleared to 0. WORK_AREA_GUEST_TYPE was
previously cleared in SetCr3ForPageTables64 (see commit ab77b60).
This doesn't work after TDX is introduced in Ovmf. It is because all
TDX CPUs (BSP and APs) start to run from 0xfffffff0. In previous code
WORK_AREA_GUEST_TYPE will be cleared multi-times in TDX guest. So for
SEV and Legacy guest it is moved to Main16 entry point (after
TransitionFromReal16To32BitFlat). For TDX guest WORK_AREA_GUEST_TYPE
is cleared and set in InitTdxWorkarea
Thanks!
Min


Re: [PATCH 1/2] MdePkg: Introduce TdProtocol for TD-Guest firmware

Yao, Jiewen
 

Hi Liming
We just published the GHCI spec version 1.0 revision 002 at https://software.intel.com/content/dam/develop/external/us/en/documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-002.pdf

4.3.2 include the EFI_TD_PROTOCOL.

Thank you
Yao Jiewen

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of gaoliming
Sent: Wednesday, September 15, 2021 1:50 PM
To: devel@edk2.groups.io; Xu, Min M <min.m.xu@intel.com>
Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Liu, Zhiguang
<zhiguang.liu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Wang, Jian J
<jian.j.wang@intel.com>; Lu, Ken <ken.lu@intel.com>
Subject: 回复: [edk2-devel] [PATCH 1/2] MdePkg: Introduce TdProtocol for TD-
Guest firmware

Min:
Which public spec defines this new protocol?

Thanks
Liming
-----邮件原件-----
发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Min Xu
发送时间: 2021年9月14日 9:57
收件人: devel@edk2.groups.io
抄送: Min Xu <min.m.xu@intel.com>; Michael D Kinney
<michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
Zhiguang Liu <zhiguang.liu@intel.com>; Jiewen Yao <jiewen.yao@intel.com>;
Jian J Wang <jian.j.wang@intel.com>; Ken Lu <ken.lu@intel.com>
主题: [edk2-devel] [PATCH 1/2] MdePkg: Introduce TdProtocol for TD-Guest
firmware

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3625

If TD-Guest firmware supports measurement and an event is created,
TD-Guest firmware is designed to report the event log with the same data
structure in TCG-Platform-Firmware-Profile specification with
EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 format.

The TD-Guest firmware supports measurement, the TD Guest Firmware is
designed to produce EFI_TD_PROTOCOL with new GUID
EFI_TD_PROTOCOL_GUID
to report event log and provides hash capability.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ken Lu <ken.lu@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/Protocol/TdProtocol.h | 305
+++++++++++++++++++++++++++
MdePkg/MdePkg.dec | 3 +
2 files changed, 308 insertions(+)
create mode 100644 MdePkg/Include/Protocol/TdProtocol.h

diff --git a/MdePkg/Include/Protocol/TdProtocol.h
b/MdePkg/Include/Protocol/TdProtocol.h
new file mode 100644
index 000000000000..5a015fca0079
--- /dev/null
+++ b/MdePkg/Include/Protocol/TdProtocol.h
@@ -0,0 +1,305 @@
+/** @file
+ If TD-Guest firmware supports measurement and an event is created,
TD-Guest
+ firmware is designed to report the event log with the same data
structure
+ in TCG-Platform-Firmware-Profile specification with
+ EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 format.
+
+ The TD-Guest firmware supports measurement, the TD Guest Firmware is
designed
+ to produce EFI_TD_PROTOCOL with new GUID EFI_TD_PROTOCOL_GUID
to report
+ event log and provides hash capability.
+
+Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef TD_PROTOCOL_H_
+#define TD_PROTOCOL_H_
+
+#include <Uefi/UefiBaseType.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <IndustryStandard/Tpm20.h>
+
+
+#define EFI_TD_PROTOCOL_GUID \
+ { 0x96751a3d, 0x72f4, 0x41a6, { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67,
0xae,
0x6b }}
+extern EFI_GUID gEfiTdProtocolGuid;
+
+typedef struct _EFI_TD_PROTOCOL EFI_TD_PROTOCOL;
+
+typedef struct {
+ UINT8 Major;
+ UINT8 Minor;
+} EFI_TD_VERSION;
+
+typedef UINT32 EFI_TD_EVENT_LOG_BITMAP;
+typedef UINT32 EFI_TD_EVENT_LOG_FORMAT;
+typedef UINT32
EFI_TD_EVENT_ALGORITHM_BITMAP;
+typedef UINT32 EFI_TD_MR_INDEX;
+
+#define EFI_TD_EVENT_LOG_FORMAT_TCG_2 0x00000002
+#define EFI_TD_BOOT_HASH_ALG_SHA384 0x00000004
+
+//
+// This bit is shall be set when an event shall be extended but not
logged.
+//
+#define EFI_TD_FLAG_EXTEND_ONLY 0x0000000000000001
+//
+// This bit shall be set when the intent is to measure a PE/COFF image.
+//
+#define EFI_TD_FLAG_PE_COFF_IMAGE 0x0000000000000010
+
+#define MR_INDEX_MRTD 0
+#define MR_INDEX_RTMR0 1
+#define MR_INDEX_RTMR1 2
+#define MR_INDEX_RTMR2 3
+#define MR_INDEX_RTMR3 4
+
+//
+// This bit shall be set when the intent is to measure a PE/COFF image.
+//
+#define PE_COFF_IMAGE 0x0000000000000010
+
+#pragma pack (1)
+
+#define EFI_TD_EVENT_HEADER_VERSION 1
+
+typedef struct {
+ //
+ // Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)).
+ //
+ UINT32 HeaderSize;
+ //
+ // Header version. For this version of this specification, the value
shall be
1.
+ //
+ UINT16 HeaderVersion;
+ //
+ // Index of the MR that shall be extended.
+ //
+ EFI_TD_MR_INDEX MrIndex;
+ //
+ // Type of the event that shall be extended (and optionally logged).
+ //
+ UINT32 EventType;
+} EFI_TD_EVENT_HEADER;
+
+typedef struct {
+ //
+ // Total size of the event including the Size component, the header and
the
Event data.
+ //
+ UINT32 Size;
+ EFI_TD_EVENT_HEADER Header;
+ UINT8 Event[1];
+} EFI_TD_EVENT;
+
+#pragma pack()
+
+
+typedef struct {
+ //
+ // Allocated size of the structure
+ //
+ UINT8 Size;
+ //
+ // Version of the EFI_TD_BOOT_SERVICE_CAPABILITY structure itself.
+ // For this version of the protocol, the Major version shall be set to
1
+ // and the Minor version shall be set to 1.
+ //
+ EFI_TD_VERSION StructureVersion;
+ //
+ // Version of the EFI TD protocol.
+ // For this version of the protocol, the Major version shall be set to
1
+ // and the Minor version shall be set to 1.
+ //
+ EFI_TD_VERSION ProtocolVersion;
+ //
+ // Supported hash algorithms
+ //
+ EFI_TD_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
+ //
+ // Bitmap of supported event log formats
+ //
+ EFI_TD_EVENT_LOG_BITMAP SupportedEventLogs;
+
+ //
+ // False = TD not present
+ //
+ BOOLEAN TdPresentFlag;
+} EFI_TD_BOOT_SERVICE_CAPABILITY;
+
+/**
+ The EFI_TD_PROTOCOL GetCapability function call provides protocol
+ capability information and state information.
+
+ @param[in] This Indicates the calling context
+ @param[in, out] ProtocolCapability The caller allocates memory for a
EFI_TD_BOOT_SERVICE_CAPABILITY
+ structure and sets the size
field to the size of the structure allocated.
+ The callee fills in the fields
with the EFI protocol capability information
+ and the current EFI TD state
information up to the number of fields which
+ fit within the size of the
structure passed in.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ The ProtocolCapability variable will
not be populated.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are
incorrect.
+ The ProtocolCapability variable will
not be populated.
+ @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is
too small to hold the full response.
+ It will be partially populated
(required Size field will be set).
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TD_GET_CAPABILITY) (
+ IN EFI_TD_PROTOCOL *This,
+ IN OUT EFI_TD_BOOT_SERVICE_CAPABILITY *ProtocolCapability
+ );
+
+/**
+ The EFI_TD_PROTOCOL Get Event Log function call allows a caller to
+ retrieve the address of a given event log and its last entry.
+
+ @param[in] This Indicates the calling context
+ @param[in] EventLogFormat The type of the event log for which
the information is requested.
+ @param[out] EventLogLocation A pointer to the memory address of
the event log.
+ @param[out] EventLogLastEntry If the Event Log contains more than
one entry, this is a pointer to the
+ address of the start of the last
entry in the event log in memory.
+ @param[out] EventLogTruncated If the Event Log is missing at least one
entry because an event would
+ have exceeded the area allocated
for events, this value is set to TRUE.
+ Otherwise, the value will be FALSE
and the Event Log will be complete.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are
incorrect
+ (e.g. asking for an event log whose
format is not supported).
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TD_GET_EVENT_LOG) (
+ IN EFI_TD_PROTOCOL *This,
+ IN EFI_TD_EVENT_LOG_FORMAT EventLogFormat,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry,
+ OUT BOOLEAN *EventLogTruncated
+ );
+
+/**
+ The EFI_TD_PROTOCOL HashLogExtendEvent function call provides callers
with
+ an opportunity to extend and optionally log events without requiring
+ knowledge of actual TD commands.
+ The extend operation will occur even if this function cannot create an
event
+ log entry (e.g. due to the event log being full).
+
+ @param[in] This Indicates the calling context
+ @param[in] Flags Bitmap providing additional
information.
+ @param[in] DataToHash Physical address of the start of the
data buffer to be hashed.
+ @param[in] DataToHashLen The length in bytes of the buffer
referenced by DataToHash.
+ @param[in] EfiTdEvent Pointer to data buffer containing
information about the event.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_VOLUME_FULL The extend operation occurred, but
the event could not be written to one or more event logs.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are
incorrect.
+ @retval EFI_UNSUPPORTED The PE/COFF image type is not
supported.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_TD_HASH_LOG_EXTEND_EVENT) (
+ IN EFI_TD_PROTOCOL *This,
+ IN UINT64 Flags,
+ IN EFI_PHYSICAL_ADDRESS DataToHash,
+ IN UINT64 DataToHashLen,
+ IN EFI_TD_EVENT *EfiTdEvent
+ );
+
+/**
+ The EFI_TD_PROTOCOL MapPcrToMrIndex function call provides callers
+ the info on TPM PCR<-> measurement register mapping information.
+
+ In current version, we use below mapping:
+ PCR0 -> MRTD (Index 0)
+ PCR1 -> RTMR0 (Index 1)
+ PCR2~6 -> RTMR1 (Index 2)
+ PCR7 -> RTMR0 (Index 1)
+ PCR8~15 -> RTMR2 (Index 3)
+
+ @param[in] This Indicates the calling context
+ @param[in] PcrIndex TPM PCR index.
+ @param[out] MrIndex Measurement register index.
+
+ @retval EFI_SUCCESS The MR index is returned.
+ @retval EFI_INVALID_PARAMETER The MrIndex is NULL.
+ @retval EFI_UNSUPPORTED The PcrIndex is invalid.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_TD_MAP_PCR_TO_MR_INDEX) (
+ IN EFI_TD_PROTOCOL *This,
+ IN TCG_PCRINDEX PcrIndex,
+ OUT EFI_TD_MR_INDEX *MrIndex
+ );
+
+struct _EFI_TD_PROTOCOL {
+ EFI_TD_GET_CAPABILITY GetCapability;
+ EFI_TD_GET_EVENT_LOG GetEventLog;
+ EFI_TD_HASH_LOG_EXTEND_EVENT
HashLogExtendEvent;
+ EFI_TD_MAP_PCR_TO_MR_INDEX MapPcrToMrIndex;
+};
+
+
+//
+// TD event log
+//
+
+#pragma pack(1)
+
+//
+// Crypto Agile Log Entry Format.
+// It is similar with TCG_PCR_EVENT2 except the field of MrIndex and
PCRIndex.
+//
+typedef struct {
+ EFI_TD_MR_INDEX MrIndex;
+ UINT32 EventType;
+ TPML_DIGEST_VALUES Digests;
+ UINT32 EventSize;
+ UINT8 Event[1];
+} TD_EVENT;
+
+//
+// EFI TD Event Header
+// It is similar with TCG_PCR_EVENT2_HDR except the field of MrIndex and
PCRIndex
+//
+typedef struct {
+ EFI_TD_MR_INDEX MrIndex;
+ UINT32 EventType;
+ TPML_DIGEST_VALUES Digests;
+ UINT32 EventSize;
+} TD_EVENT_HDR;
+
+#pragma pack()
+
+//
+// Log entries after Get Event Log service
+//
+
+
+typedef struct {
+ //
+ // The version of this structure. It shall be set ot 1.
+ //
+ UINT64 Version;
+ //
+ // Number of events recorded after invocation of GetEventLog API
+ //
+ UINT64 NumberOfEvents;
+ //
+ // List of events of type TCG_TD_EVENT.
+ //
+ //TD_EVENT Event[1];
+} EFI_TD_FINAL_EVENTS_TABLE;
+
+
+#define EFI_TD_FINAL_EVENTS_TABLE_GUID \
+ {0xdd4a4648, 0x2de7, 0x4665, {0x96, 0x4d, 0x21, 0xd9, 0xef, 0x5f, 0xb4,
0x46}}
+
+extern EFI_GUID gEfiTdFinalEventsTableGuid;
+
+#endif
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index a28a2daaffa8..2f48f6c40c1e 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -1008,6 +1008,9 @@
## Include/Protocol/PcdInfo.h
gGetPcdInfoProtocolGuid = { 0x5be40f57, 0xfa68, 0x4610, { 0xbb,
0xbf, 0xe9, 0xc5, 0xfc, 0xda, 0xd3, 0x65 } }

+ ## Include/Protocol/TdProtocol.h
+ gEfiTdProtocolGuid = { 0x96751a3d, 0x72f4, 0x41a6, { 0xa7,
0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b }}
+
#
# Protocols defined in PI1.0.
#
--
2.29.2.windows.2










[edk2-platforms][PATCH v2 1/1] MinPlatformPkg/AcpiTables: Update structures for ACPI 6.3

Michael Kubacki
 

From: Daniel Maddy <danmad@microsoft.com>

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3D3535

Updates ACPI table structures in MinPlatformPkg for ACPI 6.3.

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Daniel Maddy <danmad@microsoft.com>
Co-authored-by: Michael Kubacki <michael.kubacki@microsoft.com>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c | 181 +++++=
+++++----------
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c | 11 +-
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c | 74 ++++-=
---
3 files changed, 138 insertions(+), 128 deletions(-)

diff --git a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c=
b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c
index 843ba832ce67..f5c4f2c3f1a9 100644
--- a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c
+++ b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c
@@ -2,6 +2,7 @@
ACPI Platform Driver
=20
Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
=20
**/
@@ -11,7 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#pragma pack(1)
=20
typedef struct {
- UINT32 AcpiProcessorId;
+ UINT32 AcpiProcessorUid;
UINT32 ApicId;
UINT32 Flags;
UINT32 SocketNum;
@@ -25,9 +26,9 @@ typedef struct {
// Define Union of IO APIC & Local APIC structure;
//
typedef union {
- EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE AcpiLocalApic;
- EFI_ACPI_4_0_IO_APIC_STRUCTURE AcpiIoApic;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE AcpiLocalx2Apic;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE AcpiLocalApic;
+ EFI_ACPI_6_3_IO_APIC_STRUCTURE AcpiIoApic;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE AcpiLocalx2Apic;
struct {
UINT8 Type;
UINT8 Length;
@@ -36,9 +37,9 @@ typedef union {
=20
#pragma pack()
=20
-extern EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs;
-extern EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt;
-extern EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER Hpet;
+extern EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs;
+extern EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE Fadt;
+extern EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER Hpet;
extern EFI_ACPI_WSMT_TABLE Wsmt;
=20
VOID *mLocalTable[] =3D {
@@ -103,7 +104,7 @@ DebugDisplayReOrderTable (
for (Index =3D 0; Index < mNumberOfCpus; Index++) {
DEBUG ((DEBUG_INFO, " %02d 0x%02X 0x%02X %d %d=
%d\n",
Index,
- CpuApicIdOrderTable[Index].AcpiProcessorId,
+ CpuApicIdOrderTable[Index].AcpiProcessorUid,
CpuApicIdOrderTable[Index].ApicId,
CpuApicIdOrderTable[Index].Thread,
CpuApicIdOrderTable[Index].Flags,
@@ -118,31 +119,31 @@ AppendCpuMapTableEntry (
)
{
EFI_STATUS Status;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApicPtr;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE *LocalX2ApicPtr;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApicPtr;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE *LocalX2ApicPtr;
UINT8 Type;
=20
Status =3D EFI_SUCCESS;
Type =3D ((ACPI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiApicCommon.Type;
- LocalApicPtr =3D (EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE *)(&((AC=
PI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalApic);
- LocalX2ApicPtr =3D (EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)(&=
((ACPI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalx2Apic);
+ LocalApicPtr =3D (EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE *)(&((AC=
PI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalApic);
+ LocalX2ApicPtr =3D (EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)(&=
((ACPI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalx2Apic);
=20
- if(Type =3D=3D EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC) {
+ if(Type =3D=3D EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC) {
if(!mX2ApicEnabled) {
- LocalApicPtr->Flags =3D (UINT8)mCpuApicIdOrderTable[Loca=
lApicCounter].Flags;
- LocalApicPtr->ApicId =3D (UINT8)mCpuApicIdOrderTable[Loca=
lApicCounter].ApicId;
- LocalApicPtr->AcpiProcessorId =3D (UINT8)mCpuApicIdOrderTable[Loca=
lApicCounter].AcpiProcessorId;
+ LocalApicPtr->Flags =3D (UINT8)mCpuApicIdOrderTable[Loc=
alApicCounter].Flags;
+ LocalApicPtr->ApicId =3D (UINT8)mCpuApicIdOrderTable[Loc=
alApicCounter].ApicId;
+ LocalApicPtr->AcpiProcessorUid =3D (UINT8)mCpuApicIdOrderTable[Loc=
alApicCounter].AcpiProcessorUid;
} else {
- LocalApicPtr->Flags =3D 0;
- LocalApicPtr->ApicId =3D 0xFF;
- LocalApicPtr->AcpiProcessorId =3D (UINT8)0xFF;
+ LocalApicPtr->Flags =3D 0;
+ LocalApicPtr->ApicId =3D 0xFF;
+ LocalApicPtr->AcpiProcessorUid =3D (UINT8)0xFF;
Status =3D EFI_UNSUPPORTED;
}
- } else if(Type =3D=3D EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC) {
+ } else if(Type =3D=3D EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC) {
if(mX2ApicEnabled) {
LocalX2ApicPtr->Flags =3D (UINT8)mCpuApicIdOrderTable[L=
ocalApicCounter].Flags;
LocalX2ApicPtr->X2ApicId =3D mCpuApicIdOrderTable[LocalApi=
cCounter].ApicId;
- LocalX2ApicPtr->AcpiProcessorUid =3D mCpuApicIdOrderTable[LocalApi=
cCounter].AcpiProcessorId;
+ LocalX2ApicPtr->AcpiProcessorUid =3D mCpuApicIdOrderTable[LocalApi=
cCounter].AcpiProcessorUid;
} else {
LocalX2ApicPtr->Flags =3D 0;
LocalX2ApicPtr->X2ApicId =3D (UINT32)-1;
@@ -201,15 +202,15 @@ SortCpuLocalApicInTable (
//update processorbitMask
if (CpuIdMapPtr->Flags =3D=3D 1) {
if (mForceX2ApicId) {
- CpuIdMapPtr->SocketNum &=3D 0x7;
- CpuIdMapPtr->AcpiProcessorId &=3D 0xFF; //keep lower 8bit due =
to use Proc obj in dsdt
+ CpuIdMapPtr->SocketNum &=3D 0x7;
+ CpuIdMapPtr->AcpiProcessorUid &=3D 0xFF; //keep lower 8bit due=
to use Proc obj in dsdt
}
}
} else { //not enabled
- CpuIdMapPtr->ApicId =3D (UINT32)-1;
- CpuIdMapPtr->Thread =3D (UINT32)-1;
- CpuIdMapPtr->Flags =3D 0;
- CpuIdMapPtr->SocketNum =3D (UINT32)-1;
+ CpuIdMapPtr->ApicId =3D (UINT32)-1;
+ CpuIdMapPtr->Thread =3D (UINT32)-1;
+ CpuIdMapPtr->Flags =3D 0;
+ CpuIdMapPtr->SocketNum =3D (UINT32)-1;
} //end if PROC ENABLE
} //end for CurrentProcessor
=20
@@ -280,12 +281,12 @@ SortCpuLocalApicInTable (
}
=20
//
- // 5. Re-assigen AcpiProcessorId for AcpiProcessorUId uses purpose.
+ // 5. Re-assign AcpiProcessorId for AcpiProcessorUid uses purpose.
//
for (Socket =3D 0; Socket < FixedPcdGet32 (PcdMaxCpuSocketCount); Sock=
et++) {
for (CurrProcessor =3D 0, Index =3D 0; CurrProcessor < mNumberOfCpus=
; CurrProcessor++) {
if (mCpuApicIdOrderTable[CurrProcessor].Flags && (mCpuApicIdOrderT=
able[CurrProcessor].SocketNum =3D=3D Socket)) {
- mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId =3D (Process=
orInfoBuffer.Location.Package << mNumOfBitShift) + Index;
+ mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorUid =3D (Proces=
sorInfoBuffer.Location.Package << mNumOfBitShift) + Index;
Index++;
}
}
@@ -312,17 +313,17 @@ typedef struct {
} STRUCTURE_HEADER;
=20
STRUCTURE_HEADER mMadtStructureTable[] =3D {
- {EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC, sizeof (EFI_ACPI_4_0_PROC=
ESSOR_LOCAL_APIC_STRUCTURE)},
- {EFI_ACPI_4_0_IO_APIC, sizeof (EFI_ACPI_4_0_IO_A=
PIC_STRUCTURE)},
- {EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE, sizeof (EFI_ACPI_4_0_INTE=
RRUPT_SOURCE_OVERRIDE_STRUCTURE)},
- {EFI_ACPI_4_0_NON_MASKABLE_INTERRUPT_SOURCE, sizeof (EFI_ACPI_4_0_NON_=
MASKABLE_INTERRUPT_SOURCE_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_APIC_NMI, sizeof (EFI_ACPI_4_0_LOCA=
L_APIC_NMI_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_APIC_ADDRESS_OVERRIDE, sizeof (EFI_ACPI_4_0_LOCA=
L_APIC_ADDRESS_OVERRIDE_STRUCTURE)},
- {EFI_ACPI_4_0_IO_SAPIC, sizeof (EFI_ACPI_4_0_IO_S=
APIC_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_SAPIC, sizeof (EFI_ACPI_4_0_PROC=
ESSOR_LOCAL_SAPIC_STRUCTURE)},
- {EFI_ACPI_4_0_PLATFORM_INTERRUPT_SOURCES, sizeof (EFI_ACPI_4_0_PLAT=
FORM_INTERRUPT_SOURCES_STRUCTURE)},
- {EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC, sizeof (EFI_ACPI_4_0_PROC=
ESSOR_LOCAL_X2APIC_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_X2APIC_NMI, sizeof (EFI_ACPI_4_0_LOCA=
L_X2APIC_NMI_STRUCTURE)}
+ {EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC, sizeof (EFI_ACPI_6_3_PROC=
ESSOR_LOCAL_APIC_STRUCTURE)},
+ {EFI_ACPI_6_3_IO_APIC, sizeof (EFI_ACPI_6_3_IO_A=
PIC_STRUCTURE)},
+ {EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE, sizeof (EFI_ACPI_6_3_INTE=
RRUPT_SOURCE_OVERRIDE_STRUCTURE)},
+ {EFI_ACPI_6_3_NON_MASKABLE_INTERRUPT_SOURCE, sizeof (EFI_ACPI_6_3_NON_=
MASKABLE_INTERRUPT_SOURCE_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_APIC_NMI, sizeof (EFI_ACPI_6_3_LOCA=
L_APIC_NMI_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_APIC_ADDRESS_OVERRIDE, sizeof (EFI_ACPI_6_3_LOCA=
L_APIC_ADDRESS_OVERRIDE_STRUCTURE)},
+ {EFI_ACPI_6_3_IO_SAPIC, sizeof (EFI_ACPI_6_3_IO_S=
APIC_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_SAPIC, sizeof (EFI_ACPI_6_3_PROC=
ESSOR_LOCAL_SAPIC_STRUCTURE)},
+ {EFI_ACPI_6_3_PLATFORM_INTERRUPT_SOURCES, sizeof (EFI_ACPI_6_3_PLAT=
FORM_INTERRUPT_SOURCES_STRUCTURE)},
+ {EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC, sizeof (EFI_ACPI_6_3_PROC=
ESSOR_LOCAL_X2APIC_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_X2APIC_NMI, sizeof (EFI_ACPI_6_3_LOCA=
L_X2APIC_NMI_STRUCTURE)}
};
=20
/**
@@ -481,7 +482,7 @@ InitializeHeader (
**/
EFI_STATUS
InitializeMadtHeader (
- IN OUT EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader
+ IN OUT EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader
)
{
EFI_STATUS Status;
@@ -493,8 +494,8 @@ InitializeMadtHeader (
=20
Status =3D InitializeHeader (
&MadtHeader->Header,
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
0
);
if (EFI_ERROR (Status)) {
@@ -502,7 +503,7 @@ InitializeMadtHeader (
}
=20
MadtHeader->LocalApicAddress =3D PcdGet32(PcdLocalApicAddress);
- MadtHeader->Flags =3D EFI_ACPI_4_0_PCAT_COMPAT;
+ MadtHeader->Flags =3D EFI_ACPI_6_3_PCAT_COMPAT;
=20
return EFI_SUCCESS;
}
@@ -539,7 +540,7 @@ CopyStructure (
//
// Initialize the number of table entries and the table based on the t=
able header passed in.
//
- if (Header->Signature =3D=3D EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TA=
BLE_SIGNATURE) {
+ if (Header->Signature =3D=3D EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TA=
BLE_SIGNATURE) {
TableNumEntries =3D sizeof (mMadtStructureTable) / sizeof (STRUCTURE=
_HEADER);
StructureTable =3D mMadtStructureTable;
} else {
@@ -649,7 +650,7 @@ BuildAcpiTable (
return EFI_INVALID_PARAMETER;
}
=20
- if (AcpiHeader->Signature !=3D EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_=
TABLE_SIGNATURE) {
+ if (AcpiHeader->Signature !=3D EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_=
TABLE_SIGNATURE) {
DEBUG ((
DEBUG_ERROR,
"MADT header signature is expected, actually 0x%08x\n",
@@ -740,15 +741,15 @@ InstallMadtFromScratch (
{
EFI_STATUS Status;
UINTN Index;
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *NewMadtTable;
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *NewMadtTable;
UINTN TableHandle;
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER MadtTableHeader;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE ProcLocalApicStruc=
t;
- EFI_ACPI_4_0_IO_APIC_STRUCTURE IoApicStruct;
- EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE IntSrcOverrideStru=
ct;
- EFI_ACPI_4_0_LOCAL_APIC_NMI_STRUCTURE LocalApciNmiStruct=
;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE ProcLocalX2ApicStr=
uct;
- EFI_ACPI_4_0_LOCAL_X2APIC_NMI_STRUCTURE LocalX2ApicNmiStru=
ct;
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER MadtTableHeader;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE ProcLocalApicStruc=
t;
+ EFI_ACPI_6_3_IO_APIC_STRUCTURE IoApicStruct;
+ EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE IntSrcOverrideStru=
ct;
+ EFI_ACPI_6_3_LOCAL_APIC_NMI_STRUCTURE LocalApciNmiStruct=
;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE ProcLocalX2ApicStr=
uct;
+ EFI_ACPI_6_3_LOCAL_X2APIC_NMI_STRUCTURE LocalX2ApicNmiStru=
ct;
STRUCTURE_HEADER **MadtStructs;
UINTN MaxMadtStructCount=
;
UINTN MadtStructsIndex;
@@ -809,11 +810,11 @@ InstallMadtFromScratch (
//
// Build Processor Local APIC Structures and Processor Local X2APIC St=
ructures
//
- ProcLocalApicStruct.Type =3D EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC;
- ProcLocalApicStruct.Length =3D sizeof (EFI_ACPI_4_0_PROCESSOR_LOCAL_AP=
IC_STRUCTURE);
+ ProcLocalApicStruct.Type =3D EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC;
+ ProcLocalApicStruct.Length =3D sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_AP=
IC_STRUCTURE);
=20
- ProcLocalX2ApicStruct.Type =3D EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC;
- ProcLocalX2ApicStruct.Length =3D sizeof (EFI_ACPI_4_0_PROCESSOR_LOCAL_=
X2APIC_STRUCTURE);
+ ProcLocalX2ApicStruct.Type =3D EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC;
+ ProcLocalX2ApicStruct.Length =3D sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_=
X2APIC_STRUCTURE);
ProcLocalX2ApicStruct.Reserved[0] =3D 0;
ProcLocalX2ApicStruct.Reserved[1] =3D 0;
=20
@@ -824,9 +825,9 @@ InstallMadtFromScratch (
// use a processor local x2APIC structure.
//
if (!mX2ApicEnabled && mCpuApicIdOrderTable[Index].ApicId < MAX_UINT=
8) {
- ProcLocalApicStruct.Flags =3D (UINT8) mCpuApicIdOrderTab=
le[Index].Flags;
- ProcLocalApicStruct.ApicId =3D (UINT8) mCpuApicIdOrderTab=
le[Index].ApicId;
- ProcLocalApicStruct.AcpiProcessorId =3D (UINT8) mCpuApicIdOrderTab=
le[Index].AcpiProcessorId;
+ ProcLocalApicStruct.Flags =3D (UINT8) mCpuApicIdOrderTa=
ble[Index].Flags;
+ ProcLocalApicStruct.ApicId =3D (UINT8) mCpuApicIdOrderTa=
ble[Index].ApicId;
+ ProcLocalApicStruct.AcpiProcessorUid =3D (UINT8) mCpuApicIdOrderTa=
ble[Index].AcpiProcessorUid;
=20
ASSERT (MadtStructsIndex < MaxMadtStructCount);
Status =3D CopyStructure (
@@ -837,7 +838,7 @@ InstallMadtFromScratch (
} else if (mCpuApicIdOrderTable[Index].ApicId !=3D 0xFFFFFFFF) {
ProcLocalX2ApicStruct.Flags =3D (UINT8) mCpuApicIdOrder=
Table[Index].Flags;
ProcLocalX2ApicStruct.X2ApicId =3D mCpuApicIdOrderTable[In=
dex].ApicId;
- ProcLocalX2ApicStruct.AcpiProcessorUid =3D mCpuApicIdOrderTable[In=
dex].AcpiProcessorId;
+ ProcLocalX2ApicStruct.AcpiProcessorUid =3D mCpuApicIdOrderTable[In=
dex].AcpiProcessorUid;
=20
ASSERT (MadtStructsIndex < MaxMadtStructCount);
Status =3D CopyStructure (
@@ -855,8 +856,8 @@ InstallMadtFromScratch (
//
// Build I/O APIC Structures
//
- IoApicStruct.Type =3D EFI_ACPI_4_0_IO_APIC;
- IoApicStruct.Length =3D sizeof (EFI_ACPI_4_0_IO_APIC_STRUCTURE);
+ IoApicStruct.Type =3D EFI_ACPI_6_3_IO_APIC;
+ IoApicStruct.Length =3D sizeof (EFI_ACPI_6_3_IO_APIC_STRUCTURE);
IoApicStruct.Reserved =3D 0;
=20
PcIoApicEnable =3D PcdGet32 (PcdPcIoApicEnable);
@@ -902,8 +903,8 @@ InstallMadtFromScratch (
//
// Build Interrupt Source Override Structures
//
- IntSrcOverrideStruct.Type =3D EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE;
- IntSrcOverrideStruct.Length =3D sizeof (EFI_ACPI_4_0_INTERRUPT_SOURCE_=
OVERRIDE_STRUCTURE);
+ IntSrcOverrideStruct.Type =3D EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE;
+ IntSrcOverrideStruct.Length =3D sizeof (EFI_ACPI_6_3_INTERRUPT_SOURCE_=
OVERRIDE_STRUCTURE);
=20
//
// IRQ0=3D>IRQ2 Interrupt Source Override Structure
@@ -946,11 +947,11 @@ InstallMadtFromScratch (
//
// Build Local APIC NMI Structures
//
- LocalApciNmiStruct.Type =3D EFI_ACPI_4_0_LOCAL_APIC_NMI;
- LocalApciNmiStruct.Length =3D sizeof (EFI_ACPI_4_0_LOCAL_APIC_NMI_STRU=
CTURE);
- LocalApciNmiStruct.AcpiProcessorId =3D 0xFF; // Applies to all pr=
ocessors
- LocalApciNmiStruct.Flags =3D 0x0005; // Flags - Edge-tigg=
ered, Active High
- LocalApciNmiStruct.LocalApicLint =3D 0x1;
+ LocalApciNmiStruct.Type =3D EFI_ACPI_6_3_LOCAL_APIC_NMI;
+ LocalApciNmiStruct.Length =3D sizeof (EFI_ACPI_6_3_LOCAL_APIC_NMI_STRU=
CTURE);
+ LocalApciNmiStruct.AcpiProcessorUid =3D 0xFF; // Applies to all p=
rocessors
+ LocalApciNmiStruct.Flags =3D 0x0005; // Flags - Edge-tig=
gered, Active High
+ LocalApciNmiStruct.LocalApicLint =3D 0x1;
=20
ASSERT (MadtStructsIndex < MaxMadtStructCount);
Status =3D CopyStructure (
@@ -967,8 +968,8 @@ InstallMadtFromScratch (
// Build Local x2APIC NMI Structure
//
if (mX2ApicEnabled) {
- LocalX2ApicNmiStruct.Type =3D EFI_ACPI_4_0_LOCAL_X2APIC_NMI;
- LocalX2ApicNmiStruct.Length =3D sizeof (EFI_ACPI_4_0_LOCAL_X2APIC_NM=
I_STRUCTURE);
+ LocalX2ApicNmiStruct.Type =3D EFI_ACPI_6_3_LOCAL_X2APIC_NMI;
+ LocalX2ApicNmiStruct.Length =3D sizeof (EFI_ACPI_6_3_LOCAL_X2APIC_NM=
I_STRUCTURE);
LocalX2ApicNmiStruct.Flags =3D 0x000D; // Flags - Le=
vel-tiggered, Active High
LocalX2ApicNmiStruct.AcpiProcessorUid =3D 0xFFFFFFFF; // Applies to=
all processors
LocalX2ApicNmiStruct.LocalX2ApicLint =3D 0x01;
@@ -992,12 +993,12 @@ InstallMadtFromScratch (
// Build Madt Structure from the Madt Header and collection of pointer=
s in MadtStructs[]
//
Status =3D BuildAcpiTable (
- (EFI_ACPI_DESCRIPTION_HEADER *) &MadtTableHeader,
- sizeof (EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER=
),
- MadtStructs,
- MadtStructsIndex,
- (UINT8 **) &NewMadtTable
- );
+ (EFI_ACPI_DESCRIPTION_HEADER *) &MadtTableHeader,
+ sizeof (EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER)=
,
+ MadtStructs,
+ MadtStructsIndex,
+ (UINT8 **)&NewMadtTable
+ );
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "BuildAcpiTable failed: %r\n", Status));
goto Done;
@@ -1087,7 +1088,7 @@ InstallMcfgFromScratch (
}
=20
//
- // Publish Madt Structure to ACPI
+ // Publish Mcfg Structure to ACPI
//
Status =3D mAcpiTable->InstallAcpiTable (
mAcpiTable,
@@ -1120,7 +1121,7 @@ PlatformUpdateTables (
EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
UINT8 *TempOemId;
UINT64 TempOemTableId;
- EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtHeader;
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *FadtHeader;
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *HpetTable;
UINT32 HpetBaseAddress;
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_BLOCK_ID HpetBlockId;
@@ -1177,12 +1178,12 @@ PlatformUpdateTables (
//
switch (Table->Signature) {
=20
- case EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
- ASSERT (FALSE);
+ case EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
+ ASSERT(FALSE);
break;
=20
- case EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
- FadtHeader =3D (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *) Tabl=
e;
+ case EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
+ FadtHeader =3D (EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *) Table;
=20
FadtHeader->PreferredPmProfile =3D PcdGet8 (PcdFadtPreferredPmProfil=
e);
FadtHeader->IaPcBootArch =3D PcdGet16 (PcdFadtIaPcBootArch);
@@ -1228,7 +1229,7 @@ PlatformUpdateTables (
DEBUG ((DEBUG_INFO, " Flags 0x%x\n", FadtHeader->Flags));
break;
=20
- case EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
+ case EFI_ACPI_6_3_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
HpetTable =3D (EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *)Ta=
ble;
HpetBaseAddress =3D PcdGet32 (PcdHpetBaseAddress);
HpetTable->BaseAddressLower32Bit.Address =3D HpetBaseAddress;
@@ -1280,8 +1281,8 @@ IsHardwareChange (
UINTN HWChangeSize;
UINT32 PciId;
UINTN Handle;
- EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *FacsPtr;
- EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *pFADT;
+ EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE *FacsPtr;
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *pFADT;
=20
HandleCount =3D 0;
HandleBuffer =3D NULL;
@@ -1327,7 +1328,7 @@ IsHardwareChange (
//
Handle =3D 0;
Status =3D LocateAcpiTableBySignature (
- EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
(EFI_ACPI_DESCRIPTION_HEADER **) &pFADT,
&Handle
);
@@ -1349,7 +1350,7 @@ IsHardwareChange (
//
// Set HardwareSignature value based on CRC value.
//
- FacsPtr =3D (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)pFA=
DT->FirmwareCtrl;
+ FacsPtr =3D (EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)pFA=
DT->FirmwareCtrl;
FacsPtr->HardwareSignature =3D CRC;
FreePool (HWChange);
}
diff --git a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c b/=
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c
index cde6e478c6b9..8700c44e633d 100644
--- a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c
+++ b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c
@@ -1,9 +1,10 @@
/** @file
- This file contains a structure definition for the ACPI 5.0 Firmware AC=
PI
+ This file contains a structure definition for the ACPI 6.3 Firmware AC=
PI
Control Structure (FACS). The contents of this file should only be mo=
dified
for bug fixes, no porting is required.
=20
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
=20
**/
@@ -35,9 +36,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// Please modify all values in Facs.h only.
//
=20
-EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs =3D {
- EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE,
- sizeof (EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE),
+EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs =3D {
+ EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE,
+ sizeof (EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE),
=20
//
// Hardware Signature will be updated at runtime
@@ -48,7 +49,7 @@ EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs =3D {
EFI_ACPI_GLOBAL_LOCK,
EFI_ACPI_FIRMWARE_CONTROL_STRUCTURE_FLAGS,
EFI_ACPI_X_FIRMWARE_WAKING_VECTOR,
- EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION,
+ EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION,
{
EFI_ACPI_RESERVED_BYTE,
EFI_ACPI_RESERVED_BYTE,
diff --git a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c b/=
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c
index 6efb38cda40d..3418e960972f 100644
--- a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c
+++ b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c
@@ -1,9 +1,10 @@
/** @file
- This file contains a structure definition for the ACPI 5.0 Fixed ACPI
+ This file contains a structure definition for the ACPI 6.3 Fixed ACPI
Description Table (FADT). The contents of this file should only be mo=
dified
for bug fixes, no porting is required.
=20
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
=20
**/
@@ -44,9 +45,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// IA-PC Boot Architecture Flags
//
-
#define EFI_ACPI_IAPC_BOOT_ARCH 0 // To be fixed
=20
+//
+// ARM Boot Architecture Flags
+//
+#define EFI_ACPI_ARM_BOOT_ARCH 0 // To be fixed
+
//
// Fixed Feature Flags
//
@@ -55,7 +60,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1A Event Register Block Generic Address Information
//
-#define EFI_ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1A_EVT_BLK_BIT_WIDTH 0x20
#define EFI_ACPI_PM1A_EVT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1A_EVT_BLK_ADDRESS 0 // To be fixed
@@ -63,7 +68,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1B Event Register Block Generic Address Information
//
-#define EFI_ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1B_EVT_BLK_BIT_WIDTH 0x00
#define EFI_ACPI_PM1B_EVT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1B_EVT_BLK_ADDRESS 0 // To be fixed
@@ -71,7 +76,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1A Control Register Block Generic Address Information
//
-#define EFI_ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1A_CNT_BLK_BIT_WIDTH 0x10
#define EFI_ACPI_PM1A_CNT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1A_CNT_BLK_ADDRESS 0 // To be fixed
@@ -79,7 +84,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1B Control Register Block Generic Address Information
//
-#define EFI_ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1B_CNT_BLK_BIT_WIDTH 0x00
#define EFI_ACPI_PM1B_CNT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1B_CNT_BLK_ADDRESS 0 // To be fixed
@@ -87,7 +92,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM2 Control Register Block Generic Address Information
//
-#define EFI_ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM2_CNT_BLK_BIT_WIDTH 0x08
#define EFI_ACPI_PM2_CNT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM2_CNT_BLK_ADDRESS 0 // To be fixed
@@ -96,7 +101,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// Power Management Timer Control Register Block Generic Address
// Information
//
-#define EFI_ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM_TMR_BLK_BIT_WIDTH 0x20
#define EFI_ACPI_PM_TMR_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM_TMR_BLK_ADDRESS 0 // To be fixed
@@ -105,7 +110,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// General Purpose Event 0 Register Block Generic Address
// Information
//
-#define EFI_ACPI_GPE0_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_GPE0_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_GPE0_BLK_BIT_WIDTH 0 // size of R_PCH_ACPI_GPE=
0_STS_127_96 + R_PCH_ACPI_GPE0_EN_127_96
#define EFI_ACPI_GPE0_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_GPE0_BLK_ADDRESS 0 // To be fixed
@@ -114,14 +119,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// General Purpose Event 1 Register Block Generic Address
// Information
//
-#define EFI_ACPI_GPE1_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_GPE1_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_GPE1_BLK_BIT_WIDTH 0x0
#define EFI_ACPI_GPE1_BLK_BIT_OFFSET 0x0
#define EFI_ACPI_GPE1_BLK_ADDRESS 0 // To be fixed
//
// Reset Register Generic Address Information
//
-#define EFI_ACPI_RESET_REG_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_RESET_REG_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_RESET_REG_BIT_WIDTH 0x08
#define EFI_ACPI_RESET_REG_BIT_OFFSET 0x00
#define EFI_ACPI_RESET_REG_ADDRESS 0x00000CF9
@@ -162,11 +167,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// Please modify all values in Fadt.h only.
//
=20
-EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
+EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
{
- EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
- sizeof (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE),
- EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ sizeof (EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE),
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_REVISION,
=20
//
// Checksum will be updated at runtime
@@ -187,9 +192,9 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
//
// These addresses will be updated at runtime
//
- 0x00000000,=20
0x00000000,
- =20
+ 0x00000000,
+
EFI_ACPI_RESERVED_BYTE,
EFI_ACPI_PREFERRED_PM_PROFILE,
EFI_ACPI_SCI_INT,
@@ -198,7 +203,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_ACPI_DISABLE,
EFI_ACPI_S4_BIOS_REQ,
EFI_ACPI_PSTATE_CNT,
- =20
+
EFI_ACPI_PM1A_EVT_BLK_ADDRESS,
EFI_ACPI_PM1B_EVT_BLK_ADDRESS,
EFI_ACPI_PM1A_CNT_BLK_ADDRESS,
@@ -240,15 +245,13 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D =
{
EFI_ACPI_RESET_REG_ADDRESS_SPACE_ID,
EFI_ACPI_RESET_REG_BIT_WIDTH,
EFI_ACPI_RESET_REG_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_RESET_REG_ADDRESS
},
EFI_ACPI_RESET_VALUE,
- {
- EFI_ACPI_RESERVED_BYTE,
- EFI_ACPI_RESERVED_BYTE,
- EFI_ACPI_RESERVED_BYTE
- },
+
+ EFI_ACPI_ARM_BOOT_ARCH,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION,
=20
//
// These addresses will be updated at runtime
@@ -263,7 +266,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1A_EVT_BLK_BIT_WIDTH,
EFI_ACPI_PM1A_EVT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1A_EVT_BLK_ADDRESS
},
{
@@ -273,7 +276,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1B_EVT_BLK_BIT_WIDTH,
EFI_ACPI_PM1B_EVT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1B_EVT_BLK_ADDRESS
},
{
@@ -283,7 +286,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1A_CNT_BLK_BIT_WIDTH,
EFI_ACPI_PM1A_CNT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1A_CNT_BLK_ADDRESS
},
{
@@ -293,7 +296,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1B_CNT_BLK_BIT_WIDTH,
EFI_ACPI_PM1B_CNT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1B_CNT_BLK_ADDRESS
},
{
@@ -303,7 +306,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM2_CNT_BLK_BIT_WIDTH,
EFI_ACPI_PM2_CNT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_PM2_CNT_BLK_ADDRESS
},
{
@@ -313,7 +316,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM_TMR_BLK_BIT_WIDTH,
EFI_ACPI_PM_TMR_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_DWORD,
+ EFI_ACPI_6_3_DWORD,
EFI_ACPI_PM_TMR_BLK_ADDRESS
},
{
@@ -323,7 +326,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_GPE0_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_GPE0_BLK_BIT_WIDTH,
EFI_ACPI_GPE0_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_GPE0_BLK_ADDRESS
},
{
@@ -333,7 +336,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_GPE1_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_GPE1_BLK_BIT_WIDTH,
EFI_ACPI_GPE1_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_GPE1_BLK_ADDRESS
},
{
@@ -355,5 +358,10 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
0,
0,
0
- }
+ },
+
+ //
+ // Hypervisor Vendor Identity
+ //
+ 0x0000000000000000,
};
--=20
2.28.0.windows.1


Re: [PATCH V7 1/1] OvmfPkg: Enable TDX in ResetVector

Yao, Jiewen
 

Comment below

-----Original Message-----
From: kraxel@redhat.com <kraxel@redhat.com>
Sent: Friday, September 24, 2021 10:02 PM
To: Yao, Jiewen <jiewen.yao@intel.com>
Cc: devel@edk2.groups.io; Xu, Min M <min.m.xu@intel.com>; Brijesh Singh
<brijesh.singh@amd.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>;
Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
<erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
Lendacky <thomas.lendacky@amd.com>
Subject: Re: [edk2-devel] [PATCH V7 1/1] OvmfPkg: Enable TDX in ResetVector

On Fri, Sep 24, 2021 at 10:33:35AM +0000, Yao, Jiewen wrote:
Again. Two topics. We need discuss them separately.

Topic 1: TD metadata table is an architecture way to communicate with
VMM. We took the design from PE/COFF image section, which is flexible
to support different binary format.
EDKII TDVF is just one possible producer. There could be other
producer in the future. We don't want to define something only meet
current TDVF need.
Hmm. efi has a kind-of binary format (EFI_FIRMWARE_VOLUME_HEADER).
It's not fully self-contained though, you need to know where the
architecture places the firmware (i.e. just below 4G for x86)
because the load address isn't there. So I do see the point of
adding other headers adding that.

Possible alternative approach: Define an extension
(EFI_FIRMWARE_VOLUME_EXT_HEADER) for the load address and use that
instead of defining something new.
[Jiewen] I would say it is terrible idea to use EFI_FIRMWARE_VOLUME_HEADER.

This is defined by PI specification, the purpose is to have a way to manage the firmware file.
It is very complicated and with overhead only needed for flash.

Intel has multiple technologies requires firmware/hardware interface. None of them uses EFI_FIRMARE_VOLUME_HEADER, because it is unnecessary to carry the complexity.

The most famous firmware/hardware interface is called Firmware Interface Table (FIT) table. - https://software.intel.com/content/dam/develop/external/us/en/documents/firmware-interface-table-bios-specification-r1p2p1.pdf.

Also using EFI_FIRMWARE_VOLUME_HEADER means you have to use PI FV layout, which is another unnecessary limitation.

I would strongly disagree to using EFI_FIRMWARE_VOLUME_HEADER for metadata table.

Still not clear why the size is in there twice. I think you could
instead use a flag telling whenever a section must be loaded from
the image or not. This is what COFF and ELF are doing too.

Also not clear why you want stick to 64bit base address. Loading the
firmware above 4G isn't going to work without also changing a bunch of
other things and it will break backward compatibility anyway.
[Jiewen] That is our previously experience, when we define a physical address, we always use 64bit to leave room for extension.
Like UEFI specification defines PHYSICAL_ADDRESS to be UINT64 even in IA32 platform.

Let me tell you a story.
In https://github.com/tianocore/edk2/blob/master/SecurityPkg/Include/Ppi/FirmwareVolumeInfoPrehashedFV.h, we defined the physical address to be FvBase.
UINT32 FvBase;
UINT32 FvLength;

It is rare, because in other context, we usually define FvBase to be 64bit.

Later, when we want to enable a host app based unit test for this data structure, we got test crash directly, because the OS app test allocates an above 4G base address, and the test case cast it to UINT32.

Do we really care to save 4 bytes in the PPI definition? I don't think so.
But it just defines in this way and it brings a big burden to enable unit test.
This code has been checked in for 2 years. Till now, I still regret that why we didn't use UINT64 in the beginning.

I have seen other examples to define small size, such as PI Section Size (24 bit), FFS Size (24 bit), HOB size (16 bit). Then we run into problem to support large structure later and we have to figure out ugly work-around to support those cases.

Defining UINT64 gives us enough flexibility for the future, including test in above 4G environment.
I am wondering that, do you really care to save 4 bytes from UINT64 to UINT32 ?

For type, maybe 2^16 is enough. But for flags, I prefer 32bit.


I think the entry size can be cut in half with something like this:

struct {
uint32_t file_offset;
uint32_t load_address;
uint32_t section_size;
uint16_t section_type;
uint16_t section_flags;
};

Topic 2: In config-B we remove PEI.
I think we should say it in different way: We add PEI back in config-A.
In our original design we totally eliminated PEI, because it is unnecessary.
IMHO, it is totally an overdesign in OVMF to include PEI.

Granted. PEI basically allows OEMs to plug their binary PEIMs into
early hardware initialization. For a full open source firmware there
is little reason to support that, other than maybe using PEIMs from
other edk2 Pkgs unmodified.

But, again, I don't want have two completely different initialization
code paths in OVMF. We can certainly investigate and discuss dropping
PEI, but that clearly shouldn't be a TDX-only thing. When we eliminate
PEI, we should do it for all OVMF builds.
[Jiewen] I think this is out of scope of TDVF config-B patch series.
I don't think it is fair to enable OVMF to remove PEI, just because TDVF does not need PEI.

If you look around other edk2 platform projects, you can already find some of them does not have PEI. And EmbeddedPkg includes some libs to support those case, such as https://github.com/tianocore/edk2/tree/master/EmbeddedPkg/Library/PrePiHobLib, https://github.com/tianocore/edk2/tree/master/EmbeddedPkg/Library/PrePiLib.
But that does not mean, we need do that for every platform.

Each platform owner can have their own choice.

If you have intertest to remove PEI, I am happy to discuss with you on detail.
However, I would treat "removing PEI from OVMF" and "enable TDVF config-B" be two different tasks.



take care,
Gerd


Re: [PATCH V7 1/1] OvmfPkg: Enable TDX in ResetVector

Gerd Hoffmann
 

On Fri, Sep 24, 2021 at 10:33:35AM +0000, Yao, Jiewen wrote:
Again. Two topics. We need discuss them separately.

Topic 1: TD metadata table is an architecture way to communicate with
VMM. We took the design from PE/COFF image section, which is flexible
to support different binary format.
EDKII TDVF is just one possible producer. There could be other
producer in the future. We don't want to define something only meet
current TDVF need.
Hmm. efi has a kind-of binary format (EFI_FIRMWARE_VOLUME_HEADER).
It's not fully self-contained though, you need to know where the
architecture places the firmware (i.e. just below 4G for x86)
because the load address isn't there. So I do see the point of
adding other headers adding that.

Possible alternative approach: Define an extension
(EFI_FIRMWARE_VOLUME_EXT_HEADER) for the load address and use that
instead of defining something new.

Still not clear why the size is in there twice. I think you could
instead use a flag telling whenever a section must be loaded from
the image or not. This is what COFF and ELF are doing too.

Also not clear why you want stick to 64bit base address. Loading the
firmware above 4G isn't going to work without also changing a bunch of
other things and it will break backward compatibility anyway.

I think the entry size can be cut in half with something like this:

struct {
uint32_t file_offset;
uint32_t load_address;
uint32_t section_size;
uint16_t section_type;
uint16_t section_flags;
};

Topic 2: In config-B we remove PEI.
I think we should say it in different way: We add PEI back in config-A.
In our original design we totally eliminated PEI, because it is unnecessary. IMHO, it is totally an overdesign in OVMF to include PEI.
Granted. PEI basically allows OEMs to plug their binary PEIMs into
early hardware initialization. For a full open source firmware there
is little reason to support that, other than maybe using PEIMs from
other edk2 Pkgs unmodified.

But, again, I don't want have two completely different initialization
code paths in OVMF. We can certainly investigate and discuss dropping
PEI, but that clearly shouldn't be a TDX-only thing. When we eliminate
PEI, we should do it for all OVMF builds.

take care,
Gerd


Re: [PATCH v3 15/28] Ampere: PCIe: Add PciSegmentLib library instance

Ard Biesheuvel
 

On Wed, 15 Sept 2021 at 18:00, Nhi Pham <nhi@os.amperecomputing.com> wrote:

From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Provides wrapper calls to the Ac01PcieLib to handle the PCIe access.
As Ampere Altra processor supports upto 16 PCIe Root Complexs, the
target Root Complex will depend on the segment number parsed from the
input address.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
OK, this is not your fault, but this file is 99% boilerplate, with the
only platform specific piece being the calls to Ac01PcieConfigRW(),
right?

Leif, Michael, do you see any avenues here to improve this situation?
I don't think it should hold up this patch, but I have seen this
pattern a few times now (and I am responsible for at least one of
them)

For the change itself,

Acked-by: Ard Biesheuvel <ardb@kernel.org>

---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 1 +
Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLibPci.inf | 28 +
Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLib.c | 1189 ++++++++++++++++++++
3 files changed, 1218 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index dc66b711aba8..dbcd1c9acaa2 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -229,6 +229,7 @@ [LibraryClasses.common.DXE_DRIVER]
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
PciHostBridgeLib|Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
+ PciSegmentLib|Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLibPci.inf

[LibraryClasses.common.UEFI_APPLICATION]
UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLibPci.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLibPci.inf
new file mode 100644
index 000000000000..64897653e126
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLibPci.inf
@@ -0,0 +1,28 @@
+## @file
+#
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PciSegmentLibPci
+ FILE_GUID = 0AF5E76D-D31E-492B-AE69-A7B441FF62D9
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciSegmentLib
+
+[Sources]
+ PciSegmentLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+
+[LibraryClasses]
+ Ac01PcieLib
+ BaseLib
+ DebugLib
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLib.c
new file mode 100644
index 000000000000..c893c56dfadf
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLib.c
@@ -0,0 +1,1189 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/Ac01PcieLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PciLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Ac01PcieCommon.h>
+
+/**
+ Assert the validity of a PCI Segment address.
+ A valid PCI Segment address should not contain 1's in bits 28..31 and 48..63
+ and the segment should be 0.
+
+ @param A The address to validate.
+ @param M Additional bits to assert to be zero.
+
+**/
+#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A,M) \
+ ASSERT (((A) & (0xffff0000f0000000ULL | (M))) == 0)
+
+/**
+ Convert the PCI Segment library address to PCI library address.
+
+ @param A The address to convert.
+**/
+#define PCI_SEGMENT_TO_PCI_ADDRESS(A) ((UINTN)(UINT32)A)
+
+/**
+ Register a PCI device so PCI configuration registers may be accessed after
+ SetVirtualAddressMap().
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @retval RETURN_SUCCESS The PCI device was registered for runtime access.
+ @retval RETURN_UNSUPPORTED An attempt was made to call this function
+ after ExitBootServices().
+ @retval RETURN_UNSUPPORTED The resources required to access the PCI device
+ at runtime could not be mapped.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
+ complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+ IN UINTN Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+ return PciRegisterForRuntimeAccess (PCI_SEGMENT_TO_PCI_ADDRESS (Address));
+}
+
+/**
+ Reads an 8-bit PCI configuration register.
+
+ Reads and returns the 8-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 8-bit PCI configuration register specified by Address.
+
+**/
+UINT8
+EFIAPI
+PciSegmentRead8 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+ return PciRead8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address));
+}
+
+/**
+ Writes an 8-bit PCI configuration register.
+
+ Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentWrite8 (
+ IN UINT64 Address,
+ IN UINT8 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+ return PciWrite8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value);
+}
+
+/**
+ Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentOr8 (
+ IN UINT64 Address,
+ IN UINT8 OrData
+ )
+{
+ return PciWrite8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), (UINT8)(PciSegmentRead8 (Address) | OrData));
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAnd8 (
+ IN UINT64 Address,
+ IN UINT8 AndData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & AndData));
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
+ followed a bitwise OR with another 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAndThenOr8 (
+ IN UINT64 Address,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & AndData) | OrData));
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in an 8-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldRead8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 8-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param Value New value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldWrite8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 Value
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 8-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 8-bit register.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND between the read result and the value specified by AndData, and
+ writes the result to the 8-bit PCI configuration register specified by
+ Address. The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are
+ serialized. Extra left bits in AndData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAnd8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 8-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAndThenOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a 16-bit PCI configuration register.
+
+ Reads and returns the 16-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 16-bit PCI configuration register specified by Address.
+
+**/
+UINT16
+EFIAPI
+PciSegmentRead16 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+ return PciRead16 (PCI_SEGMENT_TO_PCI_ADDRESS (Address));
+}
+
+/**
+ Writes a 16-bit PCI configuration register.
+
+ Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT16
+EFIAPI
+PciSegmentWrite16 (
+ IN UINT64 Address,
+ IN UINT16 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+ return PciWrite16 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value);
+}
+
+/**
+ Performs a bitwise OR of a 16-bit PCI configuration register with
+ a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by OrData, and
+ writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned. This function
+ must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function and
+ Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentOr16 (
+ IN UINT64 Address,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) | OrData));
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAnd16 (
+ IN UINT64 Address,
+ IN UINT16 AndData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) & AndData));
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
+ followed a bitwise OR with another 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAndThenOr16 (
+ IN UINT64 Address,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16) ((PciSegmentRead16 (Address) & AndData) | OrData));
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 16-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldRead16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 16-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param Value New value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldWrite16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 Value
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, writes
+ the result back to the bit field in the 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 16-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
+ AND, writes the result back to the bit field in the 16-bit register.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise AND between the read result and the value specified by AndData, and
+ writes the result to the 16-bit PCI configuration register specified by
+ Address. The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are
+ serialized. Extra left bits in AndData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAnd16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 16-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAndThenOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a 32-bit PCI configuration register.
+
+ Reads and returns the 32-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 32-bit PCI configuration register specified by Address.
+
+**/
+UINT32
+EFIAPI
+PciSegmentRead32 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+ return PciRead32 (PCI_SEGMENT_TO_PCI_ADDRESS (Address));
+}
+
+/**
+ Writes a 32-bit PCI configuration register.
+
+ Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT32
+EFIAPI
+PciSegmentWrite32 (
+ IN UINT64 Address,
+ IN UINT32 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+ return PciWrite32 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value);
+}
+
+/**
+ Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentOr32 (
+ IN UINT64 Address,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAnd32 (
+ IN UINT64 Address,
+ IN UINT32 AndData
+ )
+{
+ return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
+ followed a bitwise OR with another 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAndThenOr32 (
+ IN UINT64 Address,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData);
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 32-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldRead32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 32-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param Value New value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldWrite32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 Value
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 32-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 32-bit register.
+
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
+ AND between the read result and the value specified by AndData, and writes the result
+ to the 32-bit PCI configuration register specified by Address. The value written to
+ the PCI configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in AndData are stripped.
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAnd32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 32-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAndThenOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a range of PCI configuration registers into a caller supplied buffer.
+
+ Reads the range of PCI configuration registers specified by StartAddress and
+ Size into the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be read. Size is
+ returned. When possible 32-bit PCI configuration read cycles are used to read
+ from StartAddress to StartAddress + Size. Due to alignment restrictions, 8-bit
+ and 16-bit PCI configuration read cycles may be used at the beginning and the
+ end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress Starting address that encodes the PCI Segment, Bus, Device,
+ Function and Register.
+ @param Size Size in bytes of the transfer.
+ @param Buffer Pointer to a buffer receiving the data read.
+
+ @return Size
+
+**/
+UINTN
+EFIAPI
+PciSegmentReadBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+ ASSERT (((StartAddress & 0xFFF) + Size) <= SIZE_4KB);
+
+ if (Size == 0) {
+ return Size;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ Status = Ac01PcieConfigRW (NULL, StartAddress, FALSE, Size, Buffer);
+ ASSERT_EFI_ERROR (Status);
+
+ return Size;
+}
+
+/**
+ Copies the data in a caller supplied buffer to a specified range of PCI
+ configuration space.
+
+ Writes the range of PCI configuration registers specified by StartAddress and
+ Size from the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be written. Size is
+ returned. When possible 32-bit PCI configuration write cycles are used to
+ write from StartAddress to StartAddress + Size. Due to alignment restrictions,
+ 8-bit and 16-bit PCI configuration write cycles may be used at the beginning
+ and the end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress Starting address that encodes the PCI Segment, Bus, Device,
+ Function and Register.
+ @param Size Size in bytes of the transfer.
+ @param Buffer Pointer to a buffer containing the data to write.
+
+ @return The parameter of Size.
+
+**/
+UINTN
+EFIAPI
+PciSegmentWriteBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+ ASSERT (((StartAddress & 0xFFF) + Size) <= SIZE_4KB);
+
+ if (Size == 0) {
+ return Size;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ Status = Ac01PcieConfigRW (NULL, StartAddress, TRUE, Size, Buffer);
+ ASSERT_EFI_ERROR (Status);
+
+ return Size;
+}
--
2.17.1


Re: [PATCH v3 14/28] Ampere: PCIe: Add PciHostBridgeLib library instance

Ard Biesheuvel
 

On Wed, 15 Sept 2021 at 18:00, Nhi Pham <nhi@os.amperecomputing.com> wrote:

From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Provides the number of supported RootBridges and the resource allocated
for each RootBridge. These information are essential to the HostBridge
driver to initialize the PCIe subsystem.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
This looks ok to me, although I will note the code that patches the
_STA methods in the DSDT according to which host bridges actually
exist in the system should not typically live in a library. However,
this particular library is designed to be incorporated only by
PciHostBridgeDxe so in this case, I can live with it.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>

---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 1 +
Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf | 48 +++
Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c | 378 ++++++++++++++++++++
3 files changed, 427 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index d4e1b84c0276..dc66b711aba8 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -228,6 +228,7 @@ [LibraryClasses.common.DXE_DRIVER]
PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
+ PciHostBridgeLib|Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf

[LibraryClasses.common.UEFI_APPLICATION]
UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
new file mode 100644
index 000000000000..a8ee0c2b9278
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,48 @@
+## @file
+#
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PciHostBridgeLib
+ FILE_GUID = 9D0522E5-B5FD-4E3F-9D10-52AE221FA314
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER
+ CONSTRUCTOR = HostBridgeConstructor
+
+[Sources]
+ PciHostBridgeLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ Ac01PcieLib
+ AcpiLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ IoLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+
+[Guids]
+ gEfiEventReadyToBootGuid
+
+[Protocols]
+ gEfiCpuIo2ProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
new file mode 100644
index 000000000000..281f20b4bb63
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,378 @@
+/** @file
+ PCI Host Bridge Library instance for Ampere Altra-based platforms.
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/Ac01PcieLib.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Ac01PcieCommon.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+STATIC CHAR16 CONST * CONST mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+#pragma pack(1)
+typedef struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+#pragma pack ()
+
+STATIC EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = {
+ {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
+ }
+ },
+ EISA_PNP_ID (0x0A08), // PCIe
+ 0
+ }, {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+STATIC PCI_ROOT_BRIDGE mRootBridgeTemplate = {
+ 0, // Segment
+ 0, // Supports
+ 0, // Attributes
+ TRUE, // DmaAbove4G
+ FALSE, // NoExtendedConfigSpace
+ FALSE, // ResourceAssigned
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE,
+ {
+ // Bus
+ 0,
+ 0
+ }, {
+ // Io
+ 0,
+ 0,
+ 0
+ }, {
+ // Mem
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // MemAbove4G
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // PMem
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // PMemAbove4G
+ MAX_UINT64,
+ 0,
+ 0
+ },
+ (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath
+};
+
+UINT8 mRootBridgeCount = 0;
+PCI_ROOT_BRIDGE *mRootBridges = NULL;
+
+EFI_STATUS
+UpdateStatusMethodObject (
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
+ EFI_ACPI_HANDLE TableHandle,
+ CHAR8 *AsciiObjectPath,
+ CHAR8 ReturnValue
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_HANDLE ObjectHandle;
+ EFI_ACPI_DATA_TYPE DataType;
+ CHAR8 *Buffer;
+ UINTN DataSize;
+
+ Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);
+ if (EFI_ERROR (Status) || ObjectHandle == NULL) {
+ return EFI_SUCCESS;
+ }
+ ASSERT (ObjectHandle != NULL);
+
+ Status = AcpiSdtProtocol->GetOption (ObjectHandle, 2, &DataType, (VOID *)&Buffer, &DataSize);
+ if (!EFI_ERROR (Status) && Buffer[2] == AML_BYTE_PREFIX) {
+ //
+ // Only patch when the initial value is byte object.
+ //
+ Buffer[3] = ReturnValue;
+ }
+
+ AcpiSdtProtocol->Close (ObjectHandle);
+ return Status;
+}
+
+/**
+ This function will be called when ReadyToBoot event is signaled.
+
+ @param Event signaled event
+ @param Context calling context
+
+ @retval VOID
+**/
+VOID
+EFIAPI
+PciHostBridgeReadyToBootEvent (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ UINTN TableKey;
+ UINTN TableIndex;
+ EFI_ACPI_HANDLE TableHandle;
+ CHAR8 NodePath[256];
+ UINTN Count;
+ UINTN Idx1;
+ UINTN Idx2;
+
+ Count = 0;
+
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID **)&AcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate ACPI table protocol\n"));
+ return;
+ }
+
+ TableIndex = 0;
+ Status = AcpiLocateTableBySignature (
+ AcpiSdtProtocol,
+ EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ &TableIndex,
+ &Table,
+ &TableKey
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a %d Status = %r \n", __FUNCTION__, __LINE__, Status));
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
+ Status = AcpiSdtProtocol->OpenSdt (TableKey, &TableHandle);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ AcpiSdtProtocol->Close (TableHandle);
+ return;
+ }
+
+ for (Idx1 = 0; Idx1 < Ac01PcieGetTotalHBs (); Idx1++) {
+ for (Idx2 = 0; Idx2 < Ac01PcieGetTotalRBsPerHB (Idx1); Idx2++) {
+ AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X._STA", Count);
+ if (Ac01PcieCheckRootBridgeDisabled (Idx1, Idx2)) {
+ UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
+ } else {
+ UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xf);
+ }
+ Count++;
+ }
+ }
+
+ AcpiSdtProtocol->Close (TableHandle);
+ AcpiUpdateChecksum ((UINT8 *)Table, Table->Length);
+
+ //
+ // Close the event, so it will not be signalled again.
+ //
+ gBS->CloseEvent (Event);
+}
+
+EFI_STATUS
+HostBridgeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;
+ EFI_EVENT EvtReadyToBoot;
+
+ mRootBridges = AllocatePool (Ac01PcieGetTotalHBs () * sizeof (PCI_ROOT_BRIDGE));
+ if (mRootBridges == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Ac01PcieSetup ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < Ac01PcieGetTotalHBs (); Index++) {
+ CopyMem (&mRootBridges[mRootBridgeCount], &mRootBridgeTemplate, sizeof (PCI_ROOT_BRIDGE));
+
+ Status = Ac01PcieSetupRootBridge (Index, 0, (VOID *)&mRootBridges[mRootBridgeCount]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ mRootBridges[mRootBridgeCount].Segment = Ac01PcieGetRootBridgeSegmentNumber (Index, 0);
+
+ DevicePath = AllocateCopyPool (
+ sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH),
+ (VOID *)&mEfiPciRootBridgeDevicePath
+ );
+ if (DevicePath == NULL) {
+ continue;
+ }
+
+ //
+ // Embedded RC Index to the DevicePath
+ // This will be used later by the platform NotifyPhase()
+ //
+ DevicePath->AcpiDevicePath.UID = Index;
+
+ mRootBridges[mRootBridgeCount].DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
+ mRootBridgeCount++;
+ }
+
+ Ac01PcieEnd ();
+
+ //
+ // Register event to fixup ACPI table
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL, // Type,
+ TPL_NOTIFY, // NotifyTpl
+ PciHostBridgeReadyToBootEvent, // NotifyFunction
+ NULL, // NotifyContext
+ &gEfiEventReadyToBootGuid, // EventGroup
+ &EvtReadyToBoot // Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ UINTN *Count
+ )
+{
+ *Count = mRootBridgeCount;
+ return mRootBridges;
+}
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ )
+{
+ //
+ // Unsupported
+ //
+}
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource
+ descriptors. The Configuration contains the resources
+ for all the root bridges. The resource for each root
+ bridge is terminated with END descriptor and an
+ additional END is appended indicating the end of the
+ entire resources. The resource descriptor field
+ values follow the description in
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN RootBridgeIndex;
+ DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+ RootBridgeIndex = 0;
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
+ while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+ for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ ASSERT (Descriptor->ResType <
+ (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /
+ sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])
+ )
+ );
+ DEBUG ((DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+ mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+ Descriptor->AddrLen, Descriptor->AddrRangeMax
+ ));
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ DEBUG ((DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
+ Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ ((Descriptor->SpecificFlag &
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+ ) != 0) ? L" (Prefetchable)" : L""
+ ));
+ }
+ }
+ //
+ // Skip the END descriptor for root bridge
+ //
+ ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+ (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+ );
+ }
+}
--
2.17.1


Re: [PATCH v3 18/28] Ampere: PCIe: Add PciPlatformDxe driver

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:17 +0700, Nhi Pham wrote:
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Registers the Platform NotifyPhase() to prevent unexpected issues
caused by the enabled PCIe controllers which have unstable link.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>

---
Platform/Ampere/JadePkg/Jade.dsc | 5 +
Platform/Ampere/JadePkg/Jade.fdf | 1 +
Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.inf | 37 ++++
Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.c | 212 ++++++++++++++++++++
4 files changed, 255 insertions(+)

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index b733f8430806..ce5f2c0dc4e1 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -148,6 +148,11 @@ [Components.common]
Silicon/Ampere/AmpereAltraPkg/AcpiCommonTables/AcpiCommonTables.inf
Platform/Ampere/JadePkg/AcpiTables/AcpiTables.inf

+ #
+ # PCIe
+ #
+ Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.inf
+
#
# VGA Aspeed
#
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 195da2d63a7a..8ddfabcdd9a8 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -298,6 +298,7 @@ [FV.FvMain]
#
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+ INF Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.inf

#
# VGA Aspeed
diff --git a/Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.inf b/Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.inf
new file mode 100644
index 000000000000..5f5316055217
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.inf
@@ -0,0 +1,37 @@
+## @file
+#
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PciPlatformDxe
+ FILE_GUID = 73276F3D-DCBC-49B2-9890-7564F917501D
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PciPlatformDriverEntry
+
+[Sources]
+ PciPlatformDxe.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+
+[LibraryClasses]
+ Ac01PcieLib
+ DebugLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiPciHostBridgeResourceAllocationProtocolGuid
+ gEfiPciPlatformProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.c b/Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.c
new file mode 100644
index 000000000000..196f857175e9
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/PciPlatformDxe/PciPlatformDxe.c
@@ -0,0 +1,212 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/Ac01PcieLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciPlatform.h>
+
+#pragma pack(1)
+typedef struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+#pragma pack ()
+
+/**
+
+ Perform initialization by the phase indicated.
+
+ @param This Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge The associated PCI host bridge handle.
+ @param Phase The phase of the PCI controller enumeration.
+ @param ChipsetPhase Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS Must return with success.
+
+**/
+EFI_STATUS
+EFIAPI
+PhaseNotify (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+{
+ EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *RootBridgeDevPath;
+ EFI_HANDLE RootBridgeHandle = NULL;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *ResAlloc = NULL;
+ EFI_STATUS Status;
+
+ if (ChipsetPhase != ChipsetExit) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get HostBridgeInstance from HostBridge handle.
+ //
+ Status = gBS->HandleProtocol (
+ HostBridge,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ (VOID **)&ResAlloc
+ );
+
+ while (TRUE) {
+ Status = ResAlloc->GetNextRootBridge (ResAlloc, &RootBridgeHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = gBS->HandleProtocol (
+ RootBridgeHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&RootBridgeDevPath
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a %d: Failed to locate RootBridge DevicePath\n", __FUNCTION__, __LINE__));
+ break;
+ }
+
+ Ac01PcieHostBridgeNotifyPhase (RootBridgeDevPath->AcpiDevicePath.UID, 0, Phase);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ The PlatformPrepController() function can be used to notify the platform driver so that
+ it can perform platform-specific actions. No specific actions are required.
+ Several notification points are defined at this time. More synchronization points may be
+ added as required in the future. The PCI bus driver calls the platform driver twice for
+ every PCI controller-once before the PCI Host Bridge Resource Allocation Protocol driver
+ is notified, and once after the PCI Host Bridge Resource Allocation Protocol driver has
+ been notified.
+ This member function may not perform any error checking on the input parameters. It also
+ does not return any error codes. If this member function detects any error condition, it
+ needs to handle those errors on its own because there is no way to surface any errors to
+ the caller.
+
+ @param This Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge The associated PCI host bridge handle.
+ @param RootBridge The associated PCI root bridge handle.
+ @param PciAddress The address of the PCI device on the PCI bus.
+ @param Phase The phase of the PCI controller enumeration.
+ @param ChipsetPhase Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformPrepController (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_HANDLE RootBridge,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Set the PciPolicy as EFI_RESERVE_ISA_IO_NO_ALIAS | EFI_RESERVE_VGA_IO_NO_ALIAS.
+
+ @param This The pointer to the Protocol itself.
+ @param PciPolicy The returned Policy.
+
+ @retval EFI_UNSUPPORTED Function not supported.
+ @retval EFI_INVALID_PARAMETER Invalid PciPolicy value.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformPolicy (
+ IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
+ OUT EFI_PCI_PLATFORM_POLICY *PciPolicy
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Return a PCI ROM image for the onboard device represented by PciHandle.
+
+ @param This Protocol instance pointer.
+ @param PciHandle PCI device to return the ROM image for.
+ @param RomImage PCI Rom Image for onboard device.
+ @param RomSize Size of RomImage in bytes.
+
+ @retval EFI_SUCCESS RomImage is valid.
+ @retval EFI_NOT_FOUND No RomImage.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPciRom (
+ IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage,
+ OUT UINTN *RomSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+//
+// Interface defintion of PCI Platform protocol.
+//
+EFI_PCI_PLATFORM_PROTOCOL mPciPlatformProtocol = {
+ .PlatformNotify = PhaseNotify,
+ .PlatformPrepController = PlatformPrepController,
+ .GetPlatformPolicy = GetPlatformPolicy,
+ .GetPciRom = GetPciRom
+};
+
+/**
+
+ The Entry point of the Pci Platform Driver.
+
+ @param ImageHandle Handle to the image.
+ @param SystemTable Handle to System Table.
+
+ @retval EFI_STATUS Status of the function calling.
+
+**/
+EFI_STATUS
+PciPlatformDriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE PciPlatformHandle;
+
+ //
+ // Install on a new handle
+ //
+ PciPlatformHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PciPlatformHandle,
+ &gEfiPciPlatformProtocolGuid,
+ &mPciPlatformProtocol,
+ NULL
+ );
+
+ return Status;
+}
--
2.17.1


Re: [PATCH v3 28/28] AmpereAltraPkg: Add configuration screen for Pcie Devices

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:27 +0700, Nhi Pham wrote:
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

This screen provide menu options to configure Max Payload and Max Read
Request size for each PCIe device under Root Port. PCIe devices which
attach to external switch are not supported yet.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>

---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 +
Platform/Ampere/JadePkg/Jade.dsc | 1 +
Platform/Ampere/JadePkg/Jade.fdf | 1 +
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.inf | 59 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.h | 78 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.h | 56 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.h | 58 ++
Silicon/Ampere/AmpereAltraPkg/Include/Guid/PlatformPcieDeviceConfigHii.h | 19 +
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.vfr | 50 +
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.c | 1045 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.c | 191 ++++
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.uni | 24 +
12 files changed, 1585 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index b0e1f3ec6f2a..6ce545fda8dd 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -59,6 +59,9 @@ [Guids]
# GUID for the Watchdog HII configuration form
gWatchdogConfigFormSetGuid = { 0xC3F8EC6E, 0x95EE, 0x460C, { 0xA4, 0x8D, 0xEA, 0x54, 0x2F, 0xFF, 0x01, 0x61 } }

+ # GUID for the Pcie Device HII configuration form
+ gPlatformPcieDeviceConfigFormSetGuid = { 0xEC7B1D21, 0x9167, 0x4B9D, { 0xF7, 0x94, 0xCD, 0x1A, 0xEB, 0xBC, 0xB7, 0x59 } }
+
## NVParam MM GUID
gNVParamMmGuid = { 0xE4AC5024, 0x29BE, 0x4ADC, { 0x93, 0x36, 0x87, 0xB5, 0xA0, 0x76, 0x23, 0x2D } }

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index b752ea3e5264..9db1cf316249 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -202,3 +202,4 @@ [Components.common]
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 8f3df6ccf01b..ae444d702bbe 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -360,5 +360,6 @@ [FV.FvMain]
INF Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.inf

!include Platform/Ampere/AmperePlatformPkg/FvRules.fdf.inc
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.inf
new file mode 100644
index 000000000000..79d7bd185b7d
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.inf
@@ -0,0 +1,59 @@
+## @file
+#
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PlatformPcieDeviceConfigDxe
+ FILE_GUID = 17E9369D-0A1B-45F4-A286-B1DED6D85D33
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PlatformPcieDeviceConfigEntryPoint
+
+[Sources.common]
+ PlatformPcieDeviceConfigDxe.c
+ PlatformPcieDeviceConfigDxe.h
+ PlatformPcieDeviceConfigDxe.uni
+ PlatformPcieDeviceConfigVfr.h
+ PlatformPcieDeviceConfigVfr.vfr
+ PlatformPcieHelper.c
+ PlatformPcieHelper.h
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ HiiLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathToTextProtocolGuid
+
+[Guids]
+ gEfiIfrTianoGuid
+ gPlatformPcieDeviceConfigFormSetGuid
+ gPlatformManagerFormsetGuid
+ gPlatformManagerEntryEventGuid
+
+[Depex]
+ TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.h
new file mode 100644
index 000000000000..a39257da06ba
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.h
@@ -0,0 +1,78 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_PCIE_DEVICE_CONFIG_H_
+#define PLATFORM_PCIE_DEVICE_CONFIG_H_
+
+#include <Uefi.h>
+
+#include <Library/HiiLib.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigKeyword.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+
+#include "PlatformPcieDeviceConfigVfr.h"
+
+#define MAX_STRING_SIZE 100
+
+#define PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'E', 'D', 'C')
+#define PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, PRIVATE_DATA, ConfigAccess, PRIVATE_DATA_SIGNATURE)
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatformPcieDeviceConfigVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatformPcieDeviceConfigDxeStrings[];
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ VARSTORE_DATA LastVarStoreConfig;
+ VARSTORE_DATA VarStoreConfig;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} PRIVATE_DATA;
+
+#endif // PLATFORM_PCIE_DEVICE_CONFIG_H_
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.h
new file mode 100644
index 000000000000..ee4469ea5a2a
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.h
@@ -0,0 +1,56 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_PCIE_DEVICE_CONFIG_VFR_H_
+#define PLATFORM_PCIE_DEVICE_CONFIG_VFR_H_
+
+#include <Guid/PlatformPcieDeviceConfigHii.h>
+
+#define VARSTORE_NAME L"PlatformPcieDeviceConfigNVData"
+
+#define MAIN_FORM_ID 0x01
+#define DEVICE_FORM_ID 0x02
+#define VARSTORE_ID 0x03
+
+#define MAIN_LABEL_UPDATE 0x21
+#define MAIN_LABEL_END 0x22
+#define DEVICE_LABEL_UPDATE 0x31
+#define DEVICE_LABEL_END 0x32
+
+#define DEVICE_KEY 0x6000
+#define MPS_ONE_OF_KEY 0x7000
+#define MRR_ONE_OF_KEY 0x8000
+
+#define MAX_DEVICE 40
+
+#define DEFAULT_MPS 0x00 // Section 7.5.3.4
+#define DEFAULT_MRR 0x02 // Section 7.5.3.4
+
+#define PCIE_ADD(Vid, Did, Seg, Bus, Dev) \
+ (UINT64)(Vid) << 40 | (UINT64)(Did) << 24 | Seg << 16 | Bus << 8 | Dev;
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 DEV;
+ UINT8 BUS;
+ UINT8 SEG;
+ UINT16 DID;
+ UINT16 VID;
+ UINT8 SlotId;
+} SLOT_INFO;
+
+typedef struct {
+ UINT8 MPS[MAX_DEVICE];
+ UINT8 MRR[MAX_DEVICE];
+ UINT64 SlotInfo[MAX_DEVICE];
+} VARSTORE_DATA;
+
+#pragma pack()
+
+#endif /* PLATFORM_PCIE_DEVICE_CONFIG_VFR_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.h
new file mode 100644
index 000000000000..56aed0379539
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.h
@@ -0,0 +1,58 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_PCIE_HELPER_H_
+#define PLATFORM_PCIE_HELPER_H_
+
+#define PCIE_MAX_PAYLOAD_MASK 0x07
+#define PCIE_CONTROL_MAX_PAYLOAD_OFF 5
+#define PCIE_MAX_READ_REQUEST_MASK 0x07
+#define PCIE_CONTROL_READ_REQUEST_OFF 12
+
+#define PCI_EXPRESS_CAPABILITY_DEVICE_CAPABILITIES_REG 0x04
+#define PCI_EXPRESS_CAPABILITY_DEVICE_CONTROL_REG 0x08
+
+#define FOR_EACH(Node, Tail, Type) \
+ for (Node = Tail->Type; Node != NULL; Node = Node->Type)
+
+struct _PCIE_NODE {
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 MaxMps;
+ UINT8 PcieCapOffset;
+ UINT16 Vid;
+ UINT16 Did;
+ UINT8 Seg;
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Fun;
+ struct _PCIE_NODE *Parent;
+ struct _PCIE_NODE *Brother;
+};
+
+typedef struct _PCIE_NODE PCIE_NODE;
+
+EFI_STATUS
+WriteMps (
+ PCIE_NODE *Node,
+ UINT8 Value
+ );
+
+EFI_STATUS
+WriteMrr (
+ PCIE_NODE *Node,
+ UINT8 Value
+ );
+
+EFI_STATUS
+FindCapabilityPtr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 CapabilityId,
+ OUT UINT8 *CapabilityPtr
+ );
+
+#endif // PLATFORM_PCIE_HELPER_H_
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Guid/PlatformPcieDeviceConfigHii.h b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/PlatformPcieDeviceConfigHii.h
new file mode 100644
index 000000000000..ed592a0027ed
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/PlatformPcieDeviceConfigHii.h
@@ -0,0 +1,19 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_PCIE_DEVICE_CONFIG_HII_H_
+#define PLATFORM_PCIE_DEVICE_CONFIG_HII_H_
+
+#define PLATFORM_PCIE_DEVICE_CONFIG_FORMSET_GUID \
+ { \
+ 0xEC7B1D21, 0x9167, 0x4B9D, { 0xF7, 0x94, 0xCD, 0x1A, 0xEB, 0xBC, 0xB7, 0x59 } \
+ }
+
+extern EFI_GUID gPlatformPcieDeviceConfigFormSetGuid;
+
+#endif /* PLATFORM_PCIE_DEVICE_CONFIG_HII_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.vfr b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.vfr
new file mode 100644
index 000000000000..27ca33164e23
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigVfr.vfr
@@ -0,0 +1,50 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/PlatformManagerHii.h>
+#include "PlatformPcieDeviceConfigVfr.h"
+
+formset
+ guid = PLATFORM_PCIE_DEVICE_CONFIG_FORMSET_GUID,
+ title = STRING_TOKEN(STR_DEVICE_CONFIG_FORM),
+ help = STRING_TOKEN(STR_DEVICE_CONFIG_HELP),
+ classguid = gPlatformManagerFormsetGuid,
+
+ //
+ // Define a variable Storage
+ //
+ varstore VARSTORE_DATA,
+ varid = VARSTORE_ID,
+ name = PlatformPcieDeviceConfigNVData,
+ guid = PLATFORM_PCIE_DEVICE_CONFIG_FORMSET_GUID;
+
+ form
+ formid = MAIN_FORM_ID,
+ title = STRING_TOKEN(STR_DEVICE_CONFIG_FORM);
+
+ subtitle text = STRING_TOKEN(STR_DEVICE_CONFIG_FORM);
+
+ label MAIN_LABEL_UPDATE;
+ // dynamic content here
+ label MAIN_LABEL_END;
+
+ endform;
+
+ form
+ formid = DEVICE_FORM_ID,
+ title = STRING_TOKEN(STR_DEVICE_FORM);
+
+ subtitle text = STRING_TOKEN(STR_DEVICE_FORM);
+
+ label DEVICE_LABEL_UPDATE;
+ // dynamic content here
+ label DEVICE_LABEL_END;
+
+ endform;
+
+endformset;
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.c
new file mode 100644
index 000000000000..b06014529c7b
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.c
@@ -0,0 +1,1045 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/PlatformPcieDeviceConfigHii.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/PciIo.h>
+
+#include "PlatformPcieDeviceConfigDxe.h"
+#include "PlatformPcieHelper.h"
+
+VOID *mPciProtocolNotifyRegistration;
+CHAR16 *mVariableName = VARSTORE_NAME;
+PCIE_NODE *mDeviceBuf[MAX_DEVICE] = {NULL};
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ PLATFORM_PCIE_DEVICE_CONFIG_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+VOID
+FlushDeviceData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ PCIE_NODE *Node;
+ PRIVATE_DATA *PrivateData;
+ UINT8 Index;
+ VARSTORE_DATA *LastVarStoreConfig;
+ VARSTORE_DATA *VarStoreConfig;
+
+ PrivateData = (PRIVATE_DATA *)Context;
+ LastVarStoreConfig = &PrivateData->LastVarStoreConfig;
+ VarStoreConfig = &PrivateData->VarStoreConfig;
+
+ //
+ // If config has changed, update NVRAM
+ //
+ if (CompareMem (VarStoreConfig, LastVarStoreConfig, sizeof (VARSTORE_DATA)) != 0) {
+ DEBUG ((DEBUG_INFO, "%a Update Device Config Variable\n", __FUNCTION__));
+ Status = gRT->SetVariable (
+ mVariableName,
+ &gPlatformPcieDeviceConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (VARSTORE_DATA),
+ VarStoreConfig
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to set variable status %r",
+ __FUNCTION__,
+ Status
+ ));
+ return;
+ }
+ }
+
+ // Iterate through the list, then write corresponding MPS MRR
+ for (Index = 0; Index < MAX_DEVICE; Index++) {
+ if (mDeviceBuf[Index] == NULL) {
+ continue;
+ }
+
+ // Write MPS value
+ WriteMps (mDeviceBuf[Index], VarStoreConfig->MPS[Index]);
+
+ FOR_EACH (Node, mDeviceBuf[Index], Parent) {
+ WriteMps (Node, VarStoreConfig->MPS[Index]);
+ }
+
+ FOR_EACH (Node, mDeviceBuf[Index], Brother) {
+ WriteMps (Node, VarStoreConfig->MPS[Index]);
+ }
+
+ // Write MRR value
+ // No need to update MRR of parent node
+ WriteMrr (mDeviceBuf[Index], VarStoreConfig->MRR[Index]);
+
+ FOR_EACH (Node, mDeviceBuf[Index], Brother) {
+ WriteMrr (Node, VarStoreConfig->MRR[Index]);
+ }
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+EFI_STATUS
+UpdateDeviceForm (
+ UINT8 Index,
+ PRIVATE_DATA *PrivateData
+ )
+{
+ CHAR16 Str[MAX_STRING_SIZE];
+ UINT8 MaxMps;
+
+ VOID *StartOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ VOID *MpsOpCodeHandle;
+ VOID *MrrOpCodeHandle;
+ PCIE_NODE *Node;
+
+ if (mDeviceBuf[Index] == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MaxMps = mDeviceBuf[Index]->MaxMps;
+ FOR_EACH (Node, mDeviceBuf[Index], Parent) {
+ if (Node->MaxMps < MaxMps) {
+ MaxMps = Node->MaxMps;
+ }
+ }
+
+ UnicodeSPrint (
+ Str,
+ sizeof (Str),
+ L"PCIe Device 0x%04x:0x%04x",
+ mDeviceBuf[Index]->Vid,
+ mDeviceBuf[Index]->Did
+ );
+
+ HiiSetString (
+ PrivateData->HiiHandle,
+ STRING_TOKEN (STR_DEVICE_FORM),
+ Str,
+ NULL
+ );
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = DEVICE_LABEL_UPDATE;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = DEVICE_LABEL_END;
+
+ // Create Option OpCode for MPS selection
+ MpsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (MpsOpCodeHandle != NULL);
+
+ switch (MaxMps) {
+ case 5:
+ HiiCreateOneOfOptionOpCode (
+ MpsOpCodeHandle,
+ STRING_TOKEN (STR_4096),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 5
+ );
+
+ case 4:
+ HiiCreateOneOfOptionOpCode (
+ MpsOpCodeHandle,
+ STRING_TOKEN (STR_2048),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 4
+ );
+
+ case 3:
+ HiiCreateOneOfOptionOpCode (
+ MpsOpCodeHandle,
+ STRING_TOKEN (STR_1024),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 3
+ );
+
+ case 2:
+ HiiCreateOneOfOptionOpCode (
+ MpsOpCodeHandle,
+ STRING_TOKEN (STR_512),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 2
+ );
+
+ case 1:
+ HiiCreateOneOfOptionOpCode (
+ MpsOpCodeHandle,
+ STRING_TOKEN (STR_256),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 1
+ );
+
+ case 0:
+ HiiCreateOneOfOptionOpCode (
+ MpsOpCodeHandle,
+ STRING_TOKEN (STR_128),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 0
+ );
+ }
+
+ // Create MPS OneOf
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ (MPS_ONE_OF_KEY + Index), // Question ID (or call it "key")
+ VARSTORE_ID, // VarStore ID
+ Index, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PCIE_MPS), // Question prompt text
+ STRING_TOKEN (STR_PCIE_MPS_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ MpsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ // Create Option OpCode for MRR selection
+ MrrOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (MrrOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ MrrOpCodeHandle,
+ STRING_TOKEN (STR_4096),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 5
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ MrrOpCodeHandle,
+ STRING_TOKEN (STR_2048),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 4
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ MrrOpCodeHandle,
+ STRING_TOKEN (STR_1024),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 3
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ MrrOpCodeHandle,
+ STRING_TOKEN (STR_512),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 2
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ MrrOpCodeHandle,
+ STRING_TOKEN (STR_256),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 1
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ MrrOpCodeHandle,
+ STRING_TOKEN (STR_128),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 0
+ );
+
+ // Create MRR OneOf
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ (MRR_ONE_OF_KEY + Index), // Question ID (or call it "key")
+ VARSTORE_ID, // VarStore ID
+ MAX_DEVICE + Index, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PCIE_MRR), // Question prompt text
+ STRING_TOKEN (STR_PCIE_MRR_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ MrrOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &gPlatformPcieDeviceConfigFormSetGuid, // Formset GUID
+ DEVICE_FORM_ID, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ HiiFreeOpCodeHandle (MpsOpCodeHandle);
+ HiiFreeOpCodeHandle (MrrOpCodeHandle);
+ return EFI_SUCCESS;
+}
+
+VOID
+OnPciIoProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ EFI_HANDLE HandleBuffer;
+ PCI_TYPE00 Pci;
+
+ UINTN BufferSize;
+ UINTN PciBusNumber;
+ UINTN PciDeviceNumber;
+ UINTN PciFunctionNumber;
+ UINTN PciSegment;
+
+ UINT8 Idx;
+ UINT8 CapabilityPtr;
+ UINT16 TmpValue;
+ UINT64 SlotInfo;
+
+ PCIE_NODE *Node;
+ PRIVATE_DATA *PrivateData;
+ STATIC PCIE_NODE *LastNode;
+ STATIC UINT8 Index;
+ STATIC UINT8 LastBus;
+
+ VARSTORE_DATA *LastVarStoreConfig;
+ VARSTORE_DATA *VarStoreConfig;
+
+ PrivateData = (PRIVATE_DATA *)Context;
+ LastVarStoreConfig = &PrivateData->LastVarStoreConfig;
+ VarStoreConfig = &PrivateData->VarStoreConfig;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mPciProtocolNotifyRegistration,
+ &BufferSize,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ // Get device bus location
+ Status = PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBusNumber,
+ &PciDeviceNumber,
+ &PciFunctionNumber
+ );
+ if (EFI_ERROR (Status) ||
+ ((PciBusNumber == 0) && (PciDeviceNumber == 0)))
+ {
+ // Filter out Host Bridge
+ DEBUG ((DEBUG_INFO, "Filter out Host Bridge %x\n", PciSegment));
+ continue;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ ">> Dev 0x%04x:0x%02x:0x%02x:0x%02x\n",
+ PciSegment,
+ PciBusNumber,
+ PciDeviceNumber,
+ PciFunctionNumber
+ ));
+
+ Status = FindCapabilityPtr (PciIo, EFI_PCI_CAPABILITY_ID_PCIEXP, &CapabilityPtr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: PCI Express Capability not found\n",
+ __FUNCTION__
+ ));
+ continue;
+ }
+
+ // Get Device's max MPS support
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ CapabilityPtr + PCI_EXPRESS_CAPABILITY_DEVICE_CAPABILITIES_REG,
+ 1,
+ &TmpValue
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ // Read device's VID:PID
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "VendorId 0x%04x - DeviceId 0x%04x\n",
+ Pci.Hdr.VendorId,
+ Pci.Hdr.DeviceId
+ ));
+
+ Node = AllocateZeroPool (sizeof (*Node));
+ Node->MaxMps = TmpValue & PCIE_MAX_PAYLOAD_MASK;
+ Node->PcieCapOffset = CapabilityPtr;
+ Node->PciIo = PciIo;
+ Node->Seg = PciSegment;
+ Node->Bus = PciBusNumber;
+ Node->Dev = PciDeviceNumber;
+ Node->Fun = PciFunctionNumber;
+ Node->Vid = Pci.Hdr.VendorId;
+ Node->Did = Pci.Hdr.DeviceId;
+ SlotInfo = PCIE_ADD (Node->Vid, Node->Did, Node->Seg, Node->Bus, Node->Dev);
+
+ // Presume child devices were registered follow root port
+ if (PciBusNumber != 0) {
+ if (LastBus == 0) {
+ Node->Parent = LastNode;
+ mDeviceBuf[Index] = Node;
+
+ VarStoreConfig->MPS[Index] = DEFAULT_MPS;
+ VarStoreConfig->MRR[Index] = DEFAULT_MRR;
+ VarStoreConfig->SlotInfo[Index] = SlotInfo;
+
+ // Retrieve setting from previous variable
+ for (Idx = 0; Idx < MAX_DEVICE; Idx++) {
+ if (SlotInfo == LastVarStoreConfig->SlotInfo[Idx]) {
+ VarStoreConfig->MPS[Index] = LastVarStoreConfig->MPS[Idx];
+ VarStoreConfig->MRR[Index] = LastVarStoreConfig->MRR[Idx];
+ break;
+ }
+ }
+
+ Index++;
+ } else if (PciBusNumber == LastBus) {
+ LastNode->Brother = Node;
+ } else {
+ // Ignore devices don't stay under root port
+ continue;
+ }
+ }
+
+ LastBus = PciBusNumber;
+ LastNode = Node;
+ }
+}
+
+VOID
+UpdateMainForm (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+ EFI_STRING_ID StrId;
+ CHAR16 Str[MAX_STRING_SIZE];
+ VOID *StartOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ PRIVATE_DATA *PrivateData;
+
+ DEBUG ((DEBUG_INFO, "%a Entry ...\n", __FUNCTION__));
+
+ PrivateData = (PRIVATE_DATA *)Context;
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = MAIN_LABEL_UPDATE;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = MAIN_LABEL_END;
+
+ for (Index = 0; Index < MAX_DEVICE; Index++) {
+ if (mDeviceBuf[Index] == NULL) {
+ break;
+ }
+ DEBUG ((DEBUG_INFO, ">> Add item %d\n", Index));
+
+ UnicodeSPrint (
+ Str,
+ sizeof (Str),
+ L"PCIe Device 0x%04x:0x%04x - %04x:%02x:%02x",
+ mDeviceBuf[Index]->Vid,
+ mDeviceBuf[Index]->Did,
+ mDeviceBuf[Index]->Seg,
+ mDeviceBuf[Index]->Bus,
+ mDeviceBuf[Index]->Dev
+ );
+
+ StrId = HiiSetString (PrivateData->HiiHandle, 0, Str, NULL);
+
+ //
+ // Create a Goto OpCode to device configuration
+ //
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ DEVICE_FORM_ID, // Target Form ID
+ StrId, // Prompt text
+ STRING_TOKEN (STR_DEVICE_GOTO_HELP), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ (DEVICE_KEY + Index) // Question ID
+ );
+ }
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &gPlatformPcieDeviceConfigFormSetGuid, // Formset GUID
+ MAIN_FORM_ID, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ gBS->CloseEvent (Event);
+}
+
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ UINTN Size;
+ CHAR16 *StrPointer;
+ BOOLEAN AllocatedRequest;
+ VARSTORE_DATA *VarStoreConfig;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ PrivateData = PRIVATE_DATA_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ VarStoreConfig = &PrivateData->VarStoreConfig;
+ ASSERT (VarStoreConfig != NULL);
+
+ BufferSize = sizeof (VARSTORE_DATA);
+
+ if (Request == NULL) {
+ //
+ // Request is set to NULL, construct full request string.
+ //
+
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a
+ // Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (
+ &gPlatformPcieDeviceConfigFormSetGuid,
+ mVariableName,
+ PrivateData->DriverHandle
+ );
+ if (ConfigRequestHdr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (
+ ConfigRequest,
+ Size,
+ L"%s&OFFSET=0&WIDTH=%016LX",
+ ConfigRequestHdr,
+ (UINT64)BufferSize
+ );
+ FreePool (ConfigRequestHdr);
+ ConfigRequestHdr = NULL;
+ } else {
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Request, &gPlatformPcieDeviceConfigFormSetGuid, NULL)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Set Request to the unified request string.
+ //
+ ConfigRequest = Request;
+
+ //
+ // Check whether Request includes Request Element.
+ //
+ if (StrStr (Request, L"OFFSET") == NULL) {
+ //
+ // Check Request Element does exist in Request String
+ //
+ StrPointer = StrStr (Request, L"PATH");
+ if (StrPointer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (StrStr (StrPointer, L"&") == NULL) {
+ Size = (StrLen (Request) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (
+ ConfigRequest,
+ Size,
+ L"%s&OFFSET=0&WIDTH=%016LX",
+ Request,
+ (UINT64)BufferSize
+ );
+ }
+ }
+ }
+ //
+ // Check if requesting Name/Value storage
+ //
+ if (StrStr (ConfigRequest, L"OFFSET") == NULL) {
+ //
+ // Don't have any Name/Value storage names
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *)VarStoreConfig,
+ BufferSize,
+ Results,
+ Progress
+ );
+ }
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ }
+ if (ConfigRequestHdr != NULL) {
+ FreePool (ConfigRequestHdr);
+ }
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ VARSTORE_DATA *VarStoreConfig;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ PrivateData = PRIVATE_DATA_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+ VarStoreConfig = &PrivateData->VarStoreConfig;
+ ASSERT (VarStoreConfig != NULL);
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (
+ Configuration,
+ &gPlatformPcieDeviceConfigFormSetGuid,
+ NULL
+ ))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check if configuring Name/Value storage
+ //
+ if (StrStr (Configuration, L"OFFSET") == NULL) {
+ //
+ // Don't have any Name/Value storage names
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (VARSTORE_DATA);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *)VarStoreConfig,
+ &BufferSize,
+ Progress
+ );
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+**/
+EFI_STATUS
+EFIAPI
+DriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ EFI_STATUS Status;
+ PRIVATE_DATA *PrivateData;
+
+ if (((Value == NULL) &&
+ (Action != EFI_BROWSER_ACTION_FORM_OPEN) &&
+ (Action != EFI_BROWSER_ACTION_FORM_CLOSE)) ||
+ (ActionRequest == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PRIVATE_DATA_FROM_THIS (This);
+
+ switch (Action) {
+ case EFI_BROWSER_ACTION_CHANGING:
+ if ((QuestionId >= DEVICE_KEY)
+ & (QuestionId <= (DEVICE_KEY + MAX_DEVICE)))
+ {
+ Status = UpdateDeviceForm (QuestionId - DEVICE_KEY, PrivateData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_DEFAULT_STANDARD:
+ case EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING:
+ if ((QuestionId >= MPS_ONE_OF_KEY)
+ & (QuestionId <= (MPS_ONE_OF_KEY + MAX_DEVICE)))
+ {
+ Value->u8 = DEFAULT_MPS;
+ }
+
+ if ((QuestionId >= MRR_ONE_OF_KEY)
+ & (QuestionId <= (MRR_ONE_OF_KEY + MAX_DEVICE)))
+ {
+ Value->u8 = DEFAULT_MRR;
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_SUBMITTED:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+PlatformPcieDeviceConfigEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_STATUS Status;
+ EFI_EVENT PlatformUiEntryEvent;
+ EFI_EVENT FlushDeviceEvent;
+ EFI_EVENT PciProtocolNotifyEvent;
+ PRIVATE_DATA *PrivateData;
+ UINTN BufferSize;
+
+ DriverHandle = NULL;
+ PrivateData = AllocateZeroPool (sizeof (*PrivateData));
+ if (PrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ PrivateData->Signature = PRIVATE_DATA_SIGNATURE;
+
+ PrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ PrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ PrivateData->ConfigAccess.Callback = DriverCallback;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID **)&HiiConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ PrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &PrivateData->ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ PrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle = HiiAddPackages (
+ &gPlatformPcieDeviceConfigFormSetGuid,
+ DriverHandle,
+ PlatformPcieDeviceConfigDxeStrings,
+ PlatformPcieDeviceConfigVfrBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ PrivateData->HiiHandle = HiiHandle;
+
+ // Event to fixup screen
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ UpdateMainForm,
+ (VOID *)PrivateData,
+ &gPlatformManagerEntryEventGuid,
+ &PlatformUiEntryEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ // Event to collect PciIo
+ PciProtocolNotifyEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiPciIoProtocolGuid,
+ TPL_CALLBACK,
+ OnPciIoProtocolNotify,
+ (VOID *)PrivateData,
+ &mPciProtocolNotifyRegistration
+ );
+ ASSERT (PciProtocolNotifyEvent != NULL);
+
+ // Event to flush device data
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ FlushDeviceData,
+ (VOID *)PrivateData,
+ &gEfiEventReadyToBootGuid,
+ &FlushDeviceEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ // Verify varstore
+ BufferSize = sizeof (VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ mVariableName,
+ &gPlatformPcieDeviceConfigFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->LastVarStoreConfig
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Last config is not found\n", __FUNCTION__));
+ }
+
+ return EFI_SUCCESS;
+
+Exit:
+ FreePool (PrivateData);
+ return Status;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.c
new file mode 100644
index 000000000000..6bd753ef327f
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieHelper.c
@@ -0,0 +1,191 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <IndustryStandard/Pci.h>
+#include <Protocol/PciIo.h>
+
+#include "PlatformPcieDeviceConfigDxe.h"
+#include "PlatformPcieHelper.h"
+
+EFI_STATUS
+FindCapabilityPtr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 CapabilityId,
+ OUT UINT8 *CapabilityPtr
+ )
+{
+ EFI_STATUS Status;
+ UINT8 NextPtr;
+ UINT16 TmpValue;
+
+ ASSERT (PciIo != NULL);
+
+ //
+ // Get pointer to first PCI Capability header
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CAPBILITY_POINTER_OFFSET,
+ 1,
+ &NextPtr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ while (TRUE) {
+ if (NextPtr == 0x00) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ //
+ // Retrieve PCI Capability header
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ NextPtr,
+ 1,
+ &TmpValue
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((TmpValue & 0xFF) == CapabilityId) {
+ *CapabilityPtr = NextPtr;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ NextPtr = (TmpValue >> 8) & 0xFF;
+ }
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+WriteMps (
+ PCIE_NODE *Node,
+ UINT8 Value
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT16 TmpValue;
+ UINT8 PcieCapOffset;
+
+ if (Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PciIo = Node->PciIo;
+ PcieCapOffset = Node->PcieCapOffset;
+
+ // Get current device control reg
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PcieCapOffset + PCI_EXPRESS_CAPABILITY_DEVICE_CONTROL_REG,
+ 1,
+ &TmpValue
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Update value and write to device
+ TmpValue = (TmpValue & ~(PCIE_MAX_PAYLOAD_MASK << PCIE_CONTROL_MAX_PAYLOAD_OFF))
+ | Value << PCIE_CONTROL_MAX_PAYLOAD_OFF;
+ Status = PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PcieCapOffset + PCI_EXPRESS_CAPABILITY_DEVICE_CONTROL_REG,
+ 1,
+ &TmpValue
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Write MPS %d to device 0x%04x:0x%02x:0x%02x:0x%02x\n",
+ __FUNCTION__,
+ Value,
+ Node->Seg,
+ Node->Bus,
+ Node->Dev,
+ Node->Fun
+ ));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+WriteMrr (
+ PCIE_NODE *Node,
+ UINT8 Value
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT16 TmpValue;
+ UINT8 PcieCapOffset;
+
+ if (Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PciIo = Node->PciIo;
+ PcieCapOffset = Node->PcieCapOffset;
+
+ // Get current device control reg
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PcieCapOffset + PCI_EXPRESS_CAPABILITY_DEVICE_CONTROL_REG,
+ 1,
+ &TmpValue
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Update value and write to device
+ TmpValue = (TmpValue & ~(PCIE_MAX_READ_REQUEST_MASK << PCIE_CONTROL_READ_REQUEST_OFF))
+ | Value << PCIE_CONTROL_READ_REQUEST_OFF;
+ Status = PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PcieCapOffset + PCI_EXPRESS_CAPABILITY_DEVICE_CONTROL_REG,
+ 1,
+ &TmpValue
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Write MRR %d to device 0x%04x:0x%02x:0x%02x:0x%02x\n",
+ __FUNCTION__,
+ Value,
+ Node->Seg,
+ Node->Bus,
+ Node->Dev,
+ Node->Fun
+ ));
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.uni
new file mode 100644
index 000000000000..f6cd94ffee36
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformPcieDeviceConfigDxe/PlatformPcieDeviceConfigDxe.uni
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#langdef en-US "English" // English
+
+#string STR_DEVICE_CONFIG_FORM #language en-US "PCIE Device Configuration"
+#string STR_DEVICE_CONFIG_HELP #language en-US "PCIE Device Configuration"
+
+#string STR_DEVICE_FORM #language en-US "PCIE Device Form"
+#string STR_DEVICE_GOTO_HELP #language en-US "PCIE Device Configuration"
+
+#string STR_PCIE_MPS #language en-US "Max Payload Size"
+#string STR_PCIE_MPS_HELP #language en-US "Max Payload Size"
+#string STR_PCIE_MRR #language en-US "Max Read Request Size"
+#string STR_PCIE_MRR_HELP #language en-US "Max Read Request Size"
+#string STR_128 #language en-US "128 bytes"
+#string STR_256 #language en-US "256 bytes"
+#string STR_512 #language en-US "512 bytes"
+#string STR_1024 #language en-US "1024 bytes"
+#string STR_2048 #language en-US "2048 bytes"
+#string STR_4096 #language en-US "4096 bytes"
--
2.17.1


Re: [PATCH v3 27/28] AmpereAltraPkg: Add configuration screen for Watchdog timer

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:26 +0700, Nhi Pham wrote:
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

There are secure and non-secure watchdog timers supported in the Mt.
Jade system. They are used to monitor the system booting like system
firmware, UEFI, and OS. The system will be reset if the timer expires.
So, this patch adds the configuration screen for the watchdog timer
which provides options to configure the timeout of these timers.

By default, the values of these options are 5 minutes.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 +
Platform/Ampere/JadePkg/Jade.dsc | 1 +
Platform/Ampere/JadePkg/Jade.fdf | 1 +
Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf | 50 +++
Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.h | 82 ++++
Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigNVDataStruct.h | 27 ++
Silicon/Ampere/AmpereAltraPkg/Include/Guid/WatchdogConfigHii.h | 19 +
Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigVfr.vfr | 58 +++
Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.c | 460 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigStrings.uni | 26 ++
10 files changed, 727 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index 196611d67280..b0e1f3ec6f2a 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -56,6 +56,9 @@ [Guids]
# GUID for the ACPI HII configuration form
gAcpiConfigFormSetGuid = { 0x0ceb6764, 0xd415, 0x4b01, { 0xa8, 0x43, 0xd1, 0x01, 0xbc, 0xb0, 0xd8, 0x29 } }

+ # GUID for the Watchdog HII configuration form
+ gWatchdogConfigFormSetGuid = { 0xC3F8EC6E, 0x95EE, 0x460C, { 0xA4, 0x8D, 0xEA, 0x54, 0x2F, 0xFF, 0x01, 0x61 } }
+
## NVParam MM GUID
gNVParamMmGuid = { 0xE4AC5024, 0x29BE, 0x4ADC, { 0x93, 0x36, 0x87, 0xB5, 0xA0, 0x76, 0x23, 0x2D } }

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index b5ac2547c8f8..b752ea3e5264 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -201,3 +201,4 @@ [Components.common]
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index e0d4b049f6bf..8f3df6ccf01b 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -359,5 +359,6 @@ [FV.FvMain]
INF Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf

!include Platform/Ampere/AmperePlatformPkg/FvRules.fdf.inc
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf
new file mode 100644
index 000000000000..3ed37bfb15da
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.inf
@@ -0,0 +1,50 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = WatchdogConfigDxe
+ FILE_GUID = 135A0CA5-4851-4EF5-9E1A-C6E4610C39A9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = WatchdogConfigInitialize
+
+[Sources.common]
+ WatchdogConfigNVDataStruct.h
+ WatchdogConfigVfr.vfr
+ WatchdogConfigStrings.uni
+ WatchdogConfigDxe.c
+ WatchdogConfigDxe.h
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ DevicePathLib
+ HiiLib
+ NVParamLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Guids]
+ gPlatformManagerFormsetGuid
+ gWatchdogConfigFormSetGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.h
new file mode 100644
index 000000000000..5f47531c538e
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.h
@@ -0,0 +1,82 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef WATCHDOG_CONFIG_DXE_H_
+#define WATCHDOG_CONFIG_DXE_H_
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NVParamLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <NVParamDef.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
Should only include files actually required here.

/
Leif

+
+#include "WatchdogConfigNVDataStruct.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+//
+extern UINT8 WatchdogConfigVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+//
+extern UINT8 WatchdogConfigDxeStrings[];
+
+#define WATCHDOG_CONFIG_PRIVATE_SIGNATURE SIGNATURE_32 ('W', 'D', 'T', 'C')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ WATCHDOG_CONFIG_VARSTORE_DATA Configuration;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} WATCHDOG_CONFIG_PRIVATE_DATA;
+
+#define WATCHDOG_CONFIG_PRIVATE_FROM_THIS(a) CR (a, WATCHDOG_CONFIG_PRIVATE_DATA, ConfigAccess, WATCHDOG_CONFIG_PRIVATE_SIGNATURE)
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+EFI_STATUS
+WatchdogConfigNvParamSet (
+ IN WATCHDOG_CONFIG_VARSTORE_DATA *VarStoreConfig
+ );
+
+EFI_STATUS
+WatchdogConfigNvParamGet (
+ OUT WATCHDOG_CONFIG_VARSTORE_DATA *VarStoreConfig
+ );
+
+#endif /* WATCHDOG_CONFIG_DXE_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigNVDataStruct.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigNVDataStruct.h
new file mode 100644
index 000000000000..470a2821ffe7
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigNVDataStruct.h
@@ -0,0 +1,27 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef WATCHDOG_CONFIG_NV_DATA_STRUCT_H_
+#define WATCHDOG_CONFIG_NV_DATA_STRUCT_H_
+
+#include <Guid/WatchdogConfigHii.h>
+
+#define WATCHDOG_CONFIG_VARSTORE_ID 0x1234
+#define WATCHDOG_CONFIG_FORM_ID 0x1235
+
+#define NWDT_UEFI_DEFAULT_VALUE 300 // 5 minutes
+#define SWDT_DEFAULT_VALUE 300 // 5 minutes
+
+#pragma pack(1)
+typedef struct {
+ UINT32 WatchdogTimerUEFITimeout;
+ UINT32 SecureWatchdogTimerTimeout;
+} WATCHDOG_CONFIG_VARSTORE_DATA;
+#pragma pack()
+
+#endif /* WATCHDOG_CONFIG_NV_DATA_STRUCT_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Guid/WatchdogConfigHii.h b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/WatchdogConfigHii.h
new file mode 100644
index 000000000000..16319d61a759
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/WatchdogConfigHii.h
@@ -0,0 +1,19 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef WATCHDOG_CONFIG_HII_H_
+#define WATCHDOG_CONFIG_HII_H_
+
+#define WATCHDOG_CONFIG_FORMSET_GUID \
+ { \
+ 0xC3F8EC6E, 0x95EE, 0x460C, { 0xA4, 0x8D, 0xEA, 0x54, 0x2F, 0xFF, 0x01, 0x61 } \
+ }
+
+extern EFI_GUID gWatchdogConfigFormSetGuid;
+
+#endif /* WATCHDOG_CONFIG_HII_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigVfr.vfr b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigVfr.vfr
new file mode 100644
index 000000000000..48f2aef227f6
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigVfr.vfr
@@ -0,0 +1,58 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "WatchdogConfigNVDataStruct.h"
+
+formset
+ guid = WATCHDOG_CONFIG_FORMSET_GUID,
+ title = STRING_TOKEN(STR_WATCHDOG_CONFIG_FORM),
+ help = STRING_TOKEN(STR_WATCHDOG_CONFIG_FORM_HELP),
+ classguid = gPlatformManagerFormsetGuid,
+
+ //
+ // Define a variable Storage
+ //
+ varstore WATCHDOG_CONFIG_VARSTORE_DATA,
+ varid = WATCHDOG_CONFIG_VARSTORE_ID,
+ name = WatchdogConfigNVData,
+ guid = WATCHDOG_CONFIG_FORMSET_GUID;
+
+ form
+ formid = WATCHDOG_CONFIG_FORM_ID,
+ title = STRING_TOKEN(STR_WATCHDOG_CONFIG_FORM);
+ subtitle text = STRING_TOKEN(STR_WATCHDOG_CONFIG_FORM_HELP);
+
+ oneof varid = WatchdogConfigNVData.WatchdogTimerUEFITimeout,
+ prompt = STRING_TOKEN(STR_NWDT_TIMEOUT_UEFI),
+ help = STRING_TOKEN(STR_NWDT_TIMEOUT_UEFI_HELP),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN (STR_WDT_TIME_DISABLE), value = 0, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_5MIN), value = 300, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_6MIN), value = 360, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_10MIN), value = 600, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_15MIN), value = 900, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_20MIN), value = 1200, flags = 0;
+ default = NWDT_UEFI_DEFAULT_VALUE,
+ endoneof;
+
+ oneof varid = WatchdogConfigNVData.SecureWatchdogTimerTimeout,
+ prompt = STRING_TOKEN(STR_SWDT_TIMEOUT),
+ help = STRING_TOKEN(STR_SWDT_TIMEOUT_HELP),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN (STR_WDT_TIME_DISABLE), value = 0, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_5MIN), value = 300, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_6MIN), value = 360, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_10MIN), value = 600, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_15MIN), value = 900, flags = 0;
+ option text = STRING_TOKEN (STR_WDT_TIME_20MIN), value = 1200, flags = 0;
+ default = SWDT_DEFAULT_VALUE,
+ endoneof;
+
+ endform;
+
+endformset;
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.c
new file mode 100644
index 000000000000..bd7b929dccda
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigDxe.c
@@ -0,0 +1,460 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "WatchdogConfigDxe.h"
+
+CHAR16 WatchDogConfigVarstoreDataName[] = L"WatchdogConfigNVData";
+
+EFI_HANDLE mDriverHandle = NULL;
+WATCHDOG_CONFIG_PRIVATE_DATA *mPrivateData = NULL;
+
+HII_VENDOR_DEVICE_PATH mWatchdogConfigHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ WATCHDOG_CONFIG_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+EFI_STATUS
+WatchdogConfigNvParamGet (
+ OUT WATCHDOG_CONFIG_VARSTORE_DATA *VarStoreConfig
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Value;
+ BOOLEAN SetDefault;
+
+ SetDefault = FALSE;
+ Status = NVParamGet (
+ NV_SI_WDT_BIOS_EXP_MINS,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->WatchdogTimerUEFITimeout = NWDT_UEFI_DEFAULT_VALUE;
+ if (Status == EFI_NOT_FOUND) {
+ SetDefault = TRUE;
+ } else {
+ ASSERT (FALSE);
+ }
+ } else {
+ VarStoreConfig->WatchdogTimerUEFITimeout = Value * 60;
+ }
+
+ Status = NVParamGet (
+ NV_SI_SEC_WDT_BIOS_EXP_MINS,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->SecureWatchdogTimerTimeout = SWDT_DEFAULT_VALUE;
+ if (Status == EFI_NOT_FOUND) {
+ SetDefault = TRUE;
+ } else {
+ ASSERT (FALSE);
+ }
+ } else {
+ VarStoreConfig->SecureWatchdogTimerTimeout = Value;
+ }
+
+ if (SetDefault) {
+ WatchdogConfigNvParamSet (VarStoreConfig);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+WatchdogConfigNvParamSet (
+ IN WATCHDOG_CONFIG_VARSTORE_DATA *VarStoreConfig
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Value;
+
+ Status = NVParamGet (
+ NV_SI_WDT_BIOS_EXP_MINS,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)
+ || Value != (VarStoreConfig->WatchdogTimerUEFITimeout / 60))
+ {
+ Status = NVParamSet (
+ NV_SI_WDT_BIOS_EXP_MINS,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ (VarStoreConfig->WatchdogTimerUEFITimeout / 60)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = NVParamGet (
+ NV_SI_SEC_WDT_BIOS_EXP_MINS,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)
+ || Value != VarStoreConfig->SecureWatchdogTimerTimeout)
+ {
+ Status = NVParamSet (
+ NV_SI_SEC_WDT_BIOS_EXP_MINS,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ VarStoreConfig->SecureWatchdogTimerTimeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogConfigExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ WATCHDOG_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ UINTN Size;
+ BOOLEAN AllocatedRequest;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gWatchdogConfigFormSetGuid, WatchDogConfigVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = WATCHDOG_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get current setting from NVParam.
+ //
+ Status = WatchdogConfigNvParamGet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ BufferSize = sizeof (WATCHDOG_CONFIG_VARSTORE_DATA);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gWatchdogConfigFormSetGuid, WatchDogConfigVarstoreDataName, PrivateData->DriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ if (ConfigRequest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *)&PrivateData->Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogConfigRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ WATCHDOG_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = WATCHDOG_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gWatchdogConfigFormSetGuid, WatchDogConfigVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get configuration data from NVParam
+ //
+ Status = WatchdogConfigNvParamGet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (WATCHDOG_CONFIG_VARSTORE_DATA);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *)&PrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store configuration data back to NVParam
+ //
+ Status = WatchdogConfigNvParamSet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogConfigCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if (Action != EFI_BROWSER_ACTION_CHANGING) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ if (((Value == NULL)
+ && (Action != EFI_BROWSER_ACTION_FORM_OPEN)
+ && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))
+ || (ActionRequest == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+WatchdogConfigInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ //
+ // Initialize driver private data
+ //
+ mPrivateData = AllocateZeroPool (sizeof (WATCHDOG_CONFIG_PRIVATE_DATA));
+ if (mPrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->Signature = WATCHDOG_CONFIG_PRIVATE_SIGNATURE;
+
+ mPrivateData->ConfigAccess.ExtractConfig = WatchdogConfigExtractConfig;
+ mPrivateData->ConfigAccess.RouteConfig = WatchdogConfigRouteConfig;
+ mPrivateData->ConfigAccess.Callback = WatchdogConfigCallback;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&HiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mWatchdogConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle = mDriverHandle;
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle = HiiAddPackages (
+ &gWatchdogConfigFormSetGuid,
+ mDriverHandle,
+ WatchdogConfigDxeStrings,
+ WatchdogConfigVfrBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mWatchdogConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle = HiiHandle;
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigStrings.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigStrings.uni
new file mode 100644
index 000000000000..1d0f820e456f
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/WatchdogConfigDxe/WatchdogConfigStrings.uni
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#langdef en-US "English"
+
+#string STR_WATCHDOG_CONFIG_FORM #language en-US "Watchdog Configuration"
+#string STR_WATCHDOG_CONFIG_FORM_HELP #language en-US "Watchdog Configuration"
+
+#string STR_WDT_TIME_DISABLE #language en-US "Disabled"
+#string STR_WDT_TIME_3MIN #language en-US "3 minutes"
+#string STR_WDT_TIME_4MIN #language en-US "4 minutes"
+#string STR_WDT_TIME_5MIN #language en-US "5 minutes"
+#string STR_WDT_TIME_6MIN #language en-US "6 minutes"
+#string STR_WDT_TIME_10MIN #language en-US "10 minutes"
+#string STR_WDT_TIME_15MIN #language en-US "15 minutes"
+#string STR_WDT_TIME_20MIN #language en-US "20 minutes"
+
+#string STR_NWDT_TIMEOUT_OS #language en-US "OS Watchdog Timeout"
+#string STR_NWDT_TIMEOUT_OS_HELP #language en-US "Timeout when boot OS."
+#string STR_NWDT_TIMEOUT_UEFI #language en-US "UEFI Watchdog Timeout"
+#string STR_NWDT_TIMEOUT_UEFI_HELP #language en-US "Timeout when boot UEFI"
+#string STR_SWDT_TIMEOUT #language en-US "Secure Watchdog Timeout"
+#string STR_SWDT_TIMEOUT_HELP #language en-US "Timeout when SCP will reset system if it doesn't receive response from ARMv8."
--
2.17.1


Re: [PATCH v3 26/28] AmpereAltraPkg: Add configuration screen for RAS

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:25 +0700, Nhi Pham wrote:
From: Quan Nguyen <quan@os.amperecomputing.com>

This supports user to enable/disable RAS APEI components running in the
system firmware such as HEST, BERT, and EINJ.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Quan Nguyen <quan@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>

---
Platform/Ampere/JadePkg/Jade.dsc | 1 +
Platform/Ampere/JadePkg/Jade.fdf | 1 +
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf | 56 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.h | 61 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigNVDataStruct.h | 46 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigVfr.vfr | 95 +++
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.c | 822 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigStrings.uni | 38 +
8 files changed, 1120 insertions(+)

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index daac52e84ea2..b5ac2547c8f8 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -200,3 +200,4 @@ [Components.common]
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 1564e45c30cd..e0d4b049f6bf 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -358,5 +358,6 @@ [FV.FvMain]
INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf

!include Platform/Ampere/AmperePlatformPkg/FvRules.fdf.inc
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf
new file mode 100644
index 000000000000..9b03ed57944f
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.inf
@@ -0,0 +1,56 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = RasConfigDxe
+ FILE_GUID = 5b5ee6e3-3135-45f7-ad21-46a3f36813cc
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RasConfigEntryPoint
+
+[Sources.common]
+ RasConfigNVDataStruct.h
+ RasConfigDxe.c
+ RasConfigDxe.h
+ RasConfigVfr.vfr
+ RasConfigStrings.uni
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ AmpereCpuLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ DevicePathLib
+ HiiLib
+ MemoryAllocationLib
+ NVParamLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Guids]
+ gEfiIfrTianoGuid
+ gPlatformManagerFormsetGuid
+ gAcpiConfigFormSetGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.h
new file mode 100644
index 000000000000..1258fbeda6a1
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.h
@@ -0,0 +1,61 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef RAS_CONFIG_DXE_H_
+#define RAS_CONFIG_DXE_H_
+
+#include "RasConfigNVDataStruct.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+//
+extern UINT8 RasConfigVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+//
+extern UINT8 RasConfigDxeStrings[];
+
+#define RAS_DDR_CE_THRESHOLD_OFST OFFSET_OF (RAS_CONFIG_VARSTORE_DATA, RasDdrCeThreshold)
+#define RAS_2P_CE_THRESHOLD_OFST OFFSET_OF (RAS_CONFIG_VARSTORE_DATA, Ras2pCeThreshold)
+
+#define RAS_CONFIG_PRIVATE_SIGNATURE SIGNATURE_32 ('R', 'A', 'S', 'C')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ RAS_CONFIG_VARSTORE_DATA Configuration;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} RAS_CONFIG_PRIVATE_DATA;
+
+#define RAS_CONFIG_PRIVATE_FROM_THIS(a) CR (a, RAS_CONFIG_PRIVATE_DATA, ConfigAccess, RAS_CONFIG_PRIVATE_SIGNATURE)
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+#endif /* RAS_CONFIG_DXE_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigNVDataStruct.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigNVDataStruct.h
new file mode 100644
index 000000000000..8c528f043c27
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigNVDataStruct.h
@@ -0,0 +1,46 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef RAS_CONFIG_NV_DATA_STRUCT_H_
+#define RAS_CONFIG_NV_DATA_STRUCT_H_
+
+#define RAS_CONFIG_VARSTORE_ID 0x1234
+#define RAS_CONFIG_FORM_ID 0x1235
+
+#define RAS_VARSTORE_NAME L"RasConfigNVData"
+
+#define RAS_CONFIG_FORMSET_GUID \
+ { \
+ 0x96934cc6, 0xcb15, 0x4d8a, { 0xbe, 0x5f, 0x8e, 0x7d, 0x55, 0x0e, 0xc9, 0xc6 } \
+ }
+
+//
+// Labels definition
+//
+#define LABEL_UPDATE 0x3234
+#define LABEL_END 0xffff
+
+#pragma pack(1)
+
+//
+// Ras Configuration NV data structure definition
+//
+typedef struct {
+ UINT32 RasHardwareEinj;
+ UINT32 RasPcieAerFwFirstEnabled;
+ UINT32 RasBertEnabled;
+ UINT32 RasSdeiEnabled;
+ UINT32 RasDdrCeThreshold;
+ UINT32 Ras2pCeThreshold;
+ UINT32 RasCpmCeThreshold;
+ UINT32 RasLinkErrThreshold;
+} RAS_CONFIG_VARSTORE_DATA;
+
+#pragma pack()
+
+#endif /* RAS_CONFIG_NV_DATA_STRUCT_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigVfr.vfr b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigVfr.vfr
new file mode 100644
index 000000000000..ec38eb186c1b
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigVfr.vfr
@@ -0,0 +1,95 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RasConfigNVDataStruct.h"
+
+formset
+ guid = RAS_CONFIG_FORMSET_GUID,
+ title = STRING_TOKEN(STR_RAS_FORM),
+ help = STRING_TOKEN(STR_RAS_FORM_HELP),
+ classguid = gPlatformManagerFormsetGuid,
+
+ //
+ // Define a variable Storage
+ //
+ varstore RAS_CONFIG_VARSTORE_DATA,
+ varid = RAS_CONFIG_VARSTORE_ID,
+ name = RasConfigNVData,
+ guid = RAS_CONFIG_FORMSET_GUID;
+
+ form formid = RAS_CONFIG_FORM_ID,
+ title = STRING_TOKEN(STR_RAS_FORM);
+
+ subtitle text = STRING_TOKEN(STR_RAS_FORM);
+
+ oneof varid = RasConfigNVData.RasHardwareEinj,
+ prompt = STRING_TOKEN(STR_RAS_HARDWARE_EINJ_PROMPT),
+ help = STRING_TOKEN(STR_RAS_HARDWARE_EINJ_HELP),
+ flags = NUMERIC_SIZE_4 | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_RAS_COMMON_ENABLE), value = 1, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_RAS_COMMON_DISABLE), value = 0, flags = 0;
+
+ endoneof;
+
+ oneof varid = RasConfigNVData.RasPcieAerFwFirstEnabled,
+ prompt = STRING_TOKEN(STR_RAS_PCIE_AER_FW_FIRST_PROMPT),
+ help = STRING_TOKEN(STR_RAS_PCIE_AER_FW_FIRST_HELP),
+ flags = NUMERIC_SIZE_4 | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_RAS_COMMON_ENABLE), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_RAS_COMMON_DISABLE), value = 0, flags = DEFAULT;
+
+ endoneof;
+
+ oneof varid = RasConfigNVData.RasBertEnabled,
+ prompt = STRING_TOKEN(STR_RAS_BERT_ENABLED_PROMPT),
+ help = STRING_TOKEN(STR_RAS_BERT_ENABLED_HELP),
+ flags = NUMERIC_SIZE_4 | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_RAS_COMMON_ENABLE), value = 1, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_RAS_COMMON_DISABLE), value = 0, flags = 0;
+
+ endoneof;
+
+ oneof varid = RasConfigNVData.RasSdeiEnabled,
+ prompt = STRING_TOKEN(STR_RAS_SDEI_ENABLED_PROMPT),
+ help = STRING_TOKEN(STR_RAS_SDEI_ENABLED_HELP),
+ flags = NUMERIC_SIZE_4 | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_RAS_COMMON_ENABLE), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_RAS_COMMON_DISABLE), value = 0, flags = DEFAULT;
+
+ endoneof;
+
+ label LABEL_UPDATE;
+ //
+ // This is where we will dynamically add other Action type op-code
+ //
+ label LABEL_END;
+
+ numeric varid = RasConfigNVData.RasCpmCeThreshold,
+ prompt = STRING_TOKEN(STR_RAS_CPM_CE_THRESHOLD_PROMPT),
+ help = STRING_TOKEN(STR_RAS_CPM_CE_THRESHOLD_HELP),
+ flags = NUMERIC_SIZE_4 | RESET_REQUIRED,
+ minimum = 1,
+ maximum = 8192,
+ default = 1,
+
+ endnumeric;
+
+ numeric varid = RasConfigNVData.RasLinkErrThreshold,
+ prompt = STRING_TOKEN(STR_RAS_LINK_ERR_THRESHOLD_PROMPT),
+ help = STRING_TOKEN(STR_RAS_LINK_ERR_THRESHOLD_HELP),
+ flags = NUMERIC_SIZE_4 | RESET_REQUIRED,
+ minimum = 1,
+ maximum = 8192,
+ default = 1,
+
+ endnumeric;
+
+
+ endform;
+
+endformset;
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.c
new file mode 100644
index 000000000000..41554775a0b4
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigDxe.c
@@ -0,0 +1,822 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NVParamLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <NVParamDef.h>
+#include <PlatformInfoHob.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+
+#include "RasConfigDxe.h"
+
+CHAR16 RasConfigVarstoreDataName[] = L"RasConfigNVData";
+
+EFI_HANDLE mDriverHandle = NULL;
+RAS_CONFIG_PRIVATE_DATA *mPrivateData = NULL;
+
+EFI_GUID mRasConfigFormSetGuid = RAS_CONFIG_FORMSET_GUID;
+
+//
+// Default RAS Settings
+//
+#define RAS_DEFAULT_HARDWARE_EINJ_SUPPORT 0
+#define RAS_DEFAULT_PCIE_AER_FW_FIRST 0
+#define RAS_DEFAULT_BERT_SUPPORT 1
+#define RAS_DEFAULT_SDEI_SUPPORT 0
+#define RAS_DEFAULT_DDR_CE_THRESHOLD 1
+#define RAS_DEFAULT_2P_CE_THRESHOLD 1
+#define RAS_DEFAULT_PROCESSOR_CE_THRESHOLD 1
+#define RAS_DEFAULT_DDR_LINK_ERROR_THRESHOLD 1
+
+
+HII_VENDOR_DEVICE_PATH mRasConfigHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ RAS_CONFIG_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+BOOLEAN
+IsDdrCeWindowEnabled (
+ VOID
+ )
+{
+ UINT32 DdrCeWindow;
+ EFI_STATUS Status;
+
+ Status = NVParamGet (
+ NV_SI_RO_BOARD_RAS_DDR_CE_WINDOW,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &DdrCeWindow
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return (DdrCeWindow != 0) ? TRUE : FALSE;
+}
+
+EFI_STATUS
+RasConfigNvParamGet (
+ OUT RAS_CONFIG_VARSTORE_DATA *Configuration
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Value;
+
+ Status = NVParamGet (
+ NV_SI_HARDWARE_EINJ,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_HARDWARE_EINJ_SUPPORT;
+ Status = NVParamSet (
+ NV_SI_HARDWARE_EINJ,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->RasHardwareEinj = Value;
+
+ Status = NVParamGet (
+ NV_SI_RAS_PCIE_AER_FW_FIRST,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_PCIE_AER_FW_FIRST;
+ Status = NVParamSet (
+ NV_SI_RAS_PCIE_AER_FW_FIRST,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->RasPcieAerFwFirstEnabled = Value;
+
+ Status = NVParamGet (
+ NV_SI_RAS_BERT_ENABLED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_BERT_SUPPORT;
+ Status = NVParamSet (
+ NV_SI_RAS_BERT_ENABLED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->RasBertEnabled = Value;
+
+ Status = NVParamGet (
+ NV_SI_RAS_SDEI_ENABLED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_SDEI_SUPPORT;
+ Status = NVParamSet (
+ NV_SI_RAS_SDEI_ENABLED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->RasSdeiEnabled = Value;
+
+ Status = NVParamGet (
+ NV_SI_DDR_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_DDR_CE_THRESHOLD;
+ Status = NVParamSet (
+ NV_SI_DDR_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->RasDdrCeThreshold = Value;
+
+ Status = NVParamGet (
+ NV_SI_2P_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_2P_CE_THRESHOLD;
+ Status = NVParamSet (
+ NV_SI_2P_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->Ras2pCeThreshold = Value;
+
+ Status = NVParamGet (
+ NV_SI_CPM_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_PROCESSOR_CE_THRESHOLD;
+ Status = NVParamSet (
+ NV_SI_CPM_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->RasCpmCeThreshold = Value;
+
+ Status = NVParamGet (
+ NV_SI_LINK_ERR_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value = RAS_DEFAULT_DDR_LINK_ERROR_THRESHOLD;
+ Status = NVParamSet (
+ NV_SI_LINK_ERR_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:%d NVParamSet() failed!\n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ Value = 0;
+ }
+ }
+ Configuration->RasLinkErrThreshold = Value;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RasConfigNvParamSet (
+ IN RAS_CONFIG_VARSTORE_DATA *Configuration
+ )
+{
+ EFI_STATUS Status;
+
+ Status = NVParamSet (
+ NV_SI_HARDWARE_EINJ,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->RasHardwareEinj
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = NVParamSet (
+ NV_SI_RAS_PCIE_AER_FW_FIRST,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->RasPcieAerFwFirstEnabled
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = NVParamSet (
+ NV_SI_RAS_BERT_ENABLED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->RasBertEnabled
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = NVParamSet (
+ NV_SI_RAS_SDEI_ENABLED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->RasSdeiEnabled
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = NVParamSet (
+ NV_SI_DDR_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->RasDdrCeThreshold
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = NVParamSet (
+ NV_SI_2P_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->Ras2pCeThreshold
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = NVParamSet (
+ NV_SI_CPM_CE_RAS_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->RasCpmCeThreshold
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = NVParamSet (
+ NV_SI_LINK_ERR_THRESHOLD,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->RasLinkErrThreshold
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RasConfigExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ RAS_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ UINTN Size;
+ BOOLEAN AllocatedRequest;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mRasConfigFormSetGuid, RasConfigVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = RAS_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get current setting from NVParam.
+ //
+ Status = RasConfigNvParamGet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ BufferSize = sizeof (RAS_CONFIG_VARSTORE_DATA);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&mRasConfigFormSetGuid, RasConfigVarstoreDataName, PrivateData->DriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ if (ConfigRequest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *)&PrivateData->Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RasConfigRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ RAS_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = RAS_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &mRasConfigFormSetGuid, RasConfigVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get configuration data from NVParam
+ //
+ Status = RasConfigNvParamGet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (RAS_CONFIG_VARSTORE_DATA);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *)&PrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store configuration data back to NVParam
+ //
+ Status = RasConfigNvParamSet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+RasConfigCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if (Action != EFI_BROWSER_ACTION_CHANGING) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ if (((Value == NULL)
+ && (Action != EFI_BROWSER_ACTION_FORM_OPEN)
+ && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))
+ || (ActionRequest == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+UpdateRasConfigScreen (
+ IN RAS_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ VOID *StartOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ if (StartLabel == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FreeOpCodeBuffer;
+ }
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_UPDATE;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ if (EndLabel == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FreeOpCodeBuffer;
+ }
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ //
+ // Create the numeric for DDR CE threshold
+ //
+ if (!IsDdrCeWindowEnabled ()) {
+ HiiCreateNumericOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8004, // Question ID
+ RAS_CONFIG_VARSTORE_ID, // VarStore ID
+ (UINT16)RAS_DDR_CE_THRESHOLD_OFST, // Offset in Buffer Storage
+ STRING_TOKEN (STR_RAS_DDR_CE_THRESHOLD_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_RAS_DDR_CE_THRESHOLD_HELP),
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 1,
+ 8192,
+ 1,
+ NULL
+ );
+ }
+
+ //
+ // Create the numeric for 2P CE threshold
+ //
+ if (IsSlaveSocketActive ()) {
+ HiiCreateNumericOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8005, // Question ID
+ RAS_CONFIG_VARSTORE_ID, // VarStore ID
+ (UINT16)RAS_2P_CE_THRESHOLD_OFST, // Offset in Buffer Storage
+ STRING_TOKEN (STR_RAS_2P_CE_THRESHOLD_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_RAS_2P_CE_THRESHOLD_HELP),
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 1,
+ 8192,
+ 1,
+ NULL
+ );
+ }
+
+ Status = HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &mRasConfigFormSetGuid, // Formset GUID
+ RAS_CONFIG_FORM_ID, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+FreeOpCodeBuffer:
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+RasConfigUnload (
+ VOID
+ )
+{
+ ASSERT (mPrivateData != NULL);
+
+ if (mDriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRasConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ mDriverHandle = NULL;
+ }
+
+ if (mPrivateData->HiiHandle != NULL) {
+ HiiRemovePackages (mPrivateData->HiiHandle);
+ }
+
+ FreePool (mPrivateData);
+ mPrivateData = NULL;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+RasConfigEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ //
+ // Initialize driver private data
+ //
+ mPrivateData = AllocateZeroPool (sizeof (RAS_CONFIG_PRIVATE_DATA));
+ if (mPrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->Signature = RAS_CONFIG_PRIVATE_SIGNATURE;
+
+ mPrivateData->ConfigAccess.ExtractConfig = RasConfigExtractConfig;
+ mPrivateData->ConfigAccess.RouteConfig = RasConfigRouteConfig;
+ mPrivateData->ConfigAccess.Callback = RasConfigCallback;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&HiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRasConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle = mDriverHandle;
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle = HiiAddPackages (
+ &mRasConfigFormSetGuid,
+ mDriverHandle,
+ RasConfigDxeStrings,
+ RasConfigVfrBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRasConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle = HiiHandle;
+
+ Status = UpdateRasConfigScreen (mPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a %d Fail to update Memory Configuration screen \n",
+ __FUNCTION__,
+ __LINE__
+ ));
+ RasConfigUnload ();
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigStrings.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigStrings.uni
new file mode 100644
index 000000000000..c502093a2bbf
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/RasConfigDxe/RasConfigStrings.uni
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#langdef en-US "English"
+
+#string STR_RAS_FORM #language en-US "RAS Configuration"
+#string STR_RAS_FORM_HELP #language en-US "RAS Configuration"
+
+#string STR_RAS_FORM_SEPERATE_LINE #language en-US ""
+#string STR_RAS_COMMON_ENABLE #language en-US "Enabled"
+#string STR_RAS_COMMON_DISABLE #language en-US "Disabled"
+
+#string STR_RAS_HARDWARE_EINJ_PROMPT #language en-US "Hardware EINJ"
+#string STR_RAS_HARDWARE_EINJ_HELP #language en-US "Enable hardware EINJ support, if disabled EINJ is software simulated"
+
+#string STR_RAS_PCIE_AER_FW_FIRST_PROMPT #language en-US "PCIe AER Firmware First"
+#string STR_RAS_PCIE_AER_FW_FIRST_HELP #language en-US "Enable firmware to detect PCIe AER, if disabled OS detects AER"
+
+#string STR_RAS_BERT_ENABLED_PROMPT #language en-US "Enable BERT"
+#string STR_RAS_BERT_ENABLED_HELP #language en-US "Enable Boot Error Record Table, if disabled BERT will not be populated"
+
+#string STR_RAS_SDEI_ENABLED_PROMPT #language en-US "Enable SDEI"
+#string STR_RAS_SDEI_ENABLED_HELP #language en-US "Enable Software Delegated Exception Interface for NMI support"
+
+#string STR_RAS_DDR_CE_THRESHOLD_PROMPT #language en-US "DDR CE Threshold"
+#string STR_RAS_DDR_CE_THRESHOLD_HELP #language en-US "Number of DDR CEs to occur before using SCI notification to OS rather than polled notification"
+
+#string STR_RAS_2P_CE_THRESHOLD_PROMPT #language en-US "2P CE Threshold"
+#string STR_RAS_2P_CE_THRESHOLD_HELP #language en-US "Number of 2P CEs to occur before using SCI notification to OS rather than polled notification"
+
+#string STR_RAS_CPM_CE_THRESHOLD_PROMPT #language en-US "Processor CE Threshold"
+#string STR_RAS_CPM_CE_THRESHOLD_HELP #language en-US "Number of processor CEs to occur before using SCI notification to OS rather than polled notification"
+
+#string STR_RAS_LINK_ERR_THRESHOLD_PROMPT #language en-US "DDR Link Error Threshold"
+#string STR_RAS_LINK_ERR_THRESHOLD_HELP #language en-US "Number of DDR link errors before considering it fatal severity"
--
2.17.1


Re: [PATCH v3 25/28] AmpereAltraPkg: Add configuration screen for ACPI

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:24 +0700, Nhi Pham wrote:
This supports:
* Enable/Disable APEI Support
* Enable/Disable CPPC Support
* Enable/Disable LPI support
* Enable/Disable Max Performance Mode

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>

---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 +
Platform/Ampere/JadePkg/Jade.dsc | 1 +
Platform/Ampere/JadePkg/Jade.fdf | 1 +
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf | 1 +
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf | 58 ++
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.h | 7 +-
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.h | 62 ++
Silicon/Ampere/AmpereAltraPkg/Include/AcpiConfigNVDataStruct.h | 28 +
Silicon/Ampere/AmpereAltraPkg/Include/Guid/AcpiConfigFormSet.h | 19 +
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigVfr.vfr | 69 ++
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.c | 25 +-
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.c | 729 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigStrings.uni | 27 +
13 files changed, 1026 insertions(+), 4 deletions(-)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index 6ea247c75e87..196611d67280 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -53,6 +53,9 @@ [Guids]
# GUID for the CPU HII configuration form
gCpuConfigFormSetGuid = { 0x43FAA144, 0xA2DF, 0x4050, { 0xA7, 0xFD, 0xEE, 0x17, 0xC9, 0xB8, 0x88, 0x8E } }

+ # GUID for the ACPI HII configuration form
+ gAcpiConfigFormSetGuid = { 0x0ceb6764, 0xd415, 0x4b01, { 0xa8, 0x43, 0xd1, 0x01, 0xbc, 0xb0, 0xd8, 0x29 } }
+
## NVParam MM GUID
gNVParamMmGuid = { 0xE4AC5024, 0x29BE, 0x4ADC, { 0x93, 0x36, 0x87, 0xB5, 0xA0, 0x76, 0x23, 0x2D } }

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index 8ca3a729728f..daac52e84ea2 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -199,3 +199,4 @@ [Components.common]
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformInfoDxe/PlatformInfoDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index d9552886fbcf..1564e45c30cd 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -357,5 +357,6 @@ [FV.FvMain]
INF Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformInfoDxe/PlatformInfoDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf

!include Platform/Ampere/AmperePlatformPkg/FvRules.fdf.inc
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
index 2b2a3728a406..a2b3886a0236 100644
--- a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -66,6 +66,7 @@ [Guids]
gArmMpCoreInfoGuid
gEfiAcpiTableGuid
gEfiEventReadyToBootGuid
+ gAcpiConfigFormSetGuid
gPlatformHobGuid

[Protocols]
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
new file mode 100644
index 000000000000..075183aa9c58
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.inf
@@ -0,0 +1,58 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = AcpiConfigDxe
+ FILE_GUID = F36685AE-2623-4231-ABC0-2C151451E6B7
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = AcpiConfigEntryPoint
+
+[Sources.common]
+ AcpiConfigDxe.c
+ AcpiConfigDxe.h
+ AcpiConfigVfr.vfr
+ AcpiConfigStrings.uni
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ AcpiLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ HiiLib
+ HobLib
+ MemoryAllocationLib
+ SystemFirmwareInterfaceLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Guids]
+ gPlatformManagerFormsetGuid
+ gAcpiConfigFormSetGuid
+ gEfiEventReadyToBootGuid
+ gPlatformHobGuid
+
+[Protocols]
+ gEfiAcpiSdtProtocolGuid ## COMSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.h b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.h
index 2e763422cbc6..035912a1a331 100644
--- a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.h
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.h
@@ -9,7 +9,9 @@
#ifndef ACPI_APEI_H_
#define ACPI_APEI_H_

+#include <AcpiConfigNVDataStruct.h>
#include <Base.h>
+#include <Guid/AcpiConfigFormSet.h>
#include <IndustryStandard/Acpi63.h>
#include <Library/AcpiLib.h>
#include <Library/AmpereCpuLib.h>
@@ -34,9 +36,10 @@
#define PLAT_CRASH_ITERATOR_SIZE 0x398
#define SMPRO_CRASH_SIZE 0x800
#define PMPRO_CRASH_SIZE 0x800
+#define RASIP_CRASH_SIZE 0x1000
#define HEST_NUM_ENTRIES_PER_SOC 3

-#define CURRENT_BERT_VERSION 0x10
+#define CURRENT_BERT_VERSION 0x11
#define BERT_FLASH_OFFSET 0x91B30000ULL
#define BERT_DDR_OFFSET 0x88230000ULL
#define BERT_DDR_LENGTH 0x50000
@@ -53,8 +56,10 @@ typedef struct {
UINT8 BertRev;
UINT8 S0PmproRegisters[PMPRO_CRASH_SIZE];
UINT8 S0SmproRegisters[SMPRO_CRASH_SIZE];
+ UINT8 S0RasIpRegisters[RASIP_CRASH_SIZE];
UINT8 S1PmproRegisters[PMPRO_CRASH_SIZE];
UINT8 S1SmproRegisters[SMPRO_CRASH_SIZE];
+ UINT8 S1RasIpRegisters[RASIP_CRASH_SIZE];
UINT8 AtfDump[PLATFORM_CPU_MAX_NUM_CORES * PLAT_CRASH_ITERATOR_SIZE];
} APEI_CRASH_DUMP_DATA;

diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.h
new file mode 100644
index 000000000000..8a2cc2f5e679
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.h
@@ -0,0 +1,62 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef ACPI_CONFIG_DXE_H_
+#define ACPI_CONFIG_DXE_H_
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+//
+extern UINT8 AcpiConfigVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+//
+extern UINT8 AcpiConfigDxeStrings[];
+
+//
+// Signature: Ampere Computing ACPI Configuration
+//
+#define ACPI_CONFIG_PRIVATE_SIGNATURE SIGNATURE_32 ('A', 'C', 'A', 'C')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ ACPI_CONFIG_VARSTORE_DATA Configuration;
+ PLATFORM_INFO_HOB *PlatformHob;
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
+ EFI_ACPI_HANDLE AcpiTableHandle;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} ACPI_CONFIG_PRIVATE_DATA;
+
+#define ACPI_CONFIG_PRIVATE_FROM_THIS(a) CR (a, ACPI_CONFIG_PRIVATE_DATA, ConfigAccess, ACPI_CONFIG_PRIVATE_SIGNATURE)
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+#endif
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/AcpiConfigNVDataStruct.h b/Silicon/Ampere/AmpereAltraPkg/Include/AcpiConfigNVDataStruct.h
new file mode 100644
index 000000000000..a56bfa9aa694
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/AcpiConfigNVDataStruct.h
@@ -0,0 +1,28 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef ACPI_CONFIG_NV_DATA_STRUC_H_
+#define ACPI_CONFIG_NV_DATA_STRUC_H_
+
+#pragma pack(1)
+
+//
+// ACPI Configuration NV data structure definition
+//
+typedef struct {
+ UINT32 EnableApeiSupport;
+ UINT32 AcpiCppcEnable;
+ UINT32 AcpiLpiEnable;
+ UINT32 AcpiTurboSupport;
+ UINT32 AcpiTurboMode;
+ UINT32 Reserved[4];
+} ACPI_CONFIG_VARSTORE_DATA;
+
+#pragma pack()
+
+#endif /* ACPI_CONFIG_NV_DATA_STRUC_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Guid/AcpiConfigFormSet.h b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/AcpiConfigFormSet.h
new file mode 100644
index 000000000000..1779a4543769
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/AcpiConfigFormSet.h
@@ -0,0 +1,19 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef ACPI_CONFIG_FORMSET_GUID_H_
+#define ACPI_CONFIG_FORMSET_GUID_H_
+
+#define ACPI_CONFIGURATION_FORMSET_GUID \
+ { \
+ 0x0ceb6764, 0xd415, 0x4b01, { 0xa8, 0x43, 0xd1, 0x01, 0xbc, 0xb0, 0xd8, 0x29 } \
+ }
+
+extern EFI_GUID gAcpiConfigFormSetGuid;
+
+#endif /* ACPI_CONFIG_FORMSET_GUID_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigVfr.vfr b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigVfr.vfr
new file mode 100644
index 000000000000..18b44f90ddd9
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigVfr.vfr
@@ -0,0 +1,69 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Guid/AcpiConfigFormSet.h>
+#include <AcpiConfigNVDataStruct.h>
+
+#define ACPI_CONFIG_FORM_ID 1
+
+formset
+ guid = ACPI_CONFIGURATION_FORMSET_GUID,
+ title = STRING_TOKEN(STR_ACPI_FORM),
+ help = STRING_TOKEN(STR_ACPI_FORM_HELP),
+ classguid = gPlatformManagerFormsetGuid,
+
+ varstore ACPI_CONFIG_VARSTORE_DATA,
+ name = AcpiConfigNVData,
+ guid = ACPI_CONFIGURATION_FORMSET_GUID;
+
+ form
+ formid = ACPI_CONFIG_FORM_ID,
+ title = STRING_TOKEN(STR_ACPI_FORM);
+ subtitle text = STRING_TOKEN(STR_ACPI_FORM_HELP);
+
+ oneof
+ varid = AcpiConfigNVData.EnableApeiSupport,
+ prompt = STRING_TOKEN(STR_ACPI_APEI_SUPPORT_PROMPT),
+ help = STRING_TOKEN(STR_ACPI_APEI_SUPPORT_HELP),
+ option text = STRING_TOKEN(STR_ACPI_COMMON_DISABLE), value = 0, flags = 0;
+ option text = STRING_TOKEN(STR_ACPI_COMMON_ENABLE), value = 1, flags = DEFAULT;
+ endoneof;
+
+ oneof
+ varid = AcpiConfigNVData.AcpiCppcEnable,
+ prompt = STRING_TOKEN(STR_ACPI_CPPC_PROMPT),
+ help = STRING_TOKEN(STR_ACPI_CPPC_HELP),
+ option text = STRING_TOKEN(STR_ACPI_COMMON_DISABLE), value = 0, flags = 0;
+ option text = STRING_TOKEN(STR_ACPI_COMMON_ENABLE), value = 1, flags = DEFAULT;
+ endoneof;
+
+ oneof
+ varid = AcpiConfigNVData.AcpiLpiEnable,
+ prompt = STRING_TOKEN(STR_ACPI_LPI_PROMPT),
+ help = STRING_TOKEN(STR_ACPI_LPI_HELP),
+ option text = STRING_TOKEN(STR_ACPI_COMMON_DISABLE), value = 0, flags = 0;
+ option text = STRING_TOKEN(STR_ACPI_COMMON_ENABLE), value = 1, flags = DEFAULT;
+ endoneof;
+
+ grayoutif ideqval AcpiConfigNVData.AcpiTurboSupport == 0;
+ oneof
+ varid = AcpiConfigNVData.AcpiTurboMode,
+ prompt = STRING_TOKEN(STR_ACPI_TURBO_PROMPT),
+ help = STRING_TOKEN(STR_ACPI_TURBO_HELP),
+ option text = STRING_TOKEN(STR_ACPI_COMMON_ENABLE), value = 1, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_ACPI_COMMON_DISABLE), value = 0, flags = 0;
+ suppressif ideqval AcpiConfigNVData.AcpiTurboSupport > 0;
+ option text = STRING_TOKEN(STR_ACPI_UNSUPPORTED), value = 2, flags = 0;
+ endif;
+ endoneof;
+ endif;
+
+ endform;
+
+endformset;
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.c b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.c
index a216edac60ce..8a46e038c1a7 100644
--- a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.c
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiApei.c
@@ -149,7 +149,7 @@ WrapBertErrorData (
CrashSize = PLAT_CRASH_ITERATOR_SIZE *
GetNumberOfSupportedSockets () *
GetMaximumNumberOfCores ();
- CrashSize += 2 * (SMPRO_CRASH_SIZE + PMPRO_CRASH_SIZE);
+ CrashSize += 2 * (SMPRO_CRASH_SIZE + PMPRO_CRASH_SIZE + RASIP_CRASH_SIZE);
CrashSize += sizeof (WrappedError->Bed.Vendor) + sizeof (WrappedError->Bed.BertRev);

WrappedError->Ges.BlockStatus.ErrorDataEntryCount = 1;
@@ -437,8 +437,27 @@ AcpiApeiUpdate (
VOID
)
{
- if (!IsSlaveSocketActive ()) {
- AcpiApeiHestUpdateTable1P ();
+ EFI_STATUS Status;
+ ACPI_CONFIG_VARSTORE_DATA AcpiConfigData;
+ UINTN BufferSize;
+
+ BufferSize = sizeof (ACPI_CONFIG_VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ L"AcpiConfigNVData",
+ &gAcpiConfigFormSetGuid,
+ NULL,
+ &BufferSize,
+ &AcpiConfigData
+ );
+ if (!EFI_ERROR (Status) && (AcpiConfigData.EnableApeiSupport == 0)) {
+ AcpiApeiUninstallTable (EFI_ACPI_6_3_BOOT_ERROR_RECORD_TABLE_SIGNATURE);
+ AcpiApeiUninstallTable (EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE);
+ AcpiApeiUninstallTable (EFI_ACPI_6_3_SOFTWARE_DELEGATED_EXCEPTIONS_INTERFACE_TABLE_SIGNATURE);
+ AcpiApeiUninstallTable (EFI_ACPI_6_3_ERROR_INJECTION_TABLE_SIGNATURE);
+ } else {
+ if (!IsSlaveSocketActive ()) {
+ AcpiApeiHestUpdateTable1P ();
+ }
}

if (!IsSdeiEnabled ()) {
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.c
new file mode 100644
index 000000000000..d085389d2865
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigDxe.c
@@ -0,0 +1,729 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <AcpiConfigNVDataStruct.h>
+#include <Guid/AcpiConfigFormSet.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/PlatformInfoHobGuid.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SystemFirmwareInterfaceLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <PlatformInfoHob.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+
+#include "AcpiConfigDxe.h"
+
+#define ACPI_VARSTORE_ATTRIBUTES EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS | \
+ EFI_VARIABLE_NON_VOLATILE
+
+CHAR16 AcpiVarstoreDataName[] = L"AcpiConfigNVData";
+
+EFI_HANDLE mDriverHandle = NULL;
+ACPI_CONFIG_PRIVATE_DATA *mPrivateData = NULL;
+
+HII_VENDOR_DEVICE_PATH mAcpiConfigHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ ACPI_CONFIGURATION_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ ACPI_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ UINTN Size;
+ BOOLEAN AllocatedRequest;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gAcpiConfigFormSetGuid, AcpiVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = ACPI_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get Buffer Storage data from EFI variable.
+ // Try to get the current setting from variable.
+ //
+ BufferSize = sizeof (ACPI_CONFIG_VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ AcpiVarstoreDataName,
+ &gAcpiConfigFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ BufferSize = sizeof (ACPI_CONFIG_VARSTORE_DATA);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (
+ &gAcpiConfigFormSetGuid,
+ AcpiVarstoreDataName,
+ PrivateData->DriverHandle
+ );
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ if (ConfigRequest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *)&PrivateData->Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ ACPI_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = ACPI_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gAcpiConfigFormSetGuid, AcpiVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (ACPI_CONFIG_VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ AcpiVarstoreDataName,
+ &gAcpiConfigFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (ACPI_CONFIG_VARSTORE_DATA);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *)&PrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store Buffer Storage back to EFI variable
+ //
+ Status = gRT->SetVariable (
+ AcpiVarstoreDataName,
+ &gAcpiConfigFormSetGuid,
+ ACPI_VARSTORE_ATTRIBUTES,
+ sizeof (ACPI_CONFIG_VARSTORE_DATA),
+ &PrivateData->Configuration
+ );
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if (Action != EFI_BROWSER_ACTION_CHANGING) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ if (((Value == NULL)
+ && (Action != EFI_BROWSER_ACTION_FORM_OPEN)
+ && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))
+ || (ActionRequest == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+AcpiNVDataUpdate (
+ IN ACPI_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ PLATFORM_INFO_HOB *PlatformHob;
+ UINT32 TurboSupport;
+
+ ASSERT (PrivateData != NULL);
+
+ PlatformHob = PrivateData->PlatformHob;
+ TurboSupport = PlatformHob->TurboCapability[0] + PlatformHob->TurboCapability[1];
+
+ if (TurboSupport == 0) {
+ PrivateData->Configuration.AcpiTurboMode = 2; // Unsupported mode
+ PrivateData->Configuration.AcpiTurboSupport = 0;
+ } else {
+ PrivateData->Configuration.AcpiTurboSupport = 1;
+ }
+
+ Status = gRT->SetVariable (
+ AcpiVarstoreDataName,
+ &gAcpiConfigFormSetGuid,
+ ACPI_VARSTORE_ATTRIBUTES,
+ sizeof (ACPI_CONFIG_VARSTORE_DATA),
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a %d gRT->SetVariable() failed \n", __FUNCTION__, __LINE__));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+UpdateTurboModeConfig (
+ IN ACPI_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ PLATFORM_INFO_HOB *PlatformHob;
+ BOOLEAN EnableTurbo;
+
+ ASSERT (PrivateData != NULL);
+
+ if (PrivateData->Configuration.AcpiTurboSupport != 0) {
+ PlatformHob = PrivateData->PlatformHob;
+ EnableTurbo = (PrivateData->Configuration.AcpiTurboMode != 0) ? TRUE : FALSE;
+
+ if (PlatformHob->TurboCapability[0] != 0) {
+ Status = MailboxMsgTurboConfig (0, EnableTurbo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (PlatformHob->TurboCapability[1] != 0) {
+ Status = MailboxMsgTurboConfig (1, EnableTurbo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: Turbo mode is unsupported! \n", __FUNCTION__));
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+UpdateCPPCConfig (
+ IN ACPI_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 Buffer[64];
+
+ ASSERT (PrivateData != NULL);
+
+ AsciiSPrint (Buffer, sizeof (Buffer), "\\_SB.CPCE");
+ Status = AcpiAmlObjectUpdateInteger (
+ PrivateData->AcpiSdtProtocol,
+ PrivateData->AcpiTableHandle,
+ Buffer,
+ PrivateData->Configuration.AcpiCppcEnable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+UpdateLPIConfig (
+ IN ACPI_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 Buffer[64];
+
+ ASSERT (PrivateData != NULL);
+
+ AsciiSPrint (Buffer, sizeof (Buffer), "\\_SB.LPIE");
+ Status = AcpiAmlObjectUpdateInteger (
+ PrivateData->AcpiSdtProtocol,
+ PrivateData->AcpiTableHandle,
+ Buffer,
+ PrivateData->Configuration.AcpiLpiEnable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+STATIC
+VOID
+UpdateAcpiOnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ EFI_ACPI_HANDLE TableHandle;
+ UINTN TableKey;
+ UINTN TableIndex;
+
+ ASSERT (mPrivateData != NULL);
+
+ //
+ // Find the AcpiTable protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID **)&AcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate ACPI table protocol\n"));
+ return;
+ }
+
+ mPrivateData->AcpiSdtProtocol = AcpiSdtProtocol;
+
+ TableIndex = 0;
+ Status = AcpiLocateTableBySignature (
+ AcpiSdtProtocol,
+ EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ &TableIndex,
+ &Table,
+ &TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = AcpiSdtProtocol->OpenSdt (TableKey, &TableHandle);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ mPrivateData->AcpiTableHandle = TableHandle;
+
+ Status = UpdateCPPCConfig (mPrivateData);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = UpdateLPIConfig (mPrivateData);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = UpdateTurboModeConfig (mPrivateData);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Close DSDT Table
+ //
+ AcpiSdtProtocol->Close (TableHandle);
+ AcpiUpdateChecksum ((UINT8 *)Table, Table->Length);
+}
+
+STATIC
+EFI_STATUS
+AcpiConfigUnload (
+ VOID
+ )
+{
+ ASSERT (mPrivateData != NULL);
+
+ if (mDriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mAcpiConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ mDriverHandle = NULL;
+ }
+
+ if (mPrivateData->HiiHandle != NULL) {
+ HiiRemovePackages (mPrivateData->HiiHandle);
+ }
+
+ FreePool (mPrivateData);
+ mPrivateData = NULL;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+AcpiConfigEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ UINTN BufferSize;
+ ACPI_CONFIG_VARSTORE_DATA *Configuration;
+ BOOLEAN ActionFlag;
+ EFI_STRING ConfigRequestHdr;
+ EFI_EVENT ReadyToBootEvent;
+ PLATFORM_INFO_HOB *PlatformHob;
+ VOID *Hob;
+
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+
+ //
+ // Initialize driver private data
+ //
+ mPrivateData = AllocateZeroPool (sizeof (ACPI_CONFIG_PRIVATE_DATA));
+ if (mPrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->Signature = ACPI_CONFIG_PRIVATE_SIGNATURE;
+
+ mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ mPrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ mPrivateData->ConfigAccess.Callback = DriverCallback;
+
+ //
+ // Get the Platform HOB
+ //
+ Hob = GetFirstGuidHob (&gPlatformHobGuid);
+ ASSERT (Hob != NULL);
+ if (Hob == NULL) {
+ AcpiConfigUnload ();
+ return EFI_DEVICE_ERROR;
+ }
+ PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
+
+ mPrivateData->PlatformHob = PlatformHob;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&HiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mAcpiConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle = mDriverHandle;
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle = HiiAddPackages (
+ &gAcpiConfigFormSetGuid,
+ mDriverHandle,
+ AcpiConfigDxeStrings,
+ AcpiConfigVfrBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mAcpiConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle = HiiHandle;
+
+ //
+ // Initialize configuration data
+ //
+ Configuration = &mPrivateData->Configuration;
+ ZeroMem (Configuration, sizeof (ACPI_CONFIG_VARSTORE_DATA));
+
+ //
+ // Try to read NV config EFI variable first
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gAcpiConfigFormSetGuid, AcpiVarstoreDataName, mDriverHandle);
+ ASSERT (ConfigRequestHdr != NULL);
+
+ BufferSize = sizeof (ACPI_CONFIG_VARSTORE_DATA);
+ Status = gRT->GetVariable (AcpiVarstoreDataName, &gAcpiConfigFormSetGuid, NULL, &BufferSize, Configuration);
+ if (EFI_ERROR (Status)) {
+ //
+ // Store zero data Buffer Storage to EFI variable
+ //
+ Status = gRT->SetVariable (
+ AcpiVarstoreDataName,
+ &gAcpiConfigFormSetGuid,
+ ACPI_VARSTORE_ATTRIBUTES,
+ sizeof (ACPI_CONFIG_VARSTORE_DATA),
+ Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ AcpiConfigUnload ();
+ return Status;
+ }
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ if (!ActionFlag) {
+ AcpiConfigUnload ();
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // EFI variable does exist and Validate Current Setting
+ //
+ ActionFlag = HiiValidateSettings (ConfigRequestHdr);
+ if (!ActionFlag) {
+ AcpiConfigUnload ();
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ FreePool (ConfigRequestHdr);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UpdateAcpiOnReadyToBoot,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &ReadyToBootEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Fail to create ready to boot event %r!\n", Status));
+ return Status;
+ }
+
+ Status = AcpiNVDataUpdate (mPrivateData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigStrings.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigStrings.uni
new file mode 100644
index 000000000000..21a6188518fd
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/AcpiConfigDxe/AcpiConfigStrings.uni
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#langdef en-US "English"
+
+#string STR_ACPI_FORM #language en-US "ACPI Configuration"
+#string STR_ACPI_FORM_HELP #language en-US "ACPI Configuration"
+
+#string STR_ACPI_FORM_SEPERATE_LINE #language en-US ""
+#string STR_ACPI_COMMON_ENABLE #language en-US "Enabled"
+#string STR_ACPI_COMMON_DISABLE #language en-US "Disabled"
+#string STR_ACPI_UNSUPPORTED #language en-US "Unsupported"
+
+#string STR_ACPI_APEI_SUPPORT_PROMPT #language en-US "APEI Support"
+#string STR_ACPI_APEI_SUPPORT_HELP #language en-US "Enable/Disable ACPI Platform Error Interface support"
+
+#string STR_ACPI_CPPC_PROMPT #language en-US "CPPC Support"
+#string STR_ACPI_CPPC_HELP #language en-US "Enables or Disables System ability to CPPC (Collaborative Processor Performance Control)"
+
+#string STR_ACPI_LPI_PROMPT #language en-US "LPI Support"
+#string STR_ACPI_LPI_HELP #language en-US "Enables or Disables System ability to LPI (Lower Power Idle)"
+
+#string STR_ACPI_TURBO_PROMPT #language en-US "Max Performance"
+#string STR_ACPI_TURBO_HELP #language en-US "Enables or Disables System ability to Max Performance"
--
2.17.1


Re: [PATCH v3 24/28] AmpereAltraPkg: Add configuration screen for CPU

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:23 +0700, Nhi Pham wrote:
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

This screen is to add configuration regarding CPU. Currently, this
screen just adds a option for SubNUMA mode selection.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>


---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 +
Platform/Ampere/JadePkg/Jade.dsc | 1 +
Platform/Ampere/JadePkg/Jade.fdf | 1 +
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf | 58 +++
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.h | 52 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigNVDataStruc.h | 19 +
Silicon/Ampere/AmpereAltraPkg/Include/Guid/CpuConfigHii.h | 19 +
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigVfr.vfr | 43 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.c | 530 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigStrings.uni | 17 +
10 files changed, 743 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index 93da9b38def5..6ea247c75e87 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -50,6 +50,9 @@ [LibraryClasses]
TrngLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/TrngLib.h

[Guids]
+ # GUID for the CPU HII configuration form
+ gCpuConfigFormSetGuid = { 0x43FAA144, 0xA2DF, 0x4050, { 0xA7, 0xFD, 0xEE, 0x17, 0xC9, 0xB8, 0x88, 0x8E } }
+
## NVParam MM GUID
gNVParamMmGuid = { 0xE4AC5024, 0x29BE, 0x4ADC, { 0x93, 0x36, 0x87, 0xB5, 0xA0, 0x76, 0x23, 0x2D } }

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index 5fc83745cdbc..8ca3a729728f 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -198,3 +198,4 @@ [Components.common]
#
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformInfoDxe/PlatformInfoDxe.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 6fe023025034..d9552886fbcf 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -356,5 +356,6 @@ [FV.FvMain]
#
INF Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformInfoDxe/PlatformInfoDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf

!include Platform/Ampere/AmperePlatformPkg/FvRules.fdf.inc
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
new file mode 100644
index 000000000000..2b13ef526685
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.inf
@@ -0,0 +1,58 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = CpuConfigDxe
+ MODULE_UNI_FILE = CpuConfigDxe.uni
+ FILE_GUID = A20D8E6E-EE6C-43C5-809F-19BB930653AE
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CpuConfigDxeEntryPoint
+
+[Sources.common]
+ CpuConfigDxe.c
+ CpuConfigDxe.h
+ CpuConfigNVDataStruc.h
+ CpuConfigVfr.vfr
+ CpuConfigStrings.uni
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ DebugLib
+ DevicePathLib
+ HiiLib
+ HobLib
+ IoLib
+ MemoryAllocationLib
+ NVParamLib
+ PcdLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+
+[Guids]
+ gCpuConfigFormSetGuid
+ gPlatformManagerFormsetGuid
+
+[Depex]
+ TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.h
new file mode 100644
index 000000000000..b7e74a09da5b
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.h
@@ -0,0 +1,52 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_CONFIG_H_
+#define CPU_CONFIG_H_
+
+#include "CpuConfigNVDataStruc.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+//
+extern UINT8 CpuConfigVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+//
+extern UINT8 CpuConfigDxeStrings[];
+
+#define CPU_CONFIG_PRIVATE_SIGNATURE SIGNATURE_32 ('C', 'P', 'U', '_')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ CPU_VARSTORE_DATA Configuration;
+
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} CPU_CONFIG_PRIVATE_DATA;
+
+#define CPU_CONFIG_PRIVATE_FROM_THIS(a) CR (a, CPU_CONFIG_PRIVATE_DATA, ConfigAccess, CPU_CONFIG_PRIVATE_SIGNATURE)
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+#endif /* CPU_CONFIG_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigNVDataStruc.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigNVDataStruc.h
new file mode 100644
index 000000000000..dbcaebded1b7
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigNVDataStruc.h
@@ -0,0 +1,19 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_CONFIG_NV_DATA_STRUC_H_
+#define CPU_CONFIG_NV_DATA_STRUC_H_
+
+#pragma pack(1)
+typedef struct {
+ UINT32 CpuSubNumaMode;
+} CPU_VARSTORE_DATA;
+
+#pragma pack()
+
+#endif /* CPU_CONFIG_NV_DATA_STRUC_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Guid/CpuConfigHii.h b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/CpuConfigHii.h
new file mode 100644
index 000000000000..71c8492f76a1
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/CpuConfigHii.h
@@ -0,0 +1,19 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_CONFIG_HII_H_
+#define CPU_CONFIG_HII_H_
+
+#define CPU_CONFIGURATION_FORMSET_GUID \
+ { \
+ 0x43FAA144, 0xA2DF, 0x4050, { 0xA7, 0xFD, 0xEE, 0x17, 0xC9, 0xB8, 0x88, 0x8E } \
+ }
+
+extern EFI_GUID gCpuConfigFormSetGuid;
+
+#endif /* CPU_CONFIG_HII_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigVfr.vfr b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigVfr.vfr
new file mode 100644
index 000000000000..8e68b1e9dcb7
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigVfr.vfr
@@ -0,0 +1,43 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiMultiPhase.h>
+#include <Guid/PlatformManagerHii.h>
+#include <Guid/CpuConfigHii.h>
+#include "CpuConfigNVDataStruc.h"
+
+#define SUBNUMA_MODE_FORM_ID 1
+
+formset
+ guid = CPU_CONFIGURATION_FORMSET_GUID,
+ title = STRING_TOKEN(STR_CPU_FORM),
+ help = STRING_TOKEN(STR_CPU_FORM_HELP),
+ classguid = gPlatformManagerFormsetGuid,
+
+ varstore CPU_VARSTORE_DATA,
+ name = CpuConfigNVData,
+ guid = CPU_CONFIGURATION_FORMSET_GUID;
+
+ form
+ formid = SUBNUMA_MODE_FORM_ID,
+ title = STRING_TOKEN(STR_CPU_FORM);
+ subtitle text = STRING_TOKEN(STR_CPU_FORM_HELP);
+
+ oneof
+ varid = CpuConfigNVData.CpuSubNumaMode,
+ prompt = STRING_TOKEN(STR_CPU_SUBNUMA_MODE_PROMPT),
+ help = STRING_TOKEN(STR_CPU_SUBNUMA_MODE_HELP),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_CPU_SUBNUMA_MODE_MONOLITHIC), value = 0x0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_CPU_SUBNUMA_MODE_HEMISPHERE), value = 0x1, flags = 0;
+ option text = STRING_TOKEN(STR_CPU_SUBNUMA_MODE_QUADRANT), value = 0x2, flags = 0;
+ endoneof;
+
+ endform;
+
+endformset;
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.c
new file mode 100644
index 000000000000..a5cab9eb8d9a
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigDxe.c
@@ -0,0 +1,530 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/CpuConfigHii.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/PlatformManagerHii.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NVParamLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <NVParamDef.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+
+#include "CpuConfigDxe.h"
+
+//
+// Default settings definitions
+//
+#define NV_SI_SUBNUMA_MODE_DEFAULT 0x00 /* Monolithic mode */
+#define WA_ERRATUM_1542419_DEFAULT 0x00 /* Disable I-Cache coherency */
+#define NEAR_ATOMIC_DISABLE_DEFAULT 0x00 /* Enable Near Atomic */
+#define CPU_SLC_REPLACE_POLICY 0x00 /* eLRU */
+
+CHAR16 CpuVarstoreDataName[] = L"CpuConfigNVData";
+
+EFI_HANDLE mDriverHandle = NULL;
+CPU_CONFIG_PRIVATE_DATA *mPrivateData = NULL;
+
+HII_VENDOR_DEVICE_PATH mCpuConfigHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ CPU_CONFIGURATION_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+STATIC
+EFI_STATUS
+CpuNvParamGet (
+ OUT CPU_VARSTORE_DATA *Configuration
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Value;
+
+ ASSERT (Configuration != NULL);
+
+ Status = NVParamGet (
+ NV_SI_SUBNUMA_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a %d Fail to write NVParam \n", __FUNCTION__, __LINE__));
+ Configuration->CpuSubNumaMode = SUBNUMA_MODE_MONOLITHIC;
+ } else {
+ Configuration->CpuSubNumaMode = Value;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+CpuNvParamSet (
+ IN CPU_VARSTORE_DATA *Configuration
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Value;
+
+ ASSERT (Configuration != NULL);
+
+ Status = NVParamGet (
+ NV_SI_SUBNUMA_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status) || Value != Configuration->CpuSubNumaMode) {
+ Status = NVParamSet (
+ NV_SI_SUBNUMA_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Configuration->CpuSubNumaMode
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a %d Fail to access NVParam \n", __FUNCTION__, __LINE__));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SetupDefaultSettings (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Value;
+
+ //
+ // Subnuma Mode
+ //
+ Status = NVParamGet (
+ NV_SI_SUBNUMA_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ Status = NVParamSet (
+ NV_SI_SUBNUMA_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ NV_SI_SUBNUMA_MODE_DEFAULT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // ARM ERRATA 1542419 workaround
+ //
+ Status = NVParamSet (
+ NV_SI_ERRATUM_1542419_WA,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ WA_ERRATUM_1542419_DEFAULT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Near atomic
+ //
+ Status = NVParamSet (
+ NV_SI_NEAR_ATOMIC_DISABLE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ NEAR_ATOMIC_DISABLE_DEFAULT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // SLC Replacement Policy
+ //
+ Status = NVParamSet (
+ NV_SI_HNF_AUX_CTL_32_63,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ CPU_SLC_REPLACE_POLICY
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuConfigExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ CPU_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ UINTN Size;
+ BOOLEAN AllocatedRequest;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gCpuConfigFormSetGuid, CpuVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = CPU_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get current setting from NVParam.
+ //
+ Status = CpuNvParamGet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ BufferSize = sizeof (CPU_VARSTORE_DATA);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gCpuConfigFormSetGuid, CpuVarstoreDataName, PrivateData->DriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ if (ConfigRequest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *)&PrivateData->Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuConfigRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ CPU_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = CPU_CONFIG_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gCpuConfigFormSetGuid, CpuVarstoreDataName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get configuration data from NVParam
+ //
+ Status = CpuNvParamGet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (CPU_VARSTORE_DATA);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *)&PrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store configuration data back to NVParam
+ //
+ Status = CpuNvParamSet (&PrivateData->Configuration);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuConfigCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if (Action != EFI_BROWSER_ACTION_CHANGING) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))||
+ (ActionRequest == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+CpuConfigDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ //
+ // Initialize driver private data
+ //
+ mPrivateData = AllocateZeroPool (sizeof (CPU_CONFIG_PRIVATE_DATA));
+ if (mPrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->Signature = CPU_CONFIG_PRIVATE_SIGNATURE;
+
+ mPrivateData->ConfigAccess.ExtractConfig = CpuConfigExtractConfig;
+ mPrivateData->ConfigAccess.RouteConfig = CpuConfigRouteConfig;
+ mPrivateData->ConfigAccess.Callback = CpuConfigCallback;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&HiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mCpuConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle = mDriverHandle;
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle = HiiAddPackages (
+ &gCpuConfigFormSetGuid,
+ mDriverHandle,
+ CpuConfigDxeStrings,
+ CpuConfigVfrBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mCpuConfigHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle = HiiHandle;
+
+ //
+ // With the fresh system, the NVParam value is invalid (0xFFFFFFFF).
+ // It causes reading from the NVParam is failed.
+ // So, the NVParam should be setting with default values if any params is invalid.
+ //
+ Status = SetupDefaultSettings ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigStrings.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigStrings.uni
new file mode 100644
index 000000000000..70c01f65e4b6
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/CpuConfigDxe/CpuConfigStrings.uni
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#langdef en-US "English"
+
+#string STR_CPU_FORM #language en-US "CPU Configuration"
+#string STR_CPU_FORM_HELP #language en-US "CPU Configuration"
+#string STR_CPU_FORM_SEPERATE_LINE #language en-US ""
+
+#string STR_CPU_SUBNUMA_MODE_PROMPT #language en-US "ANC mode"
+#string STR_CPU_SUBNUMA_MODE_HELP #language en-US "Provides 3 modes: Monolithic, Hemisphere, Quadrant. System with Monolithic mode has single NUMA partition per socket. System with Hemisphere has 2 NUMA partitions per socket. System with Quandrant has 4 NUMA partitions per socket"
+#string STR_CPU_SUBNUMA_MODE_MONOLITHIC #language en-US "Monolithic"
+#string STR_CPU_SUBNUMA_MODE_HEMISPHERE #language en-US "Hemisphere"
+#string STR_CPU_SUBNUMA_MODE_QUADRANT #language en-US "Quadrant"
--
2.17.1


Re: [PATCH v3 23/28] AmpereAltraPkg: Add configuration screen for memory

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:22 +0700, Nhi Pham wrote:
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Provide memory screen with below info:
* Memory total capacity
* Memory RAS and Performance Configuration
* Per DIMM Information

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
---
Platform/Ampere/JadePkg/Jade.dsc | 1 +
Platform/Ampere/JadePkg/Jade.fdf | 1 +
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf | 59 +
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.h | 170 +++
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenNVDataStruct.h | 47 +
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenVfr.vfr | 62 +
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoNvramLib.c | 394 ++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.c | 1325 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.uni | 9 +
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxeExtra.uni | 9 +
Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenStrings.uni | 64 +
11 files changed, 2141 insertions(+)

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index f723be6997e6..5fc83745cdbc 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -197,3 +197,4 @@ [Components.common]
# HII
#
Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformInfoDxe/PlatformInfoDxe.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index c54b46f95ad5..6fe023025034 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -355,5 +355,6 @@ [FV.FvMain]
# HII
#
INF Silicon/Ampere/AmpereAltraPkg/Drivers/PlatformInfoDxe/PlatformInfoDxe.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf

!include Platform/Ampere/AmperePlatformPkg/FvRules.fdf.inc
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
new file mode 100644
index 000000000000..fbb2ac9dad21
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.inf
@@ -0,0 +1,59 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = MemInfoDxe
+ MODULE_UNI_FILE = MemInfoDxe.uni
+ FILE_GUID = D9EFCEFE-189B-4599-BB07-04F0A8DF5C2F
+ MODULE_TYPE = DXE_DRIVER
+ ENTRY_POINT = MemInfoScreenInitialize
+
+[Sources]
+ MemInfoNvramLib.c
+ MemInfoScreen.c
+ MemInfoScreen.h
+ MemInfoScreenStrings.uni
+ MemInfoScreenNVDataStruct.h
+ MemInfoScreenVfr.vfr
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ AmpereCpuLib
+ BaseLib
+ DevicePathLib
+ HiiLib
+ HobLib
+ MemoryAllocationLib
+ NVParamLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Guids]
+ gEfiIfrTianoGuid ## PRODUCES ## UNDEFINED
+ gPlatformManagerFormsetGuid
+ gPlatformHobGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ MemInfoDxeExtra.uni
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.h
new file mode 100644
index 000000000000..4b4b498062c8
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.h
@@ -0,0 +1,170 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MEM_INFO_SCREEN_H_
+#define MEM_INFO_SCREEN_H_
+
+#include <Uefi.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/PlatformInfoHobGuid.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <PlatformInfoHob.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigKeyword.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
Header file should only include headers they use themselves.

+
+#include "MemInfoScreenNVDataStruct.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 MemInfoScreenVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 MemInfoDxeStrings[];
+
+enum DDR_ECC_MODE {
Enum style, as commented for a couple of earlier patches.

+ ECC_DISABLE = 0,
+ ECC_SECDED,
+ SYMBOL_ECC
+};
+
+enum DDR_ERROR_CTRL_MODE_DE {
+ ERRCTLR_DE_DISABLE = 0,
+ ERRCTLR_DE_ENABLE,
+};
+
+enum DDR_ERROR_CTRL_MODE_FI {
+ ERRCTLR_FI_DISABLE = 0,
+ ERRCTLR_FI_ENABLE,
+};
+
+#define MEM_INFO_DDR_SPEED_SEL_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, DDRSpeedSel)
+#define MEM_INFO_ECC_MODE_SEL_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, EccMode)
+#define MEM_INFO_ERR_CTRL_DE_MODE_SEL_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, ErrCtrl_DE)
+#define MEM_INFO_ERR_CTRL_FI_MODE_SEL_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, ErrCtrl_FI)
+#define MEM_INFO_ERR_SLAVE_32BIT_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, Slave32bit)
+#define MEM_INFO_DDR_SCRUB_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, ScrubPatrol)
+#define MEM_INFO_DDR_DEMAND_SCRUB_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, DemandScrub)
+#define MEM_INFO_DDR_WRITE_CRC_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, WriteCrc)
+#define MEM_INFO_FGR_MODE_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, FGRMode)
+#define MEM_INFO_REFRESH2X_MODE_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, Refresh2x)
+#define MEM_INFO_NVDIMM_MODE_SEL_OFFSET OFFSET_OF (MEM_INFO_VARSTORE_DATA, NvdimmModeSel)
+
+#define MEM_INFO_SCREEN_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('M', 'E', 'M', 'i')
+
+#define MEM_INFO_DDR_SPEED_SEL_QUESTION_ID 0x8001
+#define MEM_INFO_FORM_PERFORMANCE_QUESTION_ID 0x8002
+#define MEM_INFO_FORM_PERFORMANCE_ECC_QUESTION_ID 0x8003
+#define MEM_INFO_FORM_PERFORMANCE_ERR_CTRL_DE_QUESTION_ID 0x8004
+#define MEM_INFO_FORM_PERFORMANCE_ERR_CTRL_FI_QUESTION_ID 0x8005
+#define MEM_INFO_DDR_SLAVE_32BIT_QUESTION_ID 0x8006
+#define MEM_INFO_DDR_SCRUB_PATROL_QUESTION_ID 0x8007
+#define MEM_INFO_DDR_DEMAND_SCRUB_QUESTION_ID 0x8008
+#define MEM_INFO_DDR_WRITE_CRC_QUESTION_ID 0x8009
+#define MEM_INFO_FGR_MODE_QUESTION_ID 0x800A
+#define MEM_INFO_REFRESH2X_MODE_QUESTION_ID 0x800B
+#define MEM_INFO_FORM_NVDIMM_QUESTION_ID 0x800C
+#define MEM_INFO_FORM_NVDIMM_MODE_SEL_QUESTION_ID 0x800D
+
+#define MAX_NUMBER_OF_HOURS_IN_A_DAY 24
+
+#define DDR_DEFAULT_SCRUB_PATROL_DURATION 24
+#define DDR_DEFAULT_DEMAND_SCRUB 1
+#define DDR_DEFAULT_WRITE_CRC 0
+#define DDR_DEFAULT_FGR_MODE 0
+#define DDR_DEFAULT_REFRESH2X_MODE 0
+#define DDR_DEFAULT_NVDIMM_MODE_SEL 3
+
+#define DDR_FGR_MODE_GET(Value) ((Value) & 0x3) /* Bit 0, 1 */
+#define DDR_FGR_MODE_SET(Dst, Src) do { Dst = (((Dst) & ~0x3) | ((Src) & 0x3)); } while (0)
+
+#define DDR_REFRESH_2X_GET(Value) ((Value) & 0x10000) >> 16 /* Bit 16 only */
+#define DDR_REFRESH_2X_SET(Dst, Src) do { Dst = (((Dst) & ~0x10000) | ((Src) & 0x1) << 16); } while (0)
+
+#define DDR_NVDIMM_MODE_SEL_MASK 0x7FFFFFFF
+#define DDR_NVDIMM_MODE_SEL_VALID_BIT BIT31
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ MEM_INFO_VARSTORE_DATA VarStoreConfig;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} MEM_INFO_SCREEN_PRIVATE_DATA;
+
+#define MEM_INFO_SCREEN_PRIVATE_FROM_THIS(a) CR (a, MEM_INFO_SCREEN_PRIVATE_DATA, ConfigAccess, MEM_INFO_SCREEN_PRIVATE_DATA_SIGNATURE)
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+EFI_STATUS
+MemInfoScreenInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+MemInfoScreenUnload (
+ IN EFI_HANDLE ImageHandle
+ );
+
+EFI_STATUS
+MemInfoNvparamGet (
+ OUT MEM_INFO_VARSTORE_DATA *VarStoreConfig
+ );
+
+EFI_STATUS
+MemInfoNvparamSet (
+ IN MEM_INFO_VARSTORE_DATA *VarStoreConfig
+ );
+
+#endif /* MEM_INFO_SCREEN_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenNVDataStruct.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenNVDataStruct.h
new file mode 100644
index 000000000000..75960c367880
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenNVDataStruct.h
@@ -0,0 +1,47 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MEM_INFO_SCREEN_NV_DATA_STRUCT_H_
+#define MEM_INFO_SCREEN_NV_DATA_STRUCT_H_
+
+#define MEM_INFO_VARSTORE_NAME L"MemInfoIfrNVData"
+#define MEM_INFO_VARSTORE_ID 0x1234
+#define MEM_INFO_FORM_ID 0x1235
+#define MEM_INFO_FORM_PERFORMANCE_ID 0x1236
+#define MEM_INFO_FORM_NVDIMM_ID 0x1237
+#define MEM_INFO_FORM_SET_GUID { 0xd58338ee, 0xe9f7, 0x4d8d, { 0xa7, 0x08, 0xdf, 0xb2, 0xc6, 0x66, 0x1d, 0x61 } }
+#define MEM_INFO_FORM_SET_PERFORMANCE_GUID { 0x4a072c78, 0x42f9, 0x11ea, { 0xb7, 0x7f, 0x2e, 0x28, 0xce, 0x88, 0x12, 0x62 } }
+
+#pragma pack(1)
+
+//
+// NV data structure definition
+//
+typedef struct {
+ UINT32 DDRSpeedSel;
+ UINT32 EccMode;
+ UINT32 ErrCtrl_DE;
+ UINT32 ErrCtrl_FI;
+ UINT32 Slave32bit;
+ UINT32 ScrubPatrol;
+ UINT32 DemandScrub;
+ UINT32 WriteCrc;
+ UINT32 FGRMode;
+ UINT32 Refresh2x;
+ UINT32 NvdimmModeSel;
+} MEM_INFO_VARSTORE_DATA;
+
+//
+// Labels definition
+//
+#define LABEL_UPDATE 0x2223
+#define LABEL_END 0x2224
+
+#pragma pack()
+
+#endif
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenVfr.vfr b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenVfr.vfr
new file mode 100644
index 000000000000..e3d7aa0c44bd
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenVfr.vfr
@@ -0,0 +1,62 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/PlatformManagerHii.h>
+#include "MemInfoScreenNVDataStruct.h"
+
+formset
+ guid = MEM_INFO_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_MEM_INFO_FORM),
+ help = STRING_TOKEN(STR_MEM_INFO_FORM_HELP),
+ classguid = gPlatformManagerFormsetGuid,
+
+ //
+ // Define a variable Storage
+ //
+ varstore MEM_INFO_VARSTORE_DATA,
+ varid = MEM_INFO_VARSTORE_ID,
+ name = MemInfoIfrNVData,
+ guid = MEM_INFO_FORM_SET_GUID;
+
+ form
+ formid = MEM_INFO_FORM_ID,
+ title = STRING_TOKEN(STR_MEM_INFO_FORM);
+
+ subtitle text = STRING_TOKEN(STR_MEM_INFO_FORM);
+
+ label LABEL_UPDATE;
+ // dynamic content here
+ label LABEL_END;
+
+ endform;
+
+ form
+ formid = MEM_INFO_FORM_PERFORMANCE_ID,
+ title = STRING_TOKEN(STR_MEM_INFO_PERFORMANCE_FORM);
+
+ subtitle text = STRING_TOKEN(STR_MEM_INFO_PERFORMANCE_FORM);
+
+ label LABEL_UPDATE;
+ // dynamic content here
+ label LABEL_END;
+
+ endform;
+
+ form
+ formid = MEM_INFO_FORM_NVDIMM_ID,
+ title = STRING_TOKEN(STR_MEM_INFO_NVDIMM_FORM);
+
+ subtitle text = STRING_TOKEN(STR_MEM_INFO_NVDIMM_FORM);
+
+ label LABEL_UPDATE;
+ // dynamic content here
+ label LABEL_END;
+
+ endform;
+
+endformset;
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoNvramLib.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoNvramLib.c
new file mode 100644
index 000000000000..c83f489f4078
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoNvramLib.c
@@ -0,0 +1,394 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/NVParamLib.h>
+
+#include "MemInfoScreen.h"
+#include "NVParamDef.h"
+
+#define DDR_NVPARAM_ERRCTRL_DE_FIELD_SHIFT 0
+#define DDR_NVPARAM_ERRCTRL_DE_FIELD_MASK 0x1
+
+#define DDR_NVPARAM_ERRCTRL_FI_FIELD_SHIFT 1
+#define DDR_NVPARAM_ERRCTRL_FI_FIELD_MASK 0x2
+
+/**
+ This is function collects meminfo from NVParam
+
+ @param Data The buffer to return the contents.
+
+ @retval EFI_SUCCESS Get response data successfully.
+ @retval Other value Failed to get meminfo from NVParam
+**/
+EFI_STATUS
+MemInfoNvparamGet (
+ OUT MEM_INFO_VARSTORE_DATA *VarStoreConfig
+ )
+{
+ UINT32 Value;
+ EFI_STATUS Status;
+
+ ASSERT (VarStoreConfig != NULL);
+
+ Status = NVParamGet (
+ NV_SI_DDR_SPEED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->DDRSpeedSel = 0; /* Default auto mode */
+ } else {
+ VarStoreConfig->DDRSpeedSel = Value;
+ }
+
+ Status = NVParamGet (
+ NV_SI_DDR_ECC_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->EccMode = ECC_SECDED; /* Default enable */
+ } else {
+ VarStoreConfig->EccMode = Value;
+ }
+
+ Status = NVParamGet (
+ NV_SI_DDR_ERRCTRL,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->ErrCtrl_DE = ERRCTLR_DE_ENABLE;
+ VarStoreConfig->ErrCtrl_FI = ERRCTLR_FI_ENABLE;
+ } else {
+ VarStoreConfig->ErrCtrl_DE = (Value & DDR_NVPARAM_ERRCTRL_DE_FIELD_MASK) >> DDR_NVPARAM_ERRCTRL_DE_FIELD_SHIFT;
+ VarStoreConfig->ErrCtrl_FI = (Value & DDR_NVPARAM_ERRCTRL_FI_FIELD_MASK) >> DDR_NVPARAM_ERRCTRL_FI_FIELD_SHIFT;
+ }
+
+ Status = NVParamGet (
+ NV_SI_DDR_SLAVE_32BIT_MEM_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->Slave32bit = 0; /* Default disabled */
+ } else {
+ VarStoreConfig->Slave32bit = Value;
+ }
+
+ Status = NVParamGet (
+ NV_SI_DDR_SCRUB_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->ScrubPatrol = DDR_DEFAULT_SCRUB_PATROL_DURATION;
+ } else {
+ VarStoreConfig->ScrubPatrol = Value;
+ }
+
+ Status = NVParamGet (
+ NV_SI_DDR_WR_BACK_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->DemandScrub = DDR_DEFAULT_DEMAND_SCRUB;
+ } else {
+ VarStoreConfig->DemandScrub = Value;
+ }
+
+ Status = NVParamGet (
+ NV_SI_DDR_CRC_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->WriteCrc = DDR_DEFAULT_WRITE_CRC;
+ } else {
+ VarStoreConfig->WriteCrc = Value;
+ }
+
+ Status = NVParamGet (
+ NV_SI_DDR_REFRESH_GRANULARITY,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->FGRMode = DDR_DEFAULT_FGR_MODE;
+ VarStoreConfig->Refresh2x = DDR_DEFAULT_REFRESH2X_MODE;
+ } else {
+ VarStoreConfig->FGRMode = DDR_FGR_MODE_GET (Value);
+ VarStoreConfig->Refresh2x = DDR_REFRESH_2X_GET (Value);
+ }
+
+ Status = NVParamGet (
+ NV_SI_NVDIMM_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->NvdimmModeSel = DDR_DEFAULT_NVDIMM_MODE_SEL;
+ } else {
+ VarStoreConfig->NvdimmModeSel = Value & DDR_NVDIMM_MODE_SEL_MASK; /* Mask out valid bit */
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is function stores meminfo to corresponding NVParam
+
+ @param VarStoreConfig The contents for the variable.
+
+ @retval EFI_SUCCESS Set data successfully.
+ @retval Other value Failed to set meminfo to NVParam
+
+**/
+EFI_STATUS
+MemInfoNvparamSet (
+ IN MEM_INFO_VARSTORE_DATA *VarStoreConfig
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Value, TmpValue, Value2, Update;
+
+ ASSERT (VarStoreConfig != NULL);
+
+ /* Set DDR speed */
+ Status = NVParamGet (
+ NV_SI_DDR_SPEED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value != VarStoreConfig->DDRSpeedSel) {
+ Status = NVParamSet (
+ NV_SI_DDR_SPEED,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ VarStoreConfig->DDRSpeedSel
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Set ECC mode */
+ Status = NVParamGet (
+ NV_SI_DDR_ECC_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value != VarStoreConfig->EccMode) {
+ Status = NVParamSet (
+ NV_SI_DDR_ECC_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ VarStoreConfig->EccMode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Set ErrCtrl */
+ TmpValue = (VarStoreConfig->ErrCtrl_DE << DDR_NVPARAM_ERRCTRL_DE_FIELD_SHIFT) |
+ (VarStoreConfig->ErrCtrl_FI << DDR_NVPARAM_ERRCTRL_FI_FIELD_SHIFT);
+ Status = NVParamGet (
+ NV_SI_DDR_ERRCTRL,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value != TmpValue ) {
+ Status = NVParamSet (
+ NV_SI_DDR_ERRCTRL,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ TmpValue
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Set slave's 32bit region */
+ TmpValue = VarStoreConfig->Slave32bit;
+ Status = NVParamGet (
+ NV_SI_DDR_SLAVE_32BIT_MEM_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value != TmpValue ) {
+ if (TmpValue == 0) {
+ /* Default is disabled so just clear nvparam */
+ Status = NVParamClr (
+ NV_SI_DDR_SLAVE_32BIT_MEM_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC
+ );
+ } else {
+ Status = NVParamSet (
+ NV_SI_DDR_SLAVE_32BIT_MEM_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ TmpValue
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Set Scrub patrol */
+ TmpValue = VarStoreConfig->ScrubPatrol;
+ Status = NVParamGet (
+ NV_SI_DDR_SCRUB_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value != TmpValue ) {
+ if (TmpValue == DDR_DEFAULT_SCRUB_PATROL_DURATION) {
+ Status = NVParamClr (
+ NV_SI_DDR_SCRUB_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC
+ );
+ } else {
+ Status = NVParamSet (
+ NV_SI_DDR_SCRUB_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ TmpValue
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Demand Scrub */
+ TmpValue = VarStoreConfig->DemandScrub;
+ Status = NVParamGet (
+ NV_SI_DDR_WR_BACK_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value != TmpValue ) {
+ if (TmpValue == DDR_DEFAULT_DEMAND_SCRUB) {
+ Status = NVParamClr (
+ NV_SI_DDR_WR_BACK_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC
+ );
+ } else {
+ Status = NVParamSet (
+ NV_SI_DDR_WR_BACK_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU |NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ TmpValue
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Write CRC */
+ TmpValue = VarStoreConfig->WriteCrc;
+ Status = NVParamGet (
+ NV_SI_DDR_CRC_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value != TmpValue ) {
+ if (TmpValue == DDR_DEFAULT_WRITE_CRC) {
+ Status = NVParamClr (
+ NV_SI_DDR_CRC_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC
+ );
+ } else {
+ Status = NVParamSet (
+ NV_SI_DDR_CRC_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ TmpValue
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Write FGR/Refresh2X */
+ Value = 0;
+ Update = 0;
+ TmpValue = VarStoreConfig->FGRMode;
+ Status = NVParamGet (
+ NV_SI_DDR_REFRESH_GRANULARITY,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ Value2 = DDR_FGR_MODE_GET (Value);
+ if ((EFI_ERROR (Status) && TmpValue != DDR_DEFAULT_FGR_MODE)
+ || Value2 != TmpValue)
+ {
+ DDR_FGR_MODE_SET (Value, TmpValue);
+ Update = 1;
+ }
+
+ Value2 = DDR_REFRESH_2X_GET (Value);
+ TmpValue = VarStoreConfig->Refresh2x;
+ if ((EFI_ERROR (Status) && TmpValue != DDR_DEFAULT_REFRESH2X_MODE)
+ || Value2 != TmpValue)
+ {
+ DDR_REFRESH_2X_SET (Value, TmpValue);
+ Update = 1;
+ }
+
+ if (Update == 1) {
+ Status = NVParamSet (
+ NV_SI_DDR_REFRESH_GRANULARITY,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ /* Write NVDIMM-N Mode selection */
+ Value = 0;
+ TmpValue = VarStoreConfig->NvdimmModeSel;
+ Status = NVParamGet (
+ NV_SI_NVDIMM_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ Value2 = Value & DDR_NVDIMM_MODE_SEL_MASK; /* Mask out valid bit */
+ if (EFI_ERROR (Status) || Value2 != TmpValue ) {
+ if (TmpValue == DDR_DEFAULT_NVDIMM_MODE_SEL) {
+ Status = NVParamClr (
+ NV_SI_NVDIMM_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC
+ );
+ } else {
+ Value = TmpValue | DDR_NVDIMM_MODE_SEL_VALID_BIT; /* Add valid bit */
+ Status = NVParamSet (
+ NV_SI_NVDIMM_MODE,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.c
new file mode 100644
index 000000000000..3a1a5840db9d
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreen.c
@@ -0,0 +1,1325 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemInfoScreen.h"
+
+#define MAX_STRING_SIZE 64
+#define GB_SCALE_FACTOR (1024*1024*1024)
+#define MB_SCALE_FACTOR (1024*1024)
+
+EFI_GUID gMemInfoFormSetGuid = MEM_INFO_FORM_SET_GUID;
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ MEM_INFO_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+EFI_HANDLE DriverHandle = NULL;
+MEM_INFO_SCREEN_PRIVATE_DATA *mPrivateData = NULL;
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ MEM_INFO_SCREEN_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ UINTN Size;
+ CHAR16 *StrPointer;
+ BOOLEAN AllocatedRequest;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ PrivateData = MEM_INFO_SCREEN_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get Buffer Storage data from EFI variable.
+ // Try to get the current setting from variable.
+ //
+ BufferSize = sizeof (MEM_INFO_VARSTORE_DATA);
+ Status = MemInfoNvparamGet (&PrivateData->VarStoreConfig);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Request == NULL) {
+ //
+ // Request is set to NULL, construct full request string.
+ //
+
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gMemInfoFormSetGuid, MEM_INFO_VARSTORE_NAME, PrivateData->DriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ ConfigRequestHdr = NULL;
+ } else {
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Request, &gMemInfoFormSetGuid, NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Set Request to the unified request string.
+ //
+ ConfigRequest = Request;
+
+ //
+ // Check whether Request includes Request Element.
+ //
+ if (StrStr (Request, L"OFFSET") == NULL) {
+ //
+ // Check Request Element does exist in Request String
+ //
+ StrPointer = StrStr (Request, L"PATH");
+ if (StrPointer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (StrStr (StrPointer, L"&") == NULL) {
+ Size = (StrLen (Request) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", Request, (UINT64)BufferSize);
+ }
+ }
+ }
+
+ //
+ // Check if requesting Name/Value storage
+ //
+ if (StrStr (ConfigRequest, L"OFFSET") == NULL) {
+ //
+ // Don't have any Name/Value storage names
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *)&PrivateData->VarStoreConfig,
+ BufferSize,
+ Results,
+ Progress
+ );
+ }
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ }
+
+ if (ConfigRequestHdr != NULL) {
+ FreePool (ConfigRequestHdr);
+ }
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ MEM_INFO_SCREEN_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = MEM_INFO_SCREEN_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gMemInfoFormSetGuid, NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get Buffer Storage data from NVParam
+ //
+ Status = MemInfoNvparamGet (&PrivateData->VarStoreConfig);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if configuring Name/Value storage
+ //
+ if (StrStr (Configuration, L"OFFSET") == NULL) {
+ //
+ // Don't have any Name/Value storage names
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (MEM_INFO_VARSTORE_DATA);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *)&PrivateData->VarStoreConfig,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store Buffer Storage back to NVParam
+ //
+ Status = MemInfoNvparamSet (&PrivateData->VarStoreConfig);
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+**/
+EFI_STATUS
+EFIAPI
+DriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN)
+ && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))
+ || (ActionRequest == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Action) {
+ case EFI_BROWSER_ACTION_FORM_OPEN:
+ case EFI_BROWSER_ACTION_FORM_CLOSE:
+ break;
+
+ case EFI_BROWSER_ACTION_DEFAULT_STANDARD:
+ case EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING:
+ {
+ switch (QuestionId) {
+ case MEM_INFO_DDR_SPEED_SEL_QUESTION_ID:
+ //
+ // DDR speed selection default to auto
+ //
+ Value->u32 = 0;
+ break;
+
+ case MEM_INFO_FORM_PERFORMANCE_ECC_QUESTION_ID:
+ //
+ // ECC mode default to be enabled
+ //
+ Value->u32 = ECC_SECDED;
+ break;
+
+ case MEM_INFO_FORM_PERFORMANCE_ERR_CTRL_DE_QUESTION_ID:
+ //
+ // ErrCtrl_DE default to be enabled
+ //
+ Value->u32 = ERRCTLR_DE_ENABLE;
+ break;
+
+ case MEM_INFO_FORM_PERFORMANCE_ERR_CTRL_FI_QUESTION_ID:
+ //
+ // ErrCtrl_FI default to be enabled
+ //
+ Value->u32 = ERRCTLR_FI_ENABLE;
+ break;
+
+ case MEM_INFO_DDR_SLAVE_32BIT_QUESTION_ID:
+ //
+ // Slave's 32bit region to be disabled
+ //
+ Value->u32 = 0;
+ break;
+
+ case MEM_INFO_DDR_SCRUB_PATROL_QUESTION_ID:
+ Value->u32 = DDR_DEFAULT_SCRUB_PATROL_DURATION;
+ break;
+
+ case MEM_INFO_DDR_DEMAND_SCRUB_QUESTION_ID:
+ Value->u32 = DDR_DEFAULT_DEMAND_SCRUB;
+ break;
+
+ case MEM_INFO_DDR_WRITE_CRC_QUESTION_ID:
+ Value->u32 = DDR_DEFAULT_WRITE_CRC;
+ break;
+
+ case MEM_INFO_FGR_MODE_QUESTION_ID:
+ Value->u32 = DDR_DEFAULT_FGR_MODE;
+ break;
+
+ case MEM_INFO_REFRESH2X_MODE_QUESTION_ID:
+ Value->u32 = DDR_DEFAULT_REFRESH2X_MODE;
+ break;
+
+ case MEM_INFO_FORM_NVDIMM_MODE_SEL_QUESTION_ID:
+ Value->u32 = DDR_DEFAULT_NVDIMM_MODE_SEL;
+ break;
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_RETRIEVE:
+ case EFI_BROWSER_ACTION_CHANGING:
+ case EFI_BROWSER_ACTION_SUBMITTED:
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MemInfoMainScreen (
+ PLATFORM_INFO_HOB *PlatformHob
+ )
+{
+ MEM_INFO_SCREEN_PRIVATE_DATA *PrivateData = mPrivateData;
+ EFI_STATUS Status;
+ VOID *StartOpCodeHandle;
+ VOID *OptionsOpCodeHandle;
+ VOID *OptionsOpCodeHandle1;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_STRING_ID StringId;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ CHAR16 Str[MAX_STRING_SIZE], Str1[MAX_STRING_SIZE];
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResHob;
+ PLATFORM_DIMM_INFO *DimmInfo;
+ UINT64 Size;
+ UINTN Count;
A lot of variables for a single function.

/
Leif

+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ Status = MemInfoNvparamGet (&PrivateData->VarStoreConfig);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_SUCCESS;
+
+ /* Update Total memory */
+ UnicodeSPrint (Str, sizeof (Str), L"%d GB", PlatformHob->DramInfo.TotalSize / GB_SCALE_FACTOR);
+ HiiSetString (
+ PrivateData->HiiHandle,
+ STRING_TOKEN (STR_MEM_INFO_TOTAL_MEM_VALUE),
+ Str,
+ NULL
+ );
+
+ /* Update effective memory */
+ Size = 0;
+ ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+ while (ResHob != NULL) {
+ if ((ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY)) {
+ Size += ResHob->ResourceLength;
+ }
+ ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
+ }
+ UnicodeSPrint (Str, sizeof (Str), L"%d GB", Size / GB_SCALE_FACTOR);
+ HiiSetString (
+ PrivateData->HiiHandle,
+ STRING_TOKEN (STR_MEM_INFO_EFFECT_MEM_VALUE),
+ Str,
+ NULL
+ );
+
+ /* Update current DDR speed */
+ UnicodeSPrint (Str, sizeof (Str), L"%d MHz", PlatformHob->DramInfo.MaxSpeed);
+ HiiSetString (
+ PrivateData->HiiHandle,
+ STRING_TOKEN (STR_MEM_INFO_CURRENT_SPEED_VALUE),
+ Str,
+ NULL
+ );
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Option OpCode to display speed configuration
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ //
+ // Create Option OpCode to display FGR mode configuration
+ //
+ OptionsOpCodeHandle1 = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle1 != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_UPDATE;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ //
+ // Create a total mem title
+ //
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_TOTAL_MEM),
+ STRING_TOKEN (STR_MEM_INFO_TOTAL_MEM),
+ STRING_TOKEN (STR_MEM_INFO_TOTAL_MEM_VALUE)
+ );
+
+ //
+ // Create a effective mem title
+ //
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_EFFECT_MEM),
+ STRING_TOKEN (STR_MEM_INFO_EFFECT_MEM),
+ STRING_TOKEN (STR_MEM_INFO_EFFECT_MEM_VALUE)
+ );
+
+ //
+ // Create a current speed title
+ //
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_CURRENT_SPEED),
+ STRING_TOKEN (STR_MEM_INFO_CURRENT_SPEED),
+ STRING_TOKEN (STR_MEM_INFO_CURRENT_SPEED_VALUE)
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_VALUE0),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 0
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_VALUE1),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 2133
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_VALUE2),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 2400
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_VALUE3),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 2666
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_VALUE4),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 2933
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_VALUE5),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 3200
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_DDR_SPEED_SEL_QUESTION_ID, // Question ID (or call it "key")
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_DDR_SPEED_SEL_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_SPEED_SELECT_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED, // Question flag
+ EFI_IFR_NUMERIC_SIZE_4, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ if (IsSlaveSocketActive ()) {
+ /* Display enable slave's 32bit region */
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_DDR_SLAVE_32BIT_QUESTION_ID, // Question ID
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_ERR_SLAVE_32BIT_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_32GB_SLAVE_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_32GB_SLAVE_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ NULL
+ );
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle1,
+ STRING_TOKEN (STR_MEM_INFO_FGR_MODE_VALUE0),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 0
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle1,
+ STRING_TOKEN (STR_MEM_INFO_FGR_MODE_VALUE1),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 1
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle1,
+ STRING_TOKEN (STR_MEM_INFO_FGR_MODE_VALUE2),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 2
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_FGR_MODE_QUESTION_ID, // Question ID (or call it "key")
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_FGR_MODE_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_FGR_MODE_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_FGR_MODE_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED, // Question flag
+ EFI_IFR_NUMERIC_SIZE_4, // Data type of Question Value
+ OptionsOpCodeHandle1, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ //
+ // Create a Goto OpCode to ras memory configuration
+ //
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_FORM_PERFORMANCE_ID, // Target Form ID
+ STRING_TOKEN (STR_MEM_INFO_PERFORMANCE_FORM), // Prompt text
+ STRING_TOKEN (STR_MEM_INFO_PERFORMANCE_FORM_HELP), // Help text
+ 0, // Question flag
+ MEM_INFO_FORM_PERFORMANCE_QUESTION_ID // Question ID
+ );
+
+ //
+ // Create a Goto OpCode to nvdimm-n configuration
+ //
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_FORM_NVDIMM_ID, // Target Form ID
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_FORM), // Prompt text
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_FORM_HELP), // Help text
+ 0, // Question flag
+ MEM_INFO_FORM_NVDIMM_QUESTION_ID // Question ID
+ );
+
+ //
+ // Display DIMM list info
+ //
+ HiiCreateSubTitleOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_DIMM_INFO),
+ 0,
+ 0,
+ 0
+ );
+
+ for (Count = 0; Count < PlatformHob->DimmList.BoardDimmSlots; Count++) {
+ DimmInfo = &PlatformHob->DimmList.Dimm[Count].Info;
+ switch (DimmInfo->DimmType) {
+ case UDIMM:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"UDIMM");
+ break;
+
+ case RDIMM:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"RDIMM");
+ break;
+
+ case SODIMM:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"SODIMM");
+ break;
+
+ case LRDIMM:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"LRDIMM");
+ break;
+
+ case RSODIMM:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"RSODIMM");
+ break;
+
+ case NVRDIMM:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"NV-RDIMM");
+ break;
+
+ default:
+ UnicodeSPrint (Str, sizeof (Str), L"Unknown Type");
+ }
+ if (DimmInfo->DimmStatus == DIMM_INSTALLED_OPERATIONAL) {
+ UnicodeSPrint (Str1, sizeof (Str1), L"Slot %2d: %d GB %s Installed&Operational", Count + 1, DimmInfo->DimmSize, Str);
+ } else if (DimmInfo->DimmStatus == DIMM_NOT_INSTALLED) {
+ UnicodeSPrint (Str1, sizeof (Str1), L"Slot %2d: Not Installed", Count + 1, PlatformHob->DimmList.Dimm[Count].NodeId);
+ } else if (DimmInfo->DimmStatus == DIMM_INSTALLED_NONOPERATIONAL) {
+ UnicodeSPrint (Str1, sizeof (Str1), L"Slot %2d: Installed&Non-Operational", Count + 1, PlatformHob->DimmList.Dimm[Count].NodeId);
+ } else {
+ UnicodeSPrint (Str1, sizeof (Str1), L"Slot %2d: Installed&Failed", Count + 1, PlatformHob->DimmList.Dimm[Count].NodeId);
+ }
+
+ StringId = HiiSetString (PrivateData->HiiHandle, 0, Str1, NULL);
+
+ HiiCreateSubTitleOpCode (
+ StartOpCodeHandle,
+ StringId,
+ 0,
+ 0,
+ 0
+ );
+ }
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &gMemInfoFormSetGuid, // Formset GUID
+ MEM_INFO_FORM_ID, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ return Status;
+}
+
+EFI_STATUS
+MemInfoMainPerformanceScreen (
+ PLATFORM_INFO_HOB *PlatformHob
+ )
+{
+ EFI_STATUS Status;
+ MEM_INFO_SCREEN_PRIVATE_DATA *PrivateData = mPrivateData;
+ VOID *StartOpCodeHandle;
+ VOID *OptionsEccOpCodeHandle, *OptionsScrubOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ EFI_STRING_ID StringId;
+ CHAR16 Str[MAX_STRING_SIZE];
+ UINTN Idx;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_UPDATE;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ /* Display ECC mode selection */
+ OptionsEccOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsEccOpCodeHandle != NULL);
+
+ UnicodeSPrint (Str, sizeof (Str), L"Disabled");
+ StringId = HiiSetString (PrivateData->HiiHandle, 0, Str, NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsEccOpCodeHandle,
+ StringId,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 0
+ );
+
+ UnicodeSPrint (Str, sizeof (Str), L"SECDED");
+ StringId = HiiSetString (PrivateData->HiiHandle, 0, Str, NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsEccOpCodeHandle,
+ StringId,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 1
+ );
+
+ UnicodeSPrint (Str, sizeof (Str), L"Symbol");
+ StringId = HiiSetString (PrivateData->HiiHandle, 0, Str, NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsEccOpCodeHandle,
+ StringId,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 2
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_FORM_PERFORMANCE_ECC_QUESTION_ID, // Question ID (or call it "key")
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_ECC_MODE_SEL_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_ECC_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_ECC_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED, // Question flag
+ EFI_IFR_NUMERIC_SIZE_4, // Data type of Question Value
+ OptionsEccOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ /*
+ * Display ErrCtrl options
+ */
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_FORM_PERFORMANCE_ERR_CTRL_DE_QUESTION_ID, // Question ID
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_ERR_CTRL_DE_MODE_SEL_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_ERRCTRL_DE_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_ERRCTRL_DE_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ NULL
+ );
+
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_FORM_PERFORMANCE_ERR_CTRL_FI_QUESTION_ID, // Question ID
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_ERR_CTRL_FI_MODE_SEL_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_ERRCTRL_FI_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_ERRCTRL_FI_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ NULL
+ );
+
+ /* Display Scrub Patrol selection */
+ OptionsScrubOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsScrubOpCodeHandle != NULL);
+
+ UnicodeSPrint (Str, sizeof (Str), L"Disabled");
+ StringId = HiiSetString (PrivateData->HiiHandle, 0, Str, NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsScrubOpCodeHandle,
+ StringId,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 0
+ );
+
+ for (Idx = 1; Idx <= MAX_NUMBER_OF_HOURS_IN_A_DAY; Idx++) {
+ UnicodeSPrint (Str, sizeof (Str), L"%d", Idx);
+ StringId = HiiSetString (
+ PrivateData->HiiHandle,
+ 0,
+ Str,
+ NULL
+ );
+ HiiCreateOneOfOptionOpCode (
+ OptionsScrubOpCodeHandle,
+ StringId,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ Idx
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_DDR_SCRUB_PATROL_QUESTION_ID, // Question ID (or call it "key")
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_DDR_SCRUB_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_SCRUB), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_SCRUB_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED, // Question flag
+ EFI_IFR_NUMERIC_SIZE_4, // Data type of Question Value
+ OptionsScrubOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ /*
+ * Display Demand Scrub options
+ */
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_DDR_DEMAND_SCRUB_QUESTION_ID, // Question ID
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_DDR_DEMAND_SCRUB_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_DEMAND_SCRUB_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_DEMAND_SCRUB_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ NULL
+ );
+
+ /*
+ * Display Write CRC options
+ */
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_DDR_WRITE_CRC_QUESTION_ID, // Question ID
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_DDR_WRITE_CRC_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_WRITE_CRC_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_ENABLE_WRITE_CRC_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ NULL
+ );
+
+ /*
+ * Display CVE-2020-10255 options
+ */
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_REFRESH2X_MODE_QUESTION_ID, // Question ID
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_REFRESH2X_MODE_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_REFRESH2X_MODE_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_REFRESH2X_MODE_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ NULL
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &gMemInfoFormSetGuid, // Formset GUID
+ MEM_INFO_FORM_PERFORMANCE_ID, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsEccOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsScrubOpCodeHandle);
+
+ return Status;
+}
+
+EFI_STATUS
+MemInfoMainNvdimmScreen (
+ PLATFORM_INFO_HOB *PlatformHob
+ )
+{
+ EFI_STATUS Status;
+ MEM_INFO_SCREEN_PRIVATE_DATA *PrivateData;
+ VOID *StartOpCodeHandle;
+ VOID *OptionsOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ CHAR16 Str[MAX_STRING_SIZE];
+
+ Status = EFI_SUCCESS;
+ PrivateData = mPrivateData;
+
+ if (PlatformHob == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_UPDATE;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ //
+ // Update Current NVDIMM-N Mode title Socket0
+ //
+ switch (PlatformHob->DramInfo.NvdimmMode[0]) {
+ case 0:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Non-NVDIMM");
+ break;
+
+ case 1:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Non-Hashed");
+ break;
+
+ case 2:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Hashed");
+ break;
+
+ default:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Unknown");
+ break;
+ }
+
+ HiiSetString (
+ PrivateData->HiiHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK0_VALUE),
+ Str,
+ NULL
+ );
+
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK0),
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK0),
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK0_VALUE)
+ );
+
+ //
+ // Update Current NVDIMM-N Mode title Socket1
+ //
+ if (IsSlaveSocketActive ()) {
+ switch (PlatformHob->DramInfo.NvdimmMode[1]) {
+ case 0:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Non-NVDIMM");
+ break;
+
+ case 1:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Non-Hashed");
+ break;
+
+ case 2:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Hashed");
+ break;
+
+ default:
+ UnicodeSPrint (Str, sizeof (Str), L"%s", L"Unknown");
+ break;
+ }
+
+ HiiSetString (
+ PrivateData->HiiHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK1_VALUE),
+ Str,
+ NULL
+ );
+
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK1),
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK1),
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_CUR_MODE_SK1_VALUE)
+ );
+ }
+ //
+ // Create Option OpCode to NVDIMM-N Mode Selection
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ //
+ // Create OpCode to NVDIMM-N Mode Selection
+ //
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE0),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 0
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE1),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 1
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE2),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 2
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE3),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ 3
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ MEM_INFO_FORM_NVDIMM_MODE_SEL_QUESTION_ID, // Question ID (or call it "key")
+ MEM_INFO_VARSTORE_ID, // VarStore ID
+ (UINT16)MEM_INFO_NVDIMM_MODE_SEL_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_MODE_SEL_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_MEM_INFO_NVDIMM_MODE_SEL_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED, // Question flag
+ EFI_IFR_NUMERIC_SIZE_4, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &gMemInfoFormSetGuid, // Formset GUID
+ MEM_INFO_FORM_NVDIMM_ID, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ return Status;
+}
+
+/**
+ This function sets up the first elements of the form.
+ @param PrivateData Private data.
+ @retval EFI_SUCCESS The form is set up successfully.
+**/
+EFI_STATUS
+MemInfoScreenSetup (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Hob;
+ PLATFORM_INFO_HOB *PlatformHob;
+
+ /* Get the Platform HOB */
+ Hob = GetFirstGuidHob (&gPlatformHobGuid);
+ if (Hob == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
+
+ Status = MemInfoMainScreen (PlatformHob);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = MemInfoMainPerformanceScreen (PlatformHob);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = MemInfoMainNvdimmScreen (PlatformHob);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MemInfoScreenInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ BOOLEAN ActionFlag;
+ EFI_STRING ConfigRequestHdr;
+
+ //
+ // Initialize driver private data
+ //
+ mPrivateData = AllocateZeroPool (sizeof (MEM_INFO_SCREEN_PRIVATE_DATA));
+ if (mPrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->Signature = MEM_INFO_SCREEN_PRIVATE_DATA_SIGNATURE;
+
+ mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ mPrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ mPrivateData->ConfigAccess.Callback = DriverCallback;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&HiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle = HiiAddPackages (
+ &gMemInfoFormSetGuid,
+ DriverHandle,
+ MemInfoDxeStrings,
+ MemInfoScreenVfrBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle = HiiHandle;
+
+ //
+ // Try to read NV config EFI variable first
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (
+ &gMemInfoFormSetGuid,
+ MEM_INFO_VARSTORE_NAME,
+ DriverHandle
+ );
+ ASSERT (ConfigRequestHdr != NULL);
+
+ //
+ // Validate Current Setting
+ //
+ ActionFlag = HiiValidateSettings (ConfigRequestHdr);
+ if (!ActionFlag) {
+ MemInfoScreenUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ FreePool (ConfigRequestHdr);
+
+ Status = MemInfoScreenSetup ();
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MemInfoScreenUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ ASSERT (mPrivateData != NULL);
+
+ if (DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ DriverHandle = NULL;
+ }
+
+ if (mPrivateData->HiiHandle != NULL) {
+ HiiRemovePackages (mPrivateData->HiiHandle);
+ }
+
+ FreePool (mPrivateData);
+ mPrivateData = NULL;
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.uni
new file mode 100644
index 000000000000..a8c7cb99d6a7
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxe.uni
@@ -0,0 +1,9 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#string STR_MODULE_ABSTRACT #language en-US "An Altra DDR screen setup driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver exposes a screen setup for DDR information and configuration."
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxeExtra.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxeExtra.uni
new file mode 100644
index 000000000000..f44f210594be
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoDxeExtra.uni
@@ -0,0 +1,9 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Ampere Altra MemInfo DXE Driver"
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenStrings.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenStrings.uni
new file mode 100644
index 000000000000..d170f9ee7313
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/MemInfoDxe/MemInfoScreenStrings.uni
@@ -0,0 +1,64 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#langdef en-US "English" // English
+
+#string STR_MEM_INFO_FORM #language en-US "Memory Configuration"
+#string STR_MEM_INFO_FORM_HELP #language en-US "Memory Configuration"
+#string STR_MEM_INFO_TOTAL_MEM #language en-US "Total Memory"
+#string STR_MEM_INFO_TOTAL_MEM_VALUE #language en-US "0 GB"
+#string STR_MEM_INFO_EFFECT_MEM #language en-US "Effective Memory"
+#string STR_MEM_INFO_EFFECT_MEM_VALUE #language en-US "0 MB"
+#string STR_MEM_INFO_CURRENT_SPEED #language en-US "Memory Speed"
+#string STR_MEM_INFO_CURRENT_SPEED_VALUE #language en-US "0 MHz"
+#string STR_MEM_INFO_SPEED_SELECT_PROMPT #language en-US "Memory Operating Speed Selection"
+#string STR_MEM_INFO_SPEED_SELECT_HELP #language en-US "Force specific Memory Operating Speed or use Auto setting."
+#string STR_MEM_INFO_SPEED_SELECT_VALUE0 #language en-US "Auto"
+#string STR_MEM_INFO_SPEED_SELECT_VALUE1 #language en-US "2133"
+#string STR_MEM_INFO_SPEED_SELECT_VALUE2 #language en-US "2400"
+#string STR_MEM_INFO_SPEED_SELECT_VALUE3 #language en-US "2666"
+#string STR_MEM_INFO_SPEED_SELECT_VALUE4 #language en-US "2933"
+#string STR_MEM_INFO_SPEED_SELECT_VALUE5 #language en-US "3200"
+#string STR_MEM_INFO_DIMM_INFO #language en-US "DIMM Information"
+
+#string STR_MEM_INFO_PERFORMANCE_FORM #language en-US "Memory RAS and Performance Configuration"
+#string STR_MEM_INFO_PERFORMANCE_FORM_HELP #language en-US "Displays and provides options to change the memory RAS and performance Settings"
+#string STR_MEM_INFO_ENABLE_ECC_PROMPT #language en-US "ECC mode"
+#string STR_MEM_INFO_ENABLE_ECC_HELP #language en-US "ECC mode: Disabled, SECDED or Symbol"
+#string STR_MEM_INFO_ENABLE_ERRCTRL_DE_PROMPT #language en-US "Defer uncorrectable read errors"
+#string STR_MEM_INFO_ENABLE_ERRCTRL_DE_HELP #language en-US "When enabled the DMC defers uncorrectable read errors to the consumer by sending an OK response and setting the TXDAT poison flag on the CHI-B interconnect. If this bit is clear the DMC defaults to non-deferred behavior when encountering an unrecoverable error"
+#string STR_MEM_INFO_ENABLE_ERRCTRL_FI_PROMPT #language en-US "Fault handling interrupt"
+#string STR_MEM_INFO_ENABLE_ERRCTRL_FI_HELP #language en-US "Enables fault handling interrupt. The fault handling interrupt is raised to give notice that ECC fault has been recorded"
+#string STR_MEM_INFO_ENABLE_SCRUB #language en-US "Scrub Patrol duration (hour)"
+#string STR_MEM_INFO_ENABLE_SCRUB_HELP #language en-US "Select duration (hour) for Scrub Patrol"
+#string STR_MEM_INFO_ENABLE_DEMAND_SCRUB_PROMPT #language en-US "Demand scrub"
+#string STR_MEM_INFO_ENABLE_DEMAND_SCRUB_HELP #language en-US "Enable/Disable the ability to write corrected data back to the memory once a correctable error is detected"
+#string STR_MEM_INFO_ENABLE_WRITE_CRC_PROMPT #language en-US "Write CRC"
+#string STR_MEM_INFO_ENABLE_WRITE_CRC_HELP #language en-US "Enable/Disable Cyclic Redundancy Check (CRC) functionality on write data. Be noted that enabling CRC will degrade Write bandwidth"
+
+
+#string STR_MEM_INFO_ENABLE_32GB_SLAVE_PROMPT #language en-US "Enable Slave 32bit memory region"
+#string STR_MEM_INFO_ENABLE_32GB_SLAVE_HELP #language en-US "Enables 32bit memory region (2GB) for slave socket"
+#string STR_MEM_INFO_FGR_MODE_PROMPT #language en-US "Fine Granularity Refresh (FGR)"
+#string STR_MEM_INFO_FGR_MODE_VALUE0 #language en-US "1x"
+#string STR_MEM_INFO_FGR_MODE_VALUE1 #language en-US "2x"
+#string STR_MEM_INFO_FGR_MODE_VALUE2 #language en-US "4x"
+#string STR_MEM_INFO_FGR_MODE_HELP #language en-US "Select DDR Fine Granularity Refresh (FGR) mode 1x/2x/4x"
+#string STR_MEM_INFO_REFRESH2X_MODE_PROMPT #language en-US "CVE-2020-10255 mitigation"
+#string STR_MEM_INFO_REFRESH2X_MODE_HELP #language en-US "Enable mitigation for CVE-2020-10255, TRRespass"
+
+#string STR_MEM_INFO_NVDIMM_FORM #language en-US "NVDIMM-N Configuration"
+#string STR_MEM_INFO_NVDIMM_FORM_HELP #language en-US "Displays and provides options to change the NVDIMM-N Settings"
+#string STR_MEM_INFO_NVDIMM_CUR_MODE_SK0 #language en-US "Socket0 Configured Mode"
+#string STR_MEM_INFO_NVDIMM_CUR_MODE_SK1 #language en-US "Socket1 Configured Mode"
+#string STR_MEM_INFO_NVDIMM_CUR_MODE_SK0_VALUE #language en-US "Non-NVDIMM"
+#string STR_MEM_INFO_NVDIMM_CUR_MODE_SK1_VALUE #language en-US "Non-NVDIMM"
+#string STR_MEM_INFO_NVDIMM_MODE_SEL_PROMPT #language en-US "Mode Selection"
+#string STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE0 #language en-US "Non-NVDIMM"
+#string STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE1 #language en-US "Non-Hashed"
+#string STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE2 #language en-US "Hashed"
+#string STR_MEM_INFO_NVDIMM_MODE_SEL_VALUE3 #language en-US "Auto"
+#string STR_MEM_INFO_NVDIMM_MODE_SEL_HELP #language en-US "Select NVDIMM-N Mode (Non-NVDIMM/Non-Hashed/Hashed/Auto)"
--
2.17.1


Re: [PATCH v3 21/28] AmpereAltraPkg: Add DebugInfoPei module

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:20 +0700, Nhi Pham wrote:
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Helps to show various system information like CPU info and Board Setting
values to UART console during boot process.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>

---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 4 +
Platform/Ampere/JadePkg/Jade.fdf | 2 +
Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.inf | 40 ++++
Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.c | 210 ++++++++++++++++++++
4 files changed, 256 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index 459d06c33c02..aadbf6dae83e 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -543,6 +543,10 @@ [Components.common]
ArmPlatformPkg/PlatformPei/PlatformPeim.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.inf {
+ <LibraryClasses>
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+ }
Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
ArmPkg/Drivers/CpuPei/CpuPei.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 96213edb2676..56a54b307f04 100644
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -167,6 +167,8 @@ [FV.FVMAIN_COMPACT]
#
# Print platform information before passing control into the Driver Execution Environment (DXE) phase
#
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.inf
+
INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf

FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 {
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.inf
new file mode 100644
index 000000000000..1f50f811f273
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.inf
@@ -0,0 +1,40 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = DebugInfo
+ FILE_GUID = C0571D26-6176-11E9-8647-D663BD873D93
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DebugInfoPeiEntryPoint
+
+[Sources]
+ DebugInfoPei.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ AmpereCpuLib
+ ArmLib
+ DebugLib
+ HobLib
+ NVParamLib
+ PeimEntryPoint
+
+[Guids]
+ gPlatformHobGuid
+
+[Depex]
+ TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.c
new file mode 100644
index 000000000000..ece9295864a8
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/DebugInfoPei/DebugInfoPei.c
@@ -0,0 +1,210 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Uefi.h>
+
+#include <Guid/PlatformInfoHobGuid.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/ArmLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/NVParamLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+
+#include <NVParamDef.h>
+#include <PlatformInfoHob.h>
+
+#define GB_SCALE_FACTOR 1073741824
+#define MB_SCALE_FACTOR 1048576
+#define KB_SCALE_FACTOR 1024
+#define MHZ_SCALE_FACTOR 1000000
+
+/**
+ Print any existence NVRAM.
+**/
+STATIC VOID
+PrintNVRAM (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ NVPARAM Idx;
+ UINT32 Val;
+ UINT16 ACLRd = NV_PERM_ALL;
+ BOOLEAN Flag;
+
+ Flag = FALSE;
+ for (Idx = NV_PREBOOT_PARAM_START; Idx <= NV_PREBOOT_PARAM_MAX; Idx += NVPARAM_SIZE) {
+ Status = NVParamGet (Idx, ACLRd, &Val);
+ if (!EFI_ERROR (Status)) {
+ if (!Flag) {
+ DebugPrint (DEBUG_INIT, "Pre-boot Configuration Setting:\n");
+ Flag = TRUE;
+ }
+ DebugPrint (DEBUG_INIT, " %04X: 0x%X (%d)\n", (UINT32)Idx, Val, Val);
+ }
+ }
+
+ Flag = FALSE;
+ for (Idx = NV_MANU_PARAM_START; Idx <= NV_MANU_PARAM_MAX; Idx += NVPARAM_SIZE) {
+ Status = NVParamGet (Idx, ACLRd, &Val);
+ if (!EFI_ERROR (Status)) {
+ if (!Flag) {
+ DebugPrint (DEBUG_INIT, "Manufacturer Configuration Setting:\n");
+ Flag = TRUE;
+ }
+ DebugPrint (DEBUG_INIT, " %04X: 0x%X (%d)\n", (UINT32)Idx, Val, Val);
+ }
+ }
+
+ Flag = FALSE;
+ for (Idx = NV_USER_PARAM_START; Idx <= NV_USER_PARAM_MAX; Idx += NVPARAM_SIZE) {
+ Status = NVParamGet (Idx, ACLRd, &Val);
+ if (!EFI_ERROR (Status)) {
+ if (!Flag) {
+ DebugPrint (DEBUG_INIT, "User Configuration Setting:\n");
+ Flag = TRUE;
+ }
+ DebugPrint (DEBUG_INIT, " %04X: 0x%X (%d)\n", (UINT32)Idx, Val, Val);
+ }
+ }
+
+ Flag = FALSE;
+ for (Idx = NV_BOARD_PARAM_START; Idx <= NV_BOARD_PARAM_MAX; Idx += NVPARAM_SIZE) {
+ Status = NVParamGet (Idx, ACLRd, &Val);
+ if (!EFI_ERROR (Status)) {
+ if (!Flag) {
+ DebugPrint (DEBUG_INIT, "Board Configuration Setting:\n");
+ Flag = TRUE;
+ }
+ DebugPrint (DEBUG_INIT, " %04X: 0x%X (%d)\n", (UINT32)Idx, Val, Val);
+ }
+ }
+}
+
+STATIC
+CHAR8 *
+GetCCIXLinkSpeed (
+ IN UINTN Speed
+ )
+{
+ switch (Speed) {
+ case 1:
+ return "2.5 GT/s";
+
+ case 2:
+ return "5 GT/s";
+
+ case 3:
+ return "8 GT/s";
+
+ case 4:
+ case 6:
+ return "16 GT/s";
+
+ case 0xa:
+ return "20 GT/s";
+
+ case 0xf:
+ return "25 GT/s";
+ }
+
+ return "Unknown";
+}
+
+/**
+ Print system info
+**/
+STATIC VOID
+PrintSystemInfo (
+ VOID
+ )
+{
+ UINTN Idx;
+ VOID *Hob;
+ PLATFORM_INFO_HOB *PlatformHob;
+
+ Hob = GetFirstGuidHob (&gPlatformHobGuid);
+ if (Hob == NULL) {
+ return;
+ }
+
+ PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
+
+ DebugPrint (DEBUG_INIT, "SCP FW version : %a\n", (const CHAR8 *)PlatformHob->SmPmProVer);
+ DebugPrint (DEBUG_INIT, "SCP FW build date : %a\n", (const CHAR8 *)PlatformHob->SmPmProBuild);
+
+ DebugPrint (DEBUG_INIT, "Failsafe status : %d\n", PlatformHob->FailSafeStatus);
+ DebugPrint (DEBUG_INIT, "Reset status : %d\n", PlatformHob->ResetStatus);
+ DebugPrint (DEBUG_INIT, "CPU info\n");
+ DebugPrint (DEBUG_INIT, " CPU ID : %X\n", ArmReadMidr ());
+ DebugPrint (DEBUG_INIT, " CPU Clock : %d MHz\n", PlatformHob->CpuClk / MHZ_SCALE_FACTOR);
+ DebugPrint (DEBUG_INIT, " Number of active sockets : %d\n", GetNumberOfActiveSockets ());
+ DebugPrint (DEBUG_INIT, " Number of active cores : %d\n", GetNumberOfActiveCores ());
+ if (IsSlaveSocketActive ()) {
+ DebugPrint (DEBUG_INIT,
+ " Inter Socket Connection 0 : Width: x%d / Speed %a\n",
+ PlatformHob->Link2PWidth[0],
+ GetCCIXLinkSpeed (PlatformHob->Link2PSpeed[0])
+ );
+ DebugPrint (DEBUG_INIT,
+ " Inter Socket Connection 1 : Width: x%d / Speed %a\n",
+ PlatformHob->Link2PWidth[1],
+ GetCCIXLinkSpeed (PlatformHob->Link2PSpeed[1])
+ );
+ }
+ for (Idx = 0; Idx < GetNumberOfActiveSockets (); Idx++) {
+ DebugPrint (DEBUG_INIT, " Socket[%d]: Core voltage : %d\n", Idx, PlatformHob->CoreVoltage[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: SCU ProductID : %X\n", Idx, PlatformHob->ScuProductId[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: Max cores : %d\n", Idx, PlatformHob->MaxNumOfCore[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: Warranty : %d\n", Idx, PlatformHob->Warranty[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: Subnuma : %d\n", Idx, PlatformHob->SubNumaMode[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: RC disable mask : %X\n", Idx, PlatformHob->RcDisableMask[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: AVS enabled : %d\n", Idx, PlatformHob->AvsEnable[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: AVS voltage : %d\n", Idx, PlatformHob->AvsVoltageMV[Idx]);
+ }
+
+ DebugPrint (DEBUG_INIT, "SOC info\n");
+ DebugPrint (DEBUG_INIT, " DDR Frequency : %d MHz\n", PlatformHob->DramInfo.MaxSpeed);
+ for (Idx = 0; Idx < GetNumberOfActiveSockets (); Idx++) {
+ DebugPrint (DEBUG_INIT, " Socket[%d]: Soc voltage : %d\n", Idx, PlatformHob->SocVoltage[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: DIMM1 voltage : %d\n", Idx, PlatformHob->Dimm1Voltage[Idx]);
+ DebugPrint (DEBUG_INIT, " Socket[%d]: DIMM2 voltage : %d\n", Idx, PlatformHob->Dimm2Voltage[Idx]);
+ }
+
+ DebugPrint (DEBUG_INIT, " PCP Clock : %d MHz\n", PlatformHob->PcpClk / MHZ_SCALE_FACTOR);
+ DebugPrint (DEBUG_INIT, " SOC Clock : %d MHz\n", PlatformHob->SocClk / MHZ_SCALE_FACTOR);
+ DebugPrint (DEBUG_INIT, " SYS Clock : %d MHz\n", PlatformHob->SysClk / MHZ_SCALE_FACTOR);
+ DebugPrint (DEBUG_INIT, " AHB Clock : %d MHz\n", PlatformHob->AhbClk / MHZ_SCALE_FACTOR);
+}
+
+/**
+ Entry point function for the PEIM
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @return EFI_SUCCESS If we installed our PPI
+
+**/
+EFI_STATUS
+EFIAPI
+DebugInfoPeiEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ PrintSystemInfo ();
+ PrintNVRAM ();
+
+ return EFI_SUCCESS;
+}
--
2.17.1


Re: [PATCH v3 13/28] JadePkg: Add BoardPcieLib library instance

Leif Lindholm
 

On Wed, Sep 15, 2021 at 22:55:12 +0700, Nhi Pham wrote:
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Provides basic features like:
* Screen menu to change the bifurcation setting of each Root Complex.
Note that we can only make change for the Root Complex which doesn't
come with a default value in the BoardSetting.
* Parsing the BoardSetting and coordinate with saved setting to enable
corresponding PCIe controller of each Root Complex.
* Config speed and lane of enabled controller.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
---
Platform/Ampere/JadePkg/Jade.dsc | 7 +-
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieLib.inf | 59 +
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.h | 45 +
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.h | 114 ++
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.h | 99 ++
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.vfr | 217 ++++
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.c | 436 +++++++
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieCommon.c | 329 ++++++
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.c | 1244 ++++++++++++++++++++
Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.uni | 102 ++
10 files changed, 2651 insertions(+), 1 deletion(-)

diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index 118c03eab42f..afea3407a256 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -52,7 +52,7 @@ [Defines]
DEFINE EDK2_SKIP_PEICORE = TRUE
DEFINE SECURE_BOOT_ENABLE = FALSE
DEFINE INCLUDE_TFTP_COMMAND = TRUE
- DEFINE NVRAM_UUID = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5
+ DEFINE NVRAM_UUID = 27AF4DFF-028B-4237-80B9-828FA74132F4
This shouldn't be changing in the midst of the series - please change
it where it's introduced:
"AmpereAltraPkg: Support UEFI non-volatile variable"


#
# Network definition
@@ -88,6 +88,11 @@ [LibraryClasses]
#
AcpiLib|EmbeddedPkg/Library/AcpiLib/AcpiLib.inf

+ #
+ # Pcie Board
+ #
+ BoardPcieLib|Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieLib.inf
+
################################################################################
#
# Specific Platform Pcds
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieLib.inf b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieLib.inf
new file mode 100644
index 000000000000..75e3560f4fca
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieLib.inf
@@ -0,0 +1,59 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = BoardPcieLib
+ FILE_GUID = 062191A6-E113-4FD6-84C7-E400B4B34759
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = BoardPcieLib
+
+[Sources]
+ BoardPcie.c
+ BoardPcieCommon.c
+ BoardPcieScreen.c
+ BoardPcieScreen.h
+ BoardPcieScreen.uni
+ BoardPcieVfr.h
+ BoardPcieVfr.vfr
+
+[Packages]
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ AmpereCpuLib
+ BaseLib
+ DevicePathLib
+ GpioLib
+ HiiLib
+ HobLib
+ MemoryAllocationLib
+ SystemFirmwareInterfaceLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiHiiStringProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiConfigKeywordHandlerProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES
+ gPlatformManagerFormsetGuid ## CONSUMES
+ gPlatformHobGuid ## CONSUMES
+
+[Depex]
+ TRUE
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.h b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.h
new file mode 100644
index 000000000000..73ba3ee83ac2
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.h
@@ -0,0 +1,45 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BOARD_PCIE_H_
+#define BOARD_PCIE_H_
+
+#include <Ac01PcieCommon.h>
+
+#define BITS_PER_BYTE 8
+#define BYTE_MASK 0xFF
+#define PCIE_ERRATA_SPEED1 0x0001 // Limited speed errata
+
+enum DEV_MAP_MODE {
+ DEV_MAP_1_CONTROLLER = 0,
+ DEV_MAP_2_CONTROLLERS,
+ DEV_MAP_3_CONTROLLERS,
+ DEV_MAP_4_CONTROLLERS,
+};
Enum style, as per earlier patches.

+
+BOOLEAN
+IsEmptyRC (
+ IN AC01_RC *RC
+ );
+
+VOID
+BoardPcieSetupDevmap (
+ IN AC01_RC *RC
+ );
+
+VOID
+BoardPcieGetLaneAllocation (
+ IN AC01_RC *RC
+ );
+
+VOID
+BoardPcieGetSpeed (
+ IN AC01_RC *RC
+ );
+
+#endif /* BOARD_PCIE_H_ */
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.h b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.h
new file mode 100644
index 000000000000..b95c99588a56
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.h
@@ -0,0 +1,114 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BOARD_PCIE_SCREEN_H_
+#define BOARD_PCIE_SCREEN_H_
+
+#include "BoardPcieVfr.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 BoardPcieVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 BoardPcieLibStrings[];
+
+#define MAX_EDITABLE_ELEMENTS 3
+#define RC0_STATUS_OFFSET \
+ OFFSET_OF (VARSTORE_DATA, RCStatus[0])
+#define RC0_BIFUR_LO_OFFSET \
+ OFFSET_OF (VARSTORE_DATA, RCBifurcationLow[0])
+#define RC0_BIFUR_HI_OFFSET \
+ OFFSET_OF (VARSTORE_DATA, RCBifurcationHigh[0])
+#define SMMU_PMU_OFFSET \
+ OFFSET_OF (VARSTORE_DATA, SmmuPmu)
+
+#define STRONG_ODERING_OFFSET \
Typo:
ODERING ->
ORDERING

+ OFFSET_OF (NVPARAM_VARSTORE_DATA, PcieStrongOrdering)
+
+//
+// Signature: Ampere Computing PCIe Screen
+//
+#define SCREEN_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('A', 'C', 'P', 'S')
+
+#define MAX_STRING_SIZE 32
+
+#define STRONG_ORDERING_DEFAULT_OPTION_VALUE 1
+#define STRONG_ORDERING_DEFAULT_NVPARAM_VALUE 0xFFFFFFFF
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ VARSTORE_DATA VarStoreConfig;
+ NVPARAM_VARSTORE_DATA NVParamVarStoreConfig;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} SCREEN_PRIVATE_DATA;
+
+typedef struct {
+ UINTN PciDevIdx;
+ EFI_STRING_ID GotoStringId;
+ EFI_STRING_ID GotoHelpStringId;
+ UINT16 GotoKey;
+ BOOLEAN ShowItem;
+} SETUP_GOTO_DATA;
+
+#define SCREEN_PRIVATE_FROM_THIS(a) \
+ CR (a, SCREEN_PRIVATE_DATA, ConfigAccess, SCREEN_PRIVATE_DATA_SIGNATURE)
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+UINT8
+PcieRCDevMapLowDefaultSetting (
+ IN UINTN RCIndex,
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ );
+
+UINT8
+PcieRCDevMapHighDefaultSetting (
+ IN UINTN RCIndex,
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ );
+
+BOOLEAN
+PcieRCActiveDefaultSetting (
+ IN UINTN RCIndex,
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ );
+
+#endif /* BOARD_PCIE_SCREEN_H_ */
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.h b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.h
new file mode 100644
index 000000000000..badb1c80f9ab
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.h
@@ -0,0 +1,99 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BOARD_PCIE_VFR_H_
+#define BOARD_PCIE_VFR_H_
+
+#include <Platform/Ac01.h>
+
+#define VARSTORE_NAME L"PcieIfrNVData"
+#define VARSTORE_ID 0x1234
+#define FORM_ID 0x1235
+#define RC0_FORM_ID 0x1236
+#define RC1_FORM_ID 0x1237
+#define RC2_FORM_ID 0x1238
+#define RC3_FORM_ID 0x1239
+#define RC4_FORM_ID 0x123A
+#define RC5_FORM_ID 0x123B
+#define RC6_FORM_ID 0x123C
+#define RC7_FORM_ID 0x123D
+#define RC8_FORM_ID 0x123E
+#define RC9_FORM_ID 0x123F
+#define RC10_FORM_ID 0x1240
+#define RC11_FORM_ID 0x1241
+#define RC12_FORM_ID 0x1242
+#define RC13_FORM_ID 0x1243
+#define RC14_FORM_ID 0x1244
+#define RC15_FORM_ID 0x1245
+#define FORM_SET_GUID { 0xe84e70d6, 0xe4b2, 0x4c6e, { 0x98, 0x51, 0xcb, 0x2b, 0xac, 0x77, 0x7d, 0xbb } }
+
+#define GOTO_ID_BASE 0x8040
+
+#define NVPARAM_VARSTORE_NAME L"PcieIfrNVParamData"
+#define NVPARAM_VARSTORE_ID 0x1233
+
+#pragma pack(1)
+
+//
+// NV data structure definition
+//
+typedef struct {
+ BOOLEAN RCStatus[AC01_MAX_PCIE_ROOT_COMPLEX];
+ UINT8 RCBifurcationLow[AC01_MAX_PCIE_ROOT_COMPLEX];
+ UINT8 RCBifurcationHigh[AC01_MAX_PCIE_ROOT_COMPLEX];
+ UINT32 SmmuPmu;
+} VARSTORE_DATA;
+
+//
+// NVParam data structure definition
+//
+typedef struct {
+ BOOLEAN PcieStrongOrdering;
+} NVPARAM_VARSTORE_DATA;
+
+#pragma pack()
+
+//
+// Labels definition
+//
+#define LABEL_UPDATE 0x2223
+#define LABEL_END 0x2224
+#define LABEL_RC0_UPDATE 0x2225
+#define LABEL_RC0_END 0x2226
+#define LABEL_RC1_UPDATE 0x2227
+#define LABEL_RC1_END 0x2228
+#define LABEL_RC2_UPDATE 0x2229
+#define LABEL_RC2_END 0x222A
+#define LABEL_RC3_UPDATE 0x222B
+#define LABEL_RC3_END 0x222C
+#define LABEL_RC4_UPDATE 0x222D
+#define LABEL_RC4_END 0x222E
+#define LABEL_RC5_UPDATE 0x222F
+#define LABEL_RC5_END 0x2230
+#define LABEL_RC6_UPDATE 0x2231
+#define LABEL_RC6_END 0x2232
+#define LABEL_RC7_UPDATE 0x2233
+#define LABEL_RC7_END 0x2234
+#define LABEL_RC8_UPDATE 0x2235
+#define LABEL_RC8_END 0x2236
+#define LABEL_RC9_UPDATE 0x2237
+#define LABEL_RC9_END 0x2238
+#define LABEL_RC10_UPDATE 0x2239
+#define LABEL_RC10_END 0x223A
+#define LABEL_RC11_UPDATE 0x223B
+#define LABEL_RC11_END 0x223C
+#define LABEL_RC12_UPDATE 0x223D
+#define LABEL_RC12_END 0x223E
+#define LABEL_RC13_UPDATE 0x223F
+#define LABEL_RC13_END 0x2240
+#define LABEL_RC14_UPDATE 0x2241
+#define LABEL_RC14_END 0x2242
+#define LABEL_RC15_UPDATE 0x2243
+#define LABEL_RC15_END 0x2244
+
+#endif /* BOARD_PCIE_VFR_H_ */
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.vfr b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.vfr
new file mode 100644
index 000000000000..7fb9adb67030
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieVfr.vfr
@@ -0,0 +1,217 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BoardPcieVfr.h"
+
+formset
+ guid = FORM_SET_GUID,
+ title = STRING_TOKEN(STR_PCIE_FORM),
+ help = STRING_TOKEN(STR_PCIE_FORM_HELP),
+ classguid = gPlatformManagerFormsetGuid,
+
+ //
+ // Define a variable Storage
+ //
+ varstore VARSTORE_DATA,
+ varid = VARSTORE_ID,
+ name = PcieIfrNVData,
+ guid = FORM_SET_GUID;
+
+ varstore NVPARAM_VARSTORE_DATA,
+ varid = NVPARAM_VARSTORE_ID,
+ name = PcieIfrNVParamData,
+ guid = FORM_SET_GUID;
+
+ form
+ formid = FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_FORM);
+
+ label LABEL_UPDATE;
+ // dynamic content here
+ label LABEL_END;
+ endform;
+
+ form
+ formid = RC0_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC0_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC0_FORM);
+
+ label LABEL_RC0_UPDATE;
+ // dynamic content here
+ label LABEL_RC0_END;
+ endform;
+
+ form
+ formid = RC1_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC1_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC1_FORM);
+
+ label LABEL_RC1_UPDATE;
+ // dynamic content here
+ label LABEL_RC1_END;
+ endform;
+
+ form
+ formid = RC2_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC2_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC2_FORM);
+
+ label LABEL_RC2_UPDATE;
+ // dynamic content here
+ label LABEL_RC2_END;
+ endform;
+
+ form
+ formid = RC3_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC3_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC3_FORM);
+
+ label LABEL_RC3_UPDATE;
+ // dynamic content here
+ label LABEL_RC3_END;
+ endform;
+
+ form
+ formid = RC4_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC4_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC4_FORM);
+
+ label LABEL_RC4_UPDATE;
+ // dynamic content here
+ label LABEL_RC4_END;
+ endform;
+
+ form
+ formid = RC5_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC5_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC5_FORM);
+
+ label LABEL_RC5_UPDATE;
+ // dynamic content here
+ label LABEL_RC5_END;
+ endform;
+
+ form
+ formid = RC6_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC6_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC6_FORM);
+
+ label LABEL_RC6_UPDATE;
+ // dynamic content here
+ label LABEL_RC6_END;
+ endform;
+
+ form
+ formid = RC7_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC7_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC7_FORM);
+
+ label LABEL_RC7_UPDATE;
+ // dynamic content here
+ label LABEL_RC7_END;
+ endform;
+
+ form
+ formid = RC8_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC8_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC8_FORM);
+
+ label LABEL_RC8_UPDATE;
+ // dynamic content here
+ label LABEL_RC8_END;
+ endform;
+
+ form
+ formid = RC9_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC9_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC9_FORM);
+
+ label LABEL_RC9_UPDATE;
+ // dynamic content here
+ label LABEL_RC9_END;
+ endform;
+
+ form
+ formid = RC10_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC10_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC10_FORM);
+
+ label LABEL_RC10_UPDATE;
+ // dynamic content here
+ label LABEL_RC10_END;
+ endform;
+
+ form
+ formid = RC11_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC11_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC11_FORM);
+
+ label LABEL_RC11_UPDATE;
+ // dynamic content here
+ label LABEL_RC11_END;
+ endform;
+
+ form
+ formid = RC12_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC12_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC12_FORM);
+
+ label LABEL_RC12_UPDATE;
+ // dynamic content here
+ label LABEL_RC12_END;
+ endform;
+
+ form
+ formid = RC13_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC13_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC13_FORM);
+
+ label LABEL_RC13_UPDATE;
+ // dynamic content here
+ label LABEL_RC13_END;
+ endform;
+
+ form
+ formid = RC14_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC14_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC14_FORM);
+
+ label LABEL_RC14_UPDATE;
+ // dynamic content here
+ label LABEL_RC14_END;
+ endform;
+
+ form
+ formid = RC15_FORM_ID,
+ title = STRING_TOKEN(STR_PCIE_RC15_FORM);
+
+ subtitle text = STRING_TOKEN(STR_PCIE_RC15_FORM);
+
+ label LABEL_RC15_UPDATE;
+ // dynamic content here
+ label LABEL_RC15_END;
+ endform;
+
+endformset;
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.c b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.c
new file mode 100644
index 000000000000..bb4c1863b54b
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcie.c
@@ -0,0 +1,436 @@
+/** @file
+
+ Pcie board specific driver to handle asserting PERST signal to Endpoint
+ card and parsing NVPARAM board settings for bifurcation programming.
+
+ PERST asserting is via group of GPIO pins to CPLD as Platform Specification.
+
+ NVPARAM board settings is spec-ed within Firmware Interface Requirement.
+ Bifuration devmap is programmed before at SCP following the rule
+
+ Root Complex Type-A devmap settings (RP == Root Port)
+ -----------------------------------------
+ | RP0 | RP1 | RP2 | RP3 | Devmap |
+ | (x16) | (x4) | (x8) | (x4) | (output) |
+ -------------------------------------------
+ | Y | N | N | N | 0 |
+ | Y | N | Y | N | 1 |
+ | Y | N | Y | Y | 2 |
+ | Y | Y | Y | Y | 3 |
+ -----------------------------------------
+
+ Root Complex Type-B LO (aka RCBxA) devmap settings (RP == Root Port)
+ ----------------------------------------
+ | RP0 | RP1 | RP2 | RP3 | Devmap |
+ | (x8) | (x2) | (x4) | (x3) | (output) |
+ ----------------------------------------
+ | Y | N | N | N | 0 |
+ | Y | N | Y | N | 1 |
+ | Y | N | Y | Y | 2 |
+ | Y | Y | Y | Y | 3 |
+ ----------------------------------------
+
+ Root Complex Type-B LO (aka RCBxB) devmap settings (RP == Root Port)
+ ----------------------------------------
+ | RP4 | RP5 | RP6 | RP7 | Devmap |
+ | (x8) | (x2) | (x4) | (x3) | (output) |
+ ----------------------------------------
+ | Y | N | N | N | 0 |
+ | Y | N | Y | N | 1 |
+ | Y | N | Y | Y | 2 |
+ | Y | Y | Y | Y | 3 |
+ ----------------------------------------
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/PlatformInfoHobGuid.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/GpioLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/NVParamLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <NVParamDef.h>
+#include <Platform/Ac01.h>
+#include <PlatformInfoHob.h>
+
+#include "BoardPcie.h"
+#include "BoardPcieVfr.h"
+
+#ifndef BIT
+#define BIT(nr) (1 << (nr))
+#endif
+
+#define RCA_MAX_PERST_GROUPVAL 62
+#define RCB_MAX_PERST_GROUPVAL 46
+
+extern CHAR16 gPcieVarstoreName[];
+extern EFI_GUID gPcieFormSetGuid;
+
+VOID
+EFIAPI
+BoardPcieLoadPreset (
+ IN AC01_RC *RC
RootComplex (search/replace globally).

+ )
+{
+ UINT32 Nv;
Nv what? Even expanded to Non-volatile, this name doesn't describe
what this variable holds. Please use a more descriptive name.

+ INTN NvParam;
+ INTN Ret;
+ INTN Index;
+
+ // Load default value
+ for (Index = 0; Index < MAX_PCIE_B; Index++) {
+ RC->PresetGen3[Index] = PRESET_INVALID;
+ RC->PresetGen4[Index] = PRESET_INVALID;
+ }
+
+ // Load override value
+ if (RC->Socket == 0) {
+ if (RC->Type == RCA) {
+ if (RC->ID < MAX_RCA) {
+ NvParam = NV_SI_RO_BOARD_S0_RCA0_TXRX_G3PRESET + RC->ID * NV_PARAM_ENTRYSIZE;
+ } else {
+ NvParam = NV_SI_RO_BOARD_S0_RCA4_TXRX_G3PRESET + (RC->ID - MAX_RCA) * NV_PARAM_ENTRYSIZE;
+ }
+ } else {
+ //
+ // There're two NVParam entries per RCB
+ //
+ NvParam = NV_SI_RO_BOARD_S0_RCB0A_TXRX_G3PRESET + (RC->ID - MAX_RCA) * (NV_PARAM_ENTRYSIZE * 2);
+ }
+ } else if (RC->Type == RCA) {
+ if (RC->ID < MAX_RCA) {
+ NvParam = NV_SI_RO_BOARD_S1_RCA2_TXRX_G3PRESET + (RC->ID - 2) * NV_PARAM_ENTRYSIZE;
+ } else {
+ NvParam = NV_SI_RO_BOARD_S1_RCA4_TXRX_G3PRESET + (RC->ID - MAX_RCA) * NV_PARAM_ENTRYSIZE;
+ }
+ } else {
+ //
+ // There're two NVParam entries per RCB
+ //
+ NvParam = NV_SI_RO_BOARD_S1_RCB0A_TXRX_G3PRESET + (RC->ID - MAX_RCA) * (NV_PARAM_ENTRYSIZE * 2);
+ }
This 2-level nested conditional serving only to assign a value to
NvParam should be a helpfully named helper function.

+
+ Ret = NVParamGet ((NVPARAM)NvParam, NV_PERM_ALL, &Nv);
+ if (Ret == EFI_SUCCESS) {
+ for (Index = 0; Index < MAX_PCIE_A; Index++) {
+ RC->PresetGen3[Index] = (Nv >> (Index * BITS_PER_BYTE)) & BYTE_MASK;
+ }
+ }
+
+ if (RC->Type == RCB) {
+ NvParam += NV_PARAM_ENTRYSIZE;
+ Ret = NVParamGet ((NVPARAM)NvParam, NV_PERM_ALL, &Nv);
+ if (Ret == EFI_SUCCESS) {
+ for (Index = MAX_PCIE_A; Index < MAX_PCIE; Index++) {
+ RC->PresetGen3[Index] = (Nv >> ((Index - MAX_PCIE_A) * BITS_PER_BYTE)) & BYTE_MASK;
+ }
+ }
+ }
+
+ if (RC->Socket == 0) {
+ if (RC->Type == RCA) {
+ if (RC->ID < MAX_RCA) {
+ NvParam = NV_SI_RO_BOARD_S0_RCA0_TXRX_G4PRESET + RC->ID * NV_PARAM_ENTRYSIZE;
+ } else {
+ NvParam = NV_SI_RO_BOARD_S0_RCA4_TXRX_G4PRESET + (RC->ID - MAX_RCA) * NV_PARAM_ENTRYSIZE;
+ }
+ } else {
+ //
+ // There're two NVParam entries per RCB
+ //
+ NvParam = NV_SI_RO_BOARD_S0_RCB0A_TXRX_G4PRESET + (RC->ID - MAX_RCA) * (NV_PARAM_ENTRYSIZE * 2);
+ }
+ } else if (RC->Type == RCA) {
+ if (RC->ID < MAX_RCA) {
+ NvParam = NV_SI_RO_BOARD_S1_RCA2_TXRX_G4PRESET + (RC->ID - 2) * NV_PARAM_ENTRYSIZE;
+ } else {
+ NvParam = NV_SI_RO_BOARD_S1_RCA4_TXRX_G4PRESET + (RC->ID - MAX_RCA) * NV_PARAM_ENTRYSIZE;
+ }
+ } else {
+ //
+ // There're two NVParam entries per RCB
+ //
+ NvParam = NV_SI_RO_BOARD_S1_RCB0A_TXRX_G4PRESET + (RC->ID - MAX_RCA) * (NV_PARAM_ENTRYSIZE * 2);
+ }
This 2-level nested conditional serving only to assign a value to
NvParam should be a helpfully named helper function.

+
+ Ret = NVParamGet ((NVPARAM)NvParam, NV_PERM_ALL, &Nv);
+ if (Ret == EFI_SUCCESS) {
+ for (Index = 0; Index < MAX_PCIE_A; Index++) {
+ RC->PresetGen4[Index] = (Nv >> (Index * BITS_PER_BYTE)) & BYTE_MASK;
+ }
+ }
+
+ if (RC->Type == RCB) {
+ NvParam += NV_PARAM_ENTRYSIZE;
+ Ret = NVParamGet ((NVPARAM)NvParam, NV_PERM_ALL, &Nv);
+ if (Ret == EFI_SUCCESS) {
+ for (Index = MAX_PCIE_A; Index < MAX_PCIE; Index++) {
+ RC->PresetGen4[Index] = (Nv >> ((Index - MAX_PCIE_A) * BITS_PER_BYTE)) & BYTE_MASK;
+ }
+ }
+ }
+}
+
+/**
+ Parse platform Root Complex information.
+
+ @param[out] RC Root Complex instance to store the platform information.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval Others An error occurred.
+**/
+EFI_STATUS
+EFIAPI
+BoardPcieParseRCParams (
+ OUT AC01_RC *RC
+ )
+{
+ UINT32 Efuse;
EFuse would be better coding style conformance.

+ PLATFORM_INFO_HOB *PlatformHob;
+ UINT8 PlatRCId;
+ EFI_STATUS Status;
+ VOID *Hob;
+ UINTN BufferSize;
+ VARSTORE_DATA VarStoreConfig = {
+ .RCStatus = {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE},
+ .RCBifurcationLow = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ .RCBifurcationHigh = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ .SmmuPmu = 0
+ };
+
+ DEBUG ((DEBUG_INFO, "%a - Socket%d RC%d\n", __FUNCTION__, RC->Socket, RC->ID));
+
+ PlatRCId = RC->Socket * AC01_MAX_RCS_PER_SOCKET + RC->ID;
+ // Get RC activation status
+ BufferSize = sizeof (VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ gPcieVarstoreName,
+ &gPcieFormSetGuid,
+ NULL,
+ &BufferSize,
+ &VarStoreConfig
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "%a - Failed to read PCIE variable data from config store.\n", __FUNCTION__));
+ }
+
+ RC->Active = VarStoreConfig.RCStatus[PlatRCId];
+ RC->DevMapLow = VarStoreConfig.RCBifurcationLow[PlatRCId];
+ RC->DevMapHigh = VarStoreConfig.RCBifurcationHigh[PlatRCId];
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a - Socket%d RC%d is %s\n",
+ __FUNCTION__,
+ RC->Socket,
+ RC->ID,
+ (RC->Active) ? "ACTIVE" : "INACTIVE"
+ ));
+
+ if (!IsSlaveSocketActive () && RC->Socket == 1) {
+ RC->Active = FALSE;
+ }
+
+ if (RC->Active) {
+ //
+ // Consolidate with E-fuse
+ //
+ Efuse = 0;
+ Hob = GetFirstGuidHob (&gPlatformHobGuid);
+ if (Hob != NULL) {
+ PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
+ Efuse = PlatformHob->RcDisableMask[0] | (PlatformHob->RcDisableMask[1] << AC01_MAX_RCS_PER_SOCKET);
Would that test be better as a helpfully named macro?

+ DEBUG ((
+ DEBUG_INFO,
+ "RcDisableMask[0]: 0x%x [1]: 0x%x\n",
+ PlatformHob->RcDisableMask[0],
+ PlatformHob->RcDisableMask[1]
+ ));
+
+ // Update errata flags for Ampere Altra
+ if ((PlatformHob->ScuProductId[0] & 0xff) == 0x01) {
+ if (PlatformHob->AHBCId[0] == 0x20100
+ || PlatformHob->AHBCId[0] == 0x21100
+ || (IsSlaveSocketActive ()
+ && (PlatformHob->AHBCId[1] == 0x20100
+ || PlatformHob->AHBCId[1] == 0x21100)))
+ {
+ RC->Flags |= PCIE_ERRATA_SPEED1;
+ DEBUG ((DEBUG_INFO, "RC[%d]: Flags 0x%x\n", RC->ID, RC->Flags));
+ }
+ }
+ }
+
+ RC->Active = (RC->Active && !(Efuse & BIT (PlatRCId))) ? TRUE : FALSE;
+ }
+
+ /* Load Gen3/Gen4 preset */
+ BoardPcieLoadPreset (RC);
+ BoardPcieGetLaneAllocation (RC);
+ BoardPcieSetupDevmap (RC);
+ BoardPcieGetSpeed (RC);
+
+ return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+BoardPcieReleaseAllPerst (
+ IN UINT8 SocketId
+ )
+{
+ UINT32 GpioIndex, GpioPin;
+
+ // Write 1 to all GPIO[16..21] to release all PERST
+ GpioPin = GPIO_DWAPB_PINS_PER_SOCKET * SocketId + 16;
+ for (GpioIndex = 0; GpioIndex < 6; GpioIndex++) {
+ GpioModeConfig (GpioPin + GpioIndex, GPIO_CONFIG_OUT_HI);
+ }
+}
+
+/**
+ Assert PERST of input PCIe controller
+
+ @param[in] RC Root Complex instance.
+ @param[in] PcieIndex PCIe controller index of input Root Complex.
+ @param[in] Bifurcation Bifurcation mode of input Root Complex.
+ @param[in] IsPullToHigh Target status for the PERST.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval Others An error occurred.
+**/
+EFI_STATUS
+EFIAPI
+BoardPcieAssertPerst (
+ IN AC01_RC *RC,
+ IN UINT32 PcieIndex,
+ IN UINT8 Bifurcation,
+ IN BOOLEAN IsPullToHigh
+ )
+{
+ UINT32 GpioGroupVal, Val, GpioIndex, GpioPin;
+
+ if (!IsPullToHigh) { // Pull PERST to Low
I agree with the logic of placing that comment on that line, but I
think readability would be improved by placing it on the next line
with a blanke line before the next code line.

+ if (RC->Type == RCA) { // RCA: RC->ID: 0->3 ; PcieIndex: 0->3
+ GpioGroupVal = RCA_MAX_PERST_GROUPVAL - RC->ID * MAX_PCIE_A - PcieIndex;
+ } else { // RCB: RC->ID: 4->7 ; PcieIndex: 0->7
+ GpioGroupVal = RCB_MAX_PERST_GROUPVAL - (RC->ID - MAX_RCA) * MAX_PCIE_B - PcieIndex;
+ }
+
+ // Update the value of GPIO[16..21]. Corresponding PERST line will be decoded by CPLD.
+ GpioPin = GPIO_DWAPB_PINS_PER_SOCKET * RC->Socket + 16;
+ for (GpioIndex = 0; GpioIndex < 6; GpioIndex++) {
+ Val = (GpioGroupVal & 0x3F) & (1 << GpioIndex);
+ if (Val == 0) {
+ GpioModeConfig (GpioPin + GpioIndex, GPIO_CONFIG_OUT_LOW);
+ } else {
+ GpioModeConfig (GpioPin + GpioIndex, GPIO_CONFIG_OUT_HI);
+ }
+ }
+
+ // Keep reset as low as 100 ms as specification
+ MicroSecondDelay (100 * 1000);
+ } else { // Pull PERST to High
Same comment as above.

+ BoardPcieReleaseAllPerst (RC->Socket);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Override the segment number for a root complex with a board specific number.
+
+ @param[in] RC Root Complex instance with properties.
+ @param[out] SegmentNumber Return segment number.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval Others An error occurred.
+**/
+EFI_STATUS
+EFIAPI
+BoardPcieGetRCSegmentNumber (
+ IN AC01_RC *RC,
+ OUT UINTN *SegmentNumber
+ )
+{
+ if (RC->Socket == 0) {
+ if (RC->Type == RCA) {
+ switch (RC->ID) {
+ case RCA0:
+ *SegmentNumber = 12;
+ break;
+
+ case RCA1:
+ *SegmentNumber = 13;
+ break;
+
+ case RCA2:
+ *SegmentNumber = 1;
+ break;
+
+ case RCA3:
+ *SegmentNumber = 0;
+ break;
+
+ default:
+ *SegmentNumber = 16;
+ }
+ } else { /* Socket0, CCIX: RCA0 and RCA1 */
+ *SegmentNumber = RC->ID - 2;
This is quite convoluted.

+ }
+ } else { /* Socket1, CCIX: RCA0 and RCA1 */
+ if (RC->ID == RCA0 || RC->ID == RCA1) {
+ *SegmentNumber = 16;
+ } else {
+ *SegmentNumber = 4 + RC->ID;
As is this.
I get that this is just "the way it is", but could there be some
helpful comment about what's going on here? I can't even tell if the
arithmetic is correct with what's here.

+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if SMM PMU enabled in board screen.
+
+ @param[out] IsSmmuPmuEnabled TRUE if the SMMU PMU enabled, otherwise FALSE.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval Others An error occurred.
+**/
+EFI_STATUS
+EFIAPI
+BoardPcieCheckSmmuPmuEnabled (
+ OUT BOOLEAN *IsSmmuPmuEnabled
+ )
+{
+ VARSTORE_DATA VarStoreConfig;
+ UINTN BufferSize;
+ EFI_STATUS Status;
+
+ *IsSmmuPmuEnabled = FALSE;
+
+ // Get Buffer Storage data from EFI variable
+ BufferSize = sizeof (VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ gPcieVarstoreName,
+ &gPcieFormSetGuid,
+ NULL,
+ &BufferSize,
+ &VarStoreConfig
+ );
+ if (!EFI_ERROR (Status)) {
+ *IsSmmuPmuEnabled = VarStoreConfig.SmmuPmu;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieCommon.c b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieCommon.c
new file mode 100644
index 000000000000..05fff88ba601
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieCommon.c
@@ -0,0 +1,329 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/NVParamLib.h>
+#include <Library/SystemFirmwareInterfaceLib.h>
+#include <NVParamDef.h>
+
+#include "BoardPcie.h"
+
+/* Host bridge registers */
+#define RCA_DEV_MAP_OFFSET 0x0
+#define RCB_DEV_MAP_OFFSET 0x4
+
+/* RCA_DEV_MAP_OFFSET */
+#define RCA_DEV_MAP_SET(dst, src) \
+ (((dst) & ~0x7) | (((UINT32)(src)) & 0x7))
+
+/* RCB_DEV_MAP_OFFSET */
+#define RCB_DEV_MAP_LOW_SET(dst, src) \
+ (((dst) & ~0x7) | (((UINT32)(src)) & 0x7))
+#define RCB_DEV_MAP_HIGH_SET(dst, src) \
+ (((dst) & ~0x70) | (((UINT32)(src) << 4) & 0x70))
+
+#define PCIE_GET_MAX_WIDTH(Pcie, Max) \
+ !((Pcie).MaxWidth) ? (Max) : MIN((Pcie).MaxWidth, (Max))
+
+BOOLEAN
+IsEmptyRC (
+ IN AC01_RC *RC
+ )
+{
+ INTN Idx;
+
+ for (Idx = PCIE_0; Idx < MAX_PCIE; Idx++) {
+ if (RC->Pcie[Idx].Active) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+BoardPcieSetRCBifurcation (
+ IN AC01_RC *RC,
+ IN UINT8 RPStart,
+ IN UINT8 DevMap
+ )
+{
+ UINT8 MaxWidth;
+
+ if (RPStart != PCIE_0 && RPStart != PCIE_4) {
+ return;
+ }
+
+ if (RC->Type != RCB && RPStart == PCIE_4) {
+ return;
+ }
+
+ if (RC->Type == RCA && RC->Pcie[RPStart].MaxWidth == LNKW_X16) {
+ RC->Pcie[RPStart + 1].MaxWidth = LNKW_X4;
+ RC->Pcie[RPStart + 2].MaxWidth = LNKW_X8;
+ RC->Pcie[RPStart + 3].MaxWidth = LNKW_X4;
+ }
+
+ if (RC->Type == RCB && RC->Pcie[RPStart].MaxWidth == LNKW_X8) {
+ RC->Pcie[RPStart + 1].MaxWidth = LNKW_X2;
+ RC->Pcie[RPStart + 2].MaxWidth = LNKW_X4;
+ RC->Pcie[RPStart + 3].MaxWidth = LNKW_X2;
+ }
+
+ switch (DevMap) {
+ case DEV_MAP_2_CONTROLLERS:
+ MaxWidth = (RC->Type == RCA) ? LNKW_X8 : LNKW_X4;
+ RC->Pcie[RPStart].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart], MaxWidth);
+ RC->Pcie[RPStart + 1].Active = FALSE;
+ RC->Pcie[RPStart + 2].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart + 2], MaxWidth);
+ RC->Pcie[RPStart + 2].Active = TRUE;
+ RC->Pcie[RPStart + 3].Active = FALSE;
+ break;
+
+ case DEV_MAP_3_CONTROLLERS:
+ MaxWidth = (RC->Type == RCA) ? LNKW_X8 : LNKW_X4;
+ RC->Pcie[RPStart].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart], MaxWidth);
+ RC->Pcie[RPStart + 1].Active = FALSE;
+ MaxWidth = (RC->Type == RCA) ? LNKW_X4 : LNKW_X2;
+ RC->Pcie[RPStart + 2].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart + 2], MaxWidth);
+ RC->Pcie[RPStart + 2].Active = TRUE;
+ RC->Pcie[RPStart + 3].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart + 3], MaxWidth);
+ RC->Pcie[RPStart + 3].Active = TRUE;
+ break;
+
+ case DEV_MAP_4_CONTROLLERS:
+ MaxWidth = (RC->Type == RCA) ? LNKW_X4 : LNKW_X2;
+ RC->Pcie[RPStart].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart], MaxWidth);
+ RC->Pcie[RPStart + 1].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart + 1], MaxWidth);
+ RC->Pcie[RPStart + 1].Active = TRUE;
+ RC->Pcie[RPStart + 2].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart + 2], MaxWidth);
+ RC->Pcie[RPStart + 2].Active = TRUE;
+ RC->Pcie[RPStart + 3].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart + 3], MaxWidth);
+ RC->Pcie[RPStart + 3].Active = TRUE;
+ break;
+
+ case DEV_MAP_1_CONTROLLER:
+ default:
+ MaxWidth = (RC->Type == RCA) ? LNKW_X16 : LNKW_X8;
+ RC->Pcie[RPStart].MaxWidth = PCIE_GET_MAX_WIDTH (RC->Pcie[RPStart], MaxWidth);
+ RC->Pcie[RPStart + 1].Active = FALSE;
+ RC->Pcie[RPStart + 2].Active = FALSE;
+ RC->Pcie[RPStart + 3].Active = FALSE;
+ break;
+ }
+}
+
+VOID
+BoardPcieGetLaneAllocation (
+ IN AC01_RC *RC
+ )
+{
+ INTN RPIndex, Ret;
+ UINT32 Nv, Width;
Better name for Nv.

+ NVPARAM NvParam;
+
+ // Retrieve lane allocation and capabilities for each controller
+ if (RC->Type == RCA) {
+ NvParam = ((RC->Socket == 0) ? NV_SI_RO_BOARD_S0_RCA0_CFG : NV_SI_RO_BOARD_S1_RCA0_CFG) +
+ RC->ID * NV_PARAM_ENTRYSIZE;
Ternaries are useful where the help keep the code neat and tidy. This way.
they're basically obfuscating.

NvParam = (RC->Socket == 0) ? NV_SI_RO_BOARD_S0_RCA0_CFG : NV_SI_RO_BOARD_S1_RCA0_CFG;
NvParam += RC->ID * NV_PARAM_ENTRYSIZE;

This also highlights how the enumeration names aren't descriptive
enough. I can't tell what these are referring to.

+ } else {
+ //
+ // There're two NVParam entries per RCB
+ //
+ NvParam = ((RC->Socket == 0) ? NV_SI_RO_BOARD_S0_RCB0_LO_CFG : NV_SI_RO_BOARD_S1_RCB0_LO_CFG) +
+ (RC->ID - MAX_RCA) * (NV_PARAM_ENTRYSIZE * 2);
Same as above.

+ }
+
+ Ret = NVParamGet (NvParam, NV_PERM_ALL, &Nv);
+ Nv = (Ret != EFI_SUCCESS) ? 0 : Nv;
if (EFI_ERROR (Ret)) {
Nv = 0;
}

+
+ for (RPIndex = 0; RPIndex < MAX_PCIE_A; RPIndex++) {
+ Width = (Nv >> (RPIndex * BITS_PER_BYTE)) & BYTE_MASK;
+ switch (Width) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ RC->Pcie[RPIndex].MaxWidth = 1 << Width;
+ RC->Pcie[RPIndex].MaxGen = SPEED_GEN3;
+ RC->Pcie[RPIndex].Active = TRUE;
+ break;
+
+ case 0:
+ default:
+ RC->Pcie[RPIndex].MaxWidth = LNKW_NONE;
+ RC->Pcie[RPIndex].MaxGen = SPEED_NONE;
+ RC->Pcie[RPIndex].Active = FALSE;
+ break;
+ }
+ }
+
+ if (RC->Type == RCB) {
+ NvParam += NV_PARAM_ENTRYSIZE;
+ Ret = NVParamGet (NvParam, NV_PERM_ALL, &Nv);
+ Nv = (Ret != EFI_SUCCESS) ? 0 : Nv;
+
+ for (RPIndex = MAX_PCIE_A; RPIndex < MAX_PCIE; RPIndex++) {
+ Width = (Nv >> ((RPIndex - MAX_PCIE_A) * BITS_PER_BYTE)) & BYTE_MASK;
+ switch (Width) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ RC->Pcie[RPIndex].MaxWidth = 1 << Width;
+ RC->Pcie[RPIndex].MaxGen = SPEED_GEN3;
+ RC->Pcie[RPIndex].Active = TRUE;
+ break;
+
+ case 0:
+ default:
+ RC->Pcie[RPIndex].MaxWidth = LNKW_NONE;
+ RC->Pcie[RPIndex].MaxGen = SPEED_NONE;
+ RC->Pcie[RPIndex].Active = FALSE;
+ break;
+ }
+ }
+ }
+
+ // Do not proceed if no Root Port enabled
+ if (IsEmptyRC (RC)) {
+ RC->Active = FALSE;
+ }
+}
+
+VOID
+BoardPcieSetupDevmap (
+ IN AC01_RC *RC
+ )
+{
+ UINT32 Val;
+
+ if (RC->Pcie[PCIE_0].Active
+ && RC->Pcie[PCIE_1].Active
+ && RC->Pcie[PCIE_2].Active
+ && RC->Pcie[PCIE_3].Active)
+ {
+ RC->DefaultDevMapLow = DEV_MAP_4_CONTROLLERS;
+ } else if (RC->Pcie[PCIE_0].Active
+ && RC->Pcie[PCIE_2].Active
+ && RC->Pcie[PCIE_3].Active)
+ {
+ RC->DefaultDevMapLow = DEV_MAP_3_CONTROLLERS;
+ } else if (RC->Pcie[PCIE_0].Active
+ && RC->Pcie[PCIE_2].Active)
+ {
+ RC->DefaultDevMapLow = DEV_MAP_2_CONTROLLERS;
+ } else {
+ RC->DefaultDevMapLow = DEV_MAP_1_CONTROLLER;
+ }
+
+ if (RC->Pcie[PCIE_4].Active
+ && RC->Pcie[PCIE_5].Active
+ && RC->Pcie[PCIE_6].Active
+ && RC->Pcie[PCIE_7].Active)
+ {
+ RC->DefaultDevMapHigh = DEV_MAP_4_CONTROLLERS;
+ } else if (RC->Pcie[PCIE_4].Active
+ && RC->Pcie[PCIE_6].Active
+ && RC->Pcie[PCIE_7].Active)
+ {
+ RC->DefaultDevMapHigh = DEV_MAP_3_CONTROLLERS;
+ } else if (RC->Pcie[PCIE_4].Active
+ && RC->Pcie[PCIE_6].Active)
+ {
+ RC->DefaultDevMapHigh = DEV_MAP_2_CONTROLLERS;
+ } else {
+ RC->DefaultDevMapHigh = DEV_MAP_1_CONTROLLER;
+ }
+
+ if (RC->DevMapLow == DEV_MAP_1_CONTROLLER) {
+ RC->DevMapLow = RC->DefaultDevMapLow;
+ }
+
+ if (RC->Type == RCB && RC->DevMapHigh == DEV_MAP_1_CONTROLLER) {
+ RC->DevMapHigh = RC->DefaultDevMapHigh;
+ }
+
+ BoardPcieSetRCBifurcation (RC, PCIE_0, RC->DevMapLow);
+ if (RC->Type == RCB) {
+ BoardPcieSetRCBifurcation (RC, PCIE_4, RC->DevMapHigh);
+ }
+
+ if (RC->Active) {
+ if (RC->Type == RCA) {
+ if (!EFI_ERROR (MailboxMsgRegisterRead (RC->Socket, RC->HBAddr + RCA_DEV_MAP_OFFSET, &Val))) {
+ Val = RCA_DEV_MAP_SET (Val, RC->DevMapLow);
+ MailboxMsgRegisterWrite (RC->Socket, RC->HBAddr + RCA_DEV_MAP_OFFSET, Val);
+ }
+ } else {
+ if (!EFI_ERROR (MailboxMsgRegisterRead (RC->Socket, RC->HBAddr + RCB_DEV_MAP_OFFSET, &Val))) {
+ Val = RCB_DEV_MAP_LOW_SET (Val, RC->DevMapLow);
+ Val = RCB_DEV_MAP_HIGH_SET (Val, RC->DevMapHigh);
+ MailboxMsgRegisterWrite (RC->Socket, RC->HBAddr + RCB_DEV_MAP_OFFSET, Val);
+ }
+ }
+ }
+}
+
+VOID
+BoardPcieGetSpeed (
+ IN AC01_RC *RC
+ )
+{
+ UINT8 MaxGenTbl[MAX_PCIE_A] = { SPEED_GEN4, SPEED_GEN4, SPEED_GEN4, SPEED_GEN4 }; // Bifurcation 0: RCA x16 / RCB x8
+ UINT8 MaxGenTblX8X4X4[MAX_PCIE_A] = { SPEED_GEN4, SPEED_GEN4, SPEED_GEN1, SPEED_GEN1 }; // Bifurcation 2: x8 x4 x4 (PCIE_ERRATA_SPEED1)
+ UINT8 MaxGenTblX4X4X4X4[MAX_PCIE_A] = { SPEED_GEN1, SPEED_GEN1, SPEED_GEN1, SPEED_GEN1 }; // Bifurcation 3: x4 x4 x4 x4 (PCIE_ERRATA_SPEED1)
Tbl -> Table.
Please drop the Xs from the variable names.

+ UINT8 MaxGenTblRCB[MAX_PCIE_A] = { SPEED_GEN1, SPEED_GEN1, SPEED_GEN1, SPEED_GEN1 }; // RCB PCIE_ERRATA_SPEED1
RootComplexB (?);


+ INTN RPIdx;
RootPortIdx.

+ UINT8 *MaxGen;
+
+ ASSERT (MAX_PCIE_A == 4);
+ ASSERT (MAX_PCIE == 8);
+
+ //
+ // Due to hardware errata, for A0/A1*
+ // RCB is limited to Gen1 speed.
+ // RCA x16, x8 port supports up to Gen4,
+ // RCA x4 port only supports Gen1.
+ //
+ MaxGen = MaxGenTbl;
+ if (RC->Type == RCB) {
+ if (RC->Flags & PCIE_ERRATA_SPEED1) {
+ MaxGen = MaxGenTblRCB;
+ }
+ } else {
+ switch (RC->DevMapLow) {
+ case DEV_MAP_3_CONTROLLERS: /* x8 x4 x4 */
+ if (RC->Flags & PCIE_ERRATA_SPEED1) {
+ MaxGen = MaxGenTblX8X4X4;
+ }
+ break;
+
+ case DEV_MAP_4_CONTROLLERS: /* X4 x4 x4 x4 */
+ if (RC->Flags & PCIE_ERRATA_SPEED1) {
+ MaxGen = MaxGenTblX4X4X4X4;
+ }
+ break;
+
+ case DEV_MAP_2_CONTROLLERS: /* x8 x8 */
+ default:
+ break;
+ }
+ }
+
+ for (RPIdx = 0; RPIdx < MAX_PCIE_A; RPIdx++) {
+ RC->Pcie[RPIdx].MaxGen = RC->Pcie[RPIdx].Active ? MaxGen[RPIdx] : SPEED_NONE;
+ }
+
+ if (RC->Type == RCB) {
+ for (RPIdx = MAX_PCIE_A; RPIdx < MAX_PCIE; RPIdx++) {
+ RC->Pcie[RPIdx].MaxGen = RC->Pcie[RPIdx].Active ?
+ MaxGen[RPIdx - MAX_PCIE_A] : SPEED_NONE;
+ }
+ }
+}
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.c b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.c
new file mode 100644
index 000000000000..eed53c6abed7
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.c
@@ -0,0 +1,1244 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/PlatformInfoHobGuid.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NVParamLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <NVParamDef.h>
+#include <Platform/Ac01.h>
+#include <PlatformInfoHob.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigKeyword.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+
+#include "BoardPcie.h"
+#include "BoardPcieScreen.h"
+
+#ifndef BIT
+#define BIT(nr) (1 << (nr))
+#endif
+
+BOOLEAN mReadOnlyStrongOrdering;
+CHAR16 mPcieNvparamVarstoreName[] = NVPARAM_VARSTORE_NAME;
+CHAR16 gPcieVarstoreName[] = VARSTORE_NAME;
+EFI_GUID gPcieFormSetGuid = FORM_SET_GUID;
+
+SCREEN_PRIVATE_DATA *mPrivateData = NULL;
+
+AC01_RC RCList[AC01_MAX_PCIE_ROOT_COMPLEX];
mRootComplexList

+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+**/
STATIC (address as appropriate through file)

+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ SCREEN_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ UINTN Size;
+ CHAR16 *StrPointer;
+ BOOLEAN AllocatedRequest;
+ UINT8 *VarStoreConfig;
+ UINT32 Value;
Number of variables suggests this function should be split up.

+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Request == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ PrivateData = SCREEN_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (HiiIsConfigHdrMatch (Request, &gPcieFormSetGuid, mPcieNvparamVarstoreName)) {
+ VarStoreConfig = (UINT8 *)&PrivateData->NVParamVarStoreConfig;
+ ASSERT (VarStoreConfig != NULL);
+
+ Status = NVParamGet (
+ NV_SI_MESH_S0_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (Value != 0) {
+ PrivateData->NVParamVarStoreConfig.PcieStrongOrdering = TRUE;
+ }
+
+ Status = NVParamGet (
+ NV_SI_MESH_S1_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &Value
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (Value != 0) {
+ PrivateData->NVParamVarStoreConfig.PcieStrongOrdering = TRUE;
+ }
+
+ BufferSize = sizeof (NVPARAM_VARSTORE_DATA);
+
+ } else if (HiiIsConfigHdrMatch (Request, &gPcieFormSetGuid, gPcieVarstoreName)) {
+ VarStoreConfig = (UINT8 *)&PrivateData->VarStoreConfig;
+ ASSERT (VarStoreConfig != NULL);
+
+ //
+ // Get Buffer Storage data from EFI variable.
+ // Try to get the current setting from variable.
+ //
+ BufferSize = sizeof (VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ gPcieVarstoreName,
+ &gPcieFormSetGuid,
+ NULL,
+ &BufferSize,
+ VarStoreConfig
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Set Request to the unified request string.
+ //
+ ConfigRequest = Request;
+
+ //
+ // Check whether Request includes Request Element.
+ //
+ if (StrStr (Request, L"OFFSET") == NULL) {
+ //
+ // Check Request Element does exist in Request String
+ //
+ StrPointer = StrStr (Request, L"PATH");
+ if (StrPointer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (StrStr (StrPointer, L"&") == NULL) {
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ Size = (StrLen (Request) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (
+ ConfigRequest,
+ Size,
+ L"%s&OFFSET=0&WIDTH=%016LX",
+ Request,
+ (UINT64)BufferSize
+ );
+ }
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ VarStoreConfig,
+ BufferSize,
+ Results,
+ Progress
+ );
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ }
+
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ SCREEN_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ UINT8 *VarStoreConfig;
+ UINT32 Value;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = SCREEN_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+
+ if (HiiIsConfigHdrMatch (Configuration, &gPcieFormSetGuid, mPcieNvparamVarstoreName)) {
+ VarStoreConfig = (UINT8 *)&PrivateData->NVParamVarStoreConfig;
+ BufferSize = sizeof (NVPARAM_VARSTORE_DATA);
+ } else if (HiiIsConfigHdrMatch (Configuration, &gPcieFormSetGuid, gPcieVarstoreName)) {
+ BufferSize = sizeof (VARSTORE_DATA);
+ VarStoreConfig = (UINT8 *)&PrivateData->VarStoreConfig;
+ }
+ ASSERT (VarStoreConfig != NULL);
+
+ //
+ // Check if configuring Name/Value storage
+ //
+ if (StrStr (Configuration, L"OFFSET") == NULL) {
+ //
+ // Don't have any Name/Value storage names
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *)VarStoreConfig,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check routing data in <ConfigHdr>.
+ //
+ if (HiiIsConfigHdrMatch (Configuration, &gPcieFormSetGuid, mPcieNvparamVarstoreName)) {
+ Value = PrivateData->NVParamVarStoreConfig.PcieStrongOrdering ? STRONG_ORDERING_DEFAULT_NVPARAM_VALUE : 0;
Break long line after question mark.

+
+ if (!mReadOnlyStrongOrdering) {
+ //
+ // Update whole 16 RCs.
+ //
+ Status = NVParamSet (
+ NV_SI_MESH_S0_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // No need to check slave present
+ //
+ Status = NVParamSet (
+ NV_SI_MESH_S1_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ Value
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else if (HiiIsConfigHdrMatch (Configuration, &gPcieFormSetGuid, gPcieVarstoreName)) {
+ //
+ // Store Buffer Storage back to variable
+ //
+ Status = gRT->SetVariable (
+ gPcieVarstoreName,
+ &gPcieFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (VARSTORE_DATA),
+ (VARSTORE_DATA *)VarStoreConfig
+ );
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+**/
+EFI_STATUS
+EFIAPI
+DriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ SCREEN_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+
+ if (((Value == NULL) &&
+ (Action != EFI_BROWSER_ACTION_FORM_OPEN) &&
+ (Action != EFI_BROWSER_ACTION_FORM_CLOSE)) ||
+ (ActionRequest == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = SCREEN_PRIVATE_FROM_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+ switch (Action) {
+ case EFI_BROWSER_ACTION_FORM_OPEN:
+ break;
+
+ case EFI_BROWSER_ACTION_FORM_CLOSE:
+ break;
+
+ case EFI_BROWSER_ACTION_DEFAULT_STANDARD:
+ case EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING:
+ if (QuestionId == 0x9000) {
Please assign #defines for question ids instead of live-coding them in
two places.

+ //
+ // SMMU PMU
+ //
+ Value->u32 = 0;
+ break;
+ }
+
+ if (QuestionId == 0x9001) {
+ //
+ // Strong Ordering
+ //
+ Value->u8 = STRONG_ORDERING_DEFAULT_OPTION_VALUE;
+ break;
+ }
+
+ switch ((QuestionId - 0x8002) % MAX_EDITABLE_ELEMENTS) {
+ case 0:
+ Value->u8 = PcieRCActiveDefaultSetting ((QuestionId - 0x8002) / MAX_EDITABLE_ELEMENTS, PrivateData);
+ break;
+
+ case 1:
+ Value->u8 = PcieRCDevMapLowDefaultSetting ((QuestionId - 0x8002) / MAX_EDITABLE_ELEMENTS, PrivateData);
+ break;
+
+ case 2:
+ Value->u8 = PcieRCDevMapHighDefaultSetting ((QuestionId - 0x8002) / MAX_EDITABLE_ELEMENTS, PrivateData);
+ break;
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_RETRIEVE:
+ case EFI_BROWSER_ACTION_CHANGING:
+ case EFI_BROWSER_ACTION_SUBMITTED:
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ This function return default settings for Dev Map LO.
+ @param RC Root Complex ID.
+ @param PrivateData Private data.
+
+ @retval Default dev settings.
+**/
+UINT8
+PcieRCDevMapLowDefaultSetting (
+ IN UINTN RCIndex,
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ )
+{
+ AC01_RC *RC = &RCList[RCIndex];
+
+ return RC->DefaultDevMapLow;
+}
+
+/**
+ This function return default settings for Dev Map HI.
+ @param RC Root Complex ID.
+ @param PrivateData Private data.
+
+ @retval Default dev settings.
+**/
+UINT8
+PcieRCDevMapHighDefaultSetting (
+ IN UINTN RCIndex,
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ )
+{
+ AC01_RC *RC = &RCList[RCIndex];
+
+ return RC->DefaultDevMapHigh;
+}
+
+BOOLEAN
+PcieRCActiveDefaultSetting (
+ IN UINTN RCIndex,
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ )
+{
+ PLATFORM_INFO_HOB *PlatformHob;
+ VOID *Hob;
+ UINT32 Efuse;
+
+ Hob = GetFirstGuidHob (&gPlatformHobGuid);
+ if (Hob != NULL) {
+ PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
+ Efuse = PlatformHob->RcDisableMask[0] | (PlatformHob->RcDisableMask[1] << AC01_MAX_RCS_PER_SOCKET);
+ return (!(Efuse & BIT (RCIndex))) ? TRUE : FALSE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function sets up the first elements of the form.
+ @param RC Root Complex ID.
+ @param PrivateData Private data.
+ @retval EFI_SUCCESS The form is set up successfully.
+**/
+EFI_STATUS
+PcieRCScreenSetup (
+ IN UINTN RCIndex,
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ )
+{
+ VOID *StartOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ VOID *OptionsOpCodeHandle;
+ VOID *OptionsHiOpCodeHandle;
+ CHAR16 Str[MAX_STRING_SIZE];
+ UINT16 DisabledStatusVarOffset;
+ UINT16 BifurLoVarOffset;
+ UINT16 BifurHiVarOffset;
+ UINT8 QuestionFlags, QuestionFlagsSubItem;
+ AC01_RC *RC;
An awful lot of variables for a single function...

+
+ RC = &RCList[RCIndex];
+
+ // Initialize the container for dynamic opcodes
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ // Create Hii Extend Label OpCode as the start opcode
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_RC0_UPDATE + 2 * RCIndex;
+
+ // Create Hii Extend Label OpCode as the end opcode
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_RC0_END + 2 * RCIndex;
+
+ // Create textbox to tell socket
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_SOCKET),
+ STRING_TOKEN (STR_PCIE_SOCKET_HELP),
+ HiiSetString (
+ PrivateData->HiiHandle,
+ 0,
+ (RC->Socket) ? L"1" : L"0",
+ NULL
+ )
+ );
+
+ // Create textbox to tell Root Complex type
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_RC_TYPE),
+ STRING_TOKEN (STR_PCIE_RC_TYPE_HELP),
+ HiiSetString (
+ PrivateData->HiiHandle,
+ 0,
+ (RC->Type == RCA) ? L"Root Complex Type-A" : L"Root Complex Type-B",
+ NULL
+ )
+ );
+
+ UnicodeSPrint (Str, sizeof (Str), L"Root Complex #%2d", RCIndex);
+
+ DisabledStatusVarOffset = (UINT16)RC0_STATUS_OFFSET +
+ sizeof (BOOLEAN) * RCIndex;
+ BifurLoVarOffset = (UINT16)RC0_BIFUR_LO_OFFSET +
+ sizeof (UINT8) * RCIndex;
+ BifurHiVarOffset = (UINT16)RC0_BIFUR_HI_OFFSET +
+ sizeof (UINT8) * RCIndex;
+
+ QuestionFlags = EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_CALLBACK;
+ if (IsEmptyRC (RC)
+ || (GetNumberOfActiveSockets () == 1 && RC->Socket == 1))
+ {
+ //
+ // Do not allow changing if none of Root Port underneath enabled
+ // or slave Root Complex on 1P system.
+ //
+ QuestionFlags |= EFI_IFR_FLAG_READ_ONLY;
+ }
+ // Create the RC disabled checkbox
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8002 + MAX_EDITABLE_ELEMENTS * RCIndex, // QuestionId (or "key")
+ VARSTORE_ID, // VarStoreId
+ DisabledStatusVarOffset, // VarOffset in Buffer Storage
+ HiiSetString (
+ PrivateData->HiiHandle,
+ 0,
+ Str,
+ NULL
+ ), // Prompt
+ STRING_TOKEN (STR_PCIE_RC_STATUS_HELP), // Help
+ QuestionFlags, // QuestionFlags
+ 0, // CheckBoxFlags
+ NULL // DefaultsOpCodeHandle
+ );
+
+ if (RC->Type == RCA) {
+ // Create Option OpCode to display bifurcation for RCA
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE0),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 0 // Devmap=0
+ );
+
+
+ if (RC->DefaultDevMapLow != 0) {
+ QuestionFlags |= EFI_IFR_FLAG_READ_ONLY;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE1),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 1 // Devmap=1
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE2),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 2 // Devmap=2
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE3),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 3 // Devmap=3
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8003 + MAX_EDITABLE_ELEMENTS * RCIndex, // Question ID (or call it "key")
+ VARSTORE_ID, // VarStore ID
+ BifurLoVarOffset, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PCIE_RCA_BIFUR), // Question prompt text
+ STRING_TOKEN (STR_PCIE_RCA_BIFUR_HELP), // Question help text
+ QuestionFlags, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+ } else {
+ // Create Option OpCode to display bifurcation for RCB-Lo
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE4),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 0 // Devmap=0
+ );
+
+ QuestionFlagsSubItem = QuestionFlags;
+ if (RC->DefaultDevMapLow != 0) {
+ QuestionFlagsSubItem |= EFI_IFR_FLAG_READ_ONLY;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE5),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 1 // Devmap=1
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE6),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 2 // Devmap=2
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE7),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 3 // Devmap=3
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8003 + MAX_EDITABLE_ELEMENTS * RCIndex, // Question ID (or call it "key")
+ VARSTORE_ID, // VarStore ID
+ BifurLoVarOffset, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PCIE_RCB_LO_BIFUR), // Question prompt text
+ STRING_TOKEN (STR_PCIE_RCB_LO_BIFUR_HELP), // Question help text
+ QuestionFlagsSubItem, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ // Create Option OpCode to display bifurcation for RCB-Hi
+ OptionsHiOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsHiOpCodeHandle != NULL);
+
+ QuestionFlagsSubItem = QuestionFlags;
+ if (RC->DefaultDevMapHigh != 0) {
+ QuestionFlagsSubItem |= EFI_IFR_FLAG_READ_ONLY;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsHiOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE4),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 0 // Devmap=0
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsHiOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE5),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 1 // Devmap=1
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsHiOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE6),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 2 // Devmap=2
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsHiOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_BIFUR_SELECT_VALUE7),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 3 // Devmap=3
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8004 + MAX_EDITABLE_ELEMENTS * RCIndex, // Question ID (or call it "key")
+ VARSTORE_ID, // VarStore ID
+ BifurHiVarOffset, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PCIE_RCB_HI_BIFUR), // Question prompt text
+ STRING_TOKEN (STR_PCIE_RCB_HI_BIFUR_HELP), // Question help text
+ QuestionFlagsSubItem, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsHiOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+ }
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &gPcieFormSetGuid, // Formset GUID
+ RC0_FORM_ID + RCIndex, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function sets up the first elements of the form.
+ @param PrivateData Private data.
+ @retval EFI_SUCCESS The form is set up successfully.
+**/
+EFI_STATUS
+PcieMainScreenSetup (
+ IN SCREEN_PRIVATE_DATA *PrivateData
+ )
+{
+ VOID *StartOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ CHAR16 Str[MAX_STRING_SIZE];
+ UINTN RC;
+ SETUP_GOTO_DATA *GotoItem = NULL;
+ EFI_QUESTION_ID GotoId;
+ UINT8 QuestionFlags;
+
+ // Initialize the container for dynamic opcodes
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ // Create Hii Extend Label OpCode as the start opcode
+ StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_UPDATE;
+
+ // Create Hii Extend Label OpCode as the end opcode
+ EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ QuestionFlags = EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED;
+
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x9000, // Question ID
+ VARSTORE_ID, // VarStore ID
+ (UINT16)SMMU_PMU_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PCIE_SMMU_PMU_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_PCIE_SMMU_PMU_HELP), // Question help text
+ QuestionFlags,
+ 0,
+ NULL
+ );
+
+ if (mReadOnlyStrongOrdering) {
+ QuestionFlags |= EFI_IFR_FLAG_READ_ONLY;
+ }
+
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x9001, // Question ID
+ NVPARAM_VARSTORE_ID, // VarStore ID
+ (UINT16)STRONG_ODERING_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PCIE_STRONG_ORDERING_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_PCIE_STRONG_ORDERING_HELP), // Question help text
+ QuestionFlags,
+ STRONG_ORDERING_DEFAULT_OPTION_VALUE,
+ NULL
+ );
+
+ //
+ // Create the a seperated line
+ //
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_PCIE_FORM_SEPERATE_LINE),
+ STRING_TOKEN (STR_PCIE_FORM_SEPERATE_LINE),
+ STRING_TOKEN (STR_PCIE_FORM_SEPERATE_LINE)
+ );
+
+ // Create Goto form for each RC
+ for (RC = 0; RC < AC01_MAX_PCIE_ROOT_COMPLEX; RC++) {
+
+ GotoItem = AllocateZeroPool (sizeof (SETUP_GOTO_DATA));
+ if (GotoItem == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ GotoItem->PciDevIdx = RC;
+
+ GotoId = GOTO_ID_BASE + (UINT16)RC;
+
+ // Update HII string
+ UnicodeSPrint (Str, sizeof (Str), L"Root Complex #%2d", RC);
+ GotoItem->GotoStringId = HiiSetString (
+ PrivateData->HiiHandle,
+ 0,
+ Str,
+ NULL
+ );
+ GotoItem->GotoHelpStringId = STRING_TOKEN (STR_PCIE_GOTO_HELP);
+ GotoItem->ShowItem = TRUE;
+
+ // Add goto control
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ RC0_FORM_ID + RC,
+ GotoItem->GotoStringId,
+ GotoItem->GotoHelpStringId,
+ EFI_IFR_FLAG_CALLBACK,
+ GotoId
+ );
+ }
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle, // HII handle
+ &gPcieFormSetGuid, // Formset GUID
+ FORM_ID, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ return EFI_SUCCESS;
+}
+
+VOID
+NVParamVarstoreInit (
+ VOID
+ )
+{
+ BOOLEAN BoardSettingValid;
+ BOOLEAN UserSettingValid;
+ BOOLEAN Update;
+ EFI_STATUS Status;
+ UINT32 UserValue;
+ UINT32 InitValue;
+
+ mReadOnlyStrongOrdering = FALSE;
+
+ // S0
+ UserSettingValid = FALSE;
+ Status = NVParamGet (
+ NV_SI_MESH_S0_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &UserValue
+ );
+ if (!EFI_ERROR (Status)) {
+ UserSettingValid = TRUE;
+ }
+
+ //
+ // InitValue will be default value or board setting value.
+ //
+ BoardSettingValid = FALSE;
+ Status = NVParamGet (
+ NV_SI_RO_BOARD_MESH_S0_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &InitValue
+ );
+ if (!EFI_ERROR (Status) && InitValue > 0) {
+ BoardSettingValid = TRUE;
+ mReadOnlyStrongOrdering = TRUE;
+ } else {
+ InitValue = STRONG_ORDERING_DEFAULT_NVPARAM_VALUE;
+ }
+
+ Update = TRUE;
+ if ((UserSettingValid && (UserValue == InitValue))
+ || (!BoardSettingValid && UserSettingValid && (UserValue == 0)))
+ {
Mover brace up.

/
Leif

+ Update = FALSE;
+ }
+
+ if (Update) {
+ Status = NVParamSet (
+ NV_SI_MESH_S0_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ InitValue
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // No need to check slave present.
+ //
+ UserSettingValid = FALSE;
+ Status = NVParamGet (
+ NV_SI_MESH_S1_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &UserValue
+ );
+ if (!EFI_ERROR (Status)) {
+ UserSettingValid = TRUE;
+ }
+
+ //
+ // InitValue will be default value or board setting value.
+ //
+ BoardSettingValid = FALSE;
+ Status = NVParamGet (
+ NV_SI_RO_BOARD_MESH_S1_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ &InitValue
+ );
+ if (!EFI_ERROR (Status) && InitValue > 0) {
+ BoardSettingValid = TRUE;
+ mReadOnlyStrongOrdering = TRUE;
+ } else {
+ InitValue = STRONG_ORDERING_DEFAULT_NVPARAM_VALUE;
+ }
+
+ Update = TRUE;
+ if ((UserSettingValid && (UserValue == InitValue))
+ || (!BoardSettingValid && UserSettingValid && (UserValue == 0)))
+ {
+ Update = FALSE;
+ }
+
+ if (Update) {
+ Status = NVParamSet (
+ NV_SI_MESH_S1_CXG_RC_STRONG_ORDERING_EN,
+ NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
+ NV_PERM_BIOS | NV_PERM_MANU,
+ InitValue
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Build PCIe menu screen.
+
+ @param[in] RCList List of Root Complex with properties.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval Others An error occurred.
+**/
+EFI_STATUS
+EFIAPI
+BoardPcieScreenInitialize (
+ IN AC01_RC *NewRCList
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler;
+ UINTN BufferSize;
+ BOOLEAN IsUpdated;
+ VARSTORE_DATA *VarStoreConfig;
+ UINT8 RCIndex;
+ AC01_RC *RC;
+
+ //
+ // Initialize driver private data
+ //
+ mPrivateData = AllocateZeroPool (sizeof (SCREEN_PRIVATE_DATA));
+ if (mPrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->Signature = SCREEN_PRIVATE_DATA_SIGNATURE;
+
+ mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ mPrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ mPrivateData->ConfigAccess.Callback = DriverCallback;
+
+ //
+ // Locate Hii Database protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **)&HiiDatabase
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiDatabase = HiiDatabase;
+
+ //
+ // Locate HiiString protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiStringProtocolGuid,
+ NULL,
+ (VOID **)&HiiString
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiString = HiiString;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID **)&HiiConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ //
+ // Locate keyword handler protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiConfigKeywordHandlerProtocolGuid,
+ NULL,
+ (VOID **)&HiiKeywordHandler
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiKeywordHandler = HiiKeywordHandler;
+
+ DriverHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle = HiiAddPackages (
+ &gPcieFormSetGuid,
+ DriverHandle,
+ BoardPcieLibStrings,
+ BoardPcieVfrBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle = HiiHandle;
+
+ // Make a shadow copy all Root Complexes' properties
+ CopyMem ((VOID *)RCList, (VOID *)NewRCList, sizeof (RCList));
+
+ //
+ // Initialize NVParam varstore configuration data
+ //
+ NVParamVarstoreInit ();
+
+ //
+ // Initialize efi varstore configuration data
+ //
+ VarStoreConfig = &mPrivateData->VarStoreConfig;
+ ZeroMem (VarStoreConfig, sizeof (VARSTORE_DATA));
+
+ // Get Buffer Storage data from EFI variable
+ BufferSize = sizeof (VARSTORE_DATA);
+ Status = gRT->GetVariable (
+ gPcieVarstoreName,
+ &gPcieFormSetGuid,
+ NULL,
+ &BufferSize,
+ VarStoreConfig
+ );
+
+ IsUpdated = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->SmmuPmu = 0; /* Disable by default */
+ IsUpdated = TRUE;
+ }
+ // Update board settings to menu
+ for (RCIndex = 0; RCIndex < AC01_MAX_PCIE_ROOT_COMPLEX; RCIndex++) {
+ RC = &RCList[RCIndex];
+
+ if (EFI_ERROR (Status)) {
+ VarStoreConfig->RCBifurcationLow[RCIndex] = RC->DevMapLow;
+ VarStoreConfig->RCBifurcationHigh[RCIndex] = RC->DevMapHigh;
+ VarStoreConfig->RCStatus[RCIndex] = RC->Active;
+ IsUpdated = TRUE;
+ }
+ }
+
+ if (IsUpdated) {
+ // Update Buffer Storage
+ Status = gRT->SetVariable (
+ gPcieVarstoreName,
+ &gPcieFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (VARSTORE_DATA),
+ VarStoreConfig
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ Status = PcieMainScreenSetup (mPrivateData);
+ ASSERT_EFI_ERROR (Status);
+
+ for (RCIndex = 0; RCIndex < AC01_MAX_PCIE_ROOT_COMPLEX; RCIndex++) {
+ Status = PcieRCScreenSetup (RCIndex, mPrivateData);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
diff --git a/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.uni b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.uni
new file mode 100644
index 000000000000..5739a35b4ee5
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieScreen.uni
@@ -0,0 +1,102 @@
+//
+// Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+
+#langdef en-US "English"
+
+#string STR_PCIE_FORM #language en-US "PCIE Root Complex Configuration"
+#string STR_PCIE_FORM_HELP #language en-US "Configure Root Complex"
+
+#string STR_PCIE_FORM_SEPERATE_LINE #language en-US ""
+
+/////
+
+#string STR_PCIE_GOTO #language en-US ""
+#string STR_PCIE_GOTO_HELP #language en-US "Change On Board Root Complex Settings."
+
+#string STR_PCIE_RC_STATUS #language en-US ""
+#string STR_PCIE_RC_STATUS_HELP #language en-US "Enable / Disable Root Complex"
+
+#string STR_PCIE_RCA_BIFUR #language en-US "Bifurcation x16"
+#string STR_PCIE_RCA_BIFUR_HELP #language en-US "Set bifurcation mode for x16 Root Complex Type-A"
+
+#string STR_PCIE_RCB_LO_BIFUR #language en-US "Bifurcation 1st x8"
+#string STR_PCIE_RCB_LO_BIFUR_HELP #language en-US "Set bifurcation mode for 1st x8 Root Complex Type-B"
+
+#string STR_PCIE_RCB_HI_BIFUR #language en-US "Bifurcation 2nd x8"
+#string STR_PCIE_RCB_HI_BIFUR_HELP #language en-US "Set bifurcation mode for 2nd x8 Root Complex Type-B"
+
+/////
+
+#string STR_PCIE_RC0_FORM #language en-US "Root Complex 0 Configuration"
+#string STR_PCIE_RC0_FORM_HELP #language en-US "Root Complex 0 Configuration"
+
+#string STR_PCIE_RC1_FORM #language en-US "Root Complex 1 Configuration"
+#string STR_PCIE_RC1_FORM_HELP #language en-US "Root Complex 1 Configuration"
+
+#string STR_PCIE_RC2_FORM #language en-US "Root Complex 2 Configuration"
+#string STR_PCIE_RC2_FORM_HELP #language en-US "Root Complex 2 Configuration"
+
+#string STR_PCIE_RC3_FORM #language en-US "Root Complex 3 Configuration"
+#string STR_PCIE_RC3_FORM_HELP #language en-US "Root Complex 3 Configuration"
+
+#string STR_PCIE_RC4_FORM #language en-US "Root Complex 4 Configuration"
+#string STR_PCIE_RC4_FORM_HELP #language en-US "Root Complex 4 Configuration"
+
+#string STR_PCIE_RC5_FORM #language en-US "Root Complex 5 Configuration"
+#string STR_PCIE_RC5_FORM_HELP #language en-US "Root Complex 5 Configuration"
+
+#string STR_PCIE_RC6_FORM #language en-US "Root Complex 6 Configuration"
+#string STR_PCIE_RC6_FORM_HELP #language en-US "Root Complex 6 Configuration"
+
+#string STR_PCIE_RC7_FORM #language en-US "Root Complex 7 Configuration"
+#string STR_PCIE_RC7_FORM_HELP #language en-US "Root Complex 7 Configuration"
+
+#string STR_PCIE_RC8_FORM #language en-US "Root Complex 8 Configuration"
+#string STR_PCIE_RC8_FORM_HELP #language en-US "Root Complex 8 Configuration"
+
+#string STR_PCIE_RC9_FORM #language en-US "Root Complex 9 Configuration"
+#string STR_PCIE_RC9_FORM_HELP #language en-US "Root Complex 9 Configuration"
+
+#string STR_PCIE_RC10_FORM #language en-US "Root Complex 10 Configuration"
+#string STR_PCIE_RC10_FORM_HELP #language en-US "Root Complex 10 Configuration"
+
+#string STR_PCIE_RC11_FORM #language en-US "Root Complex 11 Configuration"
+#string STR_PCIE_RC11_FORM_HELP #language en-US "Root Complex 11 Configuration"
+
+#string STR_PCIE_RC12_FORM #language en-US "Root Complex 12 Configuration"
+#string STR_PCIE_RC12_FORM_HELP #language en-US "Root Complex 12 Configuration"
+
+#string STR_PCIE_RC13_FORM #language en-US "Root Complex 13 Configuration"
+#string STR_PCIE_RC13_FORM_HELP #language en-US "Root Complex 13 Configuration"
+
+#string STR_PCIE_RC14_FORM #language en-US "Root Complex 14 Configuration"
+#string STR_PCIE_RC14_FORM_HELP #language en-US "Root Complex 14 Configuration"
+
+#string STR_PCIE_RC15_FORM #language en-US "Root Complex 15 Configuration"
+#string STR_PCIE_RC15_FORM_HELP #language en-US "Root Complex 15 Configuration"
+
+#string STR_PCIE_BIFUR_SELECT_VALUE0 #language en-US "x16"
+#string STR_PCIE_BIFUR_SELECT_VALUE1 #language en-US "x8+x8"
+#string STR_PCIE_BIFUR_SELECT_VALUE2 #language en-US "x8+x4+x4"
+#string STR_PCIE_BIFUR_SELECT_VALUE3 #language en-US "x4+x4+x4+x4"
+#string STR_PCIE_BIFUR_SELECT_VALUE4 #language en-US "x8"
+#string STR_PCIE_BIFUR_SELECT_VALUE5 #language en-US "x4+x4"
+#string STR_PCIE_BIFUR_SELECT_VALUE6 #language en-US "x4+x2+x2"
+#string STR_PCIE_BIFUR_SELECT_VALUE7 #language en-US "x2+x2+x2+x2"
+
+#string STR_PCIE_SOCKET #language en-US "Socket"
+#string STR_PCIE_SOCKET_HELP #language en-US "Socket 0 - Master; Socket 1 - Slave"
+#string STR_PCIE_SOCKET_VALUE #language en-US ""
+
+#string STR_PCIE_RC_TYPE #language en-US "Type"
+#string STR_PCIE_RC_TYPE_HELP #language en-US "Type-A: x16 lanes bifurcated down to x4; Type-B: 2 of x8 lanes, each bifurcated down to x2"
+#string STR_PCIE_RC_TYPE_VALUE #language en-US ""
+
+#string STR_PCIE_SMMU_PMU_PROMPT #language en-US "SMMU Pmu"
+#string STR_PCIE_SMMU_PMU_HELP #language en-US "Enable/Disable PMU feature for SMMU"
+
+#string STR_PCIE_STRONG_ORDERING_PROMPT #language en-US "PCIe Strong Ordering"
+#string STR_PCIE_STRONG_ORDERING_HELP #language en-US "Enable/disable PCIe Strong Ordering with internal bus"
--
2.17.1


Re: 回复: [PATCH v1 0/4] Set default Makefile name

PierreGondois
 

Hi Liming,

I created: https://bugzilla.tianocore.org/show_bug.cgi?id=3653

Regards,

Pierre

On 9/24/21 1:48 AM, gaoliming wrote:
Pierre:
Can you submit BZ for this change request?

Thanks
Liming
-----邮件原件-----
发件人: Pierre.Gondois@arm.com <Pierre.Gondois@arm.com>
发送时间: 2021年9月23日 16:59
收件人: devel@edk2.groups.io; Bob Feng <bob.c.feng@intel.com>; Liming
Gao <gaoliming@byosoft.com.cn>; Sami Mujawar <sami.mujawar@arm.com>
主题: [PATCH v1 0/4] Set default Makefile name

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

A Makefile name is not set in BaseTools when only building modules
or libraries. This patch-set sets a default Makefile name for the
"build" command.

The patch-set also:
- Removes unsused Makefile variables
- Removes hard-coded references to "target.txt" and "tools_def.txt"

The changes can be seen at:
https://github.com/PierreARM/edk2/tree/1868_BaseTools_build_py_correcti
ons_v1

Pierre Gondois (4):
BaseTools/GenMake: Use ToolDefinition as fallback option
BaseTools/build: Set MakefileName
BaseTools: Remove Makefile/MakefileName fields
BaseTools: Remove hard-coded strings for target and tools_def

BaseTools/Source/Python/AutoGen/GenMake.py | 8
++++----
BaseTools/Source/Python/AutoGen/ModuleAutoGen.py | 1 -
BaseTools/Source/Python/GenFds/GenFds.py | 4 ++--
.../Source/Python/GenFds/GenFdsGlobalVariable.py | 4 ++--
BaseTools/Source/Python/TargetTool/TargetTool.py | 3 ++-
BaseTools/Source/Python/Workspace/BuildClassObject.py | 2 --
BaseTools/Source/Python/Workspace/DscBuildData.py | 9 ++++-----
BaseTools/Source/Python/build/build.py | 11 ++++-------
8 files changed, 18 insertions(+), 24 deletions(-)

--
2.17.1


8661 - 8680 of 89698