summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Pci
diff options
context:
space:
mode:
authordavidhuang <davidhuang@6f19259b-4bc3-4df7-8a09-765794883524>2009-10-20 03:43:40 +0000
committerdavidhuang <davidhuang@6f19259b-4bc3-4df7-8a09-765794883524>2009-10-20 03:43:40 +0000
commit9060e3ec6dfd6048724832947933650cde873381 (patch)
tree0464c0e64c938ff9eb160928cc6ce3ba4ee8725a /MdeModulePkg/Bus/Pci
parentd47bdf84990a6727065ae9cb6b8f61991f609bc5 (diff)
downloadedk2-platforms-9060e3ec6dfd6048724832947933650cde873381.tar.xz
1. Impl PI 1.2 PCI part. Major changes include:
a. Update PciBusDxe module, and move it from IntelFrameworkModulePkg to MdeModulePkg b. Move IncompatiblePciDeviceSupportDxe module from IntelFrameworkModulePkg to MdeModulePkg c. Update the related consumes in inf/dsc/fdf git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9347 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Bus/Pci')
-rw-r--r--MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c387
-rw-r--r--MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf49
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c176
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h152
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c382
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h382
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf116
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c248
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h238
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c1185
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h289
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c143
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h86
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c2171
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h519
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c2494
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h463
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c394
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h189
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c1877
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h687
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c1359
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h144
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c735
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h143
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c68
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h34
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c2344
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h492
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c126
-rw-r--r--MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h55
31 files changed, 18127 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c b/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
new file mode 100644
index 0000000000..310817f777
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
@@ -0,0 +1,387 @@
+/** @file
+ This module is one template module for Incompatible PCI Device Support protocol.
+ It includes one incompatile pci devices list template.
+
+ Incompatible PCI Device Support protocol allows the PCI bus driver to support
+ resource allocation for some PCI devices that do not comply with the PCI Specification.
+
+Copyright (c) 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/IncompatiblePciDeviceSupport.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+
+typedef struct {
+ UINT64 VendorId;
+ UINT64 DeviceId;
+ UINT64 RevisionId;
+ UINT64 SubsystemVendorId;
+ UINT64 SubsystemDeviceId;
+} EFI_PCI_DEVICE_HEADER_INFO;
+
+typedef struct {
+ UINT64 ResType;
+ UINT64 GenFlag;
+ UINT64 SpecificFlag;
+ UINT64 AddrSpaceGranularity;
+ UINT64 AddrRangeMin;
+ UINT64 AddrRangeMax;
+ UINT64 AddrTranslationOffset;
+ UINT64 AddrLen;
+} EFI_PCI_RESOUCE_DESCRIPTOR;
+
+#define PCI_DEVICE_ID(VendorId, DeviceId, Revision, SubVendorId, SubDeviceId) \
+ VendorId, DeviceId, Revision, SubVendorId, SubDeviceId
+
+#define PCI_BAR_TYPE_IO ACPI_ADDRESS_SPACE_TYPE_IO
+#define PCI_BAR_TYPE_MEM ACPI_ADDRESS_SPACE_TYPE_MEM
+
+#define DEVICE_INF_TAG 0xFFF2
+#define DEVICE_RES_TAG 0xFFF1
+#define LIST_END_TAG 0x0000
+
+
+/**
+ Returns a list of ACPI resource descriptors that detail the special
+ resource configuration requirements for an incompatible PCI device.
+
+ @param This Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
+ @param VendorId A unique ID to identify the manufacturer of the PCI device.
+ @param DeviceId A unique ID to identify the particular PCI device.
+ @param RevisionId A PCI device-specific revision identifier.
+ @param SubsystemVendorId Specifies the subsystem vendor ID.
+ @param SubsystemDeviceId Specifies the subsystem device ID.
+ @param Configuration A list of ACPI resource descriptors returned that detail
+ the configuration requirement.
+
+ @retval EFI_SUCCESS Successfully got ACPI resource for specified PCI device.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_OUT_OF_RESOURCES No memory available.
+ @retval EFI_UNSUPPORTED The specified PCI device wasn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PCheckDevice (
+ IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *This,
+ IN UINTN VendorId,
+ IN UINTN DeviceId,
+ IN UINTN RevisionId,
+ IN UINTN SubsystemVendorId,
+ IN UINTN SubsystemDeviceId,
+ OUT VOID **Configuration
+ );
+
+//
+// Handle onto which the Incompatible PCI Device List is installed
+//
+EFI_HANDLE mIncompatiblePciDeviceSupportHandle = NULL;
+
+//
+// The Incompatible PCI Device Support Protocol instance produced by this driver
+//
+EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL mIncompatiblePciDeviceSupport = {
+ PCheckDevice
+};
+
+//
+// The incompatible PCI devices list template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mIncompatiblePciDeviceList[] = {
+ //
+ // DEVICE_INF_TAG,
+ // PCI_DEVICE_ID (VendorID, DeviceID, Revision, SubVendorId, SubDeviceId),
+ // DEVICE_RES_TAG,
+ // ResType, GFlag , SFlag, Granularity, RangeMin,
+ // RangeMax, Offset, AddrLen
+ //
+ //
+ // Device Adaptec 9004
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x9004, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
+ DEVICE_RES_TAG,
+ PCI_BAR_TYPE_IO,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_BAR_EVEN_ALIGN,
+ PCI_BAR_ALL,
+ PCI_BAR_NOCHANGE,
+ //
+ // Device Adaptec 9005
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x9005, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
+ DEVICE_RES_TAG,
+ PCI_BAR_TYPE_IO,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_BAR_EVEN_ALIGN,
+ PCI_BAR_ALL,
+ PCI_BAR_NOCHANGE,
+ //
+ // Device QLogic 1007
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x1077, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
+ DEVICE_RES_TAG,
+ PCI_BAR_TYPE_IO,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_BAR_EVEN_ALIGN,
+ PCI_BAR_ALL,
+ PCI_BAR_NOCHANGE,
+ //
+ // Device Agilent 103C
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x103C, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
+ DEVICE_RES_TAG,
+ PCI_BAR_TYPE_IO,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_BAR_EVEN_ALIGN,
+ PCI_BAR_ALL,
+ PCI_BAR_NOCHANGE,
+ //
+ // Device Agilent 15BC
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x15BC, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
+ DEVICE_RES_TAG,
+ PCI_BAR_TYPE_IO,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_ACPI_UNUSED,
+ PCI_BAR_EVEN_ALIGN,
+ PCI_BAR_ALL,
+ PCI_BAR_NOCHANGE,
+ //
+ // The end of the list
+ //
+ LIST_END_TAG
+};
+
+
+/**
+ Entry point of the incompatible pci device support code. Setup an incompatible device list template
+ and install EFI Incompatible PCI Device Support protocol.
+
+ @param ImageHandle A handle for the image that is initializing this driver.
+ @param SystemTable A pointer to the EFI system table.
+
+ @retval EFI_SUCCESS Installed EFI Incompatible PCI Device Support Protocol successfully.
+ @retval others Failed to install protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+IncompatiblePciDeviceSupportEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install EFI Incompatible PCI Device Support Protocol on a new handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mIncompatiblePciDeviceSupportHandle,
+ &gEfiIncompatiblePciDeviceSupportProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mIncompatiblePciDeviceSupport
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Returns a list of ACPI resource descriptors that detail the special
+ resource configuration requirements for an incompatible PCI device.
+
+ @param This Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
+ @param VendorId A unique ID to identify the manufacturer of the PCI device.
+ @param DeviceId A unique ID to identify the particular PCI device.
+ @param RevisionId A PCI device-specific revision identifier.
+ @param SubsystemVendorId Specifies the subsystem vendor ID.
+ @param SubsystemDeviceId Specifies the subsystem device ID.
+ @param Configuration A list of ACPI resource descriptors returned that detail
+ the configuration requirement.
+
+ @retval EFI_SUCCESS Successfully got ACPI resource for specified PCI device.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_OUT_OF_RESOURCES No memory available.
+ @retval EFI_UNSUPPORTED The specified PCI device wasn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PCheckDevice (
+ IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *This,
+ IN UINTN VendorId,
+ IN UINTN DeviceId,
+ IN UINTN RevisionId,
+ IN UINTN SubsystemVendorId,
+ IN UINTN SubsystemDeviceId,
+ OUT VOID **Configuration
+ )
+{
+ UINT64 Tag;
+ UINT64 *ListPtr;
+ UINT64 *TempListPtr;
+ EFI_PCI_DEVICE_HEADER_INFO *Header;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiPtr;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *OldAcpiPtr;
+ EFI_PCI_RESOUCE_DESCRIPTOR *Dsc;
+ EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;
+ UINTN Index;
+
+ //
+ // Validate the parameters
+ //
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the return value to NULL
+ //
+ * (VOID **) Configuration = NULL;
+
+ ListPtr = mIncompatiblePciDeviceList;
+ while (*ListPtr != LIST_END_TAG) {
+
+ Tag = *ListPtr;
+
+ switch (Tag) {
+ case DEVICE_INF_TAG:
+ Header = (EFI_PCI_DEVICE_HEADER_INFO *) (ListPtr + 1);
+ ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_HEADER_INFO) / sizeof (UINT64);
+ //
+ // See if the Header matches the parameters passed in
+ //
+ if (Header->VendorId != DEVICE_ID_NOCARE) {
+ if (Header->VendorId != VendorId) {
+ continue;
+ }
+ }
+
+ if (Header->DeviceId != DEVICE_ID_NOCARE) {
+ if (DeviceId != Header->DeviceId) {
+ continue;
+ }
+ }
+
+ if (Header->RevisionId != DEVICE_ID_NOCARE) {
+ if (RevisionId != Header->RevisionId) {
+ continue;
+ }
+ }
+
+ if (Header->SubsystemVendorId != DEVICE_ID_NOCARE) {
+ if (SubsystemVendorId != Header->SubsystemVendorId) {
+ continue;
+ }
+ }
+
+ if (Header->SubsystemDeviceId != DEVICE_ID_NOCARE) {
+ if (SubsystemDeviceId != Header->SubsystemDeviceId) {
+ continue;
+ }
+ }
+ //
+ // Matched an item, so construct the ACPI descriptor for the resource.
+ //
+ //
+ // Count the resource items so that to allocate space
+ //
+ for (Index = 0, TempListPtr = ListPtr; *TempListPtr == DEVICE_RES_TAG; Index++) {
+ TempListPtr = TempListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
+ }
+ //
+ // If there is at least one type of resource request,
+ // allocate an acpi resource node
+ //
+ if (Index == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ AcpiPtr = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Index + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (AcpiPtr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OldAcpiPtr = AcpiPtr;
+ //
+ // Fill the EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR structure
+ // according to the EFI_PCI_RESOUCE_DESCRIPTOR structure
+ //
+ for (; *ListPtr == DEVICE_RES_TAG;) {
+
+ Dsc = (EFI_PCI_RESOUCE_DESCRIPTOR *) (ListPtr + 1);
+
+ AcpiPtr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ AcpiPtr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ AcpiPtr->ResType = (UINT8) Dsc->ResType;
+ AcpiPtr->GenFlag = (UINT8) Dsc->GenFlag;
+ AcpiPtr->SpecificFlag = (UINT8) Dsc->SpecificFlag;
+ AcpiPtr->AddrSpaceGranularity = Dsc->AddrSpaceGranularity;;
+ AcpiPtr->AddrRangeMin = Dsc->AddrRangeMin;
+ AcpiPtr->AddrRangeMax = Dsc->AddrRangeMax;
+ AcpiPtr->AddrTranslationOffset = Dsc->AddrTranslationOffset;
+ AcpiPtr->AddrLen = Dsc->AddrLen;
+
+ ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
+ AcpiPtr++;
+ }
+ //
+ // Put the checksum
+ //
+ PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AcpiPtr);
+ PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
+ PtrEnd->Checksum = 0;
+
+ *(VOID **) Configuration = OldAcpiPtr;
+
+ return EFI_SUCCESS;
+
+ case DEVICE_RES_TAG:
+ //
+ // Adjust the pointer to the next PCI resource descriptor item
+ //
+ ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf b/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf
new file mode 100644
index 0000000000..29bf4dce2c
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf
@@ -0,0 +1,49 @@
+#/** @file
+# PCI Incompatible device support module template.
+#
+# Installs EFI PCI Incompatible Device Support protocol and includes one incompatile
+# pci devices list template.
+#
+# Copyright (c) 2009, Intel Corporation.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IncompatiblePciDeviceSupport
+ FILE_GUID = AD70855E-0CC5-4abf-8979-BE762A949EA3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = IncompatiblePciDeviceSupportEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ IncompatiblePciDeviceSupport.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ DebugLib
+
+[Protocols]
+ gEfiIncompatiblePciDeviceSupportProtocolGuid ## PRODUCEDS
+
+[Depex]
+ TRUE
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c
new file mode 100644
index 0000000000..47eba5fdbe
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c
@@ -0,0 +1,176 @@
+/** @file
+ EFI Component Name functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName = {
+ PciBusComponentNameGetDriverName,
+ PciBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PciBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PciBusComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPciBusDriverNameTable[] = {
+ { "eng;en", (CHAR16 *) L"PCI Bus Driver" },
+ { NULL , NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPciBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPciBusComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h b/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h
new file mode 100644
index 0000000000..ee30e86725
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h
@@ -0,0 +1,152 @@
+/** @file
+ EFI Component Name functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _EFI_PCI_BUS_COMPONENT_NAME_H_
+#define _EFI_PCI_BUS_COMPONENT_NAME_H_
+
+extern EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2;
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
new file mode 100644
index 0000000000..71bb5397bb
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
@@ -0,0 +1,382 @@
+/** @file
+ Driver Binding functions for PCI Bus module.
+
+ Single PCI bus driver instance will manager all PCI Root Bridges in one EFI based firmware,
+ since all PCI Root Bridges' resources need to be managed together.
+ Supported() function will try to get PCI Root Bridge IO Protocol.
+ Start() function will get PCI Host Bridge Resource Allocation Protocol to manage all
+ PCI Root Bridges. So it means platform needs install PCI Root Bridge IO protocol for each
+ PCI Root Bus and install PCI Host Bridge Resource Allocation Protocol.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+//
+// PCI Bus Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding = {
+ PciBusDriverBindingSupported,
+ PciBusDriverBindingStart,
+ PciBusDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_HANDLE gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM];
+EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *gEfiIncompatiblePciDeviceSupport = NULL;
+UINTN gPciHostBridgeNumber = 0;
+BOOLEAN gFullEnumeration = TRUE;
+UINT64 gAllOne = 0xFFFFFFFFFFFFFFFFULL;
+UINT64 gAllZero = 0;
+
+EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol;
+EFI_PCI_OVERRIDE_PROTOCOL *gPciOverrideProtocol;
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL mPciHotPlugRequest = {
+ PciHotPlugRequestNotify
+};
+
+/**
+ The Entry Point for PCI Bus module. The user code starts with this function.
+
+ Installs driver module protocols and. Creates virtual device handles for ConIn,
+ ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,
+ Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.
+ Installs Graphics Output protocol and/or UGA Draw protocol if needed.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Initializes PCI devices pool
+ //
+ InitializePciDevicePool ();
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPciBusDriverBinding,
+ ImageHandle,
+ &gPciBusComponentName,
+ &gPciBusComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is supported, install EFI PCI Hot Plug Request protocol.
+ //
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiPciHotPlugRequestProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPciHotPlugRequest
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a gEfiPciRootBridgeIoProtocolGuid protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Optional parameter use to pick a specific child.
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_DEV_PATH_PTR Node;
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ Node.DevPath = RemainingDevicePath;
+ if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
+ Node.DevPath->SubType != HW_PCI_DP ||
+ DevicePathNodeLength(Node.DevPath) != sizeof(PCI_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Check if Pci Root Bridge IO protocol is installed by platform
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on ControllerHandle and enumerate Pci bus and start
+ all device under PCI bus.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child.
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiIncompatiblePciDeviceSupportProtocolGuid,
+ NULL,
+ (VOID **) &gEfiIncompatiblePciDeviceSupport
+ );
+
+ //
+ // If PCI Platform protocol is available, get it now.
+ // If the platform implements this, it must be installed before BDS phase
+ //
+ gPciPlatformProtocol = NULL;
+ gBS->LocateProtocol (
+ &gEfiPciPlatformProtocolGuid,
+ NULL,
+ (VOID **) &gPciPlatformProtocol
+ );
+
+ //
+ // If PCI Platform protocol doesn't exist, try to Pci Override Protocol.
+ //
+ if (gPciPlatformProtocol == NULL) {
+ gPciOverrideProtocol = NULL;
+ gBS->LocateProtocol (
+ &gEfiPciOverrideProtocolGuid,
+ NULL,
+ (VOID **) &gPciOverrideProtocol
+ );
+ }
+
+ gFullEnumeration = (BOOLEAN) ((SearchHostBridgeHandle (Controller) ? FALSE : TRUE));
+
+ //
+ // Enumerate the entire host bridge
+ // After enumeration, a database that records all the device information will be created
+ //
+ //
+ Status = PciEnumerator (Controller);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Start all the devices under the entire host bridge.
+ //
+ StartPciDevices (Controller);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ DestroyRootBridgeByHandle (
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stop all the children
+ //
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ //
+ // De register all the pci device
+ //
+ Status = DeRegisterPciDevice (Controller, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
new file mode 100644
index 0000000000..722f31d03c
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
@@ -0,0 +1,382 @@
+/** @file
+ Header files and data structures needed by PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _EFI_PCI_BUS_H_
+#define _EFI_PCI_BUS_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/LoadFile2.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciHotPlugRequest.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciPlatform.h>
+#include <Protocol/PciHotPlugInit.h>
+#include <Protocol/Decompress.h>
+#include <Protocol/BusSpecificDriverOverride.h>
+#include <Protocol/IncompatiblePciDeviceSupport.h>
+#include <Protocol/PciOverride.h>
+#include <Protocol/PciEnumerationComplete.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffLib.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/Acpi.h>
+
+typedef struct _PCI_IO_DEVICE PCI_IO_DEVICE;
+typedef struct _PCI_BAR PCI_BAR;
+
+#define EFI_PCI_RID(Bus, Device, Function) (((UINT32)Bus << 8) + ((UINT32)Device << 3) + (UINT32)Function)
+#define EFI_PCI_BUS_OF_RID(RID) ((UINT32)RID >> 8)
+
+#define EFI_PCI_IOV_POLICY_ARI 0x0001
+#define EFI_PCI_IOV_POLICY_SRIOV 0x0002
+#define EFI_PCI_IOV_POLICY_MRIOV 0x0004
+
+typedef enum {
+ PciBarTypeUnknown = 0,
+ PciBarTypeIo16,
+ PciBarTypeIo32,
+ PciBarTypeMem32,
+ PciBarTypePMem32,
+ PciBarTypeMem64,
+ PciBarTypePMem64,
+ PciBarTypeIo,
+ PciBarTypeMem,
+ PciBarTypeMaxType
+} PCI_BAR_TYPE;
+
+#include "ComponentName.h"
+#include "PciIo.h"
+#include "PciCommand.h"
+#include "PciDeviceSupport.h"
+#include "PciEnumerator.h"
+#include "PciEnumeratorSupport.h"
+#include "PciDriverOverride.h"
+#include "PciRomTable.h"
+#include "PciOptionRomSupport.h"
+#include "PciPowerManagement.h"
+#include "PciHotPlugSupport.h"
+#include "PciLib.h"
+
+#define VGABASE1 0x3B0
+#define VGALIMIT1 0x3BB
+
+#define VGABASE2 0x3C0
+#define VGALIMIT2 0x3DF
+
+#define ISABASE 0x100
+#define ISALIMIT 0x3FF
+
+//
+// PCI BAR parameters
+//
+struct _PCI_BAR {
+ UINT64 BaseAddress;
+ UINT64 Length;
+ UINT64 Alignment;
+ PCI_BAR_TYPE BarType;
+ BOOLEAN Prefetchable;
+ UINT8 MemType;
+ UINT8 Offset;
+};
+
+//
+// defined in PCI Card Specification, 8.0
+//
+#define PCI_CARD_MEMORY_BASE_0 0x1C
+#define PCI_CARD_MEMORY_LIMIT_0 0x20
+#define PCI_CARD_MEMORY_BASE_1 0x24
+#define PCI_CARD_MEMORY_LIMIT_1 0x28
+#define PCI_CARD_IO_BASE_0_LOWER 0x2C
+#define PCI_CARD_IO_BASE_0_UPPER 0x2E
+#define PCI_CARD_IO_LIMIT_0_LOWER 0x30
+#define PCI_CARD_IO_LIMIT_0_UPPER 0x32
+#define PCI_CARD_IO_BASE_1_LOWER 0x34
+#define PCI_CARD_IO_BASE_1_UPPER 0x36
+#define PCI_CARD_IO_LIMIT_1_LOWER 0x38
+#define PCI_CARD_IO_LIMIT_1_UPPER 0x3A
+#define PCI_CARD_BRIDGE_CONTROL 0x3E
+
+#define PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE BIT8
+#define PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE BIT9
+
+#define PPB_BAR_0 0
+#define PPB_BAR_1 1
+#define PPB_IO_RANGE 2
+#define PPB_MEM32_RANGE 3
+#define PPB_PMEM32_RANGE 4
+#define PPB_PMEM64_RANGE 5
+#define PPB_MEM64_RANGE 0xFF
+
+#define P2C_BAR_0 0
+#define P2C_MEM_1 1
+#define P2C_MEM_2 2
+#define P2C_IO_1 3
+#define P2C_IO_2 4
+
+#define EFI_BRIDGE_IO32_DECODE_SUPPORTED 0x0001
+#define EFI_BRIDGE_PMEM32_DECODE_SUPPORTED 0x0002
+#define EFI_BRIDGE_PMEM64_DECODE_SUPPORTED 0x0004
+#define EFI_BRIDGE_IO16_DECODE_SUPPORTED 0x0008
+#define EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED 0x0010
+#define EFI_BRIDGE_MEM64_DECODE_SUPPORTED 0x0020
+#define EFI_BRIDGE_MEM32_DECODE_SUPPORTED 0x0040
+
+#define PCI_MAX_HOST_BRIDGE_NUM 0x0010
+
+//
+// Define option for attribute
+//
+#define EFI_SET_SUPPORTS 0
+#define EFI_SET_ATTRIBUTES 1
+
+#define PCI_IO_DEVICE_SIGNATURE SIGNATURE_32 ('p', 'c', 'i', 'o')
+
+struct _PCI_IO_DEVICE {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_PCI_IO_PROTOCOL PciIo;
+ LIST_ENTRY Link;
+
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL PciDriverOverride;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_LOAD_FILE2_PROTOCOL LoadFile2;
+
+ //
+ // PCI configuration space header type
+ //
+ PCI_TYPE00 Pci;
+
+ //
+ // Bus number, Device number, Function number
+ //
+ UINT8 BusNumber;
+ UINT8 DeviceNumber;
+ UINT8 FunctionNumber;
+
+ //
+ // BAR for this PCI Device
+ //
+ PCI_BAR PciBar[PCI_MAX_BAR];
+
+ //
+ // The bridge device this pci device is subject to
+ //
+ PCI_IO_DEVICE *Parent;
+
+ //
+ // A linked list for children Pci Device if it is bridge device
+ //
+ LIST_ENTRY ChildList;
+
+ //
+ // TURE if the PCI bus driver creates the handle for this PCI device
+ //
+ BOOLEAN Registered;
+
+ //
+ // TRUE if the PCI bus driver successfully allocates the resource required by
+ // this PCI device
+ //
+ BOOLEAN Allocated;
+
+ //
+ // The attribute this PCI device currently set
+ //
+ UINT64 Attributes;
+
+ //
+ // The attributes this PCI device actually supports
+ //
+ UINT64 Supports;
+
+ //
+ // The resource decode the bridge supports
+ //
+ UINT32 Decodes;
+
+ //
+ // The OptionRom Size
+ //
+ UINT64 RomSize;
+
+ //
+ // The OptionRom Size
+ //
+ UINT64 RomBase;
+
+ //
+ // TRUE if all OpROM (in device or in platform specific position) have been processed
+ //
+ BOOLEAN AllOpRomProcessed;
+
+ //
+ // TRUE if there is any EFI driver in the OptionRom
+ //
+ BOOLEAN BusOverride;
+
+ //
+ // A list tracking reserved resource on a bridge device
+ //
+ LIST_ENTRY ReservedResourceList;
+
+ //
+ // A list tracking image handle of platform specific overriding driver
+ //
+ LIST_ENTRY OptionRomDriverList;
+
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ResourcePaddingDescriptors;
+ EFI_HPC_PADDING_ATTRIBUTES PaddingAttributes;
+
+ BOOLEAN IsPciExp;
+ //
+ // For SR-IOV
+ //
+ UINT8 PciExpressCapabilityOffset;
+ UINT32 AriCapabilityOffset;
+ UINT32 SrIovCapabilityOffset;
+ UINT32 MrIovCapabilityOffset;
+ PCI_BAR VfPciBar[PCI_MAX_BAR];
+ UINT32 SystemPageSize;
+ UINT16 InitialVFs;
+ UINT16 ReservedBusNum;
+};
+
+#define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \
+ CR (a, PCI_IO_DEVICE, PciIo, PCI_IO_DEVICE_SIGNATURE)
+
+#define PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS(a) \
+ CR (a, PCI_IO_DEVICE, PciDriverOverride, PCI_IO_DEVICE_SIGNATURE)
+
+#define PCI_IO_DEVICE_FROM_LINK(a) \
+ CR (a, PCI_IO_DEVICE, Link, PCI_IO_DEVICE_SIGNATURE)
+
+#define PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS(a) \
+ CR (a, PCI_IO_DEVICE, LoadFile2, PCI_IO_DEVICE_SIGNATURE)
+
+
+
+//
+// Global Variables
+//
+extern EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *gEfiIncompatiblePciDeviceSupport;
+extern EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2;
+extern BOOLEAN gFullEnumeration;
+extern UINTN gPciHostBridgeNumber;
+extern EFI_HANDLE gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM];
+extern UINT64 gAllOne;
+extern UINT64 gAllZero;
+extern EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol;
+extern EFI_PCI_OVERRIDE_PROTOCOL *gPciOverrideProtocol;
+
+
+
+/**
+ Macro that checks whether device is a GFX device.
+
+ @param _p Specified device.
+
+ @retval TRUE Device is a a GFX device.
+ @retval FALSE Device is not a a GFX device.
+
+**/
+#define IS_PCI_GFX(_p) IS_CLASS2 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_OTHER)
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a gEfiPciRootBridgeIoProtocolGuid protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Optional parameter use to pick a specific child.
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle and enumerate Pci bus and start
+ all device under PCI bus.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child.
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
new file mode 100644
index 0000000000..cd7865c0b0
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
@@ -0,0 +1,116 @@
+#/** @file
+# Component description file for PciBus module.
+#
+# PCI bus driver. This module will probe all PCI devices and allocate MMIO and IO
+# space for these devices. Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable
+# hot plug supporting.
+#
+# Copyright (c) 2006 - 2009, Intel Corporation
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciBusDxe
+ FILE_GUID = 93B80004-9FB3-11d4-9A3A-0090273FC14D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EFI_SPECIFICATION_VERSION = 0x00020000
+ ENTRY_POINT = PciBusEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gPciBusDriverBinding
+# COMPONENT_NAME = gPciBusComponentName
+# COMPONENT_NAME2 = gPciBusComponentName2
+#
+
+[Sources.common]
+ PciLib.c
+ PciIo.c
+ PciBus.c
+ PciDeviceSupport.c
+ ComponentName.c
+ ComponentName.h
+ PciCommand.c
+ PciResourceSupport.c
+ PciEnumeratorSupport.c
+ PciEnumerator.c
+ PciOptionRomSupport.c
+ PciDriverOverride.c
+ PciPowerManagement.c
+ PciPowerManagement.h
+ PciDriverOverride.h
+ PciRomTable.c
+ PciHotPlugSupport.c
+ PciLib.h
+ PciHotPlugSupport.h
+ PciRomTable.h
+ PciOptionRomSupport.h
+ PciEnumeratorSupport.h
+ PciEnumerator.h
+ PciResourceSupport.h
+ PciDeviceSupport.h
+ PciCommand.h
+ PciIo.h
+ PciBus.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+ PeCoffLib
+
+[Protocols]
+ gEfiPciHotPlugRequestProtocolGuid ## BY_START
+ gEfiPciIoProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiBusSpecificDriverOverrideProtocolGuid ## BY_START
+ gEfiLoadedImageProtocolGuid ## CONSUMED
+ gEfiDecompressProtocolGuid ## CONSUMED
+ gEfiPciHotPlugInitProtocolGuid ## CONSUMED
+ gEfiPciHostBridgeResourceAllocationProtocolGuid ## CONSUMED
+ gEfiPciPlatformProtocolGuid ## CONSUMED
+ gEfiPciOverrideProtocolGuid ## CONSUMED
+ gEfiPciEnumerationCompleteProtocolGuid ## CONSUMED
+ gEfiPciRootBridgeIoProtocolGuid ## CONSUMED
+ gEfiIncompatiblePciDeviceSupportProtocolGuid ## CONSUMED
+ gEfiLoadFile2ProtocolGuid ## CONSUMED
+
+[FeaturePcd.common]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSupport
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAriSupport
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMrIovSupport
+
+[FixedPcd.common]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize
+# [Event]
+# ##
+# # Notify event set by CreateEventForHpc () for PCI Hot Plug controller.
+# #
+# EVT_NOTIFY_SIGNAL ## PRODUCES
+#
+#
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c
new file mode 100644
index 0000000000..601af309b7
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c
@@ -0,0 +1,248 @@
+/** @file
+ PCI command register operations supporting functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+/**
+ Operate the PCI register via PciIo function interface.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+ @param Command Operator command.
+ @param Offset The address within the PCI configuration space for the PCI controller.
+ @param Operation Type of Operation.
+ @param PtrCommand Return buffer holding old PCI command, if operation is not EFI_SET_REGISTER.
+
+ @return Status of PciIo operation.
+
+**/
+EFI_STATUS
+PciOperateRegister (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT8 Offset,
+ IN UINT8 Operation,
+ OUT UINT16 *PtrCommand
+ )
+{
+ UINT16 OldCommand;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ OldCommand = 0;
+ PciIo = &PciIoDevice->PciIo;
+
+ if (Operation != EFI_SET_REGISTER) {
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ Offset,
+ 1,
+ &OldCommand
+ );
+
+ if (Operation == EFI_GET_REGISTER) {
+ *PtrCommand = OldCommand;
+ return Status;
+ }
+ }
+
+ if (Operation == EFI_ENABLE_REGISTER) {
+ OldCommand = (UINT16) (OldCommand | Command);
+ } else if (Operation == EFI_DISABLE_REGISTER) {
+ OldCommand = (UINT16) (OldCommand & ~(Command));
+ } else {
+ OldCommand = Command;
+ }
+
+ return PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ Offset,
+ 1,
+ &OldCommand
+ );
+}
+
+/**
+ Check the cpability supporting by given device.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+
+ @retval TRUE Cpability supportted.
+ @retval FALSE Cpability not supportted.
+
+**/
+BOOLEAN
+PciCapabilitySupport (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ if ((PciIoDevice->Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Locate capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfuly located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocateCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 CapId,
+ IN OUT UINT8 *Offset,
+ OUT UINT8 *NextRegBlock OPTIONAL
+ )
+{
+ UINT8 CapabilityPtr;
+ UINT16 CapabilityEntry;
+ UINT8 CapabilityID;
+
+ //
+ // To check the cpability of this device supports
+ //
+ if (!PciCapabilitySupport (PciIoDevice)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (*Offset != 0) {
+ CapabilityPtr = *Offset;
+ } else {
+
+ CapabilityPtr = 0;
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+
+ PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR,
+ 1,
+ &CapabilityPtr
+ );
+ } else {
+
+ PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CAPBILITY_POINTER_OFFSET,
+ 1,
+ &CapabilityPtr
+ );
+ }
+ }
+
+ while ((CapabilityPtr >= 0x40) && ((CapabilityPtr & 0x03) == 0x00)) {
+ PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint16,
+ CapabilityPtr,
+ 1,
+ &CapabilityEntry
+ );
+
+ CapabilityID = (UINT8) CapabilityEntry;
+
+ if (CapabilityID == CapId) {
+ *Offset = CapabilityPtr;
+ if (NextRegBlock != NULL) {
+ *NextRegBlock = (UINT8) (CapabilityEntry >> 8);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ CapabilityPtr = (UINT8) (CapabilityEntry >> 8);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locate PciExpress capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfuly located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocatePciExpressCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 CapId,
+ IN OUT UINT32 *Offset,
+ OUT UINT32 *NextRegBlock OPTIONAL
+ )
+{
+ UINT32 CapabilityPtr;
+ UINT32 CapabilityEntry;
+ UINT16 CapabilityID;
+
+ //
+ // To check the capability of this device supports
+ //
+ if (!PciIoDevice->IsPciExp) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (*Offset != 0) {
+ CapabilityPtr = *Offset;
+ } else {
+ CapabilityPtr = EFI_PCIE_CAPABILITY_BASE_OFFSET;
+ }
+
+ while (CapabilityPtr != 0) {
+ //
+ // Mask it to DWORD alignment per PCI spec
+ //
+ CapabilityPtr &= 0xFFC;
+ PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint32,
+ CapabilityPtr,
+ 1,
+ &CapabilityEntry
+ );
+
+ CapabilityID = (UINT16) CapabilityEntry;
+
+ if (CapabilityID == CapId) {
+ *Offset = CapabilityPtr;
+ if (NextRegBlock != NULL) {
+ *NextRegBlock = (CapabilityEntry >> 20) & 0xFFF;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ CapabilityPtr = (CapabilityEntry >> 20) & 0xFFF;
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h
new file mode 100644
index 0000000000..942bea941e
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h
@@ -0,0 +1,238 @@
+/** @file
+ PCI command register operations supporting functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _EFI_PCI_COMMAND_H_
+#define _EFI_PCI_COMMAND_H_
+
+//
+// The PCI Command register bits owned by PCI Bus driver.
+//
+// They should be cleared at the beginning. The other registers
+// are owned by chipset, we should not touch them.
+//
+#define EFI_PCI_COMMAND_BITS_OWNED ( \
+ EFI_PCI_COMMAND_IO_SPACE | \
+ EFI_PCI_COMMAND_MEMORY_SPACE | \
+ EFI_PCI_COMMAND_BUS_MASTER | \
+ EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE | \
+ EFI_PCI_COMMAND_VGA_PALETTE_SNOOP | \
+ EFI_PCI_COMMAND_FAST_BACK_TO_BACK \
+ )
+
+//
+// The PCI Bridge Control register bits owned by PCI Bus driver.
+//
+// They should be cleared at the beginning. The other registers
+// are owned by chipset, we should not touch them.
+//
+#define EFI_PCI_BRIDGE_CONTROL_BITS_OWNED ( \
+ EFI_PCI_BRIDGE_CONTROL_ISA | \
+ EFI_PCI_BRIDGE_CONTROL_VGA | \
+ EFI_PCI_BRIDGE_CONTROL_VGA_16 | \
+ EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK \
+ )
+
+//
+// The PCCard Bridge Control register bits owned by PCI Bus driver.
+//
+// They should be cleared at the beginning. The other registers
+// are owned by chipset, we should not touch them.
+//
+#define EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED ( \
+ EFI_PCI_BRIDGE_CONTROL_ISA | \
+ EFI_PCI_BRIDGE_CONTROL_VGA | \
+ EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK \
+ )
+
+
+#define EFI_GET_REGISTER 1
+#define EFI_SET_REGISTER 2
+#define EFI_ENABLE_REGISTER 3
+#define EFI_DISABLE_REGISTER 4
+
+/**
+ Operate the PCI register via PciIo function interface.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+ @param Command Operator command.
+ @param Offset The address within the PCI configuration space for the PCI controller.
+ @param Operation Type of Operation.
+ @param PtrCommand Return buffer holding old PCI command, if operation is not EFI_SET_REGISTER.
+
+ @return Status of PciIo operation.
+
+**/
+EFI_STATUS
+PciOperateRegister (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT8 Offset,
+ IN UINT8 Operation,
+ OUT UINT16 *PtrCommand
+ );
+
+/**
+ Check the cpability supporting by given device.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+
+ @retval TRUE Cpability supportted.
+ @retval FALSE Cpability not supportted.
+
+**/
+BOOLEAN
+PciCapabilitySupport (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Locate capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfuly located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocateCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 CapId,
+ IN OUT UINT8 *Offset,
+ OUT UINT8 *NextRegBlock OPTIONAL
+ );
+
+/**
+ Locate PciExpress capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfuly located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocatePciExpressCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 CapId,
+ IN OUT UINT32 *Offset,
+ OUT UINT32 *NextRegBlock OPTIONAL
+ );
+
+/**
+ Macro that reads command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[out] Pointer to the 16-bit value read from command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_READ_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, 0, PCI_COMMAND_OFFSET, EFI_GET_REGISTER, b)
+
+/**
+ Macro that writes command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The 16-bit value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_SET_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_COMMAND_OFFSET, EFI_SET_REGISTER, NULL)
+
+/**
+ Macro that enables command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The enabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_ENABLE_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_COMMAND_OFFSET, EFI_ENABLE_REGISTER, NULL)
+
+/**
+ Macro that disalbes command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The disabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_DISABLE_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_COMMAND_OFFSET, EFI_DISABLE_REGISTER, NULL)
+
+/**
+ Macro that reads PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[out] The 16-bit value read from control register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_READ_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, 0, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_GET_REGISTER, b)
+
+/**
+ Macro that writes PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The 16-bit value written into control register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_SET_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_SET_REGISTER, NULL)
+
+/**
+ Macro that enables PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The enabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_ENABLE_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_ENABLE_REGISTER, NULL)
+
+/**
+ Macro that disalbes PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The disabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_DISABLE_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_DISABLE_REGISTER, NULL)
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
new file mode 100644
index 0000000000..25387bd257
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
@@ -0,0 +1,1185 @@
+/** @file
+ Supporting functions implementaion for PCI devices management.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+//
+// This device structure is serviced as a header.
+// Its next field points to the first root bridge device node.
+//
+LIST_ENTRY mPciDevicePool;
+
+/**
+ Initialize the PCI devices pool.
+
+**/
+VOID
+InitializePciDevicePool (
+ VOID
+ )
+{
+ InitializeListHead (&mPciDevicePool);
+}
+
+/**
+ Insert a root bridge into PCI device pool.
+
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+InsertRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ )
+{
+ InsertTailList (&mPciDevicePool, &(RootBridge->Link));
+}
+
+/**
+ This function is used to insert a PCI device node under
+ a bridge.
+
+ @param Bridge The PCI bridge.
+ @param PciDeviceNode The PCI device needs inserting.
+
+**/
+VOID
+InsertPciDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciDeviceNode
+ )
+{
+ InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
+ PciDeviceNode->Parent = Bridge;
+}
+
+/**
+ Destroy root bridge and remove it from deivce tree.
+
+ @param RootBridge The bridge want to be removed.
+
+**/
+VOID
+DestroyRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ )
+{
+ DestroyPciDeviceTree (RootBridge);
+
+ FreePciDevice (RootBridge);
+}
+
+/**
+ Destroy a pci device node.
+
+ All direct or indirect allocated resource for this node will be freed.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried.
+
+**/
+VOID
+FreePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ ASSERT (PciIoDevice != NULL);
+ //
+ // Assume all children have been removed underneath this device
+ //
+ if (PciIoDevice->ResourcePaddingDescriptors != NULL) {
+ FreePool (PciIoDevice->ResourcePaddingDescriptors);
+ }
+
+ if (PciIoDevice->DevicePath != NULL) {
+ FreePool (PciIoDevice->DevicePath);
+ }
+
+ FreePool (PciIoDevice);
+}
+
+/**
+ Destroy all the pci device node under the bridge.
+ Bridge itself is not included.
+
+ @param Bridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+DestroyPciDeviceTree (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ while (!IsListEmpty (&Bridge->ChildList)) {
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ //
+ // Remove this node from the linked list
+ //
+ RemoveEntryList (CurrentLink);
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ DestroyPciDeviceTree (Temp);
+ }
+
+ FreePciDevice (Temp);
+ }
+}
+
+/**
+ Destroy all device nodes under the root bridge
+ specified by Controller.
+
+ The root bridge itself is also included.
+
+ @param Controller Root bridge handle.
+
+ @retval EFI_SUCCESS Destory all devcie nodes successfully.
+ @retval EFI_NOT_FOUND Cannot find any PCI device under specified
+ root bridge.
+
+**/
+EFI_STATUS
+DestroyRootBridgeByHandle (
+ IN EFI_HANDLE Controller
+ )
+{
+
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (Temp->Handle == Controller) {
+
+ RemoveEntryList (CurrentLink);
+
+ DestroyPciDeviceTree (Temp);
+
+ FreePciDevice (Temp);
+
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function registers the PCI IO device.
+
+ It creates a handle for this PCI IO device (if the handle does not exist), attaches
+ appropriate protocols onto the handle, does necessary initialization, and sets up
+ parent/child relationship with its bus controller.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
+ @param Handle A pointer to hold the returned EFI handle for the PCI IO device.
+
+ @retval EFI_SUCCESS The PCI device is successfully registered.
+ @retval other An error occurred when registering the PCI device.
+
+**/
+EFI_STATUS
+RegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *PciIoDevice,
+ OUT EFI_HANDLE *Handle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ VOID *PlatformOpRomBuffer;
+ UINTN PlatformOpRomSize;
+ UINT8 PciExpressCapRegOffset;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Data8;
+ BOOLEAN HasEfiImage;
+ PCI_IO_DEVICE *ParrentPciIoDevice;
+ EFI_PCI_IO_PROTOCOL *ParrentPciIo;
+ UINT16 Data16;
+ UINT32 Data32;
+
+ //
+ // Install the pciio protocol, device path protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Detect if PCI Express Device
+ //
+ PciExpressCapRegOffset = 0;
+ Status = LocateCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCI_CAPABILITY_ID_PCIEXP,
+ &PciExpressCapRegOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->IsPciExp = TRUE;
+ }
+
+ //
+ // Force Interrupt line to "Unknown" or "No Connection"
+ //
+ PciIo = &(PciIoDevice->PciIo);
+ Data8 = PCI_INT_LINE_UNKNOWN;
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
+
+ //
+ // PCI-IOV programming
+ //
+ if (((FeaturePcdGet(PcdAriSupport) & EFI_PCI_IOV_POLICY_ARI) != 0) && (PciIoDevice->AriCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport) & EFI_PCI_IOV_POLICY_SRIOV) != 0) &&
+ (PciIoDevice->SrIovCapabilityOffset != 0)) {
+ //
+ // Check its parrent ARI forwarding capability
+ //
+ ParrentPciIoDevice = PciIoDevice->Parent;
+ ParrentPciIo = &(ParrentPciIoDevice->PciIo);
+ ParrentPciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET, 1, &Data32);
+ if (Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) {
+ //
+ // ARI forward support in bridge, so enable it.
+ //
+ ParrentPciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 1, &Data32);
+ Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
+ ParrentPciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 1, &Data32);
+
+ //
+ // Set ARI Capable Hierarchy for device
+ //
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 1, &Data16);
+ Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 1, &Data16);
+ }
+ }
+
+ //
+ // Process OpRom
+ //
+ if (!PciIoDevice->AllOpRomProcessed) {
+
+ //
+ // Get the OpRom provided by platform
+ //
+ if (gPciPlatformProtocol != NULL) {
+ Status = gPciPlatformProtocol->GetPciRom (
+ gPciPlatformProtocol,
+ PciIoDevice->Handle,
+ &PlatformOpRomBuffer,
+ &PlatformOpRomSize
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->RomSize = PlatformOpRomSize;
+ PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
+ PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
+ //
+ // For OpROM read from gPciPlatformProtocol:
+ // Add the Rom Image to internal database for later PCI light enumeration
+ //
+ PciRomAddImageMapping (
+ NULL,
+ PciIoDevice->PciRootBridgeIo->SegmentNumber,
+ PciIoDevice->BusNumber,
+ PciIoDevice->DeviceNumber,
+ PciIoDevice->FunctionNumber,
+ (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,
+ PciIoDevice->PciIo.RomSize
+ );
+ }
+ } else if (gPciOverrideProtocol != NULL) {
+ Status = gPciOverrideProtocol->GetPciRom (
+ gPciOverrideProtocol,
+ PciIoDevice->Handle,
+ &PlatformOpRomBuffer,
+ &PlatformOpRomSize
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->RomSize = PlatformOpRomSize;
+ PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
+ PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
+ //
+ // For OpROM read from gPciOverrideProtocol:
+ // Add the Rom Image to internal database for later PCI light enumeration
+ //
+ PciRomAddImageMapping (
+ NULL,
+ PciIoDevice->PciRootBridgeIo->SegmentNumber,
+ PciIoDevice->BusNumber,
+ PciIoDevice->DeviceNumber,
+ PciIoDevice->FunctionNumber,
+ (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,
+ PciIoDevice->PciIo.RomSize
+ );
+ }
+ }
+ }
+
+ //
+ // Determine if there are EFI images in the option rom
+ //
+ HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);
+
+ if (HasEfiImage) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ &PciIoDevice->LoadFile2,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ return Status;
+ }
+ }
+
+
+ if (!PciIoDevice->AllOpRomProcessed) {
+
+ PciIoDevice->AllOpRomProcessed = TRUE;
+
+ //
+ // Dispatch the EFI OpRom for the PCI device.
+ // The OpRom is got from platform in the above code
+ // or loaded from device in the previous round of bus enumeration
+ //
+ if (HasEfiImage) {
+ ProcessOpRomImage (PciIoDevice);
+ }
+ }
+
+ if (PciIoDevice->BusOverride) {
+ //
+ // Install Bus Specific Driver Override Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ &PciIoDevice->PciDriverOverride,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ if (HasEfiImage) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ &PciIoDevice->LoadFile2,
+ NULL
+ );
+ }
+
+ return Status;
+ }
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &(PciIoDevice->PciRootBridgeIo),
+ gPciBusDriverBinding.DriverBindingHandle,
+ PciIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Handle != NULL) {
+ *Handle = PciIoDevice->Handle;
+ }
+
+ //
+ // Indicate the pci device is registered
+ //
+ PciIoDevice->Registered = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to remove the whole PCI devices on the specified bridge from
+ the root bridge.
+
+ @param RootBridgeHandle The root bridge device handle.
+ @param Bridge The bridge device to be removed.
+
+**/
+VOID
+RemoveAllPciDeviceOnBridge (
+ EFI_HANDLE RootBridgeHandle,
+ PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ while (!IsListEmpty (&Bridge->ChildList)) {
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ //
+ // Check if the current node has been deregistered before
+ // If it is not, then deregister it
+ //
+ if (Temp->Registered) {
+ DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
+ }
+
+ //
+ // Remove this node from the linked list
+ //
+ RemoveEntryList (CurrentLink);
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
+ }
+
+ FreePciDevice (Temp);
+ }
+}
+
+/**
+ This function is used to de-register the PCI IO device.
+
+ That includes un-installing PciIo protocol from the specified PCI
+ device handle.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param Handle PCI device handle.
+
+ @retval EFI_SUCCESS The PCI device is successfully de-registered.
+ @retval other An error occurred when de-registering the PCI device.
+
+**/
+EFI_STATUS
+DeRegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ PCI_IO_DEVICE *Node;
+ LIST_ENTRY *CurrentLink;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
+
+ //
+ // If it is already de-registered
+ //
+ if (!PciIoDevice->Registered) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If it is PPB, first de-register its children
+ //
+
+ if (!IsListEmpty (&PciIoDevice->ChildList)) {
+
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+ Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ Status = DeRegisterPciDevice (Controller, Node->Handle);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ }
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Handle
+ );
+
+ //
+ // Un-install the Device Path protocol and PCI I/O protocol
+ // and Bus Specific Driver Override protocol if needed.
+ //
+ if (PciIoDevice->BusOverride) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ &PciIoDevice->PciDriverOverride,
+ NULL
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try to uninstall LoadFile2 protocol if exists
+ //
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ NULL,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ &PciIoDevice->LoadFile2,
+ NULL
+ );
+ }
+ //
+ // Restore Status
+ //
+ Status = EFI_SUCCESS;
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ //
+ // The Device Driver should disable this device after disconnect
+ // so the Pci Bus driver will not touch this device any more.
+ // Restore the register field to the original value
+ //
+ PciIoDevice->Registered = FALSE;
+ PciIoDevice->Handle = NULL;
+ } else {
+
+ //
+ // Handle may be closed before
+ //
+ return EFI_SUCCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.
+
+ @param Controller The root bridge handle.
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+ @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
+ @param NumberOfChildren Children number.
+ @param ChildHandleBuffer A pointer to the child handle buffer.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
+ @retval EFI_NOT_FOUND Can not find the specific device.
+ @retval EFI_SUCCESS Success to start Pci devices on bridge.
+
+**/
+EFI_STATUS
+StartPciDevicesOnBridge (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *RootBridge,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE *ChildHandleBuffer
+ )
+
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_DEV_PATH_PTR Node;
+ EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
+ EFI_STATUS Status;
+ LIST_ENTRY *CurrentLink;
+ UINT64 Supports;
+
+ PciIoDevice = NULL;
+ CurrentLink = RootBridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (RemainingDevicePath != NULL) {
+
+ Node.DevPath = RemainingDevicePath;
+
+ if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
+ Node.Pci->Function != PciIoDevice->FunctionNumber) {
+ CurrentLink = CurrentLink->ForwardLink;
+ continue;
+ }
+
+ //
+ // Check if the device has been assigned with required resource
+ //
+ if (!PciIoDevice->Allocated) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Check if the current node has been registered before
+ // If it is not, register it
+ //
+ if (!PciIoDevice->Registered) {
+ Status = RegisterPciDevice (
+ Controller,
+ PciIoDevice,
+ NULL
+ );
+
+ }
+
+ if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
+ ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
+ (*NumberOfChildren)++;
+ }
+
+ //
+ // Get the next device path
+ //
+ CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
+ if (IsDevicePathEnd (CurrentDevicePath)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If it is a PPB
+ //
+ if (!IsListEmpty (&PciIoDevice->ChildList)) {
+ Status = StartPciDevicesOnBridge (
+ Controller,
+ PciIoDevice,
+ CurrentDevicePath,
+ NumberOfChildren,
+ ChildHandleBuffer
+ );
+
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+
+ return Status;
+ } else {
+
+ //
+ // Currently, the PCI bus driver only support PCI-PCI bridge
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ } else {
+
+ //
+ // If remaining device path is NULL,
+ // try to enable all the pci devices under this bridge
+ //
+ if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
+ Status = RegisterPciDevice (
+ Controller,
+ PciIoDevice,
+ NULL
+ );
+
+ }
+
+ if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
+ ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
+ (*NumberOfChildren)++;
+ }
+
+ if (!IsListEmpty (&PciIoDevice->ChildList)) {
+ Status = StartPciDevicesOnBridge (
+ Controller,
+ PciIoDevice,
+ RemainingDevicePath,
+ NumberOfChildren,
+ ChildHandleBuffer
+ );
+
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ }
+
+ if (PciIoDevice == NULL) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Start to manage all the PCI devices it found previously under
+ the entire host bridge.
+
+ @param Controller The root bridge handle.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_SUCCESS Success to start Pci device on host bridge.
+
+**/
+EFI_STATUS
+StartPciDevices (
+ IN EFI_HANDLE Controller
+ )
+{
+ PCI_IO_DEVICE *RootBridge;
+ EFI_HANDLE ThisHostBridge;
+ LIST_ENTRY *CurrentLink;
+
+ RootBridge = GetRootBridgeByHandle (Controller);
+ ASSERT (RootBridge != NULL);
+ ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+
+ RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ //
+ // Locate the right root bridge to start
+ //
+ if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {
+ StartPciDevicesOnBridge (
+ RootBridge->Handle,
+ RootBridge,
+ NULL,
+ NULL,
+ NULL
+ );
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create root bridge device.
+
+ @param RootBridgeHandle Specified root bridge hanle.
+
+ @return The crated root bridge device instance, NULL means no
+ root bridge device instance created.
+
+**/
+PCI_IO_DEVICE *
+CreateRootBridge (
+ IN EFI_HANDLE RootBridgeHandle
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *Dev;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
+ if (Dev == NULL) {
+ return NULL;
+ }
+
+ Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
+ Dev->Handle = RootBridgeHandle;
+ InitializeListHead (&Dev->ChildList);
+
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Dev);
+ return NULL;
+ }
+
+ //
+ // Record the root bridge parent device path
+ //
+ Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
+
+ //
+ // Get the pci root bridge io protocol
+ //
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePciDevice (Dev);
+ return NULL;
+ }
+
+ Dev->PciRootBridgeIo = PciRootBridgeIo;
+
+ //
+ // Initialize the PCI I/O instance structure
+ //
+ InitializePciIoInstance (Dev);
+ InitializePciDriverOverrideInstance (Dev);
+ InitializePciLoadFile2 (Dev);
+
+ //
+ // Initialize reserved resource list and
+ // option rom driver list
+ //
+ InitializeListHead (&Dev->ReservedResourceList);
+ InitializeListHead (&Dev->OptionRomDriverList);
+
+ return Dev;
+}
+
+/**
+ Get root bridge device instance by specific root bridge handle.
+
+ @param RootBridgeHandle Given root bridge handle.
+
+ @return The root bridge device instance, NULL means no root bridge
+ device instance found.
+
+**/
+PCI_IO_DEVICE *
+GetRootBridgeByHandle (
+ EFI_HANDLE RootBridgeHandle
+ )
+{
+ PCI_IO_DEVICE *RootBridgeDev;
+ LIST_ENTRY *CurrentLink;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+
+ RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (RootBridgeDev->Handle == RootBridgeHandle) {
+ return RootBridgeDev;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
+/**
+ Judege whether Pci device existed.
+
+ @param Bridge Parent bridege instance.
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Pci device existed.
+ @retval FALSE Pci device did not exist.
+
+**/
+BOOLEAN
+PciDeviceExisted (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (Temp == PciIoDevice) {
+ return TRUE;
+ }
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ if (PciDeviceExisted (Temp, PciIoDevice)) {
+ return TRUE;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the active VGA device on the same segment.
+
+ @param VgaDevice PCI IO instance for the VGA device.
+
+ @return The active VGA device on the same segment.
+
+**/
+PCI_IO_DEVICE *
+ActiveVGADeviceOnTheSameSegment (
+ IN PCI_IO_DEVICE *VgaDevice
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
+
+ Temp = ActiveVGADeviceOnTheRootBridge (Temp);
+
+ if (Temp != NULL) {
+ return Temp;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
+/**
+ Get the active VGA device on the root bridge.
+
+ @param RootBridge PCI IO instance for the root bridge.
+
+ @return The active VGA device.
+
+**/
+PCI_IO_DEVICE *
+ActiveVGADeviceOnTheRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ CurrentLink = RootBridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_PCI_VGA(&Temp->Pci) &&
+ (Temp->Attributes &
+ (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO |
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
+ return Temp;
+ }
+
+ if (IS_PCI_BRIDGE (&Temp->Pci)) {
+
+ Temp = ActiveVGADeviceOnTheRootBridge (Temp);
+
+ if (Temp != NULL) {
+ return Temp;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
+
+/**
+ Get HPC PCI address according to its device path.
+
+ @param RootBridge Root bridege Io instance.
+ @param RemainingDevicePath Given searching device path.
+ @param PciAddress Buffer holding searched result.
+
+ @retval EFI_SUCCESS PCI address was stored in PciAddress
+ @retval EFI_NOT_FOUND Can not find the specific device path.
+
+**/
+EFI_STATUS
+GetHpcPciAddressFromRootBridge (
+ IN PCI_IO_DEVICE *RootBridge,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ OUT UINT64 *PciAddress
+ )
+{
+ EFI_DEV_PATH_PTR Node;
+ PCI_IO_DEVICE *Temp;
+ EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
+ LIST_ENTRY *CurrentLink;
+ BOOLEAN MisMatch;
+
+ MisMatch = FALSE;
+
+ CurrentDevicePath = RemainingDevicePath;
+ Node.DevPath = CurrentDevicePath;
+ Temp = NULL;
+
+ while (!IsDevicePathEnd (CurrentDevicePath)) {
+
+ CurrentLink = RootBridge->ChildList.ForwardLink;
+ Node.DevPath = CurrentDevicePath;
+
+ while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (Node.Pci->Device == Temp->DeviceNumber &&
+ Node.Pci->Function == Temp->FunctionNumber) {
+ RootBridge = Temp;
+ break;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Check if we find the bridge
+ //
+ if (CurrentLink == &RootBridge->ChildList) {
+
+ MisMatch = TRUE;
+ break;
+
+ }
+
+ CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
+ }
+
+ if (MisMatch) {
+
+ CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
+
+ if (IsDevicePathEnd (CurrentDevicePath)) {
+ *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+ }
+
+ if (Temp != NULL) {
+ *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h
new file mode 100644
index 0000000000..e97e90dea1
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h
@@ -0,0 +1,289 @@
+/** @file
+ Supporting functions declaration for PCI devices management.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_DEVICE_SUPPORT_H_
+#define _EFI_PCI_DEVICE_SUPPORT_H_
+
+/**
+ Initialize the PCI devices pool.
+
+**/
+VOID
+InitializePciDevicePool (
+ VOID
+ );
+
+/**
+ Insert a root bridge into PCI device pool.
+
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+InsertRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ );
+
+/**
+ This function is used to insert a PCI device node under
+ a bridge.
+
+ @param Bridge The PCI bridge.
+ @param PciDeviceNode The PCI device needs inserting.
+
+**/
+VOID
+InsertPciDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciDeviceNode
+ );
+
+/**
+ Destroy root bridge and remove it from deivce tree.
+
+ @param RootBridge The bridge want to be removed.
+
+**/
+VOID
+DestroyRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ );
+
+/**
+ Destroy all the pci device node under the bridge.
+ Bridge itself is not included.
+
+ @param Bridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+DestroyPciDeviceTree (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Destroy all device nodes under the root bridge
+ specified by Controller.
+
+ The root bridge itself is also included.
+
+ @param Controller Root bridge handle.
+
+ @retval EFI_SUCCESS Destory all devcie nodes successfully.
+ @retval EFI_NOT_FOUND Cannot find any PCI device under specified
+ root bridge.
+
+**/
+EFI_STATUS
+DestroyRootBridgeByHandle (
+ IN EFI_HANDLE Controller
+ );
+
+/**
+ This function registers the PCI IO device.
+
+ It creates a handle for this PCI IO device (if the handle does not exist), attaches
+ appropriate protocols onto the handle, does necessary initialization, and sets up
+ parent/child relationship with its bus controller.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
+ @param Handle A pointer to hold the returned EFI handle for the PCI IO device.
+
+ @retval EFI_SUCCESS The PCI device is successfully registered.
+ @retval other An error occurred when registering the PCI device.
+
+**/
+EFI_STATUS
+RegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *PciIoDevice,
+ OUT EFI_HANDLE *Handle OPTIONAL
+ );
+
+/**
+ This function is used to remove the whole PCI devices on the specified bridge from
+ the root bridge.
+
+ @param RootBridgeHandle The root bridge device handle.
+ @param Bridge The bridge device to be removed.
+
+**/
+VOID
+RemoveAllPciDeviceOnBridge (
+ EFI_HANDLE RootBridgeHandle,
+ PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ This function is used to de-register the PCI IO device.
+
+ That includes un-installing PciIo protocol from the specified PCI
+ device handle.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param Handle PCI device handle.
+
+ @retval EFI_SUCCESS The PCI device is successfully de-registered.
+ @retval other An error occurred when de-registering the PCI device.
+
+**/
+EFI_STATUS
+DeRegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ );
+
+/**
+ Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.
+
+ @param Controller The root bridge handle.
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+ @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
+ @param NumberOfChildren Children number.
+ @param ChildHandleBuffer A pointer to the child handle buffer.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
+ @retval EFI_NOT_FOUND Can not find the specific device.
+ @retval EFI_SUCCESS Success to start Pci devices on bridge.
+
+**/
+EFI_STATUS
+StartPciDevicesOnBridge (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *RootBridge,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Start to manage all the PCI devices it found previously under
+ the entire host bridge.
+
+ @param Controller The root bridge handle.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_SUCCESS Success to start Pci device on host bridge.
+
+**/
+EFI_STATUS
+StartPciDevices (
+ IN EFI_HANDLE Controller
+ );
+
+/**
+ Create root bridge device.
+
+ @param RootBridgeHandle Specified root bridge hanle.
+
+ @return The crated root bridge device instance, NULL means no
+ root bridge device instance created.
+
+**/
+PCI_IO_DEVICE *
+CreateRootBridge (
+ IN EFI_HANDLE RootBridgeHandle
+ );
+
+/**
+ Get root bridge device instance by specific root bridge handle.
+
+ @param RootBridgeHandle Given root bridge handle.
+
+ @return The root bridge device instance, NULL means no root bridge
+ device instance found.
+
+**/
+PCI_IO_DEVICE *
+GetRootBridgeByHandle (
+ EFI_HANDLE RootBridgeHandle
+ );
+
+
+/**
+ Judege whether Pci device existed.
+
+ @param Bridge Parent bridege instance.
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Pci device existed.
+ @retval FALSE Pci device did not exist.
+
+**/
+BOOLEAN
+PciDeviceExisted (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Get the active VGA device on the same segment.
+
+ @param VgaDevice PCI IO instance for the VGA device.
+
+ @return The active VGA device on the same segment.
+
+**/
+PCI_IO_DEVICE *
+ActiveVGADeviceOnTheSameSegment (
+ IN PCI_IO_DEVICE *VgaDevice
+ );
+
+/**
+ Get the active VGA device on the root bridge.
+
+ @param RootBridge PCI IO instance for the root bridge.
+
+ @return The active VGA device.
+
+**/
+PCI_IO_DEVICE *
+ActiveVGADeviceOnTheRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ );
+
+/**
+ Get HPC PCI address according to its device path.
+
+ @param RootBridge Root bridege Io instance.
+ @param RemainingDevicePath Given searching device path.
+ @param PciAddress Buffer holding searched result.
+
+ @retval EFI_SUCCESS PCI address was stored in PciAddress.
+ @retval EFI_NOT_FOUND Can not find the specific device path.
+
+**/
+EFI_STATUS
+GetHpcPciAddressFromRootBridge (
+ IN PCI_IO_DEVICE *RootBridge,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ OUT UINT64 *PciAddress
+ );
+
+/**
+ Destroy a pci device node.
+
+ All direct or indirect allocated resource for this node will be freed.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried.
+
+**/
+VOID
+FreePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c
new file mode 100644
index 0000000000..119866b3c1
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c
@@ -0,0 +1,143 @@
+/** @file
+ Functions implementation for Bus Specific Driver Override protoocl.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+/**
+ Initializes a PCI Driver Override Instance.
+
+ @param PciIoDevice PCI Device instance.
+
+**/
+VOID
+InitializePciDriverOverrideInstance (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ PciIoDevice->PciDriverOverride.GetDriver = GetDriver;
+}
+
+
+/**
+ Uses a bus specific algorithm to retrieve a driver image handle for a controller.
+
+ @param This A pointer to the EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL instance.
+ @param DriverImageHandle On input, a pointer to the previous driver image handle returned
+ by GetDriver(). On output, a pointer to the next driver
+ image handle. Passing in a NULL, will return the first driver
+ image handle.
+
+ @retval EFI_SUCCESS A bus specific override driver is returned in DriverImageHandle.
+ @retval EFI_NOT_FOUND The end of the list of override drivers was reached.
+ A bus specific override driver is not returned in DriverImageHandle.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that was returned on a
+ previous call to GetDriver().
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriver (
+ IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN OUT EFI_HANDLE *DriverImageHandle
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ LIST_ENTRY *CurrentLink;
+ PCI_DRIVER_OVERRIDE_LIST *Node;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS (This);
+
+ CurrentLink = PciIoDevice->OptionRomDriverList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->OptionRomDriverList) {
+
+ Node = DRIVER_OVERRIDE_FROM_LINK (CurrentLink);
+
+ if (*DriverImageHandle == NULL) {
+
+ *DriverImageHandle = Node->DriverImageHandle;
+ return EFI_SUCCESS;
+ }
+
+ if (*DriverImageHandle == Node->DriverImageHandle) {
+
+ if (CurrentLink->ForwardLink == &PciIoDevice->OptionRomDriverList ||
+ CurrentLink->ForwardLink == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get next node
+ //
+ Node = DRIVER_OVERRIDE_FROM_LINK (CurrentLink->ForwardLink);
+ *DriverImageHandle = Node->DriverImageHandle;
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Add an overriding driver image.
+
+ @param PciIoDevice Instance of PciIo device.
+ @param DriverImageHandle new added driver image.
+
+ @retval EFI_SUCCESS Successfully added driver.
+ @retval EFI_OUT_OF_RESOURCES No memory resource for new driver instance.
+ @retval other Some error occurred when locating gEfiLoadedImageProtocolGuid.
+
+**/
+EFI_STATUS
+AddDriver (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_HANDLE DriverImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ PCI_DRIVER_OVERRIDE_LIST *Node;
+
+ Status = gBS->HandleProtocol (DriverImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Node = AllocatePool (sizeof (PCI_DRIVER_OVERRIDE_LIST));
+ if (Node == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Node->Signature = DRIVER_OVERRIDE_SIGNATURE;
+ Node->DriverImageHandle = DriverImageHandle;
+
+ InsertTailList (&PciIoDevice->OptionRomDriverList, &(Node->Link));
+
+ PciIoDevice->BusOverride = TRUE;
+
+ ImageContext.Handle = LoadedImage->ImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image
+ //
+ PeCoffLoaderGetImageInfo (&ImageContext);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h
new file mode 100644
index 0000000000..d28fb7f846
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h
@@ -0,0 +1,86 @@
+/** @file
+ Functions declaration for Bus Specific Driver Override protoocl.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _EFI_PCI_DRIVER_OVERRRIDE_H_
+#define _EFI_PCI_DRIVER_OVERRRIDE_H_
+
+#define DRIVER_OVERRIDE_SIGNATURE SIGNATURE_32 ('d', 'r', 'o', 'v')
+
+//
+// PCI driver override driver image list
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE DriverImageHandle;
+} PCI_DRIVER_OVERRIDE_LIST;
+
+
+#define DRIVER_OVERRIDE_FROM_LINK(a) \
+ CR (a, PCI_DRIVER_OVERRIDE_LIST, Link, DRIVER_OVERRIDE_SIGNATURE)
+
+/**
+ Initializes a PCI Driver Override Instance.
+
+ @param PciIoDevice PCI Device instance.
+
+**/
+VOID
+InitializePciDriverOverrideInstance (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Add an overriding driver image.
+
+ @param PciIoDevice Instance of PciIo device.
+ @param DriverImageHandle new added driver image.
+
+ @retval EFI_SUCCESS Successfully added driver.
+ @retval EFI_OUT_OF_RESOURCES No memory resource for new driver instance.
+ @retval other Some error occurred when locating gEfiLoadedImageProtocolGuid.
+
+**/
+EFI_STATUS
+AddDriver (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_HANDLE DriverImageHandle
+ );
+
+
+/**
+ Uses a bus specific algorithm to retrieve a driver image handle for a controller.
+
+ @param This A pointer to the EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL instance.
+ @param DriverImageHandle On input, a pointer to the previous driver image handle returned
+ by GetDriver(). On output, a pointer to the next driver
+ image handle. Passing in a NULL, will return the first driver
+ image handle.
+
+ @retval EFI_SUCCESS A bus specific override driver is returned in DriverImageHandle.
+ @retval EFI_NOT_FOUND The end of the list of override drivers was reached.
+ A bus specific override driver is not returned in DriverImageHandle.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that was returned on a
+ previous call to GetDriver().
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriver (
+ IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN OUT EFI_HANDLE *DriverImageHandle
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
new file mode 100644
index 0000000000..6c1de3f3e6
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
@@ -0,0 +1,2171 @@
+/** @file
+ PCI eunmeration implementation on entire PCI bus system for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ @param Controller Parent controller handle.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumerator (
+ IN EFI_HANDLE Controller
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_HANDLE HostBridgeHandle;
+ EFI_STATUS Status;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ //
+ // If PCI bus has already done the full enumeration, never do it again
+ //
+ if (!gFullEnumeration) {
+ return PciEnumeratorLight (Controller);
+ }
+
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the host bridge handle
+ //
+ HostBridgeHandle = PciRootBridgeIo->ParentHandle;
+
+ //
+ // Get the pci host bridge resource allocation protocol
+ //
+ Status = gBS->OpenProtocol (
+ HostBridgeHandle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ (VOID **) &PciResAlloc,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the pci bus enumeration is about to begin
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration);
+
+ //
+ // Start the bus allocation phase
+ //
+ Status = PciHostBridgeEnumerator (PciResAlloc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Submit the resource request
+ //
+ Status = PciHostBridgeResourceAllocator (PciResAlloc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the pci bus enumeration is about to complete
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndEnumeration);
+
+ //
+ // Process P2C
+ //
+ Status = PciHostBridgeP2CProcess (PciResAlloc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Process attributes for devices on this host bridge
+ //
+ Status = PciHostBridgeDeviceAttribute (PciResAlloc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gFullEnumeration = FALSE;
+
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiPciEnumerationCompleteProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enumerate PCI root bridge.
+
+ @param PciResAlloc Pointer to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+ @param RootBridgeDev Instance of root bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated root bridge.
+ @retval other Failed to enumerate root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
+ UINT8 SubBusNumber;
+ UINT8 StartBusNumber;
+ UINT8 PaddedBusRange;
+ EFI_HANDLE RootBridgeHandle;
+
+ SubBusNumber = 0;
+ StartBusNumber = 0;
+ PaddedBusRange = 0;
+
+ //
+ // Get the root bridge handle
+ //
+ RootBridgeHandle = RootBridgeDev->Handle;
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_BUS_ENUM,
+ RootBridgeDev->DevicePath
+ );
+
+ //
+ // Get the Bus information
+ //
+ Status = PciResAlloc->StartBusEnumeration (
+ PciResAlloc,
+ RootBridgeHandle,
+ (VOID **) &Configuration
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the bus number to start with
+ //
+ StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
+ PaddedBusRange = (UINT8) (Configuration->AddrRangeMax);
+
+ //
+ // Initialize the subordinate bus number
+ //
+ SubBusNumber = StartBusNumber;
+
+ //
+ // Reset all assigned PCI bus number
+ //
+ ResetAllPpbBusNumber (
+ RootBridgeDev,
+ StartBusNumber
+ );
+
+ //
+ // Assign bus number
+ //
+ Status = PciScanBus (
+ RootBridgeDev,
+ (UINT8) (Configuration->AddrRangeMin),
+ &SubBusNumber,
+ &PaddedBusRange
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+
+ //
+ // Assign max bus number scanned
+ //
+ Configuration->AddrLen = SubBusNumber - StartBusNumber + 1 + PaddedBusRange;
+
+ //
+ // Set bus number
+ //
+ Status = PciResAlloc->SetBusNumbers (
+ PciResAlloc,
+ RootBridgeHandle,
+ Configuration
+ );
+
+ FreePool (Configuration);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is used to process all PCI devices' Option Rom
+ on a certain root bridge.
+
+ @param Bridge Given parent's root bridge.
+ @param RomBase Base address of ROM driver loaded from.
+ @param MaxLength Maximum rom size.
+
+**/
+VOID
+ProcessOptionRom (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT64 RomBase,
+ IN UINT64 MaxLength
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ //
+ // Go through bridges to reach all devices
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (!IsListEmpty (&Temp->ChildList)) {
+
+ //
+ // Go further to process the option rom under this bridge
+ //
+ ProcessOptionRom (Temp, RomBase, MaxLength);
+ }
+
+ if (Temp->RomSize != 0 && Temp->RomSize <= MaxLength) {
+
+ //
+ // Load and process the option rom
+ //
+ LoadOpRomImage (Temp, RomBase);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ This routine is used to assign bus number to the given PCI bus system
+
+ @param Bridge Parent root bridge instance.
+ @param StartBusNumber Number of beginning.
+ @param SubBusNumber The number of sub bus.
+
+ @retval EFI_SUCCESS Successfully assigned bus number.
+ @retval EFI_DEVICE_ERROR Failed to assign bus number.
+
+**/
+EFI_STATUS
+PciAssignBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT8 Func;
+ UINT64 Address;
+ UINTN SecondBus;
+ UINT16 Register;
+ UINT8 Register8;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+
+ SecondBus = 0;
+ Register = 0;
+
+ *SubBusNumber = StartBusNumber;
+
+ //
+ // First check to see whether the parent is ppb
+ //
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether a pci device is present
+ //
+ Status = PciDevicePresent (
+ PciRootBridgeIo,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func
+ );
+
+ if (!EFI_ERROR (Status) &&
+ (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
+
+ //
+ // Reserved one bus for cardbus bridge
+ //
+ SecondBus = ++(*SubBusNumber);
+
+ Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
+
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint16,
+ Address,
+ 1,
+ &Register
+ );
+
+ //
+ // Initialize SubBusNumber to SecondBus
+ //
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ SubBusNumber
+ );
+ //
+ // If it is PPB, resursively search down this bridge
+ //
+ if (IS_PCI_BRIDGE (&Pci)) {
+
+ Register8 = 0xFF;
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ &Register8
+ );
+
+ Status = PciAssignBusNumber (
+ Bridge,
+ (UINT8) (SecondBus),
+ SubBusNumber
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Set the current maximum bus number under the PPB
+ //
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ SubBusNumber
+ );
+
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is used to determine the root bridge attribute by interfacing
+ the host bridge resource allocation protocol.
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ @param RootBridgeDev Root bridge instance
+
+ @retval EFI_SUCCESS Successfully got root bridge's attribute.
+ @retval other Failed to get attribute.
+
+**/
+EFI_STATUS
+DetermineRootBridgeAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ )
+{
+ UINT64 Attributes;
+ EFI_STATUS Status;
+ EFI_HANDLE RootBridgeHandle;
+
+ Attributes = 0;
+ RootBridgeHandle = RootBridgeDev->Handle;
+
+ //
+ // Get root bridge attribute by calling into pci host bridge resource allocation protocol
+ //
+ Status = PciResAlloc->GetAllocAttributes (
+ PciResAlloc,
+ RootBridgeHandle,
+ &Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Here is the point where PCI bus driver calls HOST bridge allocation protocol
+ // Currently we hardcoded for ea815
+ //
+ if ((Attributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {
+ RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED;
+ }
+
+ if ((Attributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0) {
+ RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
+ }
+
+ RootBridgeDev->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
+ RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
+ RootBridgeDev->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Max Option Rom size on specified bridge.
+
+ @param Bridge Given bridge device instance.
+
+ @return Max size of option rom needed.
+
+**/
+UINT64
+GetMaxOptionRomSize (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+ UINT64 MaxOptionRomSize;
+ UINT64 TempOptionRomSize;
+
+ MaxOptionRomSize = 0;
+
+ //
+ // Go through bridges to reach all devices
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (!IsListEmpty (&Temp->ChildList)) {
+
+ //
+ // Get max option rom size under this bridge
+ //
+ TempOptionRomSize = GetMaxOptionRomSize (Temp);
+
+ //
+ // Compare with the option rom size of the bridge
+ // Get the larger one
+ //
+ if (Temp->RomSize > TempOptionRomSize) {
+ TempOptionRomSize = Temp->RomSize;
+ }
+
+ } else {
+
+ //
+ // For devices get the rom size directly
+ //
+ TempOptionRomSize = Temp->RomSize;
+ }
+
+ //
+ // Get the largest rom size on this bridge
+ //
+ if (TempOptionRomSize > MaxOptionRomSize) {
+ MaxOptionRomSize = TempOptionRomSize;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return MaxOptionRomSize;
+}
+
+/**
+ Process attributes of devices on this host bridge
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully process attribute.
+ @retval EFI_NOT_FOUND Can not find the specific root bridge device.
+ @retval other Failed to determine the root bridge device's attribute.
+
+**/
+EFI_STATUS
+PciHostBridgeDeviceAttribute (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+
+ RootBridgeHandle = NULL;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Set the attributes for devcies behind the Root Bridge
+ //
+ Status = DetermineDeviceAttribute (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get resource allocation status from the ACPI resource descriptor.
+
+ @param AcpiConfig Point to Acpi configuration table.
+ @param IoResStatus Return the status of I/O resource.
+ @param Mem32ResStatus Return the status of 32-bit Memory resource.
+ @param PMem32ResStatus Return the status of 32-bit Prefetchable Memory resource.
+ @param Mem64ResStatus Return the status of 64-bit Memory resource.
+ @param PMem64ResStatus Return the status of 64-bit Prefetchable Memory resource.
+
+**/
+VOID
+GetResourceAllocationStatus (
+ VOID *AcpiConfig,
+ OUT UINT64 *IoResStatus,
+ OUT UINT64 *Mem32ResStatus,
+ OUT UINT64 *PMem32ResStatus,
+ OUT UINT64 *Mem64ResStatus,
+ OUT UINT64 *PMem64ResStatus
+ )
+{
+ UINT8 *Temp;
+ UINT64 ResStatus;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ACPIAddressDesc;
+
+ Temp = (UINT8 *) AcpiConfig;
+
+ while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+
+ ACPIAddressDesc = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+ ResStatus = ACPIAddressDesc->AddrTranslationOffset;
+
+ switch (ACPIAddressDesc->ResType) {
+ case 0:
+ if (ACPIAddressDesc->AddrSpaceGranularity == 32) {
+ if (ACPIAddressDesc->SpecificFlag == 0x06) {
+ //
+ // Pmem32
+ //
+ *PMem32ResStatus = ResStatus;
+ } else {
+ //
+ // Mem32
+ //
+ *Mem32ResStatus = ResStatus;
+ }
+ }
+
+ if (ACPIAddressDesc->AddrSpaceGranularity == 64) {
+ if (ACPIAddressDesc->SpecificFlag == 0x06) {
+ //
+ // PMem64
+ //
+ *PMem64ResStatus = ResStatus;
+ } else {
+ //
+ // Mem64
+ //
+ *Mem64ResStatus = ResStatus;
+ }
+ }
+
+ break;
+
+ case 1:
+ //
+ // Io
+ //
+ *IoResStatus = ResStatus;
+ break;
+
+ default:
+ break;
+ }
+
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+}
+
+/**
+ Remove a PCI device from device pool and mark its bar.
+
+ @param PciDevice Instance of Pci device.
+
+ @retval EFI_SUCCESS Successfully remove the PCI device.
+ @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge.
+
+**/
+EFI_STATUS
+RejectPciDevice (
+ IN PCI_IO_DEVICE *PciDevice
+ )
+{
+ PCI_IO_DEVICE *Bridge;
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ //
+ // Remove the padding resource from a bridge
+ //
+ if ( IS_PCI_BRIDGE(&PciDevice->Pci) &&
+ PciDevice->ResourcePaddingDescriptors != NULL ) {
+ FreePool (PciDevice->ResourcePaddingDescriptors);
+ PciDevice->ResourcePaddingDescriptors = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip RB and PPB
+ //
+ if (IS_PCI_BRIDGE (&PciDevice->Pci) || (PciDevice->Parent == NULL)) {
+ return EFI_ABORTED;
+ }
+
+ if (IS_CARDBUS_BRIDGE (&PciDevice->Pci)) {
+ //
+ // Get the root bridge device
+ //
+ Bridge = PciDevice;
+ while (Bridge->Parent != NULL) {
+ Bridge = Bridge->Parent;
+ }
+
+ RemoveAllPciDeviceOnBridge (Bridge->Handle, PciDevice);
+
+ //
+ // Mark its bar
+ //
+ InitializeP2C (PciDevice);
+ }
+
+ //
+ // Remove the device
+ //
+ Bridge = PciDevice->Parent;
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (Temp == PciDevice) {
+ InitializePciDevice (Temp);
+ RemoveEntryList (CurrentLink);
+ FreePciDevice (Temp);
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_ABORTED;
+}
+
+/**
+ Determine whethter a PCI device can be rejected.
+
+ @param PciResNode Pointer to Pci resource node instance.
+
+ @retval TRUE The PCI device can be rejected.
+ @retval TRUE The PCI device cannot be rejected.
+
+**/
+BOOLEAN
+IsRejectiveDevice (
+ IN PCI_RESOURCE_NODE *PciResNode
+ )
+{
+ PCI_IO_DEVICE *Temp;
+
+ Temp = PciResNode->PciDev;
+
+ //
+ // Ensure the device is present
+ //
+ if (Temp == NULL) {
+ return FALSE;
+ }
+
+ //
+ // PPB and RB should go ahead
+ //
+ if (IS_PCI_BRIDGE (&Temp->Pci) || (Temp->Parent == NULL)) {
+ return TRUE;
+ }
+
+ //
+ // Skip device on Bus0
+ //
+ if ((Temp->Parent != NULL) && (Temp->BusNumber == 0)) {
+ return FALSE;
+ }
+
+ //
+ // Skip VGA
+ //
+ if (IS_PCI_VGA (&Temp->Pci)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Compare two resource nodes and get the larger resource consumer.
+
+ @param PciResNode1 resource node 1 want to be compared
+ @param PciResNode2 resource node 2 want to be compared
+
+ @return Larger resource node.
+
+**/
+PCI_RESOURCE_NODE *
+GetLargerConsumerDevice (
+ IN PCI_RESOURCE_NODE *PciResNode1,
+ IN PCI_RESOURCE_NODE *PciResNode2
+ )
+{
+ if (PciResNode2 == NULL) {
+ return PciResNode1;
+ }
+
+ if ((IS_PCI_BRIDGE(&(PciResNode2->PciDev->Pci)) || (PciResNode2->PciDev->Parent == NULL)) \
+ && (PciResNode2->ResourceUsage != PciResUsagePadding) )
+ {
+ return PciResNode1;
+ }
+
+ if (PciResNode1 == NULL) {
+ return PciResNode2;
+ }
+
+ if ((PciResNode1->Length) > (PciResNode2->Length)) {
+ return PciResNode1;
+ }
+
+ return PciResNode2;
+}
+
+
+/**
+ Get the max resource consumer in the host resource pool.
+
+ @param ResPool Pointer to resource pool node.
+
+ @return The max resource consumer in the host resource pool.
+
+**/
+PCI_RESOURCE_NODE *
+GetMaxResourceConsumerDevice (
+ IN PCI_RESOURCE_NODE *ResPool
+ )
+{
+ PCI_RESOURCE_NODE *Temp;
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *PciResNode;
+ PCI_RESOURCE_NODE *PPBResNode;
+
+ PciResNode = NULL;
+
+ CurrentLink = ResPool->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &ResPool->ChildList) {
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (!IsRejectiveDevice (Temp)) {
+ CurrentLink = CurrentLink->ForwardLink;
+ continue;
+ }
+
+ if ((IS_PCI_BRIDGE (&(Temp->PciDev->Pci)) || (Temp->PciDev->Parent == NULL)) \
+ && (Temp->ResourceUsage != PciResUsagePadding))
+ {
+ PPBResNode = GetMaxResourceConsumerDevice (Temp);
+ PciResNode = GetLargerConsumerDevice (PciResNode, PPBResNode);
+ } else {
+ PciResNode = GetLargerConsumerDevice (PciResNode, Temp);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return PciResNode;
+}
+
+/**
+ Adjust host bridge allocation so as to reduce resource requirement
+
+ @param IoPool Pointer to instance of I/O resource Node.
+ @param Mem32Pool Pointer to instance of 32-bit memory resource Node.
+ @param PMem32Pool Pointer to instance of 32-bit Prefetchable memory resource node.
+ @param Mem64Pool Pointer to instance of 64-bit memory resource node.
+ @param PMem64Pool Pointer to instance of 64-bit Prefetchable memory resource node.
+ @param IoResStatus Status of I/O resource Node.
+ @param Mem32ResStatus Status of 32-bit memory resource Node.
+ @param PMem32ResStatus Status of 32-bit Prefetchable memory resource node.
+ @param Mem64ResStatus Status of 64-bit memory resource node.
+ @param PMem64ResStatus Status of 64-bit Prefetchable memory resource node.
+
+ @retval EFI_SUCCESS Successfully adjusted resoruce on host bridge.
+ @retval EFI_ABORTED Host bridge hasn't this resource type or no resource be adjusted.
+
+**/
+EFI_STATUS
+PciHostBridgeAdjustAllocation (
+ IN PCI_RESOURCE_NODE *IoPool,
+ IN PCI_RESOURCE_NODE *Mem32Pool,
+ IN PCI_RESOURCE_NODE *PMem32Pool,
+ IN PCI_RESOURCE_NODE *Mem64Pool,
+ IN PCI_RESOURCE_NODE *PMem64Pool,
+ IN UINT64 IoResStatus,
+ IN UINT64 Mem32ResStatus,
+ IN UINT64 PMem32ResStatus,
+ IN UINT64 Mem64ResStatus,
+ IN UINT64 PMem64ResStatus
+ )
+{
+ BOOLEAN AllocationAjusted;
+ PCI_RESOURCE_NODE *PciResNode;
+ PCI_RESOURCE_NODE *ResPool[5];
+ PCI_IO_DEVICE *RemovedPciDev[5];
+ UINT64 ResStatus[5];
+ UINTN RemovedPciDevNum;
+ UINTN DevIndex;
+ UINTN ResType;
+ EFI_STATUS Status;
+ EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
+
+ PciResNode = NULL;
+ ZeroMem (RemovedPciDev, 5 * sizeof (PCI_IO_DEVICE *));
+ RemovedPciDevNum = 0;
+
+ ResPool[0] = IoPool;
+ ResPool[1] = Mem32Pool;
+ ResPool[2] = PMem32Pool;
+ ResPool[3] = Mem64Pool;
+ ResPool[4] = PMem64Pool;
+
+ ResStatus[0] = IoResStatus;
+ ResStatus[1] = Mem32ResStatus;
+ ResStatus[2] = PMem32ResStatus;
+ ResStatus[3] = Mem64ResStatus;
+ ResStatus[4] = PMem64ResStatus;
+
+ AllocationAjusted = FALSE;
+
+ for (ResType = 0; ResType < 5; ResType++) {
+
+ if (ResStatus[ResType] == EFI_RESOURCE_SATISFIED) {
+ continue;
+ }
+
+ if (ResStatus[ResType] == EFI_RESOURCE_NOT_SATISFIED) {
+ //
+ // Host bridge hasn't this resource type
+ //
+ return EFI_ABORTED;
+ }
+
+ //
+ // Hostbridge hasn't enough resource
+ //
+ PciResNode = GetMaxResourceConsumerDevice (ResPool[ResType]);
+ if (PciResNode == NULL) {
+ continue;
+ }
+
+ //
+ // Check if the device has been removed before
+ //
+ for (DevIndex = 0; DevIndex < RemovedPciDevNum; DevIndex++) {
+ if (PciResNode->PciDev == RemovedPciDev[DevIndex]) {
+ break;
+ }
+ }
+
+ if (DevIndex != RemovedPciDevNum) {
+ continue;
+ }
+
+ //
+ // Remove the device if it isn't in the array
+ //
+ Status = RejectPciDevice (PciResNode->PciDev);
+ if (Status == EFI_SUCCESS) {
+
+ //
+ // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
+ //
+ //
+ // Have no way to get ReqRes, AllocRes & Bar here
+ //
+ ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
+ AllocFailExtendedData.DevicePathSize = sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ AllocFailExtendedData.DevicePath = (UINT8 *) PciResNode->PciDev->DevicePath;
+ AllocFailExtendedData.Bar = PciResNode->Bar;
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
+ (VOID *) &AllocFailExtendedData,
+ sizeof (AllocFailExtendedData)
+ );
+
+ //
+ // Add it to the array and indicate at least a device has been rejected
+ //
+ RemovedPciDev[RemovedPciDevNum++] = PciResNode->PciDev;
+ AllocationAjusted = TRUE;
+ }
+ }
+ //
+ // End for
+ //
+
+ if (AllocationAjusted) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_ABORTED;
+ }
+}
+
+/**
+ Summary requests for all resource type, and contruct ACPI resource
+ requestor instance.
+
+ @param Bridge detecting bridge
+ @param IoNode Pointer to instance of I/O resource Node
+ @param Mem32Node Pointer to instance of 32-bit memory resource Node
+ @param PMem32Node Pointer to instance of 32-bit Pmemory resource node
+ @param Mem64Node Pointer to instance of 64-bit memory resource node
+ @param PMem64Node Pointer to instance of 64-bit Pmemory resource node
+ @param Config Output buffer holding new constructed APCI resource requestor
+
+ @retval EFI_SUCCESS Successfully constructed ACPI resource.
+ @retval EFI_OUT_OF_RESOURCES No memory availabe.
+
+**/
+EFI_STATUS
+ConstructAcpiResourceRequestor (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node,
+ OUT VOID **Config
+ )
+{
+ UINT8 NumConfig;
+ UINT8 Aperture;
+ UINT8 *Configuration;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+ EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;
+
+ NumConfig = 0;
+ Aperture = 0;
+
+ *Config = NULL;
+
+ //
+ // if there is io request, add to the io aperture
+ //
+ if (ResourceRequestExisted (IoNode)) {
+ NumConfig++;
+ Aperture |= 0x01;
+ }
+
+ //
+ // if there is mem32 request, add to the mem32 aperture
+ //
+ if (ResourceRequestExisted (Mem32Node)) {
+ NumConfig++;
+ Aperture |= 0x02;
+ }
+
+ //
+ // if there is pmem32 request, add to the pmem32 aperture
+ //
+ if (ResourceRequestExisted (PMem32Node)) {
+ NumConfig++;
+ Aperture |= 0x04;
+ }
+
+ //
+ // if there is mem64 request, add to the mem64 aperture
+ //
+ if (ResourceRequestExisted (Mem64Node)) {
+ NumConfig++;
+ Aperture |= 0x08;
+ }
+
+ //
+ // if there is pmem64 request, add to the pmem64 aperture
+ //
+ if (ResourceRequestExisted (PMem64Node)) {
+ NumConfig++;
+ Aperture |= 0x10;
+ }
+
+ if (NumConfig != 0) {
+
+ //
+ // If there is at least one type of resource request,
+ // allocate a acpi resource node
+ //
+ Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Configuration == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+
+ //
+ // Deal with io aperture
+ //
+ if ((Aperture & 0x01) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ //
+ // Io
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ //
+ // non ISA range
+ //
+ Ptr->SpecificFlag = 1;
+ Ptr->AddrLen = IoNode->Length;
+ Ptr->AddrRangeMax = IoNode->Alignment;
+
+ Ptr++;
+ }
+ //
+ // Deal with mem32 aperture
+ //
+ if ((Aperture & 0x02) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // Nonprefechable
+ //
+ Ptr->SpecificFlag = 0;
+ //
+ // 32 bit
+ //
+ Ptr->AddrSpaceGranularity = 32;
+ Ptr->AddrLen = Mem32Node->Length;
+ Ptr->AddrRangeMax = Mem32Node->Alignment;
+
+ Ptr++;
+ }
+
+ //
+ // Deal with Pmem32 aperture
+ //
+ if ((Aperture & 0x04) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // prefechable
+ //
+ Ptr->SpecificFlag = 0x6;
+ //
+ // 32 bit
+ //
+ Ptr->AddrSpaceGranularity = 32;
+ Ptr->AddrLen = PMem32Node->Length;
+ Ptr->AddrRangeMax = PMem32Node->Alignment;
+
+ Ptr++;
+ }
+ //
+ // Deal with mem64 aperture
+ //
+ if ((Aperture & 0x08) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // nonprefechable
+ //
+ Ptr->SpecificFlag = 0;
+ //
+ // 64 bit
+ //
+ Ptr->AddrSpaceGranularity = 64;
+ Ptr->AddrLen = Mem64Node->Length;
+ Ptr->AddrRangeMax = Mem64Node->Alignment;
+
+ Ptr++;
+ }
+ //
+ // Deal with Pmem64 aperture
+ //
+ if ((Aperture & 0x10) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // prefechable
+ //
+ Ptr->SpecificFlag = 0x06;
+ //
+ // 64 bit
+ //
+ Ptr->AddrSpaceGranularity = 64;
+ Ptr->AddrLen = PMem64Node->Length;
+ Ptr->AddrRangeMax = PMem64Node->Alignment;
+
+ Ptr++;
+ }
+
+ //
+ // put the checksum
+ //
+ PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr;
+
+ PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
+ PtrEnd->Checksum = 0;
+
+ } else {
+
+ //
+ // If there is no resource request
+ //
+ Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Configuration == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (Configuration);
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+
+ PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Ptr + 1);
+ PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
+ PtrEnd->Checksum = 0;
+ }
+
+ *Config = Configuration;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get resource base from an acpi configuration descriptor.
+
+ @param Config An acpi configuration descriptor.
+ @param IoBase Output of I/O resource base address.
+ @param Mem32Base Output of 32-bit memory base address.
+ @param PMem32Base Output of 32-bit prefetchable memory base address.
+ @param Mem64Base Output of 64-bit memory base address.
+ @param PMem64Base Output of 64-bit prefetchable memory base address.
+
+**/
+VOID
+GetResourceBase (
+ IN VOID *Config,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ )
+{
+ UINT8 *Temp;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+ UINT64 ResStatus;
+
+ ASSERT (Config != NULL);
+
+ *IoBase = 0xFFFFFFFFFFFFFFFFULL;
+ *Mem32Base = 0xFFFFFFFFFFFFFFFFULL;
+ *PMem32Base = 0xFFFFFFFFFFFFFFFFULL;
+ *Mem64Base = 0xFFFFFFFFFFFFFFFFULL;
+ *PMem64Base = 0xFFFFFFFFFFFFFFFFULL;
+
+ Temp = (UINT8 *) Config;
+
+ while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+ ResStatus = Ptr->AddrTranslationOffset;
+
+ if (ResStatus == EFI_RESOURCE_SATISFIED) {
+
+ switch (Ptr->ResType) {
+
+ //
+ // Memory type aperture
+ //
+ case 0:
+
+ //
+ // Check to see the granularity
+ //
+ if (Ptr->AddrSpaceGranularity == 32) {
+ if ((Ptr->SpecificFlag & 0x06) != 0) {
+ *PMem32Base = Ptr->AddrRangeMin;
+ } else {
+ *Mem32Base = Ptr->AddrRangeMin;
+ }
+ }
+
+ if (Ptr->AddrSpaceGranularity == 64) {
+ if ((Ptr->SpecificFlag & 0x06) != 0) {
+ *PMem64Base = Ptr->AddrRangeMin;
+ } else {
+ *Mem64Base = Ptr->AddrRangeMin;
+ }
+ }
+ break;
+
+ case 1:
+
+ //
+ // Io type aperture
+ //
+ *IoBase = Ptr->AddrRangeMin;
+ break;
+
+ default:
+ break;
+
+ }
+ //
+ // End switch
+ //
+ }
+ //
+ // End for
+ //
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+}
+
+/**
+ Enumerate pci bridge, allocate resource and determine attribute
+ for devices on this bridge.
+
+ @param BridgeDev Pointer to instance of bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated PCI bridge.
+ @retval other Failed to enumerate.
+
+**/
+EFI_STATUS
+PciBridgeEnumerator (
+ IN PCI_IO_DEVICE *BridgeDev
+ )
+{
+ UINT8 SubBusNumber;
+ UINT8 StartBusNumber;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ SubBusNumber = 0;
+ StartBusNumber = 0;
+ PciIo = &(BridgeDev->PciIo);
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x19, 1, &StartBusNumber);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciAssignBusNumber (
+ BridgeDev,
+ StartBusNumber,
+ &SubBusNumber
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciPciDeviceInfoCollector (BridgeDev, StartBusNumber);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciBridgeResourceAllocator (BridgeDev);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = DetermineDeviceAttribute (BridgeDev);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Allocate all kinds of resource for PCI bridge.
+
+ @param Bridge Pointer to bridge instance.
+
+ @retval EFI_SUCCESS Successfully allocated resource for PCI bridge.
+ @retval other Failed to allocate resource for bridge.
+
+**/
+EFI_STATUS
+PciBridgeResourceAllocator (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ PCI_RESOURCE_NODE *IoBridge;
+ PCI_RESOURCE_NODE *Mem32Bridge;
+ PCI_RESOURCE_NODE *PMem32Bridge;
+ PCI_RESOURCE_NODE *Mem64Bridge;
+ PCI_RESOURCE_NODE *PMem64Bridge;
+ UINT64 IoBase;
+ UINT64 Mem32Base;
+ UINT64 PMem32Base;
+ UINT64 Mem64Base;
+ UINT64 PMem64Base;
+ EFI_STATUS Status;
+
+ IoBridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFF,
+ 0,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ Mem32Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ PMem32Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ Mem64Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ PMem64Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ //
+ // Create resourcemap by going through all the devices subject to this root bridge
+ //
+ CreateResourceMap (
+ Bridge,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge
+ );
+
+ Status = GetResourceBaseFromBridge (
+ Bridge,
+ &IoBase,
+ &Mem32Base,
+ &PMem32Base,
+ &Mem64Base,
+ &PMem64Base
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Program IO resources
+ //
+ ProgramResource (
+ IoBase,
+ IoBridge
+ );
+
+ //
+ // Program Mem32 resources
+ //
+ ProgramResource (
+ Mem32Base,
+ Mem32Bridge
+ );
+
+ //
+ // Program PMem32 resources
+ //
+ ProgramResource (
+ PMem32Base,
+ PMem32Bridge
+ );
+
+ //
+ // Program Mem64 resources
+ //
+ ProgramResource (
+ Mem64Base,
+ Mem64Bridge
+ );
+
+ //
+ // Program PMem64 resources
+ //
+ ProgramResource (
+ PMem64Base,
+ PMem64Bridge
+ );
+
+ DestroyResourceTree (IoBridge);
+ DestroyResourceTree (Mem32Bridge);
+ DestroyResourceTree (PMem32Bridge);
+ DestroyResourceTree (PMem64Bridge);
+ DestroyResourceTree (Mem64Bridge);
+
+ gBS->FreePool (IoBridge);
+ gBS->FreePool (Mem32Bridge);
+ gBS->FreePool (PMem32Bridge);
+ gBS->FreePool (PMem64Bridge);
+ gBS->FreePool (Mem64Bridge);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get resource base address for a pci bridge device.
+
+ @param Bridge Given Pci driver instance.
+ @param IoBase Output for base address of I/O type resource.
+ @param Mem32Base Output for base address of 32-bit memory type resource.
+ @param PMem32Base Ooutput for base address of 32-bit Pmemory type resource.
+ @param Mem64Base Output for base address of 64-bit memory type resource.
+ @param PMem64Base Output for base address of 64-bit Pmemory type resource.
+
+ @retval EFI_SUCCESS Successfully got resource base address.
+ @retval EFI_OUT_OF_RESOURCES PCI bridge is not available.
+
+**/
+EFI_STATUS
+GetResourceBaseFromBridge (
+ IN PCI_IO_DEVICE *Bridge,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ )
+{
+ if (!Bridge->Allocated) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *IoBase = gAllOne;
+ *Mem32Base = gAllOne;
+ *PMem32Base = gAllOne;
+ *Mem64Base = gAllOne;
+ *PMem64Base = gAllOne;
+
+ if (IS_PCI_BRIDGE (&Bridge->Pci)) {
+
+ if (Bridge->PciBar[PPB_IO_RANGE].Length > 0) {
+ *IoBase = Bridge->PciBar[PPB_IO_RANGE].BaseAddress;
+ }
+
+ if (Bridge->PciBar[PPB_MEM32_RANGE].Length > 0) {
+ *Mem32Base = Bridge->PciBar[PPB_MEM32_RANGE].BaseAddress;
+ }
+
+ if (Bridge->PciBar[PPB_PMEM32_RANGE].Length > 0) {
+ *PMem32Base = Bridge->PciBar[PPB_PMEM32_RANGE].BaseAddress;
+ }
+
+ if (Bridge->PciBar[PPB_PMEM64_RANGE].Length > 0) {
+ *PMem64Base = Bridge->PciBar[PPB_PMEM64_RANGE].BaseAddress;
+ } else {
+ *PMem64Base = gAllOne;
+ }
+
+ }
+
+ if (IS_CARDBUS_BRIDGE (&Bridge->Pci)) {
+ if (Bridge->PciBar[P2C_IO_1].Length > 0) {
+ *IoBase = Bridge->PciBar[P2C_IO_1].BaseAddress;
+ } else {
+ if (Bridge->PciBar[P2C_IO_2].Length > 0) {
+ *IoBase = Bridge->PciBar[P2C_IO_2].BaseAddress;
+ }
+ }
+
+ if (Bridge->PciBar[P2C_MEM_1].Length > 0) {
+ if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypePMem32) {
+ *PMem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;
+ }
+
+ if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypeMem32) {
+ *Mem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;
+ }
+ }
+
+ if (Bridge->PciBar[P2C_MEM_2].Length > 0) {
+ if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypePMem32) {
+ *PMem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;
+ }
+
+ if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypeMem32) {
+ *Mem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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] PciResAlloc 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
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ EFI_HANDLE HostBridgeHandle;
+ EFI_HANDLE RootBridgeHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_STATUS Status;
+
+ HostBridgeHandle = NULL;
+ RootBridgeHandle = NULL;
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Get Host Bridge Handle.
+ //
+ PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);
+
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->HandleProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ HostBridgeHandle = PciRootBridgeIo->ParentHandle;
+
+ //
+ // Call PlatformPci::PlatformNotify() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformNotify (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetEntry
+ );
+ } else if (gPciOverrideProtocol != NULL){
+ //
+ // Get Host Bridge Handle.
+ //
+ PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);
+
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->HandleProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ HostBridgeHandle = PciRootBridgeIo->ParentHandle;
+
+ //
+ // Call PlatformPci::PhaseNotify() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformNotify (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetEntry
+ );
+ }
+
+ Status = PciResAlloc->NotifyPhase (
+ PciResAlloc,
+ Phase
+ );
+
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Call PlatformPci::PlatformNotify() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformNotify (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetExit
+ );
+
+ } else if (gPciOverrideProtocol != NULL) {
+ //
+ // Call PlatformPci::PhaseNotify() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformNotify (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetExit
+ );
+ }
+
+ 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 Bridge Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Bus The bus number of the pci device.
+ @param Device The device number of the pci device.
+ @param Func The function number of the pci device.
+ @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
+PreprocessController (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS RootBridgePciAddress;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc;
+ EFI_HANDLE RootBridgeHandle;
+ EFI_HANDLE HostBridgeHandle;
+ EFI_STATUS Status;
+
+ //
+ // Get the host bridge handle
+ //
+ HostBridgeHandle = Bridge->PciRootBridgeIo->ParentHandle;
+
+ //
+ // Get the pci host bridge resource allocation protocol
+ //
+ Status = gBS->OpenProtocol (
+ HostBridgeHandle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ (VOID **) &PciResAlloc,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get Root Brige Handle
+ //
+ while (Bridge->Parent != NULL) {
+ Bridge = Bridge->Parent;
+ }
+
+ RootBridgeHandle = Bridge->Handle;
+
+ RootBridgePciAddress.Register = 0;
+ RootBridgePciAddress.Function = Func;
+ RootBridgePciAddress.Device = Device;
+ RootBridgePciAddress.Bus = Bus;
+ RootBridgePciAddress.ExtendedRegister = 0;
+
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformPrepController (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetEntry
+ );
+ } else if (gPciOverrideProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformPrepController (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetEntry
+ );
+ }
+
+ Status = PciResAlloc->PreprocessController (
+ PciResAlloc,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase
+ );
+
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformPrepController (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetExit
+ );
+ } else if (gPciOverrideProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformPrepController (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetExit
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows the PCI bus driver to be notified to act as requested when a hot-plug event has
+ happened on the hot-plug controller. Currently, the operations include add operation and remove operation..
+
+ @param This A pointer to the hot plug request protocol.
+ @param Operation The operation the PCI bus driver is requested to make.
+ @param Controller The handle of the hot-plug controller.
+ @param RemainingDevicePath The remaining device path for the PCI-like hot-plug device.
+ @param NumberOfChildren The number of child handles.
+ For a add operation, it is an output parameter.
+ For a remove operation, it's an input parameter.
+ @param ChildHandleBuffer The buffer which contains the child handles.
+
+ @retval EFI_INVALID_PARAMETER Operation is not a legal value.
+ Controller is NULL or not a valid handle.
+ NumberOfChildren is NULL.
+ ChildHandleBuffer is NULL while Operation is add.
+ @retval EFI_OUT_OF_RESOURCES There are no enough resources to start the devices.
+ @retval EFI_NOT_FOUND Can not find bridge according to controller handle.
+ @retval EFI_SUCCESS The handles for the specified device have been created or destroyed
+ as requested, and for an add operation, the new handles are
+ returned in ChildHandleBuffer.
+**/
+EFI_STATUS
+EFIAPI
+PciHotPlugRequestNotify (
+ IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL * This,
+ IN EFI_PCI_HOTPLUG_OPERATION Operation,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE * ChildHandleBuffer
+ )
+{
+ PCI_IO_DEVICE *Bridge;
+ PCI_IO_DEVICE *Temp;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ EFI_HANDLE RootBridgeHandle;
+ EFI_STATUS Status;
+
+ //
+ // Check input parameter validity
+ //
+ if ((Controller == NULL) || (NumberOfChildren == NULL)){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Operation != EfiPciHotPlugRequestAdd) && (Operation != EfiPciHotplugRequestRemove)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Operation == EfiPciHotPlugRequestAdd){
+ if (ChildHandleBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((Operation == EfiPciHotplugRequestRemove) && (*NumberOfChildren != 0)) {
+ if (ChildHandleBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Bridge = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
+
+ //
+ // Get root bridge handle
+ //
+ Temp = Bridge;
+ while (Temp->Parent != NULL) {
+ Temp = Temp->Parent;
+ }
+
+ RootBridgeHandle = Temp->Handle;
+
+ if (Operation == EfiPciHotPlugRequestAdd) {
+
+ if (NumberOfChildren != NULL) {
+ *NumberOfChildren = 0;
+ }
+
+ if (IsListEmpty (&Bridge->ChildList)) {
+
+ Status = PciBridgeEnumerator (Bridge);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = StartPciDevicesOnBridge (
+ RootBridgeHandle,
+ Bridge,
+ RemainingDevicePath,
+ NumberOfChildren,
+ ChildHandleBuffer
+ );
+
+ return Status;
+ }
+
+ if (Operation == EfiPciHotplugRequestRemove) {
+
+ if (*NumberOfChildren == 0) {
+ //
+ // Remove all devices on the bridge
+ //
+ RemoveAllPciDeviceOnBridge (RootBridgeHandle, Bridge);
+ return EFI_SUCCESS;
+
+ }
+
+ for (Index = 0; Index < *NumberOfChildren; Index++) {
+ //
+ // De register all the pci device
+ //
+ Status = DeRegisterPciDevice (RootBridgeHandle, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+ //
+ // End for
+ //
+ return EFI_SUCCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search hostbridge according to given handle
+
+ @param RootBridgeHandle Host bridge handle.
+
+ @retval TRUE Found host bridge handle.
+ @retval FALSE Not found hot bridge handle.
+
+**/
+BOOLEAN
+SearchHostBridgeHandle (
+ IN EFI_HANDLE RootBridgeHandle
+ )
+{
+ EFI_HANDLE HostBridgeHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ HostBridgeHandle = PciRootBridgeIo->ParentHandle;
+ for (Index = 0; Index < gPciHostBridgeNumber; Index++) {
+ if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Add host bridge handle to global variable for enumerating.
+
+ @param HostBridgeHandle Host bridge handle.
+
+ @retval EFI_SUCCESS Successfully added host bridge.
+ @retval EFI_ABORTED Host bridge is NULL, or given host bridge
+ has been in host bridge list.
+
+**/
+EFI_STATUS
+AddHostBridgeEnumerator (
+ IN EFI_HANDLE HostBridgeHandle
+ )
+{
+ UINTN Index;
+
+ if (HostBridgeHandle == NULL) {
+ return EFI_ABORTED;
+ }
+
+ for (Index = 0; Index < gPciHostBridgeNumber; Index++) {
+ if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {
+ return EFI_ABORTED;
+ }
+ }
+
+ if (Index < PCI_MAX_HOST_BRIDGE_NUM) {
+ gPciHostBrigeHandles[Index] = HostBridgeHandle;
+ gPciHostBridgeNumber++;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h
new file mode 100644
index 0000000000..3c0ca2fbfd
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h
@@ -0,0 +1,519 @@
+/** @file
+ PCI bus enumeration logic function declaration for PCI bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_ENUMERATOR_H_
+#define _EFI_PCI_ENUMERATOR_H_
+
+#include "PciResourceSupport.h"
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ @param Controller Parent controller handle.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumerator (
+ IN EFI_HANDLE Controller
+ );
+
+/**
+ Enumerate PCI root bridge.
+
+ @param PciResAlloc Pointer to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+ @param RootBridgeDev Instance of root bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated root bridge.
+ @retval other Failed to enumerate root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ );
+
+/**
+ This routine is used to process all PCI devices' Option Rom
+ on a certain root bridge.
+
+ @param Bridge Given parent's root bridge.
+ @param RomBase Base address of ROM driver loaded from.
+ @param MaxLength Maximum rom size.
+
+**/
+VOID
+ProcessOptionRom (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT64 RomBase,
+ IN UINT64 MaxLength
+ );
+
+/**
+ This routine is used to assign bus number to the given PCI bus system
+
+ @param Bridge Parent root bridge instance.
+ @param StartBusNumber Number of beginning.
+ @param SubBusNumber The number of sub bus.
+
+ @retval EFI_SUCCESS Successfully assigned bus number.
+ @retval EFI_DEVICE_ERROR Failed to assign bus number.
+
+**/
+EFI_STATUS
+PciAssignBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber
+ );
+
+/**
+ This routine is used to determine the root bridge attribute by interfacing
+ the host bridge resource allocation protocol.
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ @param RootBridgeDev Root bridge instance
+
+ @retval EFI_SUCCESS Successfully got root bridge's attribute.
+ @retval other Failed to get attribute.
+
+**/
+EFI_STATUS
+DetermineRootBridgeAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ );
+
+/**
+ Get Max Option Rom size on specified bridge.
+
+ @param Bridge Given bridge device instance.
+
+ @return Max size of option rom needed.
+
+**/
+UINT64
+GetMaxOptionRomSize (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Process attributes of devices on this host bridge
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully process attribute.
+ @retval EFI_NOT_FOUND Can not find the specific root bridge device.
+ @retval other Failed to determine the root bridge device's attribute.
+
+**/
+EFI_STATUS
+PciHostBridgeDeviceAttribute (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ Get resource allocation status from the ACPI resource descriptor.
+
+ @param AcpiConfig Point to Acpi configuration table.
+ @param IoResStatus Return the status of I/O resource.
+ @param Mem32ResStatus Return the status of 32-bit Memory resource.
+ @param PMem32ResStatus Return the status of 32-bit Prefetchable Memory resource.
+ @param Mem64ResStatus Return the status of 64-bit Memory resource.
+ @param PMem64ResStatus Return the status of 64-bit Prefetchable Memory resource.
+
+**/
+VOID
+GetResourceAllocationStatus (
+ VOID *AcpiConfig,
+ OUT UINT64 *IoResStatus,
+ OUT UINT64 *Mem32ResStatus,
+ OUT UINT64 *PMem32ResStatus,
+ OUT UINT64 *Mem64ResStatus,
+ OUT UINT64 *PMem64ResStatus
+ );
+
+/**
+ Remove a PCI device from device pool and mark its bar.
+
+ @param PciDevice Instance of Pci device.
+
+ @retval EFI_SUCCESS Successfully remove the PCI device.
+ @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge.
+
+**/
+EFI_STATUS
+RejectPciDevice (
+ IN PCI_IO_DEVICE *PciDevice
+ );
+
+/**
+ Determine whethter a PCI device can be rejected.
+
+ @param PciResNode Pointer to Pci resource node instance.
+
+ @retval TRUE The PCI device can be rejected.
+ @retval TRUE The PCI device cannot be rejected.
+
+**/
+BOOLEAN
+IsRejectiveDevice (
+ IN PCI_RESOURCE_NODE *PciResNode
+ );
+
+/**
+ Compare two resource nodes and get the larger resource consumer.
+
+ @param PciResNode1 resource node 1 want to be compared
+ @param PciResNode2 resource node 2 want to be compared
+
+ @return Larger resource node.
+
+**/
+PCI_RESOURCE_NODE *
+GetLargerConsumerDevice (
+ IN PCI_RESOURCE_NODE *PciResNode1,
+ IN PCI_RESOURCE_NODE *PciResNode2
+ );
+
+/**
+ Get the max resource consumer in the host resource pool.
+
+ @param ResPool Pointer to resource pool node.
+
+ @return The max resource consumer in the host resource pool.
+
+**/
+PCI_RESOURCE_NODE *
+GetMaxResourceConsumerDevice (
+ IN PCI_RESOURCE_NODE *ResPool
+ );
+
+/**
+ Adjust host bridge allocation so as to reduce resource requirement
+
+ @param IoPool Pointer to instance of I/O resource Node.
+ @param Mem32Pool Pointer to instance of 32-bit memory resource Node.
+ @param PMem32Pool Pointer to instance of 32-bit Prefetchable memory resource node.
+ @param Mem64Pool Pointer to instance of 64-bit memory resource node.
+ @param PMem64Pool Pointer to instance of 64-bit Prefetchable memory resource node.
+ @param IoResStatus Status of I/O resource Node.
+ @param Mem32ResStatus Status of 32-bit memory resource Node.
+ @param PMem32ResStatus Status of 32-bit Prefetchable memory resource node.
+ @param Mem64ResStatus Status of 64-bit memory resource node.
+ @param PMem64ResStatus Status of 64-bit Prefetchable memory resource node.
+
+ @retval EFI_SUCCESS Successfully adjusted resoruce on host bridge.
+ @retval EFI_ABORTED Host bridge hasn't this resource type or no resource be adjusted.
+
+**/
+EFI_STATUS
+PciHostBridgeAdjustAllocation (
+ IN PCI_RESOURCE_NODE *IoPool,
+ IN PCI_RESOURCE_NODE *Mem32Pool,
+ IN PCI_RESOURCE_NODE *PMem32Pool,
+ IN PCI_RESOURCE_NODE *Mem64Pool,
+ IN PCI_RESOURCE_NODE *PMem64Pool,
+ IN UINT64 IoResStatus,
+ IN UINT64 Mem32ResStatus,
+ IN UINT64 PMem32ResStatus,
+ IN UINT64 Mem64ResStatus,
+ IN UINT64 PMem64ResStatus
+ );
+
+/**
+ Summary requests for all resource type, and contruct ACPI resource
+ requestor instance.
+
+ @param Bridge detecting bridge
+ @param IoNode Pointer to instance of I/O resource Node
+ @param Mem32Node Pointer to instance of 32-bit memory resource Node
+ @param PMem32Node Pointer to instance of 32-bit Pmemory resource node
+ @param Mem64Node Pointer to instance of 64-bit memory resource node
+ @param PMem64Node Pointer to instance of 64-bit Pmemory resource node
+ @param Config Output buffer holding new constructed APCI resource requestor
+
+ @retval EFI_SUCCESS Successfully constructed ACPI resource.
+ @retval EFI_OUT_OF_RESOURCES No memory availabe.
+
+**/
+EFI_STATUS
+ConstructAcpiResourceRequestor (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node,
+ OUT VOID **Config
+ );
+
+/**
+ Get resource base from an acpi configuration descriptor.
+
+ @param Config An acpi configuration descriptor.
+ @param IoBase Output of I/O resource base address.
+ @param Mem32Base Output of 32-bit memory base address.
+ @param PMem32Base Output of 32-bit prefetchable memory base address.
+ @param Mem64Base Output of 64-bit memory base address.
+ @param PMem64Base Output of 64-bit prefetchable memory base address.
+
+**/
+VOID
+GetResourceBase (
+ IN VOID *Config,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ );
+
+/**
+ Enumerate pci bridge, allocate resource and determine attribute
+ for devices on this bridge.
+
+ @param BridgeDev Pointer to instance of bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated PCI bridge.
+ @retval other Failed to enumerate.
+
+**/
+EFI_STATUS
+PciBridgeEnumerator (
+ IN PCI_IO_DEVICE *BridgeDev
+ );
+
+/**
+ Allocate all kinds of resource for PCI bridge.
+
+ @param Bridge Pointer to bridge instance.
+
+ @retval EFI_SUCCESS Successfully allocated resource for PCI bridge.
+ @retval other Failed to allocate resource for bridge.
+
+**/
+EFI_STATUS
+PciBridgeResourceAllocator (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Get resource base address for a pci bridge device.
+
+ @param Bridge Given Pci driver instance.
+ @param IoBase Output for base address of I/O type resource.
+ @param Mem32Base Output for base address of 32-bit memory type resource.
+ @param PMem32Base Ooutput for base address of 32-bit Pmemory type resource.
+ @param Mem64Base Output for base address of 64-bit memory type resource.
+ @param PMem64Base Output for base address of 64-bit Pmemory type resource.
+
+ @retval EFI_SUCCESS Successfully got resource base address.
+ @retval EFI_OUT_OF_RESOURCES PCI bridge is not available.
+
+**/
+EFI_STATUS
+GetResourceBaseFromBridge (
+ IN PCI_IO_DEVICE *Bridge,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ );
+
+/**
+ Process Option Rom on this host bridge
+
+ @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_NOT_FOUND Can not find the root bridge instance.
+ @retval EFI_SUCCESS Success process.
+**/
+EFI_STATUS
+PciHostBridgeP2CProcess (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ 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] PciResAlloc 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
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+ 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 Bridge Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Bus The bus number of the pci device.
+ @param Device The device number of the pci device.
+ @param Func The function number of the pci device.
+ @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
+PreprocessController (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+ This function allows the PCI bus driver to be notified to act as requested when a hot-plug event has
+ happened on the hot-plug controller. Currently, the operations include add operation and remove operation..
+
+ @param This A pointer to the hot plug request protocol.
+ @param Operation The operation the PCI bus driver is requested to make.
+ @param Controller The handle of the hot-plug controller.
+ @param RemainingDevicePath The remaining device path for the PCI-like hot-plug device.
+ @param NumberOfChildren The number of child handles.
+ For a add operation, it is an output parameter.
+ For a remove operation, it's an input parameter.
+ @param ChildHandleBuffer The buffer which contains the child handles.
+
+ @retval EFI_INVALID_PARAMETER Operation is not a legal value.
+ Controller is NULL or not a valid handle.
+ NumberOfChildren is NULL.
+ ChildHandleBuffer is NULL while Operation is add.
+ @retval EFI_OUT_OF_RESOURCES There are no enough resources to start the devices.
+ @retval EFI_NOT_FOUND Can not find bridge according to controller handle.
+ @retval EFI_SUCCESS The handles for the specified device have been created or destroyed
+ as requested, and for an add operation, the new handles are
+ returned in ChildHandleBuffer.
+**/
+EFI_STATUS
+EFIAPI
+PciHotPlugRequestNotify (
+ IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL * This,
+ IN EFI_PCI_HOTPLUG_OPERATION Operation,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE * ChildHandleBuffer
+ );
+
+/**
+ Search hostbridge according to given handle
+
+ @param RootBridgeHandle Host bridge handle.
+
+ @retval TRUE Found host bridge handle.
+ @retval FALSE Not found hot bridge handle.
+
+**/
+BOOLEAN
+SearchHostBridgeHandle (
+ IN EFI_HANDLE RootBridgeHandle
+ );
+
+/**
+ Add host bridge handle to global variable for enumerating.
+
+ @param HostBridgeHandle Host bridge handle.
+
+ @retval EFI_SUCCESS Successfully added host bridge.
+ @retval EFI_ABORTED Host bridge is NULL, or given host bridge
+ has been in host bridge list.
+
+**/
+EFI_STATUS
+AddHostBridgeEnumerator (
+ IN EFI_HANDLE HostBridgeHandle
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
new file mode 100644
index 0000000000..8f3ed5eb37
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
@@ -0,0 +1,2494 @@
+/** @file
+ PCI emumeration support functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+/**
+ This routine is used to check whether the pci device is present.
+
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pci Output buffer for PCI device configuration space.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI Func NO.
+
+ @retval EFI_NOT_FOUND PCI device not present.
+ @retval EFI_SUCCESS PCI device is found.
+
+**/
+EFI_STATUS
+PciDevicePresent (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ OUT PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ UINT64 Address;
+ EFI_STATUS Status;
+
+ //
+ // Create PCI address map in terms of Bus, Device and Func
+ //
+ Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
+
+ //
+ // Read the Vendor ID register
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ Pci
+ );
+
+ if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {
+ //
+ // Read the entire config header for the device
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ sizeof (PCI_TYPE00) / sizeof (UINT32),
+ Pci
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Collect all the resource information under this root bridge.
+
+ A database that records all the information about pci device subject to this
+ root bridge will then be created.
+
+ @param Bridge Parent bridge instance.
+ @param StartBusNumber Bus number of begining.
+
+ @retval EFI_SUCCESS PCI device is found.
+ @retval other Some error occurred when reading PCI bridge information.
+
+**/
+EFI_STATUS
+PciPciDeviceInfoCollector (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT8 Func;
+ UINT8 SecBus;
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ Status = EFI_SUCCESS;
+ SecBus = 0;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether PCI device is present
+ //
+ Status = PciDevicePresent (
+ Bridge->PciRootBridgeIo,
+ &Pci,
+ (UINT8) StartBusNumber,
+ (UINT8) Device,
+ (UINT8) Func
+ );
+ if (!EFI_ERROR (Status)) {
+
+ //
+ // Call back to host bridge function
+ //
+ PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);
+
+ //
+ // Collect all the information about the PCI device discovered
+ //
+ Status = PciSearchDevice (
+ Bridge,
+ &Pci,
+ (UINT8) StartBusNumber,
+ Device,
+ Func,
+ &PciIoDevice
+ );
+
+ //
+ // Recursively scan PCI busses on the other side of PCI-PCI bridges
+ //
+ //
+ if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
+
+ //
+ // If it is PPB, we need to get the secondary bus to continue the enumeration
+ //
+ PciIo = &(PciIoDevice->PciIo);
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get resource padding for PPB
+ //
+ GetResourcePaddingPpb (PciIoDevice);
+
+ //
+ // Deep enumerate the next level bus
+ //
+ Status = PciPciDeviceInfoCollector (
+ PciIoDevice,
+ (UINT8) (SecBus)
+ );
+
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Seach required device and create PCI device instance.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI func NO.
+ @param PciDevice Output of searched PCI device instance.
+
+ @retval EFI_SUCCESS Successfully created PCI device instance.
+ @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
+
+**/
+EFI_STATUS
+PciSearchDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ OUT PCI_IO_DEVICE **PciDevice
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = NULL;
+
+ if (!IS_PCI_BRIDGE (Pci)) {
+
+ if (IS_CARDBUS_BRIDGE (Pci)) {
+ PciIoDevice = GatherP2CInfo (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+ if ((PciIoDevice != NULL) && gFullEnumeration) {
+ InitializeP2C (PciIoDevice);
+ }
+ } else {
+
+ //
+ // Create private data for Pci Device
+ //
+ PciIoDevice = GatherDeviceInfo (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ }
+
+ } else {
+
+ //
+ // Create private data for PPB
+ //
+ PciIoDevice = GatherPpbInfo (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ //
+ // Special initialization for PPB including making the PPB quiet
+ //
+ if ((PciIoDevice != NULL) && gFullEnumeration) {
+ InitializePpb (PciIoDevice);
+ }
+ }
+
+ if (PciIoDevice == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Update the bar information for this PCI device so as to support some specific device
+ //
+ UpdatePciInfo (PciIoDevice);
+
+ if (PciIoDevice->DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Detect this function has option rom
+ //
+ if (gFullEnumeration) {
+
+ if (!IS_CARDBUS_BRIDGE (Pci)) {
+
+ GetOpRomInfo (PciIoDevice);
+
+ }
+
+ ResetPowerManagementFeature (PciIoDevice);
+
+ }
+
+ //
+ // Insert it into a global tree for future reference
+ //
+ InsertPciDevice (Bridge, PciIoDevice);
+
+ //
+ // Determine PCI device attributes
+ //
+
+ if (PciDevice != NULL) {
+ *PciDevice = PciIoDevice;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create PCI device instance for PCI device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherDeviceInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ UINTN Offset;
+ UINTN BarIndex;
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+ PciIoDevice = CreatePciIoDevice (
+ PciRootBridgeIo,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ //
+ // Create a device path for this PCI device and store it into its private data
+ //
+ CreatePciDevicePath (
+ Bridge->DevicePath,
+ PciIoDevice
+ );
+
+ //
+ // If it is a full enumeration, disconnect the device in advance
+ //
+ if (gFullEnumeration) {
+
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
+
+ }
+
+ //
+ // Start to parse the bars
+ //
+ for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {
+ Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
+ }
+
+ //
+ // Parse the SR-IOV VF bars
+ //
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
+ for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;
+ Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;
+ BarIndex++) {
+
+ ASSERT (BarIndex < PCI_MAX_BAR);
+ Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);
+ }
+ }
+ return PciIoDevice;
+}
+
+/**
+ Create PCI device instance for PCI-PCI bridge.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherPpbInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_STATUS Status;
+ UINT8 Value;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Temp;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+ PciIoDevice = CreatePciIoDevice (
+ PciRootBridgeIo,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ //
+ // Create a device path for this PCI device and store it into its private data
+ //
+ CreatePciDevicePath (
+ Bridge->DevicePath,
+ PciIoDevice
+ );
+
+ if (gFullEnumeration) {
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
+
+ //
+ // Initalize the bridge control register
+ //
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
+
+ }
+
+ //
+ // PPB can have two BARs
+ //
+ if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
+ //
+ // Not 64-bit bar
+ //
+ PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
+ }
+
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Test whether it support 32 decode or not
+ //
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
+
+ if (Value != 0) {
+ if ((Value & 0x01) != 0) {
+ PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
+ } else {
+ PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
+ }
+ }
+
+ Status = BarExisted (
+ PciIoDevice,
+ 0x24,
+ NULL,
+ NULL
+ );
+
+ //
+ // Test if it supports 64 memory or not
+ //
+ if (!EFI_ERROR (Status)) {
+
+ Status = BarExisted (
+ PciIoDevice,
+ 0x28,
+ NULL,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
+ } else {
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
+ }
+ }
+
+ //
+ // Memory 32 code is required for ppb
+ //
+ PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
+
+ GetResourcePaddingPpb (PciIoDevice);
+
+ return PciIoDevice;
+}
+
+
+/**
+ Create PCI device instance for PCI Card bridge device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherP2CInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+ PciIoDevice = CreatePciIoDevice (
+ PciRootBridgeIo,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ //
+ // Create a device path for this PCI device and store it into its private data
+ //
+ CreatePciDevicePath (
+ Bridge->DevicePath,
+ PciIoDevice
+ );
+
+ if (gFullEnumeration) {
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
+
+ //
+ // Initalize the bridge control register
+ //
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
+ }
+
+ //
+ // P2C only has one bar that is in 0x10
+ //
+ PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
+
+ //
+ // Read PciBar information from the bar register
+ //
+ GetBackPcCardBar (PciIoDevice);
+ PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |
+ EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
+ EFI_BRIDGE_IO32_DECODE_SUPPORTED;
+
+ return PciIoDevice;
+}
+
+/**
+ Create device path for pci deivce.
+
+ @param ParentDevicePath Parent bridge's path.
+ @param PciIoDevice Pci device instance.
+
+ @return Device path protocol instance for specific pci device.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CreatePciDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+
+ PCI_DEVICE_PATH PciNode;
+
+ //
+ // Create PCI device path
+ //
+ PciNode.Header.Type = HARDWARE_DEVICE_PATH;
+ PciNode.Header.SubType = HW_PCI_DP;
+ SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
+
+ PciNode.Device = PciIoDevice->DeviceNumber;
+ PciNode.Function = PciIoDevice->FunctionNumber;
+ PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);
+
+ return PciIoDevice->DevicePath;
+}
+
+/**
+ Check whether the PCI IOV VF bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+VfBarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 OriginalValue;
+ UINT32 Value;
+ EFI_TPL OldTpl;
+
+ //
+ // Ensure it is called properly
+ //
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Preserve the original value
+ //
+
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);
+
+ //
+ // Write back the original value
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ if (BarLengthValue != NULL) {
+ *BarLengthValue = Value;
+ }
+
+ if (OriginalBarValue != NULL) {
+ *OriginalBarValue = OriginalValue;
+ }
+
+ if (Value == 0) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Check whether the bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+BarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 OriginalValue;
+ UINT32 Value;
+ EFI_TPL OldTpl;
+
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Preserve the original value
+ //
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);
+
+ //
+ // Write back the original value
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ if (BarLengthValue != NULL) {
+ *BarLengthValue = Value;
+ }
+
+ if (OriginalBarValue != NULL) {
+ *OriginalBarValue = OriginalValue;
+ }
+
+ if (Value == 0) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Test whether the device can support given attributes.
+
+ @param PciIoDevice Pci device instance.
+ @param Command Input command register value, and
+ returned supported register value.
+ @param BridgeControl Inout bridge control value for PPB or P2C, and
+ returned supported bridge control value.
+ @param OldCommand Returned and stored old command register offset.
+ @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
+
+**/
+VOID
+PciTestSupportedAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN OUT UINT16 *Command,
+ IN OUT UINT16 *BridgeControl,
+ OUT UINT16 *OldCommand,
+ OUT UINT16 *OldBridgeControl
+ )
+{
+ EFI_TPL OldTpl;
+
+ //
+ // Preserve the original value
+ //
+ PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);
+ PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);
+
+ //
+ // Write back the original value
+ //
+ PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+
+ //
+ // Preserve the original value
+ //
+ PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
+ PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
+
+ //
+ // Write back the original value
+ //
+ PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ } else {
+ *OldBridgeControl = 0;
+ *BridgeControl = 0;
+ }
+}
+
+/**
+ Set the supported or current attributes of a PCI device.
+
+ @param PciIoDevice Structure pointer for PCI device.
+ @param Command Command register value.
+ @param BridgeControl Bridge control value for PPB or P2C.
+ @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
+
+**/
+VOID
+PciSetDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT16 BridgeControl,
+ IN UINTN Option
+ )
+{
+ UINT64 Attributes;
+
+ Attributes = 0;
+
+ if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
+ }
+
+ if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
+ }
+
+ if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
+ }
+
+ if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
+ }
+
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
+ }
+
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
+ }
+
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
+ }
+
+ if (Option == EFI_SET_SUPPORTS) {
+
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
+ }
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+ //
+ // For bridge, it should support IDE attributes
+ //
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
+ } else {
+
+ if (IS_PCI_IDE (&PciIoDevice->Pci)) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
+ }
+
+ if (IS_PCI_VGA (&PciIoDevice->Pci)) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
+ }
+ }
+
+ PciIoDevice->Supports = Attributes;
+ PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
+ EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
+ EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
+
+ } else {
+ PciIoDevice->Attributes = Attributes;
+ }
+}
+
+/**
+ Determine if the device can support Fast Back to Back attribute.
+
+ @param PciIoDevice Pci device instance.
+ @param StatusIndex Status register value.
+
+ @retval EFI_SUCCESS This device support Fast Back to Back attribute.
+ @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
+
+**/
+EFI_STATUS
+GetFastBackToBackSupport (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 StatusIndex
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT32 StatusRegister;
+
+ //
+ // Read the status register
+ //
+ PciIo = &PciIoDevice->PciIo;
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check the Fast B2B bit
+ //
+ if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ Process the option ROM for all the children of the specified parent PCI device.
+ It can only be used after the first full Option ROM process.
+
+ @param PciIoDevice Pci device instance.
+
+**/
+VOID
+ProcessOptionRomLight (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ //
+ // For RootBridge, PPB , P2C, go recursively to traverse all its children
+ //
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ ProcessOptionRomLight (Temp);
+ }
+
+ PciRomGetImageMapping (Temp);
+
+ //
+ // The OpRom has already been processed in the first round
+ //
+ Temp->AllOpRomProcessed = TRUE;
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ Determine the related attributes of all devices under a Root Bridge.
+
+ @param PciIoDevice PCI device instance.
+
+**/
+EFI_STATUS
+DetermineDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT16 Command;
+ UINT16 BridgeControl;
+ UINT16 OldCommand;
+ UINT16 OldBridgeControl;
+ BOOLEAN FastB2BSupport;
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+ EFI_STATUS Status;
+
+ //
+ // For Root Bridge, just copy it by RootBridgeIo proctocol
+ // so as to keep consistent with the actual attribute
+ //
+ if (PciIoDevice->Parent == NULL) {
+ Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
+ PciIoDevice->PciRootBridgeIo,
+ &PciIoDevice->Supports,
+ &PciIoDevice->Attributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+
+ //
+ // Set the attributes to be checked for common PCI devices and PPB or P2C
+ // Since some devices only support part of them, it is better to set the
+ // attribute according to its command or bridge control register
+ //
+ Command = EFI_PCI_COMMAND_IO_SPACE |
+ EFI_PCI_COMMAND_MEMORY_SPACE |
+ EFI_PCI_COMMAND_BUS_MASTER |
+ EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
+
+ BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
+
+ //
+ // Test whether the device can support attributes above
+ //
+ PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
+
+ //
+ // Set the supported attributes for specified PCI device
+ //
+ PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
+
+ //
+ // Set the current attributes for specified PCI device
+ //
+ PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
+
+ //
+ // Enable other supported attributes but not defined in PCI_IO_PROTOCOL
+ //
+ PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
+ }
+
+ FastB2BSupport = TRUE;
+
+ //
+ // P2C can not support FB2B on the secondary side
+ //
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+ FastB2BSupport = FALSE;
+ }
+
+ //
+ // For RootBridge, PPB , P2C, go recursively to traverse all its children
+ //
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ Status = DetermineDeviceAttribute (Temp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Detect Fast Bact to Bact support for the device under the bridge
+ //
+ Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
+ if (FastB2BSupport && EFI_ERROR (Status)) {
+ FastB2BSupport = FALSE;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ //
+ // Set or clear Fast Back to Back bit for the whole bridge
+ //
+ if (!IsListEmpty (&PciIoDevice->ChildList)) {
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+
+ Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
+
+ if (EFI_ERROR (Status) || (!FastB2BSupport)) {
+ FastB2BSupport = FALSE;
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
+ } else {
+ PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
+ }
+ }
+
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (FastB2BSupport) {
+ PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
+ } else {
+ PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ }
+ //
+ // End for IsListEmpty
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is used to update the bar information for those incompatible PCI device.
+
+ @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
+ Bar information.
+
+ @retval EFI_SUCCESS Successfully updated bar information.
+ @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
+
+**/
+EFI_STATUS
+UpdatePciInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ UINTN BarIndex;
+ UINTN BarEndIndex;
+ BOOLEAN SetFlag;
+ VOID *Configuration;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+
+ Configuration = NULL;
+ Status = EFI_SUCCESS;
+
+ if (gEfiIncompatiblePciDeviceSupport == NULL) {
+ //
+ // It can only be supported after the Incompatible PCI Device
+ // Support Protocol has been installed
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiIncompatiblePciDeviceSupportProtocolGuid,
+ NULL,
+ (VOID **) &gEfiIncompatiblePciDeviceSupport
+ );
+ }
+ if (Status == EFI_SUCCESS) {
+ //
+ // Check whether the device belongs to incompatible devices from protocol or not
+ // If it is , then get its special requirement in the ACPI table
+ //
+ Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (
+ gEfiIncompatiblePciDeviceSupport,
+ PciIoDevice->Pci.Hdr.VendorId,
+ PciIoDevice->Pci.Hdr.DeviceId,
+ PciIoDevice->Pci.Hdr.RevisionID,
+ PciIoDevice->Pci.Device.SubsystemVendorID,
+ PciIoDevice->Pci.Device.SubsystemID,
+ &Configuration
+ );
+
+ }
+
+ if (EFI_ERROR (Status) || Configuration == NULL ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Update PCI device information from the ACPI table
+ //
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+
+ while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
+
+ if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ //
+ // The format is not support
+ //
+ break;
+ }
+
+ BarIndex = (UINTN) Ptr->AddrTranslationOffset;
+ BarEndIndex = BarIndex;
+
+ //
+ // Update all the bars in the device
+ //
+ if (BarIndex == PCI_BAR_ALL) {
+ BarIndex = 0;
+ BarEndIndex = PCI_MAX_BAR - 1;
+ }
+
+ if (BarIndex > PCI_MAX_BAR) {
+ Ptr++;
+ continue;
+ }
+
+ for (; BarIndex <= BarEndIndex; BarIndex++) {
+ SetFlag = FALSE;
+ switch (Ptr->ResType) {
+ case ACPI_ADDRESS_SPACE_TYPE_MEM:
+
+ //
+ // Make sure the bar is memory type
+ //
+ if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
+ SetFlag = TRUE;
+ }
+ break;
+
+ case ACPI_ADDRESS_SPACE_TYPE_IO:
+
+ //
+ // Make sure the bar is IO type
+ //
+ if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
+ SetFlag = TRUE;
+ }
+ break;
+ }
+
+ if (SetFlag) {
+
+ //
+ // Update the new alignment for the device
+ //
+ SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
+
+ //
+ // Update the new length for the device
+ //
+ if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {
+ PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
+ }
+ }
+ }
+
+ Ptr++;
+ }
+
+ FreePool (Configuration);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine will update the alignment with the new alignment.
+
+ @param Alignment Input Old alignment. Output updated alignment.
+ @param NewAlignment New alignment.
+
+**/
+VOID
+SetNewAlign (
+ IN OUT UINT64 *Alignment,
+ IN UINT64 NewAlignment
+ )
+{
+ UINT64 OldAlignment;
+ UINTN ShiftBit;
+
+ //
+ // The new alignment is the same as the original,
+ // so skip it
+ //
+ if (NewAlignment == PCI_BAR_OLD_ALIGN) {
+ return ;
+ }
+ //
+ // Check the validity of the parameter
+ //
+ if (NewAlignment != PCI_BAR_EVEN_ALIGN &&
+ NewAlignment != PCI_BAR_SQUAD_ALIGN &&
+ NewAlignment != PCI_BAR_DQUAD_ALIGN ) {
+ *Alignment = NewAlignment;
+ return ;
+ }
+
+ OldAlignment = (*Alignment) + 1;
+ ShiftBit = 0;
+
+ //
+ // Get the first non-zero hex value of the length
+ //
+ while ((OldAlignment & 0x0F) == 0x00) {
+ OldAlignment = RShiftU64 (OldAlignment, 4);
+ ShiftBit += 4;
+ }
+
+ //
+ // Adjust the alignment to even, quad or double quad boundary
+ //
+ if (NewAlignment == PCI_BAR_EVEN_ALIGN) {
+ if ((OldAlignment & 0x01) != 0) {
+ OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
+ }
+ } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {
+ if ((OldAlignment & 0x03) != 0) {
+ OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
+ }
+ } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {
+ if ((OldAlignment & 0x07) != 0) {
+ OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
+ }
+ }
+
+ //
+ // Update the old value
+ //
+ NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
+ *Alignment = NewAlignment;
+
+ return ;
+}
+
+/**
+ Parse PCI IOV VF bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciIovParseVfBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ )
+{
+ UINT32 Value;
+ UINT32 OriginalValue;
+ UINT32 Mask;
+ UINT32 Data;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ //
+ // Ensure it is called properly
+ //
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {
+ return 0;
+ }
+
+ OriginalValue = 0;
+ Value = 0;
+
+ Status = VfBarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->VfPciBar[BarIndex].Length = 0;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
+
+ //
+ // Scan all the BARs anyway
+ //
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;
+ return Offset + 4;
+ }
+
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;
+ if (Value & 0x01) {
+ //
+ // Device I/Os. Impossible
+ //
+ ASSERT (FALSE);
+ return Offset + 4;
+
+ } else {
+
+ Mask = 0xfffffff0;
+
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;
+
+ switch (Value & 0x07) {
+
+ //
+ //memory space; anywhere in 32 bit address space
+ //
+ case 0x00:
+ if (Value & 0x08) {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;
+ } else {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;
+ }
+
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ //
+ // Adjust Length
+ //
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
+ //
+ // Adjust Alignment
+ //
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ break;
+
+ //
+ // memory space; anywhere in 64 bit address space
+ //
+ case 0x04:
+ if (Value & 0x08) {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;
+ } else {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;
+ }
+
+ //
+ // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
+ // is regarded as an extension for the first bar. As a result
+ // the sizing will be conducted on combined 64 bit value
+ // Here just store the masked first 32bit value for future size
+ // calculation
+ //
+ PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ //
+ // Increment the offset to point to next DWORD
+ //
+ Offset += 4;
+
+ Status = VfBarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Offset + 4;
+ }
+
+ //
+ // Fix the length to support some spefic 64 bit BAR
+ //
+ Data = Value;
+ Index = 0;
+ for (Data = Value; Data != 0; Data >>= 1) {
+ Index ++;
+ }
+ Value |= ((UINT32)(-1) << Index);
+
+ //
+ // Calculate the size of 64bit bar
+ //
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
+
+ PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ //
+ // Adjust Length
+ //
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
+ //
+ // Adjust Alignment
+ //
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ break;
+
+ //
+ // reserved
+ //
+ default:
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ break;
+ }
+ }
+
+ //
+ // Check the length again so as to keep compatible with some special bars
+ //
+ if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
+ }
+
+ //
+ // Increment number of bar
+ //
+ return Offset + 4;
+}
+
+/**
+ Parse PCI bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciParseBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ )
+{
+ UINT32 Value;
+ UINT32 OriginalValue;
+ UINT32 Mask;
+ UINT32 Data;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ OriginalValue = 0;
+ Value = 0;
+
+ Status = BarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->PciBar[BarIndex].Length = 0;
+ PciIoDevice->PciBar[BarIndex].Alignment = 0;
+
+ //
+ // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
+ //
+ PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
+ return Offset + 4;
+ }
+
+ PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
+ if ((Value & 0x01) != 0) {
+ //
+ // Device I/Os
+ //
+ Mask = 0xfffffffc;
+
+ if ((Value & 0xFFFF0000) != 0) {
+ //
+ // It is a IO32 bar
+ //
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
+ PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+
+ } else {
+ //
+ // It is a IO16 bar
+ //
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
+ PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+
+ }
+ //
+ // Workaround. Some platforms inplement IO bar with 0 length
+ // Need to treat it as no-bar
+ //
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;
+ }
+
+ PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;
+ PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
+
+ } else {
+
+ Mask = 0xfffffff0;
+
+ PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
+
+ switch (Value & 0x07) {
+
+ //
+ //memory space; anywhere in 32 bit address space
+ //
+ case 0x00:
+ if ((Value & 0x08) != 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
+ } else {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
+ }
+
+ PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
+ //
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
+ //
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
+ } else {
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+ }
+ break;
+
+ //
+ // memory space; anywhere in 64 bit address space
+ //
+ case 0x04:
+ if ((Value & 0x08) != 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
+ } else {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
+ }
+
+ //
+ // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
+ // is regarded as an extension for the first bar. As a result
+ // the sizing will be conducted on combined 64 bit value
+ // Here just store the masked first 32bit value for future size
+ // calculation
+ //
+ PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+
+ //
+ // Increment the offset to point to next DWORD
+ //
+ Offset += 4;
+
+ Status = BarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
+ //
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {
+ //
+ // some device implement MMIO bar with 0 length, need to treat it as no-bar
+ //
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
+ }
+ return Offset + 4;
+ }
+
+ //
+ // Fix the length to support some spefic 64 bit BAR
+ //
+ Data = Value;
+ Index = 0;
+ for (Data = Value; Data != 0; Data >>= 1) {
+ Index ++;
+ }
+ Value |= ((UINT32)(-1) << Index);
+
+ //
+ // Calculate the size of 64bit bar
+ //
+ PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
+
+ PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
+ PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
+ //
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
+ //
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
+ } else {
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+ }
+
+ break;
+
+ //
+ // reserved
+ //
+ default:
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
+ //
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
+ //
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
+ } else {
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+ }
+ break;
+ }
+ }
+
+ //
+ // Check the length again so as to keep compatible with some special bars
+ //
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->PciBar[BarIndex].Alignment = 0;
+ }
+
+ //
+ // Increment number of bar
+ //
+ return Offset + 4;
+}
+
+/**
+ This routine is used to initialize the bar of a PCI device.
+
+ @param PciIoDevice Pci device instance.
+
+ @note It can be called typically when a device is going to be rejected.
+
+**/
+VOID
+InitializePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Offset;
+
+ PciIo = &(PciIoDevice->PciIo);
+
+ //
+ // Put all the resource apertures
+ // Resource base is set to all ones so as to indicate its resource
+ // has not been alloacted
+ //
+ for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
+ }
+}
+
+/**
+ This routine is used to initialize the bar of a PCI-PCI Bridge device.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+**/
+VOID
+InitializePpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = &(PciIoDevice->PciIo);
+
+ //
+ // Put all the resource apertures including IO16
+ // Io32, pMem32, pMem64 to quiescent state
+ // Resource base all ones, Resource limit all zeros
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
+
+ //
+ // Don't support use io32 as for now
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
+
+ //
+ // Force Interrupt line to zero for cards that come up randomly
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
+}
+
+/**
+ This routine is used to initialize the bar of a PCI Card Bridge device.
+
+ @param PciIoDevice PCI Card bridge device.
+
+**/
+VOID
+InitializeP2C (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = &(PciIoDevice->PciIo);
+
+ //
+ // Put all the resource apertures including IO16
+ // Io32, pMem32, pMem64 to quiescent state(
+ // Resource base all ones, Resource limit all zeros
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
+
+ //
+ // Force Interrupt line to zero for cards that come up randomly
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
+}
+
+/**
+ Create and initiliaze general PCI I/O device instance for
+ PCI device/bridge device/hotplug bridge device.
+
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pci Input Pci information block.
+ @param Bus Device Bus NO.
+ @param Device Device device NO.
+ @param Func Device func NO.
+
+ @return Instance of PCI device. NULL means no instance created.
+
+**/
+PCI_IO_DEVICE *
+CreatePciIoDevice (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
+ PciIoDevice->Handle = NULL;
+ PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;
+ PciIoDevice->DevicePath = NULL;
+ PciIoDevice->BusNumber = Bus;
+ PciIoDevice->DeviceNumber = Device;
+ PciIoDevice->FunctionNumber = Func;
+ PciIoDevice->Decodes = 0;
+
+ if (gFullEnumeration) {
+ PciIoDevice->Allocated = FALSE;
+ } else {
+ PciIoDevice->Allocated = TRUE;
+ }
+
+ PciIoDevice->Registered = FALSE;
+ PciIoDevice->Attributes = 0;
+ PciIoDevice->Supports = 0;
+ PciIoDevice->BusOverride = FALSE;
+ PciIoDevice->AllOpRomProcessed = FALSE;
+
+ PciIoDevice->IsPciExp = FALSE;
+
+ CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
+
+ //
+ // Initialize the PCI I/O instance structure
+ //
+ InitializePciIoInstance (PciIoDevice);
+ InitializePciDriverOverrideInstance (PciIoDevice);
+ InitializePciLoadFile2 (PciIoDevice);
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Detect if PCI Express Device
+ //
+ PciIoDevice->PciExpressCapabilityOffset = 0;
+ Status = LocateCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCI_CAPABILITY_ID_PCIEXP,
+ &PciIoDevice->PciExpressCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->IsPciExp = TRUE;
+ }
+
+ //
+ // Initialize for PCI IOV
+ //
+
+ //
+ // Check ARI for function 0 only
+ //
+ Status = LocatePciExpressCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCIE_CAPABILITY_ID_ARI,
+ &PciIoDevice->AriCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "PCI-IOV B%x.D%x.F%x - ARI Cap offset - 0x%x\n",
+ (UINTN)Bus,
+ (UINTN)Device,
+ (UINTN)Func,
+ (UINTN)PciIoDevice->AriCapabilityOffset
+ ));
+ }
+
+ Status = LocatePciExpressCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCIE_CAPABILITY_ID_SRIOV,
+ &PciIoDevice->SrIovCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "PCI-IOV B%x.D%x.F%x - SRIOV Cap offset - 0x%x\n",
+ (UINTN)Bus,
+ (UINTN)Device,
+ (UINTN)Func,
+ (UINTN)PciIoDevice->SrIovCapabilityOffset
+ ));
+ }
+
+ Status = LocatePciExpressCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCIE_CAPABILITY_ID_MRIOV,
+ &PciIoDevice->MrIovCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "PCI-IOV B%x.D%x.F%x - MRIOV Cap offset - 0x%x\n",
+ (UINTN)Bus,
+ (UINTN)Device,
+ (UINTN)Func,
+ (UINTN)PciIoDevice->MrIovCapabilityOffset
+ ));
+ }
+
+ //
+ // Calculate SystemPageSize
+ //
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
+ 1,
+ &PciIoDevice->SystemPageSize
+ );
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SupportedPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));
+
+ PciIoDevice->SystemPageSize = (PcdGet32(PcdSrIovSystemPageSize) & PciIoDevice->SystemPageSize);
+ ASSERT (PciIoDevice->SystemPageSize != 0);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
+ 1,
+ &PciIoDevice->SystemPageSize
+ );
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SystemPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));
+ //
+ // Adjust SystemPageSize for Alignment usage later
+ //
+ PciIoDevice->SystemPageSize <<= 12;
+ }
+
+ // Calculate BusReservation for PCI IOV
+ //
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
+ UINT16 VFStride;
+ UINT16 FirstVFOffset;
+ UINT32 PFRID;
+ UINT32 LastVF;
+
+ //
+ // Read First FirstVFOffset, InitialVFs, and VFStride
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
+ 1,
+ &FirstVFOffset
+ );
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - FirstVFOffset - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)FirstVFOffset));
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
+ 1,
+ &PciIoDevice->InitialVFs
+ );
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - InitialVFs - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)PciIoDevice->InitialVFs));
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
+ 1,
+ &VFStride
+ );
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - VFStride - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)VFStride));
+
+ //
+ // Calculate LastVF
+ //
+ PFRID = EFI_PCI_RID(Bus, Device, Func);
+ LastVF = PFRID + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
+
+ //
+ // Calculate ReservedBusNum for this PF
+ //
+ PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - reserved bus number - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)PciIoDevice->ReservedBusNum));
+ }
+
+
+ //
+ // Initialize the reserved resource list
+ //
+ InitializeListHead (&PciIoDevice->ReservedResourceList);
+
+ //
+ // Initialize the driver list
+ //
+ InitializeListHead (&PciIoDevice->OptionRomDriverList);
+
+ //
+ // Initialize the child list
+ //
+ InitializeListHead (&PciIoDevice->ChildList);
+
+ return PciIoDevice;
+}
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ It is only called on the second start on the same Root Bridge.
+
+ @param Controller Parent bridge handler.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumeratorLight (
+ IN EFI_HANDLE Controller
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ PCI_IO_DEVICE *RootBridgeDev;
+ UINT16 MinBus;
+ UINT16 MaxBus;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+
+ MinBus = 0;
+ MaxBus = PCI_MAX_BUS;
+ Descriptors = NULL;
+
+ //
+ // If this root bridge has been already enumerated, then return successfully
+ //
+ if (GetRootBridgeByHandle (Controller) != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Open pci root bridge io protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
+
+ //
+ // Create a device node for root bridge device with a NULL host bridge controller handle
+ //
+ RootBridgeDev = CreateRootBridge (Controller);
+
+ if (RootBridgeDev == NULL) {
+ Descriptors++;
+ continue;
+ }
+
+ //
+ // Record the root bridgeio protocol
+ //
+ RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
+
+ Status = PciPciDeviceInfoCollector (
+ RootBridgeDev,
+ (UINT8) MinBus
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ //
+ // Remove those PCI devices which are rejected when full enumeration
+ //
+ RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
+
+ //
+ // Process option rom light
+ //
+ ProcessOptionRomLight (RootBridgeDev);
+
+ //
+ // Determine attributes for all devices under this root bridge
+ //
+ DetermineDeviceAttribute (RootBridgeDev);
+
+ //
+ // If successfully, insert the node into device pool
+ //
+ InsertRootBridge (RootBridgeDev);
+ } else {
+
+ //
+ // If unsuccessly, destroy the entire node
+ //
+ DestroyRootBridge (RootBridgeDev);
+ }
+
+ Descriptors++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get bus range from PCI resource descriptor list.
+
+ @param Descriptors A pointer to the address space descriptor.
+ @param MinBus The min bus returned.
+ @param MaxBus The max bus returned.
+ @param BusRange The bus range returned.
+
+ @retval EFI_SUCCESS Successfully got bus range.
+ @retval EFI_NOT_FOUND Can not find the specific bus.
+
+**/
+EFI_STATUS
+PciGetBusRange (
+ IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
+ OUT UINT16 *MinBus,
+ OUT UINT16 *MaxBus,
+ OUT UINT16 *BusRange
+ )
+{
+ while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ if (MinBus != NULL) {
+ *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
+ }
+
+ if (MaxBus != NULL) {
+ *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
+ }
+
+ if (BusRange != NULL) {
+ *BusRange = (UINT16) (*Descriptors)->AddrLen;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ (*Descriptors)++;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This routine can be used to start the root bridge.
+
+ @param RootBridgeDev Pci device instance.
+
+ @retval EFI_SUCCESS This device started.
+ @retval other Failed to get PCI Root Bridge I/O protocol.
+
+**/
+EFI_STATUS
+StartManagingRootBridge (
+ IN PCI_IO_DEVICE *RootBridgeDev
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ //
+ // Get the root bridge handle
+ //
+ RootBridgeHandle = RootBridgeDev->Handle;
+ PciRootBridgeIo = NULL;
+
+ //
+ // Get the pci root bridge io protocol
+ //
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ //
+ // Store the PciRootBridgeIo protocol into root bridge private data
+ //
+ RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ This routine can be used to check whether a PCI device should be rejected when light enumeration.
+
+ @param PciIoDevice Pci device instance.
+
+ @retval TRUE This device should be rejected.
+ @retval FALSE This device shouldn't be rejected.
+
+**/
+BOOLEAN
+IsPciDeviceRejected (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TestValue;
+ UINT32 OldValue;
+ UINT32 Mask;
+ UINT8 BarOffset;
+
+ //
+ // PPB should be skip!
+ //
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+ return FALSE;
+ }
+
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+ //
+ // Only test base registers for P2C
+ //
+ for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
+
+ Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ TestValue = TestValue & Mask;
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+ //
+ // The bar isn't programed, so it should be rejected
+ //
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
+ //
+ // Test PCI devices
+ //
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((TestValue & 0x01) != 0) {
+
+ //
+ // IO Bar
+ //
+ Mask = 0xFFFFFFFC;
+ TestValue = TestValue & Mask;
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+ return TRUE;
+ }
+
+ } else {
+
+ //
+ // Mem Bar
+ //
+ Mask = 0xFFFFFFF0;
+ TestValue = TestValue & Mask;
+
+ if ((TestValue & 0x07) == 0x04) {
+
+ //
+ // Mem64 or PMem64
+ //
+ BarOffset += sizeof (UINT32);
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+
+ //
+ // Test its high 32-Bit BAR
+ //
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
+ if (TestValue == OldValue) {
+ return TRUE;
+ }
+ }
+
+ } else {
+
+ //
+ // Mem32 or PMem32
+ //
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Reset all bus number from specific bridge.
+
+ @param Bridge Parent specific bridge.
+ @param StartBusNumber Start bus number.
+
+**/
+VOID
+ResetAllPpbBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT32 Register;
+ UINT8 Func;
+ UINT64 Address;
+ UINT8 SecondaryBus;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether a pci device is present
+ //
+ Status = PciDevicePresent (
+ PciRootBridgeIo,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func
+ );
+
+ if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
+
+ Register = 0;
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Register
+ );
+ SecondaryBus = (UINT8)(Register >> 8);
+
+ if (SecondaryBus != 0) {
+ ResetAllPpbBusNumber (Bridge, SecondaryBus);
+ }
+
+ //
+ // Reset register 18h, 19h, 1Ah on PCI Bridge
+ //
+ Register &= 0xFF000000;
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Register
+ );
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h
new file mode 100644
index 0000000000..31238b45cf
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h
@@ -0,0 +1,463 @@
+/** @file
+ PCI emumeration support functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_ENUMERATOR_SUPPORT_H_
+#define _EFI_PCI_ENUMERATOR_SUPPORT_H_
+
+/**
+ This routine is used to check whether the pci device is present.
+
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pci Output buffer for PCI device configuration space.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI Func NO.
+
+ @retval EFI_NOT_FOUND PCI device not present.
+ @retval EFI_SUCCESS PCI device is found.
+
+**/
+EFI_STATUS
+PciDevicePresent (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ OUT PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Collect all the resource information under this root bridge.
+
+ A database that records all the information about pci device subject to this
+ root bridge will then be created.
+
+ @param Bridge Parent bridge instance.
+ @param StartBusNumber Bus number of begining.
+
+ @retval EFI_SUCCESS PCI device is found.
+ @retval other Some error occurred when reading PCI bridge information.
+
+**/
+EFI_STATUS
+PciPciDeviceInfoCollector (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ );
+
+/**
+ Seach required device and create PCI device instance.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI func NO.
+ @param PciDevice Output of searched PCI device instance.
+
+ @retval EFI_SUCCESS Successfully created PCI device instance.
+ @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
+
+**/
+EFI_STATUS
+PciSearchDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ OUT PCI_IO_DEVICE **PciDevice
+ );
+
+/**
+ Create PCI device instance for PCI device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherDeviceInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Create PCI device instance for PCI-PCI bridge.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherPpbInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Create PCI device instance for PCI Card bridge device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherP2CInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Create device path for pci deivce.
+
+ @param ParentDevicePath Parent bridge's path.
+ @param PciIoDevice Pci device instance.
+
+ @return device path protocol instance for specific pci device.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CreatePciDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Check whether the PCI IOV VF bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+VfBarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ );
+
+/**
+ Check whether the bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+BarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ );
+
+/**
+ Test whether the device can support given attributes.
+
+ @param PciIoDevice Pci device instance.
+ @param Command Input command register value, and
+ returned supported register value.
+ @param BridgeControl Inout bridge control value for PPB or P2C, and
+ returned supported bridge control value.
+ @param OldCommand Returned and stored old command register offset.
+ @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
+
+**/
+VOID
+PciTestSupportedAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN OUT UINT16 *Command,
+ IN OUT UINT16 *BridgeControl,
+ OUT UINT16 *OldCommand,
+ OUT UINT16 *OldBridgeControl
+ );
+
+/**
+ Set the supported or current attributes of a PCI device.
+
+ @param PciIoDevice Structure pointer for PCI device.
+ @param Command Command register value.
+ @param BridgeControl Bridge control value for PPB or P2C.
+ @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
+
+**/
+VOID
+PciSetDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT16 BridgeControl,
+ IN UINTN Option
+ );
+
+/**
+ Determine if the device can support Fast Back to Back attribute.
+
+ @param PciIoDevice Pci device instance.
+ @param StatusIndex Status register value.
+
+ @retval EFI_SUCCESS This device support Fast Back to Back attribute.
+ @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
+
+**/
+EFI_STATUS
+GetFastBackToBackSupport (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 StatusIndex
+ );
+
+/**
+ Determine the related attributes of all devices under a Root Bridge.
+
+ @param PciIoDevice PCI device instance.
+
+**/
+EFI_STATUS
+DetermineDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine is used to update the bar information for those incompatible PCI device.
+
+ @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
+ Bar information.
+
+ @retval EFI_SUCCESS Successfully updated bar information.
+ @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
+
+**/
+EFI_STATUS
+UpdatePciInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine will update the alignment with the new alignment.
+
+ @param Alignment Input Old alignment. Output updated alignment.
+ @param NewAlignment New alignment.
+
+**/
+VOID
+SetNewAlign (
+ IN OUT UINT64 *Alignment,
+ IN UINT64 NewAlignment
+ );
+
+/**
+ Parse PCI bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciParseBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ );
+
+/**
+ Parse PCI IOV VF bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciIovParseVfBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ );
+
+/**
+ This routine is used to initialize the bar of a PCI device.
+
+ @param PciIoDevice Pci device instance.
+
+ @note It can be called typically when a device is going to be rejected.
+
+**/
+VOID
+InitializePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine is used to initialize the bar of a PCI-PCI Bridge device.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+**/
+VOID
+InitializePpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine is used to initialize the bar of a PCI Card Bridge device.
+
+ @param PciIoDevice PCI Card bridge device.
+
+**/
+VOID
+InitializeP2C (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Create and initiliaze general PCI I/O device instance for
+ PCI device/bridge device/hotplug bridge device.
+
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pci Input Pci information block.
+ @param Bus Device Bus NO.
+ @param Device Device device NO.
+ @param Func Device func NO.
+
+ @return Instance of PCI device. NULL means no instance created.
+
+**/
+PCI_IO_DEVICE *
+CreatePciIoDevice (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ It is only called on the second start on the same Root Bridge.
+
+ @param Controller Parent bridge handler.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumeratorLight (
+ IN EFI_HANDLE Controller
+ );
+
+/**
+ Get bus range from PCI resource descriptor list.
+
+ @param Descriptors A pointer to the address space descriptor.
+ @param MinBus The min bus returned.
+ @param MaxBus The max bus returned.
+ @param BusRange The bus range returned.
+
+ @retval EFI_SUCCESS Successfully got bus range.
+ @retval EFI_NOT_FOUND Can not find the specific bus.
+
+**/
+EFI_STATUS
+PciGetBusRange (
+ IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
+ OUT UINT16 *MinBus,
+ OUT UINT16 *MaxBus,
+ OUT UINT16 *BusRange
+ );
+
+/**
+ This routine can be used to start the root bridge.
+
+ @param RootBridgeDev Pci device instance.
+
+ @retval EFI_SUCCESS This device started.
+ @retval other Failed to get PCI Root Bridge I/O protocol.
+
+**/
+EFI_STATUS
+StartManagingRootBridge (
+ IN PCI_IO_DEVICE *RootBridgeDev
+ );
+
+/**
+ This routine can be used to check whether a PCI device should be rejected when light enumeration.
+
+ @param PciIoDevice Pci device instance.
+
+ @retval TRUE This device should be rejected.
+ @retval FALSE This device shouldn't be rejected.
+
+**/
+BOOLEAN
+IsPciDeviceRejected (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Reset all bus number from specific bridge.
+
+ @param Bridge Parent specific bridge.
+ @param StartBusNumber Start bus number.
+
+**/
+VOID
+ResetAllPpbBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c
new file mode 100644
index 0000000000..20c2c2fcfe
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c
@@ -0,0 +1,394 @@
+/** @file
+ PCI Hot Plug support functions implementation for PCI Bus module..
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit = NULL;
+EFI_HPC_LOCATION *gPciRootHpcPool = NULL;
+UINTN gPciRootHpcCount = 0;
+ROOT_HPC_DATA *gPciRootHpcData = NULL;
+
+
+/**
+ Event notification function to set Hot Plug controller status.
+
+ @param Event The event that invoke this function.
+ @param Context The calling context, pointer to ROOT_HPC_DATA.
+
+**/
+VOID
+EFIAPI
+PciHPCInitialized (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ROOT_HPC_DATA *HpcData;
+
+ HpcData = (ROOT_HPC_DATA *) Context;
+ HpcData->Initialized = TRUE;
+}
+
+/**
+ Compare two device pathes to check if they are exactly same.
+
+ @param DevicePath1 A pointer to the first device path data structure.
+ @param DevicePath2 A pointer to the second device path data structure.
+
+ @retval TRUE They are same.
+ @retval FALSE They are not same.
+
+**/
+BOOLEAN
+EfiCompareDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
+ )
+{
+ UINTN Size1;
+ UINTN Size2;
+
+ Size1 = GetDevicePathSize (DevicePath1);
+ Size2 = GetDevicePathSize (DevicePath2);
+
+ if (Size1 != Size2) {
+ return FALSE;
+ }
+
+ if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check hot plug support and initialize root hot plug private data.
+
+ If Hot Plug is supported by the platform, call PCI Hot Plug Init protocol
+ to get PCI Hot Plug controller's information and constructor the root hot plug
+ private data structure.
+
+ @retval EFI_SUCCESS They are same.
+ @retval EFI_UNSUPPORTED No PCI Hot Plug controler on the platform.
+ @retval EFI_OUT_OF_RESOURCES No memory to constructor root hot plug private
+ data structure.
+
+**/
+EFI_STATUS
+InitializeHotPlugSupport (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HPC_LOCATION *HpcList;
+ UINTN HpcCount;
+
+ //
+ // Locate the PciHotPlugInit Protocol
+ // If it doesn't exist, that means there is no
+ // hot plug controller supported on the platform
+ // the PCI Bus driver is running on. HotPlug Support
+ // is an optional feature, so absence of the protocol
+ // won't incur the penalty.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiPciHotPlugInitProtocolGuid,
+ NULL,
+ (VOID **) &gPciHotPlugInit
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gPciHotPlugInit->GetRootHpcList (
+ gPciHotPlugInit,
+ &HpcCount,
+ &HpcList
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ gPciRootHpcPool = HpcList;
+ gPciRootHpcCount = HpcCount;
+ gPciRootHpcData = AllocateZeroPool (sizeof (ROOT_HPC_DATA) * gPciRootHpcCount);
+ if (gPciRootHpcData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Test whether device path is for root pci hot plug bus.
+
+ @param HpbDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is retuned.
+
+ @retval TRUE The device path is for root pci hot plug bus.
+ @retval FALSE The device path is not for root pci hot plug bus.
+
+**/
+BOOLEAN
+IsRootPciHotPlugBus (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpbDevicePath,
+ OUT UINTN *HpIndex OPTIONAL
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < gPciRootHpcCount; Index++) {
+
+ if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpbDevicePath, HpbDevicePath)) {
+
+ if (HpIndex != NULL) {
+ *HpIndex = Index;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Test whether device path is for root pci hot plug controller.
+
+ @param HpcDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is retuned.
+
+ @retval TRUE The device path is for root pci hot plug controller.
+ @retval FALSE The device path is not for root pci hot plug controller.
+
+**/
+BOOLEAN
+IsRootPciHotPlugController (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
+ OUT UINTN *HpIndex
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < gPciRootHpcCount; Index++) {
+
+ if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpcDevicePath, HpcDevicePath)) {
+
+ if (HpIndex != NULL) {
+ *HpIndex = Index;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Creating event object for PCI Hot Plug controller.
+
+ @param HpIndex Index of hot plug device in global array.
+ @param Event The retuned event that invoke this function.
+
+ @return Status of create event invoken.
+
+**/
+EFI_STATUS
+CreateEventForHpc (
+ IN UINTN HpIndex,
+ OUT EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PciHPCInitialized,
+ gPciRootHpcData + HpIndex,
+ &((gPciRootHpcData + HpIndex)->Event)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ *Event = (gPciRootHpcData + HpIndex)->Event;
+ }
+
+ return Status;
+}
+
+/**
+ Wait for all root PCI Hot Plug controller finished initializing.
+
+ @param TimeoutInMicroSeconds Microseconds to wait for all root HPCs' initialization.
+
+ @retval EFI_SUCCESS All HPCs initialization finished.
+ @retval EFI_TIMEOUT Not ALL HPCs initialization finished in Microseconds.
+
+**/
+EFI_STATUS
+AllRootHPCInitialized (
+ IN UINTN TimeoutInMicroSeconds
+ )
+{
+ UINT32 Delay;
+ UINTN Index;
+
+ Delay = (UINT32) ((TimeoutInMicroSeconds / 30) + 1);
+
+ do {
+ for (Index = 0; Index < gPciRootHpcCount; Index++) {
+
+ if (!gPciRootHpcData[Index].Initialized) {
+ break;
+ }
+ }
+
+ if (Index == gPciRootHpcCount) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 30 microseconds..
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Check whether PCI-PCI bridge has PCI Hot Plug capability register block.
+
+ @param PciIoDevice A Pointer to the PCI-PCI bridge.
+
+ @retval TRUE PCI device is HPC.
+ @retval FALSE PCI device is not HPC.
+
+**/
+BOOLEAN
+IsSHPC (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+
+ EFI_STATUS Status;
+ UINT8 Offset;
+
+ if (PciIoDevice == NULL) {
+ return FALSE;
+ }
+
+ Offset = 0;
+ Status = LocateCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCI_CAPABILITY_ID_HOTPLUG,
+ &Offset,
+ NULL
+ );
+
+ //
+ // If the PCI-PCI bridge has the hot plug controller build-in,
+ // then return TRUE;
+ //
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get resource padding if the specified PCI bridge is a hot plug bus.
+
+ @param PciIoDevice PCI bridge instance.
+
+**/
+VOID
+GetResourcePaddingForHpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_HPC_PADDING_ATTRIBUTES Attributes;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+
+ if (IsPciHotPlugBus (PciIoDevice)) {
+ //
+ // If PCI-PCI bridge device is PCI Hot Plug bus.
+ //
+ PciAddress = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
+ Status = gPciHotPlugInit->GetResourcePadding (
+ gPciHotPlugInit,
+ PciIoDevice->DevicePath,
+ PciAddress,
+ &State,
+ (VOID **) &Descriptors,
+ &Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if ((State & EFI_HPC_STATE_ENABLED) != 0 && (State & EFI_HPC_STATE_INITIALIZED) != 0) {
+ PciIoDevice->ResourcePaddingDescriptors = Descriptors;
+ PciIoDevice->PaddingAttributes = Attributes;
+ }
+
+ return;
+ }
+}
+
+/**
+ Test whether PCI device is hot plug bus.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval TRUE PCI device is a hot plug bus.
+ @retval FALSE PCI device is not a hot plug bus.
+
+**/
+BOOLEAN
+IsPciHotPlugBus (
+ PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ if (IsSHPC (PciIoDevice)) {
+ //
+ // If the PPB has the hot plug controller build-in,
+ // then return TRUE;
+ //
+ return TRUE;
+ }
+
+ //
+ // Otherwise, see if it is a Root HPC
+ //
+ if(IsRootPciHotPlugBus (PciIoDevice->DevicePath, NULL)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h
new file mode 100644
index 0000000000..a84e256b90
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h
@@ -0,0 +1,189 @@
+/** @file
+ PCI Hot Plug support functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_HOT_PLUG_SUPPORT_H_
+#define _EFI_PCI_HOT_PLUG_SUPPORT_H_
+
+//
+// stall 1 second, its unit is 100ns
+//
+#define STALL_1_SECOND 1000000
+
+//
+// PCI Hot Plug controller private data
+//
+typedef struct {
+ EFI_EVENT Event;
+ BOOLEAN Initialized;
+ VOID *Padding;
+} ROOT_HPC_DATA;
+
+//
+// Reference of some global variabes
+//
+extern EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit;
+extern EFI_HPC_LOCATION *gPciRootHpcPool;
+extern ROOT_HPC_DATA *gPciRootHpcData;
+
+/**
+ Event notification function to set Hot Plug controller status.
+
+ @param Event The event that invoke this function.
+ @param Context The calling context, pointer to ROOT_HPC_DATA.
+
+**/
+VOID
+EFIAPI
+PciHPCInitialized (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Compare two device pathes to check if they are exactly same.
+
+ @param DevicePath1 A pointer to the first device path data structure.
+ @param DevicePath2 A pointer to the second device path data structure.
+
+ @retval TRUE They are same.
+ @retval FALSE They are not same.
+
+**/
+BOOLEAN
+EfiCompareDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
+ );
+
+/**
+ Check hot plug support and initialize root hot plug private data.
+
+ If Hot Plug is supported by the platform, call PCI Hot Plug Init protocol
+ to get PCI Hot Plug controller's information and constructor the root hot plug
+ private data structure.
+
+ @retval EFI_SUCCESS They are same.
+ @retval EFI_UNSUPPORTED No PCI Hot Plug controler on the platform.
+ @retval EFI_OUT_OF_RESOURCES No memory to constructor root hot plug private
+ data structure.
+
+**/
+EFI_STATUS
+InitializeHotPlugSupport (
+ VOID
+ );
+
+/**
+ Test whether PCI device is hot plug bus.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval TRUE PCI device is a hot plug bus.
+ @retval FALSE PCI device is not a hot plug bus.
+
+**/
+BOOLEAN
+IsPciHotPlugBus (
+ PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Test whether device path is for root pci hot plug bus.
+
+ @param HpbDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is retuned.
+
+ @retval TRUE The device path is for root pci hot plug bus.
+ @retval FALSE The device path is not for root pci hot plug bus.
+
+**/
+BOOLEAN
+IsRootPciHotPlugBus (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpbDevicePath,
+ OUT UINTN *HpIndex OPTIONAL
+ );
+
+/**
+ Test whether device path is for root pci hot plug controller.
+
+ @param HpcDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is retuned.
+
+ @retval TRUE The device path is for root pci hot plug controller.
+ @retval FALSE The device path is not for root pci hot plug controller.
+
+**/
+BOOLEAN
+IsRootPciHotPlugController (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
+ OUT UINTN *HpIndex
+ );
+
+/**
+ Creating event object for PCI Hot Plug controller.
+
+ @param HpIndex Index of hot plug device in global array.
+ @param Event The retuned event that invoke this function.
+
+ @return Status of create event invoken.
+
+**/
+EFI_STATUS
+CreateEventForHpc (
+ IN UINTN HpIndex,
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Wait for all root PCI Hot Plug controller finished initializing.
+
+ @param TimeoutInMicroSeconds Microseconds to wait for all root HPCs' initialization.
+
+ @retval EFI_SUCCESS All HPCs initialization finished.
+ @retval EFI_TIMEOUT Not ALL HPCs initialization finished in Microseconds.
+
+**/
+EFI_STATUS
+AllRootHPCInitialized (
+ IN UINTN TimeoutInMicroSeconds
+ );
+
+/**
+ Check whether PCI-PCI bridge has PCI Hot Plug capability register block.
+
+ @param PciIoDevice A Pointer to the PCI-PCI bridge.
+
+ @retval TRUE PCI device is HPC.
+ @retval FALSE PCI device is not HPC.
+
+**/
+BOOLEAN
+IsSHPC (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Get resource padding if the specified PCI bridge is a hot plug bus.
+
+ @param PciIoDevice PCI bridge instance.
+
+**/
+VOID
+GetResourcePaddingForHpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
new file mode 100644
index 0000000000..5cc5967245
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
@@ -0,0 +1,1877 @@
+/** @file
+ EFI PCI IO protocol functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+//
+// Pci Io Protocol Interface
+//
+EFI_PCI_IO_PROTOCOL mPciIoInterface = {
+ PciIoPollMem,
+ PciIoPollIo,
+ {
+ PciIoMemRead,
+ PciIoMemWrite
+ },
+ {
+ PciIoIoRead,
+ PciIoIoWrite
+ },
+ {
+ PciIoConfigRead,
+ PciIoConfigWrite
+ },
+ PciIoCopyMem,
+ PciIoMap,
+ PciIoUnmap,
+ PciIoAllocateBuffer,
+ PciIoFreeBuffer,
+ PciIoFlush,
+ PciIoGetLocation,
+ PciIoAttributes,
+ PciIoGetBarAttributes,
+ PciIoSetBarAttributes,
+ 0,
+ NULL
+};
+
+/**
+ Report a error Status code of PCI bus driver controller.
+
+ @param PciIoDevice Pci device instance.
+ @param Code Status code value.
+
+**/
+EFI_STATUS
+ReportErrorStatusCode (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_STATUS_CODE_VALUE Code
+ )
+{
+ return REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ Code,
+ PciIoDevice->DevicePath
+ );
+}
+
+/**
+ Initializes a PCI I/O Instance.
+
+ @param PciIoDevice Pci device instance.
+
+**/
+VOID
+InitializePciIoInstance (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ CopyMem (&PciIoDevice->PciIo, &mPciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));
+}
+
+/**
+ Verifies access to a PCI Base Address Register (BAR).
+
+ @param PciIoDevice Pci device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Type Operation type could be memory or I/O.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyBarAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE Type,
+ IN IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN IN UINTN Count,
+ IN UINT64 *Offset
+ )
+{
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // BarIndex 0-5 is legal
+ //
+ if (BarIndex >= PCI_MAX_BAR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
+ // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
+ //
+ if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verifies access to a PCI Configuration Header.
+
+ @param PciIoDevice Pci device instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width
+ @retval EFI_UNSUPPORTED Offset overflowed.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyConfigAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT64 *Offset
+ )
+{
+ UINT64 ExtendOffset;
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
+ //
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ if (PciIoDevice->IsPciExp) {
+ if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ExtendOffset = LShiftU64 (*Offset, 32);
+ *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
+ *Offset = (*Offset) | ExtendOffset;
+
+ } else {
+ if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param 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_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @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.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Width > EfiPciIoWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->PollMem (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Mask,
+ Value,
+ Delay,
+ Result
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param 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_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @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.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollIo (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Width < 0 || Width > EfiPciIoWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->PollIo (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Mask,
+ Value,
+ Delay,
+ Result
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Io.Read (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Io.Write (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ UINT64 Address;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Address = Offset;
+ Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Address,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ UINT64 Address;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Address = Offset;
+ Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Address,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+ memory space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to
+ start the memory writes for the copy operation.
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
+ the memory reads for the copy operation.
+ @param Count The number of memory operations to perform. Bytes moved is Width
+ size * Count, starting at DestOffset and SrcOffset.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count
+ is not valid for the PCI BAR specified by DestBarIndex.
+ @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is
+ not valid for the PCI BAR specified by SrcBarIndex.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoCopyMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width == EfiPciIoWidthFifoUint8 ||
+ Width == EfiPciIoWidthFifoUint16 ||
+ Width == EfiPciIoWidthFifoUint32 ||
+ Width == EfiPciIoWidthFifoUint64 ||
+ Width == EfiPciIoWidthFillUint8 ||
+ Width == EfiPciIoWidthFillUint16 ||
+ Width == EfiPciIoWidthFillUint32 ||
+ Width == EfiPciIoWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->CopyMem (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ DestOffset,
+ SrcOffset,
+ Count
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Provides the PCI controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to 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 hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Operation < 0 || Operation >= EfiPciIoOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
+ Operation = (EFI_PCI_IO_PROTOCOL_OPERATION) (Operation + EfiPciOperationBusMasterRead64);
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Map (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoUnmap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Status = PciIoDevice->PciRootBridgeIo->Unmap (
+ PciIoDevice->PciRootBridgeIo,
+ Mapping
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
+ mapping.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @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.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAllocateBuffer (
+ IN EFI_PCI_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;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ if ((Attributes &
+ (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) != 0){
+ return EFI_UNSUPPORTED;
+ }
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
+ Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
+ PciIoDevice->PciRootBridgeIo,
+ Type,
+ MemoryType,
+ Pages,
+ HostAddress,
+ Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @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
+PciIoFreeBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
+ PciIoDevice->PciRootBridgeIo,
+ Pages,
+ HostAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+ @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
+PciIoFlush (
+ IN EFI_PCI_IO_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Status = PciIoDevice->PciRootBridgeIo->Flush (
+ PciIoDevice->PciRootBridgeIo
+ );
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param SegmentNumber The PCI controller's current PCI segment number.
+ @param BusNumber The PCI controller's current PCI bus number.
+ @param DeviceNumber The PCI controller's current PCI device number.
+ @param FunctionNumber The PCI controller's current PCI function number.
+
+ @retval EFI_SUCCESS The PCI controller location was returned.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetLocation (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *Segment,
+ OUT UINTN *Bus,
+ OUT UINTN *Device,
+ OUT UINTN *Function
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Segment = PciIoDevice->PciRootBridgeIo->SegmentNumber;
+ *Bus = PciIoDevice->BusNumber;
+ *Device = PciIoDevice->DeviceNumber;
+ *Function = PciIoDevice->FunctionNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check BAR type for PCI resource.
+
+ @param PciIoDevice PCI device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param BarType Memory or I/O.
+
+ @retval TRUE Pci device's bar type is same with input BarType.
+ @retval TRUE Pci device's bar type is not same with input BarType.
+
+**/
+BOOLEAN
+CheckBarType (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE BarType
+ )
+{
+ switch (BarType) {
+
+ case PciBarTypeMem:
+
+ if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64 ) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+ case PciBarTypeIo:
+ if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
+ return FALSE;
+ }
+
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ Set/Disable new attributes to a Root Bridge.
+
+ @param PciIoDevice Pci device instance.
+ @param Attributes New attribute want to be set.
+ @param Operation Set or Disable.
+
+ @retval EFI_UNSUPPORTED If root bridge does not support change attribute.
+ @retval EFI_SUCCESS Successfully set new attributs.
+
+**/
+EFI_STATUS
+ModifyRootBridgeAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT64 Attributes,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ )
+{
+ UINT64 PciRootBridgeSupports;
+ UINT64 PciRootBridgeAttributes;
+ UINT64 NewPciRootBridgeAttributes;
+ EFI_STATUS Status;
+
+ //
+ // Get the current attributes of this PCI device's PCI Root Bridge
+ //
+ Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
+ PciIoDevice->PciRootBridgeIo,
+ &PciRootBridgeSupports,
+ &PciRootBridgeAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Record the new attribute of the Root Bridge
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ NewPciRootBridgeAttributes = PciRootBridgeAttributes | Attributes;
+ } else {
+ NewPciRootBridgeAttributes = PciRootBridgeAttributes & (~Attributes);
+ }
+
+ //
+ // Call the PCI Root Bridge to attempt to modify the attributes
+ //
+ if ((NewPciRootBridgeAttributes ^ PciRootBridgeAttributes) != 0) {
+
+ Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
+ PciIoDevice->PciRootBridgeIo,
+ NewPciRootBridgeAttributes,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // The PCI Root Bridge could not modify the attributes, so return the error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Also update the attributes for this Root Bridge structure
+ //
+ PciIoDevice->Attributes = NewPciRootBridgeAttributes;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether this device can be enable/disable to snoop.
+
+ @param PciIoDevice Pci device instance.
+ @param Operation Enable/Disable.
+
+ @retval EFI_UNSUPPORTED Pci device is not GFX device or not support snoop.
+ @retval EFI_SUCCESS Snoop can be supported.
+
+**/
+EFI_STATUS
+SupportPaletteSnoopAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ UINT16 VGACommand;
+
+ //
+ // Snoop attribute can be only modified by GFX
+ //
+ if (!IS_PCI_GFX (&PciIoDevice->Pci)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the boot VGA on the same segement
+ //
+ Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
+
+ if (Temp == NULL) {
+ //
+ // If there is no VGA device on the segement, set
+ // this graphics card to decode the palette range
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check these two agents are on the same path
+ //
+ if (!PciDevicesOnTheSamePath (Temp, PciIoDevice)) {
+ //
+ // they are not on the same path, so snoop can be enabled or disabled
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // Check if they are on the same bus
+ //
+ if (Temp->Parent == PciIoDevice->Parent) {
+
+ PCI_READ_COMMAND_REGISTER (Temp, &VGACommand);
+
+ //
+ // If they are on the same bus, either one can
+ // be set to snoop, the other set to decode
+ //
+ if ((VGACommand & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
+ //
+ // VGA has set to snoop, so GFX can be only set to disable snoop
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ //
+ // VGA has disabled to snoop, so GFX can be only enabled
+ //
+ if (Operation == EfiPciIoAttributeOperationDisable) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If they are on the same path but on the different bus
+ // The first agent is set to snoop, the second one set to
+ // decode
+ //
+
+ if (Temp->BusNumber < PciIoDevice->BusNumber) {
+ //
+ // GFX should be set to decode
+ //
+ if (Operation == EfiPciIoAttributeOperationDisable) {
+ PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
+ Temp->Attributes |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ } else {
+ //
+ // GFX should be set to snoop
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
+ Temp->Attributes &= (~EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Performs an operation on the attributes that this PCI controller supports. The operations include
+ getting the set of supported attributes, retrieving the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+ @param Result A pointer to the result mask of attributes that are returned for the Get
+ and Supported operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ PCI_IO_DEVICE *PciIoDevice;
+ PCI_IO_DEVICE *UpStreamBridge;
+ PCI_IO_DEVICE *Temp;
+
+ UINT64 Supports;
+ UINT64 UpStreamAttributes;
+ UINT16 BridgeControl;
+ UINT16 Command;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ switch (Operation) {
+ case EfiPciIoAttributeOperationGet:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Result = PciIoDevice->Attributes;
+ return EFI_SUCCESS;
+
+ case EfiPciIoAttributeOperationSupported:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Result = PciIoDevice->Supports;
+ return EFI_SUCCESS;
+
+ case EfiPciIoAttributeOperationSet:
+ Status = PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ Attributes,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationDisable,
+ (~Attributes) & (PciIoDevice->Supports),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+
+ case EfiPciIoAttributeOperationEnable:
+ case EfiPciIoAttributeOperationDisable:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Just a trick for ENABLE attribute
+ // EFI_PCI_DEVICE_ENABLE is not defined in UEFI spec, which is the internal usage.
+ // So, this logic doesn't confrom to UEFI spec, which should be removed.
+ // But this trick logic is still kept for some binary drivers that depend on it.
+ //
+ if ((Attributes & EFI_PCI_DEVICE_ENABLE) == EFI_PCI_DEVICE_ENABLE) {
+ Attributes &= (PciIoDevice->Supports);
+
+ //
+ // Raise the EFI_P_PC_ENABLE Status code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_P_PC_ENABLE,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ //
+ // If no attributes can be supported, then return.
+ // Otherwise, set the attributes that it can support.
+ //
+ Supports = (PciIoDevice->Supports) & Attributes;
+ if (Supports != Attributes) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // For Root Bridge, just call RootBridgeIo to set attributes;
+ //
+ if (PciIoDevice->Parent == NULL) {
+ Status = ModifyRootBridgeAttributes (PciIoDevice, Attributes, Operation);
+ return Status;
+ }
+
+ Command = 0;
+ BridgeControl = 0;
+
+ //
+ // Check VGA and VGA16, they can not be set at the same time
+ //
+ if (((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) != 0 &&
+ (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO_16) != 0) ||
+ ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) != 0 &&
+ (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16) != 0) ||
+ ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) != 0 &&
+ (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO_16) != 0) ||
+ ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) != 0 &&
+ (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16) != 0) ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // For PPB & P2C, set relevant attribute bits
+ //
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
+ BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA;
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) != 0) {
+ BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA;
+ }
+
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
+ Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
+ }
+
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
+ BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA_16;
+ }
+
+ } else {
+ //
+ // Do with the attributes on VGA
+ // Only for VGA's legacy resource, we just can enable once.
+ //
+ if ((Attributes &
+ (EFI_PCI_IO_ATTRIBUTE_VGA_IO |
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |
+ EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY)) != 0) {
+ //
+ // Check if a VGA has been enabled before enabling a new one
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ //
+ // Check if there have been an active VGA device on the same segment
+ //
+ Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
+ if (Temp != NULL && Temp != PciIoDevice) {
+ //
+ // An active VGA has been detected, so can not enable another
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Do with the attributes on GFX
+ //
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
+
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ //
+ // Check if snoop can be enabled in current configuration
+ //
+ Status = SupportPaletteSnoopAttributes (PciIoDevice, Operation);
+
+ if (EFI_ERROR (Status)) {
+
+ //
+ // Enable operation is forbidden, so mask the bit in attributes
+ // so as to keep consistent with the actual Status
+ //
+ // Attributes &= (~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
+ //
+ //
+ //
+ return EFI_UNSUPPORTED;
+
+ }
+ }
+
+ //
+ // It can be supported, so get ready to set the bit
+ //
+ Command |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
+ }
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
+ Command |= EFI_PCI_COMMAND_IO_SPACE;
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) != 0) {
+ Command |= EFI_PCI_COMMAND_MEMORY_SPACE;
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) != 0) {
+ Command |= EFI_PCI_COMMAND_BUS_MASTER;
+ }
+ //
+ // The upstream bridge should be also set to revelant attribute
+ // expect for IO, Mem and BusMaster
+ //
+ UpStreamAttributes = Attributes &
+ (~(EFI_PCI_IO_ATTRIBUTE_IO |
+ EFI_PCI_IO_ATTRIBUTE_MEMORY |
+ EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
+ )
+ );
+ UpStreamBridge = PciIoDevice->Parent;
+
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ //
+ // Enable relevant attributes to command register and bridge control register
+ //
+ Status = PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, Command);
+ if (BridgeControl != 0) {
+ Status = PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
+ }
+
+ PciIoDevice->Attributes |= Attributes;
+
+ //
+ // Enable attributes of the upstream bridge
+ //
+ Status = UpStreamBridge->PciIo.Attributes (
+ &(UpStreamBridge->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ UpStreamAttributes,
+ NULL
+ );
+ } else {
+
+ //
+ // Disable relevant attributes to command register and bridge control register
+ //
+ Status = PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, Command);
+ if (BridgeControl != 0) {
+ Status = PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
+ }
+
+ PciIoDevice->Attributes &= (~Attributes);
+ Status = EFI_SUCCESS;
+
+ }
+
+ if (EFI_ERROR (Status)) {
+ ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
+ }
+
+ return Status;
+}
+
+/**
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Supports A pointer to the mask of attributes that this PCI controller supports
+ setting for this BAR with SetBarAttributes().
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this BAR of the PCI controller.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
+ controller supports are returned in Supports. If Resources
+ is not NULL, then the ACPI 2.0 resource descriptors that the PCI
+ controller is currently using are returned in Resources.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
+ Resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports, OPTIONAL
+ OUT VOID **Resources OPTIONAL
+ )
+{
+
+ UINT8 *Configuration;
+ UINT8 NumConfig;
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+ EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;
+
+ NumConfig = 0;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Supports == NULL && Resources == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BarIndex >= PCI_MAX_BAR) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // This driver does not support modifications to the WRITE_COMBINE or
+ // CACHED attributes for BAR ranges.
+ //
+ if (Supports != NULL) {
+ *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
+ }
+
+ if (Resources != NULL) {
+
+ if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeUnknown) {
+ NumConfig = 1;
+ }
+
+ Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Configuration == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+
+ if (NumConfig == 1) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+
+ Ptr->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
+ Ptr->AddrLen = PciIoDevice->PciBar[BarIndex].Length;
+ Ptr->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
+
+ switch (PciIoDevice->PciBar[BarIndex].BarType) {
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ //
+ // Io
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case PciBarTypeMem32:
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // 32 bit
+ //
+ Ptr->AddrSpaceGranularity = 32;
+ break;
+
+ case PciBarTypePMem32:
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // prefechable
+ //
+ Ptr->SpecificFlag = 0x6;
+ //
+ // 32 bit
+ //
+ Ptr->AddrSpaceGranularity = 32;
+ break;
+
+ case PciBarTypeMem64:
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // 64 bit
+ //
+ Ptr->AddrSpaceGranularity = 64;
+ break;
+
+ case PciBarTypePMem64:
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // prefechable
+ //
+ Ptr->SpecificFlag = 0x6;
+ //
+ // 64 bit
+ //
+ Ptr->AddrSpaceGranularity = 64;
+ break;
+
+ default:
+ break;
+ }
+
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR));
+ }
+
+ //
+ // put the checksum
+ //
+ PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) ((UINT8 *) Ptr);
+ PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
+ PtrEnd->Checksum = 0;
+
+ *Resources = Configuration;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Attributes The mask of attributes to set for the resource range specified by
+ BarIndex, Offset, and Length.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Offset A pointer to the BAR relative base address of the resource range to be
+ modified by the attributes specified by Attributes.
+ @param Length A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by BarIndex, Offset, and Length were
+ set on the PCI controller, and the actual resource range is returned
+ in Offset and Length.
+ @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BarIndex, Offset, and
+ Length.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoSetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ UINT64 NonRelativeOffset;
+ UINT64 Supports;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ //
+ // Make sure Offset and Length are not NULL
+ //
+ if (Offset == NULL || Length == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
+ // If Attributes is not 0, then return EFI_UNSUPPORTED.
+ //
+ Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
+
+ if (Attributes != (Attributes & Supports)) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Attributes must be supported. Make sure the BAR range describd by BarIndex, Offset, and
+ // Length are valid for this PCI device.
+ //
+ NonRelativeOffset = *Offset;
+ Status = PciIoVerifyBarAccess (
+ PciIoDevice,
+ BarIndex,
+ PciBarTypeMem,
+ EfiPciIoWidthUint8,
+ (UINT32) *Length,
+ &NonRelativeOffset
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Program parent bridge's attribute recurrently.
+
+ @param PciIoDevice Child Pci device instance
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+EFI_STATUS
+UpStreamBridgesAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes
+ )
+{
+ PCI_IO_DEVICE *Parent;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ Parent = PciIoDevice->Parent;
+
+ while (Parent != NULL && IS_PCI_BRIDGE (&Parent->Pci)) {
+
+ //
+ // Get the PciIo Protocol
+ //
+ PciIo = &Parent->PciIo;
+
+ PciIo->Attributes (PciIo, Operation, Attributes, NULL);
+
+ Parent = Parent->Parent;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Test whether two Pci devices has same parent bridge.
+
+ @param PciDevice1 The first pci device for testing.
+ @param PciDevice2 The second pci device for testing.
+
+ @retval TRUE Two Pci device has the same parent bridge.
+ @retval FALSE Two Pci device has not the same parent bridge.
+
+**/
+BOOLEAN
+PciDevicesOnTheSamePath (
+ IN PCI_IO_DEVICE *PciDevice1,
+ IN PCI_IO_DEVICE *PciDevice2
+ )
+{
+ BOOLEAN Existed1;
+ BOOLEAN Existed2;
+
+ if (PciDevice1->Parent == PciDevice2->Parent) {
+ return TRUE;
+ }
+
+ Existed1 = PciDeviceExisted (PciDevice1->Parent, PciDevice2);
+ Existed2 = PciDeviceExisted (PciDevice2->Parent, PciDevice1);
+
+ return (BOOLEAN) (Existed1 || Existed2);
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h
new file mode 100644
index 0000000000..fbfd2b4ff9
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h
@@ -0,0 +1,687 @@
+/** @file
+ EFI PCI IO protocol functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_IO_PROTOCOL_H_
+#define _EFI_PCI_IO_PROTOCOL_H_
+
+/**
+ Initializes a PCI I/O Instance.
+
+ @param PciIoDevice Pci device instance.
+
+**/
+VOID
+InitializePciIoInstance (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Verifies access to a PCI Base Address Register (BAR).
+
+ @param PciIoDevice Pci device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Type Operation type could be memory or I/O.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyBarAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE Type,
+ IN IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN IN UINTN Count,
+ IN UINT64 *Offset
+ );
+
+/**
+ Verifies access to a PCI Configuration Header.
+
+ @param PciIoDevice Pci device instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width
+ @retval EFI_UNSUPPORTED Offset overflowed.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyConfigAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT64 *Offset
+ );
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param 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_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @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.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param 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_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @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.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollIo (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+ memory space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to
+ start the memory writes for the copy operation.
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
+ the memory reads for the copy operation.
+ @param Count The number of memory operations to perform. Bytes moved is Width
+ size * Count, starting at DestOffset and SrcOffset.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count
+ is not valid for the PCI BAR specified by DestBarIndex.
+ @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is
+ not valid for the PCI BAR specified by SrcBarIndex.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoCopyMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ );
+
+/**
+ Provides the PCI controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to 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 hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_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.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoUnmap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
+ mapping.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @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.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAllocateBuffer (
+ IN EFI_PCI_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().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @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
+PciIoFreeBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+ @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
+PciIoFlush (
+ IN EFI_PCI_IO_PROTOCOL *This
+ );
+
+/**
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param SegmentNumber The PCI controller's current PCI segment number.
+ @param BusNumber The PCI controller's current PCI bus number.
+ @param DeviceNumber The PCI controller's current PCI device number.
+ @param FunctionNumber The PCI controller's current PCI function number.
+
+ @retval EFI_SUCCESS The PCI controller location was returned.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetLocation (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *Segment,
+ OUT UINTN *Bus,
+ OUT UINTN *Device,
+ OUT UINTN *Function
+ );
+
+/**
+ Check BAR type for PCI resource.
+
+ @param PciIoDevice PCI device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param BarType Memory or I/O.
+
+ @retval TRUE Pci device's bar type is same with input BarType.
+ @retval TRUE Pci device's bar type is not same with input BarType.
+
+**/
+BOOLEAN
+CheckBarType (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE BarType
+ );
+
+/**
+ Set/Disable new attributes to a Root Bridge.
+
+ @param PciIoDevice Pci device instance.
+ @param Attributes New attribute want to be set.
+ @param Operation Set or Disable.
+
+ @retval EFI_UNSUPPORTED If root bridge does not support change attribute.
+ @retval EFI_SUCCESS Successfully set new attributs.
+
+**/
+EFI_STATUS
+ModifyRootBridgeAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT64 Attributes,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ );
+
+/**
+ Check whether this device can be enable/disable to snoop.
+
+ @param PciIoDevice Pci device instance.
+ @param Operation Enable/Disable.
+
+ @retval EFI_UNSUPPORTED Pci device is not GFX device or not support snoop.
+ @retval EFI_SUCCESS Snoop can be supported.
+
+**/
+EFI_STATUS
+SupportPaletteSnoopAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ );
+
+/**
+ Performs an operation on the attributes that this PCI controller supports. The operations include
+ getting the set of supported attributes, retrieving the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+ @param Result A pointer to the result mask of attributes that are returned for the Get
+ and Supported operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ );
+
+/**
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Supports A pointer to the mask of attributes that this PCI controller supports
+ setting for this BAR with SetBarAttributes().
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this BAR of the PCI controller.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
+ controller supports are returned in Supports. If Resources
+ is not NULL, then the ACPI 2.0 resource descriptors that the PCI
+ controller is currently using are returned in Resources.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
+ Resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports, OPTIONAL
+ OUT VOID **Resources OPTIONAL
+ );
+
+/**
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Attributes The mask of attributes to set for the resource range specified by
+ BarIndex, Offset, and Length.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Offset A pointer to the BAR relative base address of the resource range to be
+ modified by the attributes specified by Attributes.
+ @param Length A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by BarIndex, Offset, and Length were
+ set on the PCI controller, and the actual resource range is returned
+ in Offset and Length.
+ @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BarIndex, Offset, and
+ Length.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoSetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ );
+
+/**
+ Program parent bridge's attribute recurrently.
+
+ @param PciIoDevice Child Pci device instance
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+EFI_STATUS
+UpStreamBridgesAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes
+ );
+
+/**
+ Test whether two Pci devices has same parent bridge.
+
+ @param PciDevice1 The first pci device for testing.
+ @param PciDevice2 The second pci device for testing.
+
+ @retval TRUE Two Pci device has the same parent bridge.
+ @retval FALSE Two Pci device has not the same parent bridge.
+
+**/
+BOOLEAN
+PciDevicesOnTheSamePath (
+ IN PCI_IO_DEVICE *PciDevice1,
+ IN PCI_IO_DEVICE *PciDevice2
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
new file mode 100644
index 0000000000..f40000672f
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
@@ -0,0 +1,1359 @@
+/** @file
+ Internal library implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+
+/**
+ Retrieve the PCI Card device BAR information via PciIo interface.
+
+ @param PciIoDevice PCI Card device instance.
+
+**/
+VOID
+GetBackPcCardBar (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT32 Address;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return;
+ }
+
+ //
+ // Read PciBar information from the bar register
+ //
+ if (!gFullEnumeration) {
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_0,
+ 1,
+ &Address
+ );
+
+ (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;
+ (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_1,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;
+ (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_0_LOWER,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;
+ (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_1_LOWER,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;
+ (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;
+
+ }
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ GetResourcePaddingForHpb (PciIoDevice);
+ }
+}
+
+/**
+ Remove rejected pci device from specific root bridge
+ handle.
+
+ @param RootBridgeHandle Specific parent root bridge handle.
+ @param Bridge Bridge device instance.
+
+**/
+VOID
+RemoveRejectedPciDevices (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *LastLink;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return;
+ }
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_PCI_BRIDGE (&Temp->Pci)) {
+ //
+ // Remove rejected devices recusively
+ //
+ RemoveRejectedPciDevices (RootBridgeHandle, Temp);
+ } else {
+ //
+ // Skip rejection for all PPBs, while detect rejection for others
+ //
+ if (IsPciDeviceRejected (Temp)) {
+
+ //
+ // For P2C, remove all devices on it
+ //
+ if (!IsListEmpty (&Temp->ChildList)) {
+ RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
+ }
+
+ //
+ // Finally remove itself
+ //
+ LastLink = CurrentLink->BackLink;
+ RemoveEntryList (CurrentLink);
+ FreePciDevice (Temp);
+
+ CurrentLink = LastLink;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
+
+ @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully finished resource allocation.
+ @retval EFI_NOT_FOUND Cannot get root bridge instance.
+ @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
+ @retval other Some error occurred when allocating resources for the PCI Host Bridge.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciHostBridgeResourceAllocator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_HANDLE RootBridgeHandle;
+ VOID *AcpiConfig;
+ EFI_STATUS Status;
+ UINT64 IoBase;
+ UINT64 Mem32Base;
+ UINT64 PMem32Base;
+ UINT64 Mem64Base;
+ UINT64 PMem64Base;
+ UINT64 IoResStatus;
+ UINT64 Mem32ResStatus;
+ UINT64 PMem32ResStatus;
+ UINT64 Mem64ResStatus;
+ UINT64 PMem64ResStatus;
+ UINT64 MaxOptionRomSize;
+ PCI_RESOURCE_NODE *IoBridge;
+ PCI_RESOURCE_NODE *Mem32Bridge;
+ PCI_RESOURCE_NODE *PMem32Bridge;
+ PCI_RESOURCE_NODE *Mem64Bridge;
+ PCI_RESOURCE_NODE *PMem64Bridge;
+ PCI_RESOURCE_NODE IoPool;
+ PCI_RESOURCE_NODE Mem32Pool;
+ PCI_RESOURCE_NODE PMem32Pool;
+ PCI_RESOURCE_NODE Mem64Pool;
+ PCI_RESOURCE_NODE PMem64Pool;
+ BOOLEAN ReAllocate;
+ EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
+ EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
+
+ //
+ // Reallocate flag
+ //
+ ReAllocate = FALSE;
+
+ //
+ // It may try several times if the resource allocation fails
+ //
+ while (TRUE) {
+ //
+ // Initialize resource pool
+ //
+ InitializeResourcePool (&IoPool, PciBarTypeIo16);
+ InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
+ InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
+ InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
+ InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
+
+ RootBridgeDev = NULL;
+ RootBridgeHandle = 0;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get Root Bridge Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Create the entire system resource map from the information collected by
+ // enumerator. Several resource tree was created
+ //
+
+ IoBridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFF,
+ 0,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ Mem32Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ PMem32Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ Mem64Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ PMem64Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ //
+ // Create resourcemap by going through all the devices subject to this root bridge
+ //
+ CreateResourceMap (
+ RootBridgeDev,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge
+ );
+
+ //
+ // Get the max ROM size that the root bridge can process
+ //
+ RootBridgeDev->RomSize = Mem32Bridge->Length;
+
+ //
+ // Skip to enlarge the resource request during realloction
+ //
+ if (!ReAllocate) {
+ //
+ // Get Max Option Rom size for current root bridge
+ //
+ MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
+
+ //
+ // Enlarger the mem32 resource to accomdate the option rom
+ // if the mem32 resource is not enough to hold the rom
+ //
+ if (MaxOptionRomSize > Mem32Bridge->Length) {
+
+ Mem32Bridge->Length = MaxOptionRomSize;
+ RootBridgeDev->RomSize = MaxOptionRomSize;
+
+ //
+ // Alignment should be adjusted as well
+ //
+ if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {
+ Mem32Bridge->Alignment = MaxOptionRomSize - 1;
+ }
+ }
+ }
+
+ //
+ // Based on the all the resource tree, contruct ACPI resource node to
+ // submit the resource aperture to pci host bridge protocol
+ //
+ Status = ConstructAcpiResourceRequestor (
+ RootBridgeDev,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge,
+ &AcpiConfig
+ );
+
+ //
+ // Insert these resource nodes into the database
+ //
+ InsertResourceNode (&IoPool, IoBridge);
+ InsertResourceNode (&Mem32Pool, Mem32Bridge);
+ InsertResourceNode (&PMem32Pool, PMem32Bridge);
+ InsertResourceNode (&Mem64Pool, Mem64Bridge);
+ InsertResourceNode (&PMem64Pool, PMem64Bridge);
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // Submit the resource requirement
+ //
+ Status = PciResAlloc->SubmitResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ AcpiConfig
+ );
+ }
+
+ //
+ // Free acpi resource node
+ //
+ if (AcpiConfig != NULL) {
+ FreePool (AcpiConfig);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+ return Status;
+ }
+ }
+ //
+ // End while, at least one Root Bridge should be found.
+ //
+ ASSERT (RootBridgeDev != NULL);
+
+ //
+ // Notify platform to start to program the resource
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is not supported
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Allocation failed, then return
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Allocation succeed.
+ // Get host bridge handle for status report, and then skip the main while
+ //
+ HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
+
+ break;
+
+ } else {
+ //
+ // If Hot Plug is supported
+ //
+ if (!EFI_ERROR (Status)) {
+ //
+ // Allocation succeed, then continue the following
+ //
+ break;
+ }
+
+ //
+ // If the resource allocation is unsuccessful, free resources on bridge
+ //
+
+ RootBridgeDev = NULL;
+ RootBridgeHandle = 0;
+
+ IoResStatus = EFI_RESOURCE_SATISFIED;
+ Mem32ResStatus = EFI_RESOURCE_SATISFIED;
+ PMem32ResStatus = EFI_RESOURCE_SATISFIED;
+ Mem64ResStatus = EFI_RESOURCE_SATISFIED;
+ PMem64ResStatus = EFI_RESOURCE_SATISFIED;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get host bridge handle for status report
+ //
+ HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
+
+ //
+ // Get acpi resource node for all the resource types
+ //
+ AcpiConfig = NULL;
+
+ Status = PciResAlloc->GetProposedResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ &AcpiConfig
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (AcpiConfig != NULL) {
+ //
+ // Adjust resource allocation policy for each RB
+ //
+ GetResourceAllocationStatus (
+ AcpiConfig,
+ &IoResStatus,
+ &Mem32ResStatus,
+ &PMem32ResStatus,
+ &Mem64ResStatus,
+ &PMem64ResStatus
+ );
+ FreePool (AcpiConfig);
+ }
+ }
+ //
+ // End while
+ //
+
+ //
+ // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
+ //
+ //
+ // It is very difficult to follow the spec here
+ // Device path , Bar index can not be get here
+ //
+ ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
+ (VOID *) &AllocFailExtendedData,
+ sizeof (AllocFailExtendedData)
+ );
+
+ Status = PciHostBridgeAdjustAllocation (
+ &IoPool,
+ &Mem32Pool,
+ &PMem32Pool,
+ &Mem64Pool,
+ &PMem64Pool,
+ IoResStatus,
+ Mem32ResStatus,
+ PMem32ResStatus,
+ Mem64ResStatus,
+ PMem64ResStatus
+ );
+
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ReAllocate = TRUE;
+ }
+ }
+ //
+ // End main while
+ //
+
+ //
+ // Raise the EFI_IOB_PCI_RES_ALLOC status code
+ //
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,
+ (VOID *) &HandleExtendedData,
+ sizeof (HandleExtendedData)
+ );
+
+ //
+ // Notify pci bus driver starts to program the resource
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
+
+ RootBridgeDev = NULL;
+
+ RootBridgeHandle = 0;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get acpi resource node for all the resource types
+ //
+ AcpiConfig = NULL;
+ Status = PciResAlloc->GetProposedResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ &AcpiConfig
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the resource base by interpreting acpi resource node
+ //
+ //
+ GetResourceBase (
+ AcpiConfig,
+ &IoBase,
+ &Mem32Base,
+ &PMem32Base,
+ &Mem64Base,
+ &PMem64Base
+ );
+
+ //
+ // Process option rom for this root bridge
+ //
+ ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);
+
+ //
+ // Create the entire system resource map from the information collected by
+ // enumerator. Several resource tree was created
+ //
+ GetResourceMap (
+ RootBridgeDev,
+ &IoBridge,
+ &Mem32Bridge,
+ &PMem32Bridge,
+ &Mem64Bridge,
+ &PMem64Bridge,
+ &IoPool,
+ &Mem32Pool,
+ &PMem32Pool,
+ &Mem64Pool,
+ &PMem64Pool
+ );
+
+ //
+ // Program IO resources
+ //
+ ProgramResource (
+ IoBase,
+ IoBridge
+ );
+
+ //
+ // Program Mem32 resources
+ //
+ ProgramResource (
+ Mem32Base,
+ Mem32Bridge
+ );
+
+ //
+ // Program PMem32 resources
+ //
+ ProgramResource (
+ PMem32Base,
+ PMem32Bridge
+ );
+
+ //
+ // Program Mem64 resources
+ //
+ ProgramResource (
+ Mem64Base,
+ Mem64Bridge
+ );
+
+ //
+ // Program PMem64 resources
+ //
+ ProgramResource (
+ PMem64Base,
+ PMem64Bridge
+ );
+
+ FreePool (AcpiConfig);
+ }
+
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+
+ //
+ // Notify the resource allocation phase is to end
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Scan pci bus and assign bus number to the given PCI bus system.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber start point.
+ @param SubBusNumber Point to sub bus number.
+ @param PaddedBusRange Customized bus number.
+
+ @retval EFI_SUCCESS Successfully scanned and assigned bus number.
+ @retval other Some error occurred when scanning pci bus.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciScanBus (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber,
+ OUT UINT8 *PaddedBusRange
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT8 Func;
+ UINT64 Address;
+ UINTN SecondBus;
+ UINT16 Register;
+ UINTN HpIndex;
+ PCI_IO_DEVICE *PciDevice;
+ EFI_EVENT Event;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_HPC_PADDING_ATTRIBUTES Attributes;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+ UINT16 BusRange;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ BOOLEAN BusPadding;
+ UINT32 TempReservedBusNum;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+ SecondBus = 0;
+ Register = 0;
+ State = 0;
+ Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;
+ BusRange = 0;
+ BusPadding = FALSE;
+ PciDevice = NULL;
+ PciAddress = 0;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ TempReservedBusNum = 0;
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether a pci device is present
+ //
+ Status = PciDevicePresent (
+ PciRootBridgeIo,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func
+ );
+
+ if (EFI_ERROR (Status)) {
+ if (Func == 0) {
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+
+ continue;
+ }
+
+ DEBUG((EFI_D_INFO, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // Get the PCI device information
+ //
+ Status = PciSearchDevice (
+ Bridge,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func,
+ &PciDevice
+ );
+
+ ASSERT (!EFI_ERROR (Status));
+
+ PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
+
+ if (!IS_PCI_BRIDGE (&Pci)) {
+ //
+ // PCI bridges will be called later
+ // Here just need for PCI device or PCI to cardbus controller
+ // EfiPciBeforeChildBusEnumeration for PCI Device Node
+ //
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+ }
+
+ //
+ // For Pci Hotplug controller devcie only
+ //
+ if (gPciHotPlugInit != NULL) {
+ //
+ // Check if it is a Hotplug PCI controller
+ //
+ if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
+
+ if (!gPciRootHpcData[HpIndex].Initialized) {
+
+ Status = CreateEventForHpc (HpIndex, &Event);
+
+ ASSERT (!EFI_ERROR (Status));
+
+ Status = gPciHotPlugInit->InitializeRootHpc (
+ gPciHotPlugInit,
+ gPciRootHpcPool[HpIndex].HpcDevicePath,
+ PciAddress,
+ Event,
+ &State
+ );
+
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+ }
+ }
+ }
+ }
+
+ if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
+ //
+ // For PPB
+ //
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is not supported,
+ // get the bridge information
+ //
+ Status = PciSearchDevice (
+ Bridge,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func,
+ &PciDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // If Hot Plug is supported,
+ // Get the bridge information
+ //
+ BusPadding = FALSE;
+ if (gPciHotPlugInit != NULL) {
+
+ if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {
+
+ //
+ // If it is initialized, get the padded bus range
+ //
+ Status = gPciHotPlugInit->GetResourcePadding (
+ gPciHotPlugInit,
+ gPciRootHpcPool[HpIndex].HpbDevicePath,
+ PciAddress,
+ &State,
+ (VOID **) &Descriptors,
+ &Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BusRange = 0;
+ Status = PciGetBusRange (
+ &Descriptors,
+ NULL,
+ NULL,
+ &BusRange
+ );
+
+ FreePool (Descriptors);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BusPadding = TRUE;
+ }
+ }
+ }
+
+ //
+ // Add feature to support customized secondary bus number
+ //
+ if (*SubBusNumber == 0) {
+ *SubBusNumber = *PaddedBusRange;
+ *PaddedBusRange = 0;
+ }
+
+ (*SubBusNumber)++;
+ SecondBus = *SubBusNumber;
+
+ Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint16,
+ Address,
+ 1,
+ &Register
+ );
+
+
+ //
+ // If it is PPB, resursively search down this bridge
+ //
+ if (IS_PCI_BRIDGE (&Pci)) {
+
+ //
+ // Temporarily initialize SubBusNumber to maximum bus number to ensure the
+ // PCI configuration transaction to go through any PPB
+ //
+ Register = 0xFF;
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ &Register
+ );
+
+ //
+ // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
+ //
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+
+ DEBUG((EFI_D_INFO, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber));
+ Status = PciScanBus (
+ PciDevice,
+ (UINT8) (SecondBus),
+ SubBusNumber,
+ PaddedBusRange
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {
+ //
+ // Ensure the device is enabled and initialized
+ //
+ if ((Attributes == EfiPaddingPciRootBridge) &&
+ (State & EFI_HPC_STATE_ENABLED) != 0 &&
+ (State & EFI_HPC_STATE_INITIALIZED) != 0) {
+ *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);
+ } else {
+ *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);
+ }
+ }
+
+ //
+ // Set the current maximum bus number under the PPB
+ //
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ SubBusNumber
+ );
+ } else {
+ //
+ // It is device. Check PCI IOV for Bus reservation
+ //
+ if (PciDevice == NULL) {
+ //
+ // No PciDevice found, conitue Scan
+ //
+ continue;
+ }
+ //
+ // Go through each function, just reserve the MAX ReservedBusNum for one device
+ //
+ if ((PciDevice->AriCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
+
+ if (TempReservedBusNum < PciDevice->ReservedBusNum) {
+
+ (*SubBusNumber) = (UINT8)((*SubBusNumber) + PciDevice->ReservedBusNum - TempReservedBusNum);
+ TempReservedBusNum = PciDevice->ReservedBusNum;
+
+ if (Func == 0) {
+ DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x\n", *SubBusNumber));
+ } else {
+ DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x (Update)\n", *SubBusNumber));
+ }
+ }
+ }
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Option Rom on the specified root bridge.
+
+ @param Bridge Pci root bridge device instance.
+
+ @retval EFI_SUCCESS Success process.
+ @retval other Some error occurred when processing Option Rom on the root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeP2CProcess (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_STATUS Status;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
+
+ if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+
+ //
+ // Raise the EFI_IOB_PCI_HPC_INIT status code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,
+ Temp->DevicePath
+ );
+
+ PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
+ Status = gPciHotPlugInit->InitializeRootHpc (
+ gPciHotPlugInit,
+ Temp->DevicePath,
+ PciAddress,
+ NULL,
+ &State
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = PciBridgeEnumerator (Temp);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ continue;
+
+ }
+ }
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ Status = PciRootBridgeP2CProcess (Temp);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Option Rom on the specified host bridge.
+
+ @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Success process.
+ @retval EFI_NOT_FOUND Can not find the root bridge instance.
+ @retval other Some error occurred when processing Option Rom on the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeP2CProcess (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return EFI_SUCCESS;
+ }
+
+ RootBridgeHandle = NULL;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = PciRootBridgeP2CProcess (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to enumerate the entire host bridge
+ in a given platform.
+
+ @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
+
+ @retval EFI_SUCCESS Successfully enumerated the host bridge.
+ @retval EFI_OUT_OF_RESOURCES No enough memory available.
+ @retval other Some error occurred when enumerating the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINT16 MinBus;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
+ UINT8 StartBusNumber;
+ LIST_ENTRY RootBridgeList;
+ LIST_ENTRY *Link;
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ InitializeHotPlugSupport ();
+ }
+
+ InitializeListHead (&RootBridgeList);
+
+ //
+ // Notify the bus allocation phase is about to start
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
+
+ DEBUG((EFI_D_INFO, "PCI Bus First Scanning\n"));
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enumerate all the buses under this root bridge
+ //
+ Status = PciRootBridgeEnumerator (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));
+ } else {
+ DestroyRootBridge (RootBridgeDev);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Notify the bus allocation phase is finished for the first time
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // Reset all assigned PCI bus number in all PPB
+ //
+ RootBridgeHandle = NULL;
+ Link = GetFirstNode (&RootBridgeList);
+ while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&
+ (!IsNull (&RootBridgeList, Link))) {
+ RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);
+ //
+ // Get the Bus information
+ //
+ Status = PciResAlloc->StartBusEnumeration (
+ PciResAlloc,
+ RootBridgeHandle,
+ (VOID **) &Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the bus number to start with
+ //
+ StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
+
+ ResetAllPpbBusNumber (
+ RootBridgeDev,
+ StartBusNumber
+ );
+
+ FreePool (Configuration);
+ Link = GetNextNode (&RootBridgeList, Link);
+ DestroyRootBridge (RootBridgeDev);
+ }
+
+ //
+ // Wait for all HPC initialized
+ //
+ Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the bus allocation phase is about to start for the 2nd time
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
+
+ DEBUG((EFI_D_INFO, "PCI Bus Second Scanning\n"));
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enumerate all the buses under this root bridge
+ //
+ Status = PciRootBridgeEnumerator (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ DestroyRootBridge (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Notify the bus allocation phase is to end for the 2nd time
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
+ }
+
+ //
+ // Notify the resource allocation phase is to start
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);
+
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = StartManagingRootBridge (RootBridgeDev);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
+ Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Determine root bridge attribute by calling interface of Pcihostbridge
+ // protocol
+ //
+ DetermineRootBridgeAttributes (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ //
+ // Collect all the resource information under this root bridge
+ // A database that records all the information about pci device subject to this
+ // root bridge will then be created
+ //
+ Status = PciPciDeviceInfoCollector (
+ RootBridgeDev,
+ (UINT8) MinBus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ InsertRootBridge (RootBridgeDev);
+
+ //
+ // Record the hostbridge handle
+ //
+ AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h
new file mode 100644
index 0000000000..43e3e48f2b
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h
@@ -0,0 +1,144 @@
+/** @file
+ Internal library declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_LIB_H_
+#define _EFI_PCI_LIB_H_
+
+
+typedef struct {
+ EFI_HANDLE Handle;
+} EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD;
+
+typedef struct {
+ UINT32 Bar;
+ UINT16 DevicePathSize;
+ UINT16 ReqResSize;
+ UINT16 AllocResSize;
+ UINT8 *DevicePath;
+ UINT8 *ReqRes;
+ UINT8 *AllocRes;
+} EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD;
+
+
+/**
+ Retrieve the PCI Card device BAR information via PciIo interface.
+
+ @param PciIoDevice PCI Card device instance.
+
+**/
+VOID
+GetBackPcCardBar (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Remove rejected pci device from specific root bridge
+ handle.
+
+ @param RootBridgeHandle Specific parent root bridge handle.
+ @param Bridge Bridge device instance.
+
+**/
+VOID
+RemoveRejectedPciDevices (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
+
+ @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully finished resource allocation.
+ @retval EFI_NOT_FOUND Cannot get root bridge instance.
+ @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
+ @retval other Some error occurred when allocating resources for the PCI Host Bridge.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciHostBridgeResourceAllocator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ Scan pci bus and assign bus number to the given PCI bus system.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber start point.
+ @param SubBusNumber Point to sub bus number.
+ @param PaddedBusRange Customized bus number.
+
+ @retval EFI_SUCCESS Successfully scanned and assigned bus number.
+ @retval other Some error occurred when scanning pci bus.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciScanBus (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber,
+ OUT UINT8 *PaddedBusRange
+ );
+
+/**
+ Process Option Rom on the specified root bridge.
+
+ @param Bridge Pci root bridge device instance.
+
+ @retval EFI_SUCCESS Success process.
+ @retval other Some error occurred when processing Option Rom on the root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeP2CProcess (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Process Option Rom on the specified host bridge.
+
+ @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Success process.
+ @retval EFI_NOT_FOUND Can not find the root bridge instance.
+ @retval other Some error occurred when processing Option Rom on the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeP2CProcess (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ This function is used to enumerate the entire host bridge
+ in a given platform.
+
+ @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
+
+ @retval EFI_SUCCESS Successfully enumerated the host bridge.
+ @retval EFI_OUT_OF_RESOURCES No enough memory available.
+ @retval other Some error occurred when enumerating the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
new file mode 100644
index 0000000000..19803efb2c
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
@@ -0,0 +1,735 @@
+/** @file
+ PCI Rom supporting funtions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+/**
+ Load the EFI Image from Option ROM
+
+ @param PciIoDevice PCI IO device instance.
+ @param FilePath The file path of the EFI Image
+ @param BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to Buffer.
+ On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
+ then no the size of the requested file is returned in BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
+ @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete the request.
+**/
+EFI_STATUS
+LocalLoadFile2 (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *EfiOpRomImageNode;
+ EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
+ PCI_DATA_STRUCTURE *Pcir;
+ UINT32 ImageSize;
+ UINT8 *ImageBuffer;
+ UINT32 ImageLength;
+ UINT32 DestinationSize;
+ UINT32 ScratchSize;
+ VOID *Scratch;
+ EFI_DECOMPRESS_PROTOCOL *Decompress;
+
+ EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath;
+ if ((EfiOpRomImageNode == NULL) ||
+ (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) ||
+ (DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) ||
+ (DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) ||
+ (!IsDevicePathEnd (NextDevicePathNode (FilePath))) ||
+ (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) ||
+ (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) ||
+ (BufferSize == NULL)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (
+ (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset
+ );
+ if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ return EFI_NOT_FOUND;
+ }
+
+
+ Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader + EfiRomHeader->PcirOffset);
+
+
+ if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
+ (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
+ ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
+ (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) &&
+ (EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED)
+ ) {
+
+ ImageSize = (UINT32) EfiRomHeader->InitializationSize * 512;
+ ImageBuffer = (UINT8 *) EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset;
+ ImageLength = ImageSize - EfiRomHeader->EfiImageHeaderOffset;
+
+ if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
+ //
+ // Uncompressed: Copy the EFI Image directly to user's buffer
+ //
+ if (Buffer == NULL || *BufferSize < ImageLength) {
+ *BufferSize = ImageLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = ImageLength;
+ CopyMem (Buffer, ImageBuffer, ImageLength);
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // Compressed: Uncompress before copying
+ //
+ Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ Status = Decompress->GetInfo (
+ Decompress,
+ ImageBuffer,
+ ImageLength,
+ &DestinationSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Buffer == NULL || *BufferSize < DestinationSize) {
+ *BufferSize = DestinationSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = DestinationSize;
+ Scratch = AllocatePool (ScratchSize);
+ if (Scratch == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Decompress->Decompress (
+ Decompress,
+ ImageBuffer,
+ ImageLength,
+ Buffer,
+ DestinationSize,
+ Scratch,
+ ScratchSize
+ );
+ FreePool (Scratch);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Initialize a PCI LoadFile2 instance.
+
+ @param PciIoDevice PCI IO Device.
+
+**/
+VOID
+InitializePciLoadFile2 (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ PciIoDevice->LoadFile2.LoadFile = LoadFile2;
+}
+
+/**
+ Causes the driver to load a specified file.
+
+ @param This Indicates a pointer to the calling context.
+ @param FilePath The device specific path of the file to load.
+ @param BootPolicy Should always be FALSE.
+ @param BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to Buffer.
+ On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
+ then no the size of the requested file is returned in BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_UNSUPPORTED BootPolicy is TRUE.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
+ @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadFile2 (
+ IN EFI_LOAD_FILE2_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+
+ if (BootPolicy) {
+ return EFI_UNSUPPORTED;
+ }
+ PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);
+
+ return LocalLoadFile2 (
+ PciIoDevice,
+ FilePath,
+ BufferSize,
+ Buffer
+ );
+}
+
+/**
+ Get Pci device's oprom information.
+
+ @param PciIoDevice Input Pci device instance.
+ Output Pci device instance with updated OptionRom size.
+
+ @retval EFI_NOT_FOUND Pci device has not Option Rom.
+ @retval EFI_SUCCESS Pci device has Option Rom.
+
+**/
+EFI_STATUS
+GetOpRomInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT8 RomBarIndex;
+ UINT32 AllOnes;
+ UINT64 Address;
+ EFI_STATUS Status;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ Bus = PciIoDevice->BusNumber;
+ Device = PciIoDevice->DeviceNumber;
+ Function = PciIoDevice->FunctionNumber;
+
+ PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
+
+ //
+ // Offset is 0x30 if is not ppb
+ //
+
+ //
+ // 0x30
+ //
+ RomBarIndex = PCI_EXPANSION_ROM_BASE;
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+ //
+ // If is ppb, 0x38
+ //
+ RomBarIndex = PCI_BRIDGE_ROMBAR;
+ }
+ //
+ // The bit0 is 0 to prevent the enabling of the Rom address decoder
+ //
+ AllOnes = 0xfffffffe;
+ Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &AllOnes
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Read back
+ //
+ Status = PciRootBridgeIo->Pci.Read(
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &AllOnes
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Bits [1, 10] are reserved
+ //
+ AllOnes &= 0xFFFFF800;
+ if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the RomImage contains EFI Images.
+
+ @param RomImage The ROM address of Image for check.
+ @param RomSize Size of ROM for check.
+
+ @retval TRUE ROM contain EFI Image.
+ @retval FALSE ROM not contain EFI Image.
+
+**/
+BOOLEAN
+ContainEfiImage (
+ IN VOID *RomImage,
+ IN UINT64 RomSize
+ )
+{
+ PCI_EXPANSION_ROM_HEADER *RomHeader;
+ PCI_DATA_STRUCTURE *RomPcir;
+ BOOLEAN FirstCheck;
+
+ FirstCheck = TRUE;
+ RomHeader = RomImage;
+
+ while ((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) {
+ if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ if (FirstCheck) {
+ return FALSE;
+ } else {
+ RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512);
+ continue;
+ }
+ }
+
+ FirstCheck = FALSE;
+ RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader + RomHeader->PcirOffset);
+
+ if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
+ return TRUE;
+ }
+
+ RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + RomPcir->Length * 512);
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Load Option Rom image for specified PCI device.
+
+ @param PciDevice Pci device instance.
+ @param RomBase Base address of Option Rom.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
+ @retval EFI_SUCESS Successfully loaded Option Rom.
+
+**/
+EFI_STATUS
+LoadOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT64 RomBase
+ )
+{
+ UINT8 RomBarIndex;
+ UINT8 Indicator;
+ UINT16 OffsetPcir;
+ UINT32 RomBarOffset;
+ UINT32 RomBar;
+ EFI_STATUS RetStatus;
+ BOOLEAN FirstCheck;
+ UINT8 *Image;
+ PCI_EXPANSION_ROM_HEADER *RomHeader;
+ PCI_DATA_STRUCTURE *RomPcir;
+ UINT64 RomSize;
+ UINT64 RomImageSize;
+ UINT8 *RomInMemory;
+ UINT8 CodeType;
+
+ RomSize = PciDevice->RomSize;
+
+ Indicator = 0;
+ RomImageSize = 0;
+ RomInMemory = NULL;
+ CodeType = 0xFF;
+
+ //
+ // Get the RomBarIndex
+ //
+
+ //
+ // 0x30
+ //
+ RomBarIndex = PCI_EXPANSION_ROM_BASE;
+ if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
+ //
+ // if is ppb
+ //
+
+ //
+ // 0x38
+ //
+ RomBarIndex = PCI_BRIDGE_ROMBAR;
+ }
+ //
+ // Allocate memory for Rom header and PCIR
+ //
+ RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
+ if (RomHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
+ if (RomPcir == NULL) {
+ FreePool (RomHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RomBar = (UINT32) RomBase;
+
+ //
+ // Enable RomBar
+ //
+ RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
+
+ RomBarOffset = RomBar;
+ RetStatus = EFI_NOT_FOUND;
+ FirstCheck = TRUE;
+
+ do {
+ PciDevice->PciRootBridgeIo->Mem.Read (
+ PciDevice->PciRootBridgeIo,
+ EfiPciWidthUint8,
+ RomBarOffset,
+ sizeof (PCI_EXPANSION_ROM_HEADER),
+ (UINT8 *) RomHeader
+ );
+
+ if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ RomBarOffset = RomBarOffset + 512;
+ if (FirstCheck) {
+ break;
+ } else {
+ RomImageSize = RomImageSize + 512;
+ continue;
+ }
+ }
+
+ FirstCheck = FALSE;
+ OffsetPcir = RomHeader->PcirOffset;
+ PciDevice->PciRootBridgeIo->Mem.Read (
+ PciDevice->PciRootBridgeIo,
+ EfiPciWidthUint8,
+ RomBarOffset + OffsetPcir,
+ sizeof (PCI_DATA_STRUCTURE),
+ (UINT8 *) RomPcir
+ );
+ if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
+ CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
+ }
+ Indicator = RomPcir->Indicator;
+ RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
+ RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
+ } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
+
+ //
+ // Some Legacy Cards do not report the correct ImageLength so used the maximum
+ // of the legacy length and the PCIR Image Length
+ //
+ if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
+ RomImageSize = MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));
+ }
+
+ if (RomImageSize > 0) {
+ RetStatus = EFI_SUCCESS;
+ Image = AllocatePool ((UINT32) RomImageSize);
+ if (Image == NULL) {
+ RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
+ FreePool (RomHeader);
+ FreePool (RomPcir);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy Rom image into memory
+ //
+ PciDevice->PciRootBridgeIo->Mem.Read (
+ PciDevice->PciRootBridgeIo,
+ EfiPciWidthUint8,
+ RomBar,
+ (UINT32) RomImageSize,
+ Image
+ );
+ RomInMemory = Image;
+ }
+
+ RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
+
+ PciDevice->PciIo.RomSize = RomImageSize;
+ PciDevice->PciIo.RomImage = RomInMemory;
+
+ //
+ // For OpROM read from PCI device:
+ // Add the Rom Image to internal database for later PCI light enumeration
+ //
+ PciRomAddImageMapping (
+ NULL,
+ PciDevice->PciRootBridgeIo->SegmentNumber,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ (UINT64) (UINTN) PciDevice->PciIo.RomImage,
+ PciDevice->PciIo.RomSize
+ );
+
+ //
+ // Free allocated memory
+ //
+ FreePool (RomHeader);
+ FreePool (RomPcir);
+
+ return RetStatus;
+}
+
+/**
+ Enable/Disable Option Rom decode.
+
+ @param PciDevice Pci device instance.
+ @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param RomBar Base address of Option Rom.
+ @param Enable Flag for enable/disable decode.
+
+**/
+VOID
+RomDecode (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT8 RomBarIndex,
+ IN UINT32 RomBar,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 Value32;
+ UINT32 Offset;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = &PciDevice->PciIo;
+ if (Enable) {
+ //
+ // Clear all bars
+ //
+ for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);
+ }
+
+ //
+ // set the Rom base address: now is hardcode
+ // enable its decoder
+ //
+ Value32 = RomBar | 0x1;
+ PciIo->Pci.Write (
+ PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
+ RomBarIndex,
+ 1,
+ &Value32
+ );
+
+ //
+ // Programe all upstream bridge
+ //
+ ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);
+
+ //
+ // Setting the memory space bit in the function's command register
+ //
+ PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ } else {
+
+ //
+ // disable command register decode to memory
+ //
+ PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ //
+ // Destroy the programmed bar in all the upstream bridge.
+ //
+ ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);
+
+ //
+ // disable rom decode
+ //
+ Value32 = 0xFFFFFFFE;
+ PciIo->Pci.Write (
+ PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
+ RomBarIndex,
+ 1,
+ &Value32
+ );
+
+ }
+}
+
+/**
+ Load and start the Option Rom image.
+
+ @param PciDevice Pci device instance.
+
+ @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
+ @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
+
+**/
+EFI_STATUS
+ProcessOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice
+ )
+{
+ UINT8 Indicator;
+ UINT32 ImageSize;
+ VOID *RomBar;
+ UINT8 *RomBarOffset;
+ EFI_HANDLE ImageHandle;
+ EFI_STATUS Status;
+ EFI_STATUS RetStatus;
+ BOOLEAN FirstCheck;
+ EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
+ PCI_DATA_STRUCTURE *Pcir;
+ EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;
+ MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;
+ VOID *Buffer;
+ UINTN BufferSize;
+
+ Indicator = 0;
+
+ //
+ // Get the Address of the Option Rom image
+ //
+ RomBar = PciDevice->PciIo.RomImage;
+ RomBarOffset = (UINT8 *) RomBar;
+ RetStatus = EFI_NOT_FOUND;
+ FirstCheck = TRUE;
+
+ do {
+ EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
+ if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ RomBarOffset += 512;
+ if (FirstCheck) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ FirstCheck = FALSE;
+ Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
+ ImageSize = (UINT32) (Pcir->ImageLength * 512);
+ Indicator = Pcir->Indicator;
+
+ //
+ // Create Pci Option Rom Image device path header
+ //
+ EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;
+ EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;
+ SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));
+ EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar;
+ EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;
+
+ PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);
+ ASSERT (PciOptionRomImageDevicePath != NULL);
+
+ //
+ // load image and start image
+ //
+ BufferSize = 0;
+ Buffer = NULL;
+ Status = EFI_SUCCESS;
+ ImageHandle = NULL;
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->LoadImage (
+ FALSE,
+ gPciBusDriverBinding.DriverBindingHandle,
+ PciOptionRomImageDevicePath,
+ Buffer,
+ BufferSize,
+ &ImageHandle
+ );
+ }
+
+ //
+ // load image and start image
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->LoadImage (
+ FALSE,
+ gPciBusDriverBinding.DriverBindingHandle,
+ PciOptionRomImageDevicePath,
+ Buffer,
+ BufferSize,
+ &ImageHandle
+ );
+ }
+
+ FreePool (PciOptionRomImageDevicePath);
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ AddDriver (PciDevice, ImageHandle);
+ PciRomAddImageMapping (
+ ImageHandle,
+ PciDevice->PciRootBridgeIo->SegmentNumber,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ (UINT64) (UINTN) PciDevice->PciIo.RomImage,
+ PciDevice->PciIo.RomSize
+ );
+ RetStatus = EFI_SUCCESS;
+ }
+ }
+
+ RomBarOffset += ImageSize;
+
+ } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
+
+ return RetStatus;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h
new file mode 100644
index 0000000000..4615a5fe33
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h
@@ -0,0 +1,143 @@
+/** @file
+ PCI Rom supporting funtions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_OPTION_ROM_SUPPORT_H_
+#define _EFI_PCI_OPTION_ROM_SUPPORT_H_
+
+
+/**
+ Initialize a PCI LoadFile2 instance.
+
+ @param PciIoDevice PCI IO Device.
+
+**/
+VOID
+InitializePciLoadFile2 (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Causes the driver to load a specified file.
+
+ @param This Indicates a pointer to the calling context.
+ @param FilePath The device specific path of the file to load.
+ @param BootPolicy Should always be FALSE.
+ @param BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to Buffer.
+ On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
+ then no the size of the requested file is returned in BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_UNSUPPORTED BootPolicy is TRUE.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
+ @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadFile2 (
+ IN EFI_LOAD_FILE2_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ );
+
+/**
+ Check if the RomImage contains EFI Images.
+
+ @param RomImage The ROM address of Image for check.
+ @param RomSize Size of ROM for check.
+
+ @retval TRUE ROM contain EFI Image.
+ @retval FALSE ROM not contain EFI Image.
+
+**/
+BOOLEAN
+ContainEfiImage (
+ IN VOID *RomImage,
+ IN UINT64 RomSize
+ );
+
+
+/**
+ Get Pci device's oprom information.
+
+ @param PciIoDevice Input Pci device instance.
+ Output Pci device instance with updated OptionRom size.
+
+ @retval EFI_NOT_FOUND Pci device has not Option Rom.
+ @retval EFI_SUCCESS Pci device has Option Rom.
+
+**/
+EFI_STATUS
+GetOpRomInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Load Option Rom image for specified PCI device.
+
+ @param PciDevice Pci device instance.
+ @param RomBase Base address of Option Rom.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
+ @retval EFI_SUCESS Successfully loaded Option Rom.
+
+**/
+EFI_STATUS
+LoadOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT64 RomBase
+ );
+
+/**
+ Enable/Disable Option Rom decode.
+
+ @param PciDevice Pci device instance.
+ @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param RomBar Base address of Option Rom.
+ @param Enable Flag for enable/disable decode.
+
+**/
+VOID
+RomDecode (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT8 RomBarIndex,
+ IN UINT32 RomBar,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Load and start the Option Rom image.
+
+ @param PciDevice Pci device instance.
+
+ @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
+ @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
+
+**/
+EFI_STATUS
+ProcessOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c
new file mode 100644
index 0000000000..860d427f35
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c
@@ -0,0 +1,68 @@
+/** @file
+ Power management support fucntions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+/**
+ This function is intended to turn off PWE assertion and
+ put the device to D0 state if the device supports
+ PCI Power Management.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval EFI_UNSUPPORTED PCI Device does not support power management.
+ @retval EFI_SUCCESS Turned off PWE successfully.
+
+**/
+EFI_STATUS
+ResetPowerManagementFeature (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ UINT8 PowerManagementRegBlock;
+ UINT16 PowerManagementCSR;
+
+ PowerManagementRegBlock = 0;
+
+ Status = LocateCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCI_CAPABILITY_ID_PMI,
+ &PowerManagementRegBlock,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Turn off the PWE assertion and put the device into D0 State
+ //
+ PowerManagementCSR = 0x8000;
+
+ //
+ // Write PMCSR
+ //
+ PciIoDevice->PciIo.Pci.Write (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint16,
+ PowerManagementRegBlock + 4,
+ 1,
+ &PowerManagementCSR
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h
new file mode 100644
index 0000000000..88462709e3
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h
@@ -0,0 +1,34 @@
+/** @file
+ Power management support fucntions delaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_POWER_MANAGEMENT_H_
+#define _EFI_PCI_POWER_MANAGEMENT_H_
+
+/**
+ This function is intended to turn off PWE assertion and
+ put the device to D0 state if the device supports
+ PCI Power Management.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval EFI_UNSUPPORTED PCI Device does not support power management.
+ @retval EFI_SUCCESS Turned off PWE successfully.
+
+**/
+EFI_STATUS
+ResetPowerManagementFeature (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c
new file mode 100644
index 0000000000..2cacd441c8
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c
@@ -0,0 +1,2344 @@
+/** @file
+ PCI resouces support functions implemntation for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+/**
+ The function is used to skip VGA range.
+
+ @param Start Returned start address including VGA range.
+ @param Length The length of VGA range.
+
+**/
+VOID
+SkipVGAAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ )
+{
+ UINT64 Original;
+ UINT64 Mask;
+ UINT64 StartOffset;
+ UINT64 LimitOffset;
+
+ ASSERT (Start != NULL);
+ //
+ // For legacy VGA, bit 10 to bit 15 is not decoded
+ //
+ Mask = 0x3FF;
+
+ Original = *Start;
+ StartOffset = Original & Mask;
+ LimitOffset = ((*Start) + Length - 1) & Mask;
+ if (LimitOffset >= VGABASE1) {
+ *Start = *Start - StartOffset + VGALIMIT2 + 1;
+ }
+}
+
+/**
+ This function is used to skip ISA aliasing aperture.
+
+ @param Start Returned start address including ISA aliasing aperture.
+ @param Length The length of ISA aliasing aperture.
+
+**/
+VOID
+SkipIsaAliasAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ )
+{
+
+ UINT64 Original;
+ UINT64 Mask;
+ UINT64 StartOffset;
+ UINT64 LimitOffset;
+
+ ASSERT (Start != NULL);
+
+ //
+ // For legacy ISA, bit 10 to bit 15 is not decoded
+ //
+ Mask = 0x3FF;
+
+ Original = *Start;
+ StartOffset = Original & Mask;
+ LimitOffset = ((*Start) + Length - 1) & Mask;
+
+ if (LimitOffset >= ISABASE) {
+ *Start = *Start - StartOffset + ISALIMIT + 1;
+ }
+}
+
+/**
+ This function inserts a resource node into the resource list.
+ The resource list is sorted in descend order.
+
+ @param Bridge PCI resource node for bridge.
+ @param ResNode Resource node want to be inserted.
+
+**/
+VOID
+InsertResourceNode (
+ IN OUT PCI_RESOURCE_NODE *Bridge,
+ IN PCI_RESOURCE_NODE *ResNode
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Temp;
+ UINT64 ResNodeAlignRest;
+ UINT64 TempAlignRest;
+
+ ASSERT (Bridge != NULL);
+ ASSERT (ResNode != NULL);
+
+ InsertHeadList (&Bridge->ChildList, &ResNode->Link);
+
+ CurrentLink = Bridge->ChildList.ForwardLink->ForwardLink;
+ while (CurrentLink != &Bridge->ChildList) {
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (ResNode->Alignment > Temp->Alignment) {
+ break;
+ } else if (ResNode->Alignment == Temp->Alignment) {
+ ResNodeAlignRest = ResNode->Length & ResNode->Alignment;
+ TempAlignRest = Temp->Length & Temp->Alignment;
+ if ((ResNodeAlignRest == 0) || (ResNodeAlignRest >= TempAlignRest)) {
+ break;
+ }
+ }
+
+ SwapListEntries (&ResNode->Link, CurrentLink);
+
+ CurrentLink = ResNode->Link.ForwardLink;
+ }
+}
+
+/**
+ This routine is used to merge two different resource trees in need of
+ resoure degradation.
+
+ For example, if an upstream PPB doesn't support,
+ prefetchable memory decoding, the PCI bus driver will choose to call this function
+ to merge prefectchable memory resource list into normal memory list.
+
+ If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
+ type.
+ If Dst is NULL or Res is NULL, ASSERT ().
+
+ @param Dst Point to destination resource tree.
+ @param Res Point to source resource tree.
+ @param TypeMerge If the TypeMerge is TRUE, Res resource type is changed to the type of
+ destination resource type.
+
+**/
+VOID
+MergeResourceTree (
+ IN PCI_RESOURCE_NODE *Dst,
+ IN PCI_RESOURCE_NODE *Res,
+ IN BOOLEAN TypeMerge
+ )
+{
+
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Temp;
+
+ ASSERT (Dst != NULL);
+ ASSERT (Res != NULL);
+
+ while (!IsListEmpty (&Res->ChildList)) {
+ CurrentLink = Res->ChildList.ForwardLink;
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (TypeMerge) {
+ Temp->ResType = Dst->ResType;
+ }
+
+ RemoveEntryList (CurrentLink);
+ InsertResourceNode (Dst, Temp);
+ }
+}
+
+/**
+ This function is used to calculate the IO16 aperture
+ for a bridge.
+
+ @param Bridge PCI resource node for bridge.
+
+**/
+VOID
+CalculateApertureIo16 (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Aperture;
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Node;
+ UINT64 Offset;
+ BOOLEAN IsaEnable;
+ BOOLEAN VGAEnable;
+ EFI_PCI_PLATFORM_POLICY PciPolicy;
+
+ //
+ // Always assume there is ISA device and VGA device on the platform
+ // will be customized later
+ //
+ IsaEnable = FALSE;
+ VGAEnable = FALSE;
+
+ //
+ // Check PciPlatform policy
+ //
+ if (gPciPlatformProtocol != NULL) {
+ Status = gPciPlatformProtocol->GetPlatformPolicy (
+ gPciPlatformProtocol,
+ &PciPolicy
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) {
+ IsaEnable = TRUE;
+ }
+ if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) {
+ VGAEnable = TRUE;
+ }
+ }
+ } else if (gPciOverrideProtocol != NULL) {
+ Status = gPciOverrideProtocol->GetPlatformPolicy (
+ gPciOverrideProtocol,
+ &PciPolicy
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) {
+ IsaEnable = TRUE;
+ }
+ if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) {
+ VGAEnable = TRUE;
+ }
+ }
+ }
+
+ Aperture = 0;
+
+ if (Bridge == NULL) {
+ return ;
+ }
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ //
+ // Assume the bridge is aligned
+ //
+ while (CurrentLink != &Bridge->ChildList) {
+
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ //
+ // Consider the aperture alignment
+ //
+ Offset = Aperture & (Node->Alignment);
+
+ if (Offset != 0) {
+
+ Aperture = Aperture + (Node->Alignment + 1) - Offset;
+
+ }
+
+ //
+ // IsaEnable and VGAEnable can not be implemented now.
+ // If both of them are enabled, then the IO resource would
+ // become too limited to meet the requirement of most of devices.
+ //
+ if (IsaEnable || VGAEnable) {
+ if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
+ //
+ // Check if there is need to support ISA/VGA decoding
+ // If so, we need to avoid isa/vga aliasing range
+ //
+ if (IsaEnable) {
+ SkipIsaAliasAperture (
+ &Aperture,
+ Node->Length
+ );
+ Offset = Aperture & (Node->Alignment);
+ if (Offset != 0) {
+ Aperture = Aperture + (Node->Alignment + 1) - Offset;
+ }
+ } else if (VGAEnable) {
+ SkipVGAAperture (
+ &Aperture,
+ Node->Length
+ );
+ Offset = Aperture & (Node->Alignment);
+ if (Offset != 0) {
+ Aperture = Aperture + (Node->Alignment + 1) - Offset;
+ }
+ }
+ }
+ }
+
+ Node->Offset = Aperture;
+
+ //
+ // Increment aperture by the length of node
+ //
+ Aperture += Node->Length;
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // At last, adjust the aperture with the bridge's
+ // alignment
+ //
+ Offset = Aperture & (Bridge->Alignment);
+
+ if (Offset != 0) {
+ Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
+ }
+
+ Bridge->Length = Aperture;
+ //
+ // At last, adjust the bridge's alignment to the first child's alignment
+ // if the bridge has at least one child
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ if (CurrentLink != &Bridge->ChildList) {
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+ if (Node->Alignment > Bridge->Alignment) {
+ Bridge->Alignment = Node->Alignment;
+ }
+ }
+}
+
+/**
+ This function is used to calculate the resource aperture
+ for a given bridge device.
+
+ @param Bridge PCI resouce node for given bridge device.
+
+**/
+VOID
+CalculateResourceAperture (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ UINT64 Aperture;
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Node;
+
+ UINT64 Offset;
+
+ Aperture = 0;
+
+ if (Bridge == NULL) {
+ return ;
+ }
+
+ if (Bridge->ResType == PciBarTypeIo16) {
+
+ CalculateApertureIo16 (Bridge);
+ return ;
+ }
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ //
+ // Assume the bridge is aligned
+ //
+ while (CurrentLink != &Bridge->ChildList) {
+
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ //
+ // Apply padding resource if available
+ //
+ Offset = Aperture & (Node->Alignment);
+
+ if (Offset != 0) {
+
+ Aperture = Aperture + (Node->Alignment + 1) - Offset;
+
+ }
+
+ //
+ // Recode current aperture as a offset
+ // this offset will be used in future real allocation
+ //
+ Node->Offset = Aperture;
+
+ //
+ // Increment aperture by the length of node
+ //
+ Aperture += Node->Length;
+
+ //
+ // Consider the aperture alignment
+ //
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // At last, adjust the aperture with the bridge's
+ // alignment
+ //
+ Offset = Aperture & (Bridge->Alignment);
+ if (Offset != 0) {
+ Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
+ }
+
+ //
+ // If the bridge has already padded the resource and the
+ // amount of padded resource is larger, then keep the
+ // padded resource
+ //
+ if (Bridge->Length < Aperture) {
+ Bridge->Length = Aperture;
+ }
+
+ //
+ // At last, adjust the bridge's alignment to the first child's alignment
+ // if the bridge has at least one child
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ if (CurrentLink != &Bridge->ChildList) {
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+ if (Node->Alignment > Bridge->Alignment) {
+ Bridge->Alignment = Node->Alignment;
+ }
+ }
+}
+
+/**
+ Get IO/Memory resource infor for given PCI device.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO .
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+GetResourceFromDevice (
+ IN PCI_IO_DEVICE *PciDev,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+
+ UINT8 Index;
+ PCI_RESOURCE_NODE *Node;
+ BOOLEAN ResourceRequested;
+
+ Node = NULL;
+ ResourceRequested = FALSE;
+
+ for (Index = 0; Index < PCI_MAX_BAR; Index++) {
+
+ switch ((PciDev->PciBar)[Index].BarType) {
+
+ case PciBarTypeMem32:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypeMem64:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem64Node,
+ Node
+ );
+
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypePMem64:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem64Node,
+ Node
+ );
+
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypePMem32:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypeUnknown:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // Add VF resource
+ //
+ for (Index = 0; Index < PCI_MAX_BAR; Index++) {
+
+ switch ((PciDev->VfPciBar)[Index].BarType) {
+
+ case PciBarTypeMem32:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+
+ break;
+
+ case PciBarTypeMem64:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem64Node,
+ Node
+ );
+
+ break;
+
+ case PciBarTypePMem64:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem64Node,
+ Node
+ );
+
+ break;
+
+ case PciBarTypePMem32:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+ break;
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ break;
+
+ case PciBarTypeUnknown:
+ break;
+
+ default:
+ break;
+ }
+ }
+ // If there is no resource requested from this device,
+ // then we indicate this device has been allocated naturally.
+ //
+ if (!ResourceRequested) {
+ PciDev->Allocated = TRUE;
+ }
+}
+
+/**
+ This function is used to create a resource node.
+
+ @param PciDev Pci device instance.
+ @param Length Length of Io/Memory resource.
+ @param Alignment Alignment of resource.
+ @param Bar Bar index.
+ @param ResType Type of resource: IO/Memory.
+ @param ResUsage Resource usage.
+
+ @return PCI resource node created for given PCI device.
+ NULL means PCI resource node is not created.
+
+**/
+PCI_RESOURCE_NODE *
+CreateResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ )
+{
+ PCI_RESOURCE_NODE *Node;
+
+ Node = NULL;
+
+ Node = AllocateZeroPool (sizeof (PCI_RESOURCE_NODE));
+ ASSERT (Node != NULL);
+ if (Node == NULL) {
+ return NULL;
+ }
+
+ Node->Signature = PCI_RESOURCE_SIGNATURE;
+ Node->PciDev = PciDev;
+ Node->Length = Length;
+ Node->Alignment = Alignment;
+ Node->Bar = Bar;
+ Node->ResType = ResType;
+ Node->Reserved = FALSE;
+ Node->ResourceUsage = ResUsage;
+ InitializeListHead (&Node->ChildList);
+
+ return Node;
+}
+
+/**
+ This function is used to create a IOV VF resource node.
+
+ @param PciDev Pci device instance.
+ @param Length Length of Io/Memory resource.
+ @param Alignment Alignment of resource.
+ @param Bar Bar index.
+ @param ResType Type of resource: IO/Memory.
+ @param ResUsage Resource usage.
+
+ @return PCI resource node created for given VF PCI device.
+ NULL means PCI resource node is not created.
+
+**/
+PCI_RESOURCE_NODE *
+CreateVfResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ )
+{
+ PCI_RESOURCE_NODE *Node;
+
+ DEBUG ((
+ EFI_D_INFO,
+ "PCI-IOV B%x.D%x.F%x - VfResource (Bar - 0x%x) (Type - 0x%x) (Length - 0x%x)\n",
+ (UINTN)PciDev->BusNumber,
+ (UINTN)PciDev->DeviceNumber,
+ (UINTN)PciDev->FunctionNumber,
+ (UINTN)Bar,
+ (UINTN)ResType,
+ (UINTN)Length
+ ));
+
+ Node = CreateResourceNode (PciDev, Length, Alignment, Bar, ResType, ResUsage);
+ if (Node == NULL) {
+ return Node;
+ }
+
+ Node->Virtual = TRUE;
+
+ return Node;
+}
+
+/**
+ This function is used to extract resource request from
+ device node list.
+
+ @param Bridge Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+CreateResourceMap (
+ IN PCI_IO_DEVICE *Bridge,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ PCI_RESOURCE_NODE *IoBridge;
+ PCI_RESOURCE_NODE *Mem32Bridge;
+ PCI_RESOURCE_NODE *PMem32Bridge;
+ PCI_RESOURCE_NODE *Mem64Bridge;
+ PCI_RESOURCE_NODE *PMem64Bridge;
+ LIST_ENTRY *CurrentLink;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ //
+ // Create resource nodes for this device by scanning the
+ // Bar array in the device private data
+ // If the upstream bridge doesn't support this device,
+ // no any resource node will be created for this device
+ //
+ GetResourceFromDevice (
+ Temp,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+
+ if (IS_PCI_BRIDGE (&Temp->Pci)) {
+
+ //
+ // If the device has children, create a bridge resource node for this PPB
+ // Note: For PPB, memory aperture is aligned with 1MB and IO aperture
+ // is aligned with 4KB
+ // This device is typically a bridge device like PPB and P2C
+ // Note: 0x1000 aligned
+ //
+ IoBridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFF,
+ PPB_IO_RANGE,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ Mem32Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_MEM32_RANGE,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ PMem32Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_PMEM32_RANGE,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ Mem64Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_MEM64_RANGE,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ PMem64Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_PMEM64_RANGE,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ //
+ // Recursively create resouce map on this bridge
+ //
+ CreateResourceMap (
+ Temp,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge
+ );
+
+ if (ResourceRequestExisted (IoBridge)) {
+ InsertResourceNode (
+ IoNode,
+ IoBridge
+ );
+ } else {
+ FreePool (IoBridge);
+ IoBridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (Mem32Bridge)) {
+ InsertResourceNode (
+ Mem32Node,
+ Mem32Bridge
+ );
+ } else {
+ FreePool (Mem32Bridge);
+ Mem32Bridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (PMem32Bridge)) {
+ InsertResourceNode (
+ PMem32Node,
+ PMem32Bridge
+ );
+ } else {
+ FreePool (PMem32Bridge);
+ PMem32Bridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (Mem64Bridge)) {
+ InsertResourceNode (
+ Mem64Node,
+ Mem64Bridge
+ );
+ } else {
+ FreePool (Mem64Bridge);
+ Mem64Bridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (PMem64Bridge)) {
+ InsertResourceNode (
+ PMem64Node,
+ PMem64Bridge
+ );
+ } else {
+ FreePool (PMem64Bridge);
+ PMem64Bridge = NULL;
+ }
+
+ }
+
+ //
+ // If it is P2C, apply hard coded resource padding
+ //
+ if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
+ ResourcePaddingForCardBusBridge (
+ Temp,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // To do some platform specific resource padding ...
+ //
+ ResourcePaddingPolicy (
+ Bridge,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+
+ //
+ // Degrade resource if necessary
+ //
+ DegradeResource (
+ Bridge,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+
+ //
+ // Calculate resource aperture for this bridge device
+ //
+ CalculateResourceAperture (Mem32Node);
+ CalculateResourceAperture (PMem32Node);
+ CalculateResourceAperture (Mem64Node);
+ CalculateResourceAperture (PMem64Node);
+ CalculateResourceAperture (IoNode);
+}
+
+/**
+ This function is used to do the resource padding for a specific platform.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingPolicy (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ //
+ // Create padding resource node
+ //
+ if (PciDev->ResourcePaddingDescriptors != NULL) {
+ ApplyResourcePadding (
+ PciDev,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+ }
+}
+
+/**
+ This function is used to degrade resource if the upstream bridge
+ doesn't support certain resource. Degradation path is
+ PMEM64 -> MEM64 -> MEM32
+ PMEM64 -> PMEM32 -> MEM32
+ IO32 -> IO16.
+
+ @param Bridge Pci device instance.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+DegradeResource (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ BOOLEAN HasOprom;
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ //
+ // For RootBridge, PPB , P2C, go recursively to traverse all its children
+ // to find if this bridge and downstream has OptionRom.
+ //
+ HasOprom = FALSE;
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (Temp->RomSize != 0) {
+ HasOprom = TRUE;
+ break;
+ }
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // If bridge doesn't support Prefetchable
+ // memory64, degrade it to Prefetchable memory32
+ //
+ if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
+ MergeResourceTree (
+ PMem32Node,
+ PMem64Node,
+ TRUE
+ );
+ } else {
+ //
+ // if no PMem32 request and no OptionRom request, still keep PMem64. Otherwise degrade to PMem32
+ //
+ if ((PMem32Node != NULL && (PMem32Node->Length != 0 && Bridge->Parent != NULL)) || HasOprom) {
+ //
+ // Fixed the issue that there is no resource for 64-bit (above 4G)
+ //
+ MergeResourceTree (
+ PMem32Node,
+ PMem64Node,
+ TRUE
+ );
+ }
+ }
+
+
+ //
+ // If bridge doesn't support Mem64
+ // degrade it to mem32
+ //
+ if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
+ MergeResourceTree (
+ Mem32Node,
+ Mem64Node,
+ TRUE
+ );
+ }
+
+ //
+ // If bridge doesn't support Pmem32
+ // degrade it to mem32
+ //
+ if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
+ MergeResourceTree (
+ Mem32Node,
+ PMem32Node,
+ TRUE
+ );
+ }
+
+ //
+ // if bridge supports combined Pmem Mem decoding
+ // merge these two type of resource
+ //
+ if (BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {
+ MergeResourceTree (
+ Mem32Node,
+ PMem32Node,
+ FALSE
+ );
+
+ MergeResourceTree (
+ Mem64Node,
+ PMem64Node,
+ FALSE
+ );
+ }
+}
+
+/**
+ Test whether bridge device support decode resource.
+
+ @param Bridge Bridge device instance.
+ @param Decode Decode type according to resource type.
+
+ @return TRUE The bridge device support decode resource.
+ @return FALSE The bridge device don't support decode resource.
+
+**/
+BOOLEAN
+BridgeSupportResourceDecode (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT32 Decode
+ )
+{
+ if (((Bridge->Decodes) & Decode) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function is used to program the resource allocated
+ for each resource node under specified bridge.
+
+ @param Base Base address of resource to be progammed.
+ @param Bridge PCI resource node for the bridge device.
+
+ @retval EFI_SUCCESS Successfully to program all resouces
+ on given PCI bridge device.
+ @retval EFI_OUT_OF_RESOURCES Base is all one.
+
+**/
+EFI_STATUS
+ProgramResource (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Node;
+ EFI_STATUS Status;
+
+ if (Base == gAllOne) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != &Bridge->ChildList) {
+
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {
+
+ if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
+ //
+ // Program the PCI Card Bus device
+ //
+ ProgramP2C (Base, Node);
+ } else {
+ //
+ // Program the PCI device BAR
+ //
+ ProgramBar (Base, Node);
+ }
+ } else {
+ //
+ // Program the PCI devices under this bridge
+ //
+ Status = ProgramResource (Base + Node->Offset, Node);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ProgramPpbApperture (Base, Node);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Program Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be progammed.
+ @param Node Point to resoure node structure.
+
+**/
+VOID
+ProgramBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT32 Address32;
+
+ ASSERT (Node->Bar < PCI_MAX_BAR);
+
+ //
+ // Check VF BAR
+ //
+ if (Node->Virtual) {
+ ProgramVfBar (Base, Node);
+ }
+
+ Address = 0;
+ PciIo = &(Node->PciDev->PciIo);
+
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate pci bus driver has allocated
+ // resource for this device
+ // It might be a temporary solution here since
+ // pci device could have multiple bar
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ case PciBarTypeMem32:
+ case PciBarTypePMem32:
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+
+ break;
+
+ case PciBarTypeMem64:
+ case PciBarTypePMem64:
+
+ Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 (Address, 32);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Program IOV VF Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be progammed.
+ @param Node Point to resoure node structure.
+
+**/
+EFI_STATUS
+ProgramVfBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT32 Address32;
+
+ ASSERT (Node->Bar < PCI_MAX_BAR);
+ ASSERT (Node->Virtual);
+
+ Address = 0;
+ PciIo = &(Node->PciDev->PciIo);
+
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate pci bus driver has allocated
+ // resource for this device
+ // It might be a temporary solution here since
+ // pci device could have multiple bar
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch ((Node->PciDev->VfPciBar[Node->Bar]).BarType) {
+
+ case PciBarTypeMem32:
+ case PciBarTypePMem32:
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->VfPciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+
+ Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
+
+ DEBUG ((
+ EFI_D_INFO,
+ "PCI-IOV B%x.D%x.F%x - VF Bar (Offset - 0x%x) 32Mem (Address - 0x%x)\n",
+ (UINTN)Node->PciDev->BusNumber,
+ (UINTN)Node->PciDev->DeviceNumber,
+ (UINTN)Node->PciDev->FunctionNumber,
+ (UINTN)(Node->PciDev->VfPciBar[Node->Bar]).Offset,
+ (UINTN)Address
+ ));
+
+ break;
+
+ case PciBarTypeMem64:
+ case PciBarTypePMem64:
+
+ Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->VfPciBar[Node->Bar]).Offset,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 (Address, 32);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4),
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
+
+ DEBUG ((
+ EFI_D_INFO,
+ "PCI-IOV B%x.D%x.F%x - VF Bar (Offset - 0x%x) 64Mem (Address - 0x%lx)\n",
+ (UINTN)Node->PciDev->BusNumber,
+ (UINTN)Node->PciDev->DeviceNumber,
+ (UINTN)Node->PciDev->FunctionNumber,
+ (UINTN)(Node->PciDev->VfPciBar[Node->Bar]).Offset,
+ (UINT64)Address
+ ));
+
+ break;
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ break;
+
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Program PCI-PCI bridge apperture.
+
+ @param Base Base address for resource.
+ @param Node Point to resoure node structure.
+
+**/
+VOID
+ProgramPpbApperture (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT32 Address32;
+
+ Address = 0;
+ //
+ // If no device resource of this PPB, return anyway
+ // Apperture is set default in the initialization code
+ //
+ if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {
+ //
+ // For padding resource node, just ignore when programming
+ //
+ return ;
+ }
+
+ PciIo = &(Node->PciDev->PciIo);
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate the PPB resource has been allocated
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch (Node->Bar) {
+
+ case PPB_BAR_0:
+ case PPB_BAR_1:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+
+ break;
+
+ case PPB_IO_RANGE:
+
+ Address32 = ((UINT32) (Address)) >> 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x1C,
+ 1,
+ &Address32
+ );
+
+ Address32 >>= 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x30,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) (Address + Node->Length - 1);
+ Address32 = ((UINT32) (Address32)) >> 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x1D,
+ 1,
+ &Address32
+ );
+
+ Address32 >>= 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x32,
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ case PPB_MEM32_RANGE:
+
+ Address32 = ((UINT32) (Address)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x20,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) (Address + Node->Length - 1);
+ Address32 = ((UINT32) (Address32)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x22,
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ case PPB_PMEM32_RANGE:
+ case PPB_PMEM64_RANGE:
+
+ Address32 = ((UINT32) (Address)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x24,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) (Address + Node->Length - 1);
+ Address32 = ((UINT32) (Address32)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x26,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 (Address, 32);
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0x28,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0x2C,
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Program parent bridge for Option Rom.
+
+ @param PciDevice Pci deivce instance.
+ @param OptionRomBase Base address for Optiona Rom.
+ @param Enable Enable or disable PCI memory.
+
+**/
+VOID
+ProgrameUpstreamBridgeForRom (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT32 OptionRomBase,
+ IN BOOLEAN Enable
+ )
+{
+ PCI_IO_DEVICE *Parent;
+ PCI_RESOURCE_NODE Node;
+ //
+ // For root bridge, just return.
+ //
+ Parent = PciDevice->Parent;
+ ZeroMem (&Node, sizeof (Node));
+ while (Parent != NULL) {
+ if (!IS_PCI_BRIDGE (&Parent->Pci)) {
+ break;
+ }
+
+ Node.PciDev = Parent;
+ Node.Length = PciDevice->RomSize;
+ Node.Alignment = 0;
+ Node.Bar = PPB_MEM32_RANGE;
+ Node.ResType = PciBarTypeMem32;
+ Node.Offset = 0;
+
+ //
+ // Program PPB to only open a single <= 16MB apperture
+ //
+ if (Enable) {
+ ProgramPpbApperture (OptionRomBase, &Node);
+ PCI_ENABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
+ } else {
+ InitializePpb (Parent);
+ PCI_DISABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
+ }
+
+ Parent = Parent->Parent;
+ }
+}
+
+/**
+ Test whether resource exists for a bridge.
+
+ @param Bridge Point to resource node for a bridge.
+
+ @retval TRUE There is resource on the given bridge.
+ @retval FALSE There isn't resource on the given bridge.
+
+**/
+BOOLEAN
+ResourceRequestExisted (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ if (Bridge != NULL) {
+ if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Initialize resource pool structure.
+
+ @param ResourcePool Point to resource pool structure. This pool
+ is reset to all zero when returned.
+ @param ResourceType Type of resource.
+
+**/
+VOID
+InitializeResourcePool (
+ IN OUT PCI_RESOURCE_NODE *ResourcePool,
+ IN PCI_BAR_TYPE ResourceType
+ )
+{
+ ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
+ ResourcePool->ResType = ResourceType;
+ ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
+ InitializeListHead (&ResourcePool->ChildList);
+}
+
+
+/**
+ Get all resource information for given Pci device.
+
+ @param PciDev Pci device instance.
+ @param IoBridge Io resource node.
+ @param Mem32Bridge 32-bit memory node.
+ @param PMem32Bridge 32-bit Pmemory node.
+ @param Mem64Bridge 64-bit memory node.
+ @param PMem64Bridge 64-bit PMemory node.
+ @param IoPool Link list header for Io resource.
+ @param Mem32Pool Link list header for 32-bit memory.
+ @param PMem32Pool Link list header for 32-bit Prefetchable memory.
+ @param Mem64Pool Link list header for 64-bit memory.
+ @param PMem64Pool Link list header for 64-bit Prefetchable memory.
+
+**/
+VOID
+GetResourceMap (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE **IoBridge,
+ IN PCI_RESOURCE_NODE **Mem32Bridge,
+ IN PCI_RESOURCE_NODE **PMem32Bridge,
+ IN PCI_RESOURCE_NODE **Mem64Bridge,
+ IN PCI_RESOURCE_NODE **PMem64Bridge,
+ IN PCI_RESOURCE_NODE *IoPool,
+ IN PCI_RESOURCE_NODE *Mem32Pool,
+ IN PCI_RESOURCE_NODE *PMem32Pool,
+ IN PCI_RESOURCE_NODE *Mem64Pool,
+ IN PCI_RESOURCE_NODE *PMem64Pool
+ )
+{
+
+ PCI_RESOURCE_NODE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ CurrentLink = IoPool->ChildList.ForwardLink;
+
+ //
+ // Get Io resource map
+ //
+ while (CurrentLink != &IoPool->ChildList) {
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (Temp->PciDev == PciDev) {
+ *IoBridge = Temp;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Get Mem32 resource map
+ //
+ CurrentLink = Mem32Pool->ChildList.ForwardLink;
+
+ while (CurrentLink != &Mem32Pool->ChildList) {
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (Temp->PciDev == PciDev) {
+ *Mem32Bridge = Temp;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Get Pmem32 resource map
+ //
+ CurrentLink = PMem32Pool->ChildList.ForwardLink;
+
+ while (CurrentLink != &PMem32Pool->ChildList) {
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (Temp->PciDev == PciDev) {
+ *PMem32Bridge = Temp;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Get Mem64 resource map
+ //
+ CurrentLink = Mem64Pool->ChildList.ForwardLink;
+
+ while (CurrentLink != &Mem64Pool->ChildList) {
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (Temp->PciDev == PciDev) {
+ *Mem64Bridge = Temp;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Get Pmem64 resource map
+ //
+ CurrentLink = PMem64Pool->ChildList.ForwardLink;
+
+ while (CurrentLink != &PMem64Pool->ChildList) {
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (Temp->PciDev == PciDev) {
+ *PMem64Bridge = Temp;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ Destory given resource tree.
+
+ @param Bridge PCI resource root node of resource tree.
+
+**/
+VOID
+DestroyResourceTree (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ PCI_RESOURCE_NODE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ while (!IsListEmpty (&Bridge->ChildList)) {
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+ ASSERT (Temp);
+
+ RemoveEntryList (CurrentLink);
+
+ if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
+ DestroyResourceTree (Temp);
+ }
+
+ FreePool (Temp);
+ }
+}
+
+/**
+ Insert resource padding for P2C.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingForCardBusBridge (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ PCI_RESOURCE_NODE *Node;
+
+ Node = NULL;
+
+ //
+ // Memory Base/Limit Register 0
+ // Bar 1 denodes memory range 0
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x2000000,
+ 0x1ffffff,
+ 1,
+ PciBarTypeMem32,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+
+ //
+ // Memory Base/Limit Register 1
+ // Bar 2 denodes memory range1
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x2000000,
+ 0x1ffffff,
+ 2,
+ PciBarTypePMem32,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+
+ //
+ // Io Base/Limit
+ // Bar 3 denodes io range 0
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x100,
+ 0xff,
+ 3,
+ PciBarTypeIo16,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+
+ //
+ // Io Base/Limit
+ // Bar 4 denodes io range 0
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x100,
+ 0xff,
+ 4,
+ PciBarTypeIo16,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+}
+
+/**
+ Program PCI Card device register for given resource node.
+
+ @param Base Base address of PCI Card device to be programmed.
+ @param Node Given resource node.
+
+**/
+VOID
+ProgramP2C (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT64 TempAddress;
+ UINT16 BridgeControl;
+
+ Address = 0;
+ PciIo = &(Node->PciDev->PciIo);
+
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate pci bus driver has allocated
+ // resource for this device
+ // It might be a temporary solution here since
+ // pci device could have multiple bar
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch (Node->Bar) {
+
+ case P2C_BAR_0:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ case P2C_MEM_1:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_0,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_LIMIT_0,
+ 1,
+ &TempAddress
+ );
+
+ if (Node->ResType == PciBarTypeMem32) {
+ //
+ // Set non-prefetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl &= (UINT16) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ } else {
+ //
+ // Set pre-fetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+ }
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+
+ break;
+
+ case P2C_MEM_2:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_1,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_LIMIT_1,
+ 1,
+ &TempAddress
+ );
+
+ if (Node->ResType == PciBarTypeMem32) {
+
+ //
+ // Set non-prefetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl &= (UINT16) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE);
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ } else {
+
+ //
+ // Set pre-fetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+ }
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+ break;
+
+ case P2C_IO_1:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_0_LOWER,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_LIMIT_0_LOWER,
+ 1,
+ &TempAddress
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+
+ break;
+
+ case P2C_IO_2:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_1_LOWER,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_LIMIT_1_LOWER,
+ 1,
+ &TempAddress
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Create padding resource node.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ApplyResourcePadding (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+ PCI_RESOURCE_NODE *Node;
+ UINT8 DummyBarIndex;
+
+ DummyBarIndex = 0;
+ Ptr = PciDev->ResourcePaddingDescriptors;
+
+ while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {
+
+ if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
+ if (Ptr->AddrLen != 0) {
+
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypeIo16,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+
+ if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+
+ if (Ptr->AddrSpaceGranularity == 32) {
+
+ //
+ // prefechable
+ //
+ if (Ptr->SpecificFlag == 0x6) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypePMem32,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+
+ //
+ // Non-prefechable
+ //
+ if (Ptr->SpecificFlag == 0) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypeMem32,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+ }
+
+ if (Ptr->AddrSpaceGranularity == 64) {
+
+ //
+ // prefechable
+ //
+ if (Ptr->SpecificFlag == 0x6) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypePMem64,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ PMem64Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+
+ //
+ // Non-prefechable
+ //
+ if (Ptr->SpecificFlag == 0) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypeMem64,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ Mem64Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+ }
+ }
+
+ Ptr++;
+ }
+}
+
+/**
+ Get padding resource for PCI-PCI bridge.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determines
+ whether need to pad resource for them.
+**/
+VOID
+GetResourcePaddingPpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
+ GetResourcePaddingForHpb (PciIoDevice);
+ }
+ }
+}
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h
new file mode 100644
index 0000000000..faa6c0d60c
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h
@@ -0,0 +1,492 @@
+/** @file
+ PCI resouces support functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_RESOURCE_SUPPORT_H_
+#define _EFI_PCI_RESOURCE_SUPPORT_H_
+
+typedef enum {
+ PciResUsageTypical = 0,
+ PciResUsagePadding,
+ PciResUsageOptionRomProcessing
+} PCI_RESOURCE_USAGE;
+
+#define PCI_RESOURCE_SIGNATURE SIGNATURE_32 ('p', 'c', 'r', 'c')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ LIST_ENTRY ChildList;
+ PCI_IO_DEVICE *PciDev;
+ UINT64 Alignment;
+ UINT64 Offset;
+ UINT8 Bar;
+ PCI_BAR_TYPE ResType;
+ UINT64 Length;
+ BOOLEAN Reserved;
+ PCI_RESOURCE_USAGE ResourceUsage;
+ BOOLEAN Virtual;
+} PCI_RESOURCE_NODE;
+
+#define RESOURCE_NODE_FROM_LINK(a) \
+ CR (a, PCI_RESOURCE_NODE, Link, PCI_RESOURCE_SIGNATURE)
+
+/**
+ The function is used to skip VGA range.
+
+ @param Start Returned start address including VGA range.
+ @param Length The length of VGA range.
+
+**/
+VOID
+SkipVGAAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ );
+
+/**
+ This function is used to skip ISA aliasing aperture.
+
+ @param Start Returned start address including ISA aliasing aperture.
+ @param Length The length of ISA aliasing aperture.
+
+**/
+VOID
+SkipIsaAliasAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ );
+
+/**
+ This function inserts a resource node into the resource list.
+ The resource list is sorted in descend order.
+
+ @param Bridge PCI resource node for bridge.
+ @param ResNode Resource node want to be inserted.
+
+**/
+VOID
+InsertResourceNode (
+ IN OUT PCI_RESOURCE_NODE *Bridge,
+ IN PCI_RESOURCE_NODE *ResNode
+ );
+
+/**
+ This routine is used to merge two different resource trees in need of
+ resoure degradation.
+
+ For example, if an upstream PPB doesn't support,
+ prefetchable memory decoding, the PCI bus driver will choose to call this function
+ to merge prefectchable memory resource list into normal memory list.
+
+ If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
+ type.
+ If Dst is NULL or Res is NULL, ASSERT ().
+
+ @param Dst Point to destination resource tree.
+ @param Res Point to source resource tree.
+ @param TypeMerge If the TypeMerge is TRUE, Res resource type is changed to the type of
+ destination resource type.
+
+**/
+VOID
+MergeResourceTree (
+ IN PCI_RESOURCE_NODE *Dst,
+ IN PCI_RESOURCE_NODE *Res,
+ IN BOOLEAN TypeMerge
+ );
+
+/**
+ This function is used to calculate the IO16 aperture
+ for a bridge.
+
+ @param Bridge PCI resource node for bridge.
+
+**/
+VOID
+CalculateApertureIo16 (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ This function is used to calculate the resource aperture
+ for a given bridge device.
+
+ @param Bridge PCI resouce node for given bridge device.
+
+**/
+VOID
+CalculateResourceAperture (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Get IO/Memory resource infor for given PCI device.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO .
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+GetResourceFromDevice (
+ IN PCI_IO_DEVICE *PciDev,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ This function is used to create a resource node.
+
+ @param PciDev Pci device instance.
+ @param Length Length of Io/Memory resource.
+ @param Alignment Alignment of resource.
+ @param Bar Bar index.
+ @param ResType Type of resource: IO/Memory.
+ @param ResUsage Resource usage.
+
+ @return PCI resource node created for given PCI device.
+ NULL means PCI resource node is not created.
+
+**/
+PCI_RESOURCE_NODE *
+CreateResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ );
+
+/**
+ This function is used to extract resource request from
+ IOV VF device node list.
+
+ @param Bridge Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+PCI_RESOURCE_NODE *
+CreateVfResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ );
+
+/**
+ This function is used to extract resource request from
+ device node list.
+
+ @param Bridge Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+CreateResourceMap (
+ IN PCI_IO_DEVICE *Bridge,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ This function is used to do the resource padding for a specific platform.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingPolicy (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ This function is used to degrade resource if the upstream bridge
+ doesn't support certain resource. Degradation path is
+ PMEM64 -> MEM64 -> MEM32
+ PMEM64 -> PMEM32 -> MEM32
+ IO32 -> IO16.
+
+ @param Bridge Pci device instance.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+DegradeResource (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ Test whether bridge device support decode resource.
+
+ @param Bridge Bridge device instance.
+ @param Decode Decode type according to resource type.
+
+ @return TRUE The bridge device support decode resource.
+ @return FALSE The bridge device don't support decode resource.
+
+**/
+BOOLEAN
+BridgeSupportResourceDecode (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT32 Decode
+ );
+
+/**
+ This function is used to program the resource allocated
+ for each resource node under specified bridge.
+
+ @param Base Base address of resource to be progammed.
+ @param Bridge PCI resource node for the bridge device.
+
+ @retval EFI_SUCCESS Successfully to program all resouces
+ on given PCI bridge device.
+ @retval EFI_OUT_OF_RESOURCES Base is all one.
+
+**/
+EFI_STATUS
+ProgramResource (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Program Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be progammed.
+ @param Node Point to resoure node structure.
+
+**/
+VOID
+ProgramBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Program IOV VF Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be progammed.
+ @param Node Point to resoure node structure.
+
+**/
+EFI_STATUS
+ProgramVfBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Program PCI-PCI bridge apperture.
+
+ @param Base Base address for resource.
+ @param Node Point to resoure node structure.
+
+**/
+VOID
+ProgramPpbApperture (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Program parent bridge for Option Rom.
+
+ @param PciDevice Pci deivce instance.
+ @param OptionRomBase Base address for Optiona Rom.
+ @param Enable Enable or disable PCI memory.
+
+**/
+VOID
+ProgrameUpstreamBridgeForRom (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT32 OptionRomBase,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Test whether resource exists for a bridge.
+
+ @param Bridge Point to resource node for a bridge.
+
+ @retval TRUE There is resource on the given bridge.
+ @retval FALSE There isn't resource on the given bridge.
+
+**/
+BOOLEAN
+ResourceRequestExisted (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Initialize resource pool structure.
+
+ @param ResourcePool Point to resource pool structure. This pool
+ is reset to all zero when returned.
+ @param ResourceType Type of resource.
+
+**/
+VOID
+InitializeResourcePool (
+ IN OUT PCI_RESOURCE_NODE *ResourcePool,
+ IN PCI_BAR_TYPE ResourceType
+ );
+
+/**
+ Get all resource information for given Pci device.
+
+ @param PciDev Pci device instance.
+ @param IoBridge Io resource node.
+ @param Mem32Bridge 32-bit memory node.
+ @param PMem32Bridge 32-bit Pmemory node.
+ @param Mem64Bridge 64-bit memory node.
+ @param PMem64Bridge 64-bit PMemory node.
+ @param IoPool Link list header for Io resource.
+ @param Mem32Pool Link list header for 32-bit memory.
+ @param PMem32Pool Link list header for 32-bit Prefetchable memory.
+ @param Mem64Pool Link list header for 64-bit memory.
+ @param PMem64Pool Link list header for 64-bit Prefetchable memory.
+
+**/
+VOID
+GetResourceMap (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE **IoBridge,
+ IN PCI_RESOURCE_NODE **Mem32Bridge,
+ IN PCI_RESOURCE_NODE **PMem32Bridge,
+ IN PCI_RESOURCE_NODE **Mem64Bridge,
+ IN PCI_RESOURCE_NODE **PMem64Bridge,
+ IN PCI_RESOURCE_NODE *IoPool,
+ IN PCI_RESOURCE_NODE *Mem32Pool,
+ IN PCI_RESOURCE_NODE *PMem32Pool,
+ IN PCI_RESOURCE_NODE *Mem64Pool,
+ IN PCI_RESOURCE_NODE *PMem64Pool
+ );
+
+/**
+ Destory given resource tree.
+
+ @param Bridge PCI resource root node of resource tree.
+
+**/
+VOID
+DestroyResourceTree (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Insert resource padding for P2C.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingForCardBusBridge (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ Program PCI Card device register for given resource node.
+
+ @param Base Base address of PCI Card device to be programmed.
+ @param Node Given resource node.
+
+**/
+VOID
+ProgramP2C (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Create padding resource node.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ApplyResourcePadding (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ Get padding resource for PCI-PCI bridge.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determines
+ whether need to pad resource for them.
+**/
+VOID
+GetResourcePaddingPpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c
new file mode 100644
index 0000000000..9addcf920a
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c
@@ -0,0 +1,126 @@
+/** @file
+ Set up ROM Table for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciBus.h"
+
+//
+// PCI ROM image information
+//
+typedef struct {
+ EFI_HANDLE ImageHandle;
+ UINTN Seg;
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Func;
+ UINT64 RomAddress;
+ UINT64 RomLength;
+} EFI_PCI_ROM_IMAGE_MAPPING;
+
+UINTN mNumberOfPciRomImages = 0;
+UINTN mMaxNumberOfPciRomImages = 0;
+EFI_PCI_ROM_IMAGE_MAPPING *mRomImageTable = NULL;
+
+/**
+ Add the Rom Image to internal database for later PCI light enumeration.
+
+ @param ImageHandle Option Rom image handle.
+ @param Seg Segment of PCI space.
+ @param Bus Bus NO of PCI space.
+ @param Dev Dev NO of PCI space.
+ @param Func Func NO of PCI space.
+ @param RomAddress Base address of OptionRom.
+ @param RomLength Length of rom image.
+
+**/
+VOID
+PciRomAddImageMapping (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN Seg,
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 Func,
+ IN UINT64 RomAddress,
+ IN UINT64 RomLength
+ )
+{
+ EFI_PCI_ROM_IMAGE_MAPPING *TempMapping;
+
+ if (mNumberOfPciRomImages >= mMaxNumberOfPciRomImages) {
+
+ mMaxNumberOfPciRomImages += 0x20;
+
+ TempMapping = NULL;
+ TempMapping = AllocatePool (mMaxNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING));
+ if (TempMapping == NULL) {
+ return ;
+ }
+
+ CopyMem (TempMapping, mRomImageTable, mNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING));
+
+ if (mRomImageTable != NULL) {
+ FreePool (mRomImageTable);
+ }
+
+ mRomImageTable = TempMapping;
+ }
+
+ mRomImageTable[mNumberOfPciRomImages].ImageHandle = ImageHandle;
+ mRomImageTable[mNumberOfPciRomImages].Seg = Seg;
+ mRomImageTable[mNumberOfPciRomImages].Bus = Bus;
+ mRomImageTable[mNumberOfPciRomImages].Dev = Dev;
+ mRomImageTable[mNumberOfPciRomImages].Func = Func;
+ mRomImageTable[mNumberOfPciRomImages].RomAddress = RomAddress;
+ mRomImageTable[mNumberOfPciRomImages].RomLength = RomLength;
+ mNumberOfPciRomImages++;
+}
+
+/**
+ Get Option rom driver's mapping for PCI device.
+
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Found Image mapping.
+ @retval FALSE Cannot found image mapping.
+
+**/
+BOOLEAN
+PciRomGetImageMapping (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINTN Index;
+ BOOLEAN Found;
+
+ PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
+ Found = FALSE;
+
+ for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
+ if (mRomImageTable[Index].Seg == PciRootBridgeIo->SegmentNumber &&
+ mRomImageTable[Index].Bus == PciIoDevice->BusNumber &&
+ mRomImageTable[Index].Dev == PciIoDevice->DeviceNumber &&
+ mRomImageTable[Index].Func == PciIoDevice->FunctionNumber ) {
+ Found = TRUE;
+
+ if (mRomImageTable[Index].ImageHandle != NULL) {
+ AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle);
+ } else {
+ PciIoDevice->PciIo.RomImage = (VOID *) (UINTN) mRomImageTable[Index].RomAddress;
+ PciIoDevice->PciIo.RomSize = (UINTN) mRomImageTable[Index].RomLength;
+ }
+ }
+ }
+
+ return Found;
+}
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h
new file mode 100644
index 0000000000..e1b41a7c86
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h
@@ -0,0 +1,55 @@
+/** @file
+ Set up ROM Table for PCI Bus module.
+
+Copyright (c) 2006 - 2009, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_PCI_ROM_TABLE_H_
+#define _EFI_PCI_ROM_TABLE_H_
+
+/**
+ Add the Rom Image to internal database for later PCI light enumeration.
+
+ @param ImageHandle Option Rom image handle.
+ @param Seg Segment of PCI space.
+ @param Bus Bus NO of PCI space.
+ @param Dev Dev NO of PCI space.
+ @param Func Func NO of PCI space.
+ @param RomAddress Base address of OptionRom.
+ @param RomLength Length of rom image.
+
+**/
+VOID
+PciRomAddImageMapping (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN Seg,
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 Func,
+ IN UINT64 RomAddress,
+ IN UINT64 RomLength
+ );
+
+/**
+ Get Option rom driver's mapping for PCI device.
+
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Found Image mapping.
+ @retval FALSE Cannot found image mapping.
+
+**/
+BOOLEAN
+PciRomGetImageMapping (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif