[edk2-devel] [edk2-platforms][PATCH v2 16/32] AmpereAltraPkg: Add PciHostBridge driver

Leif Lindholm leif at nuviainc.com
Tue Jun 8 22:26:46 UTC 2021


Hi Nhi,

This is the only patch in the series I have not yet reviewed. And it's
because it's massive.
I can't usefully review whether this is correct or not, but I presume
it has been well tested.
I do have some concerns again with regards to driver-local constructs
being given names that identify them as part of an industry standard.

I have no further comments on this set, and look forward to v3.

Best Regards,

Leif

On Wed, May 26, 2021 at 17:07:08 +0700, Nhi Pham wrote:
> From: Vu Nguyen <vunguyen at os.amperecomputing.com>
> 
> The roles of this driver:
> * Consume PcieCoreLib to initialize all enable PCIe controllers.
> * Produce neccessary protocols like RootBridgeIo an ResourceAllocation
>   which will be used later by PciBus.
> 
> 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/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf |   56 +
>  Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h      |  451 ++++++
>  Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.h    |  554 +++++++
>  Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c      | 1419 ++++++++++++++++++
>  Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c    | 1582 ++++++++++++++++++++
>  5 files changed, 4062 insertions(+)
> 
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> new file mode 100755
> index 000000000000..5b67d61926c7
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> @@ -0,0 +1,56 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = PciHostBridgeDxe
> +  FILE_GUID                      = D7ABBD62-2E03-11E8-B467-0ED5F89F718B
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = InitializePciHostBridge
> +
> +[Sources]
> +  PciHostBridge.c
> +  PciHostBridge.h
> +  PciRootBridgeIo.c
> +  PciRootBridgeIo.h
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  ArmPlatformPkg/ArmPlatformPkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +
> +[LibraryClasses]
> +  AcpiHelperLib
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  DevicePathLib
> +  DxeServicesTableLib
> +  IoLib
> +  MemoryAllocationLib
> +  PcdLib
> +  PcieCoreLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +
> +[Protocols]
> +  gEfiPciHostBridgeResourceAllocationProtocolGuid
> +  gEfiPciRootBridgeIoProtocolGuid
> +  gEfiMetronomeArchProtocolGuid
> +  gEfiDevicePathProtocolGuid
> +
> +[FixedPcd]
> +  gArmTokenSpaceGuid.PcdSystemMemoryBase
> +
> +[Depex]
> +  gEfiMetronomeArchProtocolGuid
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
> new file mode 100644
> index 000000000000..ab62ebf3c3ef
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
> @@ -0,0 +1,451 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PCI_HOST_BRIDGE_H_
> +#define PCI_HOST_BRIDGE_H_
> +
> +#include <IndustryStandard/Acpi.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DxeServicesTableLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PciHostBridgeLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/Metronome.h>
> +#include <Protocol/PciHostBridgeResourceAllocation.h>
> +#include <Protocol/PciRootBridgeIo.h>
> +
> +#undef PCIE_PLATFORM_DEBUG
> +#undef PCIE_MMIO_DEBUG
> +
> +#ifdef PCIE_PLATFORM_DEBUG
> +#define PCIE_DEBUG(arg...)       DEBUG((DEBUG_INFO,"PCIHostBridge: "));DEBUG((DEBUG_INFO,## arg))
> +#else
> +#define PCIE_DEBUG(arg...)
> +#endif
> +
> +#ifdef PCIE_MMIO_DEBUG
> +#define PCIE_MMIO_DEBUG(arg...)       DEBUG((DEBUG_INFO,"PCIRootBridge: "));DEBUG((DEBUG_INFO,## arg))
> +#else
> +#define PCIE_MMIO_DEBUG(arg...)
> +#endif
> +
> +#define PCIE_WARN(arg...)        DEBUG((DEBUG_WARN,"PCIHostBridge (WARN): "));DEBUG((DEBUG_WARN,## arg))
> +#define PCIE_ERR(arg...)         DEBUG((DEBUG_ERROR,"PCIHostBridge (ERROR): "));DEBUG((DEBUG_ERROR,## arg))
> +
> +#define PCI_HOST_BRIDGE_SIGNATURE  SIGNATURE_32('e', 'h', 's', 't')
> +#define PCI_ROOT_BRIDGE_SIGNATURE  SIGNATURE_32('e', '2', 'p', 'b')
> +
> +#define PCI_HOST_BRIDGE_FROM_THIS(a) \
> +  CR (a, PCI_HOST_BRIDGE_INSTANCE, ResAlloc, PCI_HOST_BRIDGE_SIGNATURE)
> +
> +#define PCI_RESOURCE_LESS         0xFFFFFFFFFFFFFFFEULL
> +
> +//
> +// Driver Instance Data Macros
> +//
> +#define ROOT_BRIDGE_FROM_THIS(a) \
> +  CR (a, PCI_ROOT_BRIDGE_INSTANCE, RbIo, PCI_ROOT_BRIDGE_SIGNATURE)
> +
> +#define ROOT_BRIDGE_FROM_LINK(a) \
> +  CR (a, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_ROOT_BRIDGE_SIGNATURE)
> +
> +//
> +// PCI Resource Type
> +//
> +typedef enum {
> +  TypeIo    = 0,
> +  TypeMem32,
> +  TypePMem32,
> +  TypeMem64,
> +  TypePMem64,
> +  TypeBus,
> +  TypeMax
> +} PCI_RESOURCE_TYPE;
> +
> +//
> +// Type of Resource status
> +//
> +typedef enum {
> +  ResNone = 0,
> +  ResSubmitted,
> +  ResAllocated,
> +  ResStatusMax
> +} RES_STATUS;
> +
> +//
> +// Struct of Resource Node
> +//
> +typedef struct {
> +  PCI_RESOURCE_TYPE  Type;
> +  UINT64             Base;
> +  UINT64             Length;
> +  UINT64             Alignment;
> +  RES_STATUS         Status;
> +} PCI_RES_NODE;
> +
> +//
> +// Type of PCIE operation
> +//
> +typedef enum {
> +  IoOperation,
> +  MemOperation,
> +  PciOperation
> +} OPERATION_TYPE;
> +
> +//
> +// Struct of Device Mapping
> +//
> +typedef struct {
> +  ACPI_HID_DEVICE_PATH     AcpiDevicePath;
> +  EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
> +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
> +
> +//
> +// Struct of Root Bridge Instance
> +//
> +typedef struct {
> +  UINT32                          Signature;
> +  LIST_ENTRY                      Link;
> +  EFI_HANDLE                      RootBridgeHandle;
> +  UINT64                          RootBridgeAttrib;
> +  VOID                            *ConfigBuffer;
> +  PCI_RES_NODE                    ResAllocNode[TypeMax];
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL RbIo;
> +  PCI_ROOT_BRIDGE                 RootBridge;
> +} PCI_ROOT_BRIDGE_INSTANCE;
> +
> +//
> +// Struct of Mapping Info
> +//
> +typedef struct {
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation;
> +  UINTN                                     NumberOfBytes;
> +  UINTN                                     NumberOfPages;
> +  EFI_PHYSICAL_ADDRESS                      HostAddress;
> +  EFI_PHYSICAL_ADDRESS                      MappedHostAddress;
> +} MAP_INFO;
> +
> +//
> +// Struct of Host Bridge Instance
> +//
> +typedef struct {
> +  UINTN                                            Signature;
> +  EFI_HANDLE                                       HostBridgeHandle;
> +  UINTN                                            RootBridgeNumber;
> +  LIST_ENTRY                                       Head;
> +  BOOLEAN                                          ResourceSubmited;
> +  BOOLEAN                                          CanRestarted;
> +  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc;
> +} PCI_HOST_BRIDGE_INSTANCE;
> +
> +/**
> +   These are the notifications from the PCI bus driver that it is about to enter a certain
> +   phase of the PCI enumeration process.
> +
> +   This member function can be used to notify the host bridge driver to perform specific actions,
> +   including any chipset-specific initialization, so that the chipset is ready to enter the next phase.
> +   Eight notification points are defined at this time. See belows:
> +   EfiPciHostBridgeBeginEnumeration       Resets the host bridge PCI apertures and internal data
> +                                          structures. The PCI enumerator should issue this notification
> +                                          before starting a fresh enumeration process. Enumeration cannot
> +                                          be restarted after sending any other notification such as
> +                                          EfiPciHostBridgeBeginBusAllocation.
> +   EfiPciHostBridgeBeginBusAllocation     The bus allocation phase is about to begin. No specific action is
> +                                          required here. This notification can be used to perform any
> +                                          chipset-specific programming.
> +   EfiPciHostBridgeEndBusAllocation       The bus allocation and bus programming phase is complete. No
> +                                          specific action is required here. This notification can be used to
> +                                          perform any chipset-specific programming.
> +   EfiPciHostBridgeBeginResourceAllocation
> +                                          The resource allocation phase is about to begin. No specific
> +                                          action is required here. This notification can be used to perform
> +                                          any chipset-specific programming.
> +   EfiPciHostBridgeAllocateResources      Allocates resources per previously submitted requests for all the PCI
> +                                          root bridges. These resource settings are returned on the next call to
> +                                          GetProposedResources(). Before calling NotifyPhase() with a Phase of
> +                                          EfiPciHostBridgeAllocateResource, the PCI bus enumerator is responsible
> +                                          for gathering I/O and memory requests for
> +                                          all the PCI root bridges and submitting these requests using
> +                                          SubmitResources(). This function pads the resource amount
> +                                          to suit the root bridge hardware, takes care of dependencies between
> +                                          the PCI root bridges, and calls the Global Coherency Domain (GCD)
> +                                          with the allocation request. In the case of padding, the allocated range
> +                                          could be bigger than what was requested.
> +   EfiPciHostBridgeSetResources           Programs the host bridge hardware to decode previously allocated
> +                                          resources (proposed resources) for all the PCI root bridges. After the
> +                                          hardware is programmed, reassigning resources will not be supported.
> +                                          The bus settings are not affected.
> +   EfiPciHostBridgeFreeResources          Deallocates resources that were previously allocated for all the PCI
> +                                          root bridges and resets the I/O and memory apertures to their initial
> +                                          state. The bus settings are not affected. If the request to allocate
> +                                          resources fails, the PCI enumerator can use this notification to
> +                                          deallocate previous resources, adjust the requests, and retry
> +                                          allocation.
> +   EfiPciHostBridgeEndResourceAllocation  The resource allocation phase is completed. No specific action is
> +                                          required here. This notification can be used to perform any chipsetspecific
> +                                          programming.
> +
> +   @param[in] This                The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in] Phase               The phase during enumeration
> +
> +   @retval EFI_NOT_READY          This phase cannot be entered at this time. For example, this error
> +                                  is valid for a Phase of EfiPciHostBridgeAllocateResources if
> +                                  SubmitResources() has not been called for one or more
> +                                  PCI root bridges before this call
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware error. This error is valid
> +                                  for a Phase of EfiPciHostBridgeSetResources.
> +   @retval EFI_INVALID_PARAMETER  Invalid phase parameter
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +                                  This error is valid for a Phase of EfiPciHostBridgeAllocateResources if the
> +                                  previously submitted resource requests cannot be fulfilled or
> +                                  were only partially fulfilled.
> +   @retval EFI_SUCCESS            The notification was accepted without any errors.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NotifyPhase (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE    Phase
> +  );
> +
> +/**
> +   Return the device handle of the next PCI root bridge that is associated with this Host Bridge.
> +
> +   This function is called multiple times to retrieve the device handles of all the PCI root bridges that
> +   are associated with this PCI host bridge. Each PCI host bridge is associated with one or more PCI
> +   root bridges. On each call, the handle that was returned by the previous call is passed into the
> +   interface, and on output the interface returns the device handle of the next PCI root bridge. The
> +   caller can use the handle to obtain the instance of the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
> +   for that root bridge. When there are no more PCI root bridges to report, the interface returns
> +   EFI_NOT_FOUND. A PCI enumerator must enumerate the PCI root bridges in the order that they
> +   are returned by this function.
> +   For D945 implementation, there is only one root bridge in PCI host bridge.
> +
> +   @param[in]       This              The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in, out]  RootBridgeHandle  Returns the device handle of the next PCI root bridge.
> +
> +   @retval EFI_SUCCESS            If parameter RootBridgeHandle = NULL, then return the first Rootbridge handle of the
> +                                  specific Host bridge and return EFI_SUCCESS.
> +   @retval EFI_NOT_FOUND          Can not find the any more root bridge in specific host bridge.
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not an EFI_HANDLE that was
> +                                  returned on a previous call to GetNextRootBridge().
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextRootBridge (
> +  IN     EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN OUT EFI_HANDLE                                       *RootBridgeHandle
> +  );
> +
> +/**
> +   Returns the allocation attributes of a PCI root bridge.
> +
> +   The function returns the allocation attributes of a specific PCI root bridge. The attributes can vary
> +   from one PCI root bridge to another. These attributes are different from the decode-related
> +   attributes that are returned by the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.GetAttributes() member function. The
> +   RootBridgeHandle parameter is used to specify the instance of the PCI root bridge. The device
> +   handles of all the root bridges that are associated with this host bridge must be obtained by calling
> +   GetNextRootBridge(). The attributes are static in the sense that they do not change during or
> +   after the enumeration process. The hardware may provide mechanisms to change the attributes on
> +   the fly, but such changes must be completed before EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL is
> +   installed. The permitted values of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ATTRIBUTES are defined in
> +   "Related Definitions" below. The caller uses these attributes to combine multiple resource requests.
> +   For example, if the flag EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM is set, the PCI bus enumerator needs to
> +   include requests for the prefetchable memory in the nonprefetchable memory pool and not request any
> +   prefetchable memory.
> +      Attribute                                 Description
> +   ------------------------------------         ----------------------------------------------------------------------
> +   EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM         If this bit is set, then the PCI root bridge does not support separate
> +                                                windows for nonprefetchable and prefetchable memory. A PCI bus
> +                                                driver needs to include requests for prefetchable memory in the
> +                                                nonprefetchable memory pool.
> +
> +   EFI_PCI_HOST_BRIDGE_MEM64_DECODE             If this bit is set, then the PCI root bridge supports 64-bit memory
> +                                                windows. If this bit is not set, the PCI bus driver needs to include
> +                                                requests for a 64-bit memory address in the corresponding 32-bit
> +                                                memory pool.
> +
> +   @param[in]   This               The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in]   RootBridgeHandle   The device handle of the PCI root bridge in which the caller is interested. Type
> +                                   EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI 2.0 Specification.
> +   @param[out]  Attributes         The pointer to attribte of root bridge, it is output parameter
> +
> +   @retval EFI_INVALID_PARAMETER   Attribute pointer is NULL
> +   @retval EFI_INVALID_PARAMETER   RootBridgehandle is invalid.
> +   @retval EFI_SUCCESS             Success to get attribute of interested root bridge.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetAttributes (
> +  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN  EFI_HANDLE                                       RootBridgeHandle,
> +  OUT UINT64                                           *Attributes
> +  );
> +
> +/**
> +   Sets up the specified PCI root bridge for the bus enumeration process.
> +
> +   This member function sets up the root bridge for bus enumeration and returns the PCI bus range
> +   over which the search should be performed in ACPI 2.0 resource descriptor format.
> +
> +   @param[in]   This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
> +   @param[in]   RootBridgeHandle  The PCI Root Bridge to be set up.
> +   @param[out]  Configuration     Pointer to the pointer to the PCI bus resource descriptor.
> +
> +   @retval EFI_INVALID_PARAMETER Invalid Root bridge's handle
> +   @retval EFI_OUT_OF_RESOURCES  Fail to allocate ACPI resource descriptor tag.
> +   @retval EFI_SUCCESS           Sucess to allocate ACPI resource descriptor.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +StartBusEnumeration (
> +  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN  EFI_HANDLE                                       RootBridgeHandle,
> +  OUT VOID                                             **Configuration
> +  );
> +
> +/**
> +   Programs the PCI root bridge hardware so that it decodes the specified PCI bus range.
> +
> +   This member function programs the specified PCI root bridge to decode the bus range that is
> +   specified by the input parameter Configuration.
> +   The bus range information is specified in terms of the ACPI 2.0 resource descriptor format.
> +
> +   @param[in] This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
> +   @param[in] RootBridgeHandle  The PCI Root Bridge whose bus range is to be programmed
> +   @param[in] Configuration     The pointer to the PCI bus resource descriptor
> +
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
> +   @retval EFI_INVALID_PARAMETER  Configuration does not point to a valid ACPI 2.0 resource descriptor.
> +   @retval EFI_INVALID_PARAMETER  Configuration does not include a valid ACPI 2.0 bus resource descriptor.
> +   @retval EFI_INVALID_PARAMETER  Configuration includes valid ACPI 2.0 resource descriptors other than
> +                                  bus descriptors.
> +   @retval EFI_INVALID_PARAMETER  Configuration contains one or more invalid ACPI resource descriptors.
> +   @retval EFI_INVALID_PARAMETER  "Address Range Minimum" is invalid for this root bridge.
> +   @retval EFI_INVALID_PARAMETER  "Address Range Length" is invalid for this root bridge.
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware error.
> +   @retval EFI_SUCCESS            The bus range for the PCI root bridge was programmed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetBusNumbers (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_HANDLE                                       RootBridgeHandle,
> +  IN VOID                                             *Configuration
> +  );
> +
> +/**
> +   Submits the I/O and memory resource requirements for the specified PCI root bridge.
> +
> +   This function is used to submit all the I/O and memory resources that are required by the specified
> +   PCI root bridge. The input parameter Configuration is used to specify the following:
> +   - The various types of resources that are required
> +   - The associated lengths in terms of ACPI 2.0 resource descriptor format
> +
> +   @param[in] This              Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +   @param[in] RootBridgeHandle  The PCI root bridge whose I/O and memory resource requirements are being submitted.
> +   @param[in] Configuration     The pointer to the PCI I/O and PCI memory resource descriptor.
> +
> +   @retval EFI_SUCCESS            The I/O and memory resource requests for a PCI root bridge were accepted.
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
> +   @retval EFI_INVALID_PARAMETER  Configuration does not point to a valid ACPI 2.0 resource descriptor.
> +   @retval EFI_INVALID_PARAMETER  Configuration includes requests for one or more resource types that are
> +                                  not supported by this PCI root bridge. This error will happen if the caller
> +                                  did not combine resources according to Attributes that were returned by
> +                                  GetAllocAttributes().
> +   @retval EFI_INVALID_PARAMETER  Address Range Maximum" is invalid.
> +   @retval EFI_INVALID_PARAMETER  "Address Range Length" is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  "Address Space Granularity" is invalid for this PCI root bridge.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SubmitResources (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_HANDLE                                       RootBridgeHandle,
> +  IN VOID                                             *Configuration
> +  );
> +
> +/**
> +   Returns the proposed resource settings for the specified PCI root bridge.
> +
> +   This member function returns the proposed resource settings for the specified PCI root bridge. The
> +   proposed resource settings are prepared when NotifyPhase() is called with a Phase of
> +   EfiPciHostBridgeAllocateResources. The output parameter Configuration
> +   specifies the following:
> +   - The various types of resources, excluding bus resources, that are allocated
> +   - The associated lengths in terms of ACPI 2.0 resource descriptor format
> +
> +   @param[in]  This              Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +   @param[in]  RootBridgeHandle  The PCI root bridge handle. Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI 2.0 Specification.
> +   @param[out] Configuration     The pointer to the pointer to the PCI I/O and memory resource descriptor.
> +
> +   @retval EFI_SUCCESS            The requested parameters were returned.
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware error.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProposedResources (
> +  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN  EFI_HANDLE                                       RootBridgeHandle,
> +  OUT VOID                                             **Configuration
> +  );
> +
> +/**
> +   Provides the hooks from the PCI bus driver to every PCI controller (device/function) at various
> +   stages of the PCI enumeration process that allow the host bridge driver to preinitialize individual
> +   PCI controllers before enumeration.
> +
> +   This function is called during the PCI enumeration process. No specific action is expected from this
> +   member function. It allows the host bridge driver to preinitialize individual PCI controllers before
> +   enumeration.
> +
> +   @param This              Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +   @param RootBridgeHandle  The associated PCI root bridge handle. Type EFI_HANDLE is defined in
> +                            InstallProtocolInterface() in the UEFI 2.0 Specification.
> +   @param PciAddress        The address of the PCI device on the PCI bus. This address can be passed to the
> +                            EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL member functions to access the PCI
> +                            configuration space of the device. See Table 12-1 in the UEFI 2.0 Specification for
> +                            the definition of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS.
> +   @param Phase             The phase of the PCI device enumeration.
> +
> +   @retval EFI_SUCCESS              The requested parameters were returned.
> +   @retval EFI_INVALID_PARAMETER    RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_INVALID_PARAMETER    Phase is not a valid phase that is defined in
> +                                    EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE.
> +   @retval EFI_DEVICE_ERROR         Programming failed due to a hardware error. The PCI enumerator should
> +                                    not enumerate this device, including its child devices if it is a PCI-to-PCI
> +                                    bridge.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PreprocessController (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_HANDLE                                       RootBridgeHandle,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS      PciAddress,
> +  IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE     Phase
> +  );
> +
> +#endif /* PCI_HOST_BRIDGE_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.h b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.h
> new file mode 100644
> index 000000000000..9f09e8f4d7bc
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.h
> @@ -0,0 +1,554 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PCI_ROOT_BRIDGE_IO_H_
> +#define PCI_ROOT_BRIDGE_IO_H_
> +
> +#include <IndustryStandard/Pci.h>
> +#include <Library/PciLib.h>
> +
> +/**
> +   Polls an address in memory mapped I/O space until an exit condition is met, or
> +   a timeout occurs.
> +
> +   This function provides a standard way to poll a PCI memory location. A PCI memory read
> +   operation is performed at the PCI memory address specified by Address for the width specified
> +   by Width. The result of this PCI memory read operation is stored in Result. This PCI memory
> +   read operation is repeated until either a timeout of Delay 100 ns units has expired, or (Result &
> +   Mask) is equal to Value.
> +
> +   @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Width     Signifies the width of the memory operations.
> +   @param[in]   Address   The base address of the memory operations. The caller is
> +   responsible for aligning Address if required.
> +   @param[in]   Mask      Mask used for the polling criteria. Bytes above Width in Mask
> +   are ignored. The bits in the bytes below Width which are zero in
> +   Mask are ignored when polling the memory address.
> +   @param[in]   Value     The comparison value used for the polling exit criteria.
> +   @param[in]   Delay     The number of 100 ns units to poll. Note that timer available may
> +   be of poorer granularity.
> +   @param[out]  Result    Pointer to the last value read from the memory location.
> +
> +   @retval EFI_SUCCESS            The last data returned from the access matched the poll exit criteria.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid.
> +   @retval EFI_INVALID_PARAMETER  Result is NULL.
> +   @retval EFI_TIMEOUT            Delay expired before a match occurred.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPollMem (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINT64                                Mask,
> +  IN  UINT64                                Value,
> +  IN  UINT64                                Delay,
> +  OUT UINT64                                *Result
> +  );
> +
> +/**
> +   Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is
> +   satisfied or after a defined duration.
> +
> +   This function provides a standard way to poll a PCI I/O location. A PCI I/O read operation is
> +   performed at the PCI I/O address specified by Address for the width specified by Width.
> +   The result of this PCI I/O read operation is stored in Result. This PCI I/O read operation is
> +   repeated until either a timeout of Delay 100 ns units has expired, or (Result & Mask) is equal
> +   to Value.
> +
> +   @param[in] This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in] Width     Signifies the width of the I/O operations.
> +   @param[in] Address   The base address of the I/O operations. The caller is responsible
> +   for aligning Address if required.
> +   @param[in] Mask      Mask used for the polling criteria. Bytes above Width in Mask
> +   are ignored. The bits in the bytes below Width which are zero in
> +   Mask are ignored when polling the I/O address.
> +   @param[in] Value     The comparison value used for the polling exit criteria.
> +   @param[in] Delay     The number of 100 ns units to poll. Note that timer available may
> +   be of poorer granularity.
> +   @param[out] Result   Pointer to the last value read from the memory location.
> +
> +   @retval EFI_SUCCESS            The last data returned from the access matched the poll exit criteria.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid.
> +   @retval EFI_INVALID_PARAMETER  Result is NULL.
> +   @retval EFI_TIMEOUT            Delay expired before a match occurred.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPollIo (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINT64                                Mask,
> +  IN  UINT64                                Value,
> +  IN  UINT64                                Delay,
> +  OUT UINT64                                *Result
> +  );
> +
> +/**
> +   Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
> +
> +   The Mem.Read(), and Mem.Write() functions enable a driver to access PCI controller
> +   registers in the PCI root bridge memory space.
> +   The memory operations are carried out exactly as requested. The caller is responsible for satisfying
> +   any alignment and memory width restrictions that a PCI Root Bridge on a platform might require.
> +
> +   @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Width     Signifies the width of the memory operation.
> +   @param[in]   Address   The base address of the memory operation. The caller is
> +   responsible for aligning the Address if required.
> +   @param[in]   Count     The number of memory operations to perform. Bytes moved is
> +   Width size * Count, starting at Address.
> +   @param[out]  Buffer    For read operations, the destination buffer to store the results. For
> +   write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoMemRead (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINTN                                 Count,
> +  OUT VOID                                  *Buffer
> +  );
> +
> +/**
> +   Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
> +
> +   The Mem.Read(), and Mem.Write() functions enable a driver to access PCI controller
> +   registers in the PCI root bridge memory space.
> +   The memory operations are carried out exactly as requested. The caller is responsible for satisfying
> +   any alignment and memory width restrictions that a PCI Root Bridge on a platform might require.
> +
> +   @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Width     Signifies the width of the memory operation.
> +   @param[in]   Address   The base address of the memory operation. The caller is
> +   responsible for aligning the Address if required.
> +   @param[in]   Count     The number of memory operations to perform. Bytes moved is
> +   Width size * Count, starting at Address.
> +   @param[in]   Buffer    For read operations, the destination buffer to store the results. For
> +   write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoMemWrite (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                Address,
> +  IN UINTN                                 Count,
> +  IN VOID                                  *Buffer
> +  );
> +
> +/**
> +   Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space.
> +
> +   @param[in]   This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Width       Signifies the width of the memory operations.
> +   @param[in]   UserAddress The base address of the I/O operation. The caller is responsible for
> +   aligning the Address if required.
> +   @param[in]   Count       The number of I/O operations to perform. Bytes moved is Width
> +   size * Count, starting at Address.
> +   @param[out]  UserBuffer  For read operations, the destination buffer to store the results. For
> +   write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS              The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER    Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER    Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoIoRead (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                UserAddress,
> +  IN  UINTN                                 Count,
> +  OUT VOID                                  *UserBuffer
> +  );
> +
> +/**
> +   Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space.
> +
> +   @param[in]   This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Width       Signifies the width of the memory operations.
> +   @param[in]   UserAddress The base address of the I/O operation. The caller is responsible for
> +   aligning the Address if required.
> +   @param[in]   Count       The number of I/O operations to perform. Bytes moved is Width
> +   size * Count, starting at Address.
> +   @param[in]   UserBuffer  For read operations, the destination buffer to store the results. For
> +   write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS              The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER    Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER    Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoIoWrite (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                UserAddress,
> +  IN UINTN                                 Count,
> +  IN VOID                                  *UserBuffer
> +  );
> +
> +/**
> +   Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI
> +   root bridge memory space.
> +
> +   The CopyMem() function enables a PCI driver to copy one region of PCI root bridge memory
> +   space to another region of PCI root bridge memory space. This is especially useful for video scroll
> +   operation on a memory mapped video buffer.
> +   The memory operations are carried out exactly as requested. The caller is responsible for satisfying
> +   any alignment and memory width restrictions that a PCI root bridge on a platform might require.
> +
> +   @param[in] This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
> +   @param[in] Width       Signifies the width of the memory operations.
> +   @param[in] DestAddress The destination address of the memory operation. The caller is
> +   responsible for aligning the DestAddress if required.
> +   @param[in] SrcAddress  The source address of the memory operation. The caller is
> +   responsible for aligning the SrcAddress if required.
> +   @param[in] Count       The number of memory operations to perform. Bytes moved is
> +   Width size * Count, starting at DestAddress and SrcAddress.
> +
> +   @retval  EFI_SUCCESS             The data was copied from one memory region to another memory region.
> +   @retval  EFI_INVALID_PARAMETER   Width is invalid for this PCI root bridge.
> +   @retval  EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoCopyMem (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                DestAddress,
> +  IN UINT64                                SrcAddress,
> +  IN UINTN                                 Count
> +  );
> +
> +/**
> +   Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space.
> +
> +   The Pci.Read() and Pci.Write() functions enable a driver to access PCI configuration
> +   registers for a PCI controller.
> +   The PCI Configuration operations are carried out exactly as requested. The caller is responsible for
> +   any alignment and PCI configuration width issues that a PCI Root Bridge on a platform might
> +   require.
> +
> +   @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Width     Signifies the width of the memory operations.
> +   @param[in]   Address   The address within the PCI configuration space for the PCI controller.
> +   @param[in]   Count     The number of PCI configuration operations to perform. Bytes
> +   moved is Width size * Count, starting at Address.
> +   @param[out]  Buffer    For read operations, the destination buffer to store the results. For
> +   write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPciRead (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINTN                                 Count,
> +  OUT VOID                                  *Buffer
> +  );
> +
> +/**
> +   Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space.
> +
> +   The Pci.Read() and Pci.Write() functions enable a driver to access PCI configuration
> +   registers for a PCI controller.
> +   The PCI Configuration operations are carried out exactly as requested. The caller is responsible for
> +   any alignment and PCI configuration width issues that a PCI Root Bridge on a platform might
> +   require.
> +
> +   @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Width     Signifies the width of the memory operations.
> +   @param[in]   Address   The address within the PCI configuration space for the PCI controller.
> +   @param[in]   Count     The number of PCI configuration operations to perform. Bytes
> +   moved is Width size * Count, starting at Address.
> +   @param[in]   Buffer    For read operations, the destination buffer to store the results. For
> +   write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPciWrite (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                Address,
> +  IN UINTN                                 Count,
> +  IN VOID                                  *Buffer
> +  );
> +
> +/**
> +   Provides the PCI controller-specific addresses required to access system memory from a
> +   DMA bus master.
> +
> +   The Map() function provides the PCI controller specific addresses needed to access system
> +   memory. This function is used to map system memory for PCI bus master DMA accesses.
> +
> +   @param[in]       This            A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]       Operation       Indicates if the bus master is going to read or write to system memory.
> +   @param[in]       HostAddress     The system memory address to map to the PCI controller.
> +   @param[in, out]  NumberOfBytes   On input the number of bytes to map. On output the number of bytes that were mapped.
> +   @param[out]      DeviceAddress   The resulting map address for the bus master PCI controller to use
> +   to access the system memory's HostAddress.
> +   @param[out]      Mapping         The value to pass to Unmap() when the bus master DMA operation is complete.
> +
> +   @retval EFI_SUCCESS            The range was mapped for the returned NumberOfBytes.
> +   @retval EFI_INVALID_PARAMETER  Operation is invalid.
> +   @retval EFI_INVALID_PARAMETER  HostAddress is NULL.
> +   @retval EFI_INVALID_PARAMETER  NumberOfBytes is NULL.
> +   @retval EFI_INVALID_PARAMETER  DeviceAddress is NULL.
> +   @retval EFI_INVALID_PARAMETER  Mapping is NULL.
> +   @retval EFI_UNSUPPORTED        The HostAddress cannot be mapped as a common buffer.
> +   @retval EFI_DEVICE_ERROR       The system hardware could not map the requested address.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoMap (
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
> +  IN     VOID                                      *HostAddress,
> +  IN OUT UINTN                                     *NumberOfBytes,
> +  OUT    EFI_PHYSICAL_ADDRESS                      *DeviceAddress,
> +  OUT    VOID                                      **Mapping
> +  );
> +
> +/**
> +   Completes the Map() operation and releases any corresponding resources.
> +
> +   The Unmap() function completes the Map() operation and releases any corresponding resources.
> +   If the operation was an EfiPciOperationBusMasterWrite or
> +   EfiPciOperationBusMasterWrite64, the data is committed to the target system memory.
> +   Any resources used for the mapping are freed.
> +
> +   @param[in] This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in] Mapping   The mapping value returned from Map().
> +
> +   @retval EFI_SUCCESS            The range was unmapped.
> +   @retval EFI_INVALID_PARAMETER  Mapping is not a value that was returned by Map().
> +   @retval EFI_DEVICE_ERROR       The data was not committed to the target system memory.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoUnmap (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN VOID                            *Mapping
> +  );
> +
> +/**
> +   Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or
> +   EfiPciOperationBusMasterCommonBuffer64 mapping.
> +
> +   @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param Type        This parameter is not used and must be ignored.
> +   @param MemoryType  The type of memory to allocate, EfiBootServicesData or EfiRuntimeServicesData.
> +   @param Pages       The number of pages to allocate.
> +   @param HostAddress A pointer to store the base system memory address of the allocated range.
> +   @param Attributes  The requested bit mask of attributes for the allocated range. Only
> +   the attributes EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_ATTRIBUTE_MEMORY_CACHED,
> +   and EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this function.
> +
> +   @retval EFI_SUCCESS            The requested memory pages were allocated.
> +   @retval EFI_INVALID_PARAMETER  MemoryType is invalid.
> +   @retval EFI_INVALID_PARAMETER  HostAddress is NULL.
> +   @retval EFI_UNSUPPORTED        Attributes is unsupported. The only legal attribute bits are
> +   MEMORY_WRITE_COMBINE, MEMORY_CACHED, and DUAL_ADDRESS_CYCLE.
> +   @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoAllocateBuffer (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN  EFI_ALLOCATE_TYPE               Type,
> +  IN  EFI_MEMORY_TYPE                 MemoryType,
> +  IN  UINTN                           Pages,
> +  OUT VOID                            **HostAddress,
> +  IN  UINT64                          Attributes
> +  );
> +
> +/**
> +   Frees memory that was allocated with AllocateBuffer().
> +
> +   The FreeBuffer() function frees memory that was allocated with AllocateBuffer().
> +
> +   @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param Pages       The number of pages to free.
> +   @param HostAddress The base system memory address of the allocated range.
> +
> +   @retval EFI_SUCCESS            The requested memory pages were freed.
> +   @retval EFI_INVALID_PARAMETER  The memory range specified by HostAddress and Pages
> +   was not allocated with AllocateBuffer().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoFreeBuffer (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN  UINTN                           Pages,
> +  OUT VOID                            *HostAddress
> +  );
> +
> +/**
> +   Flushes all PCI posted write transactions from a PCI host bridge to system memory.
> +
> +   The Flush() function flushes any PCI posted write transactions from a PCI host bridge to system
> +   memory. Posted write transactions are generated by PCI bus masters when they perform write
> +   transactions to target addresses in system memory.
> +   This function does not flush posted write transactions from any PCI bridges. A PCI controller
> +   specific action must be taken to guarantee that the posted write transactions have been flushed from
> +   the PCI controller and from all the PCI bridges into the PCI host bridge. This is typically done with
> +   a PCI read transaction from the PCI controller prior to calling Flush().
> +
> +   @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +
> +   @retval EFI_SUCCESS        The PCI posted write transactions were flushed from the PCI host
> +   bridge to system memory.
> +   @retval EFI_DEVICE_ERROR   The PCI posted write transactions were not flushed from the PCI
> +   host bridge due to a hardware error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoFlush (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
> +  );
> +
> +/**
> +   Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the
> +   attributes that a PCI root bridge is currently using.
> +
> +   The GetAttributes() function returns the mask of attributes that this PCI root bridge supports
> +   and the mask of attributes that the PCI root bridge is currently using.
> +
> +   @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param Supported   A pointer to the mask of attributes that this PCI root bridge
> +   supports setting with SetAttributes().
> +   @param Attributes  A pointer to the mask of attributes that this PCI root bridge is
> +   currently using.
> +
> +   @retval  EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI root
> +   bridge supports is returned in Supports. If Attributes is
> +   not NULL, then the attributes that the PCI root bridge is currently
> +   using is returned in Attributes.
> +   @retval  EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoGetAttributes (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  OUT UINT64                          *Supported,
> +  OUT UINT64                          *Attributes
> +  );
> +
> +/**
> +   Sets attributes for a resource range on a PCI root bridge.
> +
> +   The SetAttributes() function sets the attributes specified in Attributes for the PCI root
> +   bridge on the resource range specified by ResourceBase and ResourceLength. Since the
> +   granularity of setting these attributes may vary from resource type to resource type, and from
> +   platform to platform, the actual resource range and the one passed in by the caller may differ. As a
> +   result, this function may set the attributes specified by Attributes on a larger resource range
> +   than the caller requested. The actual range is returned in ResourceBase and
> +   ResourceLength. The caller is responsible for verifying that the actual range for which the
> +   attributes were set is acceptable.
> +
> +   @param[in]       This            A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]       Attributes      The mask of attributes to set. If the attribute bit
> +   MEMORY_WRITE_COMBINE, MEMORY_CACHED, or
> +   MEMORY_DISABLE is set, then the resource range is specified by
> +   ResourceBase and ResourceLength. If
> +   MEMORY_WRITE_COMBINE, MEMORY_CACHED, and
> +   MEMORY_DISABLE are not set, then ResourceBase and
> +   ResourceLength are ignored, and may be NULL.
> +   @param[in, out]  ResourceBase    A pointer to the base address of the resource range to be modified
> +   by the attributes specified by Attributes.
> +   @param[in, out]  ResourceLength  A pointer to the length of the resource range to be modified by the
> +   attributes specified by Attributes.
> +
> +   @retval  EFI_SUCCESS     The current configuration of this PCI root bridge was returned in Resources.
> +   @retval  EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be retrieved.
> +   @retval  EFI_INVALID_PARAMETER Invalid pointer of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoSetAttributes (
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN     UINT64                          Attributes,
> +  IN OUT UINT64                          *ResourceBase,
> +  IN OUT UINT64                          *ResourceLength
> +  );
> +
> +/**
> +   Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0
> +   resource descriptors.
> +
> +   There are only two resource descriptor types from the ACPI Specification that may be used to
> +   describe the current resources allocated to a PCI root bridge. These are the QWORD Address
> +   Space Descriptor (ACPI 2.0 Section 6.4.3.5.1), and the End Tag (ACPI 2.0 Section 6.4.2.8). The
> +   QWORD Address Space Descriptor can describe memory, I/O, and bus number ranges for dynamic
> +   or fixed resources. The configuration of a PCI root bridge is described with one or more QWORD
> +   Address Space Descriptors followed by an End Tag.
> +
> +   @param[in]   This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[out]  Resources   A pointer to the ACPI 2.0 resource descriptors that describe the
> +   current configuration of this PCI root bridge. The storage for the
> +   ACPI 2.0 resource descriptors is allocated by this function. The
> +   caller must treat the return buffer as read-only data, and the buffer
> +   must not be freed by the caller.
> +
> +   @retval  EFI_SUCCESS     The current configuration of this PCI root bridge was returned in Resources.
> +   @retval  EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be retrieved.
> +   @retval  EFI_INVALID_PARAMETER Invalid pointer of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoConfiguration (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  OUT VOID                            **Resources
> +  );
> +
> +#endif /* PCI_ROOT_BRIDGE_IO_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
> new file mode 100644
> index 000000000000..2e0876128158
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
> @@ -0,0 +1,1419 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Guid/EventGroup.h>
> +#include <IndustryStandard/Pci.h>
> +#include <Library/AcpiHelperLib.h>
> +#include <Library/ArmLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcieCoreLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PciHostBridgeLib.h>
> +#include <Library/PciLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/TimerLib.h>
> +#include <Library/UefiLib.h>
> +
> +#include "PciHostBridge.h"
> +#include "PciRootBridgeIo.h"
> +
> +EFI_HANDLE mDriverImageHandle;
> +
> +PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = {
> +  PCI_HOST_BRIDGE_SIGNATURE,  // Signature
> +  NULL,                       // HostBridgeHandle
> +  0,                          // RootBridgeNumber
> +  {NULL, NULL},               // Head
> +  FALSE,                      // ResourceSubiteed
> +  TRUE,                       // CanRestarted
> +  {
> +    NotifyPhase,
> +    GetNextRootBridge,
> +    GetAttributes,
> +    StartBusEnumeration,
> +    SetBusNumbers,
> +    SubmitResources,
> +    GetProposedResources,
> +    PreprocessController
> +  }
> +};
> +
> +EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciDevicePathTemplate =
> +{
> +  {
> +    {
> +      ACPI_DEVICE_PATH,
> +      ACPI_DP,
> +      {
> +        (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
> +        (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
> +      }
> +    },
> +    EISA_PNP_ID (0x0A08),
> +    0
> +  },
> +
> +  {
> +    END_DEVICE_PATH_TYPE,
> +    END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    {
> +      END_DEVICE_PATH_LENGTH,
> +      0
> +    }
> +  }
> +};
> +
> +STATIC
> +EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *
> +EFIAPI
> +GenerateRootBridgeDevicePath (
> +  UINTN HostBridgeIdx,
> +  UINTN RootBridgeIdx
> +  )
> +{
> +
> +  EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *RootBridgeDevPath = NULL;
> +
> +  RootBridgeDevPath = AllocateCopyPool (
> +                        sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH),
> +                        (VOID *)&mPciDevicePathTemplate
> +                        );
> +  if (RootBridgeDevPath == NULL) {
> +    return NULL;
> +  }
> +
> +  /* We don't expect to have more than 65536 root ports on the same root bridge */
> +  RootBridgeDevPath->AcpiDevicePath.UID = (UINT32)((HostBridgeIdx << 16) + RootBridgeIdx);
> +
> +  return RootBridgeDevPath;
> +}
> +
> +/**
> +  This function will be called when ReadyToBoot event will be signaled.
> +
> +  @param Event signaled event
> +  @param Context calling context
> +
> +  @retval VOID
> +**/
> +VOID
> +EFIAPI
> +PciHostBridgeReadyToBootEvent (
> +  EFI_EVENT Event,
> +  VOID      *Context
> +  )
> +{
> +  UINTN Idx1, Idx2, Count = 0;
> +  CHAR8 NodePath[MAX_ACPI_NODE_PATH];
> +
> +  for (Idx1 = 0; Idx1 < Ac01PcieGetTotalHBs (); Idx1++) {
> +    for (Idx2 = 0; Idx2 < Ac01PcieGetTotalRBsPerHB (Idx1); Idx2++) {
> +      AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X._STA", Count);
> +      if (Ac01PcieCheckRootBridgeDisabled (Idx1, Idx2)) {
> +        AcpiDSDTSetNodeStatusValue (NodePath, 0x0);
> +      } else {
> +        AcpiDSDTSetNodeStatusValue (NodePath, 0xf);
> +      }
> +      Count++;
> +    }
> +  }
> +
> +  //
> +  // Close the event, so it will not be signalled again.
> +  //
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +   Construct the Pci Root Bridge Io protocol
> +
> +   @param Protocol         Point to protocol instance
> +   @param HostBridgeHandle Handle of host bridge
> +   @param Attri            Attribute of host bridge
> +   @param ResAppeture      ResourceAppeture for host bridge
> +
> +   @retval EFI_SUCCESS Success to initialize the Pci Root Bridge.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +RootBridgeConstructor (
> +  IN PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance,
> +  IN EFI_HANDLE               HostBridgeHandle,
> +  IN UINT64                   Attri,
> +  IN UINT32                   Seg
> +  )
> +{
> +  PCI_RESOURCE_TYPE Index;
> +
> +  //
> +  // The host to pci bridge, the host memory and io addresses are
> +  // integrated as PCIe controller subsystem resource. We move forward to mark
> +  // resource as ResAllocated.
> +  //
> +  for (Index = TypeIo; Index < TypeMax; Index++) {
> +    RootBridgeInstance->ResAllocNode[Index].Type      = Index;
> +    RootBridgeInstance->ResAllocNode[Index].Base      = 0;
> +    RootBridgeInstance->ResAllocNode[Index].Length    = 0;
> +    RootBridgeInstance->ResAllocNode[Index].Status    = ResNone;
> +  }
> +
> +  RootBridgeInstance->RootBridgeAttrib                 = Attri;
> +  RootBridgeInstance->RootBridge.Supports              = EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
> +  // Support Extended (4096-byte) Configuration Space
> +  RootBridgeInstance->RootBridge.NoExtendedConfigSpace = FALSE;
> +  RootBridgeInstance->RootBridge.Attributes            = RootBridgeInstance->RootBridge.Supports;
> +
> +  RootBridgeInstance->RbIo.ParentHandle   = HostBridgeHandle;
> +
> +  RootBridgeInstance->RbIo.PollMem        = RootBridgeIoPollMem;
> +  RootBridgeInstance->RbIo.PollIo         = RootBridgeIoPollIo;
> +
> +  RootBridgeInstance->RbIo.Mem.Read       = RootBridgeIoMemRead;
> +  RootBridgeInstance->RbIo.Mem.Write      = RootBridgeIoMemWrite;
> +
> +  RootBridgeInstance->RbIo.Io.Read        = RootBridgeIoIoRead;
> +  RootBridgeInstance->RbIo.Io.Write       = RootBridgeIoIoWrite;
> +
> +  RootBridgeInstance->RbIo.CopyMem        = RootBridgeIoCopyMem;
> +
> +  RootBridgeInstance->RbIo.Pci.Read       = RootBridgeIoPciRead;
> +  RootBridgeInstance->RbIo.Pci.Write      = RootBridgeIoPciWrite;
> +
> +  RootBridgeInstance->RbIo.Map            = RootBridgeIoMap;
> +  RootBridgeInstance->RbIo.Unmap          = RootBridgeIoUnmap;
> +
> +  RootBridgeInstance->RbIo.AllocateBuffer = RootBridgeIoAllocateBuffer;
> +  RootBridgeInstance->RbIo.FreeBuffer     = RootBridgeIoFreeBuffer;
> +
> +  RootBridgeInstance->RbIo.Flush          = RootBridgeIoFlush;
> +
> +  RootBridgeInstance->RbIo.GetAttributes  = RootBridgeIoGetAttributes;
> +  RootBridgeInstance->RbIo.SetAttributes  = RootBridgeIoSetAttributes;
> +
> +  RootBridgeInstance->RbIo.Configuration  = RootBridgeIoConfiguration;
> +
> +  RootBridgeInstance->RbIo.SegmentNumber  = Seg;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +   Entry point of this driver
> +
> +   @param ImageHandle     Handle of driver image
> +   @param SystemTable     Point to EFI_SYSTEM_TABLE
> +
> +   @retval EFI_OUT_OF_RESOURCES  Can not allocate memory resource
> +   @retval EFI_DEVICE_ERROR      Can not install the protocol instance
> +   @retval EFI_SUCCESS           Success to initialize the Pci host bridge.
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitializePciHostBridge (
> +  IN EFI_HANDLE       ImageHandle,
> +  IN EFI_SYSTEM_TABLE *SystemTable
> +  )
> +{
> +  STATIC EFI_GUID          guidReadyToBoot = EFI_EVENT_GROUP_READY_TO_BOOT;
> +  EFI_EVENT                EvtReadyToBoot;
> +  EFI_STATUS               Status;
> +  UINTN                    Idx1;
> +  UINTN                    Idx2;
> +  UINTN                    Count = 0;
> +  PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance = NULL;
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance = NULL;
> +  UINTN                    NumberRootPortInstalled = FALSE;
> +  LIST_ENTRY               *List;
> +  UINTN                    SegmentNumber;
> +
> +  if (( Ac01PcieCheckRootBridgeDisabled == NULL)
> +      || (Ac01PcieSetup == NULL)
> +      || (Ac01PcieEnd == NULL)
> +      || (Ac01PcieSetupHostBridge == NULL)
> +      || (Ac01PcieSetupRootBridge == NULL)
> +      || (Ac01PcieConfigRW == NULL)
> +      || (Ac01PcieGetTotalHBs == NULL)
> +      || (Ac01PcieGetTotalRBsPerHB == NULL)
> +      || (Ac01PcieGetRootBridgeAttribute == NULL ))
> +  {
> +    PCIE_ERR ("PciHostBridge: Invalid Parameters\n");
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PCIE_DEBUG ("%a: START\n", __FUNCTION__);
> +
> +  mDriverImageHandle = ImageHandle;
> +
> +  // Inform Pcie Core BSP Driver to start setup phase
> +  Status = Ac01PcieSetup (ImageHandle, SystemTable);
> +  if (EFI_ERROR (Status)) {
> +    PCIE_ERR ("  PCIe Core Setup failed!\n");
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Create Host Bridge Device Handle
> +  //
> +  for (Idx1 = 0; Idx1 < Ac01PcieGetTotalHBs (); Idx1++) {
> +    HostBridgeInstance = AllocateCopyPool (
> +                           sizeof (PCI_HOST_BRIDGE_INSTANCE),
> +                           (VOID *)&mPciHostBridgeInstanceTemplate
> +                           );
> +    if (HostBridgeInstance == NULL) {
> +      PCIE_ERR ("  HB%d allocation failed!\n", Idx1);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    Status = Ac01PcieSetupHostBridge (Idx1);
> +    if (EFI_ERROR (Status)) {
> +      FreePool (HostBridgeInstance);
> +      PCIE_ERR ("  HB%d setup failed!\n", Idx1);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    HostBridgeInstance->RootBridgeNumber = Ac01PcieGetTotalRBsPerHB (Idx1);
> +
> +    InitializeListHead (&HostBridgeInstance->Head);
> +
> +    Status = gBS->InstallMultipleProtocolInterfaces (
> +                    &HostBridgeInstance->HostBridgeHandle,
> +                    &gEfiPciHostBridgeResourceAllocationProtocolGuid,
> +                    &HostBridgeInstance->ResAlloc,
> +                    NULL
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      FreePool (HostBridgeInstance);
> +      PCIE_ERR ("  HB%d instance installation failed\n", Idx1);
> +      return EFI_DEVICE_ERROR;
> +    }
> +
> +    NumberRootPortInstalled = 0;
> +
> +    //
> +    // Create Root Bridge Device Handle in this Host Bridge
> +    //
> +    for (Idx2 = 0; Idx2 < HostBridgeInstance->RootBridgeNumber; Idx2++, Count++) {
> +      RootBridgeInstance = AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE));
> +      if (RootBridgeInstance == NULL) {
> +        gBS->UninstallMultipleProtocolInterfaces (
> +               HostBridgeInstance->HostBridgeHandle,
> +               &gEfiPciHostBridgeResourceAllocationProtocolGuid,
> +               &HostBridgeInstance->ResAlloc,
> +               NULL
> +               );
> +        PCIE_ERR ("    HB%d-RB%d allocation failed!\n", Idx1, Idx2);
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      // Initialize Hardware
> +      Status = Ac01PcieSetupRootBridge (Idx1, Idx2, (VOID *)&RootBridgeInstance->RootBridge);
> +      if (EFI_ERROR (Status)) {
> +        FreePool (RootBridgeInstance);
> +        PCIE_ERR ("    HB%d-RB%d setup failed!\n", Idx1, Idx2);
> +        continue;
> +      }
> +
> +      NumberRootPortInstalled++;
> +
> +      RootBridgeInstance->ConfigBuffer = AllocateZeroPool (
> +                                           TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)
> +                                           + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
> +                                           );
> +      if (RootBridgeInstance->ConfigBuffer == NULL) {
> +        gBS->UninstallMultipleProtocolInterfaces (
> +               HostBridgeInstance->HostBridgeHandle,
> +               &gEfiPciHostBridgeResourceAllocationProtocolGuid,
> +               &HostBridgeInstance->ResAlloc,
> +               NULL
> +               );
> +        FreePool (RootBridgeInstance);
> +        PCIE_ERR ("    HB%d-RB%d Descriptor allocation failed!\n", Idx1, Idx2);
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      RootBridgeInstance->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
> +      RootBridgeInstance->RootBridge.DevicePath =
> +        (EFI_DEVICE_PATH_PROTOCOL *)GenerateRootBridgeDevicePath (Idx1, Idx2);
> +
> +      SegmentNumber = Count;
> +      if (Ac01PcieGetRootBridgeSegmentNumber) {
> +        SegmentNumber = Ac01PcieGetRootBridgeSegmentNumber (Idx1, Idx2);
> +      }
> +
> +      RootBridgeConstructor (
> +        RootBridgeInstance,
> +        HostBridgeInstance->HostBridgeHandle,
> +        Ac01PcieGetRootBridgeAttribute (Idx1, Idx2),
> +        SegmentNumber
> +        );
> +
> +      Status = gBS->InstallMultipleProtocolInterfaces (
> +                      &RootBridgeInstance->RootBridgeHandle,
> +                      &gEfiDevicePathProtocolGuid,
> +                      RootBridgeInstance->RootBridge.DevicePath,
> +                      &gEfiPciRootBridgeIoProtocolGuid,
> +                      &RootBridgeInstance->RbIo,
> +                      NULL
> +                      );
> +      if (EFI_ERROR (Status)) {
> +        // Uninstall all root ports of this bridge
> +        List = HostBridgeInstance->Head.ForwardLink;
> +        while (List != &HostBridgeInstance->Head) {
> +          RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +          gBS->UninstallMultipleProtocolInterfaces (
> +                 RootBridgeInstance->RootBridgeHandle,
> +                 &gEfiDevicePathProtocolGuid,
> +                 RootBridgeInstance->RootBridge.DevicePath,
> +                 &gEfiPciRootBridgeIoProtocolGuid,
> +                 &RootBridgeInstance->RbIo,
> +                 NULL
> +                 );
> +          FreePool (RootBridgeInstance->ConfigBuffer);
> +          FreePool (RootBridgeInstance);
> +          List = List->ForwardLink;
> +        }
> +
> +        gBS->UninstallMultipleProtocolInterfaces (
> +               HostBridgeInstance->HostBridgeHandle,
> +               &gEfiPciHostBridgeResourceAllocationProtocolGuid,
> +               &HostBridgeInstance->ResAlloc,
> +               NULL
> +               );
> +        FreePool (HostBridgeInstance);
> +        PCIE_ERR ("    HB%d-RB%d instance installation failed\n", Idx1, Idx2);
> +        return EFI_DEVICE_ERROR;
> +      }
> +
> +      InsertTailList (&HostBridgeInstance->Head, &RootBridgeInstance->Link);
> +    }
> +
> +    if (NumberRootPortInstalled == 0) {
> +      PCIE_WARN ("  No Root Port! Uninstalling HB%d\n", Idx1);
> +      gBS->UninstallMultipleProtocolInterfaces (
> +             HostBridgeInstance->HostBridgeHandle,
> +             &gEfiPciHostBridgeResourceAllocationProtocolGuid,
> +             &HostBridgeInstance->ResAlloc,
> +             NULL
> +             );
> +      FreePool (HostBridgeInstance);
> +    }
> +  }
> +
> +  // Inform BSP Pcie Driver to end setup phase
> +  Ac01PcieEnd ();
> +
> +  /* Event for ACPI Menu configuration */
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,                 // Type,
> +                  TPL_NOTIFY,                        // NotifyTpl
> +                  PciHostBridgeReadyToBootEvent,     // NotifyFunction
> +                  NULL,                              // NotifyContext
> +                  &guidReadyToBoot,                  // EventGroup
> +                  &EvtReadyToBoot                    // Event
> +                  );
> +
> +  PCIE_DEBUG ("%a: END\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +/**
> +   These are the notifications from the PCI bus driver that it is about to enter a certain
> +   phase of the PCI enumeration process.
> +
> +   This member function can be used to notify the host bridge driver to perform specific actions,
> +   including any chipset-specific initialization, so that the chipset is ready to enter the next phase.
> +   Eight notification points are defined at this time. See belows:
> +   EfiPciHostBridgeBeginEnumeration       Resets the host bridge PCI apertures and internal data
> +                                          structures. The PCI enumerator should issue this notification
> +                                          before starting a fresh enumeration process. Enumeration cannot
> +                                          be restarted after sending any other notification such as
> +                                          EfiPciHostBridgeBeginBusAllocation.
> +   EfiPciHostBridgeBeginBusAllocation     The bus allocation phase is about to begin. No specific action is
> +                                          required here. This notification can be used to perform any
> +                                          chipset-specific programming.
> +   EfiPciHostBridgeEndBusAllocation       The bus allocation and bus programming phase is complete. No
> +                                          specific action is required here. This notification can be used to
> +                                          perform any chipset-specific programming.
> +   EfiPciHostBridgeBeginResourceAllocation
> +                                          The resource allocation phase is about to begin. No specific
> +                                          action is required here. This notification can be used to perform
> +                                          any chipset-specific programming.
> +   EfiPciHostBridgeAllocateResources      Allocates resources per previously submitted requests for all the PCI
> +                                          root bridges. These resource settings are returned on the next call to
> +                                          GetProposedResources(). Before calling NotifyPhase() with a Phase of
> +                                          EfiPciHostBridgeAllocateResource, the PCI bus enumerator is responsible
> +                                          for gathering I/O and memory requests for
> +                                          all the PCI root bridges and submitting these requests using
> +                                          SubmitResources(). This function pads the resource amount
> +                                          to suit the root bridge hardware, takes care of dependencies between
> +                                          the PCI root bridges, and calls the Global Coherency Domain (GCD)
> +                                          with the allocation request. In the case of padding, the allocated range
> +                                          could be bigger than what was requested.
> +   EfiPciHostBridgeSetResources           Programs the host bridge hardware to decode previously allocated
> +                                          resources (proposed resources) for all the PCI root bridges. After the
> +                                          hardware is programmed, reassigning resources will not be supported.
> +                                          The bus settings are not affected.
> +   EfiPciHostBridgeFreeResources          Deallocates resources that were previously allocated for all the PCI
> +                                          root bridges and resets the I/O and memory apertures to their initial
> +                                          state. The bus settings are not affected. If the request to allocate
> +                                          resources fails, the PCI enumerator can use this notification to
> +                                          deallocate previous resources, adjust the requests, and retry
> +                                          allocation.
> +   EfiPciHostBridgeEndResourceAllocation  The resource allocation phase is completed. No specific action is
> +                                          required here. This notification can be used to perform any chipsetspecific
> +                                          programming.
> +
> +   @param[in] This                The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in] Phase               The phase during enumeration
> +
> +   @retval EFI_NOT_READY          This phase cannot be entered at this time. For example, this error
> +                                  is valid for a Phase of EfiPciHostBridgeAllocateResources if
> +                                  SubmitResources() has not been called for one or more
> +                                  PCI root bridges before this call
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware error. This error is valid
> +                                  for a Phase of EfiPciHostBridgeSetResources.
> +   @retval EFI_INVALID_PARAMETER  Invalid phase parameter
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +                                  This error is valid for a Phase of EfiPciHostBridgeAllocateResources if the
> +                                  previously submitted resource requests cannot be fulfilled or
> +                                  were only partially fulfilled.
> +   @retval EFI_SUCCESS            The notification was accepted without any errors.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NotifyPhase (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE    Phase
> +  )
> +{
> +  PCI_HOST_BRIDGE_INSTANCE        *HostBridgeInstance;
> +  PCI_ROOT_BRIDGE_INSTANCE        *RootBridgeInstance;
> +  PCI_RESOURCE_TYPE               Index;
> +  PCI_RES_NODE                    *ResNode;
> +  LIST_ENTRY                      *List;
> +  EFI_PHYSICAL_ADDRESS            AddrBase;
> +  EFI_PHYSICAL_ADDRESS            AddrLimit;
> +  UINT64                          AddrLen;
> +  UINTN                           BitsOfAlignment;
> +  EFI_STATUS                      Status;
> +  EFI_STATUS                      ReturnStatus;
> +  EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *DevPath;
> +  UINTN                           HostBridgeIdx, RootBridgeIdx;
> +
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  ReturnStatus = EFI_SUCCESS;
> +
> +  switch (Phase) {
> +
> +  case EfiPciHostBridgeBeginEnumeration:
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (BeginEnumeration)\n");
> +
> +    if (!HostBridgeInstance->CanRestarted) {
> +      return EFI_NOT_READY;
> +    }
> +
> +    //
> +    // Reset each Root Bridge
> +    //
> +    List = HostBridgeInstance->Head.ForwardLink;
> +    while (List != &HostBridgeInstance->Head) {
> +      RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +
> +      for (Index = TypeIo; Index < TypeMax; Index++) {
> +        ResNode = &(RootBridgeInstance->ResAllocNode[Index]);
> +
> +        ResNode->Type      = Index;
> +        ResNode->Base      = 0;
> +        ResNode->Length    = 0;
> +        ResNode->Status    = ResNone;
> +      }
> +
> +      List = List->ForwardLink;
> +    }
> +
> +    HostBridgeInstance->ResourceSubmited = FALSE;
> +    HostBridgeInstance->CanRestarted     = TRUE;
> +    break;
> +
> +  case EfiPciHostBridgeEndEnumeration:
> +    //
> +    // The Host Bridge Enumeration is completed. No specific action is required here.
> +    // This notification can be used to perform any chipset specific programming.
> +    //
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (EndEnumeration)\n");
> +    break;
> +
> +  case EfiPciHostBridgeBeginBusAllocation:
> +    // No specific action is required here, can perform any chipset specific programing
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (BeginBusAllocation)\n");
> +    HostBridgeInstance->CanRestarted = FALSE;
> +    break;
> +
> +  case EfiPciHostBridgeEndBusAllocation:
> +    // No specific action is required here, can perform any chipset specific programing
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (EndBusAllocation)\n");
> +    break;
> +
> +  case EfiPciHostBridgeBeginResourceAllocation:
> +    // No specific action is required here, can perform any chipset specific programing
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (BeginResourceAllocation)\n");
> +    break;
> +
> +  case EfiPciHostBridgeAllocateResources:
> +
> +    // Make sure the resource for all root bridges has been submitted.
> +    if (!HostBridgeInstance->ResourceSubmited) {
> +      return EFI_NOT_READY;
> +    }
> +
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (AllocateResources)\n");
> +
> +    //
> +    // Take care of the resource dependencies between the root bridges
> +    //
> +    List = HostBridgeInstance->Head.ForwardLink;
> +    while (List != &HostBridgeInstance->Head) {
> +
> +      RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +
> +      for (Index = TypeIo; Index < TypeMax; Index++) {
> +        ResNode = &(RootBridgeInstance->ResAllocNode[Index]);
> +
> +        if (ResNode->Status == ResNone) {
> +          continue;
> +        }
> +
> +        switch (Index) {
> +        case TypeIo:
> +          AddrBase = RootBridgeInstance->RootBridge.Io.Base;
> +          AddrLimit = RootBridgeInstance->RootBridge.Io.Limit;
> +          break;
> +
> +        case TypeMem32:
> +          AddrBase = RootBridgeInstance->RootBridge.Mem.Base;
> +          AddrLimit = RootBridgeInstance->RootBridge.Mem.Limit;
> +          break;
> +
> +        case TypePMem32:
> +          AddrBase = RootBridgeInstance->RootBridge.PMem.Base;
> +          AddrLimit = RootBridgeInstance->RootBridge.PMem.Limit;
> +          break;
> +
> +        case TypeMem64:
> +          AddrBase = RootBridgeInstance->RootBridge.MemAbove4G.Base;
> +          AddrLimit = RootBridgeInstance->RootBridge.MemAbove4G.Limit;
> +          break;
> +
> +        case TypePMem64:
> +          AddrBase = RootBridgeInstance->RootBridge.PMemAbove4G.Base;
> +          AddrLimit = RootBridgeInstance->RootBridge.PMemAbove4G.Limit;
> +          break;
> +
> +        default:
> +          continue;
> +        } // end switch (Index)
> +
> +        AddrLen = ResNode->Length;
> +
> +        if ((AddrBase + AddrLen - 1) > AddrLimit) {
> +          ReturnStatus = EFI_OUT_OF_RESOURCES;
> +          ResNode->Length = 0;
> +        } else {
> +          // Get the number of '1' in Alignment.
> +          BitsOfAlignment = (UINTN)(HighBitSet64 (ResNode->Alignment) + 1);
> +
> +          Status = gDS->AllocateMemorySpace (
> +                          EfiGcdAllocateAddress,
> +                          EfiGcdMemoryTypeMemoryMappedIo,
> +                          BitsOfAlignment,
> +                          AddrLen,
> +                          &AddrBase,
> +                          mDriverImageHandle,
> +                          NULL
> +                          );
> +
> +          if (!EFI_ERROR (Status)) {
> +            ResNode->Base   = (UINTN)AddrBase;
> +            ResNode->Status = ResAllocated;
> +          } else {
> +            ReturnStatus = EFI_OUT_OF_RESOURCES;
> +            ResNode->Length = 0;
> +          }
> +        }
> +      } // end for
> +      List = List->ForwardLink;
> +    } // end while
> +
> +    break;
> +
> +  case EfiPciHostBridgeSetResources:
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (SetResources)\n");
> +    break;
> +
> +  case EfiPciHostBridgeFreeResources:
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (FreeResources)\n");
> +
> +    List = HostBridgeInstance->Head.ForwardLink;
> +
> +    while (List != &HostBridgeInstance->Head) {
> +      RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +
> +      for (Index = TypeIo; Index < TypeMax; Index++) {
> +        ResNode = &(RootBridgeInstance->ResAllocNode[Index]);
> +
> +        if (ResNode->Status == ResAllocated) {
> +          AddrLen = ResNode->Length;
> +          AddrBase = ResNode->Base;
> +
> +          switch (Index) {
> +          case TypeIo:
> +          case TypeMem32:
> +          case TypePMem32:
> +          case TypeMem64:
> +          case TypePMem64:
> +            Status = gDS->FreeMemorySpace (AddrBase, AddrLen);
> +            if (EFI_ERROR (Status)) {
> +              ReturnStatus = Status;
> +            }
> +            break;
> +
> +          default:
> +            continue;
> +          } // end switch (Index)
> +
> +          ResNode->Type      = Index;
> +          ResNode->Base      = 0;
> +          ResNode->Length    = 0;
> +          ResNode->Status    = ResNone;
> +        }
> +      }
> +
> +      List = List->ForwardLink;
> +    }
> +
> +    HostBridgeInstance->ResourceSubmited = FALSE;
> +    HostBridgeInstance->CanRestarted     = TRUE;
> +    break;
> +
> +  case EfiPciHostBridgeEndResourceAllocation:
> +    //
> +    // The resource allocation phase is completed.  No specific action is required
> +    // here. This notification can be used to perform any chipset specific programming.
> +    //
> +    PCIE_DEBUG ("PciHostBridge: NotifyPhase (EndResourceAllocation)\n");
> +    HostBridgeInstance->CanRestarted = FALSE;
> +    break;
> +
> +  default:
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Notify BSP Driver the phase we are being
> +  List = HostBridgeInstance->Head.ForwardLink;
> +  while (List != &HostBridgeInstance->Head) {
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +
> +    // Retrieve the HostBridgeIdx and RootBridgeIdx from UID
> +    // UID = (UINT32)((HostBridgeIdx << 16) + RootBridgeIdx);
> +    DevPath = (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *)RootBridgeInstance->RootBridge.DevicePath;
> +    HostBridgeIdx = DevPath->AcpiDevicePath.UID / (1<<16);
> +    RootBridgeIdx = DevPath->AcpiDevicePath.UID % (1<<16);
> +
> +    // Notify BSP Driver
> +    if (Ac01PcieHostBridgeNotifyPhase != NULL) {
> +      Ac01PcieHostBridgeNotifyPhase (HostBridgeIdx, RootBridgeIdx, Phase);
> +    }
> +
> +    List = List->ForwardLink;
> +  }
> +
> +  return ReturnStatus;
> +}
> +
> +/**
> +   Return the device handle of the next PCI root bridge that is associated with this Host Bridge.
> +
> +   This function is called multiple times to retrieve the device handles of all the PCI root bridges that
> +   are associated with this PCI host bridge. Each PCI host bridge is associated with one or more PCI
> +   root bridges. On each call, the handle that was returned by the previous call is passed into the
> +   interface, and on output the interface returns the device handle of the next PCI root bridge. The
> +   caller can use the handle to obtain the instance of the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
> +   for that root bridge. When there are no more PCI root bridges to report, the interface returns
> +   EFI_NOT_FOUND. A PCI enumerator must enumerate the PCI root bridges in the order that they
> +   are returned by this function.
> +   For D945 implementation, there is only one root bridge in PCI host bridge.
> +
> +   @param[in]       This              The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in, out]  RootBridgeHandle  Returns the device handle of the next PCI root bridge.
> +
> +   @retval EFI_SUCCESS            If parameter RootBridgeHandle = NULL, then return the first Rootbridge handle of the
> +                                  specific Host bridge and return EFI_SUCCESS.
> +   @retval EFI_NOT_FOUND          Can not find the any more root bridge in specific host bridge.
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not an EFI_HANDLE that was
> +                                  returned on a previous call to GetNextRootBridge().
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextRootBridge (
> +  IN     EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN OUT EFI_HANDLE                                       *RootBridgeHandle
> +  )
> +{
> +  BOOLEAN                  NoRootBridge;
> +  LIST_ENTRY               *List;
> +  PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
> +
> +  NoRootBridge = TRUE;
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  List = HostBridgeInstance->Head.ForwardLink;
> +
> +  while (List != &HostBridgeInstance->Head) {
> +    NoRootBridge = FALSE;
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +
> +    if (*RootBridgeHandle == NULL) {
> +      //
> +      // Return the first Root Bridge Handle of the Host Bridge
> +      //
> +      *RootBridgeHandle = RootBridgeInstance->RootBridgeHandle;
> +
> +      return EFI_SUCCESS;
> +    } else {
> +      if (*RootBridgeHandle == RootBridgeInstance->RootBridgeHandle) {
> +        //
> +        // Get next if have
> +        //
> +        List = List->ForwardLink;
> +
> +        if (List != &HostBridgeInstance->Head) {
> +          RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +          *RootBridgeHandle = RootBridgeInstance->RootBridgeHandle;
> +
> +          return EFI_SUCCESS;
> +        }
> +
> +        return EFI_NOT_FOUND;
> +      }
> +    }
> +
> +    List = List->ForwardLink;
> +  } // end while
> +
> +  return NoRootBridge ? EFI_NOT_FOUND : EFI_INVALID_PARAMETER;
> +}
> +
> +/**
> +   Returns the allocation attributes of a PCI root bridge.
> +
> +   The function returns the allocation attributes of a specific PCI root bridge. The attributes can vary
> +   from one PCI root bridge to another. These attributes are different from the decode-related
> +   attributes that are returned by the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.GetAttributes() member function. The
> +   RootBridgeHandle parameter is used to specify the instance of the PCI root bridge. The device
> +   handles of all the root bridges that are associated with this host bridge must be obtained by calling
> +   GetNextRootBridge(). The attributes are static in the sense that they do not change during or
> +   after the enumeration process. The hardware may provide mechanisms to change the attributes on
> +   the fly, but such changes must be completed before EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL is
> +   installed. The permitted values of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ATTRIBUTES are defined in
> +   "Related Definitions" below. The caller uses these attributes to combine multiple resource requests.
> +   For example, if the flag EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM is set, the PCI bus enumerator needs to
> +   include requests for the prefetchable memory in the nonprefetchable memory pool and not request any
> +   prefetchable memory.
> +      Attribute                                 Description
> +   ------------------------------------         ----------------------------------------------------------------------
> +   EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM         If this bit is set, then the PCI root bridge does not support separate
> +                                                windows for nonprefetchable and prefetchable memory. A PCI bus
> +                                                driver needs to include requests for prefetchable memory in the
> +                                                nonprefetchable memory pool.
> +
> +   EFI_PCI_HOST_BRIDGE_MEM64_DECODE             If this bit is set, then the PCI root bridge supports 64-bit memory
> +                                                windows. If this bit is not set, the PCI bus driver needs to include
> +                                                requests for a 64-bit memory address in the corresponding 32-bit
> +                                                memory pool.
> +
> +   @param[in]   This               The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in]   RootBridgeHandle   The device handle of the PCI root bridge in which the caller is interested. Type
> +                                   EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI 2.0 Specification.
> +   @param[out]  Attributes         The pointer to attribte of root bridge, it is output parameter
> +
> +   @retval EFI_INVALID_PARAMETER   Attribute pointer is NULL
> +   @retval EFI_INVALID_PARAMETER   RootBridgehandle is invalid.
> +   @retval EFI_SUCCESS             Success to get attribute of interested root bridge.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetAttributes (
> +  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN  EFI_HANDLE                                       RootBridgeHandle,
> +  OUT UINT64                                           *Attributes
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
> +
> +  if (Attributes == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  List = HostBridgeInstance->Head.ForwardLink;
> +
> +  while (List != &HostBridgeInstance->Head) {
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +    if (RootBridgeHandle == RootBridgeInstance->RootBridgeHandle) {
> +      *Attributes = RootBridgeInstance->RootBridgeAttrib;
> +
> +      return EFI_SUCCESS;
> +    }
> +
> +    List = List->ForwardLink;
> +  }
> +
> +  //
> +  // RootBridgeHandle is not an EFI_HANDLE
> +  // that was returned on a previous call to GetNextRootBridge()
> +  //
> +  return EFI_INVALID_PARAMETER;
> +}
> +
> +/**
> +   Sets up the specified PCI root bridge for the bus enumeration process.
> +
> +   This member function sets up the root bridge for bus enumeration and returns the PCI bus range
> +   over which the search should be performed in ACPI 2.0 resource descriptor format.
> +
> +   @param[in]   This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
> +   @param[in]   RootBridgeHandle  The PCI Root Bridge to be set up.
> +   @param[out]  Configuration     Pointer to the pointer to the PCI bus resource descriptor.
> +
> +   @retval EFI_INVALID_PARAMETER Invalid Root bridge's handle
> +   @retval EFI_OUT_OF_RESOURCES  Fail to allocate ACPI resource descriptor tag.
> +   @retval EFI_SUCCESS           Sucess to allocate ACPI resource descriptor.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +StartBusEnumeration (
> +  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN  EFI_HANDLE                                       RootBridgeHandle,
> +  OUT VOID                                             **Configuration
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
> +  VOID                     *Buffer;
> +  UINT8                    *Temp;
> +  UINT64                   BusStart;
> +  UINT64                   BusEnd;
> +
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  List = HostBridgeInstance->Head.ForwardLink;
> +
> +  while (List != &HostBridgeInstance->Head) {
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +    if (RootBridgeHandle == RootBridgeInstance->RootBridgeHandle) {
> +      //
> +      // Set up the Root Bridge for Bus Enumeration
> +      //
> +      BusStart = RootBridgeInstance->RootBridge.Bus.Base;
> +      BusEnd   = RootBridgeInstance->RootBridge.Bus.Limit;
> +
> +      Buffer = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
> +      if (Buffer == NULL) {
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      Temp = (UINT8 *)Buffer;
> +
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->Len  = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->GenFlag = 0;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->SpecificFlag = 0;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrSpaceGranularity = 0;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrRangeMin = BusStart;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrRangeMax = BusEnd;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrTranslationOffset = 0;
> +      ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrLen = BusEnd - BusStart + 1;
> +
> +      Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
> +      ((EFI_ACPI_END_TAG_DESCRIPTOR *)Temp)->Desc = ACPI_END_TAG_DESCRIPTOR;
> +      ((EFI_ACPI_END_TAG_DESCRIPTOR *)Temp)->Checksum = 0x0;
> +
> +      *Configuration = Buffer;
> +
> +      return EFI_SUCCESS;
> +    }
> +
> +    List = List->ForwardLink;
> +  }
> +
> +  return EFI_INVALID_PARAMETER;
> +}
> +
> +/**
> +   Programs the PCI root bridge hardware so that it decodes the specified PCI bus range.
> +
> +   This member function programs the specified PCI root bridge to decode the bus range that is
> +   specified by the input parameter Configuration.
> +   The bus range information is specified in terms of the ACPI 2.0 resource descriptor format.
> +
> +   @param[in] This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
> +   @param[in] RootBridgeHandle  The PCI Root Bridge whose bus range is to be programmed
> +   @param[in] Configuration     The pointer to the PCI bus resource descriptor
> +
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
> +   @retval EFI_INVALID_PARAMETER  Configuration does not point to a valid ACPI 2.0 resource descriptor.
> +   @retval EFI_INVALID_PARAMETER  Configuration does not include a valid ACPI 2.0 bus resource descriptor.
> +   @retval EFI_INVALID_PARAMETER  Configuration includes valid ACPI 2.0 resource descriptors other than
> +                                  bus descriptors.
> +   @retval EFI_INVALID_PARAMETER  Configuration contains one or more invalid ACPI resource descriptors.
> +   @retval EFI_INVALID_PARAMETER  "Address Range Minimum" is invalid for this root bridge.
> +   @retval EFI_INVALID_PARAMETER  "Address Range Length" is invalid for this root bridge.
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware error.
> +   @retval EFI_SUCCESS            The bus range for the PCI root bridge was programmed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetBusNumbers (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_HANDLE                                       RootBridgeHandle,
> +  IN VOID                                             *Configuration
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
> +  PCI_RES_NODE             *ResNode;
> +  UINT8                    *Ptr;
> +  UINTN                    BusStart;
> +  UINTN                    BusEnd;
> +  UINTN                    BusLen;
> +
> +  if (Configuration == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Ptr = Configuration;
> +
> +  //
> +  // Check the Configuration is valid
> +  //
> +  if (*Ptr != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
> +  if (*Ptr != ACPI_END_TAG_DESCRIPTOR) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  List = HostBridgeInstance->Head.ForwardLink;
> +
> +  Ptr = Configuration;
> +
> +  while (List != &HostBridgeInstance->Head) {
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +    if (RootBridgeHandle == RootBridgeInstance->RootBridgeHandle) {
> +      BusStart = (UINTN)((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrRangeMin;
> +      BusLen = (UINTN)((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrLen;
> +      BusEnd = BusStart + BusLen - 1;
> +
> +      if (BusStart > BusEnd) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +
> +      if ((BusStart < RootBridgeInstance->RootBridge.Bus.Base) ||
> +          (BusEnd > RootBridgeInstance->RootBridge.Bus.Limit))
> +      {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +
> +      //
> +      // Update the Bus Range
> +      //
> +      ResNode = &(RootBridgeInstance->ResAllocNode[TypeBus]);
> +      ResNode->Base   = BusStart;
> +      ResNode->Length = BusLen;
> +      ResNode->Status = ResAllocated;
> +
> +      return EFI_SUCCESS;
> +    }
> +
> +    List = List->ForwardLink;
> +  }
> +
> +  return EFI_INVALID_PARAMETER;
> +}
> +
> +/**
> +   Submits the I/O and memory resource requirements for the specified PCI root bridge.
> +
> +   This function is used to submit all the I/O and memory resources that are required by the specified
> +   PCI root bridge. The input parameter Configuration is used to specify the following:
> +   - The various types of resources that are required
> +   - The associated lengths in terms of ACPI 2.0 resource descriptor format
> +
> +   @param[in] This              Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +   @param[in] RootBridgeHandle  The PCI root bridge whose I/O and memory resource requirements are being submitted.
> +   @param[in] Configuration     The pointer to the PCI I/O and PCI memory resource descriptor.
> +
> +   @retval EFI_SUCCESS            The I/O and memory resource requests for a PCI root bridge were accepted.
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
> +   @retval EFI_INVALID_PARAMETER  Configuration does not point to a valid ACPI 2.0 resource descriptor.
> +   @retval EFI_INVALID_PARAMETER  Configuration includes requests for one or more resource types that are
> +                                  not supported by this PCI root bridge. This error will happen if the caller
> +                                  did not combine resources according to Attributes that were returned by
> +                                  GetAllocAttributes().
> +   @retval EFI_INVALID_PARAMETER  Address Range Maximum" is invalid.
> +   @retval EFI_INVALID_PARAMETER  "Address Range Length" is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  "Address Space Granularity" is invalid for this PCI root bridge.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SubmitResources (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_HANDLE                                       RootBridgeHandle,
> +  IN VOID                                             *Configuration
> +  )
> +{
> +  LIST_ENTRY                        *List;
> +  PCI_HOST_BRIDGE_INSTANCE          *HostBridgeInstance;
> +  PCI_ROOT_BRIDGE_INSTANCE          *RootBridgeInstance = NULL;
> +  PCI_RES_NODE                      *ResNode;
> +  UINT8                             *Temp;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
> +  UINTN                             Index = 0;
> +  UINTN                             AddrSpaceCnt = 0;
> +  UINTN                             i;
> +
> +  //
> +  // Check the input parameter: Configuration
> +  //
> +  if (Configuration == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  List = HostBridgeInstance->Head.ForwardLink;
> +
> +  //
> +  // Input resource descriptor must end properly
> +  //
> +  Temp = (UINT8 *)Configuration;
> +  AddrSpaceCnt = 0;
> +  while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
> +    Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
> +    AddrSpaceCnt++;
> +  }
> +  if (*Temp != ACPI_END_TAG_DESCRIPTOR) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Get the corresponding Root Bridge Instance
> +  //
> +  while (List != &HostBridgeInstance->Head) {
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +
> +    if (RootBridgeHandle == RootBridgeInstance->RootBridgeHandle) {
> +      break;
> +    }
> +
> +    List = List->ForwardLink;
> +  }
> +
> +  if (RootBridgeHandle != RootBridgeInstance->RootBridgeHandle) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PCIE_DEBUG ("%a: \n", __FUNCTION__);
> +
> +  Temp = (UINT8 *)Configuration;
> +  for (i = 0; i < AddrSpaceCnt; i++) {
> +    Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp;
> +
> +    PCIE_DEBUG ("Ptr->ResType:%d\n", Ptr->ResType);
> +    PCIE_DEBUG ("Ptr->Addrlen:0x%llx\n", Ptr->AddrLen);
> +    PCIE_DEBUG ("Ptr->AddrRangeMax:0x%llx\n", Ptr->AddrRangeMax);
> +    PCIE_DEBUG ("Ptr->AddrRangeMin:0x%llx\n", Ptr->AddrRangeMin);
> +    PCIE_DEBUG ("Ptr->SpecificFlag:0x%llx\n", Ptr->SpecificFlag);
> +    PCIE_DEBUG ("Ptr->AddrSpaceGranularity:%d\n", Ptr->AddrSpaceGranularity);
> +    PCIE_DEBUG ("RootBridgeInstance->RootBridgeAttrib:0x%llx\n", RootBridgeInstance->RootBridgeAttrib);
> +
> +    switch (Ptr->ResType) {
> +    case ACPI_ADDRESS_SPACE_TYPE_MEM:
> +
> +      if (Ptr->AddrSpaceGranularity != 32 && Ptr->AddrSpaceGranularity != 64) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +
> +      if (Ptr->AddrSpaceGranularity == 32) {
> +        if (Ptr->AddrLen >= SIZE_4GB) {
> +          return EFI_INVALID_PARAMETER;
> +        }
> +
> +        Index = (Ptr->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) ?
> +                TypePMem32 : TypeMem32;
> +      }
> +
> +      if (Ptr->AddrSpaceGranularity == 64) {
> +        Index = (Ptr->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) ?
> +                TypePMem64 : TypeMem64;
> +      }
> +
> +      break;
> +
> +    case ACPI_ADDRESS_SPACE_TYPE_IO:
> +      //
> +      // Check address range alignment
> +      //
> +      if (Ptr->AddrRangeMax != (GetPowerOfTwo64 (Ptr->AddrRangeMax + 1) - 1)) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +
> +      Index = TypeIo;
> +      break;
> +
> +    case ACPI_ADDRESS_SPACE_TYPE_BUS:
> +    default:
> +      ASSERT (FALSE);
> +      break;
> +    }
> +
> +    ResNode = &(RootBridgeInstance->ResAllocNode[Index]);
> +    ResNode->Length  = Ptr->AddrLen;
> +    ResNode->Alignment = Ptr->AddrRangeMax;
> +    ResNode->Status  = ResSubmitted;
> +
> +    Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
> +  }
> +
> +  HostBridgeInstance->ResourceSubmited = TRUE;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +   Returns the proposed resource settings for the specified PCI root bridge.
> +
> +   This member function returns the proposed resource settings for the specified PCI root bridge. The
> +   proposed resource settings are prepared when NotifyPhase() is called with a Phase of
> +   EfiPciHostBridgeAllocateResources. The output parameter Configuration
> +   specifies the following:
> +   - The various types of resources, excluding bus resources, that are allocated
> +   - The associated lengths in terms of ACPI 2.0 resource descriptor format
> +
> +   @param[in]  This              Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +   @param[in]  RootBridgeHandle  The PCI root bridge handle. Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI 2.0 Specification.
> +   @param[out] Configuration     The pointer to the pointer to the PCI I/O and memory resource descriptor.
> +
> +   @retval EFI_SUCCESS            The requested parameters were returned.
> +   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware error.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProposedResources (
> +  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN  EFI_HANDLE                                       RootBridgeHandle,
> +  OUT VOID                                             **Configuration
> +  )
> +{
> +  LIST_ENTRY                        *List = NULL;
> +  PCI_HOST_BRIDGE_INSTANCE          *HostBridgeInstance = NULL;
> +  PCI_ROOT_BRIDGE_INSTANCE          *RootBridgeInstance = NULL;
> +  UINTN                             Index = 0;
> +  VOID                              *Buffer = NULL;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor = NULL;
> +  EFI_ACPI_END_TAG_DESCRIPTOR       *End = NULL;
> +  UINT64                            ResStatus;
> +
> +  Buffer = NULL;
> +
> +  PCIE_DEBUG ("%a: \n", __FUNCTION__);
> +
> +  //
> +  // Get the Host Bridge Instance from the resource allocation protocol
> +  //
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  List = HostBridgeInstance->Head.ForwardLink;
> +
> +  //
> +  // Get the corresponding Root Bridge Instance
> +  //
> +  while (List != &HostBridgeInstance->Head) {
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +
> +    if (RootBridgeHandle == RootBridgeInstance->RootBridgeHandle) {
> +      break;
> +    }
> +
> +    List = List->ForwardLink;
> +  }
> +
> +  if (RootBridgeHandle != RootBridgeInstance->RootBridgeHandle) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Buffer = AllocateZeroPool (
> +             (TypeMax - 1) * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
> +             sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
> +             );
> +  if (Buffer == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Buffer;
> +  for (Index = TypeIo; Index < TypeMax; Index++) {
> +    ResStatus = RootBridgeInstance->ResAllocNode[Index].Status;
> +
> +    switch (Index) {
> +    case TypeIo:
> +      Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_IO;
> +      Descriptor->SpecificFlag         = 0;
> +      Descriptor->AddrSpaceGranularity = 32;
> +      break;
> +
> +    case TypeMem32:
> +    case TypePMem32:
> +      Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      Descriptor->SpecificFlag         = (Index == TypeMem32) ? 0 :
> +                                         EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
> +      Descriptor->AddrSpaceGranularity = 32;
> +      break;
> +
> +    case TypeMem64:
> +    case TypePMem64:
> +      Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      Descriptor->SpecificFlag         = (Index == TypeMem64) ? 0 :
> +                                         EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
> +      Descriptor->AddrSpaceGranularity = 64;
> +      break;
> +
> +    default:
> +      continue;
> +    }
> +
> +    Descriptor->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +    Descriptor->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
> +    Descriptor->GenFlag               = 0;
> +    Descriptor->AddrRangeMin          = RootBridgeInstance->ResAllocNode[Index].Base;
> +    Descriptor->AddrLen               = RootBridgeInstance->ResAllocNode[Index].Length;
> +    Descriptor->AddrRangeMax          = Descriptor->AddrRangeMin + Descriptor->AddrLen - 1;
> +    Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;
> +
> +    PCIE_DEBUG ("Descriptor->ResType:%d\n", Descriptor->ResType);
> +    PCIE_DEBUG ("Descriptor->Addrlen:%llx\n", Descriptor->AddrLen);
> +    PCIE_DEBUG ("Descriptor->AddrRangeMax:%llx\n", Descriptor->AddrRangeMax);
> +    PCIE_DEBUG ("Descriptor->AddrRangeMin:%llx\n", Descriptor->AddrRangeMin);
> +    PCIE_DEBUG ("Descriptor->SpecificFlag:%llx\n", Descriptor->SpecificFlag);
> +    PCIE_DEBUG ("Descriptor->AddrTranslationOffset:%d\n", Descriptor->AddrTranslationOffset);
> +    PCIE_DEBUG ("Descriptor->AddrSpaceGranularity:%d\n", Descriptor->AddrSpaceGranularity);
> +
> +    Descriptor++;
> +  }
> +
> +  //
> +  // Terminate the entries.
> +  //
> +  End = (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor;
> +  End->Desc      = ACPI_END_TAG_DESCRIPTOR;
> +  End->Checksum  = 0x0;
> +
> +  *Configuration = Buffer;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +   Provides the hooks from the PCI bus driver to every PCI controller (device/function) at various
> +   stages of the PCI enumeration process that allow the host bridge driver to preinitialize individual
> +   PCI controllers before enumeration.
> +
> +   This function is called during the PCI enumeration process. No specific action is expected from this
> +   member function. It allows the host bridge driver to preinitialize individual PCI controllers before
> +   enumeration.
> +
> +   @param This              Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +   @param RootBridgeHandle  The associated PCI root bridge handle. Type EFI_HANDLE is defined in
> +                            InstallProtocolInterface() in the UEFI 2.0 Specification.
> +   @param PciAddress        The address of the PCI device on the PCI bus. This address can be passed to the
> +                            EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL member functions to access the PCI
> +                            configuration space of the device. See Table 12-1 in the UEFI 2.0 Specification for
> +                            the definition of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS.
> +   @param Phase             The phase of the PCI device enumeration.
> +
> +   @retval EFI_SUCCESS              The requested parameters were returned.
> +   @retval EFI_INVALID_PARAMETER    RootBridgeHandle is not a valid root bridge handle.
> +   @retval EFI_INVALID_PARAMETER    Phase is not a valid phase that is defined in
> +                                    EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE.
> +   @retval EFI_DEVICE_ERROR         Programming failed due to a hardware error. The PCI enumerator should
> +                                    not enumerate this device, including its child devices if it is a PCI-to-PCI
> +                                    bridge.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PreprocessController (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
> +  IN EFI_HANDLE                                       RootBridgeHandle,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS      PciAddress,
> +  IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE     Phase
> +  )
> +{
> +  PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
> +  LIST_ENTRY               *List;
> +
> +  HostBridgeInstance = PCI_HOST_BRIDGE_FROM_THIS (This);
> +  List = HostBridgeInstance->Head.ForwardLink;
> +
> +  //
> +  // Enumerate the root bridges in this host bridge
> +  //
> +  while (List != &HostBridgeInstance->Head) {
> +
> +    RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
> +    if (RootBridgeHandle == RootBridgeInstance->RootBridgeHandle) {
> +      break;
> +    }
> +    List = List->ForwardLink;
> +  }
> +
> +  if (List == &HostBridgeInstance->Head) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((UINT32)Phase > EfiPciBeforeResourceCollection) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
> new file mode 100644
> index 000000000000..552a5f6de4c6
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
> @@ -0,0 +1,1582 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <IndustryStandard/Pci.h>
> +#include <Library/ArmLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcieCoreLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PciHostBridgeLib.h>
> +#include <Library/PciLib.h>
> +#include <Library/TimerLib.h>
> +#include <Library/UefiLib.h>
> +
> +#include "PciHostBridge.h"
> +#include "PciRootBridgeIo.h"
> +
> +//
> +// Memory Controller Pci Root Bridge Io Module Variables
> +//
> +EFI_METRONOME_ARCH_PROTOCOL *mMetronome = NULL;
> +
> +//
> +// Lookup table for increment values based on transfer widths
> +//
> +UINT8 mInStride[] = {
> +  1, // EfiPciWidthUint8
> +  2, // EfiPciWidthUint16
> +  4, // EfiPciWidthUint32
> +  8, // EfiPciWidthUint64
> +  0, // EfiPciWidthFifoUint8
> +  0, // EfiPciWidthFifoUint16
> +  0, // EfiPciWidthFifoUint32
> +  0, // EfiPciWidthFifoUint64
> +  1, // EfiPciWidthFillUint8
> +  2, // EfiPciWidthFillUint16
> +  4, // EfiPciWidthFillUint32
> +  8  // EfiPciWidthFillUint64
> +};
> +
> +//
> +// Lookup table for increment values based on transfer widths
> +//
> +UINT8 mOutStride[] = {
> +  1, // EfiPciWidthUint8
> +  2, // EfiPciWidthUint16
> +  4, // EfiPciWidthUint32
> +  8, // EfiPciWidthUint64
> +  1, // EfiPciWidthFifoUint8
> +  2, // EfiPciWidthFifoUint16
> +  4, // EfiPciWidthFifoUint32
> +  8, // EfiPciWidthFifoUint64
> +  0, // EfiPciWidthFillUint8
> +  0, // EfiPciWidthFillUint16
> +  0, // EfiPciWidthFillUint32
> +  0  // EfiPciWidthFillUint64
> +};
> +
> +/**
> +  Check parameters for IO, MMIO, PCI read/write services of PCI Root Bridge IO.
> +
> +  The I/O operations are carried out exactly as requested. The caller is
> +  responsible for satisfying any alignment and I/O width restrictions that a PI
> +  System on a platform might require. For example on some platforms, width
> +  requests of EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other
> +  hand, will be handled by the driver.
> +
> +  @param[in] This           A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +
> +  @param[in] OperationType  I/O operation type: IO/MMIO/PCI.
> +
> +  @param[in] Width          Signifies the width of the I/O or Memory operation.
> +
> +  @param[in] Address        The base address of the I/O operation.
> +
> +  @param[in] Count          The number of I/O operations to perform. The number
> +                            of bytes moved is Width size * Count, starting at
> +                            Address.
> +
> +  @param[in] Buffer         For read operations, the destination buffer to
> +                            store the results. For write operations, the source
> +                            buffer from which to write data.
> +
> +  @retval EFI_SUCCESS            The parameters for this request pass the
> +                                 checks.
> +
> +  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
> +
> +  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +
> +  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
> +
> +  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
> +                                 and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoCheckParameter (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN OPERATION_TYPE                        OperationType,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                Address,
> +  IN UINTN                                 Count,
> +  IN VOID                                  *Buffer
> +  )
> +{
> +  PCI_ROOT_BRIDGE_INSTANCE                    *RootBridgeInstance;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr;
> +  UINT64                                      MaxCount;
> +  UINT64                                      Base = 0;
> +  UINT64                                      Limit = 0;
> +  UINT32                                      Size;
> +
> +  //
> +  // Check to see if Buffer is NULL
> +  //
> +  if (Buffer == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Check to see if Width is in the valid range
> +  //
> +  if ((UINT32)Width >= EfiPciWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // For FIFO type, the target address won't increase during the access,
> +  // so treat Count as 1
> +  //
> +  if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
> +    Count = 1;
> +  }
> +
> +  //
> +  // Check to see if Width is in the valid range for I/O Port operations
> +  //
> +  Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03);
> +  Size  = 1 << Width;
> +
> +  //
> +  // Config space accessing does not support 64-bit width
> +  //
> +  if ((OperationType == PciOperation) && (Width == EfiPciWidthUint64)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  RootBridgeInstance = ROOT_BRIDGE_FROM_THIS (This);
> +
> +  //
> +  // Check to see if any address associated with this transfer exceeds the
> +  // maximum allowed address.  The maximum address implied by the parameters
> +  // passed in is Address + Size * Count.  If the following condition is met,
> +  // then the transfer is not supported.
> +  //
> +  //    Address + Size * Count > Limit + 1
> +  //
> +  // Since Limit can be the maximum integer value supported by the CPU and
> +  // Count can also be the maximum integer value supported by the CPU, this
> +  // range check must be adjusted to avoid all oveflow conditions.
> +  //
> +  if (OperationType == IoOperation) {
> +    if (Address + MultU64x32 (Count, Size) <= RootBridgeInstance->RootBridge.Io.Limit + 1) {
> +      Base = RootBridgeInstance->RootBridge.Io.Base;
> +      Limit = RootBridgeInstance->RootBridge.Io.Limit;
> +    }
> +  } else if (OperationType == MemOperation) {
> +    if (Address + MultU64x32 (Count, Size) <= RootBridgeInstance->RootBridge.Mem.Limit + 1) {
> +      Base = RootBridgeInstance->RootBridge.Mem.Base;
> +      Limit = RootBridgeInstance->RootBridge.Mem.Limit;
> +    } else if (Address + MultU64x32 (Count, Size) <= RootBridgeInstance->RootBridge.PMem.Limit + 1) {
> +      Base = RootBridgeInstance->RootBridge.PMem.Base;
> +      Limit = RootBridgeInstance->RootBridge.PMem.Limit;
> +    } else if (Address + MultU64x32 (Count, Size) <= RootBridgeInstance->RootBridge.MemAbove4G.Limit + 1) {
> +      Base = RootBridgeInstance->RootBridge.MemAbove4G.Base;
> +      Limit = RootBridgeInstance->RootBridge.MemAbove4G.Limit;
> +    } else {
> +      Base = RootBridgeInstance->RootBridge.PMemAbove4G.Base;
> +      Limit = RootBridgeInstance->RootBridge.PMemAbove4G.Limit;
> +    }
> +  } else {
> +    PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&Address;
> +    if (PciRbAddr->Bus < RootBridgeInstance->RootBridge.Bus.Base ||
> +        PciRbAddr->Bus > RootBridgeInstance->RootBridge.Bus.Limit)
> +    {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    if (PciRbAddr->Device > PCI_MAX_DEVICE ||
> +        PciRbAddr->Function > PCI_MAX_FUNC)
> +    {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    Address = (PciRbAddr->ExtendedRegister != 0) ?
> +              PciRbAddr->ExtendedRegister :
> +              PciRbAddr->Register;
> +
> +    Base = 0;
> +    Limit = RootBridgeInstance->RootBridge.NoExtendedConfigSpace ? 0xFF : 0xFFF;
> +  }
> +
> +  //
> +  // Check to see if Address is aligned
> +  // ( Address is derived from  Extended register/Register.
> +  //   Now we can safely check the alignments )
> +  //
> +  if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (Address < Base) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Count == 0) {
> +    if (Address > Limit) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  } else {
> +    MaxCount = RShiftU64 (Limit, Width);
> +    if (MaxCount < (Count - 1)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +    if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +   Internal help function for read and write memory space.
> +
> +   @param[in]   This          A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Write         Switch value for Read or Write.
> +   @param[in]   Width         Signifies the width of the memory operations.
> +   @param[in]   UserAddress   The address within the PCI configuration space for the PCI controller.
> +   @param[in]   Count         The number of PCI configuration operations to perform. Bytes
> +                              moved is Width size * Count, starting at Address.
> +   @param[in, out] UserBuffer For read operations, the destination buffer to store the results. For
> +                              write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoMemRW (
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN     BOOLEAN                               Write,
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN     UINT64                                Address,
> +  IN     UINTN                                 Count,
> +  IN OUT VOID                                  *Buffer
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  UINT8                                 InStride;
> +  UINT8                                 OutStride;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OperationWidth;
> +  UINT8                                 *Uint8Buffer;
> +
> +  PCIE_MMIO_DEBUG (
> +    "%a: W: %d, Width: %d, Addr: 0x%lx, Count: %d\n",
> +    __FUNCTION__,
> +    Write,
> +    Width,
> +    Address,
> +    Count
> +    );
> +
> +  Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, Count, Buffer);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  InStride = mInStride[Width];
> +  OutStride = mOutStride[Width];
> +  OperationWidth = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03);
> +
> +  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
> +    if (Write) {
> +      switch (OperationWidth) {
> +      case EfiPciWidthUint8:
> +        MmioWrite8 ((UINTN)Address, *Uint8Buffer);
> +        break;
> +
> +      case EfiPciWidthUint16:
> +        MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
> +        break;
> +
> +      case EfiPciWidthUint32:
> +        MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
> +        break;
> +
> +      case EfiPciWidthUint64:
> +        MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
> +        break;
> +
> +      default:
> +        //
> +        // The RootBridgeIoCheckParameter call above will ensure that this
> +        // path is not taken.
> +        //
> +        ASSERT (FALSE);
> +        break;
> +      }
> +    } else {
> +      switch (OperationWidth) {
> +      case EfiPciWidthUint8:
> +        *Uint8Buffer = MmioRead8 ((UINTN)Address);
> +        break;
> +
> +      case EfiPciWidthUint16:
> +        *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
> +        break;
> +
> +      case EfiPciWidthUint32:
> +        *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
> +        break;
> +
> +      case EfiPciWidthUint64:
> +        *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
> +        break;
> +
> +      default:
> +        //
> +        // The RootBridgeIoCheckParameter call above will ensure that this
> +        // path is not taken.
> +        //
> +        ASSERT (FALSE);
> +        break;
> +      }
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +   Internal help function for read and write IO space.
> +
> +   @param[in]   This          A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Write         Switch value for Read or Write.
> +   @param[in]   Width         Signifies the width of the memory operations.
> +   @param[in]   UserAddress   The address within the PCI configuration space for the PCI controller.
> +   @param[in]   Count         The number of PCI configuration operations to perform. Bytes
> +                              moved is Width size * Count, starting at Address.
> +   @param[in, out] UserBuffer For read operations, the destination buffer to store the results. For
> +                              write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoIoRW (
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN     BOOLEAN                               Write,
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN     UINT64                                Address,
> +  IN     UINTN                                 Count,
> +  IN OUT VOID                                  *Buffer
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  UINT8                                 InStride;
> +  UINT8                                 OutStride;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OperationWidth;
> +  UINT8                                 *Uint8Buffer;
> +
> +  PCIE_MMIO_DEBUG (
> +    "%a: W: %d, Width: %d, Addr: 0x%lx, Count: %d\n",
> +    __FUNCTION__,
> +    Write,
> +    Width,
> +    Address,
> +    Count
> +    );
> +
> +  Status = RootBridgeIoCheckParameter (This, IoOperation, Width, Address, Count, Buffer);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  InStride = mInStride[Width];
> +  OutStride = mOutStride[Width];
> +  OperationWidth = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03);
> +
> +  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
> +    if (Write) {
> +      switch (OperationWidth) {
> +      case EfiPciWidthUint8:
> +        MmioWrite8 ((UINTN)Address, *Uint8Buffer);
> +        break;
> +
> +      case EfiPciWidthUint16:
> +        MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
> +        break;
> +
> +      case EfiPciWidthUint32:
> +        MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
> +        break;
> +
> +      case EfiPciWidthUint64:
> +        MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
> +        break;
> +
> +      default:
> +        //
> +        // The RootBridgeIoCheckParameter call above will ensure that this
> +        // path is not taken.
> +        //
> +        ASSERT (FALSE);
> +        break;
> +      }
> +    } else {
> +      switch (OperationWidth) {
> +      case EfiPciWidthUint8:
> +        *Uint8Buffer = MmioRead8 ((UINTN)Address);
> +        break;
> +
> +      case EfiPciWidthUint16:
> +        *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
> +        break;
> +
> +      case EfiPciWidthUint32:
> +        *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
> +        break;
> +
> +      case EfiPciWidthUint64:
> +        *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
> +        break;
> +
> +      default:
> +        //
> +        // The RootBridgeIoCheckParameter call above will ensure that this
> +        // path is not taken.
> +        //
> +        ASSERT (FALSE);
> +        break;
> +      }
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +   Internal help function for read and write PCI configuration space.
> +
> +   @param[in]   This          A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +   @param[in]   Write         Switch value for Read or Write.
> +   @param[in]   Width         Signifies the width of the memory operations.
> +   @param[in]   UserAddress   The address within the PCI configuration space for the PCI controller.
> +   @param[in]   Count         The number of PCI configuration operations to perform. Bytes
> +                              moved is Width size * Count, starting at Address.
> +   @param[in, out] UserBuffer For read operations, the destination buffer to store the results. For
> +                              write operations, the source buffer to write data from.
> +
> +   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPciRW (
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN     BOOLEAN                               Write,
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN     UINT64                                Address,
> +  IN     UINTN                                 Count,
> +  IN OUT VOID                                  *Buffer
> +  )
> +{
> +  EFI_STATUS                                  Status;
> +  UINT8                                       InStride;
> +  UINT8                                       OutStride;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH       OperationWidth;
> +  UINT8                                       *Uint8Buffer;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr;
> +  UINTN                                       PcieRegAddr;
> +  PCI_ROOT_BRIDGE_INSTANCE                    *RootBridgeInstance;
> +
> +  OperationWidth = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03);
> +  PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&Address;
> +
> +  Status = RootBridgeIoCheckParameter (This, PciOperation, Width, Address, Count, Buffer);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  RootBridgeInstance = ROOT_BRIDGE_FROM_THIS (This);
> +
> +  PcieRegAddr = (UINTN)PCI_LIB_ADDRESS (
> +                         PciRbAddr->Bus,
> +                         PciRbAddr->Device,
> +                         PciRbAddr->Function,
> +                         (PciRbAddr->ExtendedRegister != 0) ? PciRbAddr->ExtendedRegister : PciRbAddr->Register
> +                         );
> +
> +  //
> +  // Select loop based on the width of the transfer
> +  //
> +  InStride  = mInStride[Width];
> +  OutStride = mOutStride[Width];
> +
> +  for (Uint8Buffer = Buffer; Count > 0; PcieRegAddr += InStride, Uint8Buffer += OutStride, Count--) {
> +    if (Write) {
> +      switch (OperationWidth) {
> +      case EfiPciWidthUint8:
> +        Ac01PcieConfigRW ((VOID *)&RootBridgeInstance->RootBridge, PcieRegAddr, TRUE, 1, Uint8Buffer);
> +        break;
> +
> +      case EfiPciWidthUint16:
> +        Ac01PcieConfigRW ((VOID *)&RootBridgeInstance->RootBridge, PcieRegAddr, TRUE, 2, Uint8Buffer);
> +        break;
> +
> +      case EfiPciWidthUint32:
> +        Ac01PcieConfigRW ((VOID *)&RootBridgeInstance->RootBridge, PcieRegAddr, TRUE, 4, Uint8Buffer);
> +        break;
> +
> +      default:
> +        //
> +        // The RootBridgeIoCheckParameter call above will ensure that this
> +        // path is not taken.
> +        //
> +        ASSERT (FALSE);
> +        break;
> +      }
> +    } else {
> +      switch (OperationWidth) {
> +      case EfiPciWidthUint8:
> +        Ac01PcieConfigRW ((VOID *)&RootBridgeInstance->RootBridge, PcieRegAddr, FALSE, 1, Uint8Buffer);
> +        break;
> +
> +      case EfiPciWidthUint16:
> +        Ac01PcieConfigRW ((VOID *)&RootBridgeInstance->RootBridge, PcieRegAddr, FALSE, 2, Uint8Buffer);
> +        break;
> +
> +      case EfiPciWidthUint32:
> +        Ac01PcieConfigRW ((VOID *)&RootBridgeInstance->RootBridge, PcieRegAddr, FALSE, 4, Uint8Buffer);
> +        break;
> +
> +      default:
> +        //
> +        // The RootBridgeIoCheckParameter call above will ensure that this
> +        // path is not taken.
> +        //
> +        ASSERT (FALSE);
> +        break;
> +      }
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Polls an address in memory mapped I/O space until an exit condition is met,
> +  or a timeout occurs.
> +
> +  This function provides a standard way to poll a PCI memory location. A PCI
> +  memory read operation is performed at the PCI memory address specified by
> +  Address for the width specified by Width. The result of this PCI memory read
> +  operation is stored in Result. This PCI memory read operation is repeated
> +  until either a timeout of Delay 100 ns units has expired, or (Result & Mask)
> +  is equal to Value.
> +
> +  @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[in]   Width     Signifies the width of the memory operations.
> +  @param[in]   Address   The base address of the memory operations. The caller
> +                         is responsible for aligning Address if required.
> +  @param[in]   Mask      Mask used for the polling criteria. Bytes above Width
> +                         in Mask are ignored. The bits in the bytes below Width
> +                         which are zero in Mask are ignored when polling the
> +                         memory address.
> +  @param[in]   Value     The comparison value used for the polling exit
> +                         criteria.
> +  @param[in]   Delay     The number of 100 ns units to poll. Note that timer
> +                         available may be of poorer granularity.
> +  @param[out]  Result    Pointer to the last value read from the memory
> +                         location.
> +
> +  @retval EFI_SUCCESS            The last data returned from the access matched
> +                                 the poll exit criteria.
> +  @retval EFI_INVALID_PARAMETER  Width is invalid.
> +  @retval EFI_INVALID_PARAMETER  Result is NULL.
> +  @retval EFI_TIMEOUT            Delay expired before a match occurred.
> +  @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a
> +                                 lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPollMem (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINT64                                Mask,
> +  IN  UINT64                                Value,
> +  IN  UINT64                                Delay,
> +  OUT UINT64                                *Result
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT64     NumberOfTicks;
> +  UINT32     Remainder;
> +
> +  if (Result == NULL || (UINT32)Width > EfiPciWidthUint64) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // No matter what, always do a single poll.
> +  //
> +  Status = This->Mem.Read (This, Width, Address, 1, Result);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if ((*Result & Mask) == Value) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (Delay == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (mMetronome == NULL) {
> +    Status = gBS->LocateProtocol (
> +                    &gEfiMetronomeArchProtocolGuid,
> +                    NULL,
> +                    (VOID **)&mMetronome
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +  }
> +
> +  //
> +  // Determine the proper # of metronome ticks to wait for polling the
> +  // location.  The nuber of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
> +  // The "+1" to account for the possibility of the first tick being short
> +  // because we started in the middle of a tick.
> +  //
> +  // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome
> +  // protocol definition is updated.
> +  //
> +  NumberOfTicks = DivU64x32Remainder (
> +                    Delay,
> +                    (UINT32)mMetronome->TickPeriod,
> +                    &Remainder
> +                    );
> +  if (Remainder != 0) {
> +    NumberOfTicks += 1;
> +  }
> +  NumberOfTicks += 1;
> +
> +  while (NumberOfTicks != 0) {
> +
> +    mMetronome->WaitForTick (mMetronome, 1);
> +
> +    Status = This->Mem.Read (This, Width, Address, 1, Result);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    if ((*Result & Mask) == Value) {
> +      return EFI_SUCCESS;
> +    }
> +
> +    NumberOfTicks -= 1;
> +  }
> +
> +  return EFI_TIMEOUT;
> +}
> +
> +/**
> +  Reads from the I/O space of a PCI Root Bridge. Returns when either the
> +  polling exit criteria is satisfied or after a defined duration.
> +
> +  This function provides a standard way to poll a PCI I/O location. A PCI I/O
> +  read operation is performed at the PCI I/O address specified by Address for
> +  the width specified by Width.
> +  The result of this PCI I/O read operation is stored in Result. This PCI I/O
> +  read operation is repeated until either a timeout of Delay 100 ns units has
> +  expired, or (Result & Mask) is equal to Value.
> +
> +  @param[in] This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[in] Width     Signifies the width of the I/O operations.
> +  @param[in] Address   The base address of the I/O operations. The caller is
> +                       responsible for aligning Address if required.
> +  @param[in] Mask      Mask used for the polling criteria. Bytes above Width in
> +                       Mask are ignored. The bits in the bytes below Width
> +                       which are zero in Mask are ignored when polling the I/O
> +                       address.
> +  @param[in] Value     The comparison value used for the polling exit criteria.
> +  @param[in] Delay     The number of 100 ns units to poll. Note that timer
> +                       available may be of poorer granularity.
> +  @param[out] Result   Pointer to the last value read from the memory location.
> +
> +  @retval EFI_SUCCESS            The last data returned from the access matched
> +                                 the poll exit criteria.
> +  @retval EFI_INVALID_PARAMETER  Width is invalid.
> +  @retval EFI_INVALID_PARAMETER  Result is NULL.
> +  @retval EFI_TIMEOUT            Delay expired before a match occurred.
> +  @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a
> +                                 lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPollIo (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINT64                                Mask,
> +  IN  UINT64                                Value,
> +  IN  UINT64                                Delay,
> +  OUT UINT64                                *Result
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT64     NumberOfTicks;
> +  UINT32     Remainder;
> +
> +  //
> +  // No matter what, always do a single poll.
> +  //
> +
> +  if (Result == NULL || (UINT32)Width > EfiPciWidthUint64) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = This->Io.Read (This, Width, Address, 1, Result);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if ((*Result & Mask) == Value) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (Delay == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // Determine the proper # of metronome ticks to wait for polling the
> +  // location.  The number of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
> +  // The "+1" to account for the possibility of the first tick being short
> +  // because we started in the middle of a tick.
> +  //
> +  NumberOfTicks = DivU64x32Remainder (
> +                    Delay,
> +                    (UINT32)mMetronome->TickPeriod,
> +                    &Remainder
> +                    );
> +  if (Remainder != 0) {
> +    NumberOfTicks += 1;
> +  }
> +  NumberOfTicks += 1;
> +
> +  while (NumberOfTicks != 0) {
> +
> +    mMetronome->WaitForTick (mMetronome, 1);
> +
> +    Status = This->Io.Read (This, Width, Address, 1, Result);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    if ((*Result & Mask) == Value) {
> +      return EFI_SUCCESS;
> +    }
> +
> +    NumberOfTicks -= 1;
> +  }
> +  return EFI_TIMEOUT;
> +}
> +
> +/**
> +  Enables a PCI driver to access PCI controller registers in the PCI root
> +  bridge memory space.
> +
> +  The Mem.Read(), and Mem.Write() functions enable a driver to access PCI
> +  controller registers in the PCI root bridge memory space.
> +  The memory operations are carried out exactly as requested. The caller is
> +  responsible for satisfying any alignment and memory width restrictions that a
> +  PCI Root Bridge on a platform might require.
> +
> +  @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[in]   Width     Signifies the width of the memory operation.
> +  @param[in]   Address   The base address of the memory operation. The caller
> +                         is responsible for aligning the Address if required.
> +  @param[in]   Count     The number of memory operations to perform. Bytes
> +                         moved is Width size * Count, starting at Address.
> +  @param[out]  Buffer    For read operations, the destination buffer to store
> +                         the results. For write operations, the source buffer
> +                         to write data from.
> +
> +  @retval EFI_SUCCESS            The data was read from or written to the PCI
> +                                 root bridge.
> +  @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +  @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a
> +                                 lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoMemRead (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINTN                                 Count,
> +  OUT VOID                                  *Buffer
> +  )
> +{
> +  return RootBridgeIoMemRW (This, FALSE, Width, Address, Count, Buffer);
> +}
> +
> +/**
> +  Enables a PCI driver to access PCI controller registers in the PCI root
> +  bridge memory space.
> +
> +  The Mem.Read(), and Mem.Write() functions enable a driver to access PCI
> +  controller registers in the PCI root bridge memory space.
> +  The memory operations are carried out exactly as requested. The caller is
> +  responsible for satisfying any alignment and memory width restrictions that a
> +  PCI Root Bridge on a platform might require.
> +
> +  @param[in]   This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[in]   Width     Signifies the width of the memory operation.
> +  @param[in]   Address   The base address of the memory operation. The caller
> +                         is responsible for aligning the Address if required.
> +  @param[in]   Count     The number of memory operations to perform. Bytes
> +                         moved is Width size * Count, starting at Address.
> +  @param[in]   Buffer    For read operations, the destination buffer to store
> +                         the results. For write operations, the source buffer
> +                         to write data from.
> +
> +  @retval EFI_SUCCESS            The data was read from or written to the PCI
> +                                 root bridge.
> +  @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.
> +  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
> +  @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a
> +                                 lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoMemWrite (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                Address,
> +  IN UINTN                                 Count,
> +  IN VOID                                  *Buffer
> +  )
> +{
> +  return RootBridgeIoMemRW (This, TRUE, Width, Address, Count, Buffer);
> +}
> +
> +/**
> +  Enables a PCI driver to access PCI controller registers in the PCI root
> +  bridge I/O space.
> +
> +  @param[in]   This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[in]   Width       Signifies the width of the memory operations.
> +  @param[in]   Address     The base address of the I/O operation. The caller is
> +                           responsible for aligning the Address if required.
> +  @param[in]   Count       The number of I/O operations to perform. Bytes moved
> +                           is Width size * Count, starting at Address.
> +  @param[out]  Buffer      For read operations, the destination buffer to store
> +                           the results. For write operations, the source buffer
> +                           to write data from.
> +
> +  @retval EFI_SUCCESS              The data was read from or written to the PCI
> +                                   root bridge.
> +  @retval EFI_INVALID_PARAMETER    Width is invalid for this PCI root bridge.
> +  @retval EFI_INVALID_PARAMETER    Buffer is NULL.
> +  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a
> +                                   lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoIoRead (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINTN                                 Count,
> +  OUT VOID                                  *Buffer
> +  )
> +{
> +  return RootBridgeIoIoRW (This, FALSE, Width, Address, Count, Buffer);
> +}
> +
> +/**
> +  Enables a PCI driver to access PCI controller registers in the PCI root
> +  bridge I/O space.
> +
> +  @param[in]   This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[in]   Width       Signifies the width of the memory operations.
> +  @param[in]   Address     The base address of the I/O operation. The caller is
> +                           responsible for aligning the Address if required.
> +  @param[in]   Count       The number of I/O operations to perform. Bytes moved
> +                           is Width size * Count, starting at Address.
> +  @param[in]   Buffer      For read operations, the destination buffer to store
> +                           the results. For write operations, the source buffer
> +                           to write data from.
> +
> +  @retval EFI_SUCCESS              The data was read from or written to the PCI
> +                                   root bridge.
> +  @retval EFI_INVALID_PARAMETER    Width is invalid for this PCI root bridge.
> +  @retval EFI_INVALID_PARAMETER    Buffer is NULL.
> +  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a
> +                                   lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoIoWrite (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                Address,
> +  IN UINTN                                 Count,
> +  IN VOID                                  *Buffer
> +  )
> +{
> +  return RootBridgeIoIoRW (This, TRUE, Width, Address, Count, Buffer);
> +}
> +
> +/**
> +  Enables a PCI driver to copy one region of PCI root bridge memory space to
> +  another region of PCI root bridge memory space.
> +
> +  The CopyMem() function enables a PCI driver to copy one region of PCI root
> +  bridge memory space to another region of PCI root bridge memory space. This
> +  is especially useful for video scroll operation on a memory mapped video
> +  buffer.
> +  The memory operations are carried out exactly as requested. The caller is
> +  responsible for satisfying any alignment and memory width restrictions that a
> +  PCI root bridge on a platform might require.
> +
> +  @param[in] This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
> +                         instance.
> +  @param[in] Width       Signifies the width of the memory operations.
> +  @param[in] DestAddress The destination address of the memory operation. The
> +                         caller is responsible for aligning the DestAddress if
> +                         required.
> +  @param[in] SrcAddress  The source address of the memory operation. The caller
> +                         is responsible for aligning the SrcAddress if
> +                         required.
> +  @param[in] Count       The number of memory operations to perform. Bytes
> +                         moved is Width size * Count, starting at DestAddress
> +                         and SrcAddress.
> +
> +  @retval  EFI_SUCCESS             The data was copied from one memory region
> +                                   to another memory region.
> +  @retval  EFI_INVALID_PARAMETER   Width is invalid for this PCI root bridge.
> +  @retval  EFI_OUT_OF_RESOURCES    The request could not be completed due to a
> +                                   lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoCopyMem (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN UINT64                                DestAddress,
> +  IN UINT64                                SrcAddress,
> +  IN UINTN                                 Count
> +  )
> +{
> +  EFI_STATUS Status;
> +  BOOLEAN    Direction;
> +  UINTN      Stride;
> +  UINTN      Index;
> +  UINT64     Result;
> +
> +  if ((UINTN)Width > (UINTN)EfiPciWidthUint64) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (DestAddress == SrcAddress) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Stride = (UINTN)(1 << Width);
> +
> +  Direction = TRUE;
> +  if ((DestAddress > SrcAddress) &&
> +      (DestAddress < (SrcAddress + Count * Stride)))
> +  {
> +    Direction   = FALSE;
> +    SrcAddress  = SrcAddress  + (Count - 1) * Stride;
> +    DestAddress = DestAddress + (Count - 1) * Stride;
> +  }
> +
> +  for (Index = 0; Index < Count; Index++) {
> +
> +    Status = RootBridgeIoMemRead (This, Width, SrcAddress, 1, &Result);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    Status = RootBridgeIoMemWrite (This, Width, DestAddress, 1, &Result);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    if (Direction) {
> +      SrcAddress  += Stride;
> +      DestAddress += Stride;
> +    } else {
> +      SrcAddress  -= Stride;
> +      DestAddress -= Stride;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Allows read from PCI configuration space.
> +
> +  @param This     A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
> +  @param Width    Signifies the width of the memory operation.
> +  @param Address  The address within the PCI configuration space
> +                  for the PCI controller.
> +  @param Count    The number of PCI configuration operations
> +                  to perform.
> +  @param Buffer   The destination buffer to store the results.
> +
> +  @retval EFI_SUCCESS           The data was read from the PCI root bridge.
> +  @retval EFI_INVALID_PARAMETER Invalid parameters found.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPciRead (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN  UINT64                                Address,
> +  IN  UINTN                                 Count,
> +  OUT VOID                                  *Buffer
> +  )
> +{
> +  return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
> +}
> +
> +/**
> +  Allows write to PCI configuration space.
> +
> +  @param This     A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
> +  @param Width    Signifies the width of the memory operation.
> +  @param Address  The address within the PCI configuration space
> +                  for the PCI controller.
> +  @param Count    The number of PCI configuration operations
> +                  to perform.
> +  @param Buffer   The source buffer to get the results.
> +
> +  @retval EFI_SUCCESS            The data was written to the PCI root bridge.
> +  @retval EFI_INVALID_PARAMETER  Invalid parameters found.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoPciWrite (
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
> +  IN     UINT64                                Address,
> +  IN     UINTN                                 Count,
> +  IN OUT VOID                                  *Buffer
> +  )
> +{
> +  return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
> +}
> +
> +/**
> +  Provides the PCI controller-specific address needed to access
> +  system memory for DMA.
> +
> +  @param This           A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param Operation      Indicate if the bus master is going to read or write
> +                        to system memory.
> +  @param HostAddress    The system memory address to map on the PCI controller.
> +  @param NumberOfBytes  On input the number of bytes to map.
> +                        On output the number of bytes that were mapped.
> +  @param DeviceAddress  The resulting map address for the bus master PCI
> +                        controller to use to access the system memory's HostAddress.
> +  @param Mapping        The value to pass to Unmap() when the bus master DMA
> +                        operation is complete.
> +
> +  @retval EFI_SUCCESS            Success.
> +  @retval EFI_INVALID_PARAMETER  Invalid parameters found.
> +  @retval EFI_UNSUPPORTED        The HostAddress cannot be mapped as a common buffer.
> +  @retval EFI_DEVICE_ERROR       The System hardware could not map the requested address.
> +  @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to lack of resources.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoMap (
> +  IN      EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
> +  IN      EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
> +  IN      VOID                                      *HostAddress,
> +  IN  OUT UINTN                                     *NumberOfBytes,
> +  OUT     EFI_PHYSICAL_ADDRESS                      *DeviceAddress,
> +  OUT     VOID                                      **Mapping
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS PhysicalAddress;
> +
> +  if (HostAddress == NULL || NumberOfBytes == NULL ||
> +      DeviceAddress == NULL || Mapping == NULL)
> +  {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Initialize the return values to their defaults
> +  //
> +  *Mapping = NULL;
> +
> +  //
> +  // Make sure that Operation is valid
> +  //
> +  if ((UINT32)Operation >= EfiPciOperationMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
> +  //
> +  // The transfer is below 4GB, so the DeviceAddress is simply the HostAddress
> +  //
> +  *DeviceAddress = PhysicalAddress;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Completes the Map() operation and releases any corresponding resources.
> +
> +  The Unmap() function completes the Map() operation and releases any
> +  corresponding resources.
> +  If the operation was an EfiPciOperationBusMasterWrite or
> +  EfiPciOperationBusMasterWrite64, the data is committed to the target system
> +  memory.
> +  Any resources used for the mapping are freed.
> +
> +  @param[in] This      A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[in] Mapping   The mapping value returned from Map().
> +
> +  @retval EFI_SUCCESS            The range was unmapped.
> +  @retval EFI_INVALID_PARAMETER  Mapping is not a value that was returned by Map().
> +  @retval EFI_DEVICE_ERROR       The data was not committed to the target system memory.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoUnmap (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN VOID                            *Mapping
> +  )
> +{
> +  MAP_INFO *MapInfo;
> +
> +  //
> +  // See if the Map() operation associated with this Unmap() required a mapping buffer.
> +  // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS.
> +  //
> +  if (Mapping != NULL) {
> +    //
> +    // Get the MAP_INFO structure from Mapping
> +    //
> +    MapInfo = (MAP_INFO *)Mapping;
> +
> +    //
> +    // If this is a write operation from the Bus Master's point of view,
> +    // then copy the contents of the mapped buffer into the real buffer
> +    // so the processor can read the contents of the real buffer.
> +    //
> +    if (MapInfo->Operation == EfiPciOperationBusMasterWrite ||
> +        MapInfo->Operation == EfiPciOperationBusMasterWrite64)
> +    {
> +      CopyMem (
> +        (VOID *)(UINTN)MapInfo->HostAddress,
> +        (VOID *)(UINTN)MapInfo->MappedHostAddress,
> +        MapInfo->NumberOfBytes
> +        );
> +    }
> +
> +    //
> +    // Free the mapped buffer and the MAP_INFO structure.
> +    //
> +    gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages);
> +    gBS->FreePool (Mapping);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer
> +  or EfiPciOperationBusMasterCommonBuffer64 mapping.
> +
> +  @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param Type        This parameter is not used and must be ignored.
> +  @param MemoryType  The type of memory to allocate, EfiBootServicesData or
> +                     EfiRuntimeServicesData.
> +  @param Pages       The number of pages to allocate.
> +  @param HostAddress A pointer to store the base system memory address of the
> +                     allocated range.
> +  @param Attributes  The requested bit mask of attributes for the allocated
> +                     range. Only the attributes
> +                     EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
> +                     EFI_PCI_ATTRIBUTE_MEMORY_CACHED, and
> +                     EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this
> +                     function.
> +
> +  @retval EFI_SUCCESS            The requested memory pages were allocated.
> +  @retval EFI_INVALID_PARAMETER  MemoryType is invalid.
> +  @retval EFI_INVALID_PARAMETER  HostAddress is NULL.
> +  @retval EFI_UNSUPPORTED        Attributes is unsupported. The only legal
> +                                 attribute bits are MEMORY_WRITE_COMBINE,
> +                                 MEMORY_CACHED, and DUAL_ADDRESS_CYCLE.
> +  @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoAllocateBuffer (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN  EFI_ALLOCATE_TYPE               Type,
> +  IN  EFI_MEMORY_TYPE                 MemoryType,
> +  IN  UINTN                           Pages,
> +  OUT VOID                            **HostAddress,
> +  IN  UINT64                          Attributes
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EFI_PHYSICAL_ADDRESS PhysicalAddress;
> +
> +  //
> +  // Validate Attributes
> +  //
> +  if ((Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Check for invalid inputs
> +  //
> +  if (HostAddress == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
> +  //
> +  if (MemoryType != EfiBootServicesData &&
> +      MemoryType != EfiRuntimeServicesData)
> +  {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(0xFFFFFFFFFFFFFFFFULL);
> +
> +  Status = gBS->AllocatePages (
> +                  AllocateMaxAddress,
> +                  MemoryType,
> +                  Pages,
> +                  &PhysicalAddress
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  *HostAddress = (VOID *)(UINTN)PhysicalAddress;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Frees memory that was allocated with AllocateBuffer().
> +
> +  The FreeBuffer() function frees memory that was allocated with
> +  AllocateBuffer().
> +
> +  @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param Pages       The number of pages to free.
> +  @param HostAddress The base system memory address of the allocated range.
> +
> +  @retval EFI_SUCCESS            The requested memory pages were freed.
> +  @retval EFI_INVALID_PARAMETER  The memory range specified by HostAddress and
> +                                 Pages was not allocated with AllocateBuffer().
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoFreeBuffer (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN  UINTN                           Pages,
> +  OUT VOID                            *HostAddress
> +  )
> +{
> +  return gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Pages);
> +}
> +
> +/**
> +  Flushes all PCI posted write transactions from a PCI host bridge to system
> +  memory.
> +
> +  The Flush() function flushes any PCI posted write transactions from a PCI
> +  host bridge to system memory. Posted write transactions are generated by PCI
> +  bus masters when they perform write transactions to target addresses in
> +  system memory.
> +  This function does not flush posted write transactions from any PCI bridges.
> +  A PCI controller specific action must be taken to guarantee that the posted
> +  write transactions have been flushed from the PCI controller and from all the
> +  PCI bridges into the PCI host bridge. This is typically done with a PCI read
> +  transaction from the PCI controller prior to calling Flush().
> +
> +  @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +
> +  @retval EFI_SUCCESS        The PCI posted write transactions were flushed
> +                             from the PCI host bridge to system memory.
> +  @retval EFI_DEVICE_ERROR   The PCI posted write transactions were not flushed
> +                             from the PCI host bridge due to a hardware error.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoFlush (
> +  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
> +  )
> +{
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Gets the attributes that a PCI root bridge supports setting with
> +  SetAttributes(), and the attributes that a PCI root bridge is currently
> +  using.
> +
> +  The GetAttributes() function returns the mask of attributes that this PCI
> +  root bridge supports and the mask of attributes that the PCI root bridge is
> +  currently using.
> +
> +  @param This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param Supported   A pointer to the mask of attributes that this PCI root
> +                     bridge supports setting with SetAttributes().
> +  @param Attributes  A pointer to the mask of attributes that this PCI root
> +                     bridge is currently using.
> +
> +  @retval  EFI_SUCCESS           If Supports is not NULL, then the attributes
> +                                 that the PCI root bridge supports is returned
> +                                 in Supports. If Attributes is not NULL, then
> +                                 the attributes that the PCI root bridge is
> +                                 currently using is returned in Attributes.
> +  @retval  EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoGetAttributes (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  OUT UINT64                          *Supported,
> +  OUT UINT64                          *Attributes
> +  )
> +{
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
> +
> +  RootBridgeInstance = ROOT_BRIDGE_FROM_THIS (This);
> +
> +  if (Attributes == NULL && Supported == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Set the return value for Supported and Attributes
> +  //
> +  if (Supported != NULL) {
> +    *Supported  = RootBridgeInstance->RootBridge.Supports;
> +  }
> +
> +  if (Attributes != NULL) {
> +    *Attributes = RootBridgeInstance->RootBridge.Attributes;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Sets attributes for a resource range on a PCI root bridge.
> +
> +  The SetAttributes() function sets the attributes specified in Attributes for
> +  the PCI root bridge on the resource range specified by ResourceBase and
> +  ResourceLength. Since the granularity of setting these attributes may vary
> +  from resource type to resource type, and from platform to platform, the
> +  actual resource range and the one passed in by the caller may differ. As a
> +  result, this function may set the attributes specified by Attributes on a
> +  larger resource range than the caller requested. The actual range is returned
> +  in ResourceBase and ResourceLength. The caller is responsible for verifying
> +  that the actual range for which the attributes were set is acceptable.
> +
> +  @param This            A pointer to the
> +                         EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param Attributes      The mask of attributes to set. If the
> +                         attribute bit MEMORY_WRITE_COMBINE,
> +                         MEMORY_CACHED, or MEMORY_DISABLE is set,
> +                         then the resource range is specified by
> +                         ResourceBase and ResourceLength. If
> +                         MEMORY_WRITE_COMBINE, MEMORY_CACHED, and
> +                         MEMORY_DISABLE are not set, then
> +                         ResourceBase and ResourceLength are ignored,
> +                         and may be NULL.
> +  @param ResourceBase    A pointer to the base address of the
> +                         resource range to be modified by the
> +                         attributes specified by Attributes.
> +  @param ResourceLength  A pointer to the length of the resource
> +                                   range to be modified by the attributes
> +                                   specified by Attributes.
> +
> +  @retval  EFI_SUCCESS           The current configuration of this PCI root bridge
> +                                 was returned in Resources.
> +  @retval  EFI_UNSUPPORTED       The current configuration of this PCI root bridge
> +                                 could not be retrieved.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoSetAttributes (
> +  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  IN     UINT64                          Attributes,
> +  IN OUT UINT64                          *ResourceBase,
> +  IN OUT UINT64                          *ResourceLength
> +  )
> +{
> +  PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
> +
> +  RootBridgeInstance = ROOT_BRIDGE_FROM_THIS (This);
> +
> +  // Then check optional parameters if eligible
> +  if ((Attributes & (EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
> +                     EFI_PCI_ATTRIBUTE_MEMORY_CACHED |
> +                     EFI_PCI_ATTRIBUTE_MEMORY_DISABLE)) != 0)
> +  {
> +    if (ResourceBase == NULL || ResourceLength == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  if (Attributes != 0) {
> +    if ((Attributes & (~(RootBridgeInstance->RootBridge.Supports))) != 0) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // This is a generic driver for a PC-AT class system.  It does not have any
> +  // chipset specific knowlegde, so none of the attributes can be set or
> +  // cleared.  Any attempt to set attribute that are already set will succeed,
> +  // and any attempt to set an attribute that is not supported will fail.
> +  //
> +  if (Attributes & (~RootBridgeInstance->RootBridge.Attributes)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Retrieves the current resource settings of this PCI root bridge in the form
> +  of a set of ACPI resource descriptors.
> +
> +  There are only two resource descriptor types from the ACPI Specification that
> +  may be used to describe the current resources allocated to a PCI root bridge.
> +  These are the QWORD Address Space Descriptor, and the End Tag. The QWORD
> +  Address Space Descriptor can describe memory, I/O, and bus number ranges for
> +  dynamic or fixed resources. The configuration of a PCI root bridge is described
> +  with one or more QWORD Address Space Descriptors followed by an End Tag.
> +
> +  @param[in]   This        A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param[out]  Resources   A pointer to the resource descriptors that
> +                           describe the current configuration of this PCI root
> +                           bridge. The storage for the resource
> +                           descriptors is allocated by this function. The
> +                           caller must treat the return buffer as read-only
> +                           data, and the buffer must not be freed by the
> +                          caller.
> +
> +  @retval  EFI_SUCCESS     The current configuration of this PCI root bridge
> +                           was returned in Resources.
> +  @retval  EFI_UNSUPPORTED The current configuration of this PCI root bridge
> +                           could not be retrieved.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RootBridgeIoConfiguration (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
> +  OUT VOID                            **Resources
> +  )
> +{
> +  PCI_ROOT_BRIDGE_INSTANCE          *RootBridgeInstance;
> +  PCI_RES_NODE                      *ResAllocNode;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
> +  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
> +  UINTN                             Index;
> +
> +  RootBridgeInstance = ROOT_BRIDGE_FROM_THIS (This);
> +  ZeroMem (
> +    RootBridgeInstance->ConfigBuffer,
> +    TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
> +    );
> +
> +  Descriptor = RootBridgeInstance->ConfigBuffer;
> +  for (Index = TypeIo; Index < TypeMax; Index++) {
> +
> +    ResAllocNode = &RootBridgeInstance->ResAllocNode[Index];
> +
> +    if (ResAllocNode->Status != ResAllocated) {
> +      continue;
> +    }
> +
> +    switch (ResAllocNode->Type) {
> +
> +    case TypeBus:
> +      Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_BUS;
> +      break;
> +
> +    case TypeIo:
> +      Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_IO;
> +      Descriptor->AddrSpaceGranularity = 32;
> +      break;
> +
> +    case TypeMem32:
> +    case TypePMem32:
> +      Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      Descriptor->SpecificFlag         = (Index == TypeMem32) ? 0 :
> +                                         EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
> +      Descriptor->AddrSpaceGranularity = 32;
> +      break;
> +
> +    case TypeMem64:
> +    case TypePMem64:
> +      Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      Descriptor->SpecificFlag         = (Index == TypeMem64) ? 0 :
> +                                         EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
> +      Descriptor->AddrSpaceGranularity = 64;
> +      break;
> +
> +    default:
> +      continue;
> +    }
> +
> +    Descriptor->Desc          = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +    Descriptor->Len           = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
> +    Descriptor->AddrRangeMin  = ResAllocNode->Base;
> +    Descriptor->AddrRangeMax  = ResAllocNode->Base + ResAllocNode->Length - 1;
> +    Descriptor->AddrLen       = ResAllocNode->Length;
> +
> +    Descriptor++;
> +  }
> +
> +  //
> +  // Terminate the entries.
> +  //
> +  End = (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor;
> +  End->Desc     = ACPI_END_TAG_DESCRIPTOR;
> +  End->Checksum = 0x0;
> +
> +  *Resources = RootBridgeInstance->ConfigBuffer;
> +
> +  return EFI_SUCCESS;
> +}
> -- 
> 2.17.1
> 


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76237): https://edk2.groups.io/g/devel/message/76237
Mute This Topic: https://groups.io/mt/83097113/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