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