From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: "KARPAGAVINAYAGAM, MANICKAVASAKAM" <manickavasakamk@ami.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Oram, Isaac W" <isaac.w.oram@intel.com>,
"Felixp@ami.com" <Felixp@ami.com>,
"DOPPALAPUDI, HARIKRISHNA" <harikrishnad@ami.com>,
"Jha, Manish" <manishj@ami.com>,
"Bobroff, Zachary" <zacharyb@ami.com>,
"KARPAGAVINAYAGAM, MANICKAVASAKAM" <manickavasakamk@ami.com>
Subject: Re: [edk2-platforms] [PATCH V1 2/2] PurleyOpenBoardPkg : Override generic PciBus Driver with Platform specific instance of PciBus driver.
Date: Thu, 29 Jul 2021 02:10:56 +0000 [thread overview]
Message-ID: <BN6PR1101MB2147C791EDA80682E692F929CDEB9@BN6PR1101MB2147.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20210616214733.10900-1-manickavasakamk@ami.com>
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
> -----Original Message-----
> From: manickavasakam karpagavinayagam <manickavasakamk@ami.com>
> Sent: Wednesday, June 16, 2021 2:48 PM
> To: devel@edk2.groups.io
> Cc: Oram, Isaac W <isaac.w.oram@intel.com>; Desimone, Nathaniel L
> <nathaniel.l.desimone@intel.com>; Felixp@ami.com; DOPPALAPUDI,
> HARIKRISHNA <harikrishnad@ami.com>; Jha, Manish <manishj@ami.com>;
> Bobroff, Zachary <zacharyb@ami.com>; KARPAGAVINAYAGAM,
> MANICKAVASAKAM <manickavasakamk@ami.com>
> Subject: [edk2-platforms] [PATCH V1 2/2] PurleyOpenBoardPkg : Override
> generic PciBus Driver with Platform specific instance of PciBus driver.
>
> Overriden generic PciBus Driver with Platform specific instance of PciBus
> driver
> To skip SPI controller initialization during PCI enumeration to avoid SET
> variable
> assert issue during POST
> To skip executing a specific MLX card UEFI OPROM
> Move
> PurleyOpenBoardPkg/Override/edk2/MdeModulePkg/Bus/Pci/PciBusDxe to
> PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/PciBusDxe
> ---
> .../BoardTiogaPass/CoreDxeInclude.dsc | 5 +-
> .../BoardTiogaPass/CoreUefiBootInclude.fdf | 5 +-
> .../Bus/Pci/PciBusDxe/ComponentName.c | 170 +
> .../Bus/Pci/PciBusDxe/ComponentName.h | 146 +
> .../MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c | 460 +++
> .../MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h | 396 +++
> .../Bus/Pci/PciBusDxe/PciBusDxe.inf | 112 +
> .../Bus/Pci/PciBusDxe/PciBusDxe.uni | 16 +
> .../Bus/Pci/PciBusDxe/PciBusDxeExtra.uni | 14 +
> .../Bus/Pci/PciBusDxe/PciCommand.c | 267 ++
> .../Bus/Pci/PciBusDxe/PciCommand.h | 232 ++
> .../Bus/Pci/PciBusDxe/PciDeviceSupport.c | 1056 ++++++
> .../Bus/Pci/PciBusDxe/PciDeviceSupport.h | 266 ++
> .../Bus/Pci/PciBusDxe/PciDriverOverride.c | 188 ++
> .../Bus/Pci/PciBusDxe/PciDriverOverride.h | 83 +
> .../Bus/Pci/PciBusDxe/PciEnumerator.c | 2210 +++++++++++++
> .../Bus/Pci/PciBusDxe/PciEnumerator.h | 515 +++
> .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.c | 2885
> +++++++++++++++++
> .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.h | 480 +++
> .../Bus/Pci/PciBusDxe/PciHotPlugSupport.c | 484 +++
> .../Bus/Pci/PciBusDxe/PciHotPlugSupport.h | 205 ++
> .../MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c | 2087 ++++++++++++
> .../MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h | 660 ++++
> .../MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c | 1809 +++++++++++
> .../MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h | 179 +
> .../Bus/Pci/PciBusDxe/PciOptionRomSupport.c | 776 +++++
> .../Bus/Pci/PciBusDxe/PciOptionRomSupport.h | 136 +
> .../Bus/Pci/PciBusDxe/PciPowerManagement.c | 82 +
> .../Bus/Pci/PciBusDxe/PciPowerManagement.h | 28 +
> .../Bus/Pci/PciBusDxe/PciResourceSupport.c | 2292 +++++++++++++
> .../Bus/Pci/PciBusDxe/PciResourceSupport.h | 456 +++
> .../Bus/Pci/PciBusDxe/PciRomTable.c | 135 +
> .../Bus/Pci/PciBusDxe/PciRomTable.h | 48 +
> 33 files changed, 18881 insertions(+), 2 deletions(-)
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/ComponentName.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/ComponentName.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBus.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBus.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBusDxe.inf
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBusDxe.uni
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBusDxeExtra.uni
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciCommand.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciCommand.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDeviceSupport.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDeviceSupport.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDriverOverride.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDriverOverride.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumerator.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumerator.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumeratorSupport.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumeratorSupport.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciHotPlugSupport.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciHotPlugSupport.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciIo.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciIo.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciLib.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciLib.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciOptionRomSupport.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciOptionRomSupport.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciPowerManagement.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciPowerManagement.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciResourceSupport.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciResourceSupport.h
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciRomTable.c
> create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciRomTable.h
>
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> index 7dcb892dd5..b0660d72dd 100644
> ---
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> @@ -78,7 +78,10 @@
> PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf
>
> #MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> - MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> +#TiogaPass Override START :Skip OPROM for specific Mellanox card & SPI
> Controller
> + #MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> +
> $(PLATFORM_BOARD_PACKAGE)/Override/MdeModulePkg/Bus/Pci/PciBus
> Dxe/PciBusDxe.inf
> +#TiogaPass Override END
>
> MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
> MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> index 478a818546..141ce5dda3 100644
> ---
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> @@ -42,7 +42,10 @@ INF
> MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntime
> Dxe.inf
> INF PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf
>
> #INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> -INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> +#TiogaPass Override START :Skip OPROM for specific Mellanox card & SPI
> Controller
> + #INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> + INF
> $(PLATFORM_BOARD_PACKAGE)/Override/MdeModulePkg/Bus/Pci/PciBus
> Dxe/PciBusDxe.inf
> +#TiogaPass Override END
>
> INF MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
> INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.c
> new file mode 100644
> index 0000000000..f3554507e2
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.c
> @@ -0,0 +1,170 @@
> +/** @file
> + EFI Component Name functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 NULL.
> +
> + @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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.h
> new file mode 100644
> index 0000000000..fc3c672760
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.h
> @@ -0,0 +1,146 @@
> +/** @file
> + EFI Component Name functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#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 NULL.
> +
> + @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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.c
> new file mode 100644
> index 0000000000..682b2dac38
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.c
> @@ -0,0 +1,460 @@
> +/** @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 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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
> *gIncompatiblePciDeviceSupport = NULL;
> +UINTN gPciHostBridgeNumber = 0;
> +BOOLEAN gFullEnumeration = TRUE;
> +UINT64 gAllOne = 0xFFFFFFFFFFFFFFFFULL;
> +UINT64 gAllZero = 0;
> +
> +EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol;
> +EFI_PCI_OVERRIDE_PROTOCOL *gPciOverrideProtocol;
> +EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
> +EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;
> +
> +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;
> + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
> + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> + //
> + // Initialize PciRootBridgeIo to suppress incorrect compiler warning.
> + //
> + PciRootBridgeIo = NULL;
> +
> + //
> + // 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;
> + }
> + }
> +
> + gBS->LocateProtocol (
> + &gEfiIncompatiblePciDeviceSupportProtocolGuid,
> + NULL,
> + (VOID **) &gIncompatiblePciDeviceSupport
> + );
> +
> + //
> + // 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
> + );
> + }
> +
> + if (mIoMmuProtocol == NULL) {
> + gBS->LocateProtocol (
> + &gEdkiiIoMmuProtocolGuid,
> + NULL,
> + (VOID **) &mIoMmuProtocol
> + );
> + }
> +
> + if (mDeviceSecurityProtocol == NULL) {
> + gBS->LocateProtocol (
> + &gEdkiiDeviceSecurityProtocolGuid,
> + NULL,
> + (VOID **) &mDeviceSecurityProtocol
> + );
> + }
> +
> + if (PcdGetBool (PcdPciDisableBusEnumeration)) {
> + gFullEnumeration = FALSE;
> + } else {
> + gFullEnumeration = (BOOLEAN) ((SearchHostBridgeHandle (Controller) ?
> FALSE : TRUE));
> + }
> +
> + //
> + // Open Device Path Protocol for PCI root bridge
> + //
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **) &ParentDevicePath,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + //
> + // Report Status Code to indicate PCI bus starts
> + //
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_PROGRESS_CODE,
> + (EFI_IO_BUS_PCI | EFI_IOB_PC_INIT),
> + ParentDevicePath
> + );
> +
> + Status = EFI_SUCCESS;
> + //
> + // Enumerate the entire host bridge
> + // After enumeration, a database that records all the device information
> will be created
> + //
> + //
> + if (gFullEnumeration) {
> + //
> + // 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)) {
> + Status = PciEnumerator (Controller, PciRootBridgeIo->ParentHandle);
> + }
> + } else {
> + //
> + // If PCI bus has already done the full enumeration, never do it again
> + //
> + Status = PciEnumeratorLight (Controller);
> + }
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Start all the devices under the entire host bridge.
> + //
> + StartPciDevices (Controller);
> +
> + if (gFullEnumeration) {
> + gFullEnumeration = FALSE;
> +
> + Status = gBS->InstallProtocolInterface (
> + &PciRootBridgeIo->ParentHandle,
> + &gEfiPciEnumerationCompleteProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + NULL
> + );
> + ASSERT_EFI_ERROR (Status);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Stop this driver on ControllerHandle. Support stopping 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.h
> new file mode 100644
> index 0000000000..967933e278
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.h
> @@ -0,0 +1,396 @@
> +/** @file
> + Header files and data structures needed by PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#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 <Protocol/IoMmu.h>
> +#include <Protocol/DeviceSecurity.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 <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,
> + PciBarTypeOpRom,
> + 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 BarTypeFixed;
> + UINT16 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 RB_IO_RANGE 1
> +#define RB_MEM32_RANGE 2
> +#define RB_PMEM32_RANGE 3
> +#define RB_MEM64_RANGE 4
> +#define RB_PMEM64_RANGE 5
> +
> +#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;
> +
> + //
> + // TRUE 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;
> +
> + //
> + // TRUE if the ROM image is from the PCI Option ROM BAR
> + //
> + BOOLEAN EmbeddedRom;
> +
> + //
> + // The OptionRom Size
> + //
> + UINT32 RomSize;
> +
> + //
> + // 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;
> +
> + //
> + // Bus number ranges for a PCI Root Bridge device
> + //
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
> +
> + 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;
> + //
> + // Per PCI to PCI Bridge spec, I/O window is 4K aligned,
> + // but some chipsets support non-standard I/O window alignments less
> than 4K.
> + // This field is used to support this case.
> + //
> + UINT16 BridgeIoAlignment;
> + UINT32 ResizableBarOffset;
> + UINT32 ResizableBarNumber;
> +};
> +
> +#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
> *gIncompatiblePciDeviceSupport;
> +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;
> +extern BOOLEAN mReserveIsaAliases;
> +extern BOOLEAN mReserveVgaAliases;
> +
> +/**
> + Macro that checks whether device is a GFX device.
> +
> + @param _p Specified device.
> +
> + @retval TRUE Device is a GFX device.
> + @retval FALSE Device is not 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 stopping 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.inf
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.inf
> new file mode 100644
> index 0000000000..9d999f973b
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.inf
> @@ -0,0 +1,112 @@
> +## @file
> +# The PCI bus driver will probe all PCI devices and allocate MMIO and IO
> space for these devices.
> +# Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable
> hot plug supporting.
> +#
> +# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = PciBusDxe
> + MODULE_UNI_FILE = PciBusDxe.uni
> + FILE_GUID = 93B80004-9FB3-11d4-9A3A-0090273FC14D
> + MODULE_TYPE = UEFI_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = PciBusEntryPoint
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
> +#
> +# DRIVER_BINDING = gPciBusDriverBinding
> +# COMPONENT_NAME = gPciBusComponentName
> +# COMPONENT_NAME2 = gPciBusComponentName2
> +#
> +
> +[Sources]
> + 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
> +
> +[Protocols]
> + gEfiPciHotPlugRequestProtocolGuid ## SOMETIMES_PRODUCES
> + gEfiPciIoProtocolGuid ## BY_START
> + gEfiDevicePathProtocolGuid ## BY_START
> + gEfiBusSpecificDriverOverrideProtocolGuid ## BY_START
> + gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiDecompressProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiPciHotPlugInitProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiPciHostBridgeResourceAllocationProtocolGuid ## TO_START
> + gEfiPciPlatformProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiPciOverrideProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiPciEnumerationCompleteProtocolGuid ## PRODUCES
> + gEfiPciRootBridgeIoProtocolGuid ## TO_START
> + gEfiIncompatiblePciDeviceSupportProtocolGuid ##
> SOMETIMES_CONSUMES
> + gEfiLoadFile2ProtocolGuid ## SOMETIMES_PRODUCES
> + gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
> + gEdkiiDeviceSecurityProtocolGuid ## SOMETIMES_CONSUMES
> + gEdkiiDeviceIdentifierTypePciGuid ## SOMETIMES_CONSUMES
> + gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES
> +
> +[FeaturePcd]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport
> ## CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdPciBridgeIoAlignmentProbe ##
> CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdUnalignedPciIoEnable ##
> CONSUMES
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdPciDegradeResourceForOptionRom
> ## CONSUMES
> +
> +[Pcd]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize ##
> SOMETIMES_CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSupport ##
> CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdAriSupport ##
> CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdMrIovSupport ##
> CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration ##
> SOMETIMES_CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarSupport ##
> CONSUMES
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> + PciBusDxeExtra.uni
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.uni
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.uni
> new file mode 100644
> index 0000000000..81bfc2c9ef
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.uni
> @@ -0,0 +1,16 @@
> +// /** @file
> +// The PCI bus driver will probe all PCI devices and allocate MMIO and IO
> space for these devices.
> +//
> +// Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable
> hot plug supporting.
> +//
> +// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT #language en-US "Probes all PCI
> devices and allocate MMIO and IO space for these devices"
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "Please use PCD
> feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting."
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxeExtra.uni
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxeExtra.uni
> new file mode 100644
> index 0000000000..f6a7cdae00
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxeExtra.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// PciBusDxe Localized Strings and Content
> +//
> +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"PCI Bus DXE Driver"
> +
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.c
> new file mode 100644
> index 0000000000..3111448643
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.c
> @@ -0,0 +1,267 @@
> +/** @file
> + PCI command register operations supporting functions implementation for
> PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 capability supporting by given device.
> +
> + @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
> +
> + @retval TRUE Capability supported.
> + @retval FALSE Capability not supported.
> +
> +**/
> +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 Successfully 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 capability 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;
> + }
> +
> + //
> + // Certain PCI device may incorrectly have capability pointing to itself,
> + // break to avoid dead loop.
> + //
> + if (CapabilityPtr == (UINT8) (CapabilityEntry >> 8)) {
> + break;
> + }
> +
> + 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 Successfully 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
> + )
> +{
> + EFI_STATUS Status;
> + 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;
> + Status = PciIoDevice->PciIo.Pci.Read (
> + &PciIoDevice->PciIo,
> + EfiPciIoWidthUint32,
> + CapabilityPtr,
> + 1,
> + &CapabilityEntry
> + );
> + if (EFI_ERROR (Status)) {
> + break;
> + }
> +
> + if (CapabilityEntry == MAX_UINT32) {
> + DEBUG ((
> + DEBUG_WARN,
> + "%a: [%02x|%02x|%02x] failed to access config space at offset 0x%x\n",
> + __FUNCTION__,
> + PciIoDevice->BusNumber,
> + PciIoDevice->DeviceNumber,
> + PciIoDevice->FunctionNumber,
> + CapabilityPtr
> + ));
> + break;
> + }
> +
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.h
> new file mode 100644
> index 0000000000..5eabd56bf2
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.h
> @@ -0,0 +1,232 @@
> +/** @file
> + PCI command register operations supporting functions declaration for PCI
> Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#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 capability supporting by given device.
> +
> + @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
> +
> + @retval TRUE Capability supported.
> + @retval FALSE Capability not supported.
> +
> +**/
> +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 Successfully 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 Successfully 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 disables 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 disables 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.c
> new file mode 100644
> index 0000000000..7effbd5053
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.c
> @@ -0,0 +1,1056 @@
> +/** @file
> + Supporting functions implementation for PCI devices management.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 device 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 destroyed.
> +
> +**/
> +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);
> + }
> +
> + if (PciIoDevice->BusNumberRanges != NULL) {
> + FreePool (PciIoDevice->BusNumberRanges);
> + }
> +
> + 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 Destroy all device 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;
> + EFI_PCI_IO_PROTOCOL *PciIo;
> + UINT8 Data8;
> + BOOLEAN HasEfiImage;
> +
> + //
> + // 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;
> + }
> +
> + //
> + // Force Interrupt line to "Unknown" or "No Connection"
> + //
> + PciIo = &(PciIoDevice->PciIo);
> + Data8 = PCI_INT_LINE_UNKNOWN;
> + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
> +
> + //
> + // 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->EmbeddedRom = FALSE;
> + PciIoDevice->RomSize = (UINT32) 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,
> + PciIoDevice->PciIo.RomImage,
> + PciIoDevice->PciIo.RomSize
> + );
> + }
> + } else if (gPciOverrideProtocol != NULL) {
> + Status = gPciOverrideProtocol->GetPciRom (
> + gPciOverrideProtocol,
> + PciIoDevice->Handle,
> + &PlatformOpRomBuffer,
> + &PlatformOpRomSize
> + );
> + if (!EFI_ERROR (Status)) {
> + PciIoDevice->EmbeddedRom = FALSE;
> + PciIoDevice->RomSize = (UINT32) 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,
> + 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 (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> + Status = StartPciDevicesOnBridge (
> + Controller,
> + PciIoDevice,
> + CurrentDevicePath,
> + NumberOfChildren,
> + ChildHandleBuffer
> + );
> +
> + PciIoDevice->PciIo.Attributes (
> + &(PciIoDevice->PciIo),
> + EfiPciIoAttributeOperationSupported,
> + 0,
> + &Supports
> + );
> + Supports &= (UINT64)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 (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> + Status = StartPciDevicesOnBridge (
> + Controller,
> + PciIoDevice,
> + RemainingDevicePath,
> + NumberOfChildren,
> + ChildHandleBuffer
> + );
> +
> + PciIoDevice->PciIo.Attributes (
> + &(PciIoDevice->PciIo),
> + EfiPciIoAttributeOperationSupported,
> + 0,
> + &Supports
> + );
> + Supports &= (UINT64)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 handle.
> +
> + @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;
> +}
> +
> +/**
> + Judge whether Pci device existed.
> +
> + @param Bridge Parent bridge 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 specified Host Bridge.
> +
> + @param HostBridgeHandle Host Bridge handle.
> +
> + @return The active VGA device on the specified Host Bridge.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDeviceOnHostBridge (
> + IN EFI_HANDLE HostBridgeHandle
> + )
> +{
> + LIST_ENTRY *CurrentLink;
> + PCI_IO_DEVICE *PciIoDevice;
> +
> + CurrentLink = mPciDevicePool.ForwardLink;
> +
> + while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
> +
> + PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> + if (PciIoDevice->PciRootBridgeIo->ParentHandle== HostBridgeHandle) {
> +
> + PciIoDevice = LocateVgaDevice (PciIoDevice);
> +
> + if (PciIoDevice != NULL) {
> + return PciIoDevice;
> + }
> + }
> +
> + CurrentLink = CurrentLink->ForwardLink;
> + }
> +
> + return NULL;
> +}
> +
> +/**
> + Locate the active VGA device under the bridge.
> +
> + @param Bridge PCI IO instance for the bridge.
> +
> + @return The active VGA device.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDevice (
> + IN PCI_IO_DEVICE *Bridge
> + )
> +{
> + LIST_ENTRY *CurrentLink;
> + PCI_IO_DEVICE *PciIoDevice;
> +
> + CurrentLink = Bridge->ChildList.ForwardLink;
> +
> + while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +
> + PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> + if (IS_PCI_VGA(&PciIoDevice->Pci) &&
> + (PciIoDevice->Attributes &
> + (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
> + EFI_PCI_IO_ATTRIBUTE_VGA_IO |
> + EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
> + return PciIoDevice;
> + }
> +
> + if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +
> + PciIoDevice = LocateVgaDevice (PciIoDevice);
> +
> + if (PciIoDevice != NULL) {
> + return PciIoDevice;
> + }
> + }
> +
> + CurrentLink = CurrentLink->ForwardLink;
> + }
> +
> + return NULL;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.h
> new file mode 100644
> index 0000000000..acc0edc0bb
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.h
> @@ -0,0 +1,266 @@
> +/** @file
> + Supporting functions declaration for PCI devices management.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 device 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 Destroy all device 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 handle.
> +
> + @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
> + );
> +
> +
> +/**
> + Judge whether Pci device existed.
> +
> + @param Bridge Parent bridge 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 specified Host Bridge.
> +
> + @param HostBridgeHandle Host Bridge handle.
> +
> + @return The active VGA device on the specified Host Bridge.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDeviceOnHostBridge (
> + IN EFI_HANDLE HostBridgeHandle
> + );
> +
> +/**
> + Locate the active VGA device under the bridge.
> +
> + @param Bridge PCI IO instance for the bridge.
> +
> + @return The active VGA device.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDevice (
> + IN PCI_IO_DEVICE *Bridge
> + );
> +
> +
> +/**
> + 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 destroyed.
> +
> +**/
> +VOID
> +FreePciDevice (
> + IN PCI_IO_DEVICE *PciIoDevice
> + );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.c
> new file mode 100644
> index 0000000000..0c3f684c8c
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.c
> @@ -0,0 +1,188 @@
> +/** @file
> + Functions implementation for Bus Specific Driver Override protocol.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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;
> +}
> +
> +/**
> + Find the image handle whose path equals to ImagePath.
> +
> + @param ImagePath Image path.
> +
> + @return Image handle.
> +**/
> +EFI_HANDLE
> +LocateImageHandle (
> + IN EFI_DEVICE_PATH_PROTOCOL *ImagePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_HANDLE *Handles;
> + UINTN Index;
> + UINTN HandleNum;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> + UINTN ImagePathSize;
> + EFI_HANDLE ImageHandle;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiLoadedImageDevicePathProtocolGuid,
> + NULL,
> + &HandleNum,
> + &Handles
> + );
> + if (EFI_ERROR (Status)) {
> + return NULL;
> + }
> +
> + ImageHandle = NULL;
> + ImagePathSize = GetDevicePathSize (ImagePath);
> +
> + for (Index = 0; Index < HandleNum; Index++) {
> + Status = gBS->HandleProtocol (Handles[Index],
> &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &DevicePath);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> + if ((ImagePathSize == GetDevicePathSize (DevicePath)) &&
> + (CompareMem (ImagePath, DevicePath, ImagePathSize) == 0)
> + ) {
> + ImageHandle = Handles[Index];
> + break;
> + }
> + }
> +
> + FreePool (Handles);
> + return ImageHandle;
> +}
> +
> +/**
> + 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 *Link;
> + PCI_DRIVER_OVERRIDE_LIST *Override;
> + BOOLEAN ReturnNext;
> +
> + Override = NULL;
> + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS (This);
> + ReturnNext = (BOOLEAN) (*DriverImageHandle == NULL);
> + for ( Link = GetFirstNode (&PciIoDevice->OptionRomDriverList)
> + ; !IsNull (&PciIoDevice->OptionRomDriverList, Link)
> + ; Link = GetNextNode (&PciIoDevice->OptionRomDriverList, Link)
> + ) {
> +
> + Override = DRIVER_OVERRIDE_FROM_LINK (Link);
> +
> + if (ReturnNext) {
> + if (Override->DriverImageHandle == NULL) {
> + Override->DriverImageHandle = LocateImageHandle (Override-
> >DriverImagePath);
> + }
> +
> + if (Override->DriverImageHandle == NULL) {
> + //
> + // The Option ROM identified by Override->DriverImagePath is not
> loaded.
> + //
> + continue;
> + } else {
> + *DriverImageHandle = Override->DriverImageHandle;
> + return EFI_SUCCESS;
> + }
> + }
> +
> + if (*DriverImageHandle == Override->DriverImageHandle) {
> + ReturnNext = TRUE;
> + }
> + }
> +
> + ASSERT (IsNull (&PciIoDevice->OptionRomDriverList, Link));
> + //
> + // ReturnNext indicates a handle match happens.
> + // If all nodes are checked without handle match happening,
> + // the DriverImageHandle should be a invalid handle.
> + //
> + if (ReturnNext) {
> + return EFI_NOT_FOUND;
> + } else {
> + return EFI_INVALID_PARAMETER;
> + }
> +}
> +
> +/**
> + Add an overriding driver image.
> +
> + @param PciIoDevice Instance of PciIo device.
> + @param DriverImageHandle Image handle of newly added driver image.
> + @param DriverImagePath Device path of newly 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,
> + IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath
> + )
> +{
> + PCI_DRIVER_OVERRIDE_LIST *Node;
> +
> + //
> + // Caller should pass in either Image Handle or Image Path, but not both.
> + //
> + ASSERT ((DriverImageHandle == NULL) || (DriverImagePath == NULL));
> +
> + Node = AllocateZeroPool (sizeof (PCI_DRIVER_OVERRIDE_LIST));
> + if (Node == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Node->Signature = DRIVER_OVERRIDE_SIGNATURE;
> + Node->DriverImageHandle = DriverImageHandle;
> + Node->DriverImagePath = DuplicateDevicePath (DriverImagePath);
> +
> + InsertTailList (&PciIoDevice->OptionRomDriverList, &Node->Link);
> +
> + PciIoDevice->BusOverride = TRUE;
> + return EFI_SUCCESS;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.h
> new file mode 100644
> index 0000000000..ab058fa762
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.h
> @@ -0,0 +1,83 @@
> +/** @file
> + Functions declaration for Bus Specific Driver Override protocol.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#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;
> + EFI_DEVICE_PATH_PROTOCOL *DriverImagePath;
> +} 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 Image handle of newly added driver image.
> + @param DriverImagePath Device path of newly 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,
> + IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath
> + );
> +
> +
> +/**
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.c
> new file mode 100644
> index 0000000000..4e1c328b7e
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.c
> @@ -0,0 +1,2210 @@
> +/** @file
> + PCI eunmeration implementation on entire PCI bus system for PCI Bus
> module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +/**
> + This routine is used to enumerate entire pci bus system
> + in a given platform.
> +
> + @param Controller Parent controller handle.
> + @param HostBridgeHandle Host bridge 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,
> + IN EFI_HANDLE HostBridgeHandle
> + )
> +{
> + EFI_STATUS Status;
> + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc;
> +
> + //
> + // 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
> + //
> + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // 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
> + //
> + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndEnumeration);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // 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;
> + }
> +
> + 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;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration1;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration2;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration3;
> + UINT8 SubBusNumber;
> + UINT8 StartBusNumber;
> + UINT8 PaddedBusRange;
> + EFI_HANDLE RootBridgeHandle;
> + UINT8 Desc;
> + UINT64 AddrLen;
> + UINT64 AddrRangeMin;
> +
> + 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_BUS_ENUM,
> + RootBridgeDev->DevicePath
> + );
> +
> + //
> + // Get the Bus information
> + //
> + Status = PciResAlloc->StartBusEnumeration (
> + PciResAlloc,
> + RootBridgeHandle,
> + (VOID **) &Configuration
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (Configuration == NULL || Configuration->Desc ==
> ACPI_END_TAG_DESCRIPTOR) {
> + return EFI_INVALID_PARAMETER;
> + }
> + RootBridgeDev->BusNumberRanges = Configuration;
> +
> + //
> + // Sort the descriptors in ascending order
> + //
> + for (Configuration1 = Configuration; Configuration1->Desc !=
> ACPI_END_TAG_DESCRIPTOR; Configuration1++) {
> + Configuration2 = Configuration1;
> + for (Configuration3 = Configuration1 + 1; Configuration3->Desc !=
> ACPI_END_TAG_DESCRIPTOR; Configuration3++) {
> + if (Configuration2->AddrRangeMin > Configuration3->AddrRangeMin) {
> + Configuration2 = Configuration3;
> + }
> + }
> + //
> + // All other fields other than AddrRangeMin and AddrLen are ignored in a
> descriptor,
> + // so only need to swap these two fields.
> + //
> + if (Configuration2 != Configuration1) {
> + AddrRangeMin = Configuration1->AddrRangeMin;
> + Configuration1->AddrRangeMin = Configuration2->AddrRangeMin;
> + Configuration2->AddrRangeMin = AddrRangeMin;
> +
> + AddrLen = Configuration1->AddrLen;
> + Configuration1->AddrLen = Configuration2->AddrLen;
> + Configuration2->AddrLen = AddrLen;
> + }
> + }
> +
> + //
> + // Get the bus number to start with
> + //
> + StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
> +
> + //
> + // Initialize the subordinate bus number
> + //
> + SubBusNumber = StartBusNumber;
> +
> + //
> + // Reset all assigned PCI bus number
> + //
> + ResetAllPpbBusNumber (
> + RootBridgeDev,
> + StartBusNumber
> + );
> +
> + //
> + // Assign bus number
> + //
> + Status = PciScanBus (
> + RootBridgeDev,
> + StartBusNumber,
> + &SubBusNumber,
> + &PaddedBusRange
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> +
> + //
> + // Assign max bus number scanned
> + //
> +
> + Status = PciAllocateBusNumber (RootBridgeDev, SubBusNumber,
> PaddedBusRange, &SubBusNumber);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Find the bus range which contains the higest bus number, then returns
> the number of buses
> + // that should be decoded.
> + //
> + while (Configuration->AddrRangeMin + Configuration->AddrLen - 1 <
> SubBusNumber) {
> + Configuration++;
> + }
> + AddrLen = Configuration->AddrLen;
> + Configuration->AddrLen = SubBusNumber - Configuration-
> >AddrRangeMin + 1;
> +
> + //
> + // Save the Desc field of the next descriptor. Mark the next descriptor as
> an END descriptor.
> + //
> + Configuration++;
> + Desc = Configuration->Desc;
> + Configuration->Desc = ACPI_END_TAG_DESCRIPTOR;
> +
> + //
> + // Set bus number
> + //
> + Status = PciResAlloc->SetBusNumbers (
> + PciResAlloc,
> + RootBridgeHandle,
> + RootBridgeDev->BusNumberRanges
> + );
> +
> + //
> + // Restore changed fields
> + //
> + Configuration->Desc = Desc;
> + (Configuration - 1)->AddrLen = AddrLen;
> +
> + return Status;
> +}
> +
> +/**
> + 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) && Func == 0) {
> + //
> + // go to next device if there is no Function 0
> + //
> + break;
> + }
> +
> + if (!EFI_ERROR (Status) &&
> + (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
> +
> + //
> + // Reserved one bus for cardbus bridge
> + //
> + Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1,
> SubBusNumber);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + 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_MEM64_DECODE_SUPPORTED;
> + 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.
> +
> +**/
> +UINT32
> +GetMaxOptionRomSize (
> + IN PCI_IO_DEVICE *Bridge
> + )
> +{
> + LIST_ENTRY *CurrentLink;
> + PCI_IO_DEVICE *Temp;
> + UINT32 MaxOptionRomSize;
> + UINT32 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);
> + 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 resource 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) {
> + DEBUG ((
> + EFI_D_ERROR,
> + "PciBus: [%02x|%02x|%02x] was rejected due to resource
> confliction.\n",
> + PciResNode->PciDev->BusNumber, PciResNode->PciDev-
> >DeviceNumber, PciResNode->PciDev->FunctionNumber
> + ));
> +
> + //
> + // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
> + //
> + //
> + // Have no way to get ReqRes, AllocRes & Bar here
> + //
> + ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
> + AllocFailExtendedData.DevicePathSize = (UINT16) 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 construct 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 available.
> +
> +**/
> +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 = (UINT16) (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 = (UINT16) (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 = (UINT16) (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 = (UINT16) (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 = (UINT16) (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_END_TAG_DESCRIPTOR));
> + if (Configuration == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Configuration);
> + 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,
> + Bridge->BridgeIoAlignment,
> + 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 Status;
> +}
> +
> +/**
> + 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) {
> + //
> + // Report Status Code to indicate hot plug happens
> + //
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_PROGRESS_CODE,
> + (EFI_IO_BUS_PCI | EFI_IOB_PC_HOTPLUG),
> + Temp->DevicePath
> + );
> +
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.h
> new file mode 100644
> index 0000000000..2a34c9043c
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.h
> @@ -0,0 +1,515 @@
> +/** @file
> + PCI bus enumeration logic function declaration for PCI bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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.
> + @param HostBridgeHandle Host bridge 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,
> + IN EFI_HANDLE HostBridgeHandle
> + );
> +
> +/**
> + 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.
> +
> +**/
> +UINT32
> +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 resource 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 construct 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 available.
> +
> +**/
> +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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.c
> new file mode 100644
> index 0000000000..99b04a462b
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.c
> @@ -0,0 +1,2885 @@
> +/** @file
> + PCI emumeration support functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> +Copyright (c) 2021, American Megatrends International LLC.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +extern CHAR16 *mBarTypeStr[];
> +extern EDKII_DEVICE_SECURITY_PROTOCOL
> *mDeviceSecurityProtocol;
> +
> +#define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL
> +#define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
> +#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
> +#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
> +
> +/**
> + 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);
> +
> +
> +//TiogaPass Override START : Skip SPI controller from Enumeration
> +
> +//
> +//
> +// It is necessary to skip SPI controller from Enumeration process otherwise
> SPI access runing DXE/DXE SMM
> +// will causes failures writting to SPI. This is a WA for LBG since currently OS
> hidde is not working.
> +//
> + if(( Bus == 0x0) && ( Device == 0x1F) && (Func == 0x05)){
> + DEBUG ((EFI_D_INFO, "DEBUG - Address - 0x%x BUS %x DEV %x Func %x
> SKIP\n", Address, Bus, Device, Func));
> + return EFI_NOT_FOUND;
> + }
> +
> +//TiogaPass Override END
> +
> + //
> + // 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 beginning.
> +
> + @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) && Func == 0) {
> + //
> + // go to next device if there is no Function 0
> + //
> + break;
> + }
> +
> + 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;
> + }
> +
> + //
> + // Ensure secondary bus number is greater than the primary bus
> number to avoid
> + // any potential dead loop when PcdPciDisableBusEnumeration is set
> to TRUE
> + //
> + if (SecBus <= StartBusNumber) {
> + break;
> + }
> +
> + //
> + // 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;
> +}
> +
> +/**
> + Search 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;
> +
> + DEBUG ((
> + EFI_D_INFO,
> + "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",
> + IS_PCI_BRIDGE (Pci) ? L"PPB" :
> + IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :
> + L"PCI",
> + Bus, Device, Func
> + ));
> +
> + 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;
> +}
> +
> +/**
> + Dump the PPB padding resource information.
> +
> + @param PciIoDevice PCI IO instance.
> + @param ResourceType The desired resource type to dump.
> + PciBarTypeUnknown means to dump all types of resources.
> +**/
> +VOID
> +DumpPpbPaddingResource (
> + IN PCI_IO_DEVICE *PciIoDevice,
> + IN PCI_BAR_TYPE ResourceType
> + )
> +{
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
> + PCI_BAR_TYPE Type;
> +
> + if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
> + return;
> + }
> +
> + if (ResourceType == PciBarTypeIo16 || ResourceType == PciBarTypeIo32) {
> + ResourceType = PciBarTypeIo;
> + }
> +
> + for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor-
> >Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) {
> +
> + Type = PciBarTypeUnknown;
> + if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&
> Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
> + Type = PciBarTypeIo;
> + } else if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&
> Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
> +
> + if (Descriptor->AddrSpaceGranularity == 32) {
> + //
> + // prefetchable
> + //
> + if (Descriptor->SpecificFlag ==
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E) {
> + Type = PciBarTypePMem32;
> + }
> +
> + //
> + // Non-prefetchable
> + //
> + if (Descriptor->SpecificFlag == 0) {
> + Type = PciBarTypeMem32;
> + }
> + }
> +
> + if (Descriptor->AddrSpaceGranularity == 64) {
> + //
> + // prefetchable
> + //
> + if (Descriptor->SpecificFlag ==
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E) {
> + Type = PciBarTypePMem64;
> + }
> +
> + //
> + // Non-prefetchable
> + //
> + if (Descriptor->SpecificFlag == 0) {
> + Type = PciBarTypeMem64;
> + }
> + }
> + }
> +
> + if ((Type != PciBarTypeUnknown) && ((ResourceType ==
> PciBarTypeUnknown) || (ResourceType == Type))) {
> + DEBUG ((
> + EFI_D_INFO,
> + " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
> + mBarTypeStr[Type], Descriptor->AddrRangeMax, Descriptor->AddrLen
> + ));
> + }
> + }
> +
> +}
> +
> +/**
> + Dump the PCI BAR information.
> +
> + @param PciIoDevice PCI IO instance.
> +**/
> +VOID
> +DumpPciBars (
> + IN PCI_IO_DEVICE *PciIoDevice
> + )
> +{
> + UINTN Index;
> +
> + for (Index = 0; Index < PCI_MAX_BAR; Index++) {
> + if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {
> + continue;
> + }
> +
> + DEBUG ((
> + EFI_D_INFO,
> + " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset =
> 0x%02x\n",
> + Index, mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType,
> PciBarTypeMaxType)],
> + PciIoDevice->PciBar[Index].Alignment, PciIoDevice-
> >PciBar[Index].Length, PciIoDevice->PciBar[Index].Offset
> + ));
> + }
> +
> + for (Index = 0; Index < PCI_MAX_BAR; Index++) {
> + if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) &&
> (PciIoDevice->VfPciBar[Index].Length == 0)) {
> + continue;
> + }
> +
> + DEBUG ((
> + EFI_D_INFO,
> + " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset =
> 0x%02x\n",
> + Index, mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType,
> PciBarTypeMaxType)],
> + PciIoDevice->VfPciBar[Index].Alignment, PciIoDevice-
> >VfPciBar[Index].Length, PciIoDevice->VfPciBar[Index].Offset
> + ));
> + }
> + DEBUG ((EFI_D_INFO, "\n"));
> +}
> +
> +/**
> + 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;
> +
> + PciIoDevice = CreatePciIoDevice (
> + Bridge,
> + Pci,
> + Bus,
> + Device,
> + Func
> + );
> +
> + if (PciIoDevice == NULL) {
> + return NULL;
> + }
> +
> + //
> + // 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 (PcdGetBool (PcdSrIovSupport) && PciIoDevice->SrIovCapabilityOffset
> != 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);
> + }
> + }
> +
> + DEBUG_CODE (DumpPciBars (PciIoDevice););
> + 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
> + )
> +{
> + PCI_IO_DEVICE *PciIoDevice;
> + EFI_STATUS Status;
> + UINT8 Value;
> + EFI_PCI_IO_PROTOCOL *PciIo;
> + UINT8 Temp;
> + UINT32 PMemBaseLimit;
> + UINT16 PrefetchableMemoryBase;
> + UINT16 PrefetchableMemoryLimit;
> +
> + PciIoDevice = CreatePciIoDevice (
> + Bridge,
> + Pci,
> + Bus,
> + Device,
> + Func
> + );
> +
> + if (PciIoDevice == NULL) {
> + return NULL;
> + }
> +
> + if (gFullEnumeration) {
> + PCI_DISABLE_COMMAND_REGISTER (PciIoDevice,
> EFI_PCI_COMMAND_BITS_OWNED);
> +
> + //
> + // Initialize 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;
> + }
> + }
> +
> + //
> + // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
> + // PCI bridge supporting non-standard I/O window alignment less than 4K.
> + //
> +
> + PciIoDevice->BridgeIoAlignment = 0xFFF;
> + if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {
> + //
> + // Check any bits of bit 3-1 of I/O Base Register are writable.
> + // if so, it is assumed non-standard I/O window alignment is supported by
> this bridge.
> + // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content
> can't be assumed.
> + //
> + Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));
> + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
> + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
> + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
> + Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));
> + switch (Value) {
> + case BIT3:
> + PciIoDevice->BridgeIoAlignment = 0x7FF;
> + break;
> + case BIT3 | BIT2:
> + PciIoDevice->BridgeIoAlignment = 0x3FF;
> + break;
> + case BIT3 | BIT2 | BIT1:
> + PciIoDevice->BridgeIoAlignment = 0x1FF;
> + break;
> + }
> + }
> +
> + Status = BarExisted (
> + PciIoDevice,
> + 0x24,
> + NULL,
> + &PMemBaseLimit
> + );
> +
> + //
> + // Test if it supports 64 memory or not
> + //
> + // The bottom 4 bits of both the Prefetchable Memory Base and
> Prefetchable Memory Limit
> + // registers:
> + // 0 - the bridge supports only 32 bit addresses.
> + // 1 - the bridge supports 64-bit addresses.
> + //
> + PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);
> + PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);
> + if (!EFI_ERROR (Status) &&
> + (PrefetchableMemoryBase & 0x000f) == 0x0001 &&
> + (PrefetchableMemoryLimit & 0x000f) == 0x0001) {
> + 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);
> +
> + DEBUG_CODE (
> + DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown);
> + DumpPciBars (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
> + )
> +{
> + PCI_IO_DEVICE *PciIoDevice;
> +
> + PciIoDevice = CreatePciIoDevice (
> + Bridge,
> + Pci,
> + Bus,
> + Device,
> + Func
> + );
> +
> + if (PciIoDevice == NULL) {
> + return NULL;
> + }
> +
> + if (gFullEnumeration) {
> + PCI_DISABLE_COMMAND_REGISTER (PciIoDevice,
> EFI_PCI_COMMAND_BITS_OWNED);
> +
> + //
> + // Initialize 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;
> +
> + DEBUG_CODE (DumpPciBars (PciIoDevice););
> +
> + return PciIoDevice;
> +}
> +
> +/**
> + Create device path for pci device.
> +
> + @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 Input 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 |= (UINT64)
> (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 (IS_PCI_LPC (&PciIoDevice->Pci)) {
> + Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
> + Attributes |= (mReserveIsaAliases ? (UINT64)
> EFI_PCI_IO_ATTRIBUTE_ISA_IO : \
> + (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
> + }
> +
> + 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;
> +
> + if (mReserveVgaAliases) {
> + Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \
> + EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);
> + } else {
> + Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \
> + EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_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 |= (mReserveVgaAliases ? (UINT64)
> EFI_PCI_IO_ATTRIBUTE_VGA_IO : \
> + (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
> + }
> + }
> +
> + 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 {
> + //
> + // When this attribute is clear, the RomImage and RomSize fields in the
> PCI IO were
> + // initialized based on the PCI option ROM found through the ROM BAR of
> the PCI controller.
> + // When this attribute is set, the PCI option ROM described by the
> RomImage and RomSize
> + // fields is not from the the ROM BAR of the PCI controller.
> + //
> + if (!PciIoDevice->EmbeddedRom) {
> + Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;
> + }
> + 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);
> + }
> +
> + Temp->AllOpRomProcessed = PciRomGetImageMapping (Temp);
> +
> + 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 protocol
> + // 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;
> + }
> + //
> + // Assume the PCI Root Bridge supports DAC
> + //
> + PciIoDevice->Supports |=
> (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
> + EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
> + EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
> +
> + } 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 PCI supported attributes but not defined in
> PCI_IO_PROTOCOL
> + // For PCI Express devices, Memory Write and Invalidate is hardwired to
> 0b so only enable it for PCI devices.
> + if (!PciIoDevice->IsPciExp) {
> + 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 Back to Back 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;
> + BOOLEAN SetFlag;
> + VOID *Configuration;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
> +
> + Configuration = NULL;
> + Status = EFI_SUCCESS;
> +
> + if (gIncompatiblePciDeviceSupport == NULL) {
> + //
> + // It can only be supported after the Incompatible PCI Device
> + // Support Protocol has been installed
> + //
> + Status = gBS->LocateProtocol (
> + &gEfiIncompatiblePciDeviceSupportProtocolGuid,
> + NULL,
> + (VOID **) &gIncompatiblePciDeviceSupport
> + );
> + }
> + 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 = gIncompatiblePciDeviceSupport->CheckDevice (
> + gIncompatiblePciDeviceSupport,
> + 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;
> + }
> +
> + for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
> + if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&
> + (Ptr->AddrTranslationOffset != MAX_UINT8) &&
> + (Ptr->AddrTranslationOffset != BarIndex)
> + ) {
> + //
> + // Skip updating when AddrTranslationOffset is not MAX_UINT64 or
> MAX_UINT8 (wide match).
> + // Skip updating when current BarIndex doesn't equal to
> AddrTranslationOffset.
> + // Comparing against MAX_UINT8 is to keep backward compatibility.
> + //
> + continue;
> + }
> +
> + 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;
> +
> + //
> + // Ignored if granularity is 0.
> + // Ignored if PCI BAR is I/O or 32-bit memory.
> + // If PCI BAR is 64-bit memory and granularity is 32, then
> + // the PCI BAR resource is allocated below 4GB.
> + // If PCI BAR is 64-bit memory and granularity is 64, then
> + // the PCI BAR resource is allocated above 4GB.
> + //
> + if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {
> + switch (Ptr->AddrSpaceGranularity) {
> + case 32:
> + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
> + case 64:
> + PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {
> + switch (Ptr->AddrSpaceGranularity) {
> + case 32:
> + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
> + case 64:
> + PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
> + break;
> + default:
> + break;
> + }
> + }
> + }
> + 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 != 0) {
> + PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
> + }
> + }
> + }
> +
> + Ptr++;
> + }
> +
> + FreePool (Configuration);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This routine will update the alignment with the new alignment.
> + Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN
> is to keep
> + backward compatibility.
> +
> + @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 == 0) || (NewAlignment == OLD_ALIGN)) {
> + return ;
> + }
> + //
> + // Check the validity of the parameter
> + //
> + if (NewAlignment != EVEN_ALIGN &&
> + NewAlignment != SQUAD_ALIGN &&
> + NewAlignment != 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 == EVEN_ALIGN) {
> + if ((OldAlignment & 0x01) != 0) {
> + OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
> + }
> + } else if (NewAlignment == SQUAD_ALIGN) {
> + if ((OldAlignment & 0x03) != 0) {
> + OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
> + }
> + } else if (NewAlignment == 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;
> + 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 = (UINT16) Offset;
> + return Offset + 4;
> + }
> +
> + PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;
> + if ((Value & 0x01) != 0) {
> + //
> + // 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) != 0) {
> + 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) != 0) {
> + 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)) {
> + PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
> + return Offset + 4;
> + }
> +
> + //
> + // Fix the length to support some special 64 bit BAR
> + //
> + Value |= ((UINT32) -1 << HighBitSet32 (Value));
> +
> + //
> + // 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;
> + 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].BarTypeFixed = FALSE;
> + 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 implement 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].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 special 64 bit BAR
> + //
> + if (Value == 0) {
> + DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64
> BAR returns 0, change to 0xFFFFFFFF.\n"));
> + Value = (UINT32) -1;
> + } else {
> + Value |= ((UINT32)(-1) << HighBitSet32 (Value));
> + }
> +
> + //
> + // 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 allocated
> + //
> + 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);
> +}
> +
> +/**
> + Authenticate the PCI device by using DeviceSecurityProtocol.
> +
> + @param PciIoDevice PCI device.
> +
> + @retval EFI_SUCCESS The device passes the authentication.
> + @return not EFI_SUCCESS The device failes the authentication or
> + unexpected error happen during authentication.
> +**/
> +EFI_STATUS
> +AuthenticatePciDevice (
> + IN PCI_IO_DEVICE *PciIoDevice
> + )
> +{
> + EDKII_DEVICE_IDENTIFIER DeviceIdentifier;
> + EFI_STATUS Status;
> +
> + if (mDeviceSecurityProtocol != NULL) {
> + //
> + // Prepare the parameter
> + //
> + DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;
> + CopyGuid (&DeviceIdentifier.DeviceType,
> &gEdkiiDeviceIdentifierTypePciGuid);
> + DeviceIdentifier.DeviceHandle = NULL;
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &DeviceIdentifier.DeviceHandle,
> + &gEfiDevicePathProtocolGuid,
> + PciIoDevice->DevicePath,
> + &gEdkiiDeviceIdentifierTypePciGuid,
> + &PciIoDevice->PciIo,
> + NULL
> + );
> + if (EFI_ERROR(Status)) {
> + return Status;
> + }
> +
> + //
> + // Do DeviceAuthentication
> + //
> + Status = mDeviceSecurityProtocol->DeviceAuthenticate
> (mDeviceSecurityProtocol, &DeviceIdentifier);
> + //
> + // Always uninstall, because they are only for Authentication.
> + // No need to check return Status.
> + //
> + gBS->UninstallMultipleProtocolInterfaces (
> + DeviceIdentifier.DeviceHandle,
> + &gEfiDevicePathProtocolGuid,
> + PciIoDevice->DevicePath,
> + &gEdkiiDeviceIdentifierTypePciGuid,
> + &PciIoDevice->PciIo,
> + NULL
> + );
> + return Status;
> + }
> +
> + //
> + // Device Security Protocol is not found, just return success
> + //
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Create and initialize general PCI I/O device instance for
> + PCI device/bridge device/hotplug bridge device.
> +
> + @param Bridge Parent bridge instance.
> + @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 PCI_IO_DEVICE *Bridge,
> + 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 = Bridge->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;
> +
> + //
> + // Create a device path for this PCI device and store it into its private data
> + //
> + CreatePciDevicePath (
> + Bridge->DevicePath,
> + PciIoDevice
> + );
> +
> + //
> + // 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;
> + }
> +
> + //
> + // Now we can do the authentication check for the device.
> + //
> + Status = AuthenticatePciDevice (PciIoDevice);
> + //
> + // If authentication fails, skip this device.
> + //
> + if (EFI_ERROR(Status)) {
> + if (PciIoDevice->DevicePath != NULL) {
> + FreePool (PciIoDevice->DevicePath);
> + }
> + FreePool (PciIoDevice);
> + return NULL;
> + }
> +
> + if (PcdGetBool (PcdAriSupport)) {
> + //
> + // Check if the device is an ARI device.
> + //
> + Status = LocatePciExpressCapabilityRegBlock (
> + PciIoDevice,
> + EFI_PCIE_CAPABILITY_ID_ARI,
> + &PciIoDevice->AriCapabilityOffset,
> + NULL
> + );
> + if (!EFI_ERROR (Status)) {
> + //
> + // We need to enable ARI feature before calculate BusReservation,
> + // because FirstVFOffset and VFStride may change after that.
> + //
> + EFI_PCI_IO_PROTOCOL *ParentPciIo;
> + UINT32 Data32;
> +
> + //
> + // Check if its parent supports ARI forwarding.
> + //
> + ParentPciIo = &Bridge->PciIo;
> + ParentPciIo->Pci.Read (
> + ParentPciIo,
> + EfiPciIoWidthUint32,
> + Bridge->PciExpressCapabilityOffset +
> EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,
> + 1,
> + &Data32
> + );
> + if ((Data32 &
> EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {
> + //
> + // ARI forward support in bridge, so enable it.
> + //
> + ParentPciIo->Pci.Read (
> + ParentPciIo,
> + EfiPciIoWidthUint32,
> + Bridge->PciExpressCapabilityOffset +
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
> + 1,
> + &Data32
> + );
> + if ((Data32 &
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {
> + Data32 |=
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
> + ParentPciIo->Pci.Write (
> + ParentPciIo,
> + EfiPciIoWidthUint32,
> + Bridge->PciExpressCapabilityOffset +
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
> + 1,
> + &Data32
> + );
> + DEBUG ((
> + EFI_D_INFO,
> + " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
> + Bridge->BusNumber,
> + Bridge->DeviceNumber,
> + Bridge->FunctionNumber
> + ));
> + }
> + }
> +
> + DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice-
> >AriCapabilityOffset));
> + }
> + }
> +
> + //
> + // Initialization for SR-IOV
> + //
> +
> + if (PcdGetBool (PcdSrIovSupport)) {
> + Status = LocatePciExpressCapabilityRegBlock (
> + PciIoDevice,
> + EFI_PCIE_CAPABILITY_ID_SRIOV,
> + &PciIoDevice->SrIovCapabilityOffset,
> + NULL
> + );
> + if (!EFI_ERROR (Status)) {
> + UINT32 SupportedPageSize;
> + UINT16 VFStride;
> + UINT16 FirstVFOffset;
> + UINT16 Data16;
> + UINT32 PFRid;
> + UINT32 LastVF;
> +
> + //
> + // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy
> for the device.
> + //
> + if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0)
> {
> + 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
> + );
> + }
> +
> + //
> + // Calculate SystemPageSize
> + //
> +
> + PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint32,
> + PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
> + 1,
> + &SupportedPageSize
> + );
> + PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) &
> SupportedPageSize);
> + ASSERT (PciIoDevice->SystemPageSize != 0);
> +
> + PciIo->Pci.Write (
> + PciIo,
> + EfiPciIoWidthUint32,
> + PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
> + 1,
> + &PciIoDevice->SystemPageSize
> + );
> + //
> + // Adjust SystemPageSize for Alignment usage later
> + //
> + PciIoDevice->SystemPageSize <<= 12;
> +
> + //
> + // Calculate BusReservation for PCI IOV
> + //
> +
> + //
> + // Read First FirstVFOffset, InitialVFs, and VFStride
> + //
> + PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint16,
> + PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
> + 1,
> + &FirstVFOffset
> + );
> + PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint16,
> + PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
> + 1,
> + &PciIoDevice->InitialVFs
> + );
> + PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint16,
> + PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
> + 1,
> + &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,
> + " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x;
> FirstVFOffset = 0x%x;\n",
> + SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset
> + ));
> + DEBUG ((
> + EFI_D_INFO,
> + " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
> + PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice-
> >SrIovCapabilityOffset
> + ));
> + }
> + }
> +
> + if (PcdGetBool (PcdMrIovSupport)) {
> + Status = LocatePciExpressCapabilityRegBlock (
> + PciIoDevice,
> + EFI_PCIE_CAPABILITY_ID_MRIOV,
> + &PciIoDevice->MrIovCapabilityOffset,
> + NULL
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice-
> >MrIovCapabilityOffset));
> + }
> + }
> +
> + PciIoDevice->ResizableBarOffset = 0;
> + if (PcdGetBool (PcdPcieResizableBarSupport)) {
> + Status = LocatePciExpressCapabilityRegBlock (
> + PciIoDevice,
> + PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID,
> + &PciIoDevice->ResizableBarOffset,
> + NULL
> + );
> + if (!EFI_ERROR (Status)) {
> + PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL
> ResizableBarControl;
> + UINT32 Offset;
> + Offset = PciIoDevice->ResizableBarOffset + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
> + + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY),
> + PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint8,
> + Offset,
> + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL),
> + &ResizableBarControl
> + );
> + PciIoDevice->ResizableBarNumber =
> ResizableBarControl.Bits.ResizableBarNumber;
> + PciProgramResizableBar (PciIoDevice, PciResizableBarMax);
> + }
> + }
> +
> + //
> + // 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 bridge-io 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 unsuccessfully, 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) && Func == 0) {
> + //
> + // go to next device if there is no Function 0
> + //
> + break;
> + }
> +
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.h
> new file mode 100644
> index 0000000000..1d39c5171d
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.h
> @@ -0,0 +1,480 @@
> +/** @file
> + PCI enumeration support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 beginning.
> +
> + @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
> + );
> +
> +/**
> + Search 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 device.
> +
> + @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 Input 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 initialize general PCI I/O device instance for
> + PCI device/bridge device/hotplug bridge device.
> +
> + @param Bridge Parent bridge instance.
> + @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 PCI_IO_DEVICE *Bridge,
> + 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
> + );
> +
> +/**
> + Dump the PPB padding resource information.
> +
> + @param PciIoDevice PCI IO instance.
> + @param ResourceType The desired resource type to dump.
> + PciBarTypeUnknown means to dump all types of resources.
> +**/
> +VOID
> +DumpPpbPaddingResource (
> + IN PCI_IO_DEVICE *PciIoDevice,
> + IN PCI_BAR_TYPE ResourceType
> + );
> +
> +/**
> + Dump the PCI BAR information.
> +
> + @param PciIoDevice PCI IO instance.
> +**/
> +VOID
> +DumpPciBars (
> + IN PCI_IO_DEVICE *PciIoDevice
> + );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.c
> new file mode 100644
> index 0000000000..d6d06b061a
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.c
> @@ -0,0 +1,484 @@
> +/** @file
> + PCI Hot Plug support functions implementation for PCI Bus module..
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 paths 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 controller 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 returned.
> +
> + @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 returned.
> +
> + @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 returned event that invoke this function.
> +
> + @return Status of create event.
> +
> +**/
> +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].Found &&
> !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_SHPC,
> + &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;
> +}
> +
> +/**
> + Check whether PciIoDevice supports PCIe hotplug.
> +
> + This is equivalent to the following condition:
> + - the device is either a PCIe switch downstream port or a root port,
> + - and the device has the SlotImplemented bit set in its PCIe capability
> + register,
> + - and the device has the HotPlugCapable bit set in its slot capabilities
> + register.
> +
> + @param[in] PciIoDevice The device being checked.
> +
> + @retval TRUE PciIoDevice is a PCIe port that accepts a hot-plugged device.
> + @retval FALSE Otherwise.
> +
> +**/
> +BOOLEAN
> +SupportsPcieHotplug (
> + IN PCI_IO_DEVICE *PciIoDevice
> + )
> +{
> + UINT32 Offset;
> + EFI_STATUS Status;
> + PCI_REG_PCIE_CAPABILITY Capability;
> + PCI_REG_PCIE_SLOT_CAPABILITY SlotCapability;
> +
> + if (PciIoDevice == NULL) {
> + return FALSE;
> + }
> +
> + //
> + // Read the PCI Express Capabilities Register
> + //
> + if (!PciIoDevice->IsPciExp) {
> + return FALSE;
> + }
> + Offset = PciIoDevice->PciExpressCapabilityOffset +
> + OFFSET_OF (PCI_CAPABILITY_PCIEXP, Capability);
> + Status = PciIoDevice->PciIo.Pci.Read (
> + &PciIoDevice->PciIo,
> + EfiPciIoWidthUint16,
> + Offset,
> + 1,
> + &Capability
> + );
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + //
> + // Check the contents of the register
> + //
> + switch (Capability.Bits.DevicePortType) {
> + case PCIE_DEVICE_PORT_TYPE_ROOT_PORT:
> + case PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT:
> + break;
> + default:
> + return FALSE;
> + }
> + if (!Capability.Bits.SlotImplemented) {
> + return FALSE;
> + }
> +
> + //
> + // Read the Slot Capabilities Register
> + //
> + Offset = PciIoDevice->PciExpressCapabilityOffset +
> + OFFSET_OF (PCI_CAPABILITY_PCIEXP, SlotCapability);
> + Status = PciIoDevice->PciIo.Pci.Read (
> + &PciIoDevice->PciIo,
> + EfiPciIoWidthUint32,
> + Offset,
> + 1,
> + &SlotCapability
> + );
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + //
> + // Check the contents of the register
> + //
> + if (SlotCapability.Bits.HotPlugCapable) {
> + 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;
> + }
> +
> + if (SupportsPcieHotplug (PciIoDevice)) {
> + //
> + // If the PPB is a PCIe root complex port or a switch downstream port, and
> + // implements a hot-plug capable slot, then also return TRUE.
> + //
> + return TRUE;
> + }
> +
> + //
> + // Otherwise, see if it is a Root HPC
> + //
> + if(IsRootPciHotPlugBus (PciIoDevice->DevicePath, NULL)) {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.h
> new file mode 100644
> index 0000000000..0b69237a3d
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.h
> @@ -0,0 +1,205 @@
> +/** @file
> + PCI Hot Plug support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 Found;
> + BOOLEAN Initialized;
> + VOID *Padding;
> +} ROOT_HPC_DATA;
> +
> +//
> +// Reference of some global variables
> +//
> +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 paths 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 controller 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 returned.
> +
> + @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 returned.
> +
> + @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 returned event that invoke this function.
> +
> + @return Status of create event.
> +
> +**/
> +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
> + );
> +
> +/**
> + Check whether PciIoDevice supports PCIe hotplug.
> +
> + This is equivalent to the following condition:
> + - the device is either a PCIe switch downstream port or a root port,
> + - and the device has the SlotImplemented bit set in its PCIe capability
> + register,
> + - and the device has the HotPlugCapable bit set in its slot capabilities
> + register.
> +
> + @param[in] PciIoDevice The device being checked.
> +
> + @retval TRUE PciIoDevice is a PCIe port that accepts a hot-plugged device.
> + @retval FALSE Otherwise.
> +
> +**/
> +BOOLEAN
> +SupportsPcieHotplug (
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.c
> new file mode 100644
> index 0000000000..c656056315
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.c
> @@ -0,0 +1,2087 @@
> +/** @file
> + EFI PCI IO protocol functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +extern EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
> +
> +//
> +// 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
> +};
> +
> +/**
> + 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 ((UINT32)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 >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) {
> + 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 ((UINT32)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 ((UINT32)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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Status = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + if ((*Result & Mask) == Value || Delay == 0) {
> + return EFI_SUCCESS;
> + }
> + do {
> + //
> + // Stall 10 us = 100 * 100ns
> + //
> + gBS->Stall (10);
> +
> + Status = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + if ((*Result & Mask) == Value) {
> + return EFI_SUCCESS;
> + }
> + if (Delay <= 100) {
> + return EFI_TIMEOUT;
> + }
> + Delay -= 100;
> + } while (TRUE);
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->PollMem (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Offset,
> + Mask,
> + Value,
> + Delay,
> + Result
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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 ((UINT32)Width > EfiPciIoWidthUint64) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width,
> 1, &Offset);
> + if (EFI_ERROR (Status)) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Status = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + if ((*Result & Mask) == Value || Delay == 0) {
> + return EFI_SUCCESS;
> + }
> + do {
> + //
> + // Stall 10 us = 100 * 100ns
> + //
> + gBS->Stall (10);
> +
> + Status = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + if ((*Result & Mask) == Value) {
> + return EFI_SUCCESS;
> + }
> + if (Delay <= 100) {
> + return EFI_TIMEOUT;
> + }
> + Delay -= 100;
> + } while (TRUE);
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->PollIo (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Offset,
> + Mask,
> + Value,
> + Delay,
> + Result
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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 ((UINT32)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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Count *= (UINTN)(1 << (Width & 0x03));
> + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> + }
> + }
> +
> +
> + Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Offset,
> + Count,
> + Buffer
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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 ((UINT32)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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Count *= (UINTN)(1 << (Width & 0x03));
> + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Offset,
> + Count,
> + Buffer
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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 ((UINT32)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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Count *= (UINTN)(1 << (Width & 0x03));
> + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->Io.Read (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Offset,
> + Count,
> + Buffer
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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 ((UINT32)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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Count *= (UINTN)(1 << (Width & 0x03));
> + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->Io.Write (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Offset,
> + Count,
> + Buffer
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Count *= (UINTN)(1 << (Width & 0x03));
> + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Address,
> + Count,
> + Buffer
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> + Count *= (UINTN)(1 << (Width & 0x03));
> + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + Address,
> + Count,
> + Buffer
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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 ((UINT32)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;
> + }
> +
> + //
> + // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> + //
> + if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> + if ((SrcOffset & ((1 << (Width & 0x03)) - 1)) != 0 || (DestOffset & ((1 <<
> (Width & 0x03)) - 1)) != 0) {
> + Count *= (UINTN)(1 << (Width & 0x03));
> + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> + }
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->CopyMem (
> + PciIoDevice->PciRootBridgeIo,
> + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> + DestOffset,
> + SrcOffset,
> + Count
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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;
> + UINT64 IoMmuAttribute;
> + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION
> RootBridgeIoOperation;
> +
> + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> + if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress ==
> NULL || Mapping == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RootBridgeIoOperation =
> (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)Operation;
> + if ((PciIoDevice->Attributes &
> EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
> + RootBridgeIoOperation =
> (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)(Operation +
> EfiPciOperationBusMasterRead64);
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->Map (
> + PciIoDevice->PciRootBridgeIo,
> + RootBridgeIoOperation,
> + HostAddress,
> + NumberOfBytes,
> + DeviceAddress,
> + Mapping
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + if (mIoMmuProtocol != NULL) {
> + if (!EFI_ERROR (Status)) {
> + switch (Operation) {
> + case EfiPciIoOperationBusMasterRead:
> + IoMmuAttribute = EDKII_IOMMU_ACCESS_READ;
> + break;
> + case EfiPciIoOperationBusMasterWrite:
> + IoMmuAttribute = EDKII_IOMMU_ACCESS_WRITE;
> + break;
> + case EfiPciIoOperationBusMasterCommonBuffer:
> + IoMmuAttribute = EDKII_IOMMU_ACCESS_READ |
> EDKII_IOMMU_ACCESS_WRITE;
> + break;
> + default:
> + ASSERT(FALSE);
> + return EFI_INVALID_PARAMETER;
> + }
> + mIoMmuProtocol->SetAttribute (
> + mIoMmuProtocol,
> + PciIoDevice->Handle,
> + *Mapping,
> + IoMmuAttribute
> + );
> + }
> + }
> +
> + 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);
> +
> + if (mIoMmuProtocol != NULL) {
> + mIoMmuProtocol->SetAttribute (
> + mIoMmuProtocol,
> + PciIoDevice->Handle,
> + Mapping,
> + 0
> + );
> + }
> +
> + Status = PciIoDevice->PciRootBridgeIo->Unmap (
> + PciIoDevice->PciRootBridgeIo,
> + Mapping
> + );
> +
> + if (EFI_ERROR (Status)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Allocates pages that are suitable for an
> EfiPciIoOperationBusMasterCommonBuffer
> + or EfiPciOperationBusMasterCommonBuffer64 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, MEMORY_CACHED and
> DUAL_ADDRESS_CYCLE.
> + @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)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + 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 attributes.
> +
> +**/
> +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;
> + }
> +
> + //
> + // Mask off attributes not supported by PCI root bridge.
> + //
> + Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
> + EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
> + EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
> +
> + //
> + // 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 Host Bridge
> + //
> + Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo-
> >ParentHandle);
> +
> + if (Temp == NULL) {
> + //
> + // If there is no VGA device on the segment, 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 &=
> (~(UINT64)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 conform 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
> + );
> + }
> +
> + //
> + // Check VGA and VGA16, they can not be set at the same time
> + //
> + if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO |
> EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) != 0) {
> + if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |
> EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> + }
> +
> + //
> + // 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;
> +
> + //
> + // 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 Host
> Bridge
> + //
> + Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo-
> >ParentHandle);
> + 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 relevant 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)) {
> + REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> + EFI_ERROR_CODE | EFI_ERROR_MINOR,
> + EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> + PciIoDevice->DevicePath
> + );
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Retrieve the AddrTranslationOffset from RootBridgeIo for the
> + specified range.
> +
> + @param RootBridgeIo Root Bridge IO instance.
> + @param AddrRangeMin The base address of the MMIO.
> + @param AddrLen The length of the MMIO.
> +
> + @retval The AddrTranslationOffset from RootBridgeIo for the
> + specified range, or (UINT64) -1 if the range is not
> + found in RootBridgeIo.
> +**/
> +UINT64
> +GetMmioAddressTranslationOffset (
> + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo,
> + UINT64 AddrRangeMin,
> + UINT64 AddrLen
> + )
> +{
> + EFI_STATUS Status;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
> +
> + Status = RootBridgeIo->Configuration (
> + RootBridgeIo,
> + (VOID **) &Configuration
> + );
> + if (EFI_ERROR (Status)) {
> + return (UINT64) -1;
> + }
> +
> + // According to UEFI 2.7,
> EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Configuration()
> + // returns host address instead of device address, while
> AddrTranslationOffset
> + // is not zero, and device address = host address + AddrTranslationOffset,
> so
> + // we convert host address to device address for range compare.
> + while (Configuration->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
> + if ((Configuration->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
> + (Configuration->AddrRangeMin + Configuration-
> >AddrTranslationOffset <= AddrRangeMin) &&
> + (Configuration->AddrRangeMin + Configuration->AddrLen +
> Configuration->AddrTranslationOffset >= AddrRangeMin + AddrLen)
> + ) {
> + return Configuration->AddrTranslationOffset;
> + }
> + Configuration++;
> + }
> +
> + //
> + // The resource occupied by BAR should be in the range reported by
> RootBridge.
> + //
> + ASSERT (FALSE);
> + return (UINT64) -1;
> +}
> +
> +/**
> + 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 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 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
> + )
> +{
> + PCI_IO_DEVICE *PciIoDevice;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
> + EFI_ACPI_END_TAG_DESCRIPTOR *End;
> +
> + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> + if (Supports == NULL && Resources == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice-
> >PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
> + 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) {
> + Descriptor = AllocateZeroPool (sizeof
> (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof
> (EFI_ACPI_END_TAG_DESCRIPTOR));
> + if (Descriptor == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + *Resources = Descriptor;
> +
> + Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> + Descriptor->Len = (UINT16) (sizeof
> (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
> + Descriptor->AddrRangeMin = PciIoDevice-
> >PciBar[BarIndex].BaseAddress;
> + Descriptor->AddrLen = PciIoDevice->PciBar[BarIndex].Length;
> + Descriptor->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
> +
> + switch (PciIoDevice->PciBar[BarIndex].BarType) {
> + case PciBarTypeIo16:
> + case PciBarTypeIo32:
> + //
> + // Io
> + //
> + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
> + break;
> +
> + case PciBarTypePMem32:
> + //
> + // prefetchable
> + //
> + Descriptor->SpecificFlag =
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E;
> + //
> + // Fall through
> + //
> + case PciBarTypeMem32:
> + //
> + // Mem
> + //
> + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
> + //
> + // 32 bit
> + //
> + Descriptor->AddrSpaceGranularity = 32;
> + break;
> +
> + case PciBarTypePMem64:
> + //
> + // prefetchable
> + //
> + Descriptor->SpecificFlag =
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E;
> + //
> + // Fall through
> + //
> + case PciBarTypeMem64:
> + //
> + // Mem
> + //
> + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
> + //
> + // 64 bit
> + //
> + Descriptor->AddrSpaceGranularity = 64;
> + break;
> +
> + default:
> + break;
> + }
> +
> + //
> + // put the checksum
> + //
> + End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
> + End->Desc = ACPI_END_TAG_DESCRIPTOR;
> + End->Checksum = 0;
> +
> + //
> + // Get the Address Translation Offset
> + //
> + if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
> + Descriptor->AddrTranslationOffset = GetMmioAddressTranslationOffset
> (
> + PciIoDevice->PciRootBridgeIo,
> + Descriptor->AddrRangeMin,
> + Descriptor->AddrLen
> + );
> + if (Descriptor->AddrTranslationOffset == (UINT64) -1) {
> + FreePool (Descriptor);
> + return EFI_UNSUPPORTED;
> + }
> + }
> +
> + // According to UEFI spec 2.7, we need return host address for
> + // PciIo->GetBarAttributes, and host address = device address -
> translation.
> + Descriptor->AddrRangeMin -= Descriptor->AddrTranslationOffset;
> + }
> +
> + 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 described 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;
> +}
> +
> +
> +/**
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.h
> new file mode 100644
> index 0000000000..c00516ee6a
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.h
> @@ -0,0 +1,660 @@
> +/** @file
> + EFI PCI IO protocol functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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
> + or EfiPciOperationBusMasterCommonBuffer64 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, MEMORY_CACHED and
> DUAL_ADDRESS_CYCLE.
> + @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 attributes.
> +
> +**/
> +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 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 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
> + );
> +
> +
> +/**
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.c
> new file mode 100644
> index 0000000000..2b76100740
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.c
> @@ -0,0 +1,1809 @@
> +/** @file
> + Internal library implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +CHAR16 *mBarTypeStr[] = {
> + L"Unknow",
> + L" Io16",
> + L" Io32",
> + L" Mem32",
> + L"PMem32",
> + L" Mem64",
> + L"PMem64",
> + L" OpRom",
> + L" Io",
> + L" Mem",
> + L"Unknow"
> + };
> +
> +/**
> + Retrieve the max bus number that is assigned to the Root Bridge hierarchy.
> + It can support the case that there are multiple bus ranges.
> +
> + @param Bridge Bridge device instance.
> +
> + @retval The max bus number that is assigned to this Root Bridge
> hierarchy.
> +
> +**/
> +UINT16
> +PciGetMaxBusNumber (
> + IN PCI_IO_DEVICE *Bridge
> + )
> +{
> + PCI_IO_DEVICE *RootBridge;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
> + UINT64 MaxNumberInRange;
> +
> + //
> + // Get PCI Root Bridge device
> + //
> + RootBridge = Bridge;
> + while (RootBridge->Parent != NULL) {
> + RootBridge = RootBridge->Parent;
> + }
> + MaxNumberInRange = 0;
> + //
> + // Iterate the bus number ranges to get max PCI bus number
> + //
> + BusNumberRanges = RootBridge->BusNumberRanges;
> + while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
> + MaxNumberInRange = BusNumberRanges->AddrRangeMin +
> BusNumberRanges->AddrLen - 1;
> + BusNumberRanges++;
> + }
> + return (UINT16) MaxNumberInRange;
> +}
> +
> +/**
> + 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;
> + }
> +}
> +
> +/**
> + Dump the resourc map of the bridge device.
> +
> + @param[in] BridgeResource Resource descriptor of the bridge device.
> +**/
> +VOID
> +DumpBridgeResource (
> + IN PCI_RESOURCE_NODE *BridgeResource
> + )
> +{
> + LIST_ENTRY *Link;
> + PCI_RESOURCE_NODE *Resource;
> + PCI_BAR *Bar;
> +
> + if ((BridgeResource != NULL) && (BridgeResource->Length != 0)) {
> + DEBUG ((
> + EFI_D_INFO, "Type = %s; Base = 0x%lx;\tLength = 0x%lx;\tAlignment =
> 0x%lx\n",
> + mBarTypeStr[MIN (BridgeResource->ResType, PciBarTypeMaxType)],
> + BridgeResource->PciDev->PciBar[BridgeResource->Bar].BaseAddress,
> + BridgeResource->Length, BridgeResource->Alignment
> + ));
> + for ( Link = GetFirstNode (&BridgeResource->ChildList)
> + ; !IsNull (&BridgeResource->ChildList, Link)
> + ; Link = GetNextNode (&BridgeResource->ChildList, Link)
> + ) {
> + Resource = RESOURCE_NODE_FROM_LINK (Link);
> + if (Resource->ResourceUsage == PciResUsageTypical) {
> + Bar = Resource->Virtual ? Resource->PciDev->VfPciBar : Resource-
> >PciDev->PciBar;
> + DEBUG ((
> + EFI_D_INFO, " Base = 0x%lx;\tLength = 0x%lx;\tAlignment =
> 0x%lx;\tOwner = %s [%02x|%02x|%02x:",
> + Bar[Resource->Bar].BaseAddress, Resource->Length, Resource-
> >Alignment,
> + IS_PCI_BRIDGE (&Resource->PciDev->Pci) ? L"PPB" :
> + IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) ? L"P2C" :
> + L"PCI",
> + Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber,
> + Resource->PciDev->FunctionNumber
> + ));
> +
> + if ((!IS_PCI_BRIDGE (&Resource->PciDev->Pci) &&
> !IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci)) ||
> + (IS_PCI_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar <
> PPB_IO_RANGE)) ||
> + (IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar
> < P2C_MEM_1))
> + ) {
> + //
> + // The resource requirement comes from the device itself.
> + //
> + DEBUG ((EFI_D_INFO, "%02x]", Bar[Resource->Bar].Offset));
> + } else {
> + //
> + // The resource requirement comes from the subordinate devices.
> + //
> + DEBUG ((EFI_D_INFO, "**]"));
> + }
> + } else {
> + DEBUG ((EFI_D_INFO, " Base = Padding;\tLength = 0x%lx;\tAlignment
> = 0x%lx", Resource->Length, Resource->Alignment));
> + }
> + if (BridgeResource->ResType != Resource->ResType) {
> + DEBUG ((EFI_D_INFO, "; Type = %s", mBarTypeStr[MIN (Resource-
> >ResType, PciBarTypeMaxType)]));
> + }
> + DEBUG ((EFI_D_INFO, "\n"));
> + }
> + }
> +}
> +
> +/**
> + Find the corresponding resource node for the Device in child list of
> BridgeResource.
> +
> + @param[in] Device Pointer to PCI_IO_DEVICE.
> + @param[in] BridgeResource Pointer to PCI_RESOURCE_NODE.
> + @param[out] DeviceResources Pointer to a buffer to receive resources for
> the Device.
> +
> + @return Count of the resource descriptors returned.
> +**/
> +UINTN
> +FindResourceNode (
> + IN PCI_IO_DEVICE *Device,
> + IN PCI_RESOURCE_NODE *BridgeResource,
> + OUT PCI_RESOURCE_NODE **DeviceResources OPTIONAL
> + )
> +{
> + LIST_ENTRY *Link;
> + PCI_RESOURCE_NODE *Resource;
> + UINTN Count;
> +
> + Count = 0;
> + for ( Link = BridgeResource->ChildList.ForwardLink
> + ; Link != &BridgeResource->ChildList
> + ; Link = Link->ForwardLink
> + ) {
> + Resource = RESOURCE_NODE_FROM_LINK (Link);
> + if (Resource->PciDev == Device) {
> + if (DeviceResources != NULL) {
> + DeviceResources[Count] = Resource;
> + }
> + Count++;
> + }
> + }
> +
> + return Count;
> +}
> +
> +/**
> + Dump the resource map of all the devices under Bridge.
> +
> + @param[in] Bridge Bridge device instance.
> + @param[in] Resources Resource descriptors for the bridge device.
> + @param[in] ResourceCount Count of resource descriptors.
> +**/
> +VOID
> +DumpResourceMap (
> + IN PCI_IO_DEVICE *Bridge,
> + IN PCI_RESOURCE_NODE **Resources,
> + IN UINTN ResourceCount
> + )
> +{
> + EFI_STATUS Status;
> + LIST_ENTRY *Link;
> + PCI_IO_DEVICE *Device;
> + UINTN Index;
> + CHAR16 *Str;
> + PCI_RESOURCE_NODE **ChildResources;
> + UINTN ChildResourceCount;
> +
> + DEBUG ((EFI_D_INFO, "PciBus: Resource Map for "));
> +
> + Status = gBS->OpenProtocol (
> + Bridge->Handle,
> + &gEfiPciRootBridgeIoProtocolGuid,
> + NULL,
> + NULL,
> + NULL,
> + EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + EFI_D_INFO, "Bridge [%02x|%02x|%02x]\n",
> + Bridge->BusNumber, Bridge->DeviceNumber, Bridge->FunctionNumber
> + ));
> + } else {
> + Str = ConvertDevicePathToText (
> + DevicePathFromHandle (Bridge->Handle),
> + FALSE,
> + FALSE
> + );
> + DEBUG ((EFI_D_INFO, "Root Bridge %s\n", Str != NULL ? Str : L""));
> + if (Str != NULL) {
> + FreePool (Str);
> + }
> + }
> +
> + for (Index = 0; Index < ResourceCount; Index++) {
> + DumpBridgeResource (Resources[Index]);
> + }
> + DEBUG ((EFI_D_INFO, "\n"));
> +
> + for ( Link = Bridge->ChildList.ForwardLink
> + ; Link != &Bridge->ChildList
> + ; Link = Link->ForwardLink
> + ) {
> + Device = PCI_IO_DEVICE_FROM_LINK (Link);
> + if (IS_PCI_BRIDGE (&Device->Pci)) {
> +
> + ChildResourceCount = 0;
> + for (Index = 0; Index < ResourceCount; Index++) {
> + ChildResourceCount += FindResourceNode (Device, Resources[Index],
> NULL);
> + }
> + ChildResources = AllocatePool (sizeof (PCI_RESOURCE_NODE *) *
> ChildResourceCount);
> + ASSERT (ChildResources != NULL);
> + ChildResourceCount = 0;
> + for (Index = 0; Index < ResourceCount; Index++) {
> + ChildResourceCount += FindResourceNode (Device, Resources[Index],
> &ChildResources[ChildResourceCount]);
> + }
> +
> + DumpResourceMap (Device, ChildResources, ChildResourceCount);
> + FreePool (ChildResources);
> + }
> + }
> +}
> +
> +/**
> + Adjust the Devices' BAR size to minimum value if it support Resizeable BAR
> capability.
> +
> + @param RootBridgeDev Pointer to instance of PCI_IO_DEVICE..
> +
> + @return TRUE if BAR size is adjusted.
> +
> +**/
> +BOOLEAN
> +AdjustPciDeviceBarSize (
> + IN PCI_IO_DEVICE *RootBridgeDev
> + )
> +{
> + PCI_IO_DEVICE *PciIoDevice;
> + LIST_ENTRY *CurrentLink;
> + BOOLEAN Adjusted;
> + UINTN Offset;
> + UINTN BarIndex;
> +
> + Adjusted = FALSE;
> + CurrentLink = RootBridgeDev->ChildList.ForwardLink;
> +
> + while (CurrentLink != NULL && CurrentLink != &RootBridgeDev->ChildList)
> {
> + PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> + if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> + if (AdjustPciDeviceBarSize (PciIoDevice)) {
> + Adjusted = TRUE;
> + }
> + } else {
> + if (PciIoDevice->ResizableBarOffset != 0) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "PciBus: [%02x|%02x|%02x] Adjust Pci Device Bar Size\n",
> + PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice-
> >FunctionNumber
> + ));
> + PciProgramResizableBar (PciIoDevice, PciResizableBarMin);
> + //
> + // Start to parse the bars
> + //
> + for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex <
> PCI_MAX_BAR; BarIndex++) {
> + Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
> + }
> + Adjusted = TRUE;
> + DEBUG_CODE (DumpPciBars (PciIoDevice););
> + }
> + }
> +
> + CurrentLink = CurrentLink->ForwardLink;
> + }
> +
> + return Adjusted;
> +}
> +
> +/**
> + 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;
> + UINT32 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;
> + EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD
> HandleExtendedData;
> + EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD
> AllocFailExtendedData;
> + BOOLEAN ResizableBarNeedAdjust;
> + BOOLEAN ResizableBarAdjusted;
> +
> + ResizableBarNeedAdjust = PcdGetBool (PcdPcieResizableBarSupport);
> +
> + //
> + // 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
> + //
> +
> + //
> + // If non-standard PCI Bridge I/O window alignment is supported,
> + // set I/O aligment to minimum possible alignment for root bridge.
> + //
> + IoBridge = CreateResourceNode (
> + RootBridgeDev,
> + 0,
> + FeaturePcdGet (PcdPciBridgeIoAlignmentProbe) ? 0x1FF: 0xFFF,
> + RB_IO_RANGE,
> + PciBarTypeIo16,
> + PciResUsageTypical
> + );
> +
> + Mem32Bridge = CreateResourceNode (
> + RootBridgeDev,
> + 0,
> + 0xFFFFF,
> + RB_MEM32_RANGE,
> + PciBarTypeMem32,
> + PciResUsageTypical
> + );
> +
> + PMem32Bridge = CreateResourceNode (
> + RootBridgeDev,
> + 0,
> + 0xFFFFF,
> + RB_PMEM32_RANGE,
> + PciBarTypePMem32,
> + PciResUsageTypical
> + );
> +
> + Mem64Bridge = CreateResourceNode (
> + RootBridgeDev,
> + 0,
> + 0xFFFFF,
> + RB_MEM64_RANGE,
> + PciBarTypeMem64,
> + PciResUsageTypical
> + );
> +
> + PMem64Bridge = CreateResourceNode (
> + RootBridgeDev,
> + 0,
> + 0xFFFFF,
> + RB_PMEM64_RANGE,
> + PciBarTypePMem64,
> + PciResUsageTypical
> + );
> +
> + //
> + // Get the max ROM size that the root bridge can process
> + // Insert to resource map so that there will be dedicate MEM32 resource
> range for Option ROM.
> + // All devices' Option ROM share the same MEM32 resource.
> + //
> + MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
> + if (MaxOptionRomSize != 0) {
> + RootBridgeDev->PciBar[0].BarType = PciBarTypeOpRom;
> + RootBridgeDev->PciBar[0].Length = MaxOptionRomSize;
> + RootBridgeDev->PciBar[0].Alignment = MaxOptionRomSize - 1;
> + GetResourceFromDevice (RootBridgeDev, IoBridge, Mem32Bridge,
> PMem32Bridge, Mem64Bridge, PMem64Bridge);
> + }
> +
> + //
> + // Create resourcemap by going through all the devices subject to this
> root bridge
> + //
> + CreateResourceMap (
> + RootBridgeDev,
> + IoBridge,
> + Mem32Bridge,
> + PMem32Bridge,
> + Mem64Bridge,
> + PMem64Bridge
> + );
> +
> + //
> + // Based on the all the resource tree, construct 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
> + );
> + //
> + // If SubmitResources returns error, PciBus isn't able to start.
> + // It's a fatal error so assertion is added.
> + //
> + DEBUG ((EFI_D_INFO, "PciBus: HostBridge->SubmitResources() - %r\n",
> Status));
> + ASSERT_EFI_ERROR (Status);
> + }
> +
> + //
> + // 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);
> + DEBUG ((EFI_D_INFO, "PciBus: HostBridge-
> >NotifyPhase(AllocateResources) - %r\n", Status));
> + 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)
> + );
> +
> + //
> + // When resource conflict happens, adjust the BAR size first.
> + // Only when adjusting BAR size doesn't help or BAR size cannot be
> adjusted,
> + // reject the device who requests largest resource that causes conflict.
> + //
> + ResizableBarAdjusted = FALSE;
> + if (ResizableBarNeedAdjust) {
> + ResizableBarAdjusted = AdjustPciDeviceBarSize (RootBridgeDev);
> + ResizableBarNeedAdjust = FALSE;
> + }
> + if (!ResizableBarAdjusted) {
> + 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;
> + }
> + }
> + }
> + //
> + // 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_RES_ALLOC,
> + (VOID *) &HandleExtendedData,
> + sizeof (HandleExtendedData)
> + );
> +
> + //
> + // Notify pci bus driver starts to program the resource
> + //
> + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + 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
> + );
> +
> + //
> + // Create the entire system resource map from the information collected
> by
> + // enumerator. Several resource tree was created
> + //
> + FindResourceNode (RootBridgeDev, &IoPool, &IoBridge);
> + FindResourceNode (RootBridgeDev, &Mem32Pool, &Mem32Bridge);
> + FindResourceNode (RootBridgeDev, &PMem32Pool, &PMem32Bridge);
> + FindResourceNode (RootBridgeDev, &Mem64Pool, &Mem64Bridge);
> + FindResourceNode (RootBridgeDev, &PMem64Pool, &PMem64Bridge);
> +
> + ASSERT (IoBridge != NULL);
> + ASSERT (Mem32Bridge != NULL);
> + ASSERT (PMem32Bridge != NULL);
> + ASSERT (Mem64Bridge != NULL);
> + ASSERT (PMem64Bridge != NULL);
> +
> + //
> + // 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
> + );
> +
> + //
> + // Process Option ROM for this root bridge after all BARs are
> programmed.
> + // The PPB's MEM32 RANGE BAR is re-programmed to the Option ROM
> BAR Base in order to
> + // shadow the Option ROM of the devices under the PPB.
> + // After the shadow, Option ROM BAR decoding is turned off and the
> PPB's MEM32 RANGE
> + // BAR is restored back to the original value.
> + // The original value is programmed by ProgramResource() above.
> + //
> + DEBUG ((
> + DEBUG_INFO, "Process Option ROM: BAR Base/Length = %lx/%lx\n",
> + RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev-
> >PciBar[0].Length
> + ));
> + ProcessOptionRom (RootBridgeDev, RootBridgeDev-
> >PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length);
> +
> + IoBridge ->PciDev->PciBar[IoBridge ->Bar].BaseAddress = IoBase;
> + Mem32Bridge ->PciDev->PciBar[Mem32Bridge ->Bar].BaseAddress =
> Mem32Base;
> + PMem32Bridge->PciDev->PciBar[PMem32Bridge->Bar].BaseAddress =
> PMem32Base;
> + Mem64Bridge ->PciDev->PciBar[Mem64Bridge ->Bar].BaseAddress =
> Mem64Base;
> + PMem64Bridge->PciDev->PciBar[PMem64Bridge->Bar].BaseAddress =
> PMem64Base;
> +
> + //
> + // Dump the resource map for current root bridge
> + //
> + DEBUG_CODE (
> + PCI_RESOURCE_NODE *Resources[5];
> + Resources[0] = IoBridge;
> + Resources[1] = Mem32Bridge;
> + Resources[2] = PMem32Bridge;
> + Resources[3] = Mem64Bridge;
> + Resources[4] = PMem64Bridge;
> + DumpResourceMap (RootBridgeDev, Resources, ARRAY_SIZE
> (Resources));
> + );
> +
> + 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
> + //
> + Status = NotifyPhase (PciResAlloc,
> EfiPciHostBridgeEndResourceAllocation);
> +
> + return Status;
> +}
> +
> +/**
> + Allocate NumberOfBuses buses and return the next available PCI bus
> number.
> +
> + @param Bridge Bridge device instance.
> + @param StartBusNumber Current available PCI bus number.
> + @param NumberOfBuses Number of buses enumerated below the
> StartBusNumber.
> + @param NextBusNumber Next available PCI bus number.
> +
> + @retval EFI_SUCCESS Available bus number resource is enough. Next
> available PCI bus number
> + is returned in NextBusNumber.
> + @retval EFI_OUT_OF_RESOURCES Available bus number resource is not
> enough for allocation.
> +
> +**/
> +EFI_STATUS
> +PciAllocateBusNumber (
> + IN PCI_IO_DEVICE *Bridge,
> + IN UINT8 StartBusNumber,
> + IN UINT8 NumberOfBuses,
> + OUT UINT8 *NextBusNumber
> + )
> +{
> + PCI_IO_DEVICE *RootBridge;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
> + UINT8 NextNumber;
> + UINT64 MaxNumberInRange;
> +
> + //
> + // Get PCI Root Bridge device
> + //
> + RootBridge = Bridge;
> + while (RootBridge->Parent != NULL) {
> + RootBridge = RootBridge->Parent;
> + }
> +
> + //
> + // Get next available PCI bus number
> + //
> + BusNumberRanges = RootBridge->BusNumberRanges;
> + while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
> + MaxNumberInRange = BusNumberRanges->AddrRangeMin +
> BusNumberRanges->AddrLen - 1;
> + if (StartBusNumber >= BusNumberRanges->AddrRangeMin &&
> StartBusNumber <= MaxNumberInRange) {
> + NextNumber = (UINT8)(StartBusNumber + NumberOfBuses);
> + while (NextNumber > MaxNumberInRange) {
> + ++BusNumberRanges;
> + if (BusNumberRanges->Desc == ACPI_END_TAG_DESCRIPTOR) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + NextNumber = (UINT8)(NextNumber + (BusNumberRanges-
> >AddrRangeMin - (MaxNumberInRange + 1)));
> + MaxNumberInRange = BusNumberRanges->AddrRangeMin +
> BusNumberRanges->AddrLen - 1;
> + }
> + *NextBusNumber = NextNumber;
> + return EFI_SUCCESS;
> + }
> + BusNumberRanges++;
> + }
> + return EFI_OUT_OF_RESOURCES;
> +}
> +
> +/**
> + 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;
> + UINT8 SecondBus;
> + UINT8 PaddedSubBus;
> + 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;
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *NextDescriptors;
> + 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) && Func == 0) {
> + //
> + // go to next device if there is no Function 0
> + //
> + break;
> + }
> +
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + //
> + // Get the PCI device information
> + //
> + Status = PciSearchDevice (
> + Bridge,
> + &Pci,
> + StartBusNumber,
> + Device,
> + Func,
> + &PciDevice
> + );
> +
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + 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
> + );
> + }
> +
> + if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> + //
> + // For Pci Hotplug controller devcie only
> + //
> + if (gPciHotPlugInit != NULL) {
> + //
> + // Check if it is a Hotplug PCI controller
> + //
> + if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
> + gPciRootHpcData[HpIndex].Found = TRUE;
> +
> + 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 supported,
> + // Get the bridge information
> + //
> + BusPadding = FALSE;
> + if (gPciHotPlugInit != NULL) {
> +
> + if (IsPciHotPlugBus (PciDevice)) {
> +
> + //
> + // If it is initialized, get the padded bus range
> + //
> + Status = gPciHotPlugInit->GetResourcePadding (
> + gPciHotPlugInit,
> + PciDevice->DevicePath,
> + PciAddress,
> + &State,
> + (VOID **) &Descriptors,
> + &Attributes
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + BusRange = 0;
> + NextDescriptors = Descriptors;
> + Status = PciGetBusRange (
> + &NextDescriptors,
> + NULL,
> + NULL,
> + &BusRange
> + );
> +
> + FreePool (Descriptors);
> +
> + if (!EFI_ERROR (Status)) {
> + BusPadding = TRUE;
> + } else if (Status != EFI_NOT_FOUND) {
> + //
> + // EFI_NOT_FOUND is not a real error. It indicates no bus number
> padding requested.
> + //
> + return Status;
> + }
> + }
> + }
> + }
> +
> + Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1,
> SubBusNumber);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + 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 = PciGetMaxBusNumber (Bridge);
> + 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
> + );
> +
> + Status = PciScanBus (
> + PciDevice,
> + 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 {
> + //
> + // Reserve the larger one between the actual occupied bus number
> and padded bus number
> + //
> + Status = PciAllocateBusNumber (PciDevice, SecondBus, (UINT8)
> (BusRange), &PaddedSubBus);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + *SubBusNumber = MAX (PaddedSubBus, *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
> + // Go through each function, just reserve the MAX ReservedBusNum
> for one device
> + //
> + if (PcdGetBool (PcdSrIovSupport) && PciDevice->SrIovCapabilityOffset
> != 0) {
> + if (TempReservedBusNum < PciDevice->ReservedBusNum) {
> +
> + Status = PciAllocateBusNumber (PciDevice, *SubBusNumber, (UINT8)
> (PciDevice->ReservedBusNum - TempReservedBusNum), SubBusNumber);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + 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_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
> + //
> + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + 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 = RemoveEntryList (Link);
> + DestroyRootBridge (RootBridgeDev);
> + }
> +
> + //
> + // Wait for all HPC initialized
> + //
> + Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_ERROR, "Some root HPC failed to initialize\n"));
> + return Status;
> + }
> +
> + //
> + // Notify the bus allocation phase is about to start for the 2nd time
> + //
> + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + 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
> + //
> + Status = NotifyPhase (PciResAlloc,
> EfiPciHostBridgeBeginResourceAllocation);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + 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;
> +}
> +
> +/**
> + This function is used to program the Resizable BAR Register.
> +
> + @param PciIoDevice A pointer to the PCI_IO_DEVICE.
> + @param ResizableBarOp PciResizableBarMax: Set BAR to max size
> + PciResizableBarMin: set BAR to min size.
> +
> + @retval EFI_SUCCESS Successfully enumerated the host bridge.
> + @retval other Some error occurred when enumerating the host
> bridge.
> +
> +**/
> +EFI_STATUS
> +PciProgramResizableBar (
> + IN PCI_IO_DEVICE *PciIoDevice,
> + IN PCI_RESIZABLE_BAR_OPERATION ResizableBarOp
> + )
> +{
> + EFI_PCI_IO_PROTOCOL *PciIo;
> + UINT64 Capabilities;
> + UINT32 Index;
> + UINT32 Offset;
> + INTN Bit;
> + UINTN ResizableBarNumber;
> + EFI_STATUS Status;
> + PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY
> Entries[PCI_MAX_BAR];
> +
> + ASSERT (PciIoDevice->ResizableBarOffset != 0);
> +
> + DEBUG ((DEBUG_INFO, " Programs Resizable BAR register, offset:
> 0x%08x, number: %d\n",
> + PciIoDevice->ResizableBarOffset, PciIoDevice->ResizableBarNumber));
> +
> + ResizableBarNumber = MIN (PciIoDevice->ResizableBarNumber,
> PCI_MAX_BAR);
> + PciIo = &PciIoDevice->PciIo;
> + Status = PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint8,
> + PciIoDevice->ResizableBarOffset + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER),
> + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY) *
> ResizableBarNumber,
> + (VOID *)(&Entries)
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + for (Index = 0; Index < ResizableBarNumber; Index++) {
> +
> + //
> + // When the bit of Capabilities Set, indicates that the Function supports
> + // operating with the BAR sized to (2^Bit) MB.
> + // Example:
> + // Bit 0 is set: supports operating with the BAR sized to 1 MB
> + // Bit 1 is set: supports operating with the BAR sized to 2 MB
> + // Bit n is set: supports operating with the BAR sized to (2^n) MB
> + //
> + Capabilities =
> LShiftU64(Entries[Index].ResizableBarControl.Bits.BarSizeCapability, 28)
> + | Entries[Index].ResizableBarCapability.Bits.BarSizeCapability;
> +
> + if (ResizableBarOp == PciResizableBarMax) {
> + Bit = HighBitSet64(Capabilities);
> + } else {
> + ASSERT (ResizableBarOp == PciResizableBarMin);
> + Bit = LowBitSet64(Capabilities);
> + }
> +
> + ASSERT (Bit >= 0);
> +
> + Offset = PciIoDevice->ResizableBarOffset + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
> + + Index * sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY)
> + + OFFSET_OF
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY,
> ResizableBarControl);
> +
> + Entries[Index].ResizableBarControl.Bits.BarSize = (UINT32) Bit;
> + DEBUG ((
> + DEBUG_INFO,
> + " Resizable Bar: Offset = 0x%x, Bar Size Capability = 0x%016lx, New Bar
> Size = 0x%lx\n",
> + OFFSET_OF (PCI_TYPE00,
> Device.Bar[Entries[Index].ResizableBarControl.Bits.BarIndex]),
> + Capabilities, LShiftU64 (SIZE_1MB, Bit)
> + ));
> + PciIo->Pci.Write (
> + PciIo,
> + EfiPciIoWidthUint32,
> + Offset,
> + 1,
> + &Entries[Index].ResizableBarControl.Uint32
> + );
> + }
> +
> + return EFI_SUCCESS;
> +}
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.h
> new file mode 100644
> index 0000000000..70ab07a8c3
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.h
> @@ -0,0 +1,179 @@
> +/** @file
> + Internal library declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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;
> +
> +typedef enum {
> + PciResizableBarMin = 0x00,
> + PciResizableBarMax = 0xFF
> +} PCI_RESIZABLE_BAR_OPERATION;
> +
> +/**
> + 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
> + );
> +
> +/**
> + Allocate NumberOfBuses buses and return the next available PCI bus
> number.
> +
> + @param Bridge Bridge device instance.
> + @param StartBusNumber Current available PCI bus number.
> + @param NumberOfBuses Number of buses enumerated below the
> StartBusNumber.
> + @param NextBusNumber Next available PCI bus number.
> +
> + @retval EFI_SUCCESS Available bus number resource is enough. Next
> available PCI bus number
> + is returned in NextBusNumber.
> + @retval EFI_OUT_OF_RESOURCES Available bus number resource is not
> enough for allocation.
> +
> +**/
> +EFI_STATUS
> +PciAllocateBusNumber (
> + IN PCI_IO_DEVICE *Bridge,
> + IN UINT8 StartBusNumber,
> + IN UINT8 NumberOfBuses,
> + OUT UINT8 *NextBusNumber
> + );
> +
> +/**
> + 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
> + );
> +
> +/**
> + This function is used to program the Resizable BAR Register.
> +
> + @param PciIoDevice A pointer to the PCI_IO_DEVICE.
> + @param ResizableBarOp PciResizableBarMax: Set BAR to max size
> + PciResizableBarMin: set BAR to min size.
> +
> + @retval EFI_SUCCESS Successfully enumerated the host bridge.
> + @retval other Some error occurred when enumerating the host
> bridge.
> +
> +**/
> +EFI_STATUS
> +PciProgramResizableBar (
> + IN PCI_IO_DEVICE *PciIoDevice,
> + IN PCI_RESIZABLE_BAR_OPERATION ResizableBarOp
> + );
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.c
> new file mode 100644
> index 0000000000..efdfa2d415
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.c
> @@ -0,0 +1,776 @@
> +/** @file
> + PCI Rom supporting funtions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2021, American Megatrends International LLC.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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;
> + UINT32 InitializationSize;
> +
> + 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);
> + ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
> +
> + 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 = Pcir->ImageLength * 512;
> + InitializationSize = (UINT32) EfiRomHeader->InitializationSize * 512;
> + if (InitializationSize > ImageSize || EfiRomHeader->EfiImageHeaderOffset
> >= InitializationSize) {
> + return EFI_NOT_FOUND;
> + }
> +
> + ImageBuffer = (UINT8 *) EfiRomHeader + EfiRomHeader-
> >EfiImageHeaderOffset;
> + ImageLength = InitializationSize - 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 = (~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;
> + UINT8 Indicator;
> +
> + Indicator = 0;
> + RomHeader = RomImage;
> + if (RomHeader == NULL) {
> + return FALSE;
> + }
> +
> + do {
> + if (RomHeader->Signature !=
> PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
> + RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *)
> RomHeader + 512);
> + continue;
> + }
> +
> + //
> + // The PCI Data Structure must be DWORD aligned.
> + //
> + if (RomHeader->PcirOffset == 0 ||
> + (RomHeader->PcirOffset & 3) != 0 ||
> + (UINT8 *) RomHeader + RomHeader->PcirOffset + sizeof
> (PCI_DATA_STRUCTURE) > (UINT8 *) RomImage + RomSize) {
> + break;
> + }
> +
> + RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader +
> RomHeader->PcirOffset);
> + if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
> + break;
> + }
> +
> + if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
> + return TRUE;
> + }
> +
> + Indicator = RomPcir->Indicator;
> + RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader
> + RomPcir->ImageLength * 512);
> + } while (((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) &&
> ((Indicator & 0x80) == 0x00));
> +
> + 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;
> + UINT32 LegacyImageLength;
> + 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;
> + LegacyImageLength = 0;
> +
> + 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;
> + //
> + // If the pointer to the PCI Data Structure is invalid, no further images can
> be located.
> + // The PCI Data Structure must be DWORD aligned.
> + //
> + if (OffsetPcir == 0 ||
> + (OffsetPcir & 3) != 0 ||
> + RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) >
> RomSize) {
> + break;
> + }
> + PciDevice->PciRootBridgeIo->Mem.Read (
> + PciDevice->PciRootBridgeIo,
> + EfiPciWidthUint8,
> + RomBarOffset + OffsetPcir,
> + sizeof (PCI_DATA_STRUCTURE),
> + (UINT8 *) RomPcir
> + );
> + //
> + // If a valid signature is not present in the PCI Data Structure, no further
> images can be located.
> + //
> + if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
> + break;
> + }
> + if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
> + break;
> + }
> + if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
> + CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
> + LegacyImageLength =
> ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)-
> >Size512) * 512;
> + }
> + 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, LegacyImageLength);
> + }
> +
> + 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->EmbeddedRom = TRUE;
> + PciDevice->PciIo.RomSize = RomImageSize;
> + PciDevice->PciIo.RomImage = RomInMemory;
> +
> + //TiogaPass Override START : Skip OPROM - Mellanox card which has SSVID
> 0x15B3 and SSDID 0x0031
> + if (PciDevice->Pci.Hdr.VendorId == 0x15B3 && PciDevice->Pci.Hdr.DeviceId
> == 0x1015) {
> + if (PciDevice->Pci.Device.SubsystemVendorID == 0x15B3 && PciDevice-
> >Pci.Device.SubsystemID == 0x0031) {
> + PciDevice->PciIo.RomImage = NULL;
> + PciDevice->PciIo.RomSize = 0;
> + DEBUG((DEBUG_ERROR,"Device_MLX @ [B%X|D%X|F%X], VID=%X,
> DID=%X SVID=%X, SVDID=%XOverrides ROM file @ %X size=%X .\n\n",
> + PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice-
> >FunctionNumber,
> + PciDevice->Pci.Hdr.VendorId, PciDevice->Pci.Hdr.DeviceId,
> PciDevice->Pci.Device.SubsystemVendorID,PciDevice-
> >Pci.Device.SubsystemID,PciDevice->PciIo.RomImage, PciDevice-
> >PciIo.RomSize));
> + }
> + }
> + //TiogaPass Override END
> +
> + // 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,
> + 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;
> + EFI_PCI_IO_PROTOCOL *PciIo;
> +
> + PciIo = &PciDevice->PciIo;
> + if (Enable) {
> +
> + //
> + // 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
> + //
> + ProgramUpstreamBridgeForRom (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.
> + //
> + ProgramUpstreamBridgeForRom (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;
> + 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;
> +
> + if (RomBar == NULL) {
> + return RetStatus;
> + }
> + ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)-
> >Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
> +
> + do {
> + EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
> + if (EfiRomHeader->Signature !=
> PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
> + RomBarOffset += 512;
> + continue;
> + }
> +
> + Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader-
> >PcirOffset);
> + ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
> + ImageSize = (UINT32) (Pcir->ImageLength * 512);
> + Indicator = Pcir->Indicator;
> +
> + //
> + // Skip the image if it is not an EFI PCI Option ROM image
> + //
> + if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
> + goto NextImage;
> + }
> +
> + //
> + // Ignore the EFI PCI Option ROM image if it is an EFI application
> + //
> + if (EfiRomHeader->EfiSubsystem ==
> EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
> + goto NextImage;
> + }
> +
> + //
> + // 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;
> + ImageHandle = NULL;
> +
> + Status = gBS->LoadImage (
> + FALSE,
> + gPciBusDriverBinding.DriverBindingHandle,
> + PciOptionRomImageDevicePath,
> + Buffer,
> + BufferSize,
> + &ImageHandle
> + );
> + if (EFI_ERROR (Status)) {
> + //
> + // Record the Option ROM Image device path when LoadImage fails.
> + // PciOverride.GetDriver() will try to look for the Image Handle using the
> device path later.
> + //
> + AddDriver (PciDevice, NULL, PciOptionRomImageDevicePath);
> + } else {
> + Status = gBS->StartImage (ImageHandle, NULL, NULL);
> + if (!EFI_ERROR (Status)) {
> + //
> + // Record the Option ROM Image Handle
> + //
> + AddDriver (PciDevice, ImageHandle, NULL);
> + PciRomAddImageMapping (
> + ImageHandle,
> + PciDevice->PciRootBridgeIo->SegmentNumber,
> + PciDevice->BusNumber,
> + PciDevice->DeviceNumber,
> + PciDevice->FunctionNumber,
> + PciDevice->PciIo.RomImage,
> + PciDevice->PciIo.RomSize
> + );
> + RetStatus = EFI_SUCCESS;
> + }
> + }
> + FreePool (PciOptionRomImageDevicePath);
> +
> +NextImage:
> + RomBarOffset += ImageSize;
> +
> + } while (((Indicator & 0x80) == 0x00) && (((UINTN) RomBarOffset - (UINTN)
> RomBar) < PciDevice->RomSize));
> +
> + return RetStatus;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.h
> new file mode 100644
> index 0000000000..60e147a7b9
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.h
> @@ -0,0 +1,136 @@
> +/** @file
> + PCI Rom supporting functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.c
> new file mode 100644
> index 0000000000..cf3f8164cd
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.c
> @@ -0,0 +1,82 @@
> +/** @file
> + Power management support functions implementation for PCI Bus
> module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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
> + //
> +
> + //
> + // Read PMCSR
> + //
> + Status = PciIoDevice->PciIo.Pci.Read (
> + &PciIoDevice->PciIo,
> + EfiPciIoWidthUint16,
> + PowerManagementRegBlock + 4,
> + 1,
> + &PowerManagementCSR
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + //
> + // Clear PME_Status bit
> + //
> + PowerManagementCSR |= BIT15;
> + //
> + // Clear PME_En bit. PowerState = D0.
> + //
> + PowerManagementCSR &= ~(BIT8 | BIT1 | BIT0);
> +
> + //
> + // Write PMCSR
> + //
> + Status = PciIoDevice->PciIo.Pci.Write (
> + &PciIoDevice->PciIo,
> + EfiPciIoWidthUint16,
> + PowerManagementRegBlock + 4,
> + 1,
> + &PowerManagementCSR
> + );
> + }
> + return Status;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.h
> new file mode 100644
> index 0000000000..44e97ec45a
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.h
> @@ -0,0 +1,28 @@
> +/** @file
> + Power management support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.c
> new file mode 100644
> index 0000000000..1461af7d5d
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.c
> @@ -0,0 +1,2292 @@
> +/** @file
> + PCI resources support functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +//
> +// The default policy for the PCI bus driver is NOT to reserve I/O ranges for
> both ISA aliases and VGA aliases.
> +//
> +BOOLEAN mReserveIsaAliases = FALSE;
> +BOOLEAN mReserveVgaAliases = FALSE;
> +BOOLEAN mPolicyDetermined = FALSE;
> +
> +/**
> + 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
> + resource 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 prefetchable 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;
> + EFI_PCI_PLATFORM_POLICY PciPolicy;
> + UINT64 PaddingAperture;
> +
> + if (!mPolicyDetermined) {
> + //
> + // Check PciPlatform policy
> + //
> + Status = EFI_NOT_FOUND;
> + PciPolicy = 0;
> + if (gPciPlatformProtocol != NULL) {
> + Status = gPciPlatformProtocol->GetPlatformPolicy (
> + gPciPlatformProtocol,
> + &PciPolicy
> + );
> + }
> +
> + if (EFI_ERROR (Status) && gPciOverrideProtocol != NULL) {
> + Status = gPciOverrideProtocol->GetPlatformPolicy (
> + gPciOverrideProtocol,
> + &PciPolicy
> + );
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) {
> + mReserveIsaAliases = TRUE;
> + }
> + if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) {
> + mReserveVgaAliases = TRUE;
> + }
> + }
> + mPolicyDetermined = TRUE;
> + }
> +
> + Aperture = 0;
> + PaddingAperture = 0;
> +
> + if (Bridge == NULL) {
> + return ;
> + }
> +
> + //
> + // Assume the bridge is aligned
> + //
> + for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
> + ; !IsNull (&Bridge->ChildList, CurrentLink)
> + ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
> + ) {
> +
> + Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
> + if (Node->ResourceUsage == PciResUsagePadding) {
> + ASSERT (PaddingAperture == 0);
> + PaddingAperture = Node->Length;
> + continue;
> + }
> + //
> + // 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 (mReserveIsaAliases || mReserveVgaAliases) {
> + 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 (mReserveIsaAliases) {
> + SkipIsaAliasAperture (
> + &Aperture,
> + Node->Length
> + );
> + Offset = Aperture & (Node->Alignment);
> + if (Offset != 0) {
> + Aperture = Aperture + (Node->Alignment + 1) - Offset;
> + }
> + } else if (mReserveVgaAliases) {
> + 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;
> + }
> +
> + //
> + // 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;
> + }
> + }
> +
> + //
> + // Hotplug controller needs padding resources.
> + // Use the larger one between the padding resource and actual occupied
> resource.
> + //
> + Bridge->Length = MAX (Bridge->Length, PaddingAperture);
> +}
> +
> +/**
> + This function is used to calculate the resource aperture
> + for a given bridge device.
> +
> + @param Bridge PCI resource node for given bridge device.
> +
> +**/
> +VOID
> +CalculateResourceAperture (
> + IN PCI_RESOURCE_NODE *Bridge
> + )
> +{
> + UINT64 Aperture[2];
> + LIST_ENTRY *CurrentLink;
> + PCI_RESOURCE_NODE *Node;
> +
> + if (Bridge == NULL) {
> + return ;
> + }
> +
> + if (Bridge->ResType == PciBarTypeIo16) {
> +
> + CalculateApertureIo16 (Bridge);
> + return ;
> + }
> +
> + Aperture[PciResUsageTypical] = 0;
> + Aperture[PciResUsagePadding] = 0;
> + //
> + // Assume the bridge is aligned
> + //
> + for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
> + ; !IsNull (&Bridge->ChildList, CurrentLink)
> + ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
> + ) {
> + Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +
> + //
> + // It's possible for a bridge to contain multiple padding resource
> + // nodes due to DegradeResource().
> + //
> + ASSERT ((Node->ResourceUsage == PciResUsageTypical) ||
> + (Node->ResourceUsage == PciResUsagePadding));
> + ASSERT (Node->ResourceUsage < ARRAY_SIZE (Aperture));
> + //
> + // Recode current aperture as a offset
> + // Apply padding resource to meet alignment requirement
> + // Node offset will be used in future real allocation
> + //
> + Node->Offset = ALIGN_VALUE (Aperture[Node->ResourceUsage], Node-
> >Alignment + 1);
> +
> + //
> + // Record the total aperture.
> + //
> + Aperture[Node->ResourceUsage] = Node->Offset + Node->Length;
> + }
> +
> + //
> + // Adjust the aperture with the bridge's alignment
> + //
> + Aperture[PciResUsageTypical] = ALIGN_VALUE
> (Aperture[PciResUsageTypical], Bridge->Alignment + 1);
> + Aperture[PciResUsagePadding] = ALIGN_VALUE
> (Aperture[PciResUsagePadding], Bridge->Alignment + 1);
> +
> + //
> + // Hotplug controller needs padding resources.
> + // Use the larger one between the padding resource and actual occupied
> resource.
> + //
> + Bridge->Length = MAX (Aperture[PciResUsageTypical],
> Aperture[PciResUsagePadding]);
> +
> + //
> + // Adjust the bridge's alignment to the MAX (first) alignment of all children.
> + //
> + 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 info 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:
> + case PciBarTypeOpRom:
> +
> + Node = CreateResourceNode (
> + PciDev,
> + (PciDev->PciBar)[Index].Length,
> + (PciDev->PciBar)[Index].Alignment,
> + Index,
> + (PciDev->PciBar)[Index].BarType,
> + 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;
> +
> + 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 (smaller alignments may be supported).
> + //
> + IoBridge = CreateResourceNode (
> + Temp,
> + 0,
> + Temp->BridgeIoAlignment,
> + 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 resource 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
> + )
> +{
> + PCI_IO_DEVICE *PciIoDevice;
> + LIST_ENTRY *ChildDeviceLink;
> + LIST_ENTRY *ChildNodeLink;
> + LIST_ENTRY *NextChildNodeLink;
> + PCI_RESOURCE_NODE *ResourceNode;
> +
> + if (FeaturePcdGet (PcdPciDegradeResourceForOptionRom)) {
> + //
> + // If any child device has both option ROM and 64-bit BAR, degrade its
> PMEM64/MEM64
> + // requests in case that if a legacy option ROM image can not access 64-bit
> resources.
> + //
> + ChildDeviceLink = Bridge->ChildList.ForwardLink;
> + while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList)
> {
> + PciIoDevice = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink);
> + if (PciIoDevice->RomSize != 0) {
> + if (!IsListEmpty (&Mem64Node->ChildList)) {
> + ChildNodeLink = Mem64Node->ChildList.ForwardLink;
> + while (ChildNodeLink != &Mem64Node->ChildList) {
> + ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
> + NextChildNodeLink = ChildNodeLink->ForwardLink;
> +
> + if ((ResourceNode->PciDev == PciIoDevice) &&
> + (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode-
> >Bar].BarTypeFixed)
> + ) {
> + RemoveEntryList (ChildNodeLink);
> + InsertResourceNode (Mem32Node, ResourceNode);
> + }
> + ChildNodeLink = NextChildNodeLink;
> + }
> + }
> +
> + if (!IsListEmpty (&PMem64Node->ChildList)) {
> + ChildNodeLink = PMem64Node->ChildList.ForwardLink;
> + while (ChildNodeLink != &PMem64Node->ChildList) {
> + ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
> + NextChildNodeLink = ChildNodeLink->ForwardLink;
> +
> + if ((ResourceNode->PciDev == PciIoDevice) &&
> + (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode-
> >Bar].BarTypeFixed)
> + ) {
> + RemoveEntryList (ChildNodeLink);
> + InsertResourceNode (PMem32Node, ResourceNode);
> + }
> + ChildNodeLink = NextChildNodeLink;
> + }
> + }
> +
> + }
> + ChildDeviceLink = ChildDeviceLink->ForwardLink;
> + }
> + }
> +
> + //
> + // If firmware is in 32-bit mode,
> + // then degrade PMEM64/MEM64 requests
> + //
> + if (sizeof (UINTN) <= 4) {
> + MergeResourceTree (
> + Mem32Node,
> + Mem64Node,
> + TRUE
> + );
> +
> + MergeResourceTree (
> + PMem32Node,
> + PMem64Node,
> + TRUE
> + );
> + } else {
> + //
> + // if the bridge does not support MEM64, degrade MEM64 to MEM32
> + //
> + if (!BridgeSupportResourceDecode (Bridge,
> EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
> + MergeResourceTree (
> + Mem32Node,
> + Mem64Node,
> + TRUE
> + );
> + }
> +
> + //
> + // if the bridge does not support PMEM64, degrade PMEM64 to PMEM32
> + //
> + if (!BridgeSupportResourceDecode (Bridge,
> EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
> + MergeResourceTree (
> + PMem32Node,
> + PMem64Node,
> + TRUE
> + );
> + }
> +
> + //
> + // if both PMEM64 and PMEM32 requests from child devices, which can
> not be satisfied
> + // by a P2P bridge simultaneously, keep PMEM64 and degrade PMEM32
> to MEM32.
> + //
> + if (!IsListEmpty (&PMem64Node->ChildList) && Bridge->Parent != NULL) {
> + MergeResourceTree (
> + Mem32Node,
> + PMem32Node,
> + TRUE
> + );
> + }
> + }
> +
> + //
> + // If bridge doesn't support Pmem32
> + // degrade it to mem32
> + //
> + if (!BridgeSupportResourceDecode (Bridge,
> EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
> + MergeResourceTree (
> + Mem32Node,
> + PMem32Node,
> + TRUE
> + );
> + }
> +
> + //
> + // if root 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
> + );
> +
> + //
> + // No need to check if to degrade MEM64 after merge, because
> + // if there are PMEM64 still here, 64-bit decode should be supported
> + // by the root bride.
> + //
> + 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 programmed.
> + @param Bridge PCI resource node for the bridge device.
> +
> + @retval EFI_SUCCESS Successfully to program all resources
> + 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 programmed.
> + @param Node Point to resource 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);
> + return;
> + }
> +
> + 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
> + );
> + //
> + // Continue to the case PciBarTypeOpRom to set the BaseAddress.
> + // PciBarTypeOpRom is a virtual BAR only in root bridge, to capture
> + // the MEM32 resource requirement for Option ROM shadow.
> + //
> +
> + case PciBarTypeOpRom:
> + 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 programmed.
> + @param Node Point to resource 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;
> + 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;
> + break;
> +
> + case PciBarTypeIo16:
> + case PciBarTypeIo32:
> + break;
> +
> + default:
> + break;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Program PCI-PCI bridge aperture.
> +
> + @param Base Base address for resource.
> + @param Node Point to resource 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
> + // Aperture 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:
> + 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;
> + Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
> + 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;
> + Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
> + break;
> +
> + default:
> + break;
> + }
> + 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 device instance.
> + @param OptionRomBase Base address for Option Rom.
> + @param Enable Enable or disable PCI memory.
> +
> +**/
> +VOID
> +ProgramUpstreamBridgeForRom (
> + IN PCI_IO_DEVICE *PciDevice,
> + IN UINT32 OptionRomBase,
> + IN BOOLEAN Enable
> + )
> +{
> + PCI_IO_DEVICE *Parent;
> + EFI_PCI_IO_PROTOCOL *PciIo;
> + UINT16 Base;
> + UINT16 Limit;
> + //
> + // For root bridge, just return.
> + //
> + Parent = PciDevice->Parent;
> + while (Parent != NULL) {
> + if (!IS_PCI_BRIDGE (&Parent->Pci)) {
> + break;
> + }
> +
> + PciIo = &Parent->PciIo;
> +
> + //
> + // Program PPB to only open a single <= 16MB aperture
> + //
> + if (Enable) {
> + //
> + // Only cover MMIO for Option ROM.
> + //
> + Base = (UINT16) (OptionRomBase >> 16);
> + Limit = (UINT16) ((OptionRomBase + PciDevice->RomSize - 1) >> 16);
> + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryBase), 1, &Base);
> + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryLimit), 1, &Limit);
> +
> + PCI_ENABLE_COMMAND_REGISTER (Parent,
> EFI_PCI_COMMAND_MEMORY_SPACE);
> + } else {
> + //
> + // Cover 32bit MMIO for devices below the bridge.
> + //
> + if (Parent->PciBar[PPB_MEM32_RANGE].Length == 0) {
> + //
> + // When devices under the bridge contains Option ROM and doesn't
> require 32bit MMIO.
> + //
> + Base = (UINT16) gAllOne;
> + Limit = (UINT16) gAllZero;
> + } else {
> + Base = (UINT16) ((UINT32) Parent-
> >PciBar[PPB_MEM32_RANGE].BaseAddress >> 16);
> + Limit = (UINT16) ((UINT32) (Parent-
> >PciBar[PPB_MEM32_RANGE].BaseAddress
> + + Parent->PciBar[PPB_MEM32_RANGE].Length - 1) >>
> 16);
> + }
> + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryBase), 1, &Base);
> + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryLimit), 1, &Limit);
> +
> + 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);
> +}
> +
> +/**
> + Destroy 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 decodes memory range 0
> + //
> + Node = CreateResourceNode (
> + PciDev,
> + 0x2000000,
> + 0x1ffffff,
> + 1,
> + PciBarTypeMem32,
> + PciResUsagePadding
> + );
> +
> + InsertResourceNode (
> + Mem32Node,
> + Node
> + );
> +
> + //
> + // Memory Base/Limit Register 1
> + // Bar 2 decodes memory range1
> + //
> + Node = CreateResourceNode (
> + PciDev,
> + 0x2000000,
> + 0x1ffffff,
> + 2,
> + PciBarTypePMem32,
> + PciResUsagePadding
> + );
> +
> + InsertResourceNode (
> + PMem32Node,
> + Node
> + );
> +
> + //
> + // Io Base/Limit
> + // Bar 3 decodes io range 0
> + //
> + Node = CreateResourceNode (
> + PciDev,
> + 0x100,
> + 0xff,
> + 3,
> + PciBarTypeIo16,
> + PciResUsagePadding
> + );
> +
> + InsertResourceNode (
> + IoNode,
> + Node
> + );
> +
> + //
> + // Io Base/Limit
> + // Bar 4 decodes 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 prefetchable 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 prefetchable 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) {
> +
> + //
> + // prefetchable
> + //
> + if (Ptr->SpecificFlag == 0x6) {
> + if (Ptr->AddrLen != 0) {
> + Node = CreateResourceNode (
> + PciDev,
> + Ptr->AddrLen,
> + Ptr->AddrRangeMax,
> + DummyBarIndex,
> + PciBarTypePMem32,
> + PciResUsagePadding
> + );
> + InsertResourceNode (
> + PMem32Node,
> + Node
> + );
> + }
> +
> + Ptr++;
> + continue;
> + }
> +
> + //
> + // Non-prefetchable
> + //
> + 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) {
> +
> + //
> + // prefetchable
> + //
> + if (Ptr->SpecificFlag == 0x6) {
> + if (Ptr->AddrLen != 0) {
> + Node = CreateResourceNode (
> + PciDev,
> + Ptr->AddrLen,
> + Ptr->AddrRangeMax,
> + DummyBarIndex,
> + PciBarTypePMem64,
> + PciResUsagePadding
> + );
> + InsertResourceNode (
> + PMem64Node,
> + Node
> + );
> + }
> +
> + Ptr++;
> + continue;
> + }
> +
> + //
> + // Non-prefetchable
> + //
> + 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.h
> new file mode 100644
> index 0000000000..2a33f77e55
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.h
> @@ -0,0 +1,456 @@
> +/** @file
> + PCI resources support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_RESOURCE_SUPPORT_H_
> +#define _EFI_PCI_RESOURCE_SUPPORT_H_
> +
> +typedef enum {
> + PciResUsageTypical,
> + PciResUsagePadding
> +} 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
> + resource 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 prefetchable 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 resource node for given bridge device.
> +
> +**/
> +VOID
> +CalculateResourceAperture (
> + IN PCI_RESOURCE_NODE *Bridge
> + );
> +
> +/**
> + Get IO/Memory resource info 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 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
> + );
> +
> +/**
> + 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 programmed.
> + @param Bridge PCI resource node for the bridge device.
> +
> + @retval EFI_SUCCESS Successfully to program all resources
> + 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 programmed.
> + @param Node Point to resource 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 programmed.
> + @param Node Point to resource node structure.
> +
> +**/
> +EFI_STATUS
> +ProgramVfBar (
> + IN UINT64 Base,
> + IN PCI_RESOURCE_NODE *Node
> + );
> +
> +/**
> + Program PCI-PCI bridge aperture.
> +
> + @param Base Base address for resource.
> + @param Node Point to resource node structure.
> +
> +**/
> +VOID
> +ProgramPpbApperture (
> + IN UINT64 Base,
> + IN PCI_RESOURCE_NODE *Node
> + );
> +
> +/**
> + Program parent bridge for Option Rom.
> +
> + @param PciDevice Pci device instance.
> + @param OptionRomBase Base address for Option Rom.
> + @param Enable Enable or disable PCI memory.
> +
> +**/
> +VOID
> +ProgramUpstreamBridgeForRom (
> + 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
> + );
> +
> +/**
> + Destroy 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/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.c
> new file mode 100644
> index 0000000000..507aed5cfe
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.c
> @@ -0,0 +1,135 @@
> +/** @file
> + Set up ROM Table for PCI Bus module.
> +
> +Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +//
> +// PCI ROM image information
> +//
> +typedef struct {
> + EFI_HANDLE ImageHandle;
> + UINTN Seg;
> + UINT8 Bus;
> + UINT8 Dev;
> + UINT8 Func;
> + VOID *RomImage;
> + UINT64 RomSize;
> +} PCI_ROM_IMAGE;
> +
> +UINTN mNumberOfPciRomImages = 0;
> +UINTN mMaxNumberOfPciRomImages = 0;
> +PCI_ROM_IMAGE *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 RomImage Option Rom buffer.
> + @param RomSize Size of Option Rom buffer.
> +**/
> +VOID
> +PciRomAddImageMapping (
> + IN EFI_HANDLE ImageHandle,
> + IN UINTN Seg,
> + IN UINT8 Bus,
> + IN UINT8 Dev,
> + IN UINT8 Func,
> + IN VOID *RomImage,
> + IN UINT64 RomSize
> + )
> +{
> + UINTN Index;
> + PCI_ROM_IMAGE *NewTable;
> +
> + for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
> + if (mRomImageTable[Index].Seg == Seg &&
> + mRomImageTable[Index].Bus == Bus &&
> + mRomImageTable[Index].Dev == Dev &&
> + mRomImageTable[Index].Func == Func) {
> + //
> + // Expect once RomImage and RomSize are recorded, they will be passed
> in
> + // later when updating ImageHandle
> + //
> + ASSERT ((mRomImageTable[Index].RomImage == NULL) || (RomImage
> == mRomImageTable[Index].RomImage));
> + ASSERT ((mRomImageTable[Index].RomSize == 0 ) || (RomSize ==
> mRomImageTable[Index].RomSize ));
> + break;
> + }
> + }
> +
> + if (Index == mNumberOfPciRomImages) {
> + //
> + // Rom Image Table buffer needs to grow.
> + //
> + if (mNumberOfPciRomImages == mMaxNumberOfPciRomImages) {
> + NewTable = ReallocatePool (
> + mMaxNumberOfPciRomImages * sizeof (PCI_ROM_IMAGE),
> + (mMaxNumberOfPciRomImages + 0x20) * sizeof
> (PCI_ROM_IMAGE),
> + mRomImageTable
> + );
> + if (NewTable == NULL) {
> + return ;
> + }
> +
> + mRomImageTable = NewTable;
> + mMaxNumberOfPciRomImages += 0x20;
> + }
> + //
> + // Record the new PCI device
> + //
> + mRomImageTable[Index].Seg = Seg;
> + mRomImageTable[Index].Bus = Bus;
> + mRomImageTable[Index].Dev = Dev;
> + mRomImageTable[Index].Func = Func;
> + mNumberOfPciRomImages++;
> + }
> +
> + mRomImageTable[Index].ImageHandle = ImageHandle;
> + mRomImageTable[Index].RomImage = RomImage;
> + mRomImageTable[Index].RomSize = RomSize;
> +}
> +
> +/**
> + 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;
> +
> + PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
> +
> + 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 ) {
> +
> + if (mRomImageTable[Index].ImageHandle != NULL) {
> + AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle, NULL);
> + }
> + PciIoDevice->PciIo.RomImage = mRomImageTable[Index].RomImage;
> + PciIoDevice->PciIo.RomSize = mRomImageTable[Index].RomSize;
> + return TRUE;
> + }
> + }
> +
> + return FALSE;
> +}
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.h
> new file mode 100644
> index 0000000000..fb356bd6de
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.h
> @@ -0,0 +1,48 @@
> +/** @file
> + Set up ROM Table for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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 RomImage Option Rom buffer.
> + @param RomSize Size of Option Rom buffer.
> +**/
> +VOID
> +PciRomAddImageMapping (
> + IN EFI_HANDLE ImageHandle,
> + IN UINTN Seg,
> + IN UINT8 Bus,
> + IN UINT8 Dev,
> + IN UINT8 Func,
> + IN VOID *RomImage,
> + IN UINT64 RomSize
> + );
> +
> +/**
> + 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
> --
> 2.25.0.windows.1
>
>
> Please consider the environment before printing this email.
>
> The information contained in this message may be confidential and
> proprietary to American Megatrends (AMI). This communication is intended
> to be read only by the individual or entity to whom it is addressed or by their
> designee. If the reader of this message is not the intended recipient, you are
> on notice that any distribution of this message, in any form, is strictly
> prohibited. Please promptly notify the sender by reply e-mail or by
> telephone at 770-246-8600, and then delete or destroy all copies of the
> transmission.
next prev parent reply other threads:[~2021-07-29 2:11 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-16 21:47 [edk2-platforms] [PATCH V1 2/2] PurleyOpenBoardPkg : Override generic PciBus Driver with Platform specific instance of PciBus driver manickavasakam karpagavinayagam
2021-07-29 2:10 ` Nate DeSimone [this message]
-- strict thread matches above, loose matches on Subject: below --
2021-06-17 0:51 [edk2-platforms] [PATCH V1] PurleyOpenBoardPkg : Support for LINUX Boot Nate DeSimone
2021-06-17 0:51 ` [edk2-platforms] [PATCH V1 2/2] PurleyOpenBoardPkg : Override generic PciBus Driver with Platform specific instance of PciBus driver Nate DeSimone
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=BN6PR1101MB2147C791EDA80682E692F929CDEB9@BN6PR1101MB2147.namprd11.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox