]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c
OvmfPkg: add PciHotPlugInitDxe
[mirror_edk2.git] / OvmfPkg / PciHotPlugInitDxe / PciHotPlugInit.c
diff --git a/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c b/OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c
new file mode 100644 (file)
index 0000000..2265b8c
--- /dev/null
@@ -0,0 +1,342 @@
+/** @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