From: "Leif Lindholm" <leif@nuviainc.com>
To: Nhi Pham <nhi@os.amperecomputing.com>
Cc: devel@edk2.groups.io, Vu Nguyen <vunguyen@os.amperecomputing.com>,
Thang Nguyen <thang@os.amperecomputing.com>,
Chuong Tran <chuong@os.amperecomputing.com>,
Phong Vo <phong@os.amperecomputing.com>,
Michael D Kinney <michael.d.kinney@intel.com>,
Ard Biesheuvel <ardb+tianocore@kernel.org>,
Nate DeSimone <nathaniel.l.desimone@intel.com>
Subject: Re: [edk2-platforms][PATCH v2 16/32] AmpereAltraPkg: Add PciHostBridge driver
Date: Tue, 8 Jun 2021 23:26:46 +0100 [thread overview]
Message-ID: <20210608222646.ftgw5ch6jwpnkazl@leviathan> (raw)
In-Reply-To: <20210526100724.5359-18-nhi@os.amperecomputing.com>
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@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@os.amperecomputing.com>
> Cc: Chuong Tran <chuong@os.amperecomputing.com>
> Cc: Phong Vo <phong@os.amperecomputing.com>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
>
> Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
> ---
> Silicon/Ampere/AmpereAltraPkg/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
>
next prev parent reply other threads:[~2021-06-08 22:26 UTC|newest]
Thread overview: 87+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-05-26 10:06 [edk2-platforms][PATCH v2 00/32] Add new Ampere Mt. Jade platform Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 01/32] Ampere: Initial support for Ampere Altra processor and " Nhi Pham
2021-06-04 23:04 ` Leif Lindholm
2021-06-09 4:50 ` Nhi Pham
2021-06-09 12:40 ` Leif Lindholm
2021-06-15 16:46 ` Nhi Pham
2021-05-26 10:06 ` [PATCH 1/1] UsbCdcNetDxe: Remove reading connection status in SNP GetStatus Nhi Pham
2021-05-26 10:23 ` [edk2-devel] " Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 02/32] AmpereAltraPkg: Add MmCommunication modules Nhi Pham
2021-06-04 23:05 ` Leif Lindholm
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 03/32] AmperePlatformPkg: Implement FailSafe library Nhi Pham
2021-06-04 23:07 ` Leif Lindholm
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 04/32] AmperePlatformPkg: Add FailSafe and WDT support Nhi Pham
2021-06-04 23:12 ` Leif Lindholm
2021-06-15 16:47 ` Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 05/32] AmpereAltraPkg: Add DwI2cLib library Nhi Pham
2021-06-04 23:21 ` Leif Lindholm
2021-06-15 16:47 ` Nhi Pham
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 06/32] AmpereAltraPkg: Add DwGpioLib library Nhi Pham
2021-06-04 23:22 ` Leif Lindholm
2021-05-26 10:06 ` [edk2-platforms][PATCH v2 07/32] JadePkg: Implement RealTimeClockLib for PCF85063 Nhi Pham
2021-06-04 23:26 ` Leif Lindholm
2021-06-15 16:48 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 08/32] AmpereAltraPkg: Add BootProgress support Nhi Pham
2021-06-04 23:27 ` Leif Lindholm
2021-06-15 16:48 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 09/32] AmpereAltraPkg: Support non-volatile variables Nhi Pham
2021-06-04 23:36 ` Leif Lindholm
2021-06-15 16:48 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 10/32] AmpereSiliconPkg: Add PlatformManagerUiLib library instance Nhi Pham
2021-06-04 23:37 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 11/32] AmperePlatformPkg: Add AcpiPccLib to support ACPI PCCT Table Nhi Pham
2021-06-04 23:44 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 12/32] AmperePlatformPkg: Add AcpiHelperLib to update ACPI DSDT table Nhi Pham
2021-06-04 23:47 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 13/32] AmpereAltraPkg, JadePkg: Add ACPI support Nhi Pham
2021-06-04 23:50 ` Leif Lindholm
2021-06-15 16:49 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 14/32] AmpereAltraPkg: Add PcieCoreLib library instance Nhi Pham
2021-06-05 0:05 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 15/32] JadePkg: Add PcieBoardLib " Nhi Pham
2021-06-07 22:45 ` Leif Lindholm
2021-06-15 16:50 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 16/32] AmpereAltraPkg: Add PciHostBridge driver Nhi Pham
2021-06-08 22:26 ` Leif Lindholm [this message]
2021-06-09 5:29 ` Ard Biesheuvel
2021-06-15 15:54 ` Nhi Pham
2021-06-16 14:20 ` Ard Biesheuvel
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 17/32] JadePkg: Enable PCIe-related libraries and device drivers Nhi Pham
2021-06-07 22:51 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 18/32] JadePkg: Add ASpeed GOP driver Nhi Pham
2021-06-07 22:51 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 19/32] AmpereAltraPkg: Add Random Number Generator Support Nhi Pham
2021-06-08 11:13 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 20/32] JadePkg: Add SMBIOS tables support Nhi Pham
2021-06-07 23:00 ` Leif Lindholm
2021-06-15 16:51 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 21/32] AmpereAltraPkg: Add DebugInfoPei module Nhi Pham
2021-06-07 23:08 ` Leif Lindholm
2021-06-15 16:51 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 22/32] AmpereAltraPkg: Add platform info screen Nhi Pham
2021-06-07 23:10 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 23/32] AmpereAltraPkg: Add configuration screen for memory Nhi Pham
2021-06-07 23:14 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 24/32] AmpereAltraPkg: Add configuration screen for CPU Nhi Pham
2021-06-07 23:15 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 25/32] AmpereAltraPkg: Add configuration screen for ACPI Nhi Pham
2021-06-07 23:20 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 26/32] AmpereAltraPkg: Add configuration screen for RAS Nhi Pham
2021-06-07 23:22 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 27/32] AmpereAltraPkg: Add configuration screen for Watchdog timer Nhi Pham
2021-06-07 23:24 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 28/32] AmpereAltraPkg: Add configuration screen for Pcie Devices Nhi Pham
2021-06-07 23:34 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 29/32] JadePkg: Recover boot options when NVRAM cleared Nhi Pham
2021-06-07 23:46 ` Leif Lindholm
2021-06-15 16:52 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 30/32] AmpereSiliconPkg: Implement PlatformBootManagerLib for LinuxBoot Nhi Pham
2021-06-07 23:50 ` Leif Lindholm
2021-06-09 15:21 ` Nhi Pham
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 31/32] Platform/Ampere: Introduce the LinuxBootPkg Nhi Pham
2021-06-07 23:51 ` Leif Lindholm
2021-05-26 10:07 ` [edk2-platforms][PATCH v2 32/32] AmpereAltraPkg,JadePkg: Support LinuxBoot DSC/FDF build for Jade platform Nhi Pham
2021-06-07 23:58 ` Leif Lindholm
2021-06-09 15:20 ` Nhi Pham
2021-05-27 12:56 ` [edk2-platforms][PATCH v2 00/32] Add new Ampere Mt. " Leif Lindholm
2021-06-04 13:54 ` Leif Lindholm
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210608222646.ftgw5ch6jwpnkazl@leviathan \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox