From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) by mx.groups.io with SMTP id smtpd.web11.280.1623191211575469499 for ; Tue, 08 Jun 2021 15:26:52 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=vQoKvvty; spf=pass (domain: nuviainc.com, ip: 209.85.221.45, mailfrom: leif@nuviainc.com) Received: by mail-wr1-f45.google.com with SMTP id e11so13011283wrg.3 for ; Tue, 08 Jun 2021 15:26:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=FufS1rMj6Vreywqjn1g8qSgW3rz+pUWN8gGoYUfrk6A=; b=vQoKvvty230co1MeuIjoI7TwOZvuiBx0GA4DtrqbVL06YNHp9Qp+ycK/5D4+Y0m6gf HEtrkRzgbp5ksuIGusQ7J597HZ77ykGYQ/hHIDbjbzHJvS2wKvvye++lrqRqj7FXuNEp 76uc+NocYKvZUrkqqf+VSLb67AxJnA6y6Lvhs7zquKYoFgwA+onhpKeR0oUK39Cz4LR4 5gDVua8nR08Pynd3L3UYVoRitPvG5ccd+YGjhUi5Z3nEWyqmuWd6Zpe2IU+sX8R02V13 BmsW8ZgPJr7FFZHctgtAV1XyMLGJ7SmCWmrXVd6wE1ucAA4JuE1RrX8xEUiKdu3cKKSF o8Pw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=FufS1rMj6Vreywqjn1g8qSgW3rz+pUWN8gGoYUfrk6A=; b=OedoeBsAz7rc/KUcSN21MGPgkc42xIREmOcK5BE+aP4iyfE+KILDOnx4UMqV+cdbSa RqAaWzFAy1b4rb/q2OPd4xaM27vCib67smQeOKbQKfoiMZ/0DB/CtSivu6G0gU87GbR+ 2fCtObJlTudwMH0WM7tVm9c3Yj2Za1B+Jg1NJYNVa3aZVZweicRtJmqtZ64WhU0PMOpr bh+zaiqwGP7GeAuf0N0D+2JaX4EgQmzDYmMQrf4+R8Oi/0xXP/v6zKYlBV6OSyaBfyOf vHmgvxCnHVT7B48YURl0wxE38ICzapui5zvFkndDSCMjIGOfslNw+tHhqn4AmmOC4KSe JyGg== X-Gm-Message-State: AOAM533Pjb98x3S39AV7T+tYnxJUicPxMAqDCaE4l5e9pNL7/BFRkxfx 0//H0G+mzAbL9fFK7XmEpfRQEg== X-Google-Smtp-Source: ABdhPJzy/fjhveJrWPfbCci98Cu3FoE8hjkas3BZtlcTw2fbnpSqELje5N3E6K6MWoQBkwWilNn8lA== X-Received: by 2002:a5d:4401:: with SMTP id z1mr25184805wrq.149.1623191209725; Tue, 08 Jun 2021 15:26:49 -0700 (PDT) Return-Path: Received: from leviathan (cpc1-cmbg19-2-0-cust915.5-4.cable.virginm.net. [82.27.183.148]) by smtp.gmail.com with ESMTPSA id l3sm19269560wmh.2.2021.06.08.15.26.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Jun 2021 15:26:48 -0700 (PDT) Date: Tue, 8 Jun 2021 23:26:46 +0100 From: "Leif Lindholm" To: Nhi Pham Cc: devel@edk2.groups.io, Vu Nguyen , Thang Nguyen , Chuong Tran , Phong Vo , Michael D Kinney , Ard Biesheuvel , Nate DeSimone Subject: Re: [edk2-platforms][PATCH v2 16/32] AmpereAltraPkg: Add PciHostBridge driver Message-ID: <20210608222646.ftgw5ch6jwpnkazl@leviathan> References: <20210526100724.5359-1-nhi@os.amperecomputing.com> <20210526100724.5359-18-nhi@os.amperecomputing.com> MIME-Version: 1.0 In-Reply-To: <20210526100724.5359-18-nhi@os.amperecomputing.com> Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 > > 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 > Cc: Chuong Tran > Cc: Phong Vo > Cc: Leif Lindholm > Cc: Michael D Kinney > Cc: Ard Biesheuvel > Cc: Nate DeSimone > > Signed-off-by: Vu Nguyen > --- > 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.
> +# > +# 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef PCI_HOST_BRIDGE_H_ > +#define PCI_HOST_BRIDGE_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef PCI_ROOT_BRIDGE_IO_H_ > +#define PCI_ROOT_BRIDGE_IO_H_ > + > +#include > +#include > + > +/** > + 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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 >