• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
GetRootHpcList(IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL * This,OUT UINTN * HpcCount,OUT EFI_HPC_LOCATION ** HpcList)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
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)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
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)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
DriverInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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