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

Join devel@edk2.groups.io to automatically receive all group messages.