[edk2-devel] [edk2-staging/UEFI_PCI_ENHANCE-2 PATCH 01/12] MdeModulePkg/PciBusDxe: Setup for PCI Express features

Javeed, Ashraf posted 12 patches 4 years, 9 months ago
[edk2-devel] [edk2-staging/UEFI_PCI_ENHANCE-2 PATCH 01/12] MdeModulePkg/PciBusDxe: Setup for PCI Express features
Posted by Javeed, Ashraf 4 years, 9 months ago
References:-
  https://bugzilla.tianocore.org/show_bug.cgi?id=1954
  https://bugzilla.tianocore.org/show_bug.cgi?id=2194
  https://bugzilla.tianocore.org/show_bug.cgi?id=2313
  https://bugzilla.tianocore.org/show_bug.cgi?id=2499
  https://bugzilla.tianocore.org/show_bug.cgi?id=2500

This code change represents the preparation of common code setup for the
new PCI Express features initialization, utilizing the new PCI Express
Platform / Override Protocol.
The new set of source files are as follows:-
  new file:   /PciFeatureSupport.c
  new file:   /PciFeatureSupport.h
  new file:   /PciPlatformSupport.c
  new file:   /PciPlatformSupport.h

Signed-off-by: Ashraf Javeed <ashraf.javeed@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
---
 MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c               |   6 +++++-
 MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h               |  12 ++++++++++--
 MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf          |   9 ++++++++-
 MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c |  12 +++++++++++-
 MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c    | 891 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h    | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c   | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h   |  87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 1540 insertions(+), 5 deletions(-)

diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
index b020ce5..714101c 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
@@ -8,7 +8,7 @@
   PCI Root Bridges. So it means platform needs install PCI Root Bridge IO protocol for each
   PCI Root Bus and install PCI Host Bridge Resource Allocation Protocol.
 
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -284,6 +284,10 @@ PciBusDriverBindingStart (
           (VOID **) &gPciOverrideProtocol
           );
   }
+  //
+  // get the PCI Express Protocol or the PCI Express Override Protocol
+  //
+  GetPciExpressProtocol ();
 
   if (mIoMmuProtocol == NULL) {
     gBS->LocateProtocol (
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
index 504a1b1..225229d 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
@@ -1,7 +1,7 @@
 /** @file
   Header files and data structures needed by PCI Bus module.
 
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -42,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <IndustryStandard/Pci.h>
 #include <IndustryStandard/PeImage.h>
 #include <IndustryStandard/Acpi.h>
+#include <Protocol/PciExpressOverride.h>
+#include <Protocol/PciExpressPlatform.h>
 
 typedef struct _PCI_IO_DEVICE              PCI_IO_DEVICE;
 typedef struct _PCI_BAR                    PCI_BAR;
@@ -79,6 +81,8 @@ typedef enum {
 #include "PciPowerManagement.h"
 #include "PciHotPlugSupport.h"
 #include "PciLib.h"
+#include "PciPlatformSupport.h"
+#include "PciFeatureSupport.h"
 
 #define VGABASE1  0x3B0
 #define VGALIMIT1 0x3BB
@@ -263,9 +267,13 @@ struct _PCI_IO_DEVICE {
 
   BOOLEAN                                   IsPciExp;
   //
-  // For SR-IOV
+  // For PCI Express Capability List Structure
   //
   UINT8                                     PciExpressCapabilityOffset;
+  PCI_CAPABILITY_PCIEXP                     PciExpressCapabilityStructure;
+  //
+  // For SR-IOV
+  //
   UINT32                                    AriCapabilityOffset;
   UINT32                                    SrIovCapabilityOffset;
   UINT32                                    MrIovCapabilityOffset;
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
index 05c2202..f06b411 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
@@ -2,7 +2,7 @@
 #  The PCI bus driver will probe all PCI devices and allocate MMIO and IO space for these devices.
 #  Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting.
 #
-#  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -57,6 +57,10 @@
   PciCommand.h
   PciIo.h
   PciBus.h
+  PciFeatureSupport.c
+  PciFeatureSupport.h
+  PciPlatformSupport.c
+  PciPlatformSupport.h
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -91,6 +95,9 @@
   gEfiLoadFile2ProtocolGuid                       ## SOMETIMES_PRODUCES
   gEdkiiIoMmuProtocolGuid                         ## SOMETIMES_CONSUMES
   gEfiLoadedImageDevicePathProtocolGuid           ## CONSUMES
+  gEfiPciExpressPlatformProtocolGuid                     ## SOMETIMES_CONSUMES
+  gEfiPciExpressOverrideProtocolGuid                     ## SOMETIMES_CONSUMES
+
 
 [FeaturePcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport      ## CONSUMES
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
index c7eafff..c9e52ea 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
@@ -1,7 +1,7 @@
 /** @file
   PCI emumeration support functions implementation for PCI Bus module.
 
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -2154,6 +2154,16 @@ CreatePciIoDevice (
              );
   if (!EFI_ERROR (Status)) {
     PciIoDevice->IsPciExp = TRUE;
+    //
+    // read the PCI device's entire PCI Express Capability structure
+    //
+    PciIo->Pci.Read (
+                  PciIo,
+                  EfiPciIoWidthUint8,
+                  PciIoDevice->PciExpressCapabilityOffset,
+                  sizeof (PCI_CAPABILITY_PCIEXP) / sizeof (UINT8),
+                  &PciIoDevice->PciExpressCapabilityStructure
+                  );
   }
 
   if (PcdGetBool (PcdAriSupport)) {
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c
new file mode 100644
index 0000000..3980a8e
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c
@@ -0,0 +1,891 @@
+/** @file
+  PCI standard feature support functions implementation for PCI Bus module..
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+#include "PciFeatureSupport.h"
+
+/**
+  Hold the current instance of Root Bridge IO protocol Handle
+**/
+EFI_HANDLE                                  mRootBridgeHandle;
+
+/**
+  A gobal pointer to BRIDGE_DEVICE_NODE buffer to track all the primary physical
+  PCI Root Ports (PCI Controllers) for a given PCI Root Bridge instance while
+  enumerating to configure the PCI features
+**/
+LIST_ENTRY                                  mRootBridgeDeviceList;
+
+/**
+ global list to indicate the supported PCI Express features of this driver, it
+ is expected to be overridden based on the platform request
+**/
+EFI_PCI_EXPRESS_PLATFORM_POLICY             mPciExpressPlatformPolicy = {
+    //
+    // support for PCI Express feature - Max. Payload Size
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Max. Read Request Size
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Extended Tag
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Relax Order
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - No-Snoop
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - ASPM state
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Common Clock Configuration
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Extended Sync
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Atomic Op
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - LTR
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - PTM
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Completion Timeout
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - Clock Power Management
+    //
+    FALSE,
+    //
+    // support for PCI Express feature - L1 PM Substates
+    //
+    FALSE
+};
+
+//
+// indicates the driver has completed query to platform on the list of supported
+// PCI features to be configured
+//
+BOOLEAN   mPciExpressGetPlatformPolicyComplete = FALSE;
+
+//
+// PCI Express feature initialization phase handle routines
+//
+PCI_EXPRESS_FEATURE_INITIALIZATION_POINT  mPciExpressFeatureInitializationList[] = {
+    //
+    // vacant entry, shall be replaced with actual entry when the PCI Express
+    // feature are added.
+    //
+  { 0, 0, NULL}
+};
+
+/**
+  Routine to serially dispatch the designated the PCI Express feature specific
+  functions defined for each of the configuration phase. The order for each phase
+  would be based entirely on the table mPciExpressFeatureInitializationList.
+
+  @param  PciDevice                       pointer to PCI_IO_DEVICE to identify device
+  @param  PciExFeatureConfigPhase         input configuration phase
+  @param  PciExpressFeatureConfiguration  used pointer to void to accomodate any PCI
+                                          Express feature specific data type
+  @retval EFI_STATUS                      output only from feature specific function
+                                          defined in the table mPciExpressFeatureInitializationList
+**/
+EFI_STATUS
+DispatchPciExpressInitializationFunctions (
+  IN PCI_IO_DEVICE                            *PciDevice,
+  IN PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE  PciExFeatureConfigPhase,
+  IN VOID                                     *PciExpressFeatureConfiguration
+  )
+{
+  UINTN       idx;
+  EFI_STATUS  Status;
+  UINT8       *PciExpressPolicy;
+
+  for (
+      idx = 0, PciExpressPolicy = (UINT8*)&mPciExpressPlatformPolicy
+      ; idx < sizeof (mPciExpressFeatureInitializationList) / sizeof (PCI_EXPRESS_FEATURE_INITIALIZATION_POINT)
+      ; idx++
+      ){
+    if (
+        //
+        // match the configuration phase
+        //
+        mPciExpressFeatureInitializationList[idx].PciExpressFeatureConfigurationPhase == PciExFeatureConfigPhase
+        //
+        // check whether the PCI Express features is enabled
+        //
+        && PciExpressPolicy[mPciExpressFeatureInitializationList[idx].PciExpressFeatureId] == TRUE
+        ) {
+      Status =  mPciExpressFeatureInitializationList[idx].PciExpressFeatureConfigurationRoutine (
+                                                            PciDevice,
+                                                            PciExpressFeatureConfiguration
+                                                            );
+    }
+  }
+  return Status;
+}
+
+/**
+  Main routine to indicate platform selection of any of the other PCI features
+  to be configured by this driver
+
+  @retval TRUE    platform has selected the other PCI features to be configured
+          FALSE   platform has not selected any of the other PCI features
+**/
+BOOLEAN
+CheckPciExpressFeatureList (
+  )
+{
+  UINTN     length;
+  UINT8     *list;
+
+  for (
+      length = 0, list = (UINT8*)&mPciExpressPlatformPolicy
+      ; length < sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY)
+      ; length++
+      ) {
+    if (list[length]) {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/**
+  helper routine to wipe out the global PCI Express feature list
+**/
+VOID
+NegatePciExpressFeatureList (
+  )
+{
+  UINTN     length;
+  UINT8      *list;
+
+  for (
+      length = 0, list = (UINT8*)&mPciExpressPlatformPolicy
+      ; length < sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY)
+      ; length++
+      ) {
+    if (list[length]) {
+      list[length] = FALSE;
+    }
+  }
+}
+
+/**
+  Main routine to indicate whether the PCI Express feature initialization is
+  required or not
+
+  @retval TRUE    PCI Express feature initialization required
+          FALSE   PCI Express feature not required
+**/
+BOOLEAN
+IsPciExpressFeatureConfigurationRequired (
+  )
+{
+  EFI_STATUS    Status;
+
+  if (mPciExpressGetPlatformPolicyComplete) {
+    return CheckPciExpressFeatureList ();
+  }
+  //
+  // initialize the PCI Express feature data members
+  //
+  InitializeListHead (&mRootBridgeDeviceList);
+  //
+  // check the platform to configure the PCI Express features
+  //
+  mPciExpressGetPlatformPolicyComplete = TRUE;
+
+  Status = PciExpressPlatformGetPolicy ();
+  if (EFI_ERROR (Status)) {
+    //
+    // fail to obtain the PCI Express feature configuration from platform,
+    // negate the list to avoid any unwanted configuration
+    //
+    NegatePciExpressFeatureList ();
+    return FALSE;
+  }
+  //
+  // PCI Express feature configuration list is ready from platform
+  //
+  return TRUE;
+}
+
+
+/**
+  Indicates whether the set of PCI Express features selected by platform requires
+  extended setup, that has additional resources that would be allocated to align
+  all the devices in the PCI tree, and free the resources later.
+
+  @retval TRUE    PCI Express feature requires extended setup
+          FALSE   PCI Express feature does not require extended setup
+**/
+BOOLEAN
+IsPciExpressFeatureExtendedSetupRequired (
+  )
+{
+  UINTN   idx;
+  UINT8   *PciExpressPolicy;
+  //
+  // return TRUE only for those features which are required to be aligned with
+  // common values among all the devices in the PCI tree
+  //
+  for (
+      idx = 0, PciExpressPolicy = (UINT8*)&mPciExpressPlatformPolicy
+      ; idx < sizeof (mPciExpressFeatureInitializationList) / sizeof (PCI_EXPRESS_FEATURE_INITIALIZATION_POINT)
+      ; idx++
+  ){
+    if (
+        //
+        // match the configuration phase to extended setup phase
+        //
+        mPciExpressFeatureInitializationList[idx].PciExpressFeatureConfigurationPhase == PciExpressFeatureEntendedSetupPhase
+        //
+        // check whether the PCI Express features is enabled
+        //
+        && PciExpressPolicy[mPciExpressFeatureInitializationList[idx].PciExpressFeatureId] == TRUE
+    ) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+ Helper routine to determine the existence of previously enumerated PCI device
+
+ @retval  TRUE  PCI device exist
+          FALSE does not exist
+**/
+BOOLEAN
+DeviceExist (
+  PCI_IO_DEVICE                   *PciDevice
+  )
+{
+  EFI_PCI_IO_PROTOCOL   *PciIoProtocol = &PciDevice->PciIo;
+  UINT16                VendorId = 0xFFFF;
+
+  PciIoProtocol->Pci.Read (
+                      PciIoProtocol,
+                      EfiPciIoWidthUint16,
+                      PCI_VENDOR_ID_OFFSET,
+                      1,
+                      &VendorId
+                      );
+  if (VendorId == 0 || VendorId == 0xFFFF) {
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
+/**
+  Free up memory alloted for the primary physical PCI Root ports of the PCI Root
+  Bridge instance. Free up all the nodes of type BRIDGE_DEVICE_NODE.
+**/
+VOID
+DestroyRootBridgeDeviceNodes ()
+{
+  LIST_ENTRY                *Link;
+  BRIDGE_DEVICE_NODE        *Temp;
+
+  Link = mRootBridgeDeviceList.ForwardLink;
+  while (Link != NULL && Link != &mRootBridgeDeviceList) {
+    Temp = ROOT_BRIDGE_DEVICE_NODE_FROM_LINK (Link);
+    Link = RemoveEntryList (Link);
+    FreePool (Temp->PciExFeaturesConfigurationTable);
+    FreePool (Temp);
+  }
+}
+
+/**
+  Main routine to determine the child PCI devices of a PCI bridge device
+  and group them under a common internal PCI features Configuration table.
+
+  @param  PciDevice                       A pointer to the PCI_IO_DEVICE.
+  @param  PciFeaturesConfigTable          A pointer to a pointer to the
+                                          PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE.
+                                          Returns NULL in case of RCiEP or the PCI
+                                          device does match with any of the physical
+                                          Root ports, or it does not belong to any
+                                          Root port's PCI bus range (not a child)
+
+  @retval EFI_SUCCESS                     able to determine the PCI feature
+                                          configuration table. For RCiEP since
+                                          since it is not prepared.
+          EFI_DEVICE_ERROR                the PCI device has invalid EFI device
+                                          path
+**/
+EFI_STATUS
+GetPciExpressFeaturesConfigurationTable (
+  IN  PCI_IO_DEVICE                             *PciDevice,
+  OUT PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE  **PciFeaturesConfigTable
+  )
+{
+  LIST_ENTRY                *Link;
+  BRIDGE_DEVICE_NODE        *Temp;
+  BOOLEAN                   NodeMatch;
+  EFI_DEVICE_PATH_PROTOCOL  *RootPortPath;
+  EFI_DEVICE_PATH_PROTOCOL  *PciDevicePath;
+
+  if (IsListEmpty (&mRootBridgeDeviceList)) {
+    //
+    // no populated PCI primary root ports to parse and match the PCI features
+    // configuration table
+    //
+    *PciFeaturesConfigTable = NULL;
+    return EFI_SUCCESS;
+  }
+
+  //
+  // The PCI features configuration table is not built for RCiEP, return NULL
+  //
+  if (PciDevice->PciExpressCapabilityStructure.Capability.Bits.DevicePortType == \
+      PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_INTEGRATED_ENDPOINT) {
+    *PciFeaturesConfigTable = NULL;
+    return EFI_SUCCESS;
+  }
+
+  if (IsDevicePathEnd (PciDevice->DevicePath)){
+    //
+    // the given PCI device does not have a valid device path
+    //
+    *PciFeaturesConfigTable = NULL;
+    return EFI_DEVICE_ERROR;
+  }
+
+
+  Link = mRootBridgeDeviceList.ForwardLink;
+  do {
+    Temp = ROOT_BRIDGE_DEVICE_NODE_FROM_LINK (Link);
+    RootPortPath = Temp->RootBridgeDevicePath;
+    PciDevicePath = PciDevice->DevicePath;
+    NodeMatch = FALSE;
+    //
+    // match the device path from the list of primary Root Ports with the given
+    // device; the initial nodes matching in sequence indicate that the given PCI
+    // device belongs to that PCI tree from the root port
+    //
+    if (IsDevicePathEnd (RootPortPath)) {
+      //
+      // critical error as no device path available in root
+      //
+      *PciFeaturesConfigTable = NULL;
+      return EFI_DEVICE_ERROR;
+    }
+
+    if (EfiCompareDevicePath (RootPortPath, PciDevicePath)) {
+      //
+      // the given PCI device is the primary root port itself
+      //
+      *PciFeaturesConfigTable = Temp->PciExFeaturesConfigurationTable;
+      return EFI_SUCCESS;
+    }
+    //
+    // check this PCI device belongs to the primary root port of the root bridge
+    // any child PCI device will have the same initial device path nodes  as
+    // its parent root port
+    //
+    while (!IsDevicePathEnd (RootPortPath)){
+
+      if (DevicePathNodeLength (RootPortPath) != DevicePathNodeLength (PciDevicePath)) {
+        //
+        // break to check the next primary root port nodes as does not match
+        //
+        NodeMatch = FALSE;
+        break;
+      }
+      if (CompareMem (RootPortPath, PciDevicePath, DevicePathNodeLength (RootPortPath)) != 0) {
+        //
+        // node does not match, break to check next node
+        //
+        NodeMatch = FALSE;
+        break;
+      }
+      NodeMatch = TRUE;
+      //
+      // advance to next node
+      //
+      RootPortPath = NextDevicePathNode (RootPortPath);
+      PciDevicePath = NextDevicePathNode (PciDevicePath);
+    }
+
+    if (NodeMatch == TRUE) {
+      //
+      // device belongs to primary root port, return its PCI feature configuration
+      // table
+      //
+      *PciFeaturesConfigTable = Temp->PciExFeaturesConfigurationTable;
+      return EFI_SUCCESS;
+    }
+
+    //
+    // advance to next Root port node
+    //
+    Link = Link->ForwardLink;
+  } while (Link != &mRootBridgeDeviceList && Link != NULL);
+  //
+  // the PCI device must be RCiEP, does not belong to any primary root port
+  //
+  *PciFeaturesConfigTable = NULL;
+  return EFI_SUCCESS;
+}
+
+/**
+  helper routine to dump the PCIe Device Port Type
+**/
+VOID
+DumpDevicePortType (
+  IN  UINT8   DevicePortType
+  )
+{
+  switch (DevicePortType){
+    case PCIE_DEVICE_PORT_TYPE_PCIE_ENDPOINT:
+      DEBUG (( DEBUG_INFO, "PCIe endpoint found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_LEGACY_PCIE_ENDPOINT:
+      DEBUG (( DEBUG_INFO, "legacy PCI endpoint found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_ROOT_PORT:
+      DEBUG (( DEBUG_INFO, "PCIe Root Port found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT:
+      DEBUG (( DEBUG_INFO, "PCI switch upstream port found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT:
+      DEBUG (( DEBUG_INFO, "PCI switch downstream port found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_PCIE_TO_PCI_BRIDGE:
+      DEBUG (( DEBUG_INFO, "PCIe-PCI bridge found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_PCI_TO_PCIE_BRIDGE:
+      DEBUG (( DEBUG_INFO, "PCI-PCIe bridge found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_INTEGRATED_ENDPOINT:
+      DEBUG (( DEBUG_INFO, "RCiEP found\n"));
+      break;
+    case PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_EVENT_COLLECTOR:
+      DEBUG (( DEBUG_INFO, "RC Event Collector found\n"));
+      break;
+  }
+}
+
+/**
+   Setup each PCI device as per the pltaform's device-specific policy, in accordance
+   with PCI Express Base specification.
+
+  @param RootBridge             A pointer to the PCI_IO_DEVICE.
+
+  @retval EFI_SUCCESS           processing each PCI feature as per policy defined
+                                was successful.
+ **/
+EFI_STATUS
+SetupDevicePciExpressFeatures (
+  IN  PCI_IO_DEVICE                           *PciDevice,
+  IN  PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciConfigPhase
+  )
+{
+  EFI_STATUS                              Status;
+  PCI_REG_PCIE_CAPABILITY                 PcieCap;
+  PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE  *PciExpressFeaturesConfigTable;
+
+  PciExpressFeaturesConfigTable = NULL;
+  Status = GetPciExpressFeaturesConfigurationTable (PciDevice, &PciExpressFeaturesConfigTable);
+
+  if (PciConfigPhase == PciExpressFeatureSetupPhase) {
+    DEBUG_CODE (
+      if (EFI_ERROR( Status)) {
+        DEBUG ((
+          DEBUG_WARN,
+          "[Cfg group: 0 {error in dev path}]"
+          ));
+      } else if (PciExpressFeaturesConfigTable == NULL) {
+        DEBUG ((
+          DEBUG_INFO,
+          "[Cfg group: 0]"
+          ));
+      } else {
+        DEBUG ((
+          DEBUG_INFO,
+          "[Cfg group: %d]",
+          PciExpressFeaturesConfigTable->ID
+          ));
+      }
+      PcieCap.Uint16 = PciDevice->PciExpressCapabilityStructure.Capability.Uint16;
+      DumpDevicePortType ((UINT8)PcieCap.Bits.DevicePortType);
+    );
+
+    //
+    // get the device-specific platform policy for the PCI Express features
+    //
+    Status = PciExpressPlatformGetDevicePolicy (PciDevice);
+    if (EFI_ERROR(Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "Error in obtaining PCI device policy!!!\n"
+        ));
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "["));
+
+  Status = DispatchPciExpressInitializationFunctions (
+            PciDevice,
+            PciConfigPhase,
+            PciExpressFeaturesConfigTable
+            );
+
+  DEBUG ((DEBUG_INFO, "]\n"));
+  return Status;
+}
+
+/**
+  Create and append a node of type BRIDGE_DEVICE_NODE in the list for the primary
+  Root Port so that all its child PCI devices can be identified against the PCI
+  features configuration table group ID, of type PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE.
+
+  @param BridgePort    A pointer to the PCI_IO_DEVICE
+  @param PortNumber    A UINTN value to identify the PCI feature configuration
+                       table group
+
+  @retval EFI_SUCCESS           success in adding a node of BRIDGE_DEVICE_NODE
+                                to the list
+          EFI_OUT_OF_RESOURCES  unable to get memory for creating the node
+**/
+EFI_STATUS
+CreatePciRootBridgeDeviceNode (
+  IN  PCI_IO_DEVICE           *BridgePort,
+  IN  UINTN                   PortNumber
+  )
+{
+  BRIDGE_DEVICE_NODE                        *RootBridgeNode = NULL;
+  PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE  *PciConfigTable = NULL;
+
+  RootBridgeNode = AllocateZeroPool (sizeof (BRIDGE_DEVICE_NODE));
+  if (RootBridgeNode == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  RootBridgeNode->Signature                     = PCI_ROOT_BRIDGE_DEVICE_SIGNATURE;
+  RootBridgeNode->RootBridgeDevicePath          = BridgePort->DevicePath;
+  PciConfigTable = AllocateZeroPool (
+                     sizeof (PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE)
+                     );
+  if (PciConfigTable) {
+    PciConfigTable->ID                          = PortNumber;
+  }
+
+  RootBridgeNode->PciExFeaturesConfigurationTable  = PciConfigTable;
+
+  InsertTailList (&mRootBridgeDeviceList, &RootBridgeNode->NextRootBridgeDevice);
+
+  if (PciConfigTable == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Scan all the nodes of the RootBridge to identify and create a separate list
+  of all primary physical PCI root ports and link each with its own instance of
+  the PCI Feature Configuration Table.
+
+  @param  RootBridge    A pointer to the PCI_IO_DEVICE of the PCI Root Bridge
+
+  @retval EFI_OUT_OF_RESOURCES  unable to allocate buffer to store PCI feature
+                                configuration table for all the physical PCI root
+                                ports given
+          EFI_NOT_FOUND         No PCI Bridge device found
+          EFI_SUCCESS           PCI Feature COnfiguration table created for all
+                                the PCI Rooot ports found
+          EFI_INVALID_PARAMETER invalid parameter passed to the routine which
+                                creates the PCI controller node for the primary
+                                Root post list
+**/
+EFI_STATUS
+CreatePciRootBridgeDeviceList (
+  IN  PCI_IO_DEVICE           *RootBridge
+  )
+{
+  EFI_STATUS              Status = EFI_NOT_FOUND;
+  LIST_ENTRY              *Link;
+  PCI_IO_DEVICE           *Device;
+  UINTN                   BridgeDeviceCount;
+
+  BridgeDeviceCount = 0;
+  for ( Link = RootBridge->ChildList.ForwardLink
+      ; Link != &RootBridge->ChildList
+      ; Link = Link->ForwardLink
+  ) {
+    Device = PCI_IO_DEVICE_FROM_LINK (Link);
+    if (!DeviceExist (Device)) {
+      continue;
+    }
+    if (IS_PCI_BRIDGE (&Device->Pci)) {
+      BridgeDeviceCount++;
+      DEBUG ((
+        DEBUG_INFO,
+        "#%d ::Bridge [%02x|%02x|%02x]",
+        BridgeDeviceCount, Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber
+        ));
+      //
+      // create a list of bridge devices if that is connected to any other device
+      //
+      if (!IsListEmpty (&Device->ChildList)) {
+        DEBUG ((
+          DEBUG_INFO,
+          "- has downstream device!\n"
+          ));
+        Status = CreatePciRootBridgeDeviceNode (Device, BridgeDeviceCount);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((
+            DEBUG_ERROR,
+            "PCI configuration table allocation failure for #%d ::Bridge [%02x|%02x|%02x]\n",
+            BridgeDeviceCount, Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber
+            ));
+        }
+      } else {
+        DEBUG ((
+          DEBUG_INFO,
+          "- no downstream device!\n"
+          ));
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Initialize the device's PCI Express features, in a staged manner
+  @param  PciDevice             A pointer to the PCI_IO_DEVICE.
+
+  @retval EFI_SUCCESS           initializing all the nodes of the root bridge
+                                instances were successfull.
+**/
+EFI_STATUS
+InitializeDevicePciExpressFeatures (
+  IN  PCI_IO_DEVICE                           *PciDevice,
+  IN  PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciConfigPhase
+  )
+{
+  EFI_STATUS            Status;
+
+  switch (PciConfigPhase) {
+    case PciExpressFeatureSetupPhase:
+    case PciExpressFeatureEntendedSetupPhase:
+    case PciExpressFeatureProgramPhase:
+      Status = SetupDevicePciExpressFeatures (PciDevice, PciConfigPhase);
+      break;
+    case PciExpressFeatureEndPhase:
+      Status = PciExpressPlatformNotifyDeviceState (PciDevice);
+      break;
+  }
+  return Status;
+}
+
+/**
+  Traverse all the nodes from the root bridge or PCI-PCI bridge instance, to
+  configure the PCI Express features as per the PCI Express Base Secification
+  by considering its device-specific platform policy, and its device capability,
+  as applicable.
+
+  @param RootBridge             A pointer to the PCI_IO_DEVICE.
+
+  @retval EFI_SUCCESS           Traversing all the nodes of the root bridge
+                                instances were successfull.
+**/
+EFI_STATUS
+InitializePciExpressFeatures (
+  IN  PCI_IO_DEVICE                           *RootBridge,
+  IN  PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciConfigPhase
+  )
+{
+  EFI_STATUS            Status;
+  LIST_ENTRY            *Link;
+  PCI_IO_DEVICE         *Device;
+
+  for ( Link = RootBridge->ChildList.ForwardLink
+      ; Link != &RootBridge->ChildList
+      ; Link = Link->ForwardLink
+  ) {
+    Device = PCI_IO_DEVICE_FROM_LINK (Link);
+    if (!DeviceExist (Device)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "::Device [%02x|%02x|%02x] - does not exist!!!\n",
+        Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber
+        ));
+      continue;
+    }
+    if (IS_PCI_BRIDGE (&Device->Pci)) {
+      DEBUG ((
+        DEBUG_INFO,
+        "::Bridge [%02x|%02x|%02x] -",
+        Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber
+        ));
+      if (Device->IsPciExp) {
+        Status = InitializeDevicePciExpressFeatures (
+                  Device,
+                  PciConfigPhase
+                  );
+      } else {
+        DEBUG ((
+          DEBUG_INFO,
+          "Not a PCIe capable device!\n"
+          ));
+        //
+        // PCI Bridge which does not have PCI Express Capability structure
+        // cannot process this kind of PCI Bridge device
+        //
+      }
+
+      InitializePciExpressFeatures (Device, PciConfigPhase);
+    } else {
+      DEBUG ((
+        DEBUG_INFO,
+        "::Device [%02x|%02x|%02x] -",
+        Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber
+        ));
+      if (Device->IsPciExp) {
+        Status = InitializeDevicePciExpressFeatures (
+                  Device,
+                  PciConfigPhase
+                  );
+      } else {
+        DEBUG ((
+          DEBUG_INFO,
+          "Not a PCIe capable device!\n"
+          ));
+        //
+        // PCI Device which does not have PCI Express Capability structure
+        // cannot process this kind of PCI device
+        //
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enumerate all the nodes of the specified root bridge or PCI-PCI Bridge, to
+  configure the other PCI features.
+
+  @param RootBridge          A pointer to the PCI_IO_DEVICE.
+
+  @retval EFI_SUCCESS           The other PCI features configuration during enumeration
+                                of all the nodes of the PCI root bridge instance were
+                                programmed in PCI-compliance pattern along with the
+                                device-specific policy, as applicable.
+  @retval EFI_UNSUPPORTED       One of the override operation maong the nodes of
+                                the PCI hierarchy resulted in a incompatible address
+                                range.
+  @retval EFI_INVALID_PARAMETER The override operation is performed with invalid input
+                                parameters.
+**/
+EFI_STATUS
+EnumeratePciExpressFeatures (
+  IN EFI_HANDLE             Controller,
+  IN PCI_IO_DEVICE          *RootBridge
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 PciExpressFeatureConfigPhase;
+
+  if (!IsPciExpressFeatureConfigurationRequired ()) {
+    //
+    // exit as agreement is not reached with platform to configure the PCI
+    // Express features
+    //
+    return EFI_SUCCESS;
+  }
+  mRootBridgeHandle = Controller;
+
+  DEBUG_CODE (
+    CHAR16                *Str;
+    Str = ConvertDevicePathToText (
+            DevicePathFromHandle (RootBridge->Handle),
+            FALSE,
+            FALSE
+            );
+    DEBUG ((
+      DEBUG_INFO,
+      "Enumerating PCI features for Root Bridge %s\n",
+      Str != NULL ? Str : L""
+      ));
+
+    if (Str != NULL) {
+      FreePool (Str);
+    }
+  );
+
+  for ( PciExpressFeatureConfigPhase = PciExpressFeaturePreProcessPhase
+      ; PciExpressFeatureConfigPhase <= PciExpressFeatureEndPhase
+      ; PciExpressFeatureConfigPhase++
+      ) {
+    DEBUG ((
+      DEBUG_INFO,
+      "<<********** Phase [%d]**********>>\n",
+      PciExpressFeatureConfigPhase
+      ));
+    if (PciExpressFeatureConfigPhase == PciExpressFeaturePreProcessPhase) {
+      //
+      // create a list of root bridge devices (root ports) of the root complex
+      // if extra setup phase required
+      //
+      if (IsPciExpressFeatureExtendedSetupRequired ()) {
+        CreatePciRootBridgeDeviceList (RootBridge);
+      }
+      continue;
+    }
+    if (PciExpressFeatureConfigPhase == PciExpressFeatureEntendedSetupPhase) {
+      if (!IsPciExpressFeatureExtendedSetupRequired ()) {
+        //
+        // since the PCI Express features require no extra initialization steps
+        // skip this phase
+        //
+        continue;
+      }
+    }
+    //
+    // setup the PCI Express features
+    //
+    Status = InitializePciExpressFeatures (RootBridge, PciExpressFeatureConfigPhase);
+
+    if (PciExpressFeatureConfigPhase == PciExpressFeatureEndPhase) {
+      //
+      // clean up the temporary resource nodes created for this root bridge
+      //
+      if (IsPciExpressFeatureExtendedSetupRequired ()) {
+        DestroyRootBridgeDeviceNodes ();
+      }
+    }
+  }
+
+  return Status;
+}
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h
new file mode 100644
index 0000000..2eff8aa
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h
@@ -0,0 +1,226 @@
+/** @file
+  PCI standard feature support functions implementation for PCI Bus module..
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_FEATURES_SUPPORT_H_
+#define _EFI_PCI_FEATURES_SUPPORT_H_
+
+extern  EFI_HANDLE                                  mRootBridgeHandle;
+extern  EFI_PCI_EXPRESS_PLATFORM_POLICY             mPciExpressPlatformPolicy;
+//
+// defines the data structure to hold the details of the PCI Root port devices
+//
+typedef struct _BRIDGE_DEVICE_NODE  BRIDGE_DEVICE_NODE;
+
+//
+// defines the data structure to hold the configuration data for the other PCI
+// features
+//
+typedef struct _PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE  PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE;
+
+//
+// define the data type for the PCI feature policy support
+//
+typedef struct _PCI_FEATURE_POLICY  PCI_FEATURE_POLICY;
+
+//
+// Signature value for the PCI Root Port node
+//
+#define PCI_ROOT_BRIDGE_DEVICE_SIGNATURE               SIGNATURE_32 ('p', 'c', 'i', 'p')
+
+//
+// Definitions of the PCI Root Port data structure members
+//
+struct _BRIDGE_DEVICE_NODE {
+  //
+  // Signature header
+  //
+  UINT32                                    Signature;
+  //
+  // linked list pointers to next node
+  //
+  LIST_ENTRY                                NextRootBridgeDevice;
+  //
+  // pointer to PCI_IO_DEVICE of the primary PCI Controller device
+  //
+  EFI_DEVICE_PATH_PROTOCOL                  *RootBridgeDevicePath;
+  //
+  // pointer to the corresponding PCI Express feature configuration Table node
+  // all the child PCI devices of the controller are aligned based on this table
+  //
+  PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE  *PciExFeaturesConfigurationTable;
+};
+
+#define ROOT_BRIDGE_DEVICE_NODE_FROM_LINK(a) \
+  CR (a, BRIDGE_DEVICE_NODE, NextRootBridgeDevice, PCI_ROOT_BRIDGE_DEVICE_SIGNATURE)
+
+//
+// Definition of the PCI Feature configuration Table members
+//
+struct _PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE {
+  //
+  // Configuration Table ID
+  //
+  UINTN                                     ID;
+};
+
+//
+// Declaration of the internal sub-phases during enumeration to configure the PCI
+// Express features
+//
+typedef enum {
+  //
+  // preprocessing applicable only to few PCI Express features to bind all devices
+  // under the common root bridge device (root port), that would be useful to align
+  // all devices with a common value. This would be optional phase based on the
+  // type of the PCI Express feature to be programmed based on platform policy
+  //
+  PciExpressFeaturePreProcessPhase,
+
+  //
+  // mandatory phase to setup the PCI Express feature to its applicable attribute,
+  // based on its device-specific platform policies, matching with its device capabilities
+  //
+  PciExpressFeatureSetupPhase,
+
+  //
+  // optional phase primarily to align all devices, specially required when PCI
+  // switch is present in the hierarchy, applicable to certain few PCI Express
+  // features only
+  //
+  PciExpressFeatureEntendedSetupPhase,
+
+  //
+  // mandatory programming phase to complete the configuration of the PCI Express
+  // features
+  //
+  PciExpressFeatureProgramPhase,
+
+  //
+  // optional phase to clean up temporary buffers, like those that were prepared
+  // during the preprocessing phase above
+  //
+  PciExpressFeatureEndPhase
+
+}PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE;
+
+//
+// declaration for the data type to harbor the PCI feature policies
+//
+struct  _PCI_FEATURE_POLICY {
+  //
+  // if set, it indicates the feature should be enabled
+  // if clear, it indicates the feature should be disabled
+  //
+  UINT8   Act : 1;
+  //
+  // this field will be specific to feature, it can be implementation specific
+  // or it can be reserved and remain unused
+  //
+  UINT8   Support : 6;
+  //
+  // if set indicates override the feature policy defined by the members above
+  // if clear it indicates that this feature policy should be ignored completely
+  // this means the above two members should not be used
+  //
+  UINT8   Override : 1;
+};
+
+//
+// Declaration of the PCI Express features unique Id
+//
+typedef enum {
+  //
+  // support for PCI Express feature - Max. Payload Size
+  //
+  PciExpressMps,
+  //
+  // support for PCI Express feature - Max. Read Request Size
+  //
+  PciExpressMrrs,
+  //
+  // support for PCI Express feature - Extended Tag
+  //
+  PciExpressExtTag,
+  //
+  // support for PCI Express feature - Relax Order
+  //
+  PciExpressRelaxOrder,
+  //
+  // support for PCI Express feature - No-Snoop
+  //
+  PciExpressNoSnoop,
+  //
+  // support for PCI Express feature - ASPM state
+  //
+  PciExpressAspm,
+  //
+  // support for PCI Express feature - Common Clock Configuration
+  //
+  PciExpressCcc,
+  //
+  // support for PCI Express feature - Extended Sync
+  //
+  PciExpressExtSync,
+  //
+  // support for PCI Express feature - Atomic Op
+  //
+  PciExpressAtomicOp,
+  //
+  // support for PCI Express feature - LTR
+  //
+  PciExpressLtr,
+  //
+  // support for PCI Express feature - PTM
+  //
+  PciExpressPtm,
+  //
+  // support for PCI Express feature - Completion Timeout
+  //
+  PciExpressCto,
+  //
+  // support for PCI Express feature - Clock Power Management
+  //
+  PciExpressCpm,
+  //
+  // support for PCI Express feature - L1 PM Substates
+  //
+  PciExpressL1PmSubstates
+
+} PCI_EXPRESS_FEATURE_ID;
+
+//
+// PCI Express feature configuration routine during initialization phases
+//
+typedef
+EFI_STATUS
+(*PCI_EXPRESS_FEATURE_CONFIGURATION_ROUTINE) (
+  IN PCI_IO_DEVICE                            *PciDevice,
+  IN VOID                                     *PciExpressFeatureConfiguration
+  );
+
+//
+// data type for the PCI Express feature initialization phases
+//
+typedef struct {
+  //
+  // Pci Express feature configuration phase
+  //
+  PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE   PciExpressFeatureConfigurationPhase;
+  //
+  // PCI Express feature Id
+  //
+  PCI_EXPRESS_FEATURE_ID                    PciExpressFeatureId;
+  //
+  // PCI Express feature configuration routine
+  //
+  PCI_EXPRESS_FEATURE_CONFIGURATION_ROUTINE PciExpressFeatureConfigurationRoutine;
+
+}PCI_EXPRESS_FEATURE_INITIALIZATION_POINT;
+
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c
new file mode 100644
index 0000000..31c675d
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c
@@ -0,0 +1,302 @@
+/** @file
+  This file encapsulate the usage of PCI Platform Protocol
+
+  This file define the necessary hooks used to obtain the platform
+  level data and policies which could be used in the PCI Enumeration phases
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+
+EFI_PCI_EXPRESS_PLATFORM_PROTOCOL             *mPciExPlatformProtocol;
+EFI_PCI_EXPRESS_OVERRIDE_PROTOCOL             *mPciExOverrideProtocol;
+
+
+/**
+  This function retrieves the PCI Express Platform Protocols published by platform
+  @retval EFI_STATUS          direct return status from the LocateProtocol ()
+                              boot service for the PCI Express Override Protocol
+          EFI_SUCCESS         The PCI Express Platform Protocol is found
+**/
+EFI_STATUS
+GetPciExpressProtocol (
+  )
+{
+  EFI_STATUS  Status;
+
+  if (mPciExPlatformProtocol) {
+    //
+    // the PCI Express Platform Protocol is already initialized
+    //
+    return EFI_SUCCESS;
+  }
+  if (mPciExOverrideProtocol) {
+    //
+    // the PCI Express Override Protocol is already initialized
+    //
+    return EFI_SUCCESS;
+  }
+  //
+  // locate the PCI Express Platform Protocol
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiPciExpressPlatformProtocolGuid,
+                  NULL,
+                  (VOID **) &mPciExPlatformProtocol
+                  );
+  if (!EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // If PCI Express Platform protocol doesn't exist, try to get the Pci Express
+  // Override Protocol.
+  //
+  return gBS->LocateProtocol (
+                &gEfiPciExpressOverrideProtocolGuid,
+                NULL,
+                (VOID **) &mPciExOverrideProtocol
+                );
+}
+
+/**
+  This function indicates that the platform has published the PCI Express Platform
+  Protocol (or PCI Express Override Protocol) to indicate that this driver can
+  initialize the PCI Express features.
+  @retval     TRUE or FALSE
+**/
+BOOLEAN
+IsPciExpressProtocolPresent (
+  )
+{
+  if (
+      mPciExPlatformProtocol == NULL
+      && mPciExOverrideProtocol == NULL
+      ) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+
+/**
+  Generic routine to setup the PCI features as per its predetermined defaults.
+**/
+VOID
+SetupDefaultPciExpressDevicePolicy (
+  IN  PCI_IO_DEVICE               *PciDevice
+  )
+{
+
+}
+
+/**
+  initialize the device policy data members
+**/
+VOID
+InitializeDevicePolicyData (
+  IN EFI_PCI_EXPRESS_DEVICE_POLICY  *PciExpressDevicePolicy
+  )
+{
+  UINTN     length;
+  UINT8     *PciExpressPolicy;
+  UINT8     *PciExDevicePolicy;
+
+
+  ZeroMem (PciExpressDevicePolicy, sizeof (EFI_PCI_EXPRESS_DEVICE_POLICY));
+
+  for (
+      length = 0
+      , PciExpressPolicy = (UINT8*)&mPciExpressPlatformPolicy
+      , PciExDevicePolicy = (UINT8*)PciExpressDevicePolicy
+      ; length < sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY)
+      ; length++
+      ) {
+    if (!PciExpressPolicy[length]) {
+      PciExDevicePolicy[length] = EFI_PCI_EXPRESS_NOT_APPLICABLE;
+    }
+  }
+}
+
+/**
+  Intermediate routine to either get the PCI device specific platform policies
+  through the PCI Platform Protocol, or its alias the PCI Override Protocol.
+
+  @param  PciDevice           A pointer to PCI_IO_DEVICE
+  @param  PciPlatformProtocol A pointer to EFI_PCI_EXPRESS_PLATFORM_PROTOCOL
+
+  @retval EFI_STATUS          The direct status from the PCI Platform Protocol
+  @retval EFI_SUCCESS         if on returning predetermined PCI features defaults,
+                              for the case when protocol returns as EFI_UNSUPPORTED
+                              to indicate PCI device exist and it has no platform
+                              policy defined.
+**/
+EFI_STATUS
+GetPciExpressDevicePolicy (
+  IN  PCI_IO_DEVICE                     *PciDevice,
+  IN  EFI_PCI_EXPRESS_PLATFORM_PROTOCOL *PciPlatformProtocol
+  )
+{
+  EFI_PCI_EXPRESS_DEVICE_POLICY               PciExpressDevicePolicy;
+  EFI_STATUS                                  Status;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress;
+
+  PciAddress.Bus = PciDevice->BusNumber;
+  PciAddress.Device = PciDevice->DeviceNumber;
+  PciAddress.Function = PciDevice->FunctionNumber;
+  PciAddress.Register = 0;
+  PciAddress.ExtendedRegister = 0;
+
+  InitializeDevicePolicyData (&PciExpressDevicePolicy);
+  Status = PciPlatformProtocol->GetDevicePolicy (
+                                  PciPlatformProtocol,
+                                  mRootBridgeHandle,
+                                  PciAddress,
+                                  sizeof (EFI_PCI_EXPRESS_DEVICE_POLICY),
+                                  &PciExpressDevicePolicy
+                                  );
+  if (!EFI_ERROR(Status)) {
+    //
+    // platform chipset policies are returned for this PCI device
+    //
+
+
+    DEBUG ((
+      DEBUG_INFO,
+      "[device policy: platform]"
+      ));
+    return Status;
+  } else if (Status == EFI_UNSUPPORTED) {
+    //
+    // platform chipset policies are not provided for this PCI device
+    // let the enumeration happen as per the PCI standard way
+    //
+    SetupDefaultPciExpressDevicePolicy (PciDevice);
+    DEBUG ((
+      DEBUG_INFO,
+      "[device policy: default]"
+      ));
+    return EFI_SUCCESS;
+  }
+  DEBUG ((
+    DEBUG_ERROR,
+    "[device policy: none (error)]"
+    ));
+  return Status;
+}
+
+/**
+  Gets the PCI device-specific platform policy from the PCI Express Platform Protocol.
+  If no PCI Platform protocol is published than setup the PCI feature to predetermined
+  defaults, in order to align all the PCI devices in the PCI hierarchy, as applicable.
+
+  @param  PciDevice     A pointer to PCI_IO_DEVICE
+
+  @retval EFI_STATUS    The direct status from the PCI Platform Protocol
+  @retval EFI_SUCCESS   On return of predetermined PCI features defaults, for
+                        the case when protocol returns as EFI_UNSUPPORTED to
+                        indicate PCI device exist and it has no platform policy
+                        defined. Also, on returns when no PCI Platform Protocol
+                        exist.
+**/
+EFI_STATUS
+PciExpressPlatformGetDevicePolicy (
+  IN PCI_IO_DEVICE          *PciDevice
+  )
+{
+  if (mPciExPlatformProtocol != NULL) {
+    return GetPciExpressDevicePolicy (PciDevice, mPciExPlatformProtocol);
+  } else if (mPciExOverrideProtocol != NULL) {
+    return GetPciExpressDevicePolicy (PciDevice, mPciExOverrideProtocol);
+  } else {
+    //
+    // no protocol found, platform does not require the PCI Express initialization
+    //
+    return EFI_UNSUPPORTED;
+  }
+}
+
+/**
+  This function gets the platform requirement to initialize the list of PCI Express
+  features from the protocol definition supported.
+  This function should be called after the LocatePciPlatformProtocol.
+  @retval EFI_SUCCESS           return by platform to acknowledge the list of
+                                PCI Express feature to be configured
+                                (in mPciExpressPlatformPolicy)
+          EFI_INVALID_PARAMETER platform does not support the protocol arguements
+                                passed
+          EFI_UNSUPPORTED       platform did not published the protocol
+**/
+EFI_STATUS
+PciExpressPlatformGetPolicy (
+  )
+{
+  EFI_STATUS    Status;
+
+  if (mPciExPlatformProtocol) {
+    Status = mPciExPlatformProtocol->GetPolicy (
+                                      mPciExPlatformProtocol,
+                                      sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY),
+                                      &mPciExpressPlatformPolicy
+                                      );
+  } else if (mPciExOverrideProtocol) {
+    Status = mPciExOverrideProtocol->GetPolicy (
+                                      mPciExOverrideProtocol,
+                                      sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY),
+                                      &mPciExpressPlatformPolicy
+                                      );
+  } else {
+    //
+    // no protocol found, platform does not require the PCI Express initialization
+    //
+    return EFI_UNSUPPORTED;
+  }
+  return Status;
+}
+
+
+/**
+  Notifies the platform about the current PCI Express state of the device.
+
+  @param  PciDevice                 A pointer to PCI_IO_DEVICE
+  @param  PciExDeviceConfiguration  Pointer to EFI_PCI_EXPRESS_DEVICE_CONFIGURATION.
+                                    Used to pass the current state of device to
+                                    platform.
+
+  @retval EFI_STATUS        The direct status from the PCI Express Platform Protocol
+  @retval EFI_UNSUPPORTED   returns when the PCI Express Platform Protocol or its
+                            alias PCI Express OVerride Protocol is not present.
+**/
+EFI_STATUS
+PciExpressPlatformNotifyDeviceState (
+  IN PCI_IO_DEVICE                        *PciDevice
+  )
+{
+  EFI_PCI_EXPRESS_DEVICE_CONFIGURATION      PciExDeviceConfiguration;
+
+
+  if (mPciExPlatformProtocol != NULL) {
+    return mPciExPlatformProtocol->NotifyDeviceState (
+                                    mPciExPlatformProtocol,
+                                    PciDevice->Handle,
+                                    sizeof (EFI_PCI_EXPRESS_DEVICE_CONFIGURATION),
+                                    &PciExDeviceConfiguration
+                                    );
+  } else if (mPciExOverrideProtocol != NULL) {
+    return mPciExOverrideProtocol->NotifyDeviceState (
+                                    mPciExOverrideProtocol,
+                                    PciDevice->Handle,
+                                    sizeof (EFI_PCI_EXPRESS_DEVICE_CONFIGURATION),
+                                    &PciExDeviceConfiguration
+                                    );
+  } else {
+    //
+    // unexpected error
+    //
+    return EFI_UNSUPPORTED;
+  }
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h
new file mode 100644
index 0000000..4283b81
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h
@@ -0,0 +1,87 @@
+/** @file
+  This file encapsulate the usage of PCI Platform Protocol
+
+  This file define the necessary hooks used to obtain the platform
+  level data and policies which could be used in the PCI Enumeration phases
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _EFI_PCI_PLATFORM_SUPPORT_H_
+#define _EFI_PCI_PLATFORM_SUPPORT_H_
+
+
+/**
+  This function retrieves the PCI Express Platform Protocols published by platform
+  @retval EFI_STATUS          direct return status from the LocateProtocol ()
+                              boot service for the PCI Express Override Protocol
+          EFI_SUCCESS         The PCI Express Platform Protocol is found
+**/
+EFI_STATUS
+GetPciExpressProtocol (
+  );
+
+/**
+  This function indicates that the platform has published the PCI Express Platform
+  Protocol (or PCI Express Override Protocol) to indicate that this driver can
+  initialize the PCI Express features.
+  @retval     TRUE or FALSE
+**/
+BOOLEAN
+IsPciExpressProtocolPresent (
+  );
+
+/**
+  This function gets the platform requirement to initialize the list of PCI Express
+  features from the protocol definition supported.
+  This function should be called after the LocatePciPlatformProtocol.
+  @retval EFI_SUCCESS           return by platform to acknowledge the list of
+                                PCI Express feature to be configured
+                                (in mPciExpressPlatformPolicy)
+          EFI_INVALID_PARAMETER platform does not support the protocol arguements
+                                passed
+          EFI_UNSUPPORTED       platform did not published the protocol
+**/
+EFI_STATUS
+PciExpressPlatformGetPolicy (
+  );
+
+/**
+  Gets the PCI device-specific platform policy from the PCI Platform Protocol.
+  If no PCI Platform protocol is published than setup the PCI feature to predetermined
+  defaults, in order to align all the PCI devices in the PCI hierarchy, as applicable.
+
+  @param  PciDevice     A pointer to PCI_IO_DEVICE
+
+  @retval EFI_STATUS    The direct status from the PCI Platform Protocol
+  @retval EFI_SUCCESS   On return of predetermined PCI features defaults, for
+                        the case when protocol returns as EFI_UNSUPPORTED to
+                        indicate PCI device exist and it has no platform policy
+                        defined. Also, on returns when no PCI Platform Protocol
+                        exist.
+**/
+EFI_STATUS
+PciExpressPlatformGetDevicePolicy (
+  IN PCI_IO_DEVICE          *PciDevice
+  );
+
+/**
+  Notifies the platform about the current PCI Express state of the device.
+
+  @param  PciDevice                 A pointer to PCI_IO_DEVICE
+  @param  PciExDeviceConfiguration  Pointer to EFI_PCI_EXPRESS_DEVICE_CONFIGURATION.
+                                    Used to pass the current state of device to
+                                    platform.
+
+  @retval EFI_STATUS        The direct status from the PCI Express Platform Protocol
+  @retval EFI_UNSUPPORTED   returns when the PCI Express Platform Protocol or its
+                            alias PCI Express OVerride Protocol is not present.
+**/
+EFI_STATUS
+PciExpressPlatformNotifyDeviceState (
+  IN PCI_IO_DEVICE                        *PciDevice
+  );
+#endif
-- 
2.21.0.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#54064): https://edk2.groups.io/g/devel/message/54064
Mute This Topic: https://groups.io/mt/71063071/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-