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/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/DevicePathLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/PciHostBridgeUtilityLib.h>
20 #include <Library/PciLib.h>
21 #include <Library/QemuFwCfgLib.h>
25 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
26 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
27 } OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
;
30 GLOBAL_REMOVE_IF_UNREFERENCED
31 CHAR16
*mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[] = {
32 L
"Mem", L
"I/O", L
"Bus"
37 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate
= {
43 (UINT8
)(sizeof (ACPI_HID_DEVICE_PATH
)),
44 (UINT8
)((sizeof (ACPI_HID_DEVICE_PATH
)) >> 8)
47 EISA_PNP_ID (0x0A03), // HID
53 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
55 END_DEVICE_PATH_LENGTH
,
62 Utility function to initialize a PCI_ROOT_BRIDGE structure.
64 @param[in] Supports Supported attributes.
66 @param[in] Attributes Initial attributes.
68 @param[in] AllocAttributes Allocation attributes.
70 @param[in] DmaAbove4G DMA above 4GB memory.
72 @param[in] NoExtendedConfigSpace No Extended Config Space.
74 @param[in] RootBusNumber The bus number to store in RootBus.
76 @param[in] MaxSubBusNumber The inclusive maximum bus number that can
77 be assigned to any subordinate bus found
78 behind any PCI bridge hanging off this
81 The caller is repsonsible for ensuring
82 that RootBusNumber <= MaxSubBusNumber. If
83 RootBusNumber equals MaxSubBusNumber, then
84 the root bus has no room for subordinate
87 @param[in] Io IO aperture.
89 @param[in] Mem MMIO aperture.
91 @param[in] MemAbove4G MMIO aperture above 4G.
93 @param[in] PMem Prefetchable MMIO aperture.
95 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
97 @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated
98 by the caller) that should be filled in by
101 @retval EFI_SUCCESS Initialization successful. A device path
102 consisting of an ACPI device path node,
103 with UID = RootBusNumber, has been
104 allocated and linked into RootBus.
106 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
110 PciHostBridgeUtilityInitRootBridge (
112 IN UINT64 Attributes
,
113 IN UINT64 AllocAttributes
,
114 IN BOOLEAN DmaAbove4G
,
115 IN BOOLEAN NoExtendedConfigSpace
,
116 IN UINT8 RootBusNumber
,
117 IN UINT8 MaxSubBusNumber
,
118 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
119 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
120 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
121 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
122 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
,
123 OUT PCI_ROOT_BRIDGE
*RootBus
126 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
*DevicePath
;
129 // Be safe if other fields are added to PCI_ROOT_BRIDGE later.
131 ZeroMem (RootBus
, sizeof *RootBus
);
133 RootBus
->Segment
= 0;
135 RootBus
->Supports
= Supports
;
136 RootBus
->Attributes
= Attributes
;
138 RootBus
->DmaAbove4G
= DmaAbove4G
;
140 RootBus
->AllocationAttributes
= AllocAttributes
;
141 RootBus
->Bus
.Base
= RootBusNumber
;
142 RootBus
->Bus
.Limit
= MaxSubBusNumber
;
143 CopyMem (&RootBus
->Io
, Io
, sizeof (*Io
));
144 CopyMem (&RootBus
->Mem
, Mem
, sizeof (*Mem
));
145 CopyMem (&RootBus
->MemAbove4G
, MemAbove4G
, sizeof (*MemAbove4G
));
146 CopyMem (&RootBus
->PMem
, PMem
, sizeof (*PMem
));
147 CopyMem (&RootBus
->PMemAbove4G
, PMemAbove4G
, sizeof (*PMemAbove4G
));
149 RootBus
->NoExtendedConfigSpace
= NoExtendedConfigSpace
;
151 DevicePath
= AllocateCopyPool (
152 sizeof mRootBridgeDevicePathTemplate
,
153 &mRootBridgeDevicePathTemplate
155 if (DevicePath
== NULL
) {
156 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
157 return EFI_OUT_OF_RESOURCES
;
160 DevicePath
->AcpiDevicePath
.UID
= RootBusNumber
;
161 RootBus
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
165 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",
168 MaxSubBusNumber
- RootBusNumber
174 Utility function to uninitialize a PCI_ROOT_BRIDGE structure set up with
175 PciHostBridgeUtilityInitRootBridge().
177 @param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and
178 initialized with PciHostBridgeUtilityInitRootBridge(),
179 that should be uninitialized. This function doesn't free
184 PciHostBridgeUtilityUninitRootBridge (
185 IN PCI_ROOT_BRIDGE
*RootBus
188 FreePool (RootBus
->DevicePath
);
192 Utility function to return all the root bridge instances in an array.
194 @param[out] Count The number of root bridge instances.
196 @param[in] Attributes Initial attributes.
198 @param[in] AllocAttributes Allocation attributes.
200 @param[in] DmaAbove4G DMA above 4GB memory.
202 @param[in] NoExtendedConfigSpace No Extended Config Space.
204 @param[in] BusMin Minimum Bus number, inclusive.
206 @param[in] BusMax Maximum Bus number, inclusive.
208 @param[in] Io IO aperture.
210 @param[in] Mem MMIO aperture.
212 @param[in] MemAbove4G MMIO aperture above 4G.
214 @param[in] PMem Prefetchable MMIO aperture.
216 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
218 @return All the root bridge instances in an array.
222 PciHostBridgeUtilityGetRootBridges (
224 IN UINT64 Attributes
,
225 IN UINT64 AllocationAttributes
,
226 IN BOOLEAN DmaAbove4G
,
227 IN BOOLEAN NoExtendedConfigSpace
,
230 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
231 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
232 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
233 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
234 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
238 FIRMWARE_CONFIG_ITEM FwCfgItem
;
240 UINT64 ExtraRootBridges
;
241 PCI_ROOT_BRIDGE
*Bridges
;
243 UINTN LastRootBridgeNumber
;
244 UINTN RootBridgeNumber
;
248 if ((BusMin
> BusMax
) || (BusMax
> PCI_MAX_BUS
)) {
251 "%a: invalid bus range with BusMin %Lu and BusMax "
261 // QEMU provides the number of extra root buses, shortening the exhaustive
262 // search below. If there is no hint, the feature is missing.
264 Status
= QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem
, &FwCfgSize
);
265 if (EFI_ERROR (Status
) || (FwCfgSize
!= sizeof ExtraRootBridges
)) {
266 ExtraRootBridges
= 0;
268 QemuFwCfgSelectItem (FwCfgItem
);
269 QemuFwCfgReadBytes (FwCfgSize
, &ExtraRootBridges
);
272 // Validate the number of extra root bridges. As BusMax is inclusive, the
273 // max bus count is (BusMax - BusMin + 1). From that, the "main" root bus
274 // is always a given, so the max count for the "extra" root bridges is one
275 // less, i.e. (BusMax - BusMin). If the QEMU hint exceeds that, we have
278 if (ExtraRootBridges
> BusMax
- BusMin
) {
281 "%a: invalid count of extra root buses (%Lu) "
282 "reported by QEMU\n",
291 "%a: %Lu extra root buses reported by QEMU\n",
298 // Allocate the "main" root bridge, and any extra root bridges.
300 Bridges
= AllocatePool ((1 + (UINTN
)ExtraRootBridges
) * sizeof *Bridges
);
301 if (Bridges
== NULL
) {
302 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
309 // The "main" root bus is always there.
311 LastRootBridgeNumber
= BusMin
;
314 // Scan all other root buses. If function 0 of any device on a bus returns a
315 // VendorId register value different from all-bits-one, then that bus is
318 for (RootBridgeNumber
= BusMin
+ 1;
319 RootBridgeNumber
<= BusMax
&& Initialized
< ExtraRootBridges
;
324 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; ++Device
) {
338 if (Device
<= PCI_MAX_DEVICE
) {
340 // Found the next root bus. We can now install the *previous* one,
341 // because now we know how big a bus number range *that* one has, for any
342 // subordinate buses that might exist behind PCI bridges hanging off it.
344 Status
= PciHostBridgeUtilityInitRootBridge (
347 AllocationAttributes
,
349 NoExtendedConfigSpace
,
350 (UINT8
)LastRootBridgeNumber
,
351 (UINT8
)(RootBridgeNumber
- 1),
357 &Bridges
[Initialized
]
359 if (EFI_ERROR (Status
)) {
364 LastRootBridgeNumber
= RootBridgeNumber
;
369 // Install the last root bus (which might be the only, ie. main, root bus, if
370 // we've found no extra root buses).
372 Status
= PciHostBridgeUtilityInitRootBridge (
375 AllocationAttributes
,
377 NoExtendedConfigSpace
,
378 (UINT8
)LastRootBridgeNumber
,
385 &Bridges
[Initialized
]
387 if (EFI_ERROR (Status
)) {
393 *Count
= Initialized
;
397 while (Initialized
> 0) {
399 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Initialized
]);
407 Utility function to free root bridge instances array from
408 PciHostBridgeUtilityGetRootBridges().
410 @param[in] Bridges The root bridge instances array.
411 @param[in] Count The count of the array.
415 PciHostBridgeUtilityFreeRootBridges (
416 IN PCI_ROOT_BRIDGE
*Bridges
,
420 if ((Bridges
== NULL
) && (Count
== 0)) {
424 ASSERT (Bridges
!= NULL
&& Count
> 0);
428 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Count
]);
435 Utility function to inform the platform that the resource conflict happens.
437 @param[in] Configuration Pointer to PCI I/O and PCI memory resource
438 descriptors. The Configuration contains the
439 resources for all the root bridges. The resource
440 for each root bridge is terminated with END
441 descriptor and an additional END is appended
442 indicating the end of the entire resources. The
443 resource descriptor field values follow the
445 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
450 PciHostBridgeUtilityResourceConflict (
451 IN VOID
*Configuration
454 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
455 UINTN RootBridgeIndex
;
457 DEBUG ((DEBUG_ERROR
, "PciHostBridge: Resource conflict happens!\n"));
460 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)Configuration
;
461 while (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
462 DEBUG ((DEBUG_ERROR
, "RootBridge[%d]:\n", RootBridgeIndex
++));
463 for ( ; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
465 Descriptor
->ResType
<
466 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
)
470 " %s: Length/Alignment = 0x%lx / 0x%lx\n",
471 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[Descriptor
->ResType
],
473 Descriptor
->AddrRangeMax
475 if (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
478 " Granularity/SpecificFlag = %ld / %02x%s\n",
479 Descriptor
->AddrSpaceGranularity
,
480 Descriptor
->SpecificFlag
,
481 ((Descriptor
->SpecificFlag
&
482 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
483 ) != 0) ? L
" (Prefetchable)" : L
""
489 // Skip the END descriptor for root bridge
491 ASSERT (Descriptor
->Desc
== ACPI_END_TAG_DESCRIPTOR
);
492 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)(
493 (EFI_ACPI_END_TAG_DESCRIPTOR
*)Descriptor
+ 1