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