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] Io IO aperture.
205 @param[in] Mem MMIO aperture.
207 @param[in] MemAbove4G MMIO aperture above 4G.
209 @param[in] PMem Prefetchable MMIO aperture.
211 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
213 @return All the root bridge instances in an array.
217 PciHostBridgeUtilityGetRootBridges (
219 IN UINT64 Attributes
,
220 IN UINT64 AllocationAttributes
,
221 IN BOOLEAN DmaAbove4G
,
222 IN BOOLEAN NoExtendedConfigSpace
,
223 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
224 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
225 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
226 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
227 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
231 FIRMWARE_CONFIG_ITEM FwCfgItem
;
233 UINT64 ExtraRootBridges
;
234 PCI_ROOT_BRIDGE
*Bridges
;
236 UINTN LastRootBridgeNumber
;
237 UINTN RootBridgeNumber
;
242 // QEMU provides the number of extra root buses, shortening the exhaustive
243 // search below. If there is no hint, the feature is missing.
245 Status
= QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem
, &FwCfgSize
);
246 if (EFI_ERROR (Status
) || FwCfgSize
!= sizeof ExtraRootBridges
) {
247 ExtraRootBridges
= 0;
249 QemuFwCfgSelectItem (FwCfgItem
);
250 QemuFwCfgReadBytes (FwCfgSize
, &ExtraRootBridges
);
252 if (ExtraRootBridges
> PCI_MAX_BUS
) {
253 DEBUG ((DEBUG_ERROR
, "%a: invalid count of extra root buses (%Lu) "
254 "reported by QEMU\n", __FUNCTION__
, ExtraRootBridges
));
257 DEBUG ((DEBUG_INFO
, "%a: %Lu extra root buses reported by QEMU\n",
258 __FUNCTION__
, ExtraRootBridges
));
262 // Allocate the "main" root bridge, and any extra root bridges.
264 Bridges
= AllocatePool ((1 + (UINTN
)ExtraRootBridges
) * sizeof *Bridges
);
265 if (Bridges
== NULL
) {
266 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
272 // The "main" root bus is always there.
274 LastRootBridgeNumber
= 0;
277 // Scan all other root buses. If function 0 of any device on a bus returns a
278 // VendorId register value different from all-bits-one, then that bus is
281 for (RootBridgeNumber
= 1;
282 RootBridgeNumber
<= PCI_MAX_BUS
&& Initialized
< ExtraRootBridges
;
283 ++RootBridgeNumber
) {
286 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; ++Device
) {
287 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber
, Device
, 0,
288 PCI_VENDOR_ID_OFFSET
)) != MAX_UINT16
) {
292 if (Device
<= PCI_MAX_DEVICE
) {
294 // Found the next root bus. We can now install the *previous* one,
295 // because now we know how big a bus number range *that* one has, for any
296 // subordinate buses that might exist behind PCI bridges hanging off it.
298 Status
= PciHostBridgeUtilityInitRootBridge (
301 AllocationAttributes
,
303 NoExtendedConfigSpace
,
304 (UINT8
) LastRootBridgeNumber
,
305 (UINT8
) (RootBridgeNumber
- 1),
311 &Bridges
[Initialized
]
313 if (EFI_ERROR (Status
)) {
317 LastRootBridgeNumber
= RootBridgeNumber
;
322 // Install the last root bus (which might be the only, ie. main, root bus, if
323 // we've found no extra root buses).
325 Status
= PciHostBridgeUtilityInitRootBridge (
328 AllocationAttributes
,
330 NoExtendedConfigSpace
,
331 (UINT8
) LastRootBridgeNumber
,
338 &Bridges
[Initialized
]
340 if (EFI_ERROR (Status
)) {
345 *Count
= Initialized
;
349 while (Initialized
> 0) {
351 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Initialized
]);
360 Utility function to free root bridge instances array from
361 PciHostBridgeUtilityGetRootBridges().
363 @param[in] Bridges The root bridge instances array.
364 @param[in] Count The count of the array.
368 PciHostBridgeUtilityFreeRootBridges (
369 IN PCI_ROOT_BRIDGE
*Bridges
,
373 if (Bridges
== NULL
&& Count
== 0) {
376 ASSERT (Bridges
!= NULL
&& Count
> 0);
380 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Count
]);
388 Utility function to inform the platform that the resource conflict happens.
390 @param[in] Configuration Pointer to PCI I/O and PCI memory resource
391 descriptors. The Configuration contains the
392 resources for all the root bridges. The resource
393 for each root bridge is terminated with END
394 descriptor and an additional END is appended
395 indicating the end of the entire resources. The
396 resource descriptor field values follow the
398 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
403 PciHostBridgeUtilityResourceConflict (
404 IN VOID
*Configuration
407 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
408 UINTN RootBridgeIndex
;
409 DEBUG ((DEBUG_ERROR
, "PciHostBridge: Resource conflict happens!\n"));
412 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
;
413 while (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
414 DEBUG ((DEBUG_ERROR
, "RootBridge[%d]:\n", RootBridgeIndex
++));
415 for (; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
416 ASSERT (Descriptor
->ResType
<
417 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
)
419 DEBUG ((DEBUG_ERROR
, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
420 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[Descriptor
->ResType
],
421 Descriptor
->AddrLen
, Descriptor
->AddrRangeMax
423 if (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
424 DEBUG ((DEBUG_ERROR
, " Granularity/SpecificFlag = %ld / %02x%s\n",
425 Descriptor
->AddrSpaceGranularity
, Descriptor
->SpecificFlag
,
426 ((Descriptor
->SpecificFlag
&
427 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
428 ) != 0) ? L
" (Prefetchable)" : L
""
433 // Skip the END descriptor for root bridge
435 ASSERT (Descriptor
->Desc
== ACPI_END_TAG_DESCRIPTOR
);
436 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)(
437 (EFI_ACPI_END_TAG_DESCRIPTOR
*)Descriptor
+ 1