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

Leif Lindholm leif at nuviainc.com
Mon Jun 7 23:34:40 UTC 2021


On Wed, May 26, 2021 at 17:07:20 +0700, Nhi Pham wrote:
> 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_

Again, concern with claiming part of global PCIE namespace.

> +
> +#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[];

PlatformPcieDeviceConfigVfrBin?

> +
> +//
> +// This is the generated String package data for all .UNI files.
> +// This data array is ready to be used as input of HiiAddPackages() to
> +// create a packagelist (which contains Form packages, String packages, etc).
> +//
> +extern UINT8 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

Please drop FIXME.

> +    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)

Please drop TODO.

> +    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))
> +  {

{ on preceding line.

> +    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)))
> +    {

{ on preceding line.
More instances below - please fix throughout.

/
    Leif

> +      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 (#76166): https://edk2.groups.io/g/devel/message/76166
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