@@ -552,6 +552,7 @@ [Components]
UefiCpuPkg/CpuDxe/CpuDxe.inf
PcAtChipsetPkg/8254TimerDxe/8254Timer.inf
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+ OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
<LibraryClasses>
PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -561,6 +561,7 @@ [Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
PcAtChipsetPkg/8254TimerDxe/8254Timer.inf
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+ OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
<LibraryClasses>
PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -559,6 +559,7 @@ [Components]
UefiCpuPkg/CpuDxe/CpuDxe.inf
PcAtChipsetPkg/8254TimerDxe/8254Timer.inf
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+ OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
<LibraryClasses>
PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -208,6 +208,7 @@ [FV.DXEFV]
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
INF PcAtChipsetPkg/8254TimerDxe/8254Timer.inf
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF PcAtChipsetPkg/KbcResetDxe/Reset.inf
@@ -208,6 +208,7 @@ [FV.DXEFV]
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
INF PcAtChipsetPkg/8254TimerDxe/8254Timer.inf
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF PcAtChipsetPkg/KbcResetDxe/Reset.inf
@@ -208,6 +208,7 @@ [FV.DXEFV]
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
INF PcAtChipsetPkg/8254TimerDxe/8254Timer.inf
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF PcAtChipsetPkg/KbcResetDxe/Reset.inf
new file mode 100644
@@ -0,0 +1,42 @@
+## @file
+# This driver implements EFI_PCI_HOT_PLUG_INIT_PROTOCOL, providing the PCI bus
+# driver with resource padding information, for PCIe hotplug purposes.
+#
+# Copyright (C) 2016, Red Hat, Inc.
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciHotPlugInitDxe
+ FILE_GUID = 11A6EDF6-A9BE-426D-A6CC-B22FE51D9224
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DriverInitialize
+
+[Sources]
+ PciHotPlugInit.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiPciHotPlugInitProtocolGuid ## SOMETIMES_PRODUCES
+
+[Depex]
+ TRUE
new file mode 100644
@@ -0,0 +1,342 @@
+/** @file
+ This driver implements EFI_PCI_HOT_PLUG_INIT_PROTOCOL, providing the PCI bus
+ driver with resource padding information, for PCIe hotplug purposes.
+
+ Copyright (C) 2016, Red Hat, Inc.
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <IndustryStandard/Acpi10.h>
+
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/PciHotPlugInit.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+//
+// The protocol interface this driver produces.
+//
+// Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform
+// Init 1.4a Spec, Volume 5.
+//
+STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;
+
+
+//
+// Resource padding template for the GetResourcePadding() protocol member
+// function.
+//
+// Refer to Table 8 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" in
+// the Platform Init 1.4a Spec, Volume 5.
+//
+// This structure is interpreted by the ApplyResourcePadding() function in the
+// edk2 PCI Bus UEFI_DRIVER.
+//
+#pragma pack (1)
+typedef struct {
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR MmioPadding;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR IoPadding;
+ EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
+} RESOURCE_PADDING;
+#pragma pack ()
+
+STATIC CONST RESOURCE_PADDING mPadding = {
+ //
+ // MmioPadding
+ //
+ {
+ ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc
+ (UINT16)( // Len
+ sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
+ OFFSET_OF (
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
+ ResType
+ )
+ ),
+ ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType
+ 0, // GenFlag:
+ // ignored
+ 0, // SpecificFlag:
+ // non-prefetchable
+ 64, // AddrSpaceGranularity:
+ // reserve 64-bit aperture
+ 0, // AddrRangeMin:
+ // ignored
+ SIZE_2MB - 1, // AddrRangeMax:
+ // align at 2MB
+ 0, // AddrTranslationOffset:
+ // ignored
+ SIZE_2MB // AddrLen:
+ // 2MB padding
+ },
+
+ //
+ // IoPadding
+ //
+ {
+ ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc
+ (UINT16)( // Len
+ sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
+ OFFSET_OF (
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
+ ResType
+ )
+ ),
+ ACPI_ADDRESS_SPACE_TYPE_IO,// ResType
+ 0, // GenFlag:
+ // ignored
+ 0, // SpecificFlag:
+ // ignored
+ 0, // AddrSpaceGranularity:
+ // ignored
+ 0, // AddrRangeMin:
+ // ignored
+ 512 - 1, // AddrRangeMax:
+ // align at 512 IO ports
+ 0, // AddrTranslationOffset:
+ // ignored
+ 512 // AddrLen:
+ // 512 IO ports
+ },
+
+ //
+ // EndDesc
+ //
+ {
+ ACPI_END_TAG_DESCRIPTOR, // Desc
+ 0 // Checksum: to be ignored
+ }
+};
+
+
+/**
+ Returns a list of root Hot Plug Controllers (HPCs) that require
+ initialization during the boot process.
+
+ This procedure returns a list of root HPCs. The PCI bus driver must
+ initialize these controllers during the boot process. The PCI bus driver may
+ or may not be able to detect these HPCs. If the platform includes a
+ PCI-to-CardBus bridge, it can be included in this list if it requires
+ initialization. The HpcList must be self consistent. An HPC cannot control
+ any of its parent buses. Only one HPC can control a PCI bus. Because this
+ list includes only root HPCs, no HPC in the list can be a child of another
+ HPC. This policy must be enforced by the EFI_PCI_HOT_PLUG_INIT_PROTOCOL.
+ The PCI bus driver may not check for such invalid conditions. The callee
+ allocates the buffer HpcList
+
+ @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
+ instance.
+ @param[out] HpcCount The number of root HPCs that were returned.
+ @param[out] HpcList The list of root HPCs. HpcCount defines the number of
+ elements in this list.
+
+ @retval EFI_SUCCESS HpcList was returned.
+ @retval EFI_OUT_OF_RESOURCES HpcList was not returned due to insufficient
+ resources.
+ @retval EFI_INVALID_PARAMETER HpcCount is NULL or HpcList is NULL.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetRootHpcList (
+ IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
+ OUT UINTN *HpcCount,
+ OUT EFI_HPC_LOCATION **HpcList
+ )
+{
+ if (HpcCount == NULL || HpcList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // There are no top-level (i.e., un-enumerable) hot-plug controllers in QEMU
+ // that would require special initialization.
+ //
+ *HpcCount = 0;
+ *HpcList = NULL;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initializes one root Hot Plug Controller (HPC). This process may causes
+ initialization of its subordinate buses.
+
+ This function initializes the specified HPC. At the end of initialization,
+ the hot-plug slots or sockets (controlled by this HPC) are powered and are
+ connected to the bus. All the necessary registers in the HPC are set up. For
+ a Standard (PCI) Hot Plug Controller (SHPC), the registers that must be set
+ up are defined in the PCI Standard Hot Plug Controller and Subsystem
+ Specification.
+
+ @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
+ instance.
+ @param[in] HpcDevicePath The device path to the HPC that is being
+ initialized.
+ @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
+ @param[in] Event The event that should be signaled when the HPC
+ initialization is complete. Set to NULL if the
+ caller wants to wait until the entire
+ initialization process is complete.
+ @param[out] HpcState The state of the HPC hardware. The state is
+ EFI_HPC_STATE_INITIALIZED or
+ EFI_HPC_STATE_ENABLED.
+
+ @retval EFI_SUCCESS If Event is NULL, the specific HPC was
+ successfully initialized. If Event is not
+ NULL, Event will be signaled at a later time
+ when initialization is complete.
+ @retval EFI_UNSUPPORTED This instance of
+ EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
+ support the specified HPC.
+ @retval EFI_OUT_OF_RESOURCES Initialization failed due to insufficient
+ resources.
+ @retval EFI_INVALID_PARAMETER HpcState is NULL.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+InitializeRootHpc (
+ IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
+ IN UINT64 HpcPciAddress,
+ IN EFI_EVENT Event, OPTIONAL
+ OUT EFI_HPC_STATE *HpcState
+ )
+{
+ //
+ // This function should never be called, due to the information returned by
+ // GetRootHpcList().
+ //
+ ASSERT (FALSE);
+
+ if (HpcState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Returns the resource padding that is required by the PCI bus that is
+ controlled by the specified Hot Plug Controller (HPC).
+
+ This function returns the resource padding that is required by the PCI bus
+ that is controlled by the specified HPC. This member function is called for
+ all the root HPCs and nonroot HPCs that are detected by the PCI bus
+ enumerator. This function will be called before PCI resource allocation is
+ completed. This function must be called after all the root HPCs, with the
+ possible exception of a PCI-to-CardBus bridge, have completed
+ initialization.
+
+ @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
+ instance.
+ @param[in] HpcDevicePath The device path to the HPC.
+ @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
+ @param[in] HpcState The state of the HPC hardware.
+ @param[out] Padding The amount of resource padding that is required
+ by the PCI bus under the control of the specified
+ HPC.
+ @param[out] Attributes Describes how padding is accounted for. The
+ padding is returned in the form of ACPI 2.0
+ resource descriptors.
+
+ @retval EFI_SUCCESS The resource padding was successfully
+ returned.
+ @retval EFI_UNSUPPORTED This instance of the
+ EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
+ support the specified HPC.
+ @retval EFI_NOT_READY This function was called before HPC
+ initialization is complete.
+ @retval EFI_INVALID_PARAMETER HpcState or Padding or Attributes is NULL.
+ @retval EFI_OUT_OF_RESOURCES ACPI 2.0 resource descriptors for Padding
+ cannot be allocated due to insufficient
+ resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetResourcePadding (
+ IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
+ IN UINT64 HpcPciAddress,
+ OUT EFI_HPC_STATE *HpcState,
+ OUT VOID **Padding,
+ OUT EFI_HPC_PADDING_ATTRIBUTES *Attributes
+ )
+{
+ DEBUG_CODE (
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;
+ CHAR16 *DevicePathString;
+
+ Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;
+ DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);
+
+ DEBUG ((EFI_D_VERBOSE, "%a: Address=%02x:%02x.%x DevicePath=%s\n",
+ __FUNCTION__, Address->Bus, Address->Device, Address->Function,
+ (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString));
+
+ if (DevicePathString != NULL) {
+ FreePool (DevicePathString);
+ }
+ );
+
+ if (HpcState == NULL || Padding == NULL || Attributes == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Padding = AllocateCopyPool (sizeof mPadding, &mPadding);
+ if (*Padding == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Resource padding is required.
+ //
+ *HpcState = EFI_HPC_STATE_INITIALIZED | EFI_HPC_STATE_ENABLED;
+
+ //
+ // The padding should be applied at PCI bus level, and considered by upstream
+ // bridges, recursively.
+ //
+ *Attributes = EfiPaddingPciBus;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Entry point for this driver.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable Pointer to SystemTable.
+
+ @retval EFI_SUCESS Driver has loaded successfully.
+ @return Error codes from lower level functions.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mPciHotPlugInit.GetRootHpcList = GetRootHpcList;
+ mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;
+ mPciHotPlugInit.GetResourcePadding = GetResourcePadding;
+ Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
+ &gEfiPciHotPlugInitProtocolGuid, &mPciHotPlugInit, NULL);
+ return Status;
+}