[edk2-devel] [edk2-platforms][PATCH v2 28/32] AmpereAltraPkg: Add configuration screen for Pcie Devices

Nhi Pham via groups.io nhi=os.amperecomputing.com at groups.io
Wed May 26 10:07:20 UTC 2021


From: Vu Nguyen <vunguyen at 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 at os.amperecomputing.com>
Cc: Chuong Tran <chuong at os.amperecomputing.com>
Cc: Phong Vo <phong at os.amperecomputing.com>
Cc: Leif Lindholm <leif at nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Ard Biesheuvel <ardb+tianocore at kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone at intel.com>

Signed-off-by: Vu Nguyen <vunguyen at 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



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#75637): https://edk2.groups.io/g/devel/message/75637
Mute This Topic: https://groups.io/mt/83097173/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list