2 This driver implements EFI_PCI_HOT_PLUG_INIT_PROTOCOL, providing the PCI bus
3 driver with resource padding information, for PCIe hotplug purposes.
5 Copyright (C) 2016, Red Hat, Inc.
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
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.
16 #include <IndustryStandard/Acpi10.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/DevicePathLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
24 #include <Protocol/PciHotPlugInit.h>
25 #include <Protocol/PciRootBridgeIo.h>
28 // The protocol interface this driver produces.
30 // Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform
31 // Init 1.4a Spec, Volume 5.
33 STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit
;
37 // Resource padding template for the GetResourcePadding() protocol member
40 // Refer to Table 8 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" in
41 // the Platform Init 1.4a Spec, Volume 5.
43 // This structure is interpreted by the ApplyResourcePadding() function in the
44 // edk2 PCI Bus UEFI_DRIVER.
46 // We can request padding for at most four resource types, each of which is
47 // optional, independently of the others:
50 // (c) non-prefetchable MMIO space (32-bit only),
51 // (d) prefetchable MMIO space (either 32-bit or 64-bit, never both).
55 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Padding
[4];
56 EFI_ACPI_END_TAG_DESCRIPTOR EndDesc
;
62 Initialize a RESOURCE_PADDING object.
64 @param[out] ResourcePadding The caller-allocated RESOURCE_PADDING object to
69 InitializeResourcePadding (
70 OUT RESOURCE_PADDING
*ResourcePadding
75 ZeroMem (ResourcePadding
, sizeof *ResourcePadding
);
78 // Fill in the Padding fields that don't vary across resource types.
80 for (Index
= 0; Index
< ARRAY_SIZE (ResourcePadding
->Padding
); ++Index
) {
81 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
83 Descriptor
= ResourcePadding
->Padding
+ Index
;
84 Descriptor
->Desc
= ACPI_ADDRESS_SPACE_DESCRIPTOR
;
85 Descriptor
->Len
= (UINT16
)(
86 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) -
88 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
,
95 // Fill in the End Tag.
97 ResourcePadding
->EndDesc
.Desc
= ACPI_END_TAG_DESCRIPTOR
;
102 Returns a list of root Hot Plug Controllers (HPCs) that require
103 initialization during the boot process.
105 This procedure returns a list of root HPCs. The PCI bus driver must
106 initialize these controllers during the boot process. The PCI bus driver may
107 or may not be able to detect these HPCs. If the platform includes a
108 PCI-to-CardBus bridge, it can be included in this list if it requires
109 initialization. The HpcList must be self consistent. An HPC cannot control
110 any of its parent buses. Only one HPC can control a PCI bus. Because this
111 list includes only root HPCs, no HPC in the list can be a child of another
112 HPC. This policy must be enforced by the EFI_PCI_HOT_PLUG_INIT_PROTOCOL.
113 The PCI bus driver may not check for such invalid conditions. The callee
114 allocates the buffer HpcList
116 @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
118 @param[out] HpcCount The number of root HPCs that were returned.
119 @param[out] HpcList The list of root HPCs. HpcCount defines the number of
120 elements in this list.
122 @retval EFI_SUCCESS HpcList was returned.
123 @retval EFI_OUT_OF_RESOURCES HpcList was not returned due to insufficient
125 @retval EFI_INVALID_PARAMETER HpcCount is NULL or HpcList is NULL.
131 IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL
*This
,
133 OUT EFI_HPC_LOCATION
**HpcList
136 if (HpcCount
== NULL
|| HpcList
== NULL
) {
137 return EFI_INVALID_PARAMETER
;
141 // There are no top-level (i.e., un-enumerable) hot-plug controllers in QEMU
142 // that would require special initialization.
151 Initializes one root Hot Plug Controller (HPC). This process may causes
152 initialization of its subordinate buses.
154 This function initializes the specified HPC. At the end of initialization,
155 the hot-plug slots or sockets (controlled by this HPC) are powered and are
156 connected to the bus. All the necessary registers in the HPC are set up. For
157 a Standard (PCI) Hot Plug Controller (SHPC), the registers that must be set
158 up are defined in the PCI Standard Hot Plug Controller and Subsystem
161 @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
163 @param[in] HpcDevicePath The device path to the HPC that is being
165 @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
166 @param[in] Event The event that should be signaled when the HPC
167 initialization is complete. Set to NULL if the
168 caller wants to wait until the entire
169 initialization process is complete.
170 @param[out] HpcState The state of the HPC hardware. The state is
171 EFI_HPC_STATE_INITIALIZED or
172 EFI_HPC_STATE_ENABLED.
174 @retval EFI_SUCCESS If Event is NULL, the specific HPC was
175 successfully initialized. If Event is not
176 NULL, Event will be signaled at a later time
177 when initialization is complete.
178 @retval EFI_UNSUPPORTED This instance of
179 EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
180 support the specified HPC.
181 @retval EFI_OUT_OF_RESOURCES Initialization failed due to insufficient
183 @retval EFI_INVALID_PARAMETER HpcState is NULL.
189 IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL
*This
,
190 IN EFI_DEVICE_PATH_PROTOCOL
*HpcDevicePath
,
191 IN UINT64 HpcPciAddress
,
192 IN EFI_EVENT Event
, OPTIONAL
193 OUT EFI_HPC_STATE
*HpcState
197 // This function should never be called, due to the information returned by
202 if (HpcState
== NULL
) {
203 return EFI_INVALID_PARAMETER
;
205 return EFI_UNSUPPORTED
;
210 Returns the resource padding that is required by the PCI bus that is
211 controlled by the specified Hot Plug Controller (HPC).
213 This function returns the resource padding that is required by the PCI bus
214 that is controlled by the specified HPC. This member function is called for
215 all the root HPCs and nonroot HPCs that are detected by the PCI bus
216 enumerator. This function will be called before PCI resource allocation is
217 completed. This function must be called after all the root HPCs, with the
218 possible exception of a PCI-to-CardBus bridge, have completed
221 @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
223 @param[in] HpcDevicePath The device path to the HPC.
224 @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
225 @param[in] HpcState The state of the HPC hardware.
226 @param[out] Padding The amount of resource padding that is required
227 by the PCI bus under the control of the specified
229 @param[out] Attributes Describes how padding is accounted for. The
230 padding is returned in the form of ACPI 2.0
231 resource descriptors.
233 @retval EFI_SUCCESS The resource padding was successfully
235 @retval EFI_UNSUPPORTED This instance of the
236 EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
237 support the specified HPC.
238 @retval EFI_NOT_READY This function was called before HPC
239 initialization is complete.
240 @retval EFI_INVALID_PARAMETER HpcState or Padding or Attributes is NULL.
241 @retval EFI_OUT_OF_RESOURCES ACPI 2.0 resource descriptors for Padding
242 cannot be allocated due to insufficient
249 IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL
*This
,
250 IN EFI_DEVICE_PATH_PROTOCOL
*HpcDevicePath
,
251 IN UINT64 HpcPciAddress
,
252 OUT EFI_HPC_STATE
*HpcState
,
254 OUT EFI_HPC_PADDING_ATTRIBUTES
*Attributes
259 RESOURCE_PADDING ReservationRequest
;
260 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*FirstResource
;
263 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS
*Address
;
264 CHAR16
*DevicePathString
;
266 Address
= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS
*)&HpcPciAddress
;
267 DevicePathString
= ConvertDevicePathToText (HpcDevicePath
, FALSE
, FALSE
);
269 DEBUG ((EFI_D_VERBOSE
, "%a: Address=%02x:%02x.%x DevicePath=%s\n",
270 __FUNCTION__
, Address
->Bus
, Address
->Device
, Address
->Function
,
271 (DevicePathString
== NULL
) ? L
"<unavailable>" : DevicePathString
));
273 if (DevicePathString
!= NULL
) {
274 FreePool (DevicePathString
);
278 if (HpcState
== NULL
|| Padding
== NULL
|| Attributes
== NULL
) {
279 return EFI_INVALID_PARAMETER
;
286 // Init ReservationRequest, and point FirstResource one past the last
287 // descriptor entry. We're going to build the entries backwards from
288 // ReservationRequest.EndDesc.
290 InitializeResourcePadding (&ReservationRequest
);
291 FirstResource
= ReservationRequest
.Padding
+
292 ARRAY_SIZE (ReservationRequest
.Padding
);
295 // (b) Reserve IO space.
302 FirstResource
->ResType
= ACPI_ADDRESS_SPACE_TYPE_IO
;
303 FirstResource
->AddrRangeMax
= 512 - 1; // align at 512 IO ports
304 FirstResource
->AddrLen
= 512; // 512 IO ports
308 // (c) Reserve non-prefetchable MMIO space (32-bit only).
315 FirstResource
->ResType
= ACPI_ADDRESS_SPACE_TYPE_MEM
;
316 FirstResource
->SpecificFlag
= 0; // non-prefetchable
317 FirstResource
->AddrSpaceGranularity
= 32; // 32-bit aperture
318 FirstResource
->AddrRangeMax
= SIZE_2MB
- 1; // align at 2MB
319 FirstResource
->AddrLen
= SIZE_2MB
; // 2MB padding
323 // Output a copy of ReservationRequest from the lowest-address populated
324 // entry until the end of the structure (including
325 // ReservationRequest.EndDesc). If no reservations are necessary, we'll only
326 // output the End Tag.
328 *Padding
= AllocateCopyPool (
329 (UINT8
*)(&ReservationRequest
+ 1) - (UINT8
*)FirstResource
,
332 if (*Padding
== NULL
) {
333 return EFI_OUT_OF_RESOURCES
;
337 // Resource padding is required.
339 *HpcState
= EFI_HPC_STATE_INITIALIZED
| EFI_HPC_STATE_ENABLED
;
342 // The padding should be applied at PCI bus level, and considered by upstream
343 // bridges, recursively.
345 *Attributes
= EfiPaddingPciBus
;
351 Entry point for this driver.
353 @param[in] ImageHandle Image handle of this driver.
354 @param[in] SystemTable Pointer to SystemTable.
356 @retval EFI_SUCESS Driver has loaded successfully.
357 @return Error codes from lower level functions.
363 IN EFI_HANDLE ImageHandle
,
364 IN EFI_SYSTEM_TABLE
*SystemTable
369 mPciHotPlugInit
.GetRootHpcList
= GetRootHpcList
;
370 mPciHotPlugInit
.InitializeRootHpc
= InitializeRootHpc
;
371 mPciHotPlugInit
.GetResourcePadding
= GetResourcePadding
;
372 Status
= gBS
->InstallMultipleProtocolInterfaces (&ImageHandle
,
373 &gEfiPciHotPlugInitProtocolGuid
, &mPciHotPlugInit
, NULL
);