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 SPDX-License-Identifier: BSD-2-Clause-Patent
12 extern CHAR16
*mBarTypeStr
[];
13 extern EDKII_DEVICE_SECURITY_PROTOCOL
*mDeviceSecurityProtocol
;
15 #define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL
16 #define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
17 #define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
18 #define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
21 This routine is used to check whether the pci device is present.
23 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
24 @param Pci Output buffer for PCI device configuration space.
25 @param Bus PCI bus NO.
26 @param Device PCI device NO.
27 @param Func PCI Func NO.
29 @retval EFI_NOT_FOUND PCI device not present.
30 @retval EFI_SUCCESS PCI device is found.
35 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
46 // Create PCI address map in terms of Bus, Device and Func
48 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Func
, 0);
51 // Read the Vendor ID register
53 Status
= PciRootBridgeIo
->Pci
.Read (
61 if (!EFI_ERROR (Status
) && (Pci
->Hdr
).VendorId
!= 0xffff) {
63 // Read the entire config header for the device
65 Status
= PciRootBridgeIo
->Pci
.Read (
69 sizeof (PCI_TYPE00
) / sizeof (UINT32
),
80 Collect all the resource information under this root bridge.
82 A database that records all the information about pci device subject to this
83 root bridge will then be created.
85 @param Bridge Parent bridge instance.
86 @param StartBusNumber Bus number of beginning.
88 @retval EFI_SUCCESS PCI device is found.
89 @retval other Some error occurred when reading PCI bridge information.
93 PciPciDeviceInfoCollector (
94 IN PCI_IO_DEVICE
*Bridge
,
95 IN UINT8 StartBusNumber
103 PCI_IO_DEVICE
*PciIoDevice
;
104 EFI_PCI_IO_PROTOCOL
*PciIo
;
106 Status
= EFI_SUCCESS
;
109 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
111 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
114 // Check to see whether PCI device is present
116 Status
= PciDevicePresent (
117 Bridge
->PciRootBridgeIo
,
119 (UINT8
) StartBusNumber
,
124 if (EFI_ERROR (Status
) && Func
== 0) {
126 // go to next device if there is no Function 0
131 if (!EFI_ERROR (Status
)) {
134 // Call back to host bridge function
136 PreprocessController (Bridge
, (UINT8
) StartBusNumber
, Device
, Func
, EfiPciBeforeResourceCollection
);
139 // Collect all the information about the PCI device discovered
141 Status
= PciSearchDevice (
144 (UINT8
) StartBusNumber
,
151 // Recursively scan PCI busses on the other side of PCI-PCI bridges
154 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
) || IS_CARDBUS_BRIDGE (&Pci
))) {
157 // If it is PPB, we need to get the secondary bus to continue the enumeration
159 PciIo
= &(PciIoDevice
->PciIo
);
161 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
, 1, &SecBus
);
163 if (EFI_ERROR (Status
)) {
168 // Ensure secondary bus number is greater than the primary bus number to avoid
169 // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE
171 if (SecBus
<= StartBusNumber
) {
176 // Get resource padding for PPB
178 GetResourcePaddingPpb (PciIoDevice
);
181 // Deep enumerate the next level bus
183 Status
= PciPciDeviceInfoCollector (
190 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
193 // Skip sub functions, this is not a multi function device
206 Search required device and create PCI device instance.
208 @param Bridge Parent bridge instance.
209 @param Pci Input PCI device information block.
210 @param Bus PCI bus NO.
211 @param Device PCI device NO.
212 @param Func PCI func NO.
213 @param PciDevice Output of searched PCI device instance.
215 @retval EFI_SUCCESS Successfully created PCI device instance.
216 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
221 IN PCI_IO_DEVICE
*Bridge
,
226 OUT PCI_IO_DEVICE
**PciDevice
229 PCI_IO_DEVICE
*PciIoDevice
;
235 "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",
236 IS_PCI_BRIDGE (Pci
) ? L
"PPB" :
237 IS_CARDBUS_BRIDGE (Pci
) ? L
"P2C" :
242 if (!IS_PCI_BRIDGE (Pci
)) {
244 if (IS_CARDBUS_BRIDGE (Pci
)) {
245 PciIoDevice
= GatherP2CInfo (
252 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
253 InitializeP2C (PciIoDevice
);
258 // Create private data for Pci Device
260 PciIoDevice
= GatherDeviceInfo (
273 // Create private data for PPB
275 PciIoDevice
= GatherPpbInfo (
284 // Special initialization for PPB including making the PPB quiet
286 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
287 InitializePpb (PciIoDevice
);
291 if (PciIoDevice
== NULL
) {
292 return EFI_OUT_OF_RESOURCES
;
296 // Update the bar information for this PCI device so as to support some specific device
298 UpdatePciInfo (PciIoDevice
);
300 if (PciIoDevice
->DevicePath
== NULL
) {
301 return EFI_OUT_OF_RESOURCES
;
305 // Detect this function has option rom
307 if (gFullEnumeration
) {
309 if (!IS_CARDBUS_BRIDGE (Pci
)) {
311 GetOpRomInfo (PciIoDevice
);
315 ResetPowerManagementFeature (PciIoDevice
);
320 // Insert it into a global tree for future reference
322 InsertPciDevice (Bridge
, PciIoDevice
);
325 // Determine PCI device attributes
328 if (PciDevice
!= NULL
) {
329 *PciDevice
= PciIoDevice
;
336 Dump the PPB padding resource information.
338 @param PciIoDevice PCI IO instance.
339 @param ResourceType The desired resource type to dump.
340 PciBarTypeUnknown means to dump all types of resources.
343 DumpPpbPaddingResource (
344 IN PCI_IO_DEVICE
*PciIoDevice
,
345 IN PCI_BAR_TYPE ResourceType
348 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
351 if (PciIoDevice
->ResourcePaddingDescriptors
== NULL
) {
355 if (ResourceType
== PciBarTypeIo16
|| ResourceType
== PciBarTypeIo32
) {
356 ResourceType
= PciBarTypeIo
;
359 for (Descriptor
= PciIoDevice
->ResourcePaddingDescriptors
; Descriptor
->Desc
!= ACPI_END_TAG_DESCRIPTOR
; Descriptor
++) {
361 Type
= PciBarTypeUnknown
;
362 if (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
&& Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_IO
) {
364 } else if (Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
&& Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
366 if (Descriptor
->AddrSpaceGranularity
== 32) {
370 if (Descriptor
->SpecificFlag
== EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) {
371 Type
= PciBarTypePMem32
;
377 if (Descriptor
->SpecificFlag
== 0) {
378 Type
= PciBarTypeMem32
;
382 if (Descriptor
->AddrSpaceGranularity
== 64) {
386 if (Descriptor
->SpecificFlag
== EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) {
387 Type
= PciBarTypePMem64
;
393 if (Descriptor
->SpecificFlag
== 0) {
394 Type
= PciBarTypeMem64
;
399 if ((Type
!= PciBarTypeUnknown
) && ((ResourceType
== PciBarTypeUnknown
) || (ResourceType
== Type
))) {
402 " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
403 mBarTypeStr
[Type
], Descriptor
->AddrRangeMax
, Descriptor
->AddrLen
411 Dump the PCI BAR information.
413 @param PciIoDevice PCI IO instance.
417 IN PCI_IO_DEVICE
*PciIoDevice
422 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
423 if (PciIoDevice
->PciBar
[Index
].BarType
== PciBarTypeUnknown
) {
429 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
430 Index
, mBarTypeStr
[MIN (PciIoDevice
->PciBar
[Index
].BarType
, PciBarTypeMaxType
)],
431 PciIoDevice
->PciBar
[Index
].Alignment
, PciIoDevice
->PciBar
[Index
].Length
, PciIoDevice
->PciBar
[Index
].Offset
435 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
436 if ((PciIoDevice
->VfPciBar
[Index
].BarType
== PciBarTypeUnknown
) && (PciIoDevice
->VfPciBar
[Index
].Length
== 0)) {
442 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
443 Index
, mBarTypeStr
[MIN (PciIoDevice
->VfPciBar
[Index
].BarType
, PciBarTypeMaxType
)],
444 PciIoDevice
->VfPciBar
[Index
].Alignment
, PciIoDevice
->VfPciBar
[Index
].Length
, PciIoDevice
->VfPciBar
[Index
].Offset
447 DEBUG ((EFI_D_INFO
, "\n"));
451 Create PCI device instance for PCI device.
453 @param Bridge Parent bridge instance.
454 @param Pci Input PCI device information block.
455 @param Bus PCI device Bus NO.
456 @param Device PCI device Device NO.
457 @param Func PCI device's func NO.
459 @return Created PCI device instance.
464 IN PCI_IO_DEVICE
*Bridge
,
473 PCI_IO_DEVICE
*PciIoDevice
;
475 PciIoDevice
= CreatePciIoDevice (
483 if (PciIoDevice
== NULL
) {
488 // If it is a full enumeration, disconnect the device in advance
490 if (gFullEnumeration
) {
492 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
497 // Start to parse the bars
499 for (Offset
= 0x10, BarIndex
= 0; Offset
<= 0x24 && BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
500 Offset
= PciParseBar (PciIoDevice
, Offset
, BarIndex
);
504 // Parse the SR-IOV VF bars
506 if (PcdGetBool (PcdSrIovSupport
) && PciIoDevice
->SrIovCapabilityOffset
!= 0) {
507 for (Offset
= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0
, BarIndex
= 0;
508 Offset
<= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5
;
511 ASSERT (BarIndex
< PCI_MAX_BAR
);
512 Offset
= PciIovParseVfBar (PciIoDevice
, Offset
, BarIndex
);
516 DEBUG_CODE (DumpPciBars (PciIoDevice
););
521 Create PCI device instance for PCI-PCI bridge.
523 @param Bridge Parent bridge instance.
524 @param Pci Input PCI device information block.
525 @param Bus PCI device Bus NO.
526 @param Device PCI device Device NO.
527 @param Func PCI device's func NO.
529 @return Created PCI device instance.
534 IN PCI_IO_DEVICE
*Bridge
,
541 PCI_IO_DEVICE
*PciIoDevice
;
544 EFI_PCI_IO_PROTOCOL
*PciIo
;
546 UINT32 PMemBaseLimit
;
547 UINT16 PrefetchableMemoryBase
;
548 UINT16 PrefetchableMemoryLimit
;
550 PciIoDevice
= CreatePciIoDevice (
558 if (PciIoDevice
== NULL
) {
562 if (gFullEnumeration
) {
563 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
566 // Initialize the bridge control register
568 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED
);
573 // PPB can have two BARs
575 if (PciParseBar (PciIoDevice
, 0x10, PPB_BAR_0
) == 0x14) {
579 PciParseBar (PciIoDevice
, 0x14, PPB_BAR_1
);
582 PciIo
= &PciIoDevice
->PciIo
;
585 // Test whether it support 32 decode or not
587 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
588 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &gAllOne
);
589 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
590 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
593 if ((Value
& 0x01) != 0) {
594 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
596 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO16_DECODE_SUPPORTED
;
601 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
602 // PCI bridge supporting non-standard I/O window alignment less than 4K.
605 PciIoDevice
->BridgeIoAlignment
= 0xFFF;
606 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe
)) {
608 // Check any bits of bit 3-1 of I/O Base Register are writable.
609 // if so, it is assumed non-standard I/O window alignment is supported by this bridge.
610 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.
612 Value
= (UINT8
)(Temp
^ (BIT3
| BIT2
| BIT1
));
613 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
614 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
615 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
616 Value
= (UINT8
)((Value
^ Temp
) & (BIT3
| BIT2
| BIT1
));
619 PciIoDevice
->BridgeIoAlignment
= 0x7FF;
622 PciIoDevice
->BridgeIoAlignment
= 0x3FF;
624 case BIT3
| BIT2
| BIT1
:
625 PciIoDevice
->BridgeIoAlignment
= 0x1FF;
630 Status
= BarExisted (
638 // Test if it supports 64 memory or not
640 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit
642 // 0 - the bridge supports only 32 bit addresses.
643 // 1 - the bridge supports 64-bit addresses.
645 PrefetchableMemoryBase
= (UINT16
)(PMemBaseLimit
& 0xffff);
646 PrefetchableMemoryLimit
= (UINT16
)(PMemBaseLimit
>> 16);
647 if (!EFI_ERROR (Status
) &&
648 (PrefetchableMemoryBase
& 0x000f) == 0x0001 &&
649 (PrefetchableMemoryLimit
& 0x000f) == 0x0001) {
650 Status
= BarExisted (
657 if (!EFI_ERROR (Status
)) {
658 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
659 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED
;
661 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
666 // Memory 32 code is required for ppb
668 PciIoDevice
->Decodes
|= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
;
670 GetResourcePaddingPpb (PciIoDevice
);
673 DumpPpbPaddingResource (PciIoDevice
, PciBarTypeUnknown
);
674 DumpPciBars (PciIoDevice
);
682 Create PCI device instance for PCI Card bridge device.
684 @param Bridge Parent bridge instance.
685 @param Pci Input PCI device information block.
686 @param Bus PCI device Bus NO.
687 @param Device PCI device Device NO.
688 @param Func PCI device's func NO.
690 @return Created PCI device instance.
695 IN PCI_IO_DEVICE
*Bridge
,
702 PCI_IO_DEVICE
*PciIoDevice
;
704 PciIoDevice
= CreatePciIoDevice (
712 if (PciIoDevice
== NULL
) {
716 if (gFullEnumeration
) {
717 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
720 // Initialize the bridge control register
722 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED
);
726 // P2C only has one bar that is in 0x10
728 PciParseBar (PciIoDevice
, 0x10, P2C_BAR_0
);
731 // Read PciBar information from the bar register
733 GetBackPcCardBar (PciIoDevice
);
734 PciIoDevice
->Decodes
= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
|
735 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
|
736 EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
738 DEBUG_CODE (DumpPciBars (PciIoDevice
););
744 Create device path for pci device.
746 @param ParentDevicePath Parent bridge's path.
747 @param PciIoDevice Pci device instance.
749 @return Device path protocol instance for specific pci device.
752 EFI_DEVICE_PATH_PROTOCOL
*
753 CreatePciDevicePath (
754 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
755 IN PCI_IO_DEVICE
*PciIoDevice
759 PCI_DEVICE_PATH PciNode
;
762 // Create PCI device path
764 PciNode
.Header
.Type
= HARDWARE_DEVICE_PATH
;
765 PciNode
.Header
.SubType
= HW_PCI_DP
;
766 SetDevicePathNodeLength (&PciNode
.Header
, sizeof (PciNode
));
768 PciNode
.Device
= PciIoDevice
->DeviceNumber
;
769 PciNode
.Function
= PciIoDevice
->FunctionNumber
;
770 PciIoDevice
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, &PciNode
.Header
);
772 return PciIoDevice
->DevicePath
;
776 Check whether the PCI IOV VF bar is existed or not.
778 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
779 @param Offset The offset.
780 @param BarLengthValue The bar length value returned.
781 @param OriginalBarValue The original bar value returned.
783 @retval EFI_NOT_FOUND The bar doesn't exist.
784 @retval EFI_SUCCESS The bar exist.
789 IN PCI_IO_DEVICE
*PciIoDevice
,
791 OUT UINT32
*BarLengthValue
,
792 OUT UINT32
*OriginalBarValue
795 EFI_PCI_IO_PROTOCOL
*PciIo
;
796 UINT32 OriginalValue
;
801 // Ensure it is called properly
803 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
804 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
805 return EFI_NOT_FOUND
;
808 PciIo
= &PciIoDevice
->PciIo
;
811 // Preserve the original value
814 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
817 // Raise TPL to high level to disable timer interrupt while the BAR is probed
819 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
821 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &gAllOne
);
822 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &Value
);
825 // Write back the original value
827 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
830 // Restore TPL to its original level
832 gBS
->RestoreTPL (OldTpl
);
834 if (BarLengthValue
!= NULL
) {
835 *BarLengthValue
= Value
;
838 if (OriginalBarValue
!= NULL
) {
839 *OriginalBarValue
= OriginalValue
;
843 return EFI_NOT_FOUND
;
850 Check whether the bar is existed or not.
852 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
853 @param Offset The offset.
854 @param BarLengthValue The bar length value returned.
855 @param OriginalBarValue The original bar value returned.
857 @retval EFI_NOT_FOUND The bar doesn't exist.
858 @retval EFI_SUCCESS The bar exist.
863 IN PCI_IO_DEVICE
*PciIoDevice
,
865 OUT UINT32
*BarLengthValue
,
866 OUT UINT32
*OriginalBarValue
869 EFI_PCI_IO_PROTOCOL
*PciIo
;
870 UINT32 OriginalValue
;
874 PciIo
= &PciIoDevice
->PciIo
;
877 // Preserve the original value
879 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &OriginalValue
);
882 // Raise TPL to high level to disable timer interrupt while the BAR is probed
884 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
886 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &gAllOne
);
887 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &Value
);
890 // Write back the original value
892 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &OriginalValue
);
895 // Restore TPL to its original level
897 gBS
->RestoreTPL (OldTpl
);
899 if (BarLengthValue
!= NULL
) {
900 *BarLengthValue
= Value
;
903 if (OriginalBarValue
!= NULL
) {
904 *OriginalBarValue
= OriginalValue
;
908 return EFI_NOT_FOUND
;
915 Test whether the device can support given attributes.
917 @param PciIoDevice Pci device instance.
918 @param Command Input command register value, and
919 returned supported register value.
920 @param BridgeControl Input bridge control value for PPB or P2C, and
921 returned supported bridge control value.
922 @param OldCommand Returned and stored old command register offset.
923 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
927 PciTestSupportedAttribute (
928 IN PCI_IO_DEVICE
*PciIoDevice
,
929 IN OUT UINT16
*Command
,
930 IN OUT UINT16
*BridgeControl
,
931 OUT UINT16
*OldCommand
,
932 OUT UINT16
*OldBridgeControl
938 // Preserve the original value
940 PCI_READ_COMMAND_REGISTER (PciIoDevice
, OldCommand
);
943 // Raise TPL to high level to disable timer interrupt while the BAR is probed
945 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
947 PCI_SET_COMMAND_REGISTER (PciIoDevice
, *Command
);
948 PCI_READ_COMMAND_REGISTER (PciIoDevice
, Command
);
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
)) {
963 // Preserve the original value
965 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, OldBridgeControl
);
968 // Raise TPL to high level to disable timer interrupt while the BAR is probed
970 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
972 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *BridgeControl
);
973 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, BridgeControl
);
976 // Write back the original value
978 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *OldBridgeControl
);
981 // Restore TPL to its original level
983 gBS
->RestoreTPL (OldTpl
);
986 *OldBridgeControl
= 0;
992 Set the supported or current attributes of a PCI device.
994 @param PciIoDevice Structure pointer for PCI device.
995 @param Command Command register value.
996 @param BridgeControl Bridge control value for PPB or P2C.
997 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
1001 PciSetDeviceAttribute (
1002 IN PCI_IO_DEVICE
*PciIoDevice
,
1004 IN UINT16 BridgeControl
,
1012 if ((Command
& EFI_PCI_COMMAND_IO_SPACE
) != 0) {
1013 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IO
;
1016 if ((Command
& EFI_PCI_COMMAND_MEMORY_SPACE
) != 0) {
1017 Attributes
|= EFI_PCI_IO_ATTRIBUTE_MEMORY
;
1020 if ((Command
& EFI_PCI_COMMAND_BUS_MASTER
) != 0) {
1021 Attributes
|= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
;
1024 if ((Command
& EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
) != 0) {
1025 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
1028 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_ISA
) != 0) {
1029 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_IO
;
1032 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA
) != 0) {
1033 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO
;
1034 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
1035 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
1038 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA_16
) != 0) {
1039 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
;
1040 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16
;
1043 if (Option
== EFI_SET_SUPPORTS
) {
1045 Attributes
|= (UINT64
) (EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
|
1046 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED
|
1047 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE
|
1048 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE
|
1049 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
|
1050 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1052 if (IS_PCI_LPC (&PciIoDevice
->Pci
)) {
1053 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO
;
1054 Attributes
|= (mReserveIsaAliases
? (UINT64
) EFI_PCI_IO_ATTRIBUTE_ISA_IO
: \
1055 (UINT64
) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16
);
1058 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
) || IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
1060 // For bridge, it should support IDE attributes
1062 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
1063 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
1065 if (mReserveVgaAliases
) {
1066 Attributes
&= ~(UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
| \
1067 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16
);
1069 Attributes
&= ~(UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO
| \
1070 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
);
1074 if (IS_PCI_IDE (&PciIoDevice
->Pci
)) {
1075 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
1076 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
1079 if (IS_PCI_VGA (&PciIoDevice
->Pci
)) {
1080 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
1081 Attributes
|= (mReserveVgaAliases
? (UINT64
) EFI_PCI_IO_ATTRIBUTE_VGA_IO
: \
1082 (UINT64
) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
);
1086 PciIoDevice
->Supports
= Attributes
;
1087 PciIoDevice
->Supports
&= ( (PciIoDevice
->Parent
->Supports
) | \
1088 EFI_PCI_IO_ATTRIBUTE_IO
| EFI_PCI_IO_ATTRIBUTE_MEMORY
| \
1089 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
);
1093 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were
1094 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.
1095 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize
1096 // fields is not from the the ROM BAR of the PCI controller.
1098 if (!PciIoDevice
->EmbeddedRom
) {
1099 Attributes
|= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
;
1101 PciIoDevice
->Attributes
= Attributes
;
1106 Determine if the device can support Fast Back to Back attribute.
1108 @param PciIoDevice Pci device instance.
1109 @param StatusIndex Status register value.
1111 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
1112 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
1116 GetFastBackToBackSupport (
1117 IN PCI_IO_DEVICE
*PciIoDevice
,
1118 IN UINT8 StatusIndex
1121 EFI_PCI_IO_PROTOCOL
*PciIo
;
1123 UINT32 StatusRegister
;
1126 // Read the status register
1128 PciIo
= &PciIoDevice
->PciIo
;
1129 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, StatusIndex
, 1, &StatusRegister
);
1130 if (EFI_ERROR (Status
)) {
1131 return EFI_UNSUPPORTED
;
1135 // Check the Fast B2B bit
1137 if ((StatusRegister
& EFI_PCI_FAST_BACK_TO_BACK_CAPABLE
) != 0) {
1140 return EFI_UNSUPPORTED
;
1145 Process the option ROM for all the children of the specified parent PCI device.
1146 It can only be used after the first full Option ROM process.
1148 @param PciIoDevice Pci device instance.
1152 ProcessOptionRomLight (
1153 IN PCI_IO_DEVICE
*PciIoDevice
1156 PCI_IO_DEVICE
*Temp
;
1157 LIST_ENTRY
*CurrentLink
;
1160 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1162 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1163 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1165 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1167 if (!IsListEmpty (&Temp
->ChildList
)) {
1168 ProcessOptionRomLight (Temp
);
1171 PciRomGetImageMapping (Temp
);
1174 // The OpRom has already been processed in the first round
1176 Temp
->AllOpRomProcessed
= TRUE
;
1178 CurrentLink
= CurrentLink
->ForwardLink
;
1183 Determine the related attributes of all devices under a Root Bridge.
1185 @param PciIoDevice PCI device instance.
1189 DetermineDeviceAttribute (
1190 IN PCI_IO_DEVICE
*PciIoDevice
1194 UINT16 BridgeControl
;
1196 UINT16 OldBridgeControl
;
1197 BOOLEAN FastB2BSupport
;
1198 PCI_IO_DEVICE
*Temp
;
1199 LIST_ENTRY
*CurrentLink
;
1203 // For Root Bridge, just copy it by RootBridgeIo protocol
1204 // so as to keep consistent with the actual attribute
1206 if (PciIoDevice
->Parent
== NULL
) {
1207 Status
= PciIoDevice
->PciRootBridgeIo
->GetAttributes (
1208 PciIoDevice
->PciRootBridgeIo
,
1209 &PciIoDevice
->Supports
,
1210 &PciIoDevice
->Attributes
1212 if (EFI_ERROR (Status
)) {
1216 // Assume the PCI Root Bridge supports DAC
1218 PciIoDevice
->Supports
|= (UINT64
)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE
|
1219 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
|
1220 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1225 // Set the attributes to be checked for common PCI devices and PPB or P2C
1226 // Since some devices only support part of them, it is better to set the
1227 // attribute according to its command or bridge control register
1229 Command
= EFI_PCI_COMMAND_IO_SPACE
|
1230 EFI_PCI_COMMAND_MEMORY_SPACE
|
1231 EFI_PCI_COMMAND_BUS_MASTER
|
1232 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
;
1234 BridgeControl
= EFI_PCI_BRIDGE_CONTROL_ISA
| EFI_PCI_BRIDGE_CONTROL_VGA
| EFI_PCI_BRIDGE_CONTROL_VGA_16
;
1237 // Test whether the device can support attributes above
1239 PciTestSupportedAttribute (PciIoDevice
, &Command
, &BridgeControl
, &OldCommand
, &OldBridgeControl
);
1242 // Set the supported attributes for specified PCI device
1244 PciSetDeviceAttribute (PciIoDevice
, Command
, BridgeControl
, EFI_SET_SUPPORTS
);
1247 // Set the current attributes for specified PCI device
1249 PciSetDeviceAttribute (PciIoDevice
, OldCommand
, OldBridgeControl
, EFI_SET_ATTRIBUTES
);
1252 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL
1253 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.
1254 if (!PciIoDevice
->IsPciExp
) {
1255 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE
);
1259 FastB2BSupport
= TRUE
;
1262 // P2C can not support FB2B on the secondary side
1264 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
1265 FastB2BSupport
= FALSE
;
1269 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1271 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1272 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1274 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1275 Status
= DetermineDeviceAttribute (Temp
);
1276 if (EFI_ERROR (Status
)) {
1280 // Detect Fast Back to Back support for the device under the bridge
1282 Status
= GetFastBackToBackSupport (Temp
, PCI_PRIMARY_STATUS_OFFSET
);
1283 if (FastB2BSupport
&& EFI_ERROR (Status
)) {
1284 FastB2BSupport
= FALSE
;
1287 CurrentLink
= CurrentLink
->ForwardLink
;
1290 // Set or clear Fast Back to Back bit for the whole bridge
1292 if (!IsListEmpty (&PciIoDevice
->ChildList
)) {
1294 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
1296 Status
= GetFastBackToBackSupport (PciIoDevice
, PCI_BRIDGE_STATUS_REGISTER_OFFSET
);
1298 if (EFI_ERROR (Status
) || (!FastB2BSupport
)) {
1299 FastB2BSupport
= FALSE
;
1300 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1302 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1306 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1307 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1308 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1309 if (FastB2BSupport
) {
1310 PCI_ENABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1312 PCI_DISABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1315 CurrentLink
= CurrentLink
->ForwardLink
;
1319 // End for IsListEmpty
1325 This routine is used to update the bar information for those incompatible PCI device.
1327 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1330 @retval EFI_SUCCESS Successfully updated bar information.
1331 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1336 IN OUT PCI_IO_DEVICE
*PciIoDevice
1342 VOID
*Configuration
;
1343 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Ptr
;
1345 Configuration
= NULL
;
1346 Status
= EFI_SUCCESS
;
1348 if (gIncompatiblePciDeviceSupport
== NULL
) {
1350 // It can only be supported after the Incompatible PCI Device
1351 // Support Protocol has been installed
1353 Status
= gBS
->LocateProtocol (
1354 &gEfiIncompatiblePciDeviceSupportProtocolGuid
,
1356 (VOID
**) &gIncompatiblePciDeviceSupport
1359 if (Status
== EFI_SUCCESS
) {
1361 // Check whether the device belongs to incompatible devices from protocol or not
1362 // If it is , then get its special requirement in the ACPI table
1364 Status
= gIncompatiblePciDeviceSupport
->CheckDevice (
1365 gIncompatiblePciDeviceSupport
,
1366 PciIoDevice
->Pci
.Hdr
.VendorId
,
1367 PciIoDevice
->Pci
.Hdr
.DeviceId
,
1368 PciIoDevice
->Pci
.Hdr
.RevisionID
,
1369 PciIoDevice
->Pci
.Device
.SubsystemVendorID
,
1370 PciIoDevice
->Pci
.Device
.SubsystemID
,
1376 if (EFI_ERROR (Status
) || Configuration
== NULL
) {
1377 return EFI_UNSUPPORTED
;
1381 // Update PCI device information from the ACPI table
1383 Ptr
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
;
1385 while (Ptr
->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
1387 if (Ptr
->Desc
!= ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
1389 // The format is not support
1394 for (BarIndex
= 0; BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
1395 if ((Ptr
->AddrTranslationOffset
!= MAX_UINT64
) &&
1396 (Ptr
->AddrTranslationOffset
!= MAX_UINT8
) &&
1397 (Ptr
->AddrTranslationOffset
!= BarIndex
)
1400 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).
1401 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.
1402 // Comparing against MAX_UINT8 is to keep backward compatibility.
1408 switch (Ptr
->ResType
) {
1409 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
1412 // Make sure the bar is memory type
1414 if (CheckBarType (PciIoDevice
, (UINT8
) BarIndex
, PciBarTypeMem
)) {
1418 // Ignored if granularity is 0.
1419 // Ignored if PCI BAR is I/O or 32-bit memory.
1420 // If PCI BAR is 64-bit memory and granularity is 32, then
1421 // the PCI BAR resource is allocated below 4GB.
1422 // If PCI BAR is 64-bit memory and granularity is 64, then
1423 // the PCI BAR resource is allocated above 4GB.
1425 if (PciIoDevice
->PciBar
[BarIndex
].BarType
== PciBarTypeMem64
) {
1426 switch (Ptr
->AddrSpaceGranularity
) {
1428 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1430 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= TRUE
;
1437 if (PciIoDevice
->PciBar
[BarIndex
].BarType
== PciBarTypePMem64
) {
1438 switch (Ptr
->AddrSpaceGranularity
) {
1440 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1442 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= TRUE
;
1451 case ACPI_ADDRESS_SPACE_TYPE_IO
:
1454 // Make sure the bar is IO type
1456 if (CheckBarType (PciIoDevice
, (UINT8
) BarIndex
, PciBarTypeIo
)) {
1465 // Update the new alignment for the device
1467 SetNewAlign (&(PciIoDevice
->PciBar
[BarIndex
].Alignment
), Ptr
->AddrRangeMax
);
1470 // Update the new length for the device
1472 if (Ptr
->AddrLen
!= 0) {
1473 PciIoDevice
->PciBar
[BarIndex
].Length
= Ptr
->AddrLen
;
1481 FreePool (Configuration
);
1487 This routine will update the alignment with the new alignment.
1488 Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep
1489 backward compatibility.
1491 @param Alignment Input Old alignment. Output updated alignment.
1492 @param NewAlignment New alignment.
1497 IN OUT UINT64
*Alignment
,
1498 IN UINT64 NewAlignment
1501 UINT64 OldAlignment
;
1505 // The new alignment is the same as the original,
1508 if ((NewAlignment
== 0) || (NewAlignment
== OLD_ALIGN
)) {
1512 // Check the validity of the parameter
1514 if (NewAlignment
!= EVEN_ALIGN
&&
1515 NewAlignment
!= SQUAD_ALIGN
&&
1516 NewAlignment
!= DQUAD_ALIGN
) {
1517 *Alignment
= NewAlignment
;
1521 OldAlignment
= (*Alignment
) + 1;
1525 // Get the first non-zero hex value of the length
1527 while ((OldAlignment
& 0x0F) == 0x00) {
1528 OldAlignment
= RShiftU64 (OldAlignment
, 4);
1533 // Adjust the alignment to even, quad or double quad boundary
1535 if (NewAlignment
== EVEN_ALIGN
) {
1536 if ((OldAlignment
& 0x01) != 0) {
1537 OldAlignment
= OldAlignment
+ 2 - (OldAlignment
& 0x01);
1539 } else if (NewAlignment
== SQUAD_ALIGN
) {
1540 if ((OldAlignment
& 0x03) != 0) {
1541 OldAlignment
= OldAlignment
+ 4 - (OldAlignment
& 0x03);
1543 } else if (NewAlignment
== DQUAD_ALIGN
) {
1544 if ((OldAlignment
& 0x07) != 0) {
1545 OldAlignment
= OldAlignment
+ 8 - (OldAlignment
& 0x07);
1550 // Update the old value
1552 NewAlignment
= LShiftU64 (OldAlignment
, ShiftBit
) - 1;
1553 *Alignment
= NewAlignment
;
1559 Parse PCI IOV VF bar information and fill them into PCI device instance.
1561 @param PciIoDevice Pci device instance.
1562 @param Offset Bar offset.
1563 @param BarIndex Bar index.
1565 @return Next bar offset.
1570 IN PCI_IO_DEVICE
*PciIoDevice
,
1576 UINT32 OriginalValue
;
1581 // Ensure it is called properly
1583 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
1584 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
1591 Status
= VfBarExisted (
1598 if (EFI_ERROR (Status
)) {
1599 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1600 PciIoDevice
->VfPciBar
[BarIndex
].Length
= 0;
1601 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1604 // Scan all the BARs anyway
1606 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT16
) Offset
;
1610 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT16
) Offset
;
1611 if ((Value
& 0x01) != 0) {
1613 // Device I/Os. Impossible
1622 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1624 switch (Value
& 0x07) {
1627 //memory space; anywhere in 32 bit address space
1630 if ((Value
& 0x08) != 0) {
1631 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1633 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1636 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1637 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1642 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1646 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1647 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1653 // memory space; anywhere in 64 bit address space
1656 if ((Value
& 0x08) != 0) {
1657 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1659 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1663 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1664 // is regarded as an extension for the first bar. As a result
1665 // the sizing will be conducted on combined 64 bit value
1666 // Here just store the masked first 32bit value for future size
1669 PciIoDevice
->VfPciBar
[BarIndex
].Length
= Value
& Mask
;
1670 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1672 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1673 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1677 // Increment the offset to point to next DWORD
1681 Status
= VfBarExisted (
1688 if (EFI_ERROR (Status
)) {
1689 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1694 // Fix the length to support some special 64 bit BAR
1696 Value
|= ((UINT32
) -1 << HighBitSet32 (Value
));
1699 // Calculate the size of 64bit bar
1701 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
) OriginalValue
, 32);
1703 PciIoDevice
->VfPciBar
[BarIndex
].Length
= PciIoDevice
->VfPciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
) Value
, 32);
1704 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(PciIoDevice
->VfPciBar
[BarIndex
].Length
)) + 1;
1705 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1710 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1714 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1715 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1724 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1725 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1726 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1728 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1729 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1737 // Check the length again so as to keep compatible with some special bars
1739 if (PciIoDevice
->VfPciBar
[BarIndex
].Length
== 0) {
1740 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1741 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1742 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1746 // Increment number of bar
1752 Parse PCI bar information and fill them into PCI device instance.
1754 @param PciIoDevice Pci device instance.
1755 @param Offset Bar offset.
1756 @param BarIndex Bar index.
1758 @return Next bar offset.
1763 IN PCI_IO_DEVICE
*PciIoDevice
,
1769 UINT32 OriginalValue
;
1776 Status
= BarExisted (
1783 if (EFI_ERROR (Status
)) {
1784 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= 0;
1785 PciIoDevice
->PciBar
[BarIndex
].Length
= 0;
1786 PciIoDevice
->PciBar
[BarIndex
].Alignment
= 0;
1789 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1791 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
) Offset
;
1795 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= FALSE
;
1796 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
) Offset
;
1797 if ((Value
& 0x01) != 0) {
1803 if ((Value
& 0xFFFF0000) != 0) {
1807 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo32
;
1808 PciIoDevice
->PciBar
[BarIndex
].Length
= ((~(Value
& Mask
)) + 1);
1809 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1815 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo16
;
1816 PciIoDevice
->PciBar
[BarIndex
].Length
= 0x0000FFFF & ((~(Value
& Mask
)) + 1);
1817 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1821 // Workaround. Some platforms implement IO bar with 0 length
1822 // Need to treat it as no-bar
1824 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1825 PciIoDevice
->PciBar
[BarIndex
].BarType
= (PCI_BAR_TYPE
) 0;
1828 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1834 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1836 switch (Value
& 0x07) {
1839 //memory space; anywhere in 32 bit address space
1842 if ((Value
& 0x08) != 0) {
1843 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1845 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1848 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1849 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1851 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1853 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1855 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1860 // memory space; anywhere in 64 bit address space
1863 if ((Value
& 0x08) != 0) {
1864 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1866 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1870 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1871 // is regarded as an extension for the first bar. As a result
1872 // the sizing will be conducted on combined 64 bit value
1873 // Here just store the masked first 32bit value for future size
1876 PciIoDevice
->PciBar
[BarIndex
].Length
= Value
& Mask
;
1877 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1880 // Increment the offset to point to next DWORD
1884 Status
= BarExisted (
1891 if (EFI_ERROR (Status
)) {
1893 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
1895 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1897 // some device implement MMIO bar with 0 length, need to treat it as no-bar
1899 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1905 // Fix the length to support some special 64 bit BAR
1908 DEBUG ((EFI_D_INFO
, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));
1909 Value
= (UINT32
) -1;
1911 Value
|= ((UINT32
)(-1) << HighBitSet32 (Value
));
1915 // Calculate the size of 64bit bar
1917 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
) OriginalValue
, 32);
1919 PciIoDevice
->PciBar
[BarIndex
].Length
= PciIoDevice
->PciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
) Value
, 32);
1920 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(PciIoDevice
->PciBar
[BarIndex
].Length
)) + 1;
1921 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1923 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1925 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1927 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1936 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1937 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1938 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1940 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1942 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1944 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 Create and initialize general PCI I/O device instance for
2138 PCI device/bridge device/hotplug bridge device.
2140 @param Bridge Parent bridge instance.
2141 @param Pci Input Pci information block.
2142 @param Bus Device Bus NO.
2143 @param Device Device device NO.
2144 @param Func Device func NO.
2146 @return Instance of PCI device. NULL means no instance created.
2151 IN PCI_IO_DEVICE
*Bridge
,
2158 PCI_IO_DEVICE
*PciIoDevice
;
2159 EFI_PCI_IO_PROTOCOL
*PciIo
;
2162 PciIoDevice
= AllocateZeroPool (sizeof (PCI_IO_DEVICE
));
2163 if (PciIoDevice
== NULL
) {
2167 PciIoDevice
->Signature
= PCI_IO_DEVICE_SIGNATURE
;
2168 PciIoDevice
->Handle
= NULL
;
2169 PciIoDevice
->PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
2170 PciIoDevice
->DevicePath
= NULL
;
2171 PciIoDevice
->BusNumber
= Bus
;
2172 PciIoDevice
->DeviceNumber
= Device
;
2173 PciIoDevice
->FunctionNumber
= Func
;
2174 PciIoDevice
->Decodes
= 0;
2176 if (gFullEnumeration
) {
2177 PciIoDevice
->Allocated
= FALSE
;
2179 PciIoDevice
->Allocated
= TRUE
;
2182 PciIoDevice
->Registered
= FALSE
;
2183 PciIoDevice
->Attributes
= 0;
2184 PciIoDevice
->Supports
= 0;
2185 PciIoDevice
->BusOverride
= FALSE
;
2186 PciIoDevice
->AllOpRomProcessed
= FALSE
;
2188 PciIoDevice
->IsPciExp
= FALSE
;
2190 CopyMem (&(PciIoDevice
->Pci
), Pci
, sizeof (PCI_TYPE01
));
2193 // Initialize the PCI I/O instance structure
2195 InitializePciIoInstance (PciIoDevice
);
2196 InitializePciDriverOverrideInstance (PciIoDevice
);
2197 InitializePciLoadFile2 (PciIoDevice
);
2198 PciIo
= &PciIoDevice
->PciIo
;
2201 // Create a device path for this PCI device and store it into its private data
2203 CreatePciDevicePath (
2209 // Detect if PCI Express Device
2211 PciIoDevice
->PciExpressCapabilityOffset
= 0;
2212 Status
= LocateCapabilityRegBlock (
2214 EFI_PCI_CAPABILITY_ID_PCIEXP
,
2215 &PciIoDevice
->PciExpressCapabilityOffset
,
2218 if (!EFI_ERROR (Status
)) {
2219 PciIoDevice
->IsPciExp
= TRUE
;
2223 // Now we can do the authentication check for the device.
2225 Status
= AuthenticatePciDevice (PciIoDevice
);
2227 // If authentication fails, skip this device.
2229 if (EFI_ERROR(Status
)) {
2230 if (PciIoDevice
->DevicePath
!= NULL
) {
2231 FreePool (PciIoDevice
->DevicePath
);
2233 FreePool (PciIoDevice
);
2237 if (PcdGetBool (PcdAriSupport
)) {
2239 // Check if the device is an ARI device.
2241 Status
= LocatePciExpressCapabilityRegBlock (
2243 EFI_PCIE_CAPABILITY_ID_ARI
,
2244 &PciIoDevice
->AriCapabilityOffset
,
2247 if (!EFI_ERROR (Status
)) {
2249 // We need to enable ARI feature before calculate BusReservation,
2250 // because FirstVFOffset and VFStride may change after that.
2252 EFI_PCI_IO_PROTOCOL
*ParentPciIo
;
2256 // Check if its parent supports ARI forwarding.
2258 ParentPciIo
= &Bridge
->PciIo
;
2259 ParentPciIo
->Pci
.Read (
2261 EfiPciIoWidthUint32
,
2262 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET
,
2266 if ((Data32
& EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING
) != 0) {
2268 // ARI forward support in bridge, so enable it.
2270 ParentPciIo
->Pci
.Read (
2272 EfiPciIoWidthUint32
,
2273 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET
,
2277 if ((Data32
& EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING
) == 0) {
2278 Data32
|= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING
;
2279 ParentPciIo
->Pci
.Write (
2281 EfiPciIoWidthUint32
,
2282 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET
,
2288 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
2290 Bridge
->DeviceNumber
,
2291 Bridge
->FunctionNumber
2296 DEBUG ((EFI_D_INFO
, " ARI: CapOffset = 0x%x\n", PciIoDevice
->AriCapabilityOffset
));
2301 // Initialization for SR-IOV
2304 if (PcdGetBool (PcdSrIovSupport
)) {
2305 Status
= LocatePciExpressCapabilityRegBlock (
2307 EFI_PCIE_CAPABILITY_ID_SRIOV
,
2308 &PciIoDevice
->SrIovCapabilityOffset
,
2311 if (!EFI_ERROR (Status
)) {
2312 UINT32 SupportedPageSize
;
2314 UINT16 FirstVFOffset
;
2320 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
2322 if (PcdGetBool (PcdAriSupport
) && PciIoDevice
->AriCapabilityOffset
!= 0) {
2325 EfiPciIoWidthUint16
,
2326 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL
,
2330 Data16
|= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY
;
2333 EfiPciIoWidthUint16
,
2334 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL
,
2341 // Calculate SystemPageSize
2346 EfiPciIoWidthUint32
,
2347 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE
,
2351 PciIoDevice
->SystemPageSize
= (PcdGet32 (PcdSrIovSystemPageSize
) & SupportedPageSize
);
2352 ASSERT (PciIoDevice
->SystemPageSize
!= 0);
2356 EfiPciIoWidthUint32
,
2357 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE
,
2359 &PciIoDevice
->SystemPageSize
2362 // Adjust SystemPageSize for Alignment usage later
2364 PciIoDevice
->SystemPageSize
<<= 12;
2367 // Calculate BusReservation for PCI IOV
2371 // Read First FirstVFOffset, InitialVFs, and VFStride
2375 EfiPciIoWidthUint16
,
2376 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF
,
2382 EfiPciIoWidthUint16
,
2383 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS
,
2385 &PciIoDevice
->InitialVFs
2389 EfiPciIoWidthUint16
,
2390 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE
,
2397 PFRid
= EFI_PCI_RID(Bus
, Device
, Func
);
2398 LastVF
= PFRid
+ FirstVFOffset
+ (PciIoDevice
->InitialVFs
- 1) * VFStride
;
2401 // Calculate ReservedBusNum for this PF
2403 PciIoDevice
->ReservedBusNum
= (UINT16
)(EFI_PCI_BUS_OF_RID (LastVF
) - Bus
+ 1);
2407 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
2408 SupportedPageSize
, PciIoDevice
->SystemPageSize
>> 12, FirstVFOffset
2412 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
2413 PciIoDevice
->InitialVFs
, PciIoDevice
->ReservedBusNum
, PciIoDevice
->SrIovCapabilityOffset
2418 if (PcdGetBool (PcdMrIovSupport
)) {
2419 Status
= LocatePciExpressCapabilityRegBlock (
2421 EFI_PCIE_CAPABILITY_ID_MRIOV
,
2422 &PciIoDevice
->MrIovCapabilityOffset
,
2425 if (!EFI_ERROR (Status
)) {
2426 DEBUG ((EFI_D_INFO
, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice
->MrIovCapabilityOffset
));
2430 PciIoDevice
->ResizableBarOffset
= 0;
2431 if (PcdGetBool (PcdPcieResizableBarSupport
)) {
2432 Status
= LocatePciExpressCapabilityRegBlock (
2434 PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID
,
2435 &PciIoDevice
->ResizableBarOffset
,
2438 if (!EFI_ERROR (Status
)) {
2439 PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl
;
2441 Offset
= PciIoDevice
->ResizableBarOffset
+ sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER
)
2442 + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY
),
2447 sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL
),
2448 &ResizableBarControl
2450 PciIoDevice
->ResizableBarNumber
= ResizableBarControl
.Bits
.ResizableBarNumber
;
2451 PciProgramResizableBar (PciIoDevice
, PciResizableBarMax
);
2456 // Initialize the reserved resource list
2458 InitializeListHead (&PciIoDevice
->ReservedResourceList
);
2461 // Initialize the driver list
2463 InitializeListHead (&PciIoDevice
->OptionRomDriverList
);
2466 // Initialize the child list
2468 InitializeListHead (&PciIoDevice
->ChildList
);
2474 This routine is used to enumerate entire pci bus system
2475 in a given platform.
2477 It is only called on the second start on the same Root Bridge.
2479 @param Controller Parent bridge handler.
2481 @retval EFI_SUCCESS PCI enumeration finished successfully.
2482 @retval other Some error occurred when enumerating the pci bus system.
2486 PciEnumeratorLight (
2487 IN EFI_HANDLE Controller
2492 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2493 PCI_IO_DEVICE
*RootBridgeDev
;
2496 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
2499 MaxBus
= PCI_MAX_BUS
;
2503 // If this root bridge has been already enumerated, then return successfully
2505 if (GetRootBridgeByHandle (Controller
) != NULL
) {
2510 // Open pci root bridge io protocol
2512 Status
= gBS
->OpenProtocol (
2514 &gEfiPciRootBridgeIoProtocolGuid
,
2515 (VOID
**) &PciRootBridgeIo
,
2516 gPciBusDriverBinding
.DriverBindingHandle
,
2518 EFI_OPEN_PROTOCOL_BY_DRIVER
2520 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
2524 Status
= PciRootBridgeIo
->Configuration (PciRootBridgeIo
, (VOID
**) &Descriptors
);
2526 if (EFI_ERROR (Status
)) {
2530 while (PciGetBusRange (&Descriptors
, &MinBus
, &MaxBus
, NULL
) == EFI_SUCCESS
) {
2533 // Create a device node for root bridge device with a NULL host bridge controller handle
2535 RootBridgeDev
= CreateRootBridge (Controller
);
2537 if (RootBridgeDev
== NULL
) {
2543 // Record the root bridge-io protocol
2545 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2547 Status
= PciPciDeviceInfoCollector (
2552 if (!EFI_ERROR (Status
)) {
2555 // Remove those PCI devices which are rejected when full enumeration
2557 RemoveRejectedPciDevices (RootBridgeDev
->Handle
, RootBridgeDev
);
2560 // Process option rom light
2562 ProcessOptionRomLight (RootBridgeDev
);
2565 // Determine attributes for all devices under this root bridge
2567 DetermineDeviceAttribute (RootBridgeDev
);
2570 // If successfully, insert the node into device pool
2572 InsertRootBridge (RootBridgeDev
);
2576 // If unsuccessfully, destroy the entire node
2578 DestroyRootBridge (RootBridgeDev
);
2588 Get bus range from PCI resource descriptor list.
2590 @param Descriptors A pointer to the address space descriptor.
2591 @param MinBus The min bus returned.
2592 @param MaxBus The max bus returned.
2593 @param BusRange The bus range returned.
2595 @retval EFI_SUCCESS Successfully got bus range.
2596 @retval EFI_NOT_FOUND Can not find the specific bus.
2601 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
**Descriptors
,
2604 OUT UINT16
*BusRange
2607 while ((*Descriptors
)->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
2608 if ((*Descriptors
)->ResType
== ACPI_ADDRESS_SPACE_TYPE_BUS
) {
2609 if (MinBus
!= NULL
) {
2610 *MinBus
= (UINT16
) (*Descriptors
)->AddrRangeMin
;
2613 if (MaxBus
!= NULL
) {
2614 *MaxBus
= (UINT16
) (*Descriptors
)->AddrRangeMax
;
2617 if (BusRange
!= NULL
) {
2618 *BusRange
= (UINT16
) (*Descriptors
)->AddrLen
;
2627 return EFI_NOT_FOUND
;
2631 This routine can be used to start the root bridge.
2633 @param RootBridgeDev Pci device instance.
2635 @retval EFI_SUCCESS This device started.
2636 @retval other Failed to get PCI Root Bridge I/O protocol.
2640 StartManagingRootBridge (
2641 IN PCI_IO_DEVICE
*RootBridgeDev
2644 EFI_HANDLE RootBridgeHandle
;
2646 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2649 // Get the root bridge handle
2651 RootBridgeHandle
= RootBridgeDev
->Handle
;
2652 PciRootBridgeIo
= NULL
;
2655 // Get the pci root bridge io protocol
2657 Status
= gBS
->OpenProtocol (
2659 &gEfiPciRootBridgeIoProtocolGuid
,
2660 (VOID
**) &PciRootBridgeIo
,
2661 gPciBusDriverBinding
.DriverBindingHandle
,
2663 EFI_OPEN_PROTOCOL_BY_DRIVER
2666 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
2671 // Store the PciRootBridgeIo protocol into root bridge private data
2673 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2680 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2682 @param PciIoDevice Pci device instance.
2684 @retval TRUE This device should be rejected.
2685 @retval FALSE This device shouldn't be rejected.
2689 IsPciDeviceRejected (
2690 IN PCI_IO_DEVICE
*PciIoDevice
2700 // PPB should be skip!
2702 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
2706 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
2708 // Only test base registers for P2C
2710 for (BarOffset
= 0x1C; BarOffset
<= 0x38; BarOffset
+= 2 * sizeof (UINT32
)) {
2712 Mask
= (BarOffset
< 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2713 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2714 if (EFI_ERROR (Status
)) {
2718 TestValue
= TestValue
& Mask
;
2719 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2721 // The bar isn't programed, so it should be rejected
2730 for (BarOffset
= 0x14; BarOffset
<= 0x24; BarOffset
+= sizeof (UINT32
)) {
2734 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2735 if (EFI_ERROR (Status
)) {
2739 if ((TestValue
& 0x01) != 0) {
2745 TestValue
= TestValue
& Mask
;
2746 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2756 TestValue
= TestValue
& Mask
;
2758 if ((TestValue
& 0x07) == 0x04) {
2763 BarOffset
+= sizeof (UINT32
);
2764 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2767 // Test its high 32-Bit BAR
2769 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2770 if (TestValue
== OldValue
) {
2780 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2791 Reset all bus number from specific bridge.
2793 @param Bridge Parent specific bridge.
2794 @param StartBusNumber Start bus number.
2798 ResetAllPpbBusNumber (
2799 IN PCI_IO_DEVICE
*Bridge
,
2800 IN UINT8 StartBusNumber
2810 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2812 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
2814 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
2815 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
2818 // Check to see whether a pci device is present
2820 Status
= PciDevicePresent (
2828 if (EFI_ERROR (Status
) && Func
== 0) {
2830 // go to next device if there is no Function 0
2835 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
))) {
2838 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
2839 Status
= PciRootBridgeIo
->Pci
.Read (
2846 SecondaryBus
= (UINT8
)(Register
>> 8);
2848 if (SecondaryBus
!= 0) {
2849 ResetAllPpbBusNumber (Bridge
, SecondaryBus
);
2853 // Reset register 18h, 19h, 1Ah on PCI Bridge
2855 Register
&= 0xFF000000;
2856 Status
= PciRootBridgeIo
->Pci
.Write (
2865 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
2867 // Skip sub functions, this is not a multi function device
2869 Func
= PCI_MAX_FUNC
;