2 OVMF's instance of the PCI Host Bridge Library.
4 Copyright (C) 2016, Red Hat, Inc.
5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <IndustryStandard/Pci.h>
13 #include <IndustryStandard/Q35MchIch9.h>
15 #include <Protocol/PciHostBridgeResourceAllocation.h>
16 #include <Protocol/PciRootBridgeIo.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/DevicePathLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/PciHostBridgeLib.h>
23 #include <Library/PciLib.h>
24 #include <Library/QemuFwCfgLib.h>
25 #include "PciHostBridge.h"
30 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
31 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
32 } OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH
;
36 GLOBAL_REMOVE_IF_UNREFERENCED
37 CHAR16
*mPciHostBridgeLibAcpiAddressSpaceTypeStr
[] = {
38 L
"Mem", L
"I/O", L
"Bus"
44 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate
= {
50 (UINT8
) (sizeof(ACPI_HID_DEVICE_PATH
)),
51 (UINT8
) ((sizeof(ACPI_HID_DEVICE_PATH
)) >> 8)
54 EISA_PNP_ID(0x0A03), // HID
60 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
62 END_DEVICE_PATH_LENGTH
,
68 STATIC PCI_ROOT_BRIDGE_APERTURE mNonExistAperture
= { MAX_UINT64
, 0 };
71 Initialize a PCI_ROOT_BRIDGE structure.
73 @param[in] Supports Supported attributes.
75 @param[in] Attributes Initial attributes.
77 @param[in] AllocAttributes Allocation attributes.
79 @param[in] RootBusNumber The bus number to store in RootBus.
81 @param[in] MaxSubBusNumber The inclusive maximum bus number that can be
82 assigned to any subordinate bus found behind any
83 PCI bridge hanging off this root bus.
85 The caller is repsonsible for ensuring that
86 RootBusNumber <= MaxSubBusNumber. If
87 RootBusNumber equals MaxSubBusNumber, then the
88 root bus has no room for subordinate buses.
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 by the
101 caller) that should be filled in by this
104 @retval EFI_SUCCESS Initialization successful. A device path
105 consisting of an ACPI device path node, with
106 UID = RootBusNumber, has been allocated and
109 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
114 IN UINT64 Attributes
,
115 IN UINT64 AllocAttributes
,
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
= FALSE
;
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
= (PcdGet16 (PcdOvmfHostBridgePciDevId
) !=
150 INTEL_Q35_MCH_DEVICE_ID
);
152 DevicePath
= AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate
,
153 &mRootBridgeDevicePathTemplate
);
154 if (DevicePath
== NULL
) {
155 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
156 return EFI_OUT_OF_RESOURCES
;
158 DevicePath
->AcpiDevicePath
.UID
= RootBusNumber
;
159 RootBus
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
162 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",
163 __FUNCTION__
, RootBusNumber
, MaxSubBusNumber
- RootBusNumber
));
169 Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge().
171 param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and
172 initialized with InitRootBridge(), that should be
173 uninitialized. This function doesn't free RootBus.
178 IN PCI_ROOT_BRIDGE
*RootBus
181 FreePool (RootBus
->DevicePath
);
186 Return all the root bridge instances in an array.
188 @param Count Return the count of root bridge instances.
190 @return All the root bridge instances in an array.
191 The array should be passed into PciHostBridgeFreeRootBridges()
196 PciHostBridgeGetRootBridges (
201 FIRMWARE_CONFIG_ITEM FwCfgItem
;
203 UINT64 ExtraRootBridges
;
204 PCI_ROOT_BRIDGE
*Bridges
;
206 UINTN LastRootBridgeNumber
;
207 UINTN RootBridgeNumber
;
209 UINT64 AllocationAttributes
;
210 PCI_ROOT_BRIDGE_APERTURE Io
;
211 PCI_ROOT_BRIDGE_APERTURE Mem
;
212 PCI_ROOT_BRIDGE_APERTURE MemAbove4G
;
214 if (PcdGetBool (PcdPciDisableBusEnumeration
)) {
215 return ScanForRootBridges (Count
);
218 ZeroMem (&Io
, sizeof (Io
));
219 ZeroMem (&Mem
, sizeof (Mem
));
220 ZeroMem (&MemAbove4G
, sizeof (MemAbove4G
));
222 Attributes
= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO
|
223 EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO
|
224 EFI_PCI_ATTRIBUTE_ISA_IO_16
|
225 EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO
|
226 EFI_PCI_ATTRIBUTE_VGA_MEMORY
|
227 EFI_PCI_ATTRIBUTE_VGA_IO_16
|
228 EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16
;
230 AllocationAttributes
= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM
;
231 if (PcdGet64 (PcdPciMmio64Size
) > 0) {
232 AllocationAttributes
|= EFI_PCI_HOST_BRIDGE_MEM64_DECODE
;
233 MemAbove4G
.Base
= PcdGet64 (PcdPciMmio64Base
);
234 MemAbove4G
.Limit
= PcdGet64 (PcdPciMmio64Base
) +
235 PcdGet64 (PcdPciMmio64Size
) - 1;
237 CopyMem (&MemAbove4G
, &mNonExistAperture
, sizeof (mNonExistAperture
));
240 Io
.Base
= PcdGet64 (PcdPciIoBase
);
241 Io
.Limit
= PcdGet64 (PcdPciIoBase
) + (PcdGet64 (PcdPciIoSize
) - 1);
242 Mem
.Base
= PcdGet64 (PcdPciMmio32Base
);
243 Mem
.Limit
= PcdGet64 (PcdPciMmio32Base
) + (PcdGet64 (PcdPciMmio32Size
) - 1);
248 // QEMU provides the number of extra root buses, shortening the exhaustive
249 // search below. If there is no hint, the feature is missing.
251 Status
= QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem
, &FwCfgSize
);
252 if (EFI_ERROR (Status
) || FwCfgSize
!= sizeof ExtraRootBridges
) {
253 ExtraRootBridges
= 0;
255 QemuFwCfgSelectItem (FwCfgItem
);
256 QemuFwCfgReadBytes (FwCfgSize
, &ExtraRootBridges
);
258 if (ExtraRootBridges
> PCI_MAX_BUS
) {
259 DEBUG ((DEBUG_ERROR
, "%a: invalid count of extra root buses (%Lu) "
260 "reported by QEMU\n", __FUNCTION__
, ExtraRootBridges
));
263 DEBUG ((DEBUG_INFO
, "%a: %Lu extra root buses reported by QEMU\n",
264 __FUNCTION__
, ExtraRootBridges
));
268 // Allocate the "main" root bridge, and any extra root bridges.
270 Bridges
= AllocatePool ((1 + (UINTN
)ExtraRootBridges
) * sizeof *Bridges
);
271 if (Bridges
== NULL
) {
272 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, EFI_OUT_OF_RESOURCES
));
278 // The "main" root bus is always there.
280 LastRootBridgeNumber
= 0;
283 // Scan all other root buses. If function 0 of any device on a bus returns a
284 // VendorId register value different from all-bits-one, then that bus is
287 for (RootBridgeNumber
= 1;
288 RootBridgeNumber
<= PCI_MAX_BUS
&& Initialized
< ExtraRootBridges
;
289 ++RootBridgeNumber
) {
292 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; ++Device
) {
293 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber
, Device
, 0,
294 PCI_VENDOR_ID_OFFSET
)) != MAX_UINT16
) {
298 if (Device
<= PCI_MAX_DEVICE
) {
300 // Found the next root bus. We can now install the *previous* one,
301 // because now we know how big a bus number range *that* one has, for any
302 // subordinate buses that might exist behind PCI bridges hanging off it.
304 Status
= InitRootBridge (
307 AllocationAttributes
,
308 (UINT8
) LastRootBridgeNumber
,
309 (UINT8
) (RootBridgeNumber
- 1),
315 &Bridges
[Initialized
]
317 if (EFI_ERROR (Status
)) {
321 LastRootBridgeNumber
= RootBridgeNumber
;
326 // Install the last root bus (which might be the only, ie. main, root bus, if
327 // we've found no extra root buses).
329 Status
= InitRootBridge (
332 AllocationAttributes
,
333 (UINT8
) LastRootBridgeNumber
,
340 &Bridges
[Initialized
]
342 if (EFI_ERROR (Status
)) {
347 *Count
= Initialized
;
351 while (Initialized
> 0) {
353 UninitRootBridge (&Bridges
[Initialized
]);
362 Free the root bridge instances array returned from
363 PciHostBridgeGetRootBridges().
365 @param The root bridge instances array.
366 @param The count of the array.
370 PciHostBridgeFreeRootBridges (
371 PCI_ROOT_BRIDGE
*Bridges
,
375 if (Bridges
== NULL
&& Count
== 0) {
378 ASSERT (Bridges
!= NULL
&& Count
> 0);
382 UninitRootBridge (&Bridges
[Count
]);
390 Inform the platform that the resource conflict happens.
392 @param HostBridgeHandle Handle of the Host Bridge.
393 @param Configuration Pointer to PCI I/O and PCI memory resource
394 descriptors. The Configuration contains the resources
395 for all the root bridges. The resource for each root
396 bridge is terminated with END descriptor and an
397 additional END is appended indicating the end of the
398 entire resources. The resource descriptor field
399 values follow the description in
400 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
405 PciHostBridgeResourceConflict (
406 EFI_HANDLE HostBridgeHandle
,
410 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
411 UINTN RootBridgeIndex
;
412 DEBUG ((DEBUG_ERROR
, "PciHostBridge: Resource conflict happens!\n"));
415 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
;
416 while (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
417 DEBUG ((DEBUG_ERROR
, "RootBridge[%d]:\n", RootBridgeIndex
++));
418 for (; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
419 ASSERT (Descriptor
->ResType
<
420 ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr
)
422 DEBUG ((DEBUG_ERROR
, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
423 mPciHostBridgeLibAcpiAddressSpaceTypeStr
[Descriptor
->ResType
],
424 Descriptor
->AddrLen
, Descriptor
->AddrRangeMax
426 if (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
427 DEBUG ((DEBUG_ERROR
, " Granularity/SpecificFlag = %ld / %02x%s\n",
428 Descriptor
->AddrSpaceGranularity
, Descriptor
->SpecificFlag
,
429 ((Descriptor
->SpecificFlag
&
430 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
431 ) != 0) ? L
" (Prefetchable)" : L
""
436 // Skip the END descriptor for root bridge
438 ASSERT (Descriptor
->Desc
== ACPI_END_TAG_DESCRIPTOR
);
439 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)(
440 (EFI_ACPI_END_TAG_DESCRIPTOR
*)Descriptor
+ 1