2 Provide common utility functions to PciHostBridgeLib instances in
3 ArmVirtPkg and OvmfPkg.
5 Copyright (C) 2016, Red Hat, Inc.
6 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2020, Huawei Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <IndustryStandard/Acpi10.h>
14 #include <IndustryStandard/Pci.h>
15 #include <Library/BaseLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/DevicePathLib.h>
19 #include <Library/HardwareInfoLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/PciHostBridgeUtilityLib.h>
22 #include <Library/PciLib.h>
23 #include <Library/QemuFwCfgLib.h>
24 #include <Protocol/PciHostBridgeResourceAllocation.h>
28 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
29 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
30 } OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
;
33 GLOBAL_REMOVE_IF_UNREFERENCED
34 CHAR16
*mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[] = {
35 L
"Mem", L
"I/O", L
"Bus"
40 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate
= {
46 (UINT8
)(sizeof (ACPI_HID_DEVICE_PATH
)),
47 (UINT8
)((sizeof (ACPI_HID_DEVICE_PATH
)) >> 8)
50 EISA_PNP_ID (0x0A03), // HID
56 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
58 END_DEVICE_PATH_LENGTH
,
65 Utility function to initialize a PCI_ROOT_BRIDGE structure.
67 @param[in] Supports Supported attributes.
69 @param[in] Attributes Initial attributes.
71 @param[in] AllocAttributes Allocation attributes.
73 @param[in] DmaAbove4G DMA above 4GB memory.
75 @param[in] NoExtendedConfigSpace No Extended Config Space.
77 @param[in] RootBusNumber The bus number to store in RootBus.
79 @param[in] MaxSubBusNumber The inclusive maximum bus number that can
80 be assigned to any subordinate bus found
81 behind any PCI bridge hanging off this
84 The caller is repsonsible for ensuring
85 that RootBusNumber <= MaxSubBusNumber. If
86 RootBusNumber equals MaxSubBusNumber, then
87 the root bus has no room for subordinate
90 @param[in] Io IO aperture.
92 @param[in] Mem MMIO aperture.
94 @param[in] MemAbove4G MMIO aperture above 4G.
96 @param[in] PMem Prefetchable MMIO aperture.
98 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
100 @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated
101 by the caller) that should be filled in by
104 @retval EFI_SUCCESS Initialization successful. A device path
105 consisting of an ACPI device path node,
106 with UID = RootBusNumber, has been
107 allocated and linked into RootBus.
109 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
113 PciHostBridgeUtilityInitRootBridge (
115 IN UINT64 Attributes
,
116 IN UINT64 AllocAttributes
,
117 IN BOOLEAN DmaAbove4G
,
118 IN BOOLEAN NoExtendedConfigSpace
,
119 IN UINT8 RootBusNumber
,
120 IN UINT8 MaxSubBusNumber
,
121 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
122 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
123 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
124 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
125 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
,
126 OUT PCI_ROOT_BRIDGE
*RootBus
129 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
*DevicePath
;
132 // Be safe if other fields are added to PCI_ROOT_BRIDGE later.
134 ZeroMem (RootBus
, sizeof *RootBus
);
136 RootBus
->Segment
= 0;
138 RootBus
->Supports
= Supports
;
139 RootBus
->Attributes
= Attributes
;
141 RootBus
->DmaAbove4G
= DmaAbove4G
;
143 RootBus
->AllocationAttributes
= AllocAttributes
;
144 RootBus
->Bus
.Base
= RootBusNumber
;
145 RootBus
->Bus
.Limit
= MaxSubBusNumber
;
146 CopyMem (&RootBus
->Io
, Io
, sizeof (*Io
));
147 CopyMem (&RootBus
->Mem
, Mem
, sizeof (*Mem
));
148 CopyMem (&RootBus
->MemAbove4G
, MemAbove4G
, sizeof (*MemAbove4G
));
149 CopyMem (&RootBus
->PMem
, PMem
, sizeof (*PMem
));
150 CopyMem (&RootBus
->PMemAbove4G
, PMemAbove4G
, sizeof (*PMemAbove4G
));
152 RootBus
->NoExtendedConfigSpace
= NoExtendedConfigSpace
;
154 DevicePath
= AllocateCopyPool (
155 sizeof mRootBridgeDevicePathTemplate
,
156 &mRootBridgeDevicePathTemplate
158 if (DevicePath
== NULL
) {
159 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
160 return EFI_OUT_OF_RESOURCES
;
163 DevicePath
->AcpiDevicePath
.UID
= RootBusNumber
;
164 RootBus
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
168 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",
171 MaxSubBusNumber
- RootBusNumber
177 Utility function to uninitialize a PCI_ROOT_BRIDGE structure set up with
178 PciHostBridgeUtilityInitRootBridge().
180 @param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and
181 initialized with PciHostBridgeUtilityInitRootBridge(),
182 that should be uninitialized. This function doesn't free
187 PciHostBridgeUtilityUninitRootBridge (
188 IN PCI_ROOT_BRIDGE
*RootBus
191 FreePool (RootBus
->DevicePath
);
195 Utility function to scan PCI root bridges and create instances for those
196 that are found not empty. Populate their resources from the default
197 provided parameters and return all the root bridge instances in an array.
199 @param[out] Count The number of root bridge instances.
201 @param[in] Attributes Initial attributes.
203 @param[in] AllocAttributes Allocation attributes.
205 @param[in] DmaAbove4G DMA above 4GB memory.
207 @param[in] NoExtendedConfigSpace No Extended Config Space.
209 @param[in] BusMin Minimum Bus number, inclusive.
211 @param[in] BusMax Maximum Bus number, inclusive.
213 @param[in] Io IO aperture.
215 @param[in] Mem MMIO aperture.
217 @param[in] MemAbove4G MMIO aperture above 4G.
219 @param[in] PMem Prefetchable MMIO aperture.
221 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
223 @return All the root bridge instances in an array.
227 PciHostBridgeUtilityGetRootBridgesBusScan (
229 IN UINT64 Attributes
,
230 IN UINT64 AllocationAttributes
,
231 IN BOOLEAN DmaAbove4G
,
232 IN BOOLEAN NoExtendedConfigSpace
,
235 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
236 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
237 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
238 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
239 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
243 FIRMWARE_CONFIG_ITEM FwCfgItem
;
245 UINT64 ExtraRootBridges
;
246 PCI_ROOT_BRIDGE
*Bridges
;
248 UINTN LastRootBridgeNumber
;
249 UINTN RootBridgeNumber
;
251 if ((BusMin
> BusMax
) || (BusMax
> PCI_MAX_BUS
)) {
254 "%a: invalid bus range with BusMin %Lu and BusMax "
264 // QEMU provides the number of extra root buses, shortening the exhaustive
265 // search below. If there is no hint, the feature is missing.
267 Status
= QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem
, &FwCfgSize
);
268 if (EFI_ERROR (Status
) || (FwCfgSize
!= sizeof ExtraRootBridges
)) {
269 ExtraRootBridges
= 0;
271 QemuFwCfgSelectItem (FwCfgItem
);
272 QemuFwCfgReadBytes (FwCfgSize
, &ExtraRootBridges
);
275 // Validate the number of extra root bridges. As BusMax is inclusive, the
276 // max bus count is (BusMax - BusMin + 1). From that, the "main" root bus
277 // is always a given, so the max count for the "extra" root bridges is one
278 // less, i.e. (BusMax - BusMin). If the QEMU hint exceeds that, we have
281 if (ExtraRootBridges
> BusMax
- BusMin
) {
284 "%a: invalid count of extra root buses (%Lu) "
285 "reported by QEMU\n",
294 "%a: %Lu extra root buses reported by QEMU\n",
301 // Allocate the "main" root bridge, and any extra root bridges.
303 Bridges
= AllocatePool ((1 + (UINTN
)ExtraRootBridges
) * sizeof *Bridges
);
304 if (Bridges
== NULL
) {
305 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
312 // The "main" root bus is always there.
314 LastRootBridgeNumber
= BusMin
;
317 // Scan all other root buses. If function 0 of any device on a bus returns a
318 // VendorId register value different from all-bits-one, then that bus is
321 for (RootBridgeNumber
= BusMin
+ 1;
322 RootBridgeNumber
<= BusMax
&& Initialized
< ExtraRootBridges
;
327 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; ++Device
) {
341 if (Device
<= PCI_MAX_DEVICE
) {
343 // Found the next root bus. We can now install the *previous* one,
344 // because now we know how big a bus number range *that* one has, for any
345 // subordinate buses that might exist behind PCI bridges hanging off it.
347 Status
= PciHostBridgeUtilityInitRootBridge (
350 AllocationAttributes
,
352 NoExtendedConfigSpace
,
353 (UINT8
)LastRootBridgeNumber
,
354 (UINT8
)(RootBridgeNumber
- 1),
360 &Bridges
[Initialized
]
362 if (EFI_ERROR (Status
)) {
367 LastRootBridgeNumber
= RootBridgeNumber
;
372 // Install the last root bus (which might be the only, ie. main, root bus, if
373 // we've found no extra root buses).
375 Status
= PciHostBridgeUtilityInitRootBridge (
378 AllocationAttributes
,
380 NoExtendedConfigSpace
,
381 (UINT8
)LastRootBridgeNumber
,
388 &Bridges
[Initialized
]
390 if (EFI_ERROR (Status
)) {
396 *Count
= Initialized
;
400 while (Initialized
> 0) {
402 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Initialized
]);
410 Utility function to read root bridges information from host-provided fw-cfg
411 file and return them in an array.
413 @param[out] Count The number of root bridge instances.
415 @return All the root bridge instances in an array parsed from
416 host-provided fw-cfg file (hardware-info).
420 PciHostBridgeUtilityGetRootBridgesHostProvided (
425 FIRMWARE_CONFIG_ITEM FwCfgItem
;
427 PCI_ROOT_BRIDGE
*Bridges
;
429 UINTN LastRootBridgeNumber
;
430 UINTN RootBridgeNumber
;
431 UINTN PciHostBridgeCount
;
432 UINT8
*HardwareInfoBlob
;
433 LIST_ENTRY HwInfoList
;
435 HARDWARE_INFO
*HwInfo
;
437 UINT64 AllocationAttributes
;
439 BOOLEAN NoExtendedConfigSpace
;
440 BOOLEAN CombineMemPMem
;
441 PCI_ROOT_BRIDGE_APERTURE Io
;
442 PCI_ROOT_BRIDGE_APERTURE Mem
;
443 PCI_ROOT_BRIDGE_APERTURE MemAbove4G
;
444 PCI_ROOT_BRIDGE_APERTURE PMem
;
445 PCI_ROOT_BRIDGE_APERTURE PMemAbove4G
;
448 // Initialize the Hardware Info list head to start with an empty but valid
451 InitializeListHead (&HwInfoList
);
452 HardwareInfoBlob
= NULL
;
455 PciHostBridgeCount
= 0;
458 // Hypervisor can provide the specifications (resources) for one or more
459 // PCI host bridges. Such information comes through fw-cfg as part of
460 // the hardware-info file.
462 Status
= QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem
, &FwCfgSize
);
464 if (EFI_ERROR (Status
)) {
468 HardwareInfoBlob
= AllocatePool (FwCfgSize
);
470 if (HardwareInfoBlob
== NULL
) {
473 "%a: Failed to allocate memory for hardware resources info\n",
479 QemuFwCfgSelectItem (FwCfgItem
);
480 QemuFwCfgReadBytes (FwCfgSize
, HardwareInfoBlob
);
483 // Create the list of hardware info devices filtering for PCI host
486 Status
= CreateHardwareInfoList (
489 HardwareInfoTypeHostBridge
,
493 if (EFI_ERROR (Status
)) {
496 "%a: Failed to create hardware info list to retrieve host "
497 "bridges information from fw-cfg\n",
504 PciHostBridgeCount
= GetHardwareInfoCountByType (
506 HardwareInfoTypeHostBridge
,
507 sizeof (HOST_BRIDGE_INFO
)
510 if (PciHostBridgeCount
== 0) {
516 "%a: Host provided description for %Lu root bridges\n",
522 // Allocate the root bridges
524 Bridges
= AllocatePool (((UINTN
)PciHostBridgeCount
) * sizeof *Bridges
);
525 if (Bridges
== NULL
) {
526 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
531 // If Host Bridges' specification was obtained from fw-cfg, the list
532 // contains information to populate all root bridges in the system
533 // including resources and attributes.
535 HwLink
= GetFirstHardwareInfoByType (
537 HardwareInfoTypeHostBridge
,
538 sizeof (HOST_BRIDGE_INFO
)
541 while (!EndOfHardwareInfoList (&HwInfoList
, HwLink
)) {
542 HwInfo
= HARDWARE_INFO_FROM_LINK (HwLink
);
544 Status
= HardwareInfoPciHostBridgeGet (
545 HwInfo
->Data
.PciHostBridge
,
546 (UINTN
)HwInfo
->Header
.Size
,
548 &LastRootBridgeNumber
,
551 &NoExtendedConfigSpace
,
561 if (EFI_ERROR (Status
)) {
565 if ((RootBridgeNumber
> LastRootBridgeNumber
) || (LastRootBridgeNumber
> PCI_MAX_BUS
)) {
568 "%a: invalid bus range with BusMin %Lu and BusMax "
571 (UINT64
)RootBridgeNumber
,
572 (UINT64
)LastRootBridgeNumber
577 AllocationAttributes
= 0;
578 if (CombineMemPMem
) {
579 AllocationAttributes
|= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM
;
582 if ((MemAbove4G
.Limit
> MemAbove4G
.Base
) ||
583 (PMemAbove4G
.Limit
> PMemAbove4G
.Base
))
585 AllocationAttributes
|= EFI_PCI_HOST_BRIDGE_MEM64_DECODE
;
588 Status
= PciHostBridgeUtilityInitRootBridge (
591 AllocationAttributes
,
593 NoExtendedConfigSpace
,
594 (UINT8
)RootBridgeNumber
,
595 (UINT8
)LastRootBridgeNumber
,
601 &Bridges
[Initialized
]
604 if (EFI_ERROR (Status
)) {
610 HwLink
= GetNextHardwareInfoByType (
613 HardwareInfoTypeHostBridge
,
614 sizeof (HOST_BRIDGE_INFO
)
618 *Count
= Initialized
;
621 // If resources were allocated for host bridges info, release them
623 if (HardwareInfoBlob
) {
624 FreePool (HardwareInfoBlob
);
627 FreeHardwareInfoList (&HwInfoList
);
631 while (Initialized
> 0) {
633 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Initialized
]);
640 if (HardwareInfoBlob
) {
641 FreePool (HardwareInfoBlob
);
644 FreeHardwareInfoList (&HwInfoList
);
649 Utility function to return all the root bridge instances in an array.
651 @param[out] Count The number of root bridge instances.
653 @param[in] Attributes Initial attributes.
655 @param[in] AllocAttributes Allocation attributes.
657 @param[in] DmaAbove4G DMA above 4GB memory.
659 @param[in] NoExtendedConfigSpace No Extended Config Space.
661 @param[in] BusMin Minimum Bus number, inclusive.
663 @param[in] BusMax Maximum Bus number, inclusive.
665 @param[in] Io IO aperture.
667 @param[in] Mem MMIO aperture.
669 @param[in] MemAbove4G MMIO aperture above 4G.
671 @param[in] PMem Prefetchable MMIO aperture.
673 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
675 @return All the root bridge instances in an array.
679 PciHostBridgeUtilityGetRootBridges (
681 IN UINT64 Attributes
,
682 IN UINT64 AllocationAttributes
,
683 IN BOOLEAN DmaAbove4G
,
684 IN BOOLEAN NoExtendedConfigSpace
,
687 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
688 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
689 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
690 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
691 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
694 PCI_ROOT_BRIDGE
*Bridges
;
699 // First attempt to get the host provided descriptions of the Root Bridges
702 Bridges
= PciHostBridgeUtilityGetRootBridgesHostProvided (Count
);
705 // If host did not provide Root Bridge information, scan the buses and
706 // auto populate them with default resources.
708 if (Bridges
== NULL
) {
709 Bridges
= PciHostBridgeUtilityGetRootBridgesBusScan (
712 AllocationAttributes
,
714 NoExtendedConfigSpace
,
729 Utility function to free root bridge instances array from
730 PciHostBridgeUtilityGetRootBridges().
732 @param[in] Bridges The root bridge instances array.
733 @param[in] Count The count of the array.
737 PciHostBridgeUtilityFreeRootBridges (
738 IN PCI_ROOT_BRIDGE
*Bridges
,
742 if ((Bridges
== NULL
) && (Count
== 0)) {
746 ASSERT (Bridges
!= NULL
&& Count
> 0);
750 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Count
]);
757 Utility function to inform the platform that the resource conflict happens.
759 @param[in] Configuration Pointer to PCI I/O and PCI memory resource
760 descriptors. The Configuration contains the
761 resources for all the root bridges. The resource
762 for each root bridge is terminated with END
763 descriptor and an additional END is appended
764 indicating the end of the entire resources. The
765 resource descriptor field values follow the
767 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
772 PciHostBridgeUtilityResourceConflict (
773 IN VOID
*Configuration
776 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
777 UINTN RootBridgeIndex
;
779 DEBUG ((DEBUG_ERROR
, "PciHostBridge: Resource conflict happens!\n"));
782 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)Configuration
;
783 while (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
784 DEBUG ((DEBUG_ERROR
, "RootBridge[%d]:\n", RootBridgeIndex
++));
785 for ( ; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
787 Descriptor
->ResType
<
788 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
)
792 " %s: Length/Alignment = 0x%lx / 0x%lx\n",
793 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[Descriptor
->ResType
],
795 Descriptor
->AddrRangeMax
797 if (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
800 " Granularity/SpecificFlag = %ld / %02x%s\n",
801 Descriptor
->AddrSpaceGranularity
,
802 Descriptor
->SpecificFlag
,
803 ((Descriptor
->SpecificFlag
&
804 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
805 ) != 0) ? L
" (Prefetchable)" : L
""
811 // Skip the END descriptor for root bridge
813 ASSERT (Descriptor
->Desc
== ACPI_END_TAG_DESCRIPTOR
);
814 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)(
815 (EFI_ACPI_END_TAG_DESCRIPTOR
*)Descriptor
+ 1