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 <IndustryStandard/Q35MchIch9.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/DevicePathLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/PciHostBridgeUtilityLib.h>
22 #include <Library/PciLib.h>
23 #include <Library/QemuFwCfgLib.h>
28 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
29 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
30 } OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
;
34 GLOBAL_REMOVE_IF_UNREFERENCED
35 CHAR16
*mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[] = {
36 L
"Mem", L
"I/O", L
"Bus"
42 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate
= {
48 (UINT8
) (sizeof(ACPI_HID_DEVICE_PATH
)),
49 (UINT8
) ((sizeof(ACPI_HID_DEVICE_PATH
)) >> 8)
52 EISA_PNP_ID(0x0A03), // HID
58 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
60 END_DEVICE_PATH_LENGTH
,
68 Utility function to initialize a PCI_ROOT_BRIDGE structure.
70 @param[in] Supports Supported attributes.
72 @param[in] Attributes Initial attributes.
74 @param[in] AllocAttributes Allocation attributes.
76 @param[in] DmaAbove4G DMA above 4GB memory.
78 @param[in] NoExtendedConfigSpace No Extended Config Space.
80 @param[in] RootBusNumber The bus number to store in RootBus.
82 @param[in] MaxSubBusNumber The inclusive maximum bus number that can
83 be assigned to any subordinate bus found
84 behind any PCI bridge hanging off this
87 The caller is repsonsible for ensuring
88 that RootBusNumber <= MaxSubBusNumber. If
89 RootBusNumber equals MaxSubBusNumber, then
90 the root bus has no room for subordinate
93 @param[in] Io IO aperture.
95 @param[in] Mem MMIO aperture.
97 @param[in] MemAbove4G MMIO aperture above 4G.
99 @param[in] PMem Prefetchable MMIO aperture.
101 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
103 @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated
104 by the caller) that should be filled in by
107 @retval EFI_SUCCESS Initialization successful. A device path
108 consisting of an ACPI device path node,
109 with UID = RootBusNumber, has been
110 allocated and linked into RootBus.
112 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
116 PciHostBridgeUtilityInitRootBridge (
118 IN UINT64 Attributes
,
119 IN UINT64 AllocAttributes
,
120 IN BOOLEAN DmaAbove4G
,
121 IN BOOLEAN NoExtendedConfigSpace
,
122 IN UINT8 RootBusNumber
,
123 IN UINT8 MaxSubBusNumber
,
124 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
125 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
126 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
127 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
128 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
,
129 OUT PCI_ROOT_BRIDGE
*RootBus
132 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
*DevicePath
;
135 // Be safe if other fields are added to PCI_ROOT_BRIDGE later.
137 ZeroMem (RootBus
, sizeof *RootBus
);
139 RootBus
->Segment
= 0;
141 RootBus
->Supports
= Supports
;
142 RootBus
->Attributes
= Attributes
;
144 RootBus
->DmaAbove4G
= DmaAbove4G
;
146 RootBus
->AllocationAttributes
= AllocAttributes
;
147 RootBus
->Bus
.Base
= RootBusNumber
;
148 RootBus
->Bus
.Limit
= MaxSubBusNumber
;
149 CopyMem (&RootBus
->Io
, Io
, sizeof (*Io
));
150 CopyMem (&RootBus
->Mem
, Mem
, sizeof (*Mem
));
151 CopyMem (&RootBus
->MemAbove4G
, MemAbove4G
, sizeof (*MemAbove4G
));
152 CopyMem (&RootBus
->PMem
, PMem
, sizeof (*PMem
));
153 CopyMem (&RootBus
->PMemAbove4G
, PMemAbove4G
, sizeof (*PMemAbove4G
));
155 RootBus
->NoExtendedConfigSpace
= NoExtendedConfigSpace
;
157 DevicePath
= AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate
,
158 &mRootBridgeDevicePathTemplate
);
159 if (DevicePath
== NULL
) {
160 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
161 return EFI_OUT_OF_RESOURCES
;
163 DevicePath
->AcpiDevicePath
.UID
= RootBusNumber
;
164 RootBus
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
167 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",
168 __FUNCTION__
, RootBusNumber
, 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
);
193 Utility function to return all the root bridge instances in an array.
195 @param[out] Count The number of root bridge instances.
197 @param[in] Attributes Initial attributes.
199 @param[in] AllocAttributes Allocation attributes.
201 @param[in] Io IO aperture.
203 @param[in] Mem MMIO aperture.
205 @param[in] MemAbove4G MMIO aperture above 4G.
207 @param[in] PMem Prefetchable MMIO aperture.
209 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
211 @return All the root bridge instances in an array.
215 PciHostBridgeUtilityGetRootBridges (
217 IN UINT64 Attributes
,
218 IN UINT64 AllocationAttributes
,
219 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
220 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
221 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
222 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
223 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
227 FIRMWARE_CONFIG_ITEM FwCfgItem
;
229 UINT64 ExtraRootBridges
;
230 PCI_ROOT_BRIDGE
*Bridges
;
232 UINTN LastRootBridgeNumber
;
233 UINTN RootBridgeNumber
;
238 // QEMU provides the number of extra root buses, shortening the exhaustive
239 // search below. If there is no hint, the feature is missing.
241 Status
= QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem
, &FwCfgSize
);
242 if (EFI_ERROR (Status
) || FwCfgSize
!= sizeof ExtraRootBridges
) {
243 ExtraRootBridges
= 0;
245 QemuFwCfgSelectItem (FwCfgItem
);
246 QemuFwCfgReadBytes (FwCfgSize
, &ExtraRootBridges
);
248 if (ExtraRootBridges
> PCI_MAX_BUS
) {
249 DEBUG ((DEBUG_ERROR
, "%a: invalid count of extra root buses (%Lu) "
250 "reported by QEMU\n", __FUNCTION__
, ExtraRootBridges
));
253 DEBUG ((DEBUG_INFO
, "%a: %Lu extra root buses reported by QEMU\n",
254 __FUNCTION__
, ExtraRootBridges
));
258 // Allocate the "main" root bridge, and any extra root bridges.
260 Bridges
= AllocatePool ((1 + (UINTN
)ExtraRootBridges
) * sizeof *Bridges
);
261 if (Bridges
== NULL
) {
262 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
268 // The "main" root bus is always there.
270 LastRootBridgeNumber
= 0;
273 // Scan all other root buses. If function 0 of any device on a bus returns a
274 // VendorId register value different from all-bits-one, then that bus is
277 for (RootBridgeNumber
= 1;
278 RootBridgeNumber
<= PCI_MAX_BUS
&& Initialized
< ExtraRootBridges
;
279 ++RootBridgeNumber
) {
282 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; ++Device
) {
283 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber
, Device
, 0,
284 PCI_VENDOR_ID_OFFSET
)) != MAX_UINT16
) {
288 if (Device
<= PCI_MAX_DEVICE
) {
290 // Found the next root bus. We can now install the *previous* one,
291 // because now we know how big a bus number range *that* one has, for any
292 // subordinate buses that might exist behind PCI bridges hanging off it.
294 Status
= PciHostBridgeUtilityInitRootBridge (
297 AllocationAttributes
,
299 PcdGet16 (PcdOvmfHostBridgePciDevId
) != INTEL_Q35_MCH_DEVICE_ID
,
300 (UINT8
) LastRootBridgeNumber
,
301 (UINT8
) (RootBridgeNumber
- 1),
307 &Bridges
[Initialized
]
309 if (EFI_ERROR (Status
)) {
313 LastRootBridgeNumber
= RootBridgeNumber
;
318 // Install the last root bus (which might be the only, ie. main, root bus, if
319 // we've found no extra root buses).
321 Status
= PciHostBridgeUtilityInitRootBridge (
324 AllocationAttributes
,
326 PcdGet16 (PcdOvmfHostBridgePciDevId
) != INTEL_Q35_MCH_DEVICE_ID
,
327 (UINT8
) LastRootBridgeNumber
,
334 &Bridges
[Initialized
]
336 if (EFI_ERROR (Status
)) {
341 *Count
= Initialized
;
345 while (Initialized
> 0) {
347 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Initialized
]);
356 Utility function to free root bridge instances array from
357 PciHostBridgeUtilityGetRootBridges().
359 @param[in] Bridges The root bridge instances array.
360 @param[in] Count The count of the array.
364 PciHostBridgeUtilityFreeRootBridges (
365 IN PCI_ROOT_BRIDGE
*Bridges
,
369 if (Bridges
== NULL
&& Count
== 0) {
372 ASSERT (Bridges
!= NULL
&& Count
> 0);
376 PciHostBridgeUtilityUninitRootBridge (&Bridges
[Count
]);
384 Utility function to inform the platform that the resource conflict happens.
386 @param[in] Configuration Pointer to PCI I/O and PCI memory resource
387 descriptors. The Configuration contains the
388 resources for all the root bridges. The resource
389 for each root bridge is terminated with END
390 descriptor and an additional END is appended
391 indicating the end of the entire resources. The
392 resource descriptor field values follow the
394 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
399 PciHostBridgeUtilityResourceConflict (
400 IN VOID
*Configuration
403 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
404 UINTN RootBridgeIndex
;
405 DEBUG ((DEBUG_ERROR
, "PciHostBridge: Resource conflict happens!\n"));
408 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
;
409 while (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
410 DEBUG ((DEBUG_ERROR
, "RootBridge[%d]:\n", RootBridgeIndex
++));
411 for (; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
412 ASSERT (Descriptor
->ResType
<
413 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
)
415 DEBUG ((DEBUG_ERROR
, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
416 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr
[Descriptor
->ResType
],
417 Descriptor
->AddrLen
, Descriptor
->AddrRangeMax
419 if (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
420 DEBUG ((DEBUG_ERROR
, " Granularity/SpecificFlag = %ld / %02x%s\n",
421 Descriptor
->AddrSpaceGranularity
, Descriptor
->SpecificFlag
,
422 ((Descriptor
->SpecificFlag
&
423 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
424 ) != 0) ? L
" (Prefetchable)" : L
""
429 // Skip the END descriptor for root bridge
431 ASSERT (Descriptor
->Desc
== ACPI_END_TAG_DESCRIPTOR
);
432 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)(
433 (EFI_ACPI_END_TAG_DESCRIPTOR
*)Descriptor
+ 1