]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c
UefiCpuPkg CpuCommFeaturesLib: Fix GP fault issue about ProcTrace
[mirror_edk2.git] / OvmfPkg / PciHotPlugInitDxe / PciHotPlugInit.c
CommitLineData
8aba40b7
LE
1/** @file\r
2 This driver implements EFI_PCI_HOT_PLUG_INIT_PROTOCOL, providing the PCI bus\r
3 driver with resource padding information, for PCIe hotplug purposes.\r
4\r
5 Copyright (C) 2016, Red Hat, Inc.\r
6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8aba40b7
LE
8**/\r
9\r
10#include <IndustryStandard/Acpi10.h>\r
3815101f 11#include <IndustryStandard/Q35MchIch9.h>\r
fe404947 12#include <IndustryStandard/QemuPciBridgeCapabilities.h>\r
8aba40b7 13\r
4776d5cb 14#include <Library/BaseLib.h>\r
a9803247 15#include <Library/BaseMemoryLib.h>\r
8aba40b7
LE
16#include <Library/DebugLib.h>\r
17#include <Library/DevicePathLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
3815101f
LE
19#include <Library/PciCapLib.h>\r
20#include <Library/PciCapPciSegmentLib.h>\r
fe404947 21#include <Library/PciLib.h>\r
8aba40b7
LE
22#include <Library/UefiBootServicesTableLib.h>\r
23\r
24#include <Protocol/PciHotPlugInit.h>\r
25#include <Protocol/PciRootBridgeIo.h>\r
26\r
3815101f
LE
27//\r
28// TRUE if the PCI platform supports extended config space, FALSE otherwise.\r
29//\r
30STATIC BOOLEAN mPciExtConfSpaceSupported;\r
31\r
32\r
8aba40b7
LE
33//\r
34// The protocol interface this driver produces.\r
35//\r
36// Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform\r
37// Init 1.4a Spec, Volume 5.\r
38//\r
39STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;\r
40\r
41\r
42//\r
43// Resource padding template for the GetResourcePadding() protocol member\r
44// function.\r
45//\r
46// Refer to Table 8 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" in\r
47// the Platform Init 1.4a Spec, Volume 5.\r
48//\r
49// This structure is interpreted by the ApplyResourcePadding() function in the\r
50// edk2 PCI Bus UEFI_DRIVER.\r
51//\r
a9803247
LE
52// We can request padding for at most four resource types, each of which is\r
53// optional, independently of the others:\r
54// (a) bus numbers,\r
55// (b) IO space,\r
56// (c) non-prefetchable MMIO space (32-bit only),\r
57// (d) prefetchable MMIO space (either 32-bit or 64-bit, never both).\r
58//\r
8aba40b7
LE
59#pragma pack (1)\r
60typedef struct {\r
a9803247 61 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Padding[4];\r
8aba40b7
LE
62 EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;\r
63} RESOURCE_PADDING;\r
64#pragma pack ()\r
65\r
a9803247
LE
66\r
67/**\r
68 Initialize a RESOURCE_PADDING object.\r
69\r
70 @param[out] ResourcePadding The caller-allocated RESOURCE_PADDING object to\r
71 initialize.\r
72**/\r
73STATIC\r
74VOID\r
75InitializeResourcePadding (\r
76 OUT RESOURCE_PADDING *ResourcePadding\r
77 )\r
78{\r
79 UINTN Index;\r
80\r
81 ZeroMem (ResourcePadding, sizeof *ResourcePadding);\r
8aba40b7
LE
82\r
83 //\r
a9803247 84 // Fill in the Padding fields that don't vary across resource types.\r
8aba40b7 85 //\r
a9803247
LE
86 for (Index = 0; Index < ARRAY_SIZE (ResourcePadding->Padding); ++Index) {\r
87 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
88\r
89 Descriptor = ResourcePadding->Padding + Index;\r
90 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
91 Descriptor->Len = (UINT16)(\r
92 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -\r
93 OFFSET_OF (\r
94 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,\r
95 ResType\r
96 )\r
97 );\r
98 }\r
8aba40b7
LE
99\r
100 //\r
a9803247 101 // Fill in the End Tag.\r
8aba40b7 102 //\r
a9803247
LE
103 ResourcePadding->EndDesc.Desc = ACPI_END_TAG_DESCRIPTOR;\r
104}\r
8aba40b7
LE
105\r
106\r
4776d5cb
LE
107/**\r
108 Set up a descriptor entry for reserving IO space.\r
109\r
110 @param[in,out] Descriptor The descriptor to configure. The caller shall have\r
111 initialized Descriptor earlier, with\r
112 InitializeResourcePadding().\r
113\r
114 @param[in] SizeExponent The size and natural alignment of the reservation\r
115 are determined by raising two to this power.\r
116**/\r
117STATIC\r
118VOID\r
119SetIoPadding (\r
120 IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,\r
121 IN UINTN SizeExponent\r
122 )\r
123{\r
124 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
125 Descriptor->AddrLen = LShiftU64 (1, SizeExponent);\r
126 Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;\r
127}\r
128\r
129\r
130/**\r
131 Set up a descriptor entry for reserving MMIO space.\r
132\r
133 @param[in,out] Descriptor The descriptor to configure. The caller shall\r
134 have initialized Descriptor earlier, with\r
135 InitializeResourcePadding().\r
136\r
137 @param[in] Prefetchable TRUE if the descriptor should reserve\r
138 prefetchable MMIO space. Pass FALSE for\r
139 reserving non-prefetchable MMIO space.\r
140\r
141 @param[in] ThirtyTwoBitOnly TRUE if the reservation should be limited to\r
142 32-bit address space. FALSE if the reservation\r
143 can be satisfied from 64-bit address space.\r
144 ThirtyTwoBitOnly is ignored if Prefetchable is\r
145 FALSE; in that case ThirtyTwoBitOnly is always\r
146 considered TRUE.\r
147\r
148 @param[in] SizeExponent The size and natural alignment of the\r
149 reservation are determined by raising two to\r
150 this power.\r
151**/\r
152STATIC\r
153VOID\r
154SetMmioPadding (\r
155 IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,\r
156 IN BOOLEAN Prefetchable,\r
157 IN BOOLEAN ThirtyTwoBitOnly,\r
158 IN UINTN SizeExponent\r
159 )\r
160{\r
161 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
162 if (Prefetchable) {\r
163 Descriptor->SpecificFlag =\r
164 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
165 Descriptor->AddrSpaceGranularity = ThirtyTwoBitOnly ? 32 : 64;\r
166 } else {\r
167 Descriptor->SpecificFlag =\r
168 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE;\r
169 Descriptor->AddrSpaceGranularity = 32;\r
170 }\r
171 Descriptor->AddrLen = LShiftU64 (1, SizeExponent);\r
172 Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;\r
173}\r
174\r
175\r
176/**\r
177 Round up a positive 32-bit value to the next whole power of two, and return\r
178 the bit position of the highest bit set in the result. Equivalent to\r
179 ceil(log2(x)).\r
180\r
181 @param[in] Operand The 32-bit operand to evaluate.\r
182\r
183 @retval -1 Operand is zero.\r
184\r
185 @retval -1 Operand is positive, not a whole power of two, and rounding it\r
186 up to the next power of two does not fit into 32 bits.\r
187\r
188 @retval 0..31 Otherwise, return ceil(log2(Value)).\r
189**/\r
190STATIC\r
191INTN\r
192HighBitSetRoundUp32 (\r
193 IN UINT32 Operand\r
194 )\r
195{\r
196 INTN HighBit;\r
197\r
198 HighBit = HighBitSet32 (Operand);\r
199 if (HighBit == -1) {\r
200 //\r
201 // Operand is zero.\r
202 //\r
203 return HighBit;\r
204 }\r
205 if ((Operand & (Operand - 1)) != 0) {\r
206 //\r
207 // Operand is not a whole power of two.\r
208 //\r
209 ++HighBit;\r
210 }\r
211 return (HighBit < 32) ? HighBit : -1;\r
212}\r
213\r
214\r
215/**\r
216 Round up a positive 64-bit value to the next whole power of two, and return\r
217 the bit position of the highest bit set in the result. Equivalent to\r
218 ceil(log2(x)).\r
219\r
220 @param[in] Operand The 64-bit operand to evaluate.\r
221\r
222 @retval -1 Operand is zero.\r
223\r
224 @retval -1 Operand is positive, not a whole power of two, and rounding it\r
225 up to the next power of two does not fit into 64 bits.\r
226\r
227 @retval 0..63 Otherwise, return ceil(log2(Value)).\r
228**/\r
229STATIC\r
230INTN\r
231HighBitSetRoundUp64 (\r
232 IN UINT64 Operand\r
233 )\r
234{\r
235 INTN HighBit;\r
236\r
237 HighBit = HighBitSet64 (Operand);\r
238 if (HighBit == -1) {\r
239 //\r
240 // Operand is zero.\r
241 //\r
242 return HighBit;\r
243 }\r
244 if ((Operand & (Operand - 1)) != 0) {\r
245 //\r
246 // Operand is not a whole power of two.\r
247 //\r
248 ++HighBit;\r
249 }\r
250 return (HighBit < 64) ? HighBit : -1;\r
251}\r
252\r
253\r
fe404947
LE
254/**\r
255 Look up the QEMU-specific Resource Reservation capability in the conventional\r
256 config space of a Hotplug Controller (that is, PCI Bridge).\r
257\r
3815101f 258 On error, the contents of ReservationHint are indeterminate.\r
fe404947
LE
259\r
260 @param[in] HpcPciAddress The address of the PCI Bridge -- Bus, Device,\r
261 Function -- in UEFI (not PciLib) encoding.\r
262\r
263 @param[out] ReservationHint The caller-allocated capability structure to\r
264 populate from the PCI Bridge's config space.\r
265\r
266 @retval EFI_SUCCESS The capability has been found, ReservationHint has\r
267 been populated.\r
268\r
3815101f
LE
269 @retval EFI_NOT_FOUND The capability is missing.\r
270\r
271 @return Error codes from PciCapPciSegmentLib and PciCapLib.\r
fe404947
LE
272**/\r
273STATIC\r
274EFI_STATUS\r
275QueryReservationHint (\r
276 IN CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *HpcPciAddress,\r
277 OUT QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION *ReservationHint\r
278)\r
279{\r
3815101f
LE
280 UINT16 PciVendorId;\r
281 EFI_STATUS Status;\r
282 PCI_CAP_DEV *PciDevice;\r
283 PCI_CAP_LIST *CapList;\r
284 UINT16 VendorInstance;\r
285 PCI_CAP *VendorCap;\r
fe404947
LE
286\r
287 //\r
288 // Check the vendor identifier.\r
289 //\r
290 PciVendorId = PciRead16 (\r
291 PCI_LIB_ADDRESS (\r
292 HpcPciAddress->Bus,\r
293 HpcPciAddress->Device,\r
294 HpcPciAddress->Function,\r
295 PCI_VENDOR_ID_OFFSET\r
296 )\r
297 );\r
298 if (PciVendorId != QEMU_PCI_BRIDGE_VENDOR_ID_REDHAT) {\r
299 return EFI_NOT_FOUND;\r
300 }\r
301\r
302 //\r
3815101f 303 // Parse the capabilities lists.\r
fe404947 304 //\r
3815101f
LE
305 Status = PciCapPciSegmentDeviceInit (\r
306 mPciExtConfSpaceSupported ? PciCapExtended : PciCapNormal,\r
307 0, // Segment\r
308 HpcPciAddress->Bus,\r
309 HpcPciAddress->Device,\r
310 HpcPciAddress->Function,\r
311 &PciDevice\r
312 );\r
313 if (EFI_ERROR (Status)) {\r
314 return Status;\r
315 }\r
316 Status = PciCapListInit (PciDevice, &CapList);\r
317 if (EFI_ERROR (Status)) {\r
318 goto UninitPciDevice;\r
fe404947
LE
319 }\r
320\r
321 //\r
3815101f
LE
322 // Scan the vendor capability instances for the Resource Reservation\r
323 // capability.\r
fe404947 324 //\r
3815101f
LE
325 VendorInstance = 0;\r
326 for (;;) {\r
327 UINT8 VendorLength;\r
328 UINT8 BridgeCapType;\r
329\r
330 Status = PciCapListFindCap (\r
331 CapList,\r
332 PciCapNormal,\r
333 EFI_PCI_CAPABILITY_ID_VENDOR,\r
334 VendorInstance++,\r
335 &VendorCap\r
336 );\r
337 if (EFI_ERROR (Status)) {\r
338 goto UninitCapList;\r
fe404947
LE
339 }\r
340\r
341 //\r
3815101f 342 // Check the vendor capability length.\r
fe404947 343 //\r
3815101f
LE
344 Status = PciCapRead (\r
345 PciDevice,\r
346 VendorCap,\r
347 OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length),\r
348 &VendorLength,\r
349 sizeof VendorLength\r
350 );\r
351 if (EFI_ERROR (Status)) {\r
352 goto UninitCapList;\r
353 }\r
354 if (VendorLength != sizeof *ReservationHint) {\r
fe404947
LE
355 continue;\r
356 }\r
357\r
358 //\r
3815101f 359 // Check the vendor bridge capability type.\r
fe404947 360 //\r
3815101f
LE
361 Status = PciCapRead (\r
362 PciDevice,\r
363 VendorCap,\r
364 OFFSET_OF (QEMU_PCI_BRIDGE_CAPABILITY_HDR, Type),\r
365 &BridgeCapType,\r
366 sizeof BridgeCapType\r
367 );\r
368 if (EFI_ERROR (Status)) {\r
369 goto UninitCapList;\r
370 }\r
371 if (BridgeCapType ==\r
fe404947 372 QEMU_PCI_BRIDGE_CAPABILITY_TYPE_RESOURCE_RESERVATION) {\r
3815101f
LE
373 //\r
374 // We have a match.\r
375 //\r
376 break;\r
fe404947 377 }\r
fe404947
LE
378 }\r
379\r
3815101f
LE
380 //\r
381 // Populate ReservationHint.\r
382 //\r
383 Status = PciCapRead (\r
384 PciDevice,\r
385 VendorCap,\r
386 0, // SourceOffsetInCap\r
387 ReservationHint,\r
388 sizeof *ReservationHint\r
389 );\r
390\r
391UninitCapList:\r
392 PciCapListUninit (CapList);\r
393\r
394UninitPciDevice:\r
395 PciCapPciSegmentDeviceUninit (PciDevice);\r
396\r
397 return Status;\r
fe404947
LE
398}\r
399\r
400\r
8aba40b7
LE
401/**\r
402 Returns a list of root Hot Plug Controllers (HPCs) that require\r
403 initialization during the boot process.\r
404\r
405 This procedure returns a list of root HPCs. The PCI bus driver must\r
406 initialize these controllers during the boot process. The PCI bus driver may\r
407 or may not be able to detect these HPCs. If the platform includes a\r
408 PCI-to-CardBus bridge, it can be included in this list if it requires\r
409 initialization. The HpcList must be self consistent. An HPC cannot control\r
410 any of its parent buses. Only one HPC can control a PCI bus. Because this\r
411 list includes only root HPCs, no HPC in the list can be a child of another\r
412 HPC. This policy must be enforced by the EFI_PCI_HOT_PLUG_INIT_PROTOCOL.\r
413 The PCI bus driver may not check for such invalid conditions. The callee\r
414 allocates the buffer HpcList\r
415\r
416 @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL\r
417 instance.\r
418 @param[out] HpcCount The number of root HPCs that were returned.\r
419 @param[out] HpcList The list of root HPCs. HpcCount defines the number of\r
420 elements in this list.\r
421\r
422 @retval EFI_SUCCESS HpcList was returned.\r
423 @retval EFI_OUT_OF_RESOURCES HpcList was not returned due to insufficient\r
424 resources.\r
425 @retval EFI_INVALID_PARAMETER HpcCount is NULL or HpcList is NULL.\r
426**/\r
427STATIC\r
428EFI_STATUS\r
429EFIAPI\r
430GetRootHpcList (\r
431 IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
432 OUT UINTN *HpcCount,\r
433 OUT EFI_HPC_LOCATION **HpcList\r
434 )\r
435{\r
436 if (HpcCount == NULL || HpcList == NULL) {\r
437 return EFI_INVALID_PARAMETER;\r
438 }\r
439\r
440 //\r
441 // There are no top-level (i.e., un-enumerable) hot-plug controllers in QEMU\r
442 // that would require special initialization.\r
443 //\r
444 *HpcCount = 0;\r
445 *HpcList = NULL;\r
446 return EFI_SUCCESS;\r
447}\r
448\r
449\r
450/**\r
451 Initializes one root Hot Plug Controller (HPC). This process may causes\r
452 initialization of its subordinate buses.\r
453\r
454 This function initializes the specified HPC. At the end of initialization,\r
455 the hot-plug slots or sockets (controlled by this HPC) are powered and are\r
456 connected to the bus. All the necessary registers in the HPC are set up. For\r
457 a Standard (PCI) Hot Plug Controller (SHPC), the registers that must be set\r
458 up are defined in the PCI Standard Hot Plug Controller and Subsystem\r
459 Specification.\r
460\r
461 @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL\r
462 instance.\r
463 @param[in] HpcDevicePath The device path to the HPC that is being\r
464 initialized.\r
465 @param[in] HpcPciAddress The address of the HPC function on the PCI bus.\r
466 @param[in] Event The event that should be signaled when the HPC\r
467 initialization is complete. Set to NULL if the\r
468 caller wants to wait until the entire\r
469 initialization process is complete.\r
470 @param[out] HpcState The state of the HPC hardware. The state is\r
471 EFI_HPC_STATE_INITIALIZED or\r
472 EFI_HPC_STATE_ENABLED.\r
473\r
474 @retval EFI_SUCCESS If Event is NULL, the specific HPC was\r
475 successfully initialized. If Event is not\r
476 NULL, Event will be signaled at a later time\r
477 when initialization is complete.\r
478 @retval EFI_UNSUPPORTED This instance of\r
479 EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not\r
480 support the specified HPC.\r
481 @retval EFI_OUT_OF_RESOURCES Initialization failed due to insufficient\r
482 resources.\r
483 @retval EFI_INVALID_PARAMETER HpcState is NULL.\r
484**/\r
485STATIC\r
486EFI_STATUS\r
487EFIAPI\r
488InitializeRootHpc (\r
489 IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
490 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
491 IN UINT64 HpcPciAddress,\r
492 IN EFI_EVENT Event, OPTIONAL\r
493 OUT EFI_HPC_STATE *HpcState\r
494 )\r
495{\r
496 //\r
497 // This function should never be called, due to the information returned by\r
498 // GetRootHpcList().\r
499 //\r
500 ASSERT (FALSE);\r
501\r
502 if (HpcState == NULL) {\r
503 return EFI_INVALID_PARAMETER;\r
504 }\r
505 return EFI_UNSUPPORTED;\r
506}\r
507\r
508\r
509/**\r
510 Returns the resource padding that is required by the PCI bus that is\r
511 controlled by the specified Hot Plug Controller (HPC).\r
512\r
513 This function returns the resource padding that is required by the PCI bus\r
514 that is controlled by the specified HPC. This member function is called for\r
515 all the root HPCs and nonroot HPCs that are detected by the PCI bus\r
516 enumerator. This function will be called before PCI resource allocation is\r
517 completed. This function must be called after all the root HPCs, with the\r
518 possible exception of a PCI-to-CardBus bridge, have completed\r
519 initialization.\r
520\r
521 @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL\r
522 instance.\r
523 @param[in] HpcDevicePath The device path to the HPC.\r
524 @param[in] HpcPciAddress The address of the HPC function on the PCI bus.\r
525 @param[in] HpcState The state of the HPC hardware.\r
526 @param[out] Padding The amount of resource padding that is required\r
527 by the PCI bus under the control of the specified\r
528 HPC.\r
529 @param[out] Attributes Describes how padding is accounted for. The\r
530 padding is returned in the form of ACPI 2.0\r
531 resource descriptors.\r
532\r
533 @retval EFI_SUCCESS The resource padding was successfully\r
534 returned.\r
535 @retval EFI_UNSUPPORTED This instance of the\r
536 EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not\r
537 support the specified HPC.\r
538 @retval EFI_NOT_READY This function was called before HPC\r
539 initialization is complete.\r
540 @retval EFI_INVALID_PARAMETER HpcState or Padding or Attributes is NULL.\r
541 @retval EFI_OUT_OF_RESOURCES ACPI 2.0 resource descriptors for Padding\r
542 cannot be allocated due to insufficient\r
543 resources.\r
544**/\r
545STATIC\r
546EFI_STATUS\r
547EFIAPI\r
548GetResourcePadding (\r
549 IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
550 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
551 IN UINT64 HpcPciAddress,\r
552 OUT EFI_HPC_STATE *HpcState,\r
553 OUT VOID **Padding,\r
554 OUT EFI_HPC_PADDING_ATTRIBUTES *Attributes\r
555 )\r
556{\r
fe404947 557 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;\r
a9803247
LE
558 BOOLEAN DefaultIo;\r
559 BOOLEAN DefaultMmio;\r
560 RESOURCE_PADDING ReservationRequest;\r
561 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FirstResource;\r
fe404947
LE
562 EFI_STATUS ReservationHintStatus;\r
563 QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION ReservationHint;\r
564\r
565 Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;\r
a9803247 566\r
8aba40b7 567 DEBUG_CODE (\r
8aba40b7
LE
568 CHAR16 *DevicePathString;\r
569\r
8aba40b7
LE
570 DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);\r
571\r
572 DEBUG ((EFI_D_VERBOSE, "%a: Address=%02x:%02x.%x DevicePath=%s\n",\r
573 __FUNCTION__, Address->Bus, Address->Device, Address->Function,\r
574 (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString));\r
575\r
576 if (DevicePathString != NULL) {\r
577 FreePool (DevicePathString);\r
578 }\r
579 );\r
580\r
581 if (HpcState == NULL || Padding == NULL || Attributes == NULL) {\r
582 return EFI_INVALID_PARAMETER;\r
583 }\r
584\r
a9803247
LE
585 DefaultIo = TRUE;\r
586 DefaultMmio = TRUE;\r
587\r
588 //\r
589 // Init ReservationRequest, and point FirstResource one past the last\r
590 // descriptor entry. We're going to build the entries backwards from\r
591 // ReservationRequest.EndDesc.\r
592 //\r
593 InitializeResourcePadding (&ReservationRequest);\r
594 FirstResource = ReservationRequest.Padding +\r
595 ARRAY_SIZE (ReservationRequest.Padding);\r
596\r
597 //\r
fe404947 598 // Try to get the QEMU-specific Resource Reservation capability.\r
a9803247 599 //\r
fe404947
LE
600 ReservationHintStatus = QueryReservationHint (Address, &ReservationHint);\r
601 if (!EFI_ERROR (ReservationHintStatus)) {\r
602 INTN HighBit;\r
603\r
604 DEBUG ((\r
605 DEBUG_VERBOSE,\r
606 "%a: BusNumbers=0x%x Io=0x%Lx NonPrefetchable32BitMmio=0x%x\n"\r
607 "%a: Prefetchable32BitMmio=0x%x Prefetchable64BitMmio=0x%Lx\n",\r
608 __FUNCTION__,\r
609 ReservationHint.BusNumbers,\r
610 ReservationHint.Io,\r
611 ReservationHint.NonPrefetchable32BitMmio,\r
612 __FUNCTION__,\r
613 ReservationHint.Prefetchable32BitMmio,\r
614 ReservationHint.Prefetchable64BitMmio\r
615 ));\r
616\r
617 //\r
618 // (a) Reserve bus numbers.\r
619 //\r
620 switch (ReservationHint.BusNumbers) {\r
621 case 0:\r
622 //\r
623 // No reservation needed.\r
624 //\r
625 break;\r
626 case MAX_UINT32:\r
627 //\r
628 // Firmware default (unspecified). Treat it as "no reservation needed".\r
629 //\r
630 break;\r
631 default:\r
632 //\r
633 // Request the specified amount.\r
634 //\r
635 --FirstResource;\r
636 FirstResource->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
637 FirstResource->AddrLen = ReservationHint.BusNumbers;\r
638 break;\r
639 }\r
640\r
641 //\r
642 // (b) Reserve IO space.\r
643 //\r
644 switch (ReservationHint.Io) {\r
645 case 0:\r
646 //\r
647 // No reservation needed, disable our built-in.\r
648 //\r
649 DefaultIo = FALSE;\r
650 break;\r
651 case MAX_UINT64:\r
652 //\r
653 // Firmware default (unspecified). Stick with our built-in.\r
654 //\r
655 break;\r
656 default:\r
657 //\r
658 // Round the specified amount up to the next power of two. If rounding is\r
659 // successful, reserve the rounded value. Fall back to the default\r
660 // otherwise.\r
661 //\r
662 HighBit = HighBitSetRoundUp64 (ReservationHint.Io);\r
663 if (HighBit != -1) {\r
664 SetIoPadding (--FirstResource, (UINTN)HighBit);\r
665 DefaultIo = FALSE;\r
666 }\r
667 break;\r
668 }\r
669\r
670 //\r
671 // (c) Reserve non-prefetchable MMIO space (32-bit only).\r
672 //\r
673 switch (ReservationHint.NonPrefetchable32BitMmio) {\r
674 case 0:\r
675 //\r
676 // No reservation needed, disable our built-in.\r
677 //\r
678 DefaultMmio = FALSE;\r
679 break;\r
680 case MAX_UINT32:\r
681 //\r
682 // Firmware default (unspecified). Stick with our built-in.\r
683 //\r
684 break;\r
685 default:\r
686 //\r
687 // Round the specified amount up to the next power of two. If rounding is\r
688 // successful, reserve the rounded value. Fall back to the default\r
689 // otherwise.\r
690 //\r
691 HighBit = HighBitSetRoundUp32 (ReservationHint.NonPrefetchable32BitMmio);\r
692 if (HighBit != -1) {\r
693 SetMmioPadding (--FirstResource, FALSE, TRUE, (UINTN)HighBit);\r
694 DefaultMmio = FALSE;\r
695 }\r
696 break;\r
697 }\r
698\r
699 //\r
700 // (d) Reserve prefetchable MMIO space (either 32-bit or 64-bit, never\r
701 // both).\r
702 //\r
703 // For either space, we treat 0 as "no reservation needed", and the maximum\r
704 // value as "firmware default". The latter is unspecified, and we interpret\r
705 // it as the former.\r
706 //\r
707 // Otherwise, round the specified amount up to the next power of two. If\r
708 // rounding is successful, reserve the rounded value. Do not reserve\r
709 // prefetchable MMIO space otherwise.\r
710 //\r
711 if (ReservationHint.Prefetchable32BitMmio > 0 &&\r
712 ReservationHint.Prefetchable32BitMmio < MAX_UINT32) {\r
713 HighBit = HighBitSetRoundUp32 (ReservationHint.Prefetchable32BitMmio);\r
714 if (HighBit != -1) {\r
715 SetMmioPadding (--FirstResource, TRUE, TRUE, (UINTN)HighBit);\r
716 }\r
717 } else if (ReservationHint.Prefetchable64BitMmio > 0 &&\r
718 ReservationHint.Prefetchable64BitMmio < MAX_UINT64) {\r
719 HighBit = HighBitSetRoundUp64 (ReservationHint.Prefetchable64BitMmio);\r
720 if (HighBit != -1) {\r
721 SetMmioPadding (--FirstResource, TRUE, FALSE, (UINTN)HighBit);\r
722 }\r
723 }\r
724 }\r
725\r
a9803247
LE
726 if (DefaultIo) {\r
727 //\r
728 // Request defaults.\r
729 //\r
4776d5cb 730 SetIoPadding (--FirstResource, (UINTN)HighBitSetRoundUp64 (512));\r
a9803247
LE
731 }\r
732\r
a9803247
LE
733 if (DefaultMmio) {\r
734 //\r
735 // Request defaults.\r
736 //\r
4776d5cb
LE
737 SetMmioPadding (\r
738 --FirstResource,\r
739 FALSE,\r
740 TRUE,\r
741 (UINTN)HighBitSetRoundUp32 (SIZE_2MB)\r
742 );\r
a9803247
LE
743 }\r
744\r
745 //\r
746 // Output a copy of ReservationRequest from the lowest-address populated\r
747 // entry until the end of the structure (including\r
748 // ReservationRequest.EndDesc). If no reservations are necessary, we'll only\r
749 // output the End Tag.\r
750 //\r
751 *Padding = AllocateCopyPool (\r
752 (UINT8 *)(&ReservationRequest + 1) - (UINT8 *)FirstResource,\r
753 FirstResource\r
754 );\r
8aba40b7
LE
755 if (*Padding == NULL) {\r
756 return EFI_OUT_OF_RESOURCES;\r
757 }\r
758\r
759 //\r
760 // Resource padding is required.\r
761 //\r
762 *HpcState = EFI_HPC_STATE_INITIALIZED | EFI_HPC_STATE_ENABLED;\r
763\r
764 //\r
765 // The padding should be applied at PCI bus level, and considered by upstream\r
766 // bridges, recursively.\r
767 //\r
768 *Attributes = EfiPaddingPciBus;\r
769 return EFI_SUCCESS;\r
770}\r
771\r
772\r
773/**\r
774 Entry point for this driver.\r
775\r
776 @param[in] ImageHandle Image handle of this driver.\r
777 @param[in] SystemTable Pointer to SystemTable.\r
778\r
779 @retval EFI_SUCESS Driver has loaded successfully.\r
780 @return Error codes from lower level functions.\r
781\r
782**/\r
783EFI_STATUS\r
784EFIAPI\r
785DriverInitialize (\r
786 IN EFI_HANDLE ImageHandle,\r
787 IN EFI_SYSTEM_TABLE *SystemTable\r
788 )\r
789{\r
790 EFI_STATUS Status;\r
791\r
3815101f
LE
792 mPciExtConfSpaceSupported = (PcdGet16 (PcdOvmfHostBridgePciDevId) ==\r
793 INTEL_Q35_MCH_DEVICE_ID);\r
8aba40b7
LE
794 mPciHotPlugInit.GetRootHpcList = GetRootHpcList;\r
795 mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;\r
796 mPciHotPlugInit.GetResourcePadding = GetResourcePadding;\r
797 Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,\r
798 &gEfiPciHotPlugInitProtocolGuid, &mPciHotPlugInit, NULL);\r
799 return Status;\r
800}\r