2 Scan the entire PCI bus for root bridges to support coreboot UEFI payload.
4 Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <IndustryStandard/Pci.h>
12 #include <Protocol/PciHostBridgeResourceAllocation.h>
13 #include <Protocol/PciRootBridgeIo.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/PciHostBridgeLib.h>
18 #include <Library/PciLib.h>
19 #include "PciHostBridge.h"
22 Adjust the collected PCI resource.
24 @param[in] Io IO aperture.
26 @param[in] Mem MMIO aperture.
28 @param[in] MemAbove4G MMIO aperture above 4G.
30 @param[in] PMem Prefetchable MMIO aperture.
32 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
35 AdjustRootBridgeResource (
36 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
37 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
38 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
39 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
40 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
46 // For now try to downgrade everything into MEM32 since
47 // - coreboot does not assign resource above 4GB
48 // - coreboot might allocate interleaved MEM32 and PMEM32 resource
51 if (PMem
->Base
< Mem
->Base
) {
52 Mem
->Base
= PMem
->Base
;
55 if (PMem
->Limit
> Mem
->Limit
) {
56 Mem
->Limit
= PMem
->Limit
;
59 PMem
->Base
= MAX_UINT64
;
62 if (MemAbove4G
->Base
< 0x100000000ULL
) {
63 if (MemAbove4G
->Base
< Mem
->Base
) {
64 Mem
->Base
= MemAbove4G
->Base
;
66 if (MemAbove4G
->Limit
> Mem
->Limit
) {
67 Mem
->Limit
= MemAbove4G
->Limit
;
69 MemAbove4G
->Base
= MAX_UINT64
;
70 MemAbove4G
->Limit
= 0;
73 if (PMemAbove4G
->Base
< 0x100000000ULL
) {
74 if (PMemAbove4G
->Base
< Mem
->Base
) {
75 Mem
->Base
= PMemAbove4G
->Base
;
77 if (PMemAbove4G
->Limit
> Mem
->Limit
) {
78 Mem
->Limit
= PMemAbove4G
->Limit
;
80 PMemAbove4G
->Base
= MAX_UINT64
;
81 PMemAbove4G
->Limit
= 0;
85 // Align IO resource at 4K boundary
88 Io
->Limit
= ((Io
->Limit
+ Mask
) & ~Mask
) - 1;
89 if (Io
->Base
!= MAX_UINT64
) {
94 // Align MEM resource at 1MB boundary
97 Mem
->Limit
= ((Mem
->Limit
+ Mask
) & ~Mask
) - 1;
98 if (Mem
->Base
!= MAX_UINT64
) {
104 Probe a bar is existed or not.
106 @param[in] Address PCI address for the BAR.
107 @param[out] OriginalValue The original bar value returned.
108 @param[out] Value The probed bar value returned.
112 PcatPciRootBridgeBarExisted (
114 OUT UINT32
*OriginalValue
,
120 PciAddress
= (UINTN
)Address
;
123 // Preserve the original value
125 *OriginalValue
= PciRead32 (PciAddress
);
128 // Disable timer interrupt while the BAR is probed
130 DisableInterrupts ();
132 PciWrite32 (PciAddress
, 0xFFFFFFFF);
133 *Value
= PciRead32 (PciAddress
);
134 PciWrite32 (PciAddress
, *OriginalValue
);
143 Parse PCI bar and collect the assigned PCI resource information.
145 @param[in] Command Supported attributes.
147 @param[in] Bus PCI bus number.
149 @param[in] Device PCI device number.
151 @param[in] Function PCI function number.
153 @param[in] BarOffsetBase PCI bar start offset.
155 @param[in] BarOffsetEnd PCI bar end offset.
157 @param[in] Io IO aperture.
159 @param[in] Mem MMIO aperture.
161 @param[in] MemAbove4G MMIO aperture above 4G.
163 @param[in] PMem Prefetchable MMIO aperture.
165 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
169 PcatPciRootBridgeParseBars (
174 IN UINTN BarOffsetBase
,
175 IN UINTN BarOffsetEnd
,
176 IN PCI_ROOT_BRIDGE_APERTURE
*Io
,
177 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
178 IN PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
179 IN PCI_ROOT_BRIDGE_APERTURE
*PMem
,
180 IN PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
184 UINT32 OriginalValue
;
186 UINT32 OriginalUpperValue
;
194 PCI_ROOT_BRIDGE_APERTURE
*MemAperture
;
196 for (Offset
= BarOffsetBase
; Offset
< BarOffsetEnd
; Offset
+= sizeof (UINT32
)) {
197 PcatPciRootBridgeBarExisted (
198 PCI_LIB_ADDRESS (Bus
, Device
, Function
, Offset
),
199 &OriginalValue
, &Value
204 if ((Value
& BIT0
) == BIT0
) {
208 if ((Command
& EFI_PCI_COMMAND_IO_SPACE
) != 0) {
210 Base
= OriginalValue
& Mask
;
211 Length
= ((~(Value
& Mask
)) & Mask
) + 0x04;
212 if (!(Value
& 0xFFFF0000)) {
213 Length
&= 0x0000FFFF;
215 Limit
= Base
+ Length
- 1;
217 if ((Base
> 0) && (Base
< Limit
)) {
218 if (Io
->Base
> Base
) {
221 if (Io
->Limit
< Limit
) {
230 if ((Command
& EFI_PCI_COMMAND_MEMORY_SPACE
) != 0) {
233 Base
= OriginalValue
& Mask
;
234 Length
= Value
& Mask
;
236 if ((Value
& (BIT1
| BIT2
)) == 0) {
240 Length
= ((~Length
) + 1) & 0xffffffff;
242 if ((Value
& BIT3
) == BIT3
) {
252 PcatPciRootBridgeBarExisted (
253 PCI_LIB_ADDRESS (Bus
, Device
, Function
, Offset
),
258 Base
= Base
| LShiftU64 ((UINT64
) OriginalUpperValue
, 32);
259 Length
= Length
| LShiftU64 ((UINT64
) UpperValue
, 32);
261 LowBit
= LowBitSet64 (Length
);
262 Length
= LShiftU64 (1ULL, LowBit
);
265 if ((Value
& BIT3
) == BIT3
) {
266 MemAperture
= PMemAbove4G
;
268 MemAperture
= MemAbove4G
;
272 Limit
= Base
+ Length
- 1;
273 if ((Base
> 0) && (Base
< Limit
)) {
274 if (MemAperture
->Base
> Base
) {
275 MemAperture
->Base
= Base
;
277 if (MemAperture
->Limit
< Limit
) {
278 MemAperture
->Limit
= Limit
;
287 Scan for all root bridges in platform.
289 @param[out] NumberOfRootBridges Number of root bridges detected
291 @retval Pointer to the allocated PCI_ROOT_BRIDGE structure array.
295 OUT UINTN
*NumberOfRootBridges
302 UINTN NumberOfDevices
;
309 PCI_ROOT_BRIDGE_APERTURE Io
;
310 PCI_ROOT_BRIDGE_APERTURE Mem
;
311 PCI_ROOT_BRIDGE_APERTURE MemAbove4G
;
312 PCI_ROOT_BRIDGE_APERTURE PMem
;
313 PCI_ROOT_BRIDGE_APERTURE PMemAbove4G
;
314 PCI_ROOT_BRIDGE_APERTURE
*MemAperture
;
315 PCI_ROOT_BRIDGE
*RootBridges
;
319 *NumberOfRootBridges
= 0;
323 // After scanning all the PCI devices on the PCI root bridge's primary bus,
324 // update the Primary Bus Number for the next PCI root bridge to be this PCI
325 // root bridge's subordinate bus number + 1.
327 for (PrimaryBus
= 0; PrimaryBus
<= PCI_MAX_BUS
; PrimaryBus
= SubBus
+ 1) {
331 ZeroMem (&Io
, sizeof (Io
));
332 ZeroMem (&Mem
, sizeof (Mem
));
333 ZeroMem (&MemAbove4G
, sizeof (MemAbove4G
));
334 ZeroMem (&PMem
, sizeof (PMem
));
335 ZeroMem (&PMemAbove4G
, sizeof (PMemAbove4G
));
336 Io
.Base
= Mem
.Base
= MemAbove4G
.Base
= PMem
.Base
= PMemAbove4G
.Base
= MAX_UINT64
;
338 // Scan all the PCI devices on the primary bus of the PCI root bridge
340 for (Device
= 0, NumberOfDevices
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
342 for (Function
= 0; Function
<= PCI_MAX_FUNC
; Function
++) {
345 // Compute the PCI configuration address of the PCI device to probe
347 Address
= PCI_LIB_ADDRESS (PrimaryBus
, Device
, Function
, 0);
350 // Read the Vendor ID from the PCI Configuration Header
352 if (PciRead16 (Address
) == MAX_UINT16
) {
355 // If the PCI Configuration Read fails, or a PCI device does not
356 // exist, then skip this entire PCI device
361 // If PCI function != 0, VendorId == 0xFFFF, we continue to search
369 // Read the entire PCI Configuration Header
371 PciReadBuffer (Address
, sizeof (Pci
), &Pci
);
374 // Increment the number of PCI device found on the primary bus of the
380 // Look for devices with the VGA Palette Snoop enabled in the COMMAND
381 // register of the PCI Config Header
383 if ((Pci
.Hdr
.Command
& EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
) != 0) {
384 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO
;
385 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16
;
393 if (IS_PCI_BRIDGE (&Pci
)) {
395 // Get the Bus range that the PPB is decoding
397 if (Pci
.Bridge
.SubordinateBus
> SubBus
) {
399 // If the subordinate bus number of the PCI-PCI bridge is greater
400 // than the PCI root bridge's current subordinate bus number,
401 // then update the PCI root bridge's subordinate bus number
403 SubBus
= Pci
.Bridge
.SubordinateBus
;
407 // Get the I/O range that the PPB is decoding
409 Value
= Pci
.Bridge
.IoBase
& 0x0f;
410 Base
= ((UINT32
) Pci
.Bridge
.IoBase
& 0xf0) << 8;
411 Limit
= (((UINT32
) Pci
.Bridge
.IoLimit
& 0xf0) << 8) | 0x0fff;
413 Base
|= ((UINT32
) Pci
.Bridge
.IoBaseUpper16
<< 16);
414 Limit
|= ((UINT32
) Pci
.Bridge
.IoLimitUpper16
<< 16);
416 if ((Base
> 0) && (Base
< Limit
)) {
417 if (Io
.Base
> Base
) {
420 if (Io
.Limit
< Limit
) {
426 // Get the Memory range that the PPB is decoding
428 Base
= ((UINT32
) Pci
.Bridge
.MemoryBase
& 0xfff0) << 16;
429 Limit
= (((UINT32
) Pci
.Bridge
.MemoryLimit
& 0xfff0) << 16) | 0xfffff;
430 if ((Base
> 0) && (Base
< Limit
)) {
431 if (Mem
.Base
> Base
) {
434 if (Mem
.Limit
< Limit
) {
440 // Get the Prefetchable Memory range that the PPB is decoding
442 Value
= Pci
.Bridge
.PrefetchableMemoryBase
& 0x0f;
443 Base
= ((UINT32
) Pci
.Bridge
.PrefetchableMemoryBase
& 0xfff0) << 16;
444 Limit
= (((UINT32
) Pci
.Bridge
.PrefetchableMemoryLimit
& 0xfff0)
448 Base
|= LShiftU64 (Pci
.Bridge
.PrefetchableBaseUpper32
, 32);
449 Limit
|= LShiftU64 (Pci
.Bridge
.PrefetchableLimitUpper32
, 32);
450 MemAperture
= &PMemAbove4G
;
452 if ((Base
> 0) && (Base
< Limit
)) {
453 if (MemAperture
->Base
> Base
) {
454 MemAperture
->Base
= Base
;
456 if (MemAperture
->Limit
< Limit
) {
457 MemAperture
->Limit
= Limit
;
462 // Look at the PPB Configuration for legacy decoding attributes
464 if ((Pci
.Bridge
.BridgeControl
& EFI_PCI_BRIDGE_CONTROL_ISA
)
465 == EFI_PCI_BRIDGE_CONTROL_ISA
) {
466 Attributes
|= EFI_PCI_ATTRIBUTE_ISA_IO
;
467 Attributes
|= EFI_PCI_ATTRIBUTE_ISA_IO_16
;
468 Attributes
|= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO
;
470 if ((Pci
.Bridge
.BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA
)
471 == EFI_PCI_BRIDGE_CONTROL_VGA
) {
472 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO
;
473 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_MEMORY
;
474 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_IO
;
475 if ((Pci
.Bridge
.BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA_16
)
477 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16
;
478 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_IO_16
;
482 BarOffsetEnd
= OFFSET_OF (PCI_TYPE01
, Bridge
.Bar
[2]);
485 // Parse the BARs of the PCI device to get what I/O Ranges, Memory
486 // Ranges, and Prefetchable Memory Ranges the device is decoding
488 if ((Pci
.Hdr
.HeaderType
& HEADER_LAYOUT_CODE
) == HEADER_TYPE_DEVICE
) {
489 BarOffsetEnd
= OFFSET_OF (PCI_TYPE00
, Device
.Bar
[6]);
493 PcatPciRootBridgeParseBars (
498 OFFSET_OF (PCI_TYPE00
, Device
.Bar
),
506 // See if the PCI device is an IDE controller
508 if (IS_CLASS2 (&Pci
, PCI_CLASS_MASS_STORAGE
,
509 PCI_CLASS_MASS_STORAGE_IDE
)) {
510 if (Pci
.Hdr
.ClassCode
[0] & 0x80) {
511 Attributes
|= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO
;
512 Attributes
|= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO
;
514 if (Pci
.Hdr
.ClassCode
[0] & 0x01) {
515 Attributes
|= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO
;
517 if (Pci
.Hdr
.ClassCode
[0] & 0x04) {
518 Attributes
|= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO
;
523 // See if the PCI device is a legacy VGA controller or
524 // a standard VGA controller
526 if (IS_CLASS2 (&Pci
, PCI_CLASS_OLD
, PCI_CLASS_OLD_VGA
) ||
527 IS_CLASS2 (&Pci
, PCI_CLASS_DISPLAY
, PCI_CLASS_DISPLAY_VGA
)
529 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO
;
530 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16
;
531 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_MEMORY
;
532 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_IO
;
533 Attributes
|= EFI_PCI_ATTRIBUTE_VGA_IO_16
;
537 // See if the PCI Device is a PCI - ISA or PCI - EISA
538 // or ISA_POSITIVE_DECODE Bridge device
540 if (Pci
.Hdr
.ClassCode
[2] == PCI_CLASS_BRIDGE
) {
541 if (Pci
.Hdr
.ClassCode
[1] == PCI_CLASS_BRIDGE_ISA
||
542 Pci
.Hdr
.ClassCode
[1] == PCI_CLASS_BRIDGE_EISA
||
543 Pci
.Hdr
.ClassCode
[1] == PCI_CLASS_BRIDGE_ISA_PDECODE
) {
544 Attributes
|= EFI_PCI_ATTRIBUTE_ISA_IO
;
545 Attributes
|= EFI_PCI_ATTRIBUTE_ISA_IO_16
;
546 Attributes
|= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO
;
551 // If this device is not a multi function device, then skip the rest
552 // of this PCI device
554 if (Function
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
561 // If at least one PCI device was found on the primary bus of this PCI
562 // root bridge, then the PCI root bridge exists.
564 if (NumberOfDevices
> 0) {
565 RootBridges
= ReallocatePool (
566 (*NumberOfRootBridges
) * sizeof (PCI_ROOT_BRIDGE
),
567 (*NumberOfRootBridges
+ 1) * sizeof (PCI_ROOT_BRIDGE
),
570 ASSERT (RootBridges
!= NULL
);
572 AdjustRootBridgeResource (&Io
, &Mem
, &MemAbove4G
, &PMem
, &PMemAbove4G
);
575 Attributes
, Attributes
, 0,
576 (UINT8
) PrimaryBus
, (UINT8
) SubBus
,
577 &Io
, &Mem
, &MemAbove4G
, &PMem
, &PMemAbove4G
,
578 &RootBridges
[*NumberOfRootBridges
]
580 RootBridges
[*NumberOfRootBridges
].ResourceAssigned
= TRUE
;
582 // Increment the index for the next PCI Root Bridge
584 (*NumberOfRootBridges
)++;
592 Scan for all root bridges from Universal Payload PciRootBridgeInfoHob
594 @param[in] PciRootBridgeInfo Pointer of Universal Payload PCI Root Bridge Info Hob
595 @param[out] NumberOfRootBridges Number of root bridges detected
597 @retval Pointer to the allocated PCI_ROOT_BRIDGE structure array.
601 RetrieveRootBridgeInfoFromHob (
602 IN UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES
*PciRootBridgeInfo
,
603 OUT UINTN
*NumberOfRootBridges
606 PCI_ROOT_BRIDGE
*PciRootBridges
;
610 ASSERT (PciRootBridgeInfo
!= NULL
);
611 ASSERT (NumberOfRootBridges
!= NULL
);
612 if (PciRootBridgeInfo
== NULL
) {
615 if (PciRootBridgeInfo
->Count
== 0) {
618 Size
= PciRootBridgeInfo
->Count
* sizeof (PCI_ROOT_BRIDGE
);
619 PciRootBridges
= (PCI_ROOT_BRIDGE
*) AllocatePool (Size
);
620 ASSERT (PciRootBridges
!= NULL
);
621 if (PciRootBridges
== NULL
) {
624 ZeroMem (PciRootBridges
, PciRootBridgeInfo
->Count
* sizeof (PCI_ROOT_BRIDGE
));
627 // Create all root bridges with PciRootBridgeInfoHob
629 for (Index
= 0; Index
< PciRootBridgeInfo
->Count
; Index
++) {
630 PciRootBridges
[Index
].Segment
= PciRootBridgeInfo
->RootBridge
[Index
].Segment
;
631 PciRootBridges
[Index
].Supports
= PciRootBridgeInfo
->RootBridge
[Index
].Supports
;
632 PciRootBridges
[Index
].Attributes
= PciRootBridgeInfo
->RootBridge
[Index
].Attributes
;
633 PciRootBridges
[Index
].DmaAbove4G
= PciRootBridgeInfo
->RootBridge
[Index
].DmaAbove4G
;
634 PciRootBridges
[Index
].NoExtendedConfigSpace
= PciRootBridgeInfo
->RootBridge
[Index
].NoExtendedConfigSpace
;
635 PciRootBridges
[Index
].ResourceAssigned
= PciRootBridgeInfo
->ResourceAssigned
;
636 PciRootBridges
[Index
].AllocationAttributes
= PciRootBridgeInfo
->RootBridge
[Index
].AllocationAttributes
;
637 PciRootBridges
[Index
].DevicePath
= CreateRootBridgeDevicePath(PciRootBridgeInfo
->RootBridge
[Index
].HID
, PciRootBridgeInfo
->RootBridge
[Index
].UID
);
638 CopyMem(&PciRootBridges
[Index
].Bus
, &PciRootBridgeInfo
->RootBridge
[Index
].Bus
, sizeof(UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE_APERTURE
));
639 CopyMem(&PciRootBridges
[Index
].Io
, &PciRootBridgeInfo
->RootBridge
[Index
].Io
, sizeof(UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE_APERTURE
));
640 CopyMem(&PciRootBridges
[Index
].Mem
, &PciRootBridgeInfo
->RootBridge
[Index
].Mem
, sizeof(UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE_APERTURE
));
641 CopyMem(&PciRootBridges
[Index
].MemAbove4G
, &PciRootBridgeInfo
->RootBridge
[Index
].MemAbove4G
, sizeof(UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE_APERTURE
));
642 CopyMem(&PciRootBridges
[Index
].PMem
, &PciRootBridgeInfo
->RootBridge
[Index
].PMem
, sizeof(UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE_APERTURE
));
643 CopyMem(&PciRootBridges
[Index
].PMemAbove4G
, &PciRootBridgeInfo
->RootBridge
[Index
].PMemAbove4G
, sizeof(UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE_APERTURE
));
646 *NumberOfRootBridges
= PciRootBridgeInfo
->Count
;
649 // Now, this library only supports RootBridge that ResourceAssigned is True
651 if (PciRootBridgeInfo
->ResourceAssigned
) {
652 PcdSetBoolS (PcdPciDisableBusEnumeration
, TRUE
);
654 DEBUG ((DEBUG_ERROR
, "There is root bridge whose ResourceAssigned is FALSE\n"));
655 PcdSetBoolS (PcdPciDisableBusEnumeration
, FALSE
);
659 return PciRootBridges
;