public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nhi Pham" <nhi@os.amperecomputing.com>
To: devel@edk2.groups.io
Cc: Vu Nguyen <vunguyen@os.amperecomputing.com>,
	Thang Nguyen <thang@os.amperecomputing.com>,
	Chuong Tran <chuong@os.amperecomputing.com>,
	Phong Vo <phong@os.amperecomputing.com>,
	Leif Lindholm <leif@nuviainc.com>,
	Michael D Kinney <michael.d.kinney@intel.com>,
	Ard Biesheuvel <ardb+tianocore@kernel.org>,
	Nate DeSimone <nathaniel.l.desimone@intel.com>
Subject: [edk2-platforms][PATCH v2 28/32] AmpereAltraPkg: Add configuration screen for Pcie Devices
Date: Wed, 26 May 2021 17:07:20 +0700	[thread overview]
Message-ID: <20210526100724.5359-30-nhi@os.amperecomputing.com> (raw)
In-Reply-To: <20210526100724.5359-1-nhi@os.amperecomputing.com>

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>
---
 Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec                                  |    3 +
 Platform/Ampere/JadePkg/Jade.dsc                                                  |    1 +
 Platform/Ampere/JadePkg/Jade.fdf                                                  |    1 +
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.inf |   59 ++
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/NVDataStruc.h           |   56 ++
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.h   |   78 ++
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieHelper.h            |   58 ++
 Silicon/Ampere/AmpereAltraPkg/Include/Guid/PcieDeviceConfigHii.h                  |   19 +
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/Vfr.vfr                 |   50 +
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.c   | 1046 ++++++++++++++++++++
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieHelper.c            |  191 ++++
 Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.uni |   24 +
 12 files changed, 1586 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index 53930869f4f6..62e27c8b49b2 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
+  gPcieDeviceConfigFormSetGuid = { 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 391ff75e237c..9d787113e3b5 100755
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -184,3 +184,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/PcieDeviceConfigDxe/PcieDeviceConfigDxe.inf
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 431c9906e98e..b0c2894d00f8 100755
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -359,5 +359,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/PcieDeviceConfigDxe/PcieDeviceConfigDxe.inf
 
 !include Platform/Ampere/AmperePlatformPkg/FvRules.fdf.inc
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.inf
new file mode 100644
index 000000000000..a04c79661842
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.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                      = PcieDeviceConfigDxe
+  FILE_GUID                      = 17E9369D-0A1B-45F4-A286-B1DED6D85D33
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PcieDeviceConfigEntryPoint
+
+[Sources.common]
+  NVDataStruc.h
+  PcieDeviceConfigDxe.c
+  PcieDeviceConfigDxe.h
+  PcieDeviceConfigDxe.uni
+  PcieHelper.c
+  PcieHelper.h
+  Vfr.vfr
+
+[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
+  gPcieDeviceConfigFormSetGuid
+  gPlatformManagerFormsetGuid
+  gPlatformManagerEntryEventGuid
+
+[Depex]
+  TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/NVDataStruc.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/NVDataStruc.h
new file mode 100644
index 000000000000..fb168e495670
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/NVDataStruc.h
@@ -0,0 +1,56 @@
+/** @file
+
+  Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef NVDATASTRUC_H_
+#define NVDATASTRUC_H_
+
+#include <Guid/PcieDeviceConfigHii.h>
+
+#define VARSTORE_NAME   L"PcieDeviceConfigNVData"
+
+#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 // NVDATASTRUC_H_
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.h
new file mode 100644
index 000000000000..40d7da1ef277
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.h
@@ -0,0 +1,78 @@
+/** @file
+
+  Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PCIE_DEVICE_CONFIG_H_
+#define 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 "NVDataStruc.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 VfrBin[];
+
+//
+// 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 PcieDeviceConfigDxeStrings[];
+
+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 // PCIE_DEVICE_CONFIG_H_
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieHelper.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieHelper.h
new file mode 100644
index 000000000000..32787865119d
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieHelper.h
@@ -0,0 +1,58 @@
+/** @file
+
+  Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PCIE_HELPER_H_
+#define 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 // PCIE_HELPER_H_
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Guid/PcieDeviceConfigHii.h b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/PcieDeviceConfigHii.h
new file mode 100644
index 000000000000..04b950abd49e
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Guid/PcieDeviceConfigHii.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 PCIE_DEVICE_CONFIG_HII_H_
+#define PCIE_DEVICE_CONFIG_HII_H_
+
+#define PCIE_DEVICE_CONFIG_FORMSET_GUID \
+  { \
+    0xEC7B1D21, 0x9167, 0x4B9D, { 0xF7, 0x94, 0xCD, 0x1A, 0xEB, 0xBC, 0xB7, 0x59 } \
+  }
+
+extern EFI_GUID gPcieDeviceConfigFormSetGuid;
+
+#endif /* PCIE_DEVICE_CONFIG_HII_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/Vfr.vfr b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/Vfr.vfr
new file mode 100644
index 000000000000..b5b16802b23e
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/Vfr.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 "NVDataStruc.h"
+
+formset
+  guid    = PCIE_DEVICE_CONFIG_FORMSET_GUID,
+  title   = STRING_TOKEN(STR_PCIE_DEVICE_CONFIG_FORM),
+  help    = STRING_TOKEN(STR_PCIE_DEVICE_CONFIG_HELP),
+  classguid = gPlatformManagerFormsetGuid,
+
+  //
+  // Define a variable Storage
+  //
+  varstore VARSTORE_DATA,
+    varid   = VARSTORE_ID,
+    name    = PcieDeviceConfigNVData,
+    guid    = PCIE_DEVICE_CONFIG_FORMSET_GUID;
+
+  form
+    formid = MAIN_FORM_ID,
+    title = STRING_TOKEN(STR_PCIE_DEVICE_CONFIG_FORM);
+
+    subtitle text = STRING_TOKEN(STR_PCIE_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/PcieDeviceConfigDxe/PcieDeviceConfigDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.c
new file mode 100644
index 000000000000..a04f789530c0
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.c
@@ -0,0 +1,1046 @@
+/** @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/PcieDeviceConfigHii.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 "PcieDeviceConfigDxe.h"
+#include "PcieHelper.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)
+      }
+    },
+    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,
+                    &gPcieDeviceConfigFormSetGuid,
+                    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
+    // FIXME: 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
+    &gPcieDeviceConfigFormSetGuid, // 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));
+
+    // TODO: convert and store in SlotID ex:SystemSlot(seg, bus, dev)
+    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
+    &gPcieDeviceConfigFormSetGuid,  // 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 (
+                         &gPcieDeviceConfigFormSetGuid,
+                         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, &gPcieDeviceConfigFormSetGuid, 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,
+         &gPcieDeviceConfigFormSetGuid,
+         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
+PcieDeviceConfigEntryPoint (
+  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 (
+                &gPcieDeviceConfigFormSetGuid,
+                DriverHandle,
+                PcieDeviceConfigDxeStrings,
+                VfrBin,
+                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,
+                  &gPcieDeviceConfigFormSetGuid,
+                  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/PcieDeviceConfigDxe/PcieHelper.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieHelper.c
new file mode 100644
index 000000000000..b4e918e2b786
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieHelper.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 "PcieDeviceConfigDxe.h"
+#include "PcieHelper.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/PcieDeviceConfigDxe/PcieDeviceConfigDxe.uni b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.uni
new file mode 100644
index 000000000000..f07b70c746a6
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/PcieDeviceConfigDxe/PcieDeviceConfigDxe.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_PCIE_DEVICE_CONFIG_FORM #language en-US "PCIE Device Configuration"
+#string STR_PCIE_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


  parent reply	other threads:[~2021-05-26 10:12 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-26 10:06 [edk2-platforms][PATCH v2 00/32] Add new Ampere Mt. Jade platform Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 01/32] Ampere: Initial support for Ampere Altra processor and " Nhi Pham
2021-06-04 23:04   ` Leif Lindholm
2021-06-09  4:50     ` Nhi Pham
2021-06-09 12:40       ` Leif Lindholm
2021-06-15 16:46     ` Nhi Pham
2021-05-26 10:06 ` [PATCH 1/1] UsbCdcNetDxe: Remove reading connection status in SNP GetStatus Nhi Pham
2021-05-26 10:23   ` [edk2-devel] " Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 02/32] AmpereAltraPkg: Add MmCommunication modules Nhi Pham
2021-06-04 23:05   ` Leif Lindholm
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 03/32] AmperePlatformPkg: Implement FailSafe library Nhi Pham
2021-06-04 23:07   ` Leif Lindholm
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 04/32] AmperePlatformPkg: Add FailSafe and WDT support Nhi Pham
2021-06-04 23:12   ` Leif Lindholm
2021-06-15 16:47     ` Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 05/32] AmpereAltraPkg: Add DwI2cLib library Nhi Pham
2021-06-04 23:21   ` Leif Lindholm
2021-06-15 16:47     ` Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 06/32] AmpereAltraPkg: Add DwGpioLib library Nhi Pham
2021-06-04 23:22   ` Leif Lindholm
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 07/32] JadePkg: Implement RealTimeClockLib for PCF85063 Nhi Pham
2021-06-04 23:26   ` Leif Lindholm
2021-06-15 16:48     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 08/32] AmpereAltraPkg: Add BootProgress support Nhi Pham
2021-06-04 23:27   ` Leif Lindholm
2021-06-15 16:48     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 09/32] AmpereAltraPkg: Support non-volatile variables Nhi Pham
2021-06-04 23:36   ` Leif Lindholm
2021-06-15 16:48     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 10/32] AmpereSiliconPkg: Add PlatformManagerUiLib library instance Nhi Pham
2021-06-04 23:37   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 11/32] AmperePlatformPkg: Add AcpiPccLib to support ACPI PCCT Table Nhi Pham
2021-06-04 23:44   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 12/32] AmperePlatformPkg: Add AcpiHelperLib to update ACPI DSDT table Nhi Pham
2021-06-04 23:47   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 13/32] AmpereAltraPkg, JadePkg: Add ACPI support Nhi Pham
2021-06-04 23:50   ` Leif Lindholm
2021-06-15 16:49     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 14/32] AmpereAltraPkg: Add PcieCoreLib library instance Nhi Pham
2021-06-05  0:05   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 15/32] JadePkg: Add PcieBoardLib " Nhi Pham
2021-06-07 22:45   ` Leif Lindholm
2021-06-15 16:50     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 16/32] AmpereAltraPkg: Add PciHostBridge driver Nhi Pham
2021-06-08 22:26   ` Leif Lindholm
2021-06-09  5:29   ` Ard Biesheuvel
2021-06-15 15:54     ` Nhi Pham
2021-06-16 14:20       ` Ard Biesheuvel
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 17/32] JadePkg: Enable PCIe-related libraries and device drivers Nhi Pham
2021-06-07 22:51   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 18/32] JadePkg: Add ASpeed GOP driver Nhi Pham
2021-06-07 22:51   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 19/32] AmpereAltraPkg: Add Random Number Generator Support Nhi Pham
2021-06-08 11:13   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 20/32] JadePkg: Add SMBIOS tables support Nhi Pham
2021-06-07 23:00   ` Leif Lindholm
2021-06-15 16:51     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 21/32] AmpereAltraPkg: Add DebugInfoPei module Nhi Pham
2021-06-07 23:08   ` Leif Lindholm
2021-06-15 16:51     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 22/32] AmpereAltraPkg: Add platform info screen Nhi Pham
2021-06-07 23:10   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 23/32] AmpereAltraPkg: Add configuration screen for memory Nhi Pham
2021-06-07 23:14   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 24/32] AmpereAltraPkg: Add configuration screen for CPU Nhi Pham
2021-06-07 23:15   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 25/32] AmpereAltraPkg: Add configuration screen for ACPI Nhi Pham
2021-06-07 23:20   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 26/32] AmpereAltraPkg: Add configuration screen for RAS Nhi Pham
2021-06-07 23:22   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 27/32] AmpereAltraPkg: Add configuration screen for Watchdog timer Nhi Pham
2021-06-07 23:24   ` Leif Lindholm
2021-05-26 10:07 ` Nhi Pham [this message]
2021-06-07 23:34   ` [edk2-platforms][PATCH v2 28/32] AmpereAltraPkg: Add configuration screen for Pcie Devices Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 29/32] JadePkg: Recover boot options when NVRAM cleared Nhi Pham
2021-06-07 23:46   ` Leif Lindholm
2021-06-15 16:52     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 30/32] AmpereSiliconPkg: Implement PlatformBootManagerLib for LinuxBoot Nhi Pham
2021-06-07 23:50   ` Leif Lindholm
2021-06-09 15:21     ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 31/32] Platform/Ampere: Introduce the LinuxBootPkg Nhi Pham
2021-06-07 23:51   ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 32/32] AmpereAltraPkg,JadePkg: Support LinuxBoot DSC/FDF build for Jade platform Nhi Pham
2021-06-07 23:58   ` Leif Lindholm
2021-06-09 15:20     ` Nhi Pham
2021-05-27 12:56 ` [edk2-platforms][PATCH v2 00/32] Add new Ampere Mt. " Leif Lindholm
2021-06-04 13:54 ` Leif Lindholm

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20210526100724.5359-30-nhi@os.amperecomputing.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

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

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