2 PCI emumeration support functions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
13 extern CHAR16
*mBarTypeStr
[];
14 extern EDKII_DEVICE_SECURITY_PROTOCOL
*mDeviceSecurityProtocol
;
16 #define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL
17 #define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
18 #define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
19 #define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
22 This routine is used to check whether the pci device is present.
24 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
25 @param Pci Output buffer for PCI device configuration space.
26 @param Bus PCI bus NO.
27 @param Device PCI device NO.
28 @param Func PCI Func NO.
30 @retval EFI_NOT_FOUND PCI device not present.
31 @retval EFI_SUCCESS PCI device is found.
36 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
47 // Create PCI address map in terms of Bus, Device and Func
49 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Func
, 0);
52 // Read the Vendor ID register
54 Status
= PciRootBridgeIo
->Pci
.Read (
62 if (!EFI_ERROR (Status
) && ((Pci
->Hdr
).VendorId
!= 0xffff)) {
64 // Read the entire config header for the device
66 Status
= PciRootBridgeIo
->Pci
.Read (
70 sizeof (PCI_TYPE00
) / sizeof (UINT32
),
81 Collect all the resource information under this root bridge.
83 A database that records all the information about pci device subject to this
84 root bridge will then be created.
86 @param Bridge Parent bridge instance.
87 @param StartBusNumber Bus number of beginning.
89 @retval EFI_SUCCESS PCI device is found.
90 @retval other Some error occurred when reading PCI bridge information.
94 PciPciDeviceInfoCollector (
95 IN PCI_IO_DEVICE
*Bridge
,
96 IN UINT8 StartBusNumber
104 PCI_IO_DEVICE
*PciIoDevice
;
105 EFI_PCI_IO_PROTOCOL
*PciIo
;
107 Status
= EFI_SUCCESS
;
110 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
111 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
113 // Check to see whether PCI device is present
115 Status
= PciDevicePresent (
116 Bridge
->PciRootBridgeIo
,
118 (UINT8
)StartBusNumber
,
123 if (EFI_ERROR (Status
) && (Func
== 0)) {
125 // go to next device if there is no Function 0
130 if (!EFI_ERROR (Status
)) {
132 // Call back to host bridge function
134 PreprocessController (Bridge
, (UINT8
)StartBusNumber
, Device
, Func
, EfiPciBeforeResourceCollection
);
137 // Collect all the information about the PCI device discovered
139 Status
= PciSearchDevice (
142 (UINT8
)StartBusNumber
,
149 // Recursively scan PCI busses on the other side of PCI-PCI bridges
152 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
) || IS_CARDBUS_BRIDGE (&Pci
))) {
154 // If it is PPB, we need to get the secondary bus to continue the enumeration
156 PciIo
= &(PciIoDevice
->PciIo
);
158 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
, 1, &SecBus
);
160 if (EFI_ERROR (Status
)) {
165 // Ensure secondary bus number is greater than the primary bus number to avoid
166 // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE
168 if (SecBus
<= StartBusNumber
) {
173 // Get resource padding for PPB
175 GetResourcePaddingPpb (PciIoDevice
);
178 // Deep enumerate the next level bus
180 Status
= PciPciDeviceInfoCollector (
186 if ((Func
== 0) && !IS_PCI_MULTI_FUNC (&Pci
)) {
188 // Skip sub functions, this is not a multi function device
200 Search required device and create PCI device instance.
202 @param Bridge Parent bridge instance.
203 @param Pci Input PCI device information block.
204 @param Bus PCI bus NO.
205 @param Device PCI device NO.
206 @param Func PCI func NO.
207 @param PciDevice Output of searched PCI device instance.
209 @retval EFI_SUCCESS Successfully created PCI device instance.
210 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
215 IN PCI_IO_DEVICE
*Bridge
,
220 OUT PCI_IO_DEVICE
**PciDevice
223 PCI_IO_DEVICE
*PciIoDevice
;
224 BOOLEAN IgnoreOptionRom
;
227 IgnoreOptionRom
= FALSE
;
231 "PciBus: Discovered %s @ [%02x|%02x|%02x] [VID = 0x%x, DID = 0x%0x]\n",
232 IS_PCI_BRIDGE (Pci
) ? L
"PPB" :
233 IS_CARDBUS_BRIDGE (Pci
) ? L
"P2C" :
242 if (!IS_PCI_BRIDGE (Pci
)) {
243 if (IS_CARDBUS_BRIDGE (Pci
)) {
244 PciIoDevice
= GatherP2CInfo (
251 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
252 InitializeP2C (PciIoDevice
);
256 // Create private data for Pci Device
258 PciIoDevice
= GatherDeviceInfo (
268 // Create private data for PPB
270 PciIoDevice
= GatherPpbInfo (
279 // Special initialization for PPB including making the PPB quiet
281 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
282 InitializePpb (PciIoDevice
);
286 if (PciIoDevice
== NULL
) {
287 return EFI_OUT_OF_RESOURCES
;
291 // Update the bar information for this PCI device so as to support some specific device
293 UpdatePciInfo (PciIoDevice
, &IgnoreOptionRom
);
295 if (PciIoDevice
->DevicePath
== NULL
) {
296 return EFI_OUT_OF_RESOURCES
;
300 // Detect this function has option rom
302 if (gFullEnumeration
) {
303 if (!IS_CARDBUS_BRIDGE (Pci
) && !IgnoreOptionRom
) {
304 GetOpRomInfo (PciIoDevice
);
307 ResetPowerManagementFeature (PciIoDevice
);
311 // Insert it into a global tree for future reference
313 InsertPciDevice (Bridge
, PciIoDevice
);
316 // Determine PCI device attributes
319 if (PciDevice
!= NULL
) {
320 *PciDevice
= PciIoDevice
;
327 Dump the PPB padding resource information.
329 @param PciIoDevice PCI IO instance.
330 @param ResourceType The desired resource type to dump.
331 PciBarTypeUnknown means to dump all types of resources.
334 DumpPpbPaddingResource (
335 IN PCI_IO_DEVICE
*PciIoDevice
,
336 IN PCI_BAR_TYPE ResourceType
339 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
342 if (PciIoDevice
->ResourcePaddingDescriptors
== NULL
) {
346 if ((ResourceType
== PciBarTypeIo16
) || (ResourceType
== PciBarTypeIo32
)) {
347 ResourceType
= PciBarTypeIo
;
350 for (Descriptor
= PciIoDevice
->ResourcePaddingDescriptors
; Descriptor
->Desc
!= ACPI_END_TAG_DESCRIPTOR
; Descriptor
++) {
351 Type
= PciBarTypeUnknown
;
352 if ((Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) && (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_IO
)) {
354 } else if ((Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) && (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
)) {
355 if (Descriptor
->AddrSpaceGranularity
== 32) {
359 if (Descriptor
->SpecificFlag
== EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) {
360 Type
= PciBarTypePMem32
;
366 if (Descriptor
->SpecificFlag
== 0) {
367 Type
= PciBarTypeMem32
;
371 if (Descriptor
->AddrSpaceGranularity
== 64) {
375 if (Descriptor
->SpecificFlag
== EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) {
376 Type
= PciBarTypePMem64
;
382 if (Descriptor
->SpecificFlag
== 0) {
383 Type
= PciBarTypeMem64
;
388 if ((Type
!= PciBarTypeUnknown
) && ((ResourceType
== PciBarTypeUnknown
) || (ResourceType
== Type
))) {
391 " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
393 Descriptor
->AddrRangeMax
,
401 Dump the PCI BAR information.
403 @param PciIoDevice PCI IO instance.
407 IN PCI_IO_DEVICE
*PciIoDevice
412 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
413 if (PciIoDevice
->PciBar
[Index
].BarType
== PciBarTypeUnknown
) {
419 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
421 mBarTypeStr
[MIN (PciIoDevice
->PciBar
[Index
].BarType
, PciBarTypeMaxType
)],
422 PciIoDevice
->PciBar
[Index
].Alignment
,
423 PciIoDevice
->PciBar
[Index
].Length
,
424 PciIoDevice
->PciBar
[Index
].Offset
428 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
429 if ((PciIoDevice
->VfPciBar
[Index
].BarType
== PciBarTypeUnknown
) && (PciIoDevice
->VfPciBar
[Index
].Length
== 0)) {
435 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
437 mBarTypeStr
[MIN (PciIoDevice
->VfPciBar
[Index
].BarType
, PciBarTypeMaxType
)],
438 PciIoDevice
->VfPciBar
[Index
].Alignment
,
439 PciIoDevice
->VfPciBar
[Index
].Length
,
440 PciIoDevice
->VfPciBar
[Index
].Offset
444 DEBUG ((DEBUG_INFO
, "\n"));
448 Create PCI device instance for PCI device.
450 @param Bridge Parent bridge instance.
451 @param Pci Input PCI device information block.
452 @param Bus PCI device Bus NO.
453 @param Device PCI device Device NO.
454 @param Func PCI device's func NO.
456 @return Created PCI device instance.
461 IN PCI_IO_DEVICE
*Bridge
,
470 PCI_IO_DEVICE
*PciIoDevice
;
472 PciIoDevice
= CreatePciIoDevice (
480 if (PciIoDevice
== NULL
) {
485 // If it is a full enumeration, disconnect the device in advance
487 if (gFullEnumeration
) {
488 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
492 // Start to parse the bars
494 for (Offset
= 0x10, BarIndex
= 0; Offset
<= 0x24 && BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
495 Offset
= PciParseBar (PciIoDevice
, Offset
, BarIndex
);
499 // Parse the SR-IOV VF bars
501 if (PcdGetBool (PcdSrIovSupport
) && (PciIoDevice
->SrIovCapabilityOffset
!= 0)) {
502 for (Offset
= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0
, BarIndex
= 0;
503 Offset
<= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5
;
506 ASSERT (BarIndex
< PCI_MAX_BAR
);
507 Offset
= PciIovParseVfBar (PciIoDevice
, Offset
, BarIndex
);
512 DumpPciBars (PciIoDevice
);
518 Create PCI device instance for PCI-PCI bridge.
520 @param Bridge Parent bridge instance.
521 @param Pci Input PCI device information block.
522 @param Bus PCI device Bus NO.
523 @param Device PCI device Device NO.
524 @param Func PCI device's func NO.
526 @return Created PCI device instance.
531 IN PCI_IO_DEVICE
*Bridge
,
538 PCI_IO_DEVICE
*PciIoDevice
;
541 EFI_PCI_IO_PROTOCOL
*PciIo
;
543 UINT32 PMemBaseLimit
;
544 UINT16 PrefetchableMemoryBase
;
545 UINT16 PrefetchableMemoryLimit
;
547 PciIoDevice
= CreatePciIoDevice (
555 if (PciIoDevice
== NULL
) {
559 if (gFullEnumeration
) {
560 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
563 // Initialize the bridge control register
565 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED
);
569 // PPB can have two BARs
571 if (PciParseBar (PciIoDevice
, 0x10, PPB_BAR_0
) == 0x14) {
575 PciParseBar (PciIoDevice
, 0x14, PPB_BAR_1
);
578 PciIo
= &PciIoDevice
->PciIo
;
581 // Test whether it support 32 decode or not
583 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
584 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &gAllOne
);
585 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
586 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
589 if ((Value
& 0x01) != 0) {
590 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
592 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO16_DECODE_SUPPORTED
;
597 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
598 // PCI bridge supporting non-standard I/O window alignment less than 4K.
601 PciIoDevice
->BridgeIoAlignment
= 0xFFF;
602 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe
)) {
604 // Check any bits of bit 3-1 of I/O Base Register are writable.
605 // if so, it is assumed non-standard I/O window alignment is supported by this bridge.
606 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.
608 Value
= (UINT8
)(Temp
^ (BIT3
| BIT2
| BIT1
));
609 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
610 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
611 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
612 Value
= (UINT8
)((Value
^ Temp
) & (BIT3
| BIT2
| BIT1
));
615 PciIoDevice
->BridgeIoAlignment
= 0x7FF;
618 PciIoDevice
->BridgeIoAlignment
= 0x3FF;
620 case BIT3
| BIT2
| BIT1
:
621 PciIoDevice
->BridgeIoAlignment
= 0x1FF;
626 Status
= BarExisted (
634 // Test if it supports 64 memory or not
636 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit
638 // 0 - the bridge supports only 32 bit addresses.
639 // 1 - the bridge supports 64-bit addresses.
641 PrefetchableMemoryBase
= (UINT16
)(PMemBaseLimit
& 0xffff);
642 PrefetchableMemoryLimit
= (UINT16
)(PMemBaseLimit
>> 16);
643 if (!EFI_ERROR (Status
) &&
644 ((PrefetchableMemoryBase
& 0x000f) == 0x0001) &&
645 ((PrefetchableMemoryLimit
& 0x000f) == 0x0001))
647 Status
= BarExisted (
654 if (!EFI_ERROR (Status
)) {
655 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
656 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED
;
658 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
663 // Memory 32 code is required for ppb
665 PciIoDevice
->Decodes
|= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
;
667 GetResourcePaddingPpb (PciIoDevice
);
670 DumpPpbPaddingResource (PciIoDevice
, PciBarTypeUnknown
);
671 DumpPciBars (PciIoDevice
);
678 Create PCI device instance for PCI Card bridge device.
680 @param Bridge Parent bridge instance.
681 @param Pci Input PCI device information block.
682 @param Bus PCI device Bus NO.
683 @param Device PCI device Device NO.
684 @param Func PCI device's func NO.
686 @return Created PCI device instance.
691 IN PCI_IO_DEVICE
*Bridge
,
698 PCI_IO_DEVICE
*PciIoDevice
;
700 PciIoDevice
= CreatePciIoDevice (
708 if (PciIoDevice
== NULL
) {
712 if (gFullEnumeration
) {
713 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
716 // Initialize the bridge control register
718 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED
);
722 // P2C only has one bar that is in 0x10
724 PciParseBar (PciIoDevice
, 0x10, P2C_BAR_0
);
727 // Read PciBar information from the bar register
729 GetBackPcCardBar (PciIoDevice
);
730 PciIoDevice
->Decodes
= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
|
731 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
|
732 EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
735 DumpPciBars (PciIoDevice
);
742 Create device path for pci device.
744 @param ParentDevicePath Parent bridge's path.
745 @param PciIoDevice Pci device instance.
747 @return Device path protocol instance for specific pci device.
750 EFI_DEVICE_PATH_PROTOCOL
*
751 CreatePciDevicePath (
752 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
753 IN PCI_IO_DEVICE
*PciIoDevice
756 PCI_DEVICE_PATH PciNode
;
759 // Create PCI device path
761 PciNode
.Header
.Type
= HARDWARE_DEVICE_PATH
;
762 PciNode
.Header
.SubType
= HW_PCI_DP
;
763 SetDevicePathNodeLength (&PciNode
.Header
, sizeof (PciNode
));
765 PciNode
.Device
= PciIoDevice
->DeviceNumber
;
766 PciNode
.Function
= PciIoDevice
->FunctionNumber
;
767 PciIoDevice
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, &PciNode
.Header
);
769 return PciIoDevice
->DevicePath
;
773 Check whether the PCI IOV VF bar is existed or not.
775 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
776 @param Offset The offset.
777 @param BarLengthValue The bar length value returned.
778 @param OriginalBarValue The original bar value returned.
780 @retval EFI_NOT_FOUND The bar doesn't exist.
781 @retval EFI_SUCCESS The bar exist.
786 IN PCI_IO_DEVICE
*PciIoDevice
,
788 OUT UINT32
*BarLengthValue
,
789 OUT UINT32
*OriginalBarValue
792 EFI_PCI_IO_PROTOCOL
*PciIo
;
793 UINT32 OriginalValue
;
798 // Ensure it is called properly
800 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
801 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
802 return EFI_NOT_FOUND
;
805 PciIo
= &PciIoDevice
->PciIo
;
808 // Preserve the original value
811 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
814 // Raise TPL to high level to disable timer interrupt while the BAR is probed
816 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
818 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &gAllOne
);
819 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &Value
);
822 // Write back the original value
824 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
827 // Restore TPL to its original level
829 gBS
->RestoreTPL (OldTpl
);
831 if (BarLengthValue
!= NULL
) {
832 *BarLengthValue
= Value
;
835 if (OriginalBarValue
!= NULL
) {
836 *OriginalBarValue
= OriginalValue
;
840 return EFI_NOT_FOUND
;
847 Check whether the bar is existed or not.
849 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
850 @param Offset The offset.
851 @param BarLengthValue The bar length value returned.
852 @param OriginalBarValue The original bar value returned.
854 @retval EFI_NOT_FOUND The bar doesn't exist.
855 @retval EFI_SUCCESS The bar exist.
860 IN PCI_IO_DEVICE
*PciIoDevice
,
862 OUT UINT32
*BarLengthValue
,
863 OUT UINT32
*OriginalBarValue
866 EFI_PCI_IO_PROTOCOL
*PciIo
;
867 UINT32 OriginalValue
;
871 PciIo
= &PciIoDevice
->PciIo
;
874 // Preserve the original value
876 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &OriginalValue
);
879 // Raise TPL to high level to disable timer interrupt while the BAR is probed
881 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
883 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &gAllOne
);
884 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &Value
);
887 // Write back the original value
889 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &OriginalValue
);
892 // Restore TPL to its original level
894 gBS
->RestoreTPL (OldTpl
);
896 if (BarLengthValue
!= NULL
) {
897 *BarLengthValue
= Value
;
900 if (OriginalBarValue
!= NULL
) {
901 *OriginalBarValue
= OriginalValue
;
905 return EFI_NOT_FOUND
;
912 Test whether the device can support given attributes.
914 @param PciIoDevice Pci device instance.
915 @param Command Input command register value, and
916 returned supported register value.
917 @param BridgeControl Input bridge control value for PPB or P2C, and
918 returned supported bridge control value.
919 @param OldCommand Returned and stored old command register offset.
920 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
924 PciTestSupportedAttribute (
925 IN PCI_IO_DEVICE
*PciIoDevice
,
926 IN OUT UINT16
*Command
,
927 IN OUT UINT16
*BridgeControl
,
928 OUT UINT16
*OldCommand
,
929 OUT UINT16
*OldBridgeControl
936 // Preserve the original value
938 PCI_READ_COMMAND_REGISTER (PciIoDevice
, OldCommand
);
941 // Raise TPL to high level to disable timer interrupt while the BAR is probed
943 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
944 CommandValue
= *Command
| *OldCommand
;
946 PCI_SET_COMMAND_REGISTER (PciIoDevice
, CommandValue
);
947 PCI_READ_COMMAND_REGISTER (PciIoDevice
, &CommandValue
);
949 *Command
= *Command
& CommandValue
;
951 // Write back the original value
953 PCI_SET_COMMAND_REGISTER (PciIoDevice
, *OldCommand
);
956 // Restore TPL to its original level
958 gBS
->RestoreTPL (OldTpl
);
960 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
) || IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
962 // Preserve the original value
964 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, OldBridgeControl
);
967 // Raise TPL to high level to disable timer interrupt while the BAR is probed
969 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
971 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *BridgeControl
);
972 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, BridgeControl
);
975 // Write back the original value
977 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *OldBridgeControl
);
980 // Restore TPL to its original level
982 gBS
->RestoreTPL (OldTpl
);
984 *OldBridgeControl
= 0;
990 Set the supported or current attributes of a PCI device.
992 @param PciIoDevice Structure pointer for PCI device.
993 @param Command Command register value.
994 @param BridgeControl Bridge control value for PPB or P2C.
995 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
999 PciSetDeviceAttribute (
1000 IN PCI_IO_DEVICE
*PciIoDevice
,
1002 IN UINT16 BridgeControl
,
1010 if ((Command
& EFI_PCI_COMMAND_IO_SPACE
) != 0) {
1011 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IO
;
1014 if ((Command
& EFI_PCI_COMMAND_MEMORY_SPACE
) != 0) {
1015 Attributes
|= EFI_PCI_IO_ATTRIBUTE_MEMORY
;
1018 if ((Command
& EFI_PCI_COMMAND_BUS_MASTER
) != 0) {
1019 Attributes
|= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
;
1022 if ((Command
& EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
) != 0) {
1023 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
1026 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_ISA
) != 0) {
1027 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_IO
;
1030 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA
) != 0) {
1031 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO
;
1032 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
1033 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
1036 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA_16
) != 0) {
1037 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
;
1038 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16
;
1041 if (Option
== EFI_SET_SUPPORTS
) {
1042 Attributes
|= (UINT64
)(EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
|
1043 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED
|
1044 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE
|
1045 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE
|
1046 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
|
1047 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1049 if (IS_PCI_LPC (&PciIoDevice
->Pci
)) {
1050 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO
;
1051 Attributes
|= (mReserveIsaAliases
? (UINT64
)EFI_PCI_IO_ATTRIBUTE_ISA_IO
: \
1052 (UINT64
)EFI_PCI_IO_ATTRIBUTE_ISA_IO_16
);
1055 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
) || IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
1057 // For bridge, it should support IDE attributes
1059 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
1060 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
1062 if (mReserveVgaAliases
) {
1063 Attributes
&= ~(UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
| \
1064 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16
);
1066 Attributes
&= ~(UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO
| \
1067 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
);
1070 if (IS_PCI_IDE (&PciIoDevice
->Pci
)) {
1071 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
1072 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
1075 if (IS_PCI_VGA (&PciIoDevice
->Pci
)) {
1076 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
1077 Attributes
|= (mReserveVgaAliases
? (UINT64
)EFI_PCI_IO_ATTRIBUTE_VGA_IO
: \
1078 (UINT64
)EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
);
1082 PciIoDevice
->Supports
= Attributes
;
1083 PciIoDevice
->Supports
&= ((PciIoDevice
->Parent
->Supports
) | \
1084 EFI_PCI_IO_ATTRIBUTE_IO
| EFI_PCI_IO_ATTRIBUTE_MEMORY
| \
1085 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
);
1088 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were
1089 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.
1090 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize
1091 // fields is not from the the ROM BAR of the PCI controller.
1093 if (!PciIoDevice
->EmbeddedRom
) {
1094 Attributes
|= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
;
1097 PciIoDevice
->Attributes
= Attributes
;
1102 Determine if the device can support Fast Back to Back attribute.
1104 @param PciIoDevice Pci device instance.
1105 @param StatusIndex Status register value.
1107 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
1108 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
1112 GetFastBackToBackSupport (
1113 IN PCI_IO_DEVICE
*PciIoDevice
,
1114 IN UINT8 StatusIndex
1117 EFI_PCI_IO_PROTOCOL
*PciIo
;
1119 UINT32 StatusRegister
;
1122 // Read the status register
1124 PciIo
= &PciIoDevice
->PciIo
;
1125 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, StatusIndex
, 1, &StatusRegister
);
1126 if (EFI_ERROR (Status
)) {
1127 return EFI_UNSUPPORTED
;
1131 // Check the Fast B2B bit
1133 if ((StatusRegister
& EFI_PCI_FAST_BACK_TO_BACK_CAPABLE
) != 0) {
1136 return EFI_UNSUPPORTED
;
1141 Process the option ROM for all the children of the specified parent PCI device.
1142 It can only be used after the first full Option ROM process.
1144 @param PciIoDevice Pci device instance.
1148 ProcessOptionRomLight (
1149 IN PCI_IO_DEVICE
*PciIoDevice
1152 PCI_IO_DEVICE
*Temp
;
1153 LIST_ENTRY
*CurrentLink
;
1156 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1158 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1159 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1160 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1162 if (!IsListEmpty (&Temp
->ChildList
)) {
1163 ProcessOptionRomLight (Temp
);
1166 Temp
->AllOpRomProcessed
= PciRomGetImageMapping (Temp
);
1168 CurrentLink
= CurrentLink
->ForwardLink
;
1173 Determine the related attributes of all devices under a Root Bridge.
1175 @param PciIoDevice PCI device instance.
1179 DetermineDeviceAttribute (
1180 IN PCI_IO_DEVICE
*PciIoDevice
1184 UINT16 BridgeControl
;
1186 UINT16 OldBridgeControl
;
1187 BOOLEAN FastB2BSupport
;
1188 PCI_IO_DEVICE
*Temp
;
1189 LIST_ENTRY
*CurrentLink
;
1193 // For Root Bridge, just copy it by RootBridgeIo protocol
1194 // so as to keep consistent with the actual attribute
1196 if (PciIoDevice
->Parent
== NULL
) {
1197 Status
= PciIoDevice
->PciRootBridgeIo
->GetAttributes (
1198 PciIoDevice
->PciRootBridgeIo
,
1199 &PciIoDevice
->Supports
,
1200 &PciIoDevice
->Attributes
1202 if (EFI_ERROR (Status
)) {
1207 // Assume the PCI Root Bridge supports DAC
1209 PciIoDevice
->Supports
|= (UINT64
)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE
|
1210 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
|
1211 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1214 // Set the attributes to be checked for common PCI devices and PPB or P2C
1215 // Since some devices only support part of them, it is better to set the
1216 // attribute according to its command or bridge control register
1218 Command
= EFI_PCI_COMMAND_IO_SPACE
|
1219 EFI_PCI_COMMAND_MEMORY_SPACE
|
1220 EFI_PCI_COMMAND_BUS_MASTER
|
1221 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
;
1223 BridgeControl
= EFI_PCI_BRIDGE_CONTROL_ISA
| EFI_PCI_BRIDGE_CONTROL_VGA
| EFI_PCI_BRIDGE_CONTROL_VGA_16
;
1226 // Test whether the device can support attributes above
1228 PciTestSupportedAttribute (PciIoDevice
, &Command
, &BridgeControl
, &OldCommand
, &OldBridgeControl
);
1231 // Set the supported attributes for specified PCI device
1233 PciSetDeviceAttribute (PciIoDevice
, Command
, BridgeControl
, EFI_SET_SUPPORTS
);
1236 // Set the current attributes for specified PCI device
1238 PciSetDeviceAttribute (PciIoDevice
, OldCommand
, OldBridgeControl
, EFI_SET_ATTRIBUTES
);
1241 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL
1242 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.
1243 if (!PciIoDevice
->IsPciExp
) {
1244 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE
);
1248 FastB2BSupport
= TRUE
;
1251 // P2C can not support FB2B on the secondary side
1253 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
1254 FastB2BSupport
= FALSE
;
1258 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1260 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1261 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1262 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1263 Status
= DetermineDeviceAttribute (Temp
);
1264 if (EFI_ERROR (Status
)) {
1269 // Detect Fast Back to Back support for the device under the bridge
1271 Status
= GetFastBackToBackSupport (Temp
, PCI_PRIMARY_STATUS_OFFSET
);
1272 if (FastB2BSupport
&& EFI_ERROR (Status
)) {
1273 FastB2BSupport
= FALSE
;
1276 CurrentLink
= CurrentLink
->ForwardLink
;
1280 // Set or clear Fast Back to Back bit for the whole bridge
1282 if (!IsListEmpty (&PciIoDevice
->ChildList
)) {
1283 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
1284 Status
= GetFastBackToBackSupport (PciIoDevice
, PCI_BRIDGE_STATUS_REGISTER_OFFSET
);
1286 if (EFI_ERROR (Status
) || (!FastB2BSupport
)) {
1287 FastB2BSupport
= FALSE
;
1288 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1290 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1294 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1295 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1296 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1297 if (FastB2BSupport
) {
1298 PCI_ENABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1300 PCI_DISABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1303 CurrentLink
= CurrentLink
->ForwardLink
;
1308 // End for IsListEmpty
1314 This routine is used to update the bar information for those incompatible PCI device.
1316 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1318 @param IgnoreOptionRom Output If the option rom of incompatible device need to be ignored.
1320 @retval EFI_SUCCESS Successfully updated bar information.
1321 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1326 IN OUT PCI_IO_DEVICE
*PciIoDevice
,
1327 OUT BOOLEAN
*IgnoreOptionRom
1333 VOID
*Configuration
;
1334 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Ptr
;
1336 Configuration
= NULL
;
1337 Status
= EFI_SUCCESS
;
1339 if (gIncompatiblePciDeviceSupport
== NULL
) {
1341 // It can only be supported after the Incompatible PCI Device
1342 // Support Protocol has been installed
1344 Status
= gBS
->LocateProtocol (
1345 &gEfiIncompatiblePciDeviceSupportProtocolGuid
,
1347 (VOID
**)&gIncompatiblePciDeviceSupport
1351 if (Status
== EFI_SUCCESS
) {
1353 // Check whether the device belongs to incompatible devices from protocol or not
1354 // If it is , then get its special requirement in the ACPI table
1356 Status
= gIncompatiblePciDeviceSupport
->CheckDevice (
1357 gIncompatiblePciDeviceSupport
,
1358 PciIoDevice
->Pci
.Hdr
.VendorId
,
1359 PciIoDevice
->Pci
.Hdr
.DeviceId
,
1360 PciIoDevice
->Pci
.Hdr
.RevisionID
,
1361 PciIoDevice
->Pci
.Device
.SubsystemVendorID
,
1362 PciIoDevice
->Pci
.Device
.SubsystemID
,
1367 if (EFI_ERROR (Status
) || (Configuration
== NULL
)) {
1368 return EFI_UNSUPPORTED
;
1372 // Update PCI device information from the ACPI table
1374 Ptr
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)Configuration
;
1376 while (Ptr
->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
1377 if (Ptr
->Desc
!= ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
1379 // The format is not support
1385 // According to "Table 20. ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage"
1386 // in PI Spec 1.7, Type-specific flags can be set to 0 when Address Translation
1387 // Offset == 6 to skip device option ROM (do not probe option rom BAR).
1389 if (((Ptr
->AddrTranslationOffset
== PCI_MAX_BAR
) && (Ptr
->SpecificFlag
== 0))) {
1390 *IgnoreOptionRom
= TRUE
;
1395 for (BarIndex
= 0; BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
1396 if ((Ptr
->AddrTranslationOffset
!= MAX_UINT64
) &&
1397 (Ptr
->AddrTranslationOffset
!= MAX_UINT8
) &&
1398 (Ptr
->AddrTranslationOffset
!= BarIndex
)
1402 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).
1403 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.
1404 // Comparing against MAX_UINT8 is to keep backward compatibility.
1410 switch (Ptr
->ResType
) {
1411 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
1414 // Make sure the bar is memory type
1416 if (CheckBarType (PciIoDevice
, (UINT8
)BarIndex
, PciBarTypeMem
)) {
1420 // Ignored if granularity is 0.
1421 // Ignored if PCI BAR is I/O or 32-bit memory.
1422 // If PCI BAR is 64-bit memory and granularity is 32, then
1423 // the PCI BAR resource is allocated below 4GB.
1424 // If PCI BAR is 64-bit memory and granularity is 64, then
1425 // the PCI BAR resource is allocated above 4GB.
1427 if (PciIoDevice
->PciBar
[BarIndex
].BarType
== PciBarTypeMem64
) {
1428 switch (Ptr
->AddrSpaceGranularity
) {
1430 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1432 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= TRUE
;
1439 if (PciIoDevice
->PciBar
[BarIndex
].BarType
== PciBarTypePMem64
) {
1440 switch (Ptr
->AddrSpaceGranularity
) {
1442 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1444 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= TRUE
;
1454 case ACPI_ADDRESS_SPACE_TYPE_IO
:
1457 // Make sure the bar is IO type
1459 if (CheckBarType (PciIoDevice
, (UINT8
)BarIndex
, PciBarTypeIo
)) {
1468 // Update the new alignment for the device
1470 SetNewAlign (&(PciIoDevice
->PciBar
[BarIndex
].Alignment
), Ptr
->AddrRangeMax
);
1473 // Update the new length for the device
1475 if (Ptr
->AddrLen
!= 0) {
1476 PciIoDevice
->PciBar
[BarIndex
].Length
= Ptr
->AddrLen
;
1484 FreePool (Configuration
);
1490 This routine will update the alignment with the new alignment.
1491 Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep
1492 backward compatibility.
1494 @param Alignment Input Old alignment. Output updated alignment.
1495 @param NewAlignment New alignment.
1500 IN OUT UINT64
*Alignment
,
1501 IN UINT64 NewAlignment
1504 UINT64 OldAlignment
;
1508 // The new alignment is the same as the original,
1511 if ((NewAlignment
== 0) || (NewAlignment
== OLD_ALIGN
)) {
1516 // Check the validity of the parameter
1518 if ((NewAlignment
!= EVEN_ALIGN
) &&
1519 (NewAlignment
!= SQUAD_ALIGN
) &&
1520 (NewAlignment
!= DQUAD_ALIGN
))
1522 *Alignment
= NewAlignment
;
1526 OldAlignment
= (*Alignment
) + 1;
1530 // Get the first non-zero hex value of the length
1532 while ((OldAlignment
& 0x0F) == 0x00) {
1533 OldAlignment
= RShiftU64 (OldAlignment
, 4);
1538 // Adjust the alignment to even, quad or double quad boundary
1540 if (NewAlignment
== EVEN_ALIGN
) {
1541 if ((OldAlignment
& 0x01) != 0) {
1542 OldAlignment
= OldAlignment
+ 2 - (OldAlignment
& 0x01);
1544 } else if (NewAlignment
== SQUAD_ALIGN
) {
1545 if ((OldAlignment
& 0x03) != 0) {
1546 OldAlignment
= OldAlignment
+ 4 - (OldAlignment
& 0x03);
1548 } else if (NewAlignment
== DQUAD_ALIGN
) {
1549 if ((OldAlignment
& 0x07) != 0) {
1550 OldAlignment
= OldAlignment
+ 8 - (OldAlignment
& 0x07);
1555 // Update the old value
1557 NewAlignment
= LShiftU64 (OldAlignment
, ShiftBit
) - 1;
1558 *Alignment
= NewAlignment
;
1564 Parse PCI IOV VF bar information and fill them into PCI device instance.
1566 @param PciIoDevice Pci device instance.
1567 @param Offset Bar offset.
1568 @param BarIndex Bar index.
1570 @return Next bar offset.
1575 IN PCI_IO_DEVICE
*PciIoDevice
,
1581 UINT32 OriginalValue
;
1586 // Ensure it is called properly
1588 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
1589 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
1596 Status
= VfBarExisted (
1603 if (EFI_ERROR (Status
)) {
1604 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1605 PciIoDevice
->VfPciBar
[BarIndex
].Length
= 0;
1606 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1609 // Scan all the BARs anyway
1611 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT16
)Offset
;
1615 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT16
)Offset
;
1616 if ((Value
& 0x01) != 0) {
1618 // Device I/Os. Impossible
1625 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1627 switch (Value
& 0x07) {
1629 // memory space; anywhere in 32 bit address space
1632 if ((Value
& 0x08) != 0) {
1633 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1635 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1638 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1639 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1644 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1648 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1649 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1655 // memory space; anywhere in 64 bit address space
1658 if ((Value
& 0x08) != 0) {
1659 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1661 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1665 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1666 // is regarded as an extension for the first bar. As a result
1667 // the sizing will be conducted on combined 64 bit value
1668 // Here just store the masked first 32bit value for future size
1671 PciIoDevice
->VfPciBar
[BarIndex
].Length
= Value
& Mask
;
1672 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1674 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1675 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1679 // Increment the offset to point to next DWORD
1683 Status
= VfBarExisted (
1690 if (EFI_ERROR (Status
)) {
1691 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1696 // Fix the length to support some special 64 bit BAR
1698 Value
|= ((UINT32
)-1 << HighBitSet32 (Value
));
1701 // Calculate the size of 64bit bar
1703 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
)OriginalValue
, 32);
1705 PciIoDevice
->VfPciBar
[BarIndex
].Length
= PciIoDevice
->VfPciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
)Value
, 32);
1706 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(PciIoDevice
->VfPciBar
[BarIndex
].Length
)) + 1;
1707 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1712 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1716 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1717 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1726 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1727 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1728 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1730 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1731 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1739 // Check the length again so as to keep compatible with some special bars
1741 if (PciIoDevice
->VfPciBar
[BarIndex
].Length
== 0) {
1742 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1743 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1744 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1748 // Increment number of bar
1754 Parse PCI bar information and fill them into PCI device instance.
1756 @param PciIoDevice Pci device instance.
1757 @param Offset Bar offset.
1758 @param BarIndex Bar index.
1760 @return Next bar offset.
1765 IN PCI_IO_DEVICE
*PciIoDevice
,
1771 UINT32 OriginalValue
;
1778 Status
= BarExisted (
1785 if (EFI_ERROR (Status
)) {
1786 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= 0;
1787 PciIoDevice
->PciBar
[BarIndex
].Length
= 0;
1788 PciIoDevice
->PciBar
[BarIndex
].Alignment
= 0;
1791 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1793 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
)Offset
;
1797 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= FALSE
;
1798 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
)Offset
;
1799 if ((Value
& 0x01) != 0) {
1805 if ((Value
& 0xFFFF0000) != 0) {
1809 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo32
;
1810 PciIoDevice
->PciBar
[BarIndex
].Length
= ((~(Value
& Mask
)) + 1);
1811 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1816 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo16
;
1817 PciIoDevice
->PciBar
[BarIndex
].Length
= 0x0000FFFF & ((~(Value
& Mask
)) + 1);
1818 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1822 // Workaround. Some platforms implement IO bar with 0 length
1823 // Need to treat it as no-bar
1825 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1826 PciIoDevice
->PciBar
[BarIndex
].BarType
= (PCI_BAR_TYPE
)0;
1829 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1833 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1835 switch (Value
& 0x07) {
1837 // memory space; anywhere in 32 bit address space
1840 if ((Value
& 0x08) != 0) {
1841 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1843 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1846 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1847 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1849 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1851 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1853 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1859 // memory space; anywhere in 64 bit address space
1862 if ((Value
& 0x08) != 0) {
1863 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1865 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1869 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1870 // is regarded as an extension for the first bar. As a result
1871 // the sizing will be conducted on combined 64 bit value
1872 // Here just store the masked first 32bit value for future size
1875 PciIoDevice
->PciBar
[BarIndex
].Length
= Value
& Mask
;
1876 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1879 // Increment the offset to point to next DWORD
1883 Status
= BarExisted (
1890 if (EFI_ERROR (Status
)) {
1892 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
1894 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1896 // some device implement MMIO bar with 0 length, need to treat it as no-bar
1898 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1904 // Fix the length to support some special 64 bit BAR
1907 DEBUG ((DEBUG_INFO
, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));
1910 Value
|= ((UINT32
)(-1) << HighBitSet32 (Value
));
1914 // Calculate the size of 64bit bar
1916 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
)OriginalValue
, 32);
1918 PciIoDevice
->PciBar
[BarIndex
].Length
= PciIoDevice
->PciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
)Value
, 32);
1919 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(PciIoDevice
->PciBar
[BarIndex
].Length
)) + 1;
1920 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1922 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1924 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1926 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1935 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1936 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1937 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1939 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1941 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1943 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1951 // Check the length again so as to keep compatible with some special bars
1953 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1954 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1955 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= 0;
1956 PciIoDevice
->PciBar
[BarIndex
].Alignment
= 0;
1960 // Increment number of bar
1966 This routine is used to initialize the bar of a PCI device.
1968 @param PciIoDevice Pci device instance.
1970 @note It can be called typically when a device is going to be rejected.
1974 InitializePciDevice (
1975 IN PCI_IO_DEVICE
*PciIoDevice
1978 EFI_PCI_IO_PROTOCOL
*PciIo
;
1981 PciIo
= &(PciIoDevice
->PciIo
);
1984 // Put all the resource apertures
1985 // Resource base is set to all ones so as to indicate its resource
1986 // has not been allocated
1988 for (Offset
= 0x10; Offset
<= 0x24; Offset
+= sizeof (UINT32
)) {
1989 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllOne
);
1994 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1996 @param PciIoDevice PCI-PCI bridge device instance.
2001 IN PCI_IO_DEVICE
*PciIoDevice
2004 EFI_PCI_IO_PROTOCOL
*PciIo
;
2006 PciIo
= &(PciIoDevice
->PciIo
);
2009 // Put all the resource apertures including IO16
2010 // Io32, pMem32, pMem64 to quiescent state
2011 // Resource base all ones, Resource limit all zeros
2013 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &gAllOne
);
2014 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1D, 1, &gAllZero
);
2016 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x20, 1, &gAllOne
);
2017 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x22, 1, &gAllZero
);
2019 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x24, 1, &gAllOne
);
2020 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x26, 1, &gAllZero
);
2022 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x28, 1, &gAllOne
);
2023 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x2C, 1, &gAllZero
);
2026 // Don't support use io32 as for now
2028 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x30, 1, &gAllOne
);
2029 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x32, 1, &gAllZero
);
2032 // Force Interrupt line to zero for cards that come up randomly
2034 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x3C, 1, &gAllZero
);
2038 This routine is used to initialize the bar of a PCI Card Bridge device.
2040 @param PciIoDevice PCI Card bridge device.
2045 IN PCI_IO_DEVICE
*PciIoDevice
2048 EFI_PCI_IO_PROTOCOL
*PciIo
;
2050 PciIo
= &(PciIoDevice
->PciIo
);
2053 // Put all the resource apertures including IO16
2054 // Io32, pMem32, pMem64 to quiescent state(
2055 // Resource base all ones, Resource limit all zeros
2057 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x1c, 1, &gAllOne
);
2058 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x20, 1, &gAllZero
);
2060 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x24, 1, &gAllOne
);
2061 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x28, 1, &gAllZero
);
2063 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x2c, 1, &gAllOne
);
2064 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x30, 1, &gAllZero
);
2066 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x34, 1, &gAllOne
);
2067 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x38, 1, &gAllZero
);
2070 // Force Interrupt line to zero for cards that come up randomly
2072 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x3C, 1, &gAllZero
);
2076 Authenticate the PCI device by using DeviceSecurityProtocol.
2078 @param PciIoDevice PCI device.
2080 @retval EFI_SUCCESS The device passes the authentication.
2081 @return not EFI_SUCCESS The device failes the authentication or
2082 unexpected error happen during authentication.
2085 AuthenticatePciDevice (
2086 IN PCI_IO_DEVICE
*PciIoDevice
2089 EDKII_DEVICE_IDENTIFIER DeviceIdentifier
;
2092 if (mDeviceSecurityProtocol
!= NULL
) {
2094 // Prepare the parameter
2096 DeviceIdentifier
.Version
= EDKII_DEVICE_IDENTIFIER_REVISION
;
2097 CopyGuid (&DeviceIdentifier
.DeviceType
, &gEdkiiDeviceIdentifierTypePciGuid
);
2098 DeviceIdentifier
.DeviceHandle
= NULL
;
2099 Status
= gBS
->InstallMultipleProtocolInterfaces (
2100 &DeviceIdentifier
.DeviceHandle
,
2101 &gEfiDevicePathProtocolGuid
,
2102 PciIoDevice
->DevicePath
,
2103 &gEdkiiDeviceIdentifierTypePciGuid
,
2104 &PciIoDevice
->PciIo
,
2107 if (EFI_ERROR (Status
)) {
2112 // Do DeviceAuthentication
2114 Status
= mDeviceSecurityProtocol
->DeviceAuthenticate (mDeviceSecurityProtocol
, &DeviceIdentifier
);
2116 // Always uninstall, because they are only for Authentication.
2117 // No need to check return Status.
2119 gBS
->UninstallMultipleProtocolInterfaces (
2120 DeviceIdentifier
.DeviceHandle
,
2121 &gEfiDevicePathProtocolGuid
,
2122 PciIoDevice
->DevicePath
,
2123 &gEdkiiDeviceIdentifierTypePciGuid
,
2124 &PciIoDevice
->PciIo
,
2131 // Device Security Protocol is not found, just return success
2137 Checks if PCI device is Root Bridge.
2139 @param PciIoDevice Instance of PCI device
2141 @retval TRUE Device is Root Bridge
2142 @retval FALSE Device is not Root Bridge
2147 IN PCI_IO_DEVICE
*PciIoDevice
2150 if (PciIoDevice
->Parent
== NULL
) {
2158 Create and initialize general PCI I/O device instance for
2159 PCI device/bridge device/hotplug bridge device.
2161 @param Bridge Parent bridge instance.
2162 @param Pci Input Pci information block.
2163 @param Bus Device Bus NO.
2164 @param Device Device device NO.
2165 @param Func Device func NO.
2167 @return Instance of PCI device. NULL means no instance created.
2172 IN PCI_IO_DEVICE
*Bridge
,
2179 PCI_IO_DEVICE
*PciIoDevice
;
2180 EFI_PCI_IO_PROTOCOL
*PciIo
;
2183 PciIoDevice
= AllocateZeroPool (sizeof (PCI_IO_DEVICE
));
2184 if (PciIoDevice
== NULL
) {
2188 PciIoDevice
->Signature
= PCI_IO_DEVICE_SIGNATURE
;
2189 PciIoDevice
->Handle
= NULL
;
2190 PciIoDevice
->PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
2191 PciIoDevice
->DevicePath
= NULL
;
2192 PciIoDevice
->BusNumber
= Bus
;
2193 PciIoDevice
->DeviceNumber
= Device
;
2194 PciIoDevice
->FunctionNumber
= Func
;
2195 PciIoDevice
->Decodes
= 0;
2197 if (gFullEnumeration
) {
2198 PciIoDevice
->Allocated
= FALSE
;
2200 PciIoDevice
->Allocated
= TRUE
;
2203 PciIoDevice
->Registered
= FALSE
;
2204 PciIoDevice
->Attributes
= 0;
2205 PciIoDevice
->Supports
= 0;
2206 PciIoDevice
->BusOverride
= FALSE
;
2207 PciIoDevice
->AllOpRomProcessed
= FALSE
;
2209 PciIoDevice
->IsPciExp
= FALSE
;
2211 CopyMem (&(PciIoDevice
->Pci
), Pci
, sizeof (PCI_TYPE01
));
2214 // Initialize the PCI I/O instance structure
2216 InitializePciIoInstance (PciIoDevice
);
2217 InitializePciDriverOverrideInstance (PciIoDevice
);
2218 InitializePciLoadFile2 (PciIoDevice
);
2219 PciIo
= &PciIoDevice
->PciIo
;
2222 // Create a device path for this PCI device and store it into its private data
2224 CreatePciDevicePath (
2230 // Detect if PCI Express Device
2232 PciIoDevice
->PciExpressCapabilityOffset
= 0;
2233 Status
= LocateCapabilityRegBlock (
2235 EFI_PCI_CAPABILITY_ID_PCIEXP
,
2236 &PciIoDevice
->PciExpressCapabilityOffset
,
2239 if (!EFI_ERROR (Status
)) {
2240 PciIoDevice
->IsPciExp
= TRUE
;
2244 // Now we can do the authentication check for the device.
2246 Status
= AuthenticatePciDevice (PciIoDevice
);
2248 // If authentication fails, skip this device.
2250 if (EFI_ERROR (Status
)) {
2251 if (PciIoDevice
->DevicePath
!= NULL
) {
2252 FreePool (PciIoDevice
->DevicePath
);
2255 FreePool (PciIoDevice
);
2260 // Check if device's parent is not Root Bridge
2262 if (PcdGetBool (PcdAriSupport
) && !IsRootBridge (Bridge
)) {
2264 // Check if the device is an ARI device.
2266 Status
= LocatePciExpressCapabilityRegBlock (
2268 EFI_PCIE_CAPABILITY_ID_ARI
,
2269 &PciIoDevice
->AriCapabilityOffset
,
2272 if (!EFI_ERROR (Status
)) {
2274 // We need to enable ARI feature before calculate BusReservation,
2275 // because FirstVFOffset and VFStride may change after that.
2277 EFI_PCI_IO_PROTOCOL
*ParentPciIo
;
2281 // Check if its parent supports ARI forwarding.
2283 ParentPciIo
= &Bridge
->PciIo
;
2284 ParentPciIo
->Pci
.Read (
2286 EfiPciIoWidthUint32
,
2287 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET
,
2291 if ((Data32
& EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING
) != 0) {
2292 PciIoDevice
->IsAriEnabled
= TRUE
;
2294 // ARI forward support in bridge, so enable it.
2296 ParentPciIo
->Pci
.Read (
2298 EfiPciIoWidthUint32
,
2299 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET
,
2303 if ((Data32
& EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING
) == 0) {
2304 Data32
|= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING
;
2305 ParentPciIo
->Pci
.Write (
2307 EfiPciIoWidthUint32
,
2308 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET
,
2314 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
2316 Bridge
->DeviceNumber
,
2317 Bridge
->FunctionNumber
2322 DEBUG ((DEBUG_INFO
, " ARI: CapOffset = 0x%x\n", PciIoDevice
->AriCapabilityOffset
));
2327 // Initialization for SR-IOV
2330 if (PcdGetBool (PcdSrIovSupport
)) {
2331 Status
= LocatePciExpressCapabilityRegBlock (
2333 EFI_PCIE_CAPABILITY_ID_SRIOV
,
2334 &PciIoDevice
->SrIovCapabilityOffset
,
2337 if (!EFI_ERROR (Status
)) {
2338 UINT32 SupportedPageSize
;
2340 UINT16 FirstVFOffset
;
2346 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
2348 if (PcdGetBool (PcdAriSupport
) && (PciIoDevice
->AriCapabilityOffset
!= 0)) {
2351 EfiPciIoWidthUint16
,
2352 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL
,
2356 Data16
|= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY
;
2359 EfiPciIoWidthUint16
,
2360 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL
,
2367 // Calculate SystemPageSize
2372 EfiPciIoWidthUint32
,
2373 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE
,
2377 PciIoDevice
->SystemPageSize
= (PcdGet32 (PcdSrIovSystemPageSize
) & SupportedPageSize
);
2378 ASSERT (PciIoDevice
->SystemPageSize
!= 0);
2382 EfiPciIoWidthUint32
,
2383 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE
,
2385 &PciIoDevice
->SystemPageSize
2388 // Adjust SystemPageSize for Alignment usage later
2390 PciIoDevice
->SystemPageSize
<<= 12;
2393 // Calculate BusReservation for PCI IOV
2397 // Read First FirstVFOffset, InitialVFs, and VFStride
2401 EfiPciIoWidthUint16
,
2402 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF
,
2408 EfiPciIoWidthUint16
,
2409 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS
,
2411 &PciIoDevice
->InitialVFs
2415 EfiPciIoWidthUint16
,
2416 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE
,
2423 if (PciIoDevice
->InitialVFs
== 0) {
2424 PciIoDevice
->ReservedBusNum
= 0;
2426 PFRid
= EFI_PCI_RID (Bus
, Device
, Func
);
2427 LastVF
= PFRid
+ FirstVFOffset
+ (PciIoDevice
->InitialVFs
- 1) * VFStride
;
2430 // Calculate ReservedBusNum for this PF
2432 PciIoDevice
->ReservedBusNum
= (UINT16
)(EFI_PCI_BUS_OF_RID (LastVF
) - Bus
);
2437 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
2439 PciIoDevice
->SystemPageSize
>> 12,
2444 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
2445 PciIoDevice
->InitialVFs
,
2446 PciIoDevice
->ReservedBusNum
,
2447 PciIoDevice
->SrIovCapabilityOffset
2452 if (PcdGetBool (PcdMrIovSupport
)) {
2453 Status
= LocatePciExpressCapabilityRegBlock (
2455 EFI_PCIE_CAPABILITY_ID_MRIOV
,
2456 &PciIoDevice
->MrIovCapabilityOffset
,
2459 if (!EFI_ERROR (Status
)) {
2460 DEBUG ((DEBUG_INFO
, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice
->MrIovCapabilityOffset
));
2464 PciIoDevice
->ResizableBarOffset
= 0;
2465 if (PcdGetBool (PcdPcieResizableBarSupport
)) {
2466 Status
= LocatePciExpressCapabilityRegBlock (
2468 PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID
,
2469 &PciIoDevice
->ResizableBarOffset
,
2472 if (!EFI_ERROR (Status
)) {
2473 PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl
;
2475 Offset
= PciIoDevice
->ResizableBarOffset
+ sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER
)
2476 + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY
),
2481 sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL
),
2482 &ResizableBarControl
2484 PciIoDevice
->ResizableBarNumber
= ResizableBarControl
.Bits
.ResizableBarNumber
;
2485 PciProgramResizableBar (PciIoDevice
, PciResizableBarMax
);
2490 // Initialize the reserved resource list
2492 InitializeListHead (&PciIoDevice
->ReservedResourceList
);
2495 // Initialize the driver list
2497 InitializeListHead (&PciIoDevice
->OptionRomDriverList
);
2500 // Initialize the child list
2502 InitializeListHead (&PciIoDevice
->ChildList
);
2508 This routine is used to enumerate entire pci bus system
2509 in a given platform.
2511 It is only called on the second start on the same Root Bridge.
2513 @param Controller Parent bridge handler.
2515 @retval EFI_SUCCESS PCI enumeration finished successfully.
2516 @retval other Some error occurred when enumerating the pci bus system.
2520 PciEnumeratorLight (
2521 IN EFI_HANDLE Controller
2525 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2526 PCI_IO_DEVICE
*RootBridgeDev
;
2529 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
2532 MaxBus
= PCI_MAX_BUS
;
2536 // If this root bridge has been already enumerated, then return successfully
2538 if (GetRootBridgeByHandle (Controller
) != NULL
) {
2543 // Open pci root bridge io protocol
2545 Status
= gBS
->OpenProtocol (
2547 &gEfiPciRootBridgeIoProtocolGuid
,
2548 (VOID
**)&PciRootBridgeIo
,
2549 gPciBusDriverBinding
.DriverBindingHandle
,
2551 EFI_OPEN_PROTOCOL_BY_DRIVER
2553 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
2557 Status
= PciRootBridgeIo
->Configuration (PciRootBridgeIo
, (VOID
**)&Descriptors
);
2559 if (EFI_ERROR (Status
)) {
2563 while (PciGetBusRange (&Descriptors
, &MinBus
, &MaxBus
, NULL
) == EFI_SUCCESS
) {
2565 // Create a device node for root bridge device with a NULL host bridge controller handle
2567 RootBridgeDev
= CreateRootBridge (Controller
);
2569 if (RootBridgeDev
== NULL
) {
2575 // Record the root bridge-io protocol
2577 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2579 Status
= PciPciDeviceInfoCollector (
2584 if (!EFI_ERROR (Status
)) {
2586 // Remove those PCI devices which are rejected when full enumeration
2588 RemoveRejectedPciDevices (RootBridgeDev
->Handle
, RootBridgeDev
);
2591 // Process option rom light
2593 ProcessOptionRomLight (RootBridgeDev
);
2596 // Determine attributes for all devices under this root bridge
2598 DetermineDeviceAttribute (RootBridgeDev
);
2601 // If successfully, insert the node into device pool
2603 InsertRootBridge (RootBridgeDev
);
2606 // If unsuccessfully, destroy the entire node
2608 DestroyRootBridge (RootBridgeDev
);
2618 Get bus range from PCI resource descriptor list.
2620 @param Descriptors A pointer to the address space descriptor.
2621 @param MinBus The min bus returned.
2622 @param MaxBus The max bus returned.
2623 @param BusRange The bus range returned.
2625 @retval EFI_SUCCESS Successfully got bus range.
2626 @retval EFI_NOT_FOUND Can not find the specific bus.
2631 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
**Descriptors
,
2634 OUT UINT16
*BusRange
2637 while ((*Descriptors
)->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
2638 if ((*Descriptors
)->ResType
== ACPI_ADDRESS_SPACE_TYPE_BUS
) {
2639 if (MinBus
!= NULL
) {
2640 *MinBus
= (UINT16
)(*Descriptors
)->AddrRangeMin
;
2643 if (MaxBus
!= NULL
) {
2644 *MaxBus
= (UINT16
)(*Descriptors
)->AddrRangeMax
;
2647 if (BusRange
!= NULL
) {
2648 *BusRange
= (UINT16
)(*Descriptors
)->AddrLen
;
2657 return EFI_NOT_FOUND
;
2661 This routine can be used to start the root bridge.
2663 @param RootBridgeDev Pci device instance.
2665 @retval EFI_SUCCESS This device started.
2666 @retval other Failed to get PCI Root Bridge I/O protocol.
2670 StartManagingRootBridge (
2671 IN PCI_IO_DEVICE
*RootBridgeDev
2674 EFI_HANDLE RootBridgeHandle
;
2676 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2679 // Get the root bridge handle
2681 RootBridgeHandle
= RootBridgeDev
->Handle
;
2682 PciRootBridgeIo
= NULL
;
2685 // Get the pci root bridge io protocol
2687 Status
= gBS
->OpenProtocol (
2689 &gEfiPciRootBridgeIoProtocolGuid
,
2690 (VOID
**)&PciRootBridgeIo
,
2691 gPciBusDriverBinding
.DriverBindingHandle
,
2693 EFI_OPEN_PROTOCOL_BY_DRIVER
2696 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
2701 // Store the PciRootBridgeIo protocol into root bridge private data
2703 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2709 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2711 @param PciIoDevice Pci device instance.
2713 @retval TRUE This device should be rejected.
2714 @retval FALSE This device shouldn't be rejected.
2718 IsPciDeviceRejected (
2719 IN PCI_IO_DEVICE
*PciIoDevice
2729 // PPB should be skip!
2731 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
2735 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
2737 // Only test base registers for P2C
2739 for (BarOffset
= 0x1C; BarOffset
<= 0x38; BarOffset
+= 2 * sizeof (UINT32
)) {
2740 Mask
= (BarOffset
< 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2741 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2742 if (EFI_ERROR (Status
)) {
2746 TestValue
= TestValue
& Mask
;
2747 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2749 // The bar isn't programed, so it should be rejected
2758 for (BarOffset
= 0x14; BarOffset
<= 0x24; BarOffset
+= sizeof (UINT32
)) {
2762 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2763 if (EFI_ERROR (Status
)) {
2767 if ((TestValue
& 0x01) != 0) {
2772 TestValue
= TestValue
& Mask
;
2773 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2781 TestValue
= TestValue
& Mask
;
2783 if ((TestValue
& 0x07) == 0x04) {
2787 BarOffset
+= sizeof (UINT32
);
2788 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2790 // Test its high 32-Bit BAR
2792 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2793 if (TestValue
== OldValue
) {
2801 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2812 Reset all bus number from specific bridge.
2814 @param Bridge Parent specific bridge.
2815 @param StartBusNumber Start bus number.
2819 ResetAllPpbBusNumber (
2820 IN PCI_IO_DEVICE
*Bridge
,
2821 IN UINT8 StartBusNumber
2831 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2833 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
2835 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
2836 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
2838 // Check to see whether a pci device is present
2840 Status
= PciDevicePresent (
2848 if (EFI_ERROR (Status
) && (Func
== 0)) {
2850 // go to next device if there is no Function 0
2855 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
))) {
2857 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
2858 Status
= PciRootBridgeIo
->Pci
.Read (
2865 SecondaryBus
= (UINT8
)(Register
>> 8);
2867 if (SecondaryBus
!= 0) {
2868 ResetAllPpbBusNumber (Bridge
, SecondaryBus
);
2872 // Reset register 18h, 19h, 1Ah on PCI Bridge
2874 Register
&= 0xFF000000;
2875 Status
= PciRootBridgeIo
->Pci
.Write (
2884 if ((Func
== 0) && !IS_PCI_MULTI_FUNC (&Pci
)) {
2886 // Skip sub functions, this is not a multi function device
2888 Func
= PCI_MAX_FUNC
;