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>
26 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
27 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
28 } OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
;
32 GLOBAL_REMOVE_IF_UNREFERENCED
33 CHAR16
*mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[] = {
34 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
,
66 Utility function to initialize a PCI_ROOT_BRIDGE structure.
68 @param[in] Supports Supported attributes.
70 @param[in] Attributes Initial attributes.
72 @param[in] AllocAttributes Allocation attributes.
74 @param[in] DmaAbove4G DMA above 4GB memory.
76 @param[in] NoExtendedConfigSpace No Extended Config Space.
78 @param[in] RootBusNumber The bus number to store in RootBus.
80 @param[in] MaxSubBusNumber The inclusive maximum bus number that can
81 be assigned to any subordinate bus found
82 behind any PCI bridge hanging off this
85 The caller is repsonsible for ensuring
86 that RootBusNumber <= MaxSubBusNumber. If
87 RootBusNumber equals MaxSubBusNumber, then
88 the root bus has no room for subordinate
91 @param[in] Io IO aperture.
93 @param[in] Mem MMIO aperture.
95 @param[in] MemAbove4G MMIO aperture above 4G.
97 @param[in] PMem Prefetchable MMIO aperture.
99 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
101 @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated
102 by the caller) that should be filled in by
105 @retval EFI_SUCCESS Initialization successful. A device path
106 consisting of an ACPI device path node,
107 with UID = RootBusNumber, has been
108 allocated and linked into RootBus.
110 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
114 PciHostBridgeUtilityInitRootBridge (
116 IN UINT64 Attributes
,
117 IN UINT64 AllocAttributes
,
118 IN BOOLEAN DmaAbove4G
,
119 IN BOOLEAN NoExtendedConfigSpace
,
120 IN UINT8 RootBusNumber
,
121 IN UINT8 MaxSubBusNumber
,
122 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
123 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
124 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
125 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
126 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
,
127 OUT PCI_ROOT_BRIDGE
*RootBus
130 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
*DevicePath
;
133 // Be safe if other fields are added to PCI_ROOT_BRIDGE later.
135 ZeroMem (RootBus
, sizeof *RootBus
);
137 RootBus
->Segment
= 0;
139 RootBus
->Supports
= Supports
;
140 RootBus
->Attributes
= Attributes
;
142 RootBus
->DmaAbove4G
= DmaAbove4G
;
144 RootBus
->AllocationAttributes
= AllocAttributes
;
145 RootBus
->Bus
.Base
= RootBusNumber
;
146 RootBus
->Bus
.Limit
= MaxSubBusNumber
;
147 CopyMem (&RootBus
->Io
, Io
, sizeof (*Io
));
148 CopyMem (&RootBus
->Mem
, Mem
, sizeof (*Mem
));
149 CopyMem (&RootBus
->MemAbove4G
, MemAbove4G
, sizeof (*MemAbove4G
));
150 CopyMem (&RootBus
->PMem
, PMem
, sizeof (*PMem
));
151 CopyMem (&RootBus
->PMemAbove4G
, PMemAbove4G
, sizeof (*PMemAbove4G
));
153 RootBus
->NoExtendedConfigSpace
= NoExtendedConfigSpace
;
155 DevicePath
= AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate
,
156 &mRootBridgeDevicePathTemplate
);
157 if (DevicePath
== NULL
) {
158 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
159 return EFI_OUT_OF_RESOURCES
;
161 DevicePath
->AcpiDevicePath
.UID
= RootBusNumber
;
162 RootBus
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
165 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",
166 __FUNCTION__
, RootBusNumber
, MaxSubBusNumber
- RootBusNumber
));
172 Utility function to uninitialize a PCI_ROOT_BRIDGE structure set up with
173 PciHostBridgeUtilityInitRootBridge().
175 @param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and
176 initialized with PciHostBridgeUtilityInitRootBridge(),
177 that should be uninitialized. This function doesn't free
182 PciHostBridgeUtilityUninitRootBridge (
183 IN PCI_ROOT_BRIDGE
*RootBus
186 FreePool (RootBus
->DevicePath
);
191 Utility function to return all the root bridge instances in an array.
193 @param[out] Count The number of root bridge instances.
195 @param[in] Attributes Initial attributes.
197 @param[in] AllocAttributes Allocation attributes.
199 @param[in] DmaAbove4G DMA above 4GB memory.
201 @param[in] NoExtendedConfigSpace No Extended Config Space.
203 @param[in] BusMin Minimum Bus number, inclusive.
205 @param[in] BusMax Maximum Bus number, inclusive.
207 @param[in] Io IO aperture.
209 @param[in] Mem MMIO aperture.
211 @param[in] MemAbove4G MMIO aperture above 4G.
213 @param[in] PMem Prefetchable MMIO aperture.
215 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
217 @return All the root bridge instances in an array.
221 PciHostBridgeUtilityGetRootBridges (
223 IN UINT64 Attributes
,
224 IN UINT64 AllocationAttributes
,
225 IN BOOLEAN DmaAbove4G
,
226 IN BOOLEAN NoExtendedConfigSpace
,
229 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
230 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
231 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
232 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
233 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
237 FIRMWARE_CONFIG_ITEM FwCfgItem
;
239 UINT64 ExtraRootBridges
;
240 PCI_ROOT_BRIDGE
*Bridges
;
242 UINTN LastRootBridgeNumber
;
243 UINTN RootBridgeNumber
;
247 if (BusMin
> BusMax
|| BusMax
> PCI_MAX_BUS
) {
248 DEBUG ((DEBUG_ERROR
, "%a: invalid bus range with BusMin %Lu and BusMax "
249 "%Lu\n", __FUNCTION__
, (UINT64
)BusMin
, (UINT64
)BusMax
));
254 // QEMU provides the number of extra root buses, shortening the exhaustive
255 // search below. If there is no hint, the feature is missing.
257 Status
= QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem
, &FwCfgSize
);
258 if (EFI_ERROR (Status
) || FwCfgSize
!= sizeof ExtraRootBridges
) {
259 ExtraRootBridges
= 0;
261 QemuFwCfgSelectItem (FwCfgItem
);
262 QemuFwCfgReadBytes (FwCfgSize
, &ExtraRootBridges
);
265 // Validate the number of extra root bridges. As BusMax is inclusive, the
266 // max bus count is (BusMax - BusMin + 1). From that, the "main" root bus
267 // is always a given, so the max count for the "extra" root bridges is one
268 // less, i.e. (BusMax - BusMin). If the QEMU hint exceeds that, we have
271 if (ExtraRootBridges
> BusMax
- BusMin
) {
272 DEBUG ((DEBUG_ERROR
, "%a: invalid count of extra root buses (%Lu) "
273 "reported by QEMU\n", __FUNCTION__
, ExtraRootBridges
));
276 DEBUG ((DEBUG_INFO
, "%a: %Lu extra root buses reported by QEMU\n",
277 __FUNCTION__
, ExtraRootBridges
));
281 // Allocate the "main" root bridge, and any extra root bridges.
283 Bridges
= AllocatePool ((1 + (UINTN
)ExtraRootBridges
) * sizeof *Bridges
);
284 if (Bridges
== NULL
) {
285 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
291 // The "main" root bus is always there.
293 LastRootBridgeNumber
= BusMin
;
296 // Scan all other root buses. If function 0 of any device on a bus returns a
297 // VendorId register value different from all-bits-one, then that bus is
300 for (RootBridgeNumber
= BusMin
+ 1;
301 RootBridgeNumber
<= BusMax
&& Initialized
< ExtraRootBridges
;
302 ++RootBridgeNumber
) {
305 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; ++Device
) {
306 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber
, Device
, 0,
307 PCI_VENDOR_ID_OFFSET
)) != MAX_UINT16
) {
311 if (Device
<= PCI_MAX_DEVICE
) {
313 // Found the next root bus. We can now install the *previous* one,
314 // because now we know how big a bus number range *that* one has, for any
315 // subordinate buses that might exist behind PCI bridges hanging off it.
317 Status
= PciHostBridgeUtilityInitRootBridge (
320 AllocationAttributes
,
322 NoExtendedConfigSpace
,
323 (UINT8
) LastRootBridgeNumber
,
324 (UINT8
) (RootBridgeNumber
- 1),
330 &Bridges
[Initialized
]
332 if (EFI_ERROR (Status
)) {
336 LastRootBridgeNumber
= RootBridgeNumber
;
341 // Install the last root bus (which might be the only, ie. main, root bus, if
342 // we've found no extra root buses).
344 Status
= PciHostBridgeUtilityInitRootBridge (
347 AllocationAttributes
,
349 NoExtendedConfigSpace
,
350 (UINT8
) LastRootBridgeNumber
,
357 &Bridges
[Initialized
]
359 if (EFI_ERROR (Status
)) {
364 *Count
= Initialized
;
368 while (Initialized
> 0) {
370 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Initialized
]);
379 Utility function to free root bridge instances array from
380 PciHostBridgeUtilityGetRootBridges().
382 @param[in] Bridges The root bridge instances array.
383 @param[in] Count The count of the array.
387 PciHostBridgeUtilityFreeRootBridges (
388 IN PCI_ROOT_BRIDGE
*Bridges
,
392 if (Bridges
== NULL
&& Count
== 0) {
395 ASSERT (Bridges
!= NULL
&& Count
> 0);
399 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Count
]);
407 Utility function to inform the platform that the resource conflict happens.
409 @param[in] Configuration Pointer to PCI I/O and PCI memory resource
410 descriptors. The Configuration contains the
411 resources for all the root bridges. The resource
412 for each root bridge is terminated with END
413 descriptor and an additional END is appended
414 indicating the end of the entire resources. The
415 resource descriptor field values follow the
417 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
422 PciHostBridgeUtilityResourceConflict (
423 IN VOID
*Configuration
426 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
427 UINTN RootBridgeIndex
;
428 DEBUG ((DEBUG_ERROR
, "PciHostBridge: Resource conflict happens!\n"));
431 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
;
432 while (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
433 DEBUG ((DEBUG_ERROR
, "RootBridge[%d]:\n", RootBridgeIndex
++));
434 for (; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
435 ASSERT (Descriptor
->ResType
<
436 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
)
438 DEBUG ((DEBUG_ERROR
, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
439 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[Descriptor
->ResType
],
440 Descriptor
->AddrLen
, Descriptor
->AddrRangeMax
442 if (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
443 DEBUG ((DEBUG_ERROR
, " Granularity/SpecificFlag = %ld / %02x%s\n",
444 Descriptor
->AddrSpaceGranularity
, Descriptor
->SpecificFlag
,
445 ((Descriptor
->SpecificFlag
&
446 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
447 ) != 0) ? L
" (Prefetchable)" : L
""
452 // Skip the END descriptor for root bridge
454 ASSERT (Descriptor
->Desc
== ACPI_END_TAG_DESCRIPTOR
);
455 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)(
456 (EFI_ACPI_END_TAG_DESCRIPTOR
*)Descriptor
+ 1