diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 6d074641be..805650059e 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -552,6 +552,7 @@ UefiCpuPkg/CpuDxe/CpuDxe.inf PcAtChipsetPkg/8254TimerDxe/8254Timer.inf OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf + OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index 664a035f18..9ed29e8849 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -211,6 +211,7 @@ INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf 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 diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 25fcb38aaf..7615ee96df 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -561,6 +561,7 @@ UefiCpuPkg/CpuDxe/CpuDxe.inf PcAtChipsetPkg/8254TimerDxe/8254Timer.inf OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf + OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index 0f5fe51d7b..80b1857033 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -211,6 +211,7 @@ INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf 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 diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index cb7ccf7961..7f8a5c25a5 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -559,6 +559,7 @@ UefiCpuPkg/CpuDxe/CpuDxe.inf PcAtChipsetPkg/8254TimerDxe/8254Timer.inf OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf + OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index 6e468a8ab0..8948ba13e8 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -211,6 +211,7 @@ INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf 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 diff --git a/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c b/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c new file mode 100644 index 0000000000..2265b8c7e1 --- /dev/null +++ b/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c @@ -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 + +#include +#include +#include +#include + +#include +#include + +// +// 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"" : 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; +} diff --git a/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf b/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf new file mode 100644 index 0000000000..641ee2cad9 --- /dev/null +++ b/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf @@ -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