Home | History | Annotate | Download | only in PciHotPlugInitDxe
      1 /** @file
      2   This driver implements EFI_PCI_HOT_PLUG_INIT_PROTOCOL, providing the PCI bus
      3   driver with resource padding information, for PCIe hotplug purposes.
      4 
      5   Copyright (C) 2016, Red Hat, Inc.
      6 
      7   This program and the accompanying materials are licensed and made available
      8   under the terms and conditions of the BSD License which accompanies this
      9   distribution. The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     13   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 **/
     15 
     16 #include <IndustryStandard/Acpi10.h>
     17 
     18 #include <Library/DebugLib.h>
     19 #include <Library/DevicePathLib.h>
     20 #include <Library/MemoryAllocationLib.h>
     21 #include <Library/UefiBootServicesTableLib.h>
     22 
     23 #include <Protocol/PciHotPlugInit.h>
     24 #include <Protocol/PciRootBridgeIo.h>
     25 
     26 //
     27 // The protocol interface this driver produces.
     28 //
     29 // Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform
     30 // Init 1.4a Spec, Volume 5.
     31 //
     32 STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;
     33 
     34 
     35 //
     36 // Resource padding template for the GetResourcePadding() protocol member
     37 // function.
     38 //
     39 // Refer to Table 8 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" in
     40 // the Platform Init 1.4a Spec, Volume 5.
     41 //
     42 // This structure is interpreted by the ApplyResourcePadding() function in the
     43 // edk2 PCI Bus UEFI_DRIVER.
     44 //
     45 #pragma pack (1)
     46 typedef struct {
     47   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR MmioPadding;
     48   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR IoPadding;
     49   EFI_ACPI_END_TAG_DESCRIPTOR       EndDesc;
     50 } RESOURCE_PADDING;
     51 #pragma pack ()
     52 
     53 STATIC CONST RESOURCE_PADDING mPadding = {
     54   //
     55   // MmioPadding
     56   //
     57   {
     58     ACPI_ADDRESS_SPACE_DESCRIPTOR,                 // Desc
     59     (UINT16)(                                      // Len
     60       sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
     61       OFFSET_OF (
     62         EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
     63         ResType
     64         )
     65       ),
     66     ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType
     67     0,                           // GenFlag:
     68                                  //   ignored
     69     0,                           // SpecificFlag:
     70                                  //   non-prefetchable
     71     64,                          // AddrSpaceGranularity:
     72                                  //   reserve 64-bit aperture
     73     0,                           // AddrRangeMin:
     74                                  //   ignored
     75     SIZE_2MB - 1,                // AddrRangeMax:
     76                                  //   align at 2MB
     77     0,                           // AddrTranslationOffset:
     78                                  //   ignored
     79     SIZE_2MB                     // AddrLen:
     80                                  //   2MB padding
     81   },
     82 
     83   //
     84   // IoPadding
     85   //
     86   {
     87     ACPI_ADDRESS_SPACE_DESCRIPTOR,                 // Desc
     88     (UINT16)(                                      // Len
     89       sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
     90       OFFSET_OF (
     91         EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
     92         ResType
     93         )
     94       ),
     95     ACPI_ADDRESS_SPACE_TYPE_IO,// ResType
     96     0,                          // GenFlag:
     97                                 //   ignored
     98     0,                          // SpecificFlag:
     99                                 //   ignored
    100     0,                          // AddrSpaceGranularity:
    101                                 //   ignored
    102     0,                          // AddrRangeMin:
    103                                 //   ignored
    104     512 - 1,                    // AddrRangeMax:
    105                                 //   align at 512 IO ports
    106     0,                          // AddrTranslationOffset:
    107                                 //   ignored
    108     512                         // AddrLen:
    109                                 //   512 IO ports
    110   },
    111 
    112   //
    113   // EndDesc
    114   //
    115   {
    116     ACPI_END_TAG_DESCRIPTOR, // Desc
    117     0                        // Checksum: to be ignored
    118   }
    119 };
    120 
    121 
    122 /**
    123   Returns a list of root Hot Plug Controllers (HPCs) that require
    124   initialization during the boot process.
    125 
    126   This procedure returns a list of root HPCs. The PCI bus driver must
    127   initialize  these controllers during the boot process. The PCI bus driver may
    128   or may not be  able to detect these HPCs. If the platform includes a
    129   PCI-to-CardBus bridge, it  can be included in this list if it requires
    130   initialization.  The HpcList must be  self consistent. An HPC cannot control
    131   any of its parent buses. Only one HPC can  control a PCI bus. Because this
    132   list includes only root HPCs, no HPC in the list  can be a child of another
    133   HPC. This policy must be enforced by the  EFI_PCI_HOT_PLUG_INIT_PROTOCOL.
    134   The PCI bus driver may not check for such  invalid conditions.  The callee
    135   allocates the buffer HpcList
    136 
    137   @param[in]  This       Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
    138                          instance.
    139   @param[out] HpcCount   The number of root HPCs that were returned.
    140   @param[out] HpcList    The list of root HPCs. HpcCount defines the number of
    141                          elements in this list.
    142 
    143   @retval EFI_SUCCESS             HpcList was returned.
    144   @retval EFI_OUT_OF_RESOURCES    HpcList was not returned due to insufficient
    145                                   resources.
    146   @retval EFI_INVALID_PARAMETER   HpcCount is NULL or HpcList is NULL.
    147 **/
    148 STATIC
    149 EFI_STATUS
    150 EFIAPI
    151 GetRootHpcList (
    152   IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
    153   OUT UINTN                          *HpcCount,
    154   OUT EFI_HPC_LOCATION               **HpcList
    155   )
    156 {
    157   if (HpcCount == NULL || HpcList == NULL) {
    158     return EFI_INVALID_PARAMETER;
    159   }
    160 
    161   //
    162   // There are no top-level (i.e., un-enumerable) hot-plug controllers in QEMU
    163   // that would require special initialization.
    164   //
    165   *HpcCount = 0;
    166   *HpcList = NULL;
    167   return EFI_SUCCESS;
    168 }
    169 
    170 
    171 /**
    172   Initializes one root Hot Plug Controller (HPC). This process may causes
    173   initialization of its subordinate buses.
    174 
    175   This function initializes the specified HPC. At the end of initialization,
    176   the hot-plug slots or sockets (controlled by this HPC) are powered and are
    177   connected to the bus. All the necessary registers in the HPC are set up. For
    178   a Standard (PCI) Hot Plug Controller (SHPC), the registers that must be set
    179   up are defined in the PCI Standard Hot Plug Controller and Subsystem
    180   Specification.
    181 
    182   @param[in]  This            Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
    183                               instance.
    184   @param[in]  HpcDevicePath   The device path to the HPC that is being
    185                               initialized.
    186   @param[in]  HpcPciAddress   The address of the HPC function on the PCI bus.
    187   @param[in]  Event           The event that should be signaled when the HPC
    188                               initialization is complete.  Set to NULL if the
    189                               caller wants to wait until the entire
    190                               initialization  process is complete.
    191   @param[out] HpcState        The state of the HPC hardware. The state is
    192                               EFI_HPC_STATE_INITIALIZED or
    193                               EFI_HPC_STATE_ENABLED.
    194 
    195   @retval EFI_SUCCESS             If Event is NULL, the specific HPC was
    196                                   successfully initialized. If Event is not
    197                                   NULL, Event will be  signaled at a later time
    198                                   when initialization is complete.
    199   @retval EFI_UNSUPPORTED         This instance of
    200                                   EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
    201                                   support the specified HPC.
    202   @retval EFI_OUT_OF_RESOURCES    Initialization failed due to insufficient
    203                                   resources.
    204   @retval EFI_INVALID_PARAMETER   HpcState is NULL.
    205 **/
    206 STATIC
    207 EFI_STATUS
    208 EFIAPI
    209 InitializeRootHpc (
    210   IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
    211   IN  EFI_DEVICE_PATH_PROTOCOL       *HpcDevicePath,
    212   IN  UINT64                         HpcPciAddress,
    213   IN  EFI_EVENT                      Event, OPTIONAL
    214   OUT EFI_HPC_STATE                  *HpcState
    215   )
    216 {
    217   //
    218   // This function should never be called, due to the information returned by
    219   // GetRootHpcList().
    220   //
    221   ASSERT (FALSE);
    222 
    223   if (HpcState == NULL) {
    224     return EFI_INVALID_PARAMETER;
    225   }
    226   return EFI_UNSUPPORTED;
    227 }
    228 
    229 
    230 /**
    231   Returns the resource padding that is required by the PCI bus that is
    232   controlled by the specified Hot Plug Controller (HPC).
    233 
    234   This function returns the resource padding that is required by the PCI bus
    235   that is controlled by the specified HPC. This member function is called for
    236   all the  root HPCs and nonroot HPCs that are detected by the PCI bus
    237   enumerator. This  function will be called before PCI resource allocation is
    238   completed. This function  must be called after all the root HPCs, with the
    239   possible exception of a  PCI-to-CardBus bridge, have completed
    240   initialization.
    241 
    242   @param[in]  This            Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
    243                               instance.
    244   @param[in]  HpcDevicePath   The device path to the HPC.
    245   @param[in]  HpcPciAddress   The address of the HPC function on the PCI bus.
    246   @param[in]  HpcState        The state of the HPC hardware.
    247   @param[out] Padding         The amount of resource padding that is required
    248                               by the PCI bus under the control of the specified
    249                               HPC.
    250   @param[out] Attributes      Describes how padding is accounted for. The
    251                               padding is returned in the form of ACPI 2.0
    252                               resource descriptors.
    253 
    254   @retval EFI_SUCCESS             The resource padding was successfully
    255                                   returned.
    256   @retval EFI_UNSUPPORTED         This instance of the
    257                                   EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
    258                                   support the specified HPC.
    259   @retval EFI_NOT_READY           This function was called before HPC
    260                                   initialization is complete.
    261   @retval EFI_INVALID_PARAMETER   HpcState or Padding or Attributes is NULL.
    262   @retval EFI_OUT_OF_RESOURCES    ACPI 2.0 resource descriptors for Padding
    263                                   cannot be allocated due to insufficient
    264                                   resources.
    265 **/
    266 STATIC
    267 EFI_STATUS
    268 EFIAPI
    269 GetResourcePadding (
    270   IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
    271   IN  EFI_DEVICE_PATH_PROTOCOL       *HpcDevicePath,
    272   IN  UINT64                         HpcPciAddress,
    273   OUT EFI_HPC_STATE                  *HpcState,
    274   OUT VOID                           **Padding,
    275   OUT EFI_HPC_PADDING_ATTRIBUTES     *Attributes
    276   )
    277 {
    278   DEBUG_CODE (
    279     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;
    280     CHAR16                                      *DevicePathString;
    281 
    282     Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;
    283     DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);
    284 
    285     DEBUG ((EFI_D_VERBOSE, "%a: Address=%02x:%02x.%x DevicePath=%s\n",
    286       __FUNCTION__, Address->Bus, Address->Device, Address->Function,
    287       (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString));
    288 
    289     if (DevicePathString != NULL) {
    290       FreePool (DevicePathString);
    291     }
    292     );
    293 
    294   if (HpcState == NULL || Padding == NULL || Attributes == NULL) {
    295     return EFI_INVALID_PARAMETER;
    296   }
    297 
    298   *Padding = AllocateCopyPool (sizeof mPadding, &mPadding);
    299   if (*Padding == NULL) {
    300     return EFI_OUT_OF_RESOURCES;
    301   }
    302 
    303   //
    304   // Resource padding is required.
    305   //
    306   *HpcState = EFI_HPC_STATE_INITIALIZED | EFI_HPC_STATE_ENABLED;
    307 
    308   //
    309   // The padding should be applied at PCI bus level, and considered by upstream
    310   // bridges, recursively.
    311   //
    312   *Attributes = EfiPaddingPciBus;
    313   return EFI_SUCCESS;
    314 }
    315 
    316 
    317 /**
    318   Entry point for this driver.
    319 
    320   @param[in] ImageHandle  Image handle of this driver.
    321   @param[in] SystemTable  Pointer to SystemTable.
    322 
    323   @retval EFI_SUCESS       Driver has loaded successfully.
    324   @return                  Error codes from lower level functions.
    325 
    326 **/
    327 EFI_STATUS
    328 EFIAPI
    329 DriverInitialize (
    330   IN EFI_HANDLE       ImageHandle,
    331   IN EFI_SYSTEM_TABLE *SystemTable
    332   )
    333 {
    334   EFI_STATUS Status;
    335 
    336   mPciHotPlugInit.GetRootHpcList = GetRootHpcList;
    337   mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;
    338   mPciHotPlugInit.GetResourcePadding = GetResourcePadding;
    339   Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
    340                   &gEfiPciHotPlugInitProtocolGuid, &mPciHotPlugInit, NULL);
    341   return Status;
    342 }
    343