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
++) {
110 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
112 // Check to see whether PCI device is present
114 Status
= PciDevicePresent (
115 Bridge
->PciRootBridgeIo
,
117 (UINT8
)StartBusNumber
,
122 if (EFI_ERROR (Status
) && (Func
== 0)) {
124 // go to next device if there is no Function 0
129 if (!EFI_ERROR (Status
)) {
131 // Call back to host bridge function
133 PreprocessController (Bridge
, (UINT8
)StartBusNumber
, Device
, Func
, EfiPciBeforeResourceCollection
);
136 // Collect all the information about the PCI device discovered
138 Status
= PciSearchDevice (
141 (UINT8
)StartBusNumber
,
148 // Recursively scan PCI busses on the other side of PCI-PCI bridges
151 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
) || IS_CARDBUS_BRIDGE (&Pci
))) {
153 // If it is PPB, we need to get the secondary bus to continue the enumeration
155 PciIo
= &(PciIoDevice
->PciIo
);
157 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
, 1, &SecBus
);
159 if (EFI_ERROR (Status
)) {
164 // Ensure secondary bus number is greater than the primary bus number to avoid
165 // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE
167 if (SecBus
<= StartBusNumber
) {
172 // Get resource padding for PPB
174 GetResourcePaddingPpb (PciIoDevice
);
177 // Deep enumerate the next level bus
179 Status
= PciPciDeviceInfoCollector (
185 if ((Func
== 0) && !IS_PCI_MULTI_FUNC (&Pci
)) {
187 // Skip sub functions, this is not a multi function device
199 Search required device and create PCI device instance.
201 @param Bridge Parent bridge instance.
202 @param Pci Input PCI device information block.
203 @param Bus PCI bus NO.
204 @param Device PCI device NO.
205 @param Func PCI func NO.
206 @param PciDevice Output of searched PCI device instance.
208 @retval EFI_SUCCESS Successfully created PCI device instance.
209 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
214 IN PCI_IO_DEVICE
*Bridge
,
219 OUT PCI_IO_DEVICE
**PciDevice
222 PCI_IO_DEVICE
*PciIoDevice
;
223 BOOLEAN IgnoreOptionRom
;
226 IgnoreOptionRom
= FALSE
;
230 "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",
231 IS_PCI_BRIDGE (Pci
) ? L
"PPB" :
232 IS_CARDBUS_BRIDGE (Pci
) ? L
"P2C" :
239 if (!IS_PCI_BRIDGE (Pci
)) {
240 if (IS_CARDBUS_BRIDGE (Pci
)) {
241 PciIoDevice
= GatherP2CInfo (
248 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
249 InitializeP2C (PciIoDevice
);
253 // Create private data for Pci Device
255 PciIoDevice
= GatherDeviceInfo (
265 // Create private data for PPB
267 PciIoDevice
= GatherPpbInfo (
276 // Special initialization for PPB including making the PPB quiet
278 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
279 InitializePpb (PciIoDevice
);
283 if (PciIoDevice
== NULL
) {
284 return EFI_OUT_OF_RESOURCES
;
288 // Update the bar information for this PCI device so as to support some specific device
290 UpdatePciInfo (PciIoDevice
, &IgnoreOptionRom
);
292 if (PciIoDevice
->DevicePath
== NULL
) {
293 return EFI_OUT_OF_RESOURCES
;
297 // Detect this function has option rom
299 if (gFullEnumeration
) {
300 if (!IS_CARDBUS_BRIDGE (Pci
) && !IgnoreOptionRom
) {
301 GetOpRomInfo (PciIoDevice
);
304 ResetPowerManagementFeature (PciIoDevice
);
308 // Insert it into a global tree for future reference
310 InsertPciDevice (Bridge
, PciIoDevice
);
313 // Determine PCI device attributes
316 if (PciDevice
!= NULL
) {
317 *PciDevice
= PciIoDevice
;
324 Dump the PPB padding resource information.
326 @param PciIoDevice PCI IO instance.
327 @param ResourceType The desired resource type to dump.
328 PciBarTypeUnknown means to dump all types of resources.
331 DumpPpbPaddingResource (
332 IN PCI_IO_DEVICE
*PciIoDevice
,
333 IN PCI_BAR_TYPE ResourceType
336 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
339 if (PciIoDevice
->ResourcePaddingDescriptors
== NULL
) {
343 if ((ResourceType
== PciBarTypeIo16
) || (ResourceType
== PciBarTypeIo32
)) {
344 ResourceType
= PciBarTypeIo
;
347 for (Descriptor
= PciIoDevice
->ResourcePaddingDescriptors
; Descriptor
->Desc
!= ACPI_END_TAG_DESCRIPTOR
; Descriptor
++) {
348 Type
= PciBarTypeUnknown
;
349 if ((Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) && (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_IO
)) {
351 } else if ((Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
) && (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
)) {
352 if (Descriptor
->AddrSpaceGranularity
== 32) {
356 if (Descriptor
->SpecificFlag
== EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) {
357 Type
= PciBarTypePMem32
;
363 if (Descriptor
->SpecificFlag
== 0) {
364 Type
= PciBarTypeMem32
;
368 if (Descriptor
->AddrSpaceGranularity
== 64) {
372 if (Descriptor
->SpecificFlag
== EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) {
373 Type
= PciBarTypePMem64
;
379 if (Descriptor
->SpecificFlag
== 0) {
380 Type
= PciBarTypeMem64
;
385 if ((Type
!= PciBarTypeUnknown
) && ((ResourceType
== PciBarTypeUnknown
) || (ResourceType
== Type
))) {
388 " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
390 Descriptor
->AddrRangeMax
,
398 Dump the PCI BAR information.
400 @param PciIoDevice PCI IO instance.
404 IN PCI_IO_DEVICE
*PciIoDevice
409 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
410 if (PciIoDevice
->PciBar
[Index
].BarType
== PciBarTypeUnknown
) {
416 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
418 mBarTypeStr
[MIN (PciIoDevice
->PciBar
[Index
].BarType
, PciBarTypeMaxType
)],
419 PciIoDevice
->PciBar
[Index
].Alignment
,
420 PciIoDevice
->PciBar
[Index
].Length
,
421 PciIoDevice
->PciBar
[Index
].Offset
425 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
426 if ((PciIoDevice
->VfPciBar
[Index
].BarType
== PciBarTypeUnknown
) && (PciIoDevice
->VfPciBar
[Index
].Length
== 0)) {
432 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
434 mBarTypeStr
[MIN (PciIoDevice
->VfPciBar
[Index
].BarType
, PciBarTypeMaxType
)],
435 PciIoDevice
->VfPciBar
[Index
].Alignment
,
436 PciIoDevice
->VfPciBar
[Index
].Length
,
437 PciIoDevice
->VfPciBar
[Index
].Offset
441 DEBUG ((DEBUG_INFO
, "\n"));
445 Create PCI device instance for PCI device.
447 @param Bridge Parent bridge instance.
448 @param Pci Input PCI device information block.
449 @param Bus PCI device Bus NO.
450 @param Device PCI device Device NO.
451 @param Func PCI device's func NO.
453 @return Created PCI device instance.
458 IN PCI_IO_DEVICE
*Bridge
,
467 PCI_IO_DEVICE
*PciIoDevice
;
469 PciIoDevice
= CreatePciIoDevice (
477 if (PciIoDevice
== NULL
) {
482 // If it is a full enumeration, disconnect the device in advance
484 if (gFullEnumeration
) {
485 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
489 // Start to parse the bars
491 for (Offset
= 0x10, BarIndex
= 0; Offset
<= 0x24 && BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
492 Offset
= PciParseBar (PciIoDevice
, Offset
, BarIndex
);
496 // Parse the SR-IOV VF bars
498 if (PcdGetBool (PcdSrIovSupport
) && (PciIoDevice
->SrIovCapabilityOffset
!= 0)) {
499 for (Offset
= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0
, BarIndex
= 0;
500 Offset
<= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5
;
503 ASSERT (BarIndex
< PCI_MAX_BAR
);
504 Offset
= PciIovParseVfBar (PciIoDevice
, Offset
, BarIndex
);
509 DumpPciBars (PciIoDevice
);
515 Create PCI device instance for PCI-PCI bridge.
517 @param Bridge Parent bridge instance.
518 @param Pci Input PCI device information block.
519 @param Bus PCI device Bus NO.
520 @param Device PCI device Device NO.
521 @param Func PCI device's func NO.
523 @return Created PCI device instance.
528 IN PCI_IO_DEVICE
*Bridge
,
535 PCI_IO_DEVICE
*PciIoDevice
;
538 EFI_PCI_IO_PROTOCOL
*PciIo
;
540 UINT32 PMemBaseLimit
;
541 UINT16 PrefetchableMemoryBase
;
542 UINT16 PrefetchableMemoryLimit
;
544 PciIoDevice
= CreatePciIoDevice (
552 if (PciIoDevice
== NULL
) {
556 if (gFullEnumeration
) {
557 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
560 // Initialize the bridge control register
562 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED
);
566 // PPB can have two BARs
568 if (PciParseBar (PciIoDevice
, 0x10, PPB_BAR_0
) == 0x14) {
572 PciParseBar (PciIoDevice
, 0x14, PPB_BAR_1
);
575 PciIo
= &PciIoDevice
->PciIo
;
578 // Test whether it support 32 decode or not
580 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
581 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &gAllOne
);
582 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
583 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
586 if ((Value
& 0x01) != 0) {
587 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
589 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO16_DECODE_SUPPORTED
;
594 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
595 // PCI bridge supporting non-standard I/O window alignment less than 4K.
598 PciIoDevice
->BridgeIoAlignment
= 0xFFF;
599 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe
)) {
601 // Check any bits of bit 3-1 of I/O Base Register are writable.
602 // if so, it is assumed non-standard I/O window alignment is supported by this bridge.
603 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.
605 Value
= (UINT8
)(Temp
^ (BIT3
| BIT2
| BIT1
));
606 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
607 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
608 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
609 Value
= (UINT8
)((Value
^ Temp
) & (BIT3
| BIT2
| BIT1
));
612 PciIoDevice
->BridgeIoAlignment
= 0x7FF;
615 PciIoDevice
->BridgeIoAlignment
= 0x3FF;
617 case BIT3
| BIT2
| BIT1
:
618 PciIoDevice
->BridgeIoAlignment
= 0x1FF;
623 Status
= BarExisted (
631 // Test if it supports 64 memory or not
633 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit
635 // 0 - the bridge supports only 32 bit addresses.
636 // 1 - the bridge supports 64-bit addresses.
638 PrefetchableMemoryBase
= (UINT16
)(PMemBaseLimit
& 0xffff);
639 PrefetchableMemoryLimit
= (UINT16
)(PMemBaseLimit
>> 16);
640 if (!EFI_ERROR (Status
) &&
641 ((PrefetchableMemoryBase
& 0x000f) == 0x0001) &&
642 ((PrefetchableMemoryLimit
& 0x000f) == 0x0001))
644 Status
= BarExisted (
651 if (!EFI_ERROR (Status
)) {
652 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
653 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED
;
655 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
660 // Memory 32 code is required for ppb
662 PciIoDevice
->Decodes
|= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
;
664 GetResourcePaddingPpb (PciIoDevice
);
667 DumpPpbPaddingResource (PciIoDevice
, PciBarTypeUnknown
);
668 DumpPciBars (PciIoDevice
);
675 Create PCI device instance for PCI Card bridge device.
677 @param Bridge Parent bridge instance.
678 @param Pci Input PCI device information block.
679 @param Bus PCI device Bus NO.
680 @param Device PCI device Device NO.
681 @param Func PCI device's func NO.
683 @return Created PCI device instance.
688 IN PCI_IO_DEVICE
*Bridge
,
695 PCI_IO_DEVICE
*PciIoDevice
;
697 PciIoDevice
= CreatePciIoDevice (
705 if (PciIoDevice
== NULL
) {
709 if (gFullEnumeration
) {
710 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
713 // Initialize the bridge control register
715 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED
);
719 // P2C only has one bar that is in 0x10
721 PciParseBar (PciIoDevice
, 0x10, P2C_BAR_0
);
724 // Read PciBar information from the bar register
726 GetBackPcCardBar (PciIoDevice
);
727 PciIoDevice
->Decodes
= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
|
728 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
|
729 EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
732 DumpPciBars (PciIoDevice
);
739 Create device path for pci device.
741 @param ParentDevicePath Parent bridge's path.
742 @param PciIoDevice Pci device instance.
744 @return Device path protocol instance for specific pci device.
747 EFI_DEVICE_PATH_PROTOCOL
*
748 CreatePciDevicePath (
749 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
750 IN PCI_IO_DEVICE
*PciIoDevice
753 PCI_DEVICE_PATH PciNode
;
756 // Create PCI device path
758 PciNode
.Header
.Type
= HARDWARE_DEVICE_PATH
;
759 PciNode
.Header
.SubType
= HW_PCI_DP
;
760 SetDevicePathNodeLength (&PciNode
.Header
, sizeof (PciNode
));
762 PciNode
.Device
= PciIoDevice
->DeviceNumber
;
763 PciNode
.Function
= PciIoDevice
->FunctionNumber
;
764 PciIoDevice
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, &PciNode
.Header
);
766 return PciIoDevice
->DevicePath
;
770 Check whether the PCI IOV VF bar is existed or not.
772 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
773 @param Offset The offset.
774 @param BarLengthValue The bar length value returned.
775 @param OriginalBarValue The original bar value returned.
777 @retval EFI_NOT_FOUND The bar doesn't exist.
778 @retval EFI_SUCCESS The bar exist.
783 IN PCI_IO_DEVICE
*PciIoDevice
,
785 OUT UINT32
*BarLengthValue
,
786 OUT UINT32
*OriginalBarValue
789 EFI_PCI_IO_PROTOCOL
*PciIo
;
790 UINT32 OriginalValue
;
795 // Ensure it is called properly
797 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
798 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
799 return EFI_NOT_FOUND
;
802 PciIo
= &PciIoDevice
->PciIo
;
805 // Preserve the original value
808 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
811 // Raise TPL to high level to disable timer interrupt while the BAR is probed
813 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
815 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &gAllOne
);
816 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &Value
);
819 // Write back the original value
821 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
824 // Restore TPL to its original level
826 gBS
->RestoreTPL (OldTpl
);
828 if (BarLengthValue
!= NULL
) {
829 *BarLengthValue
= Value
;
832 if (OriginalBarValue
!= NULL
) {
833 *OriginalBarValue
= OriginalValue
;
837 return EFI_NOT_FOUND
;
844 Check whether the bar is existed or not.
846 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
847 @param Offset The offset.
848 @param BarLengthValue The bar length value returned.
849 @param OriginalBarValue The original bar value returned.
851 @retval EFI_NOT_FOUND The bar doesn't exist.
852 @retval EFI_SUCCESS The bar exist.
857 IN PCI_IO_DEVICE
*PciIoDevice
,
859 OUT UINT32
*BarLengthValue
,
860 OUT UINT32
*OriginalBarValue
863 EFI_PCI_IO_PROTOCOL
*PciIo
;
864 UINT32 OriginalValue
;
868 PciIo
= &PciIoDevice
->PciIo
;
871 // Preserve the original value
873 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &OriginalValue
);
876 // Raise TPL to high level to disable timer interrupt while the BAR is probed
878 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
880 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &gAllOne
);
881 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &Value
);
884 // Write back the original value
886 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
)Offset
, 1, &OriginalValue
);
889 // Restore TPL to its original level
891 gBS
->RestoreTPL (OldTpl
);
893 if (BarLengthValue
!= NULL
) {
894 *BarLengthValue
= Value
;
897 if (OriginalBarValue
!= NULL
) {
898 *OriginalBarValue
= OriginalValue
;
902 return EFI_NOT_FOUND
;
909 Test whether the device can support given attributes.
911 @param PciIoDevice Pci device instance.
912 @param Command Input command register value, and
913 returned supported register value.
914 @param BridgeControl Input bridge control value for PPB or P2C, and
915 returned supported bridge control value.
916 @param OldCommand Returned and stored old command register offset.
917 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
921 PciTestSupportedAttribute (
922 IN PCI_IO_DEVICE
*PciIoDevice
,
923 IN OUT UINT16
*Command
,
924 IN OUT UINT16
*BridgeControl
,
925 OUT UINT16
*OldCommand
,
926 OUT UINT16
*OldBridgeControl
933 // Preserve the original value
935 PCI_READ_COMMAND_REGISTER (PciIoDevice
, OldCommand
);
938 // Raise TPL to high level to disable timer interrupt while the BAR is probed
940 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
941 CommandValue
= *Command
| *OldCommand
;
943 PCI_SET_COMMAND_REGISTER (PciIoDevice
, CommandValue
);
944 PCI_READ_COMMAND_REGISTER (PciIoDevice
, &CommandValue
);
946 *Command
= *Command
& CommandValue
;
948 // Write back the original value
950 PCI_SET_COMMAND_REGISTER (PciIoDevice
, *OldCommand
);
953 // Restore TPL to its original level
955 gBS
->RestoreTPL (OldTpl
);
957 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
) || IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
959 // Preserve the original value
961 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, OldBridgeControl
);
964 // Raise TPL to high level to disable timer interrupt while the BAR is probed
966 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
968 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *BridgeControl
);
969 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, BridgeControl
);
972 // Write back the original value
974 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *OldBridgeControl
);
977 // Restore TPL to its original level
979 gBS
->RestoreTPL (OldTpl
);
981 *OldBridgeControl
= 0;
987 Set the supported or current attributes of a PCI device.
989 @param PciIoDevice Structure pointer for PCI device.
990 @param Command Command register value.
991 @param BridgeControl Bridge control value for PPB or P2C.
992 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
996 PciSetDeviceAttribute (
997 IN PCI_IO_DEVICE
*PciIoDevice
,
999 IN UINT16 BridgeControl
,
1007 if ((Command
& EFI_PCI_COMMAND_IO_SPACE
) != 0) {
1008 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IO
;
1011 if ((Command
& EFI_PCI_COMMAND_MEMORY_SPACE
) != 0) {
1012 Attributes
|= EFI_PCI_IO_ATTRIBUTE_MEMORY
;
1015 if ((Command
& EFI_PCI_COMMAND_BUS_MASTER
) != 0) {
1016 Attributes
|= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
;
1019 if ((Command
& EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
) != 0) {
1020 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
1023 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_ISA
) != 0) {
1024 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_IO
;
1027 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA
) != 0) {
1028 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO
;
1029 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
1030 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
1033 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA_16
) != 0) {
1034 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
;
1035 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16
;
1038 if (Option
== EFI_SET_SUPPORTS
) {
1039 Attributes
|= (UINT64
)(EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
|
1040 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED
|
1041 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE
|
1042 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE
|
1043 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
|
1044 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1046 if (IS_PCI_LPC (&PciIoDevice
->Pci
)) {
1047 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO
;
1048 Attributes
|= (mReserveIsaAliases
? (UINT64
)EFI_PCI_IO_ATTRIBUTE_ISA_IO
: \
1049 (UINT64
)EFI_PCI_IO_ATTRIBUTE_ISA_IO_16
);
1052 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
) || IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
1054 // For bridge, it should support IDE attributes
1056 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
1057 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
1059 if (mReserveVgaAliases
) {
1060 Attributes
&= ~(UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
| \
1061 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16
);
1063 Attributes
&= ~(UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO
| \
1064 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
);
1067 if (IS_PCI_IDE (&PciIoDevice
->Pci
)) {
1068 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
1069 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
1072 if (IS_PCI_VGA (&PciIoDevice
->Pci
)) {
1073 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
1074 Attributes
|= (mReserveVgaAliases
? (UINT64
)EFI_PCI_IO_ATTRIBUTE_VGA_IO
: \
1075 (UINT64
)EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
);
1079 PciIoDevice
->Supports
= Attributes
;
1080 PciIoDevice
->Supports
&= ((PciIoDevice
->Parent
->Supports
) | \
1081 EFI_PCI_IO_ATTRIBUTE_IO
| EFI_PCI_IO_ATTRIBUTE_MEMORY
| \
1082 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
);
1085 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were
1086 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.
1087 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize
1088 // fields is not from the the ROM BAR of the PCI controller.
1090 if (!PciIoDevice
->EmbeddedRom
) {
1091 Attributes
|= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
;
1094 PciIoDevice
->Attributes
= Attributes
;
1099 Determine if the device can support Fast Back to Back attribute.
1101 @param PciIoDevice Pci device instance.
1102 @param StatusIndex Status register value.
1104 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
1105 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
1109 GetFastBackToBackSupport (
1110 IN PCI_IO_DEVICE
*PciIoDevice
,
1111 IN UINT8 StatusIndex
1114 EFI_PCI_IO_PROTOCOL
*PciIo
;
1116 UINT32 StatusRegister
;
1119 // Read the status register
1121 PciIo
= &PciIoDevice
->PciIo
;
1122 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, StatusIndex
, 1, &StatusRegister
);
1123 if (EFI_ERROR (Status
)) {
1124 return EFI_UNSUPPORTED
;
1128 // Check the Fast B2B bit
1130 if ((StatusRegister
& EFI_PCI_FAST_BACK_TO_BACK_CAPABLE
) != 0) {
1133 return EFI_UNSUPPORTED
;
1138 Process the option ROM for all the children of the specified parent PCI device.
1139 It can only be used after the first full Option ROM process.
1141 @param PciIoDevice Pci device instance.
1145 ProcessOptionRomLight (
1146 IN PCI_IO_DEVICE
*PciIoDevice
1149 PCI_IO_DEVICE
*Temp
;
1150 LIST_ENTRY
*CurrentLink
;
1153 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1155 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1156 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1157 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1159 if (!IsListEmpty (&Temp
->ChildList
)) {
1160 ProcessOptionRomLight (Temp
);
1163 Temp
->AllOpRomProcessed
= PciRomGetImageMapping (Temp
);
1165 CurrentLink
= CurrentLink
->ForwardLink
;
1170 Determine the related attributes of all devices under a Root Bridge.
1172 @param PciIoDevice PCI device instance.
1176 DetermineDeviceAttribute (
1177 IN PCI_IO_DEVICE
*PciIoDevice
1181 UINT16 BridgeControl
;
1183 UINT16 OldBridgeControl
;
1184 BOOLEAN FastB2BSupport
;
1185 PCI_IO_DEVICE
*Temp
;
1186 LIST_ENTRY
*CurrentLink
;
1190 // For Root Bridge, just copy it by RootBridgeIo protocol
1191 // so as to keep consistent with the actual attribute
1193 if (PciIoDevice
->Parent
== NULL
) {
1194 Status
= PciIoDevice
->PciRootBridgeIo
->GetAttributes (
1195 PciIoDevice
->PciRootBridgeIo
,
1196 &PciIoDevice
->Supports
,
1197 &PciIoDevice
->Attributes
1199 if (EFI_ERROR (Status
)) {
1204 // Assume the PCI Root Bridge supports DAC
1206 PciIoDevice
->Supports
|= (UINT64
)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE
|
1207 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
|
1208 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1211 // Set the attributes to be checked for common PCI devices and PPB or P2C
1212 // Since some devices only support part of them, it is better to set the
1213 // attribute according to its command or bridge control register
1215 Command
= EFI_PCI_COMMAND_IO_SPACE
|
1216 EFI_PCI_COMMAND_MEMORY_SPACE
|
1217 EFI_PCI_COMMAND_BUS_MASTER
|
1218 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
;
1220 BridgeControl
= EFI_PCI_BRIDGE_CONTROL_ISA
| EFI_PCI_BRIDGE_CONTROL_VGA
| EFI_PCI_BRIDGE_CONTROL_VGA_16
;
1223 // Test whether the device can support attributes above
1225 PciTestSupportedAttribute (PciIoDevice
, &Command
, &BridgeControl
, &OldCommand
, &OldBridgeControl
);
1228 // Set the supported attributes for specified PCI device
1230 PciSetDeviceAttribute (PciIoDevice
, Command
, BridgeControl
, EFI_SET_SUPPORTS
);
1233 // Set the current attributes for specified PCI device
1235 PciSetDeviceAttribute (PciIoDevice
, OldCommand
, OldBridgeControl
, EFI_SET_ATTRIBUTES
);
1238 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL
1239 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.
1240 if (!PciIoDevice
->IsPciExp
) {
1241 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE
);
1245 FastB2BSupport
= TRUE
;
1248 // P2C can not support FB2B on the secondary side
1250 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
1251 FastB2BSupport
= FALSE
;
1255 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1257 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1258 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1259 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1260 Status
= DetermineDeviceAttribute (Temp
);
1261 if (EFI_ERROR (Status
)) {
1266 // Detect Fast Back to Back support for the device under the bridge
1268 Status
= GetFastBackToBackSupport (Temp
, PCI_PRIMARY_STATUS_OFFSET
);
1269 if (FastB2BSupport
&& EFI_ERROR (Status
)) {
1270 FastB2BSupport
= FALSE
;
1273 CurrentLink
= CurrentLink
->ForwardLink
;
1277 // Set or clear Fast Back to Back bit for the whole bridge
1279 if (!IsListEmpty (&PciIoDevice
->ChildList
)) {
1280 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
1281 Status
= GetFastBackToBackSupport (PciIoDevice
, PCI_BRIDGE_STATUS_REGISTER_OFFSET
);
1283 if (EFI_ERROR (Status
) || (!FastB2BSupport
)) {
1284 FastB2BSupport
= FALSE
;
1285 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1287 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1291 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1292 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1293 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1294 if (FastB2BSupport
) {
1295 PCI_ENABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1297 PCI_DISABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1300 CurrentLink
= CurrentLink
->ForwardLink
;
1305 // End for IsListEmpty
1311 This routine is used to update the bar information for those incompatible PCI device.
1313 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1315 @param IgnoreOptionRom Output If the option rom of incompatible device need to be ignored.
1317 @retval EFI_SUCCESS Successfully updated bar information.
1318 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1323 IN OUT PCI_IO_DEVICE
*PciIoDevice
,
1324 OUT BOOLEAN
*IgnoreOptionRom
1330 VOID
*Configuration
;
1331 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Ptr
;
1333 Configuration
= NULL
;
1334 Status
= EFI_SUCCESS
;
1336 if (gIncompatiblePciDeviceSupport
== NULL
) {
1338 // It can only be supported after the Incompatible PCI Device
1339 // Support Protocol has been installed
1341 Status
= gBS
->LocateProtocol (
1342 &gEfiIncompatiblePciDeviceSupportProtocolGuid
,
1344 (VOID
**)&gIncompatiblePciDeviceSupport
1348 if (Status
== EFI_SUCCESS
) {
1350 // Check whether the device belongs to incompatible devices from protocol or not
1351 // If it is , then get its special requirement in the ACPI table
1353 Status
= gIncompatiblePciDeviceSupport
->CheckDevice (
1354 gIncompatiblePciDeviceSupport
,
1355 PciIoDevice
->Pci
.Hdr
.VendorId
,
1356 PciIoDevice
->Pci
.Hdr
.DeviceId
,
1357 PciIoDevice
->Pci
.Hdr
.RevisionID
,
1358 PciIoDevice
->Pci
.Device
.SubsystemVendorID
,
1359 PciIoDevice
->Pci
.Device
.SubsystemID
,
1364 if (EFI_ERROR (Status
) || (Configuration
== NULL
)) {
1365 return EFI_UNSUPPORTED
;
1369 // Update PCI device information from the ACPI table
1371 Ptr
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*)Configuration
;
1373 while (Ptr
->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
1374 if (Ptr
->Desc
!= ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
1376 // The format is not support
1382 // According to "Table 20. ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage"
1383 // in PI Spec 1.7, Type-specific flags can be set to 0 when Address Translation
1384 // Offset == 6 to skip device option ROM (do not probe option rom BAR).
1386 if (((Ptr
->AddrTranslationOffset
== PCI_MAX_BAR
) && (Ptr
->SpecificFlag
== 0))) {
1387 *IgnoreOptionRom
= TRUE
;
1392 for (BarIndex
= 0; BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
1393 if ((Ptr
->AddrTranslationOffset
!= MAX_UINT64
) &&
1394 (Ptr
->AddrTranslationOffset
!= MAX_UINT8
) &&
1395 (Ptr
->AddrTranslationOffset
!= BarIndex
)
1399 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).
1400 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.
1401 // Comparing against MAX_UINT8 is to keep backward compatibility.
1407 switch (Ptr
->ResType
) {
1408 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
1411 // Make sure the bar is memory type
1413 if (CheckBarType (PciIoDevice
, (UINT8
)BarIndex
, PciBarTypeMem
)) {
1417 // Ignored if granularity is 0.
1418 // Ignored if PCI BAR is I/O or 32-bit memory.
1419 // If PCI BAR is 64-bit memory and granularity is 32, then
1420 // the PCI BAR resource is allocated below 4GB.
1421 // If PCI BAR is 64-bit memory and granularity is 64, then
1422 // the PCI BAR resource is allocated above 4GB.
1424 if (PciIoDevice
->PciBar
[BarIndex
].BarType
== PciBarTypeMem64
) {
1425 switch (Ptr
->AddrSpaceGranularity
) {
1427 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1429 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= TRUE
;
1436 if (PciIoDevice
->PciBar
[BarIndex
].BarType
== PciBarTypePMem64
) {
1437 switch (Ptr
->AddrSpaceGranularity
) {
1439 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1441 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
)) {
1513 // Check the validity of the parameter
1515 if ((NewAlignment
!= EVEN_ALIGN
) &&
1516 (NewAlignment
!= SQUAD_ALIGN
) &&
1517 (NewAlignment
!= DQUAD_ALIGN
))
1519 *Alignment
= NewAlignment
;
1523 OldAlignment
= (*Alignment
) + 1;
1527 // Get the first non-zero hex value of the length
1529 while ((OldAlignment
& 0x0F) == 0x00) {
1530 OldAlignment
= RShiftU64 (OldAlignment
, 4);
1535 // Adjust the alignment to even, quad or double quad boundary
1537 if (NewAlignment
== EVEN_ALIGN
) {
1538 if ((OldAlignment
& 0x01) != 0) {
1539 OldAlignment
= OldAlignment
+ 2 - (OldAlignment
& 0x01);
1541 } else if (NewAlignment
== SQUAD_ALIGN
) {
1542 if ((OldAlignment
& 0x03) != 0) {
1543 OldAlignment
= OldAlignment
+ 4 - (OldAlignment
& 0x03);
1545 } else if (NewAlignment
== DQUAD_ALIGN
) {
1546 if ((OldAlignment
& 0x07) != 0) {
1547 OldAlignment
= OldAlignment
+ 8 - (OldAlignment
& 0x07);
1552 // Update the old value
1554 NewAlignment
= LShiftU64 (OldAlignment
, ShiftBit
) - 1;
1555 *Alignment
= NewAlignment
;
1561 Parse PCI IOV VF bar information and fill them into PCI device instance.
1563 @param PciIoDevice Pci device instance.
1564 @param Offset Bar offset.
1565 @param BarIndex Bar index.
1567 @return Next bar offset.
1572 IN PCI_IO_DEVICE
*PciIoDevice
,
1578 UINT32 OriginalValue
;
1583 // Ensure it is called properly
1585 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
1586 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
1593 Status
= VfBarExisted (
1600 if (EFI_ERROR (Status
)) {
1601 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1602 PciIoDevice
->VfPciBar
[BarIndex
].Length
= 0;
1603 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1606 // Scan all the BARs anyway
1608 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT16
)Offset
;
1612 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT16
)Offset
;
1613 if ((Value
& 0x01) != 0) {
1615 // Device I/Os. Impossible
1622 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1624 switch (Value
& 0x07) {
1626 // memory space; anywhere in 32 bit address space
1629 if ((Value
& 0x08) != 0) {
1630 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1632 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1635 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1636 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1641 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1645 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1646 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1652 // memory space; anywhere in 64 bit address space
1655 if ((Value
& 0x08) != 0) {
1656 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1658 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1662 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1663 // is regarded as an extension for the first bar. As a result
1664 // the sizing will be conducted on combined 64 bit value
1665 // Here just store the masked first 32bit value for future size
1668 PciIoDevice
->VfPciBar
[BarIndex
].Length
= Value
& Mask
;
1669 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1671 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1672 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1676 // Increment the offset to point to next DWORD
1680 Status
= VfBarExisted (
1687 if (EFI_ERROR (Status
)) {
1688 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1693 // Fix the length to support some special 64 bit BAR
1695 Value
|= ((UINT32
)-1 << HighBitSet32 (Value
));
1698 // Calculate the size of 64bit bar
1700 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
)OriginalValue
, 32);
1702 PciIoDevice
->VfPciBar
[BarIndex
].Length
= PciIoDevice
->VfPciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
)Value
, 32);
1703 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(PciIoDevice
->VfPciBar
[BarIndex
].Length
)) + 1;
1704 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1709 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1713 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1714 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1723 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1724 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1725 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1727 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1728 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1736 // Check the length again so as to keep compatible with some special bars
1738 if (PciIoDevice
->VfPciBar
[BarIndex
].Length
== 0) {
1739 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1740 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1741 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1745 // Increment number of bar
1751 Parse PCI bar information and fill them into PCI device instance.
1753 @param PciIoDevice Pci device instance.
1754 @param Offset Bar offset.
1755 @param BarIndex Bar index.
1757 @return Next bar offset.
1762 IN PCI_IO_DEVICE
*PciIoDevice
,
1768 UINT32 OriginalValue
;
1775 Status
= BarExisted (
1782 if (EFI_ERROR (Status
)) {
1783 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= 0;
1784 PciIoDevice
->PciBar
[BarIndex
].Length
= 0;
1785 PciIoDevice
->PciBar
[BarIndex
].Alignment
= 0;
1788 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1790 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
)Offset
;
1794 PciIoDevice
->PciBar
[BarIndex
].BarTypeFixed
= FALSE
;
1795 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
)Offset
;
1796 if ((Value
& 0x01) != 0) {
1802 if ((Value
& 0xFFFF0000) != 0) {
1806 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo32
;
1807 PciIoDevice
->PciBar
[BarIndex
].Length
= ((~(Value
& Mask
)) + 1);
1808 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1813 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo16
;
1814 PciIoDevice
->PciBar
[BarIndex
].Length
= 0x0000FFFF & ((~(Value
& Mask
)) + 1);
1815 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1819 // Workaround. Some platforms implement IO bar with 0 length
1820 // Need to treat it as no-bar
1822 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1823 PciIoDevice
->PciBar
[BarIndex
].BarType
= (PCI_BAR_TYPE
)0;
1826 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1830 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1832 switch (Value
& 0x07) {
1834 // memory space; anywhere in 32 bit address space
1837 if ((Value
& 0x08) != 0) {
1838 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1840 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1843 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1844 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1846 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1848 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1850 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1856 // memory space; anywhere in 64 bit address space
1859 if ((Value
& 0x08) != 0) {
1860 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1862 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1866 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1867 // is regarded as an extension for the first bar. As a result
1868 // the sizing will be conducted on combined 64 bit value
1869 // Here just store the masked first 32bit value for future size
1872 PciIoDevice
->PciBar
[BarIndex
].Length
= Value
& Mask
;
1873 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1876 // Increment the offset to point to next DWORD
1880 Status
= BarExisted (
1887 if (EFI_ERROR (Status
)) {
1889 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
1891 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1893 // some device implement MMIO bar with 0 length, need to treat it as no-bar
1895 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1901 // Fix the length to support some special 64 bit BAR
1904 DEBUG ((DEBUG_INFO
, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));
1907 Value
|= ((UINT32
)(-1) << HighBitSet32 (Value
));
1911 // Calculate the size of 64bit bar
1913 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
)OriginalValue
, 32);
1915 PciIoDevice
->PciBar
[BarIndex
].Length
= PciIoDevice
->PciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
)Value
, 32);
1916 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(PciIoDevice
->PciBar
[BarIndex
].Length
)) + 1;
1917 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1919 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1921 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1923 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1932 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1933 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1934 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1936 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1938 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1940 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1948 // Check the length again so as to keep compatible with some special bars
1950 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1951 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1952 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= 0;
1953 PciIoDevice
->PciBar
[BarIndex
].Alignment
= 0;
1957 // Increment number of bar
1963 This routine is used to initialize the bar of a PCI device.
1965 @param PciIoDevice Pci device instance.
1967 @note It can be called typically when a device is going to be rejected.
1971 InitializePciDevice (
1972 IN PCI_IO_DEVICE
*PciIoDevice
1975 EFI_PCI_IO_PROTOCOL
*PciIo
;
1978 PciIo
= &(PciIoDevice
->PciIo
);
1981 // Put all the resource apertures
1982 // Resource base is set to all ones so as to indicate its resource
1983 // has not been allocated
1985 for (Offset
= 0x10; Offset
<= 0x24; Offset
+= sizeof (UINT32
)) {
1986 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllOne
);
1991 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1993 @param PciIoDevice PCI-PCI bridge device instance.
1998 IN PCI_IO_DEVICE
*PciIoDevice
2001 EFI_PCI_IO_PROTOCOL
*PciIo
;
2003 PciIo
= &(PciIoDevice
->PciIo
);
2006 // Put all the resource apertures including IO16
2007 // Io32, pMem32, pMem64 to quiescent state
2008 // Resource base all ones, Resource limit all zeros
2010 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &gAllOne
);
2011 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1D, 1, &gAllZero
);
2013 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x20, 1, &gAllOne
);
2014 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x22, 1, &gAllZero
);
2016 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x24, 1, &gAllOne
);
2017 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x26, 1, &gAllZero
);
2019 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x28, 1, &gAllOne
);
2020 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x2C, 1, &gAllZero
);
2023 // Don't support use io32 as for now
2025 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x30, 1, &gAllOne
);
2026 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x32, 1, &gAllZero
);
2029 // Force Interrupt line to zero for cards that come up randomly
2031 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x3C, 1, &gAllZero
);
2035 This routine is used to initialize the bar of a PCI Card Bridge device.
2037 @param PciIoDevice PCI Card bridge device.
2042 IN PCI_IO_DEVICE
*PciIoDevice
2045 EFI_PCI_IO_PROTOCOL
*PciIo
;
2047 PciIo
= &(PciIoDevice
->PciIo
);
2050 // Put all the resource apertures including IO16
2051 // Io32, pMem32, pMem64 to quiescent state(
2052 // Resource base all ones, Resource limit all zeros
2054 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x1c, 1, &gAllOne
);
2055 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x20, 1, &gAllZero
);
2057 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x24, 1, &gAllOne
);
2058 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x28, 1, &gAllZero
);
2060 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x2c, 1, &gAllOne
);
2061 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x30, 1, &gAllZero
);
2063 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x34, 1, &gAllOne
);
2064 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x38, 1, &gAllZero
);
2067 // Force Interrupt line to zero for cards that come up randomly
2069 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x3C, 1, &gAllZero
);
2073 Authenticate the PCI device by using DeviceSecurityProtocol.
2075 @param PciIoDevice PCI device.
2077 @retval EFI_SUCCESS The device passes the authentication.
2078 @return not EFI_SUCCESS The device failes the authentication or
2079 unexpected error happen during authentication.
2082 AuthenticatePciDevice (
2083 IN PCI_IO_DEVICE
*PciIoDevice
2086 EDKII_DEVICE_IDENTIFIER DeviceIdentifier
;
2089 if (mDeviceSecurityProtocol
!= NULL
) {
2091 // Prepare the parameter
2093 DeviceIdentifier
.Version
= EDKII_DEVICE_IDENTIFIER_REVISION
;
2094 CopyGuid (&DeviceIdentifier
.DeviceType
, &gEdkiiDeviceIdentifierTypePciGuid
);
2095 DeviceIdentifier
.DeviceHandle
= NULL
;
2096 Status
= gBS
->InstallMultipleProtocolInterfaces (
2097 &DeviceIdentifier
.DeviceHandle
,
2098 &gEfiDevicePathProtocolGuid
,
2099 PciIoDevice
->DevicePath
,
2100 &gEdkiiDeviceIdentifierTypePciGuid
,
2101 &PciIoDevice
->PciIo
,
2104 if (EFI_ERROR (Status
)) {
2109 // Do DeviceAuthentication
2111 Status
= mDeviceSecurityProtocol
->DeviceAuthenticate (mDeviceSecurityProtocol
, &DeviceIdentifier
);
2113 // Always uninstall, because they are only for Authentication.
2114 // No need to check return Status.
2116 gBS
->UninstallMultipleProtocolInterfaces (
2117 DeviceIdentifier
.DeviceHandle
,
2118 &gEfiDevicePathProtocolGuid
,
2119 PciIoDevice
->DevicePath
,
2120 &gEdkiiDeviceIdentifierTypePciGuid
,
2121 &PciIoDevice
->PciIo
,
2128 // Device Security Protocol is not found, just return success
2134 Checks if PCI device is Root Bridge.
2136 @param PciIoDevice Instance of PCI device
2138 @retval TRUE Device is Root Bridge
2139 @retval FALSE Device is not Root Bridge
2144 IN PCI_IO_DEVICE
*PciIoDevice
2147 if (PciIoDevice
->Parent
== NULL
) {
2155 Create and initialize general PCI I/O device instance for
2156 PCI device/bridge device/hotplug bridge device.
2158 @param Bridge Parent bridge instance.
2159 @param Pci Input Pci information block.
2160 @param Bus Device Bus NO.
2161 @param Device Device device NO.
2162 @param Func Device func NO.
2164 @return Instance of PCI device. NULL means no instance created.
2169 IN PCI_IO_DEVICE
*Bridge
,
2176 PCI_IO_DEVICE
*PciIoDevice
;
2177 EFI_PCI_IO_PROTOCOL
*PciIo
;
2180 PciIoDevice
= AllocateZeroPool (sizeof (PCI_IO_DEVICE
));
2181 if (PciIoDevice
== NULL
) {
2185 PciIoDevice
->Signature
= PCI_IO_DEVICE_SIGNATURE
;
2186 PciIoDevice
->Handle
= NULL
;
2187 PciIoDevice
->PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
2188 PciIoDevice
->DevicePath
= NULL
;
2189 PciIoDevice
->BusNumber
= Bus
;
2190 PciIoDevice
->DeviceNumber
= Device
;
2191 PciIoDevice
->FunctionNumber
= Func
;
2192 PciIoDevice
->Decodes
= 0;
2194 if (gFullEnumeration
) {
2195 PciIoDevice
->Allocated
= FALSE
;
2197 PciIoDevice
->Allocated
= TRUE
;
2200 PciIoDevice
->Registered
= FALSE
;
2201 PciIoDevice
->Attributes
= 0;
2202 PciIoDevice
->Supports
= 0;
2203 PciIoDevice
->BusOverride
= FALSE
;
2204 PciIoDevice
->AllOpRomProcessed
= FALSE
;
2206 PciIoDevice
->IsPciExp
= FALSE
;
2208 CopyMem (&(PciIoDevice
->Pci
), Pci
, sizeof (PCI_TYPE01
));
2211 // Initialize the PCI I/O instance structure
2213 InitializePciIoInstance (PciIoDevice
);
2214 InitializePciDriverOverrideInstance (PciIoDevice
);
2215 InitializePciLoadFile2 (PciIoDevice
);
2216 PciIo
= &PciIoDevice
->PciIo
;
2219 // Create a device path for this PCI device and store it into its private data
2221 CreatePciDevicePath (
2227 // Detect if PCI Express Device
2229 PciIoDevice
->PciExpressCapabilityOffset
= 0;
2230 Status
= LocateCapabilityRegBlock (
2232 EFI_PCI_CAPABILITY_ID_PCIEXP
,
2233 &PciIoDevice
->PciExpressCapabilityOffset
,
2236 if (!EFI_ERROR (Status
)) {
2237 PciIoDevice
->IsPciExp
= TRUE
;
2241 // Now we can do the authentication check for the device.
2243 Status
= AuthenticatePciDevice (PciIoDevice
);
2245 // If authentication fails, skip this device.
2247 if (EFI_ERROR (Status
)) {
2248 if (PciIoDevice
->DevicePath
!= NULL
) {
2249 FreePool (PciIoDevice
->DevicePath
);
2252 FreePool (PciIoDevice
);
2257 // Check if device's parent is not Root Bridge
2259 if (PcdGetBool (PcdAriSupport
) && !IsRootBridge (Bridge
)) {
2261 // Check if the device is an ARI device.
2263 Status
= LocatePciExpressCapabilityRegBlock (
2265 EFI_PCIE_CAPABILITY_ID_ARI
,
2266 &PciIoDevice
->AriCapabilityOffset
,
2269 if (!EFI_ERROR (Status
)) {
2271 // We need to enable ARI feature before calculate BusReservation,
2272 // because FirstVFOffset and VFStride may change after that.
2274 EFI_PCI_IO_PROTOCOL
*ParentPciIo
;
2278 // Check if its parent supports ARI forwarding.
2280 ParentPciIo
= &Bridge
->PciIo
;
2281 ParentPciIo
->Pci
.Read (
2283 EfiPciIoWidthUint32
,
2284 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET
,
2288 if ((Data32
& EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING
) != 0) {
2290 // ARI forward support in bridge, so enable it.
2292 ParentPciIo
->Pci
.Read (
2294 EfiPciIoWidthUint32
,
2295 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET
,
2299 if ((Data32
& EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING
) == 0) {
2300 Data32
|= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING
;
2301 ParentPciIo
->Pci
.Write (
2303 EfiPciIoWidthUint32
,
2304 Bridge
->PciExpressCapabilityOffset
+ EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET
,
2310 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
2312 Bridge
->DeviceNumber
,
2313 Bridge
->FunctionNumber
2318 DEBUG ((DEBUG_INFO
, " ARI: CapOffset = 0x%x\n", PciIoDevice
->AriCapabilityOffset
));
2323 // Initialization for SR-IOV
2326 if (PcdGetBool (PcdSrIovSupport
)) {
2327 Status
= LocatePciExpressCapabilityRegBlock (
2329 EFI_PCIE_CAPABILITY_ID_SRIOV
,
2330 &PciIoDevice
->SrIovCapabilityOffset
,
2333 if (!EFI_ERROR (Status
)) {
2334 UINT32 SupportedPageSize
;
2336 UINT16 FirstVFOffset
;
2342 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
2344 if (PcdGetBool (PcdAriSupport
) && (PciIoDevice
->AriCapabilityOffset
!= 0)) {
2347 EfiPciIoWidthUint16
,
2348 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL
,
2352 Data16
|= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY
;
2355 EfiPciIoWidthUint16
,
2356 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL
,
2363 // Calculate SystemPageSize
2368 EfiPciIoWidthUint32
,
2369 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE
,
2373 PciIoDevice
->SystemPageSize
= (PcdGet32 (PcdSrIovSystemPageSize
) & SupportedPageSize
);
2374 ASSERT (PciIoDevice
->SystemPageSize
!= 0);
2378 EfiPciIoWidthUint32
,
2379 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE
,
2381 &PciIoDevice
->SystemPageSize
2384 // Adjust SystemPageSize for Alignment usage later
2386 PciIoDevice
->SystemPageSize
<<= 12;
2389 // Calculate BusReservation for PCI IOV
2393 // Read First FirstVFOffset, InitialVFs, and VFStride
2397 EfiPciIoWidthUint16
,
2398 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF
,
2404 EfiPciIoWidthUint16
,
2405 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS
,
2407 &PciIoDevice
->InitialVFs
2411 EfiPciIoWidthUint16
,
2412 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE
,
2419 if (PciIoDevice
->InitialVFs
== 0) {
2420 PciIoDevice
->ReservedBusNum
= 0;
2422 PFRid
= EFI_PCI_RID (Bus
, Device
, Func
);
2423 LastVF
= PFRid
+ FirstVFOffset
+ (PciIoDevice
->InitialVFs
- 1) * VFStride
;
2426 // Calculate ReservedBusNum for this PF
2428 PciIoDevice
->ReservedBusNum
= (UINT16
)(EFI_PCI_BUS_OF_RID (LastVF
) - Bus
+ 1);
2433 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
2435 PciIoDevice
->SystemPageSize
>> 12,
2440 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
2441 PciIoDevice
->InitialVFs
,
2442 PciIoDevice
->ReservedBusNum
,
2443 PciIoDevice
->SrIovCapabilityOffset
2448 if (PcdGetBool (PcdMrIovSupport
)) {
2449 Status
= LocatePciExpressCapabilityRegBlock (
2451 EFI_PCIE_CAPABILITY_ID_MRIOV
,
2452 &PciIoDevice
->MrIovCapabilityOffset
,
2455 if (!EFI_ERROR (Status
)) {
2456 DEBUG ((DEBUG_INFO
, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice
->MrIovCapabilityOffset
));
2460 PciIoDevice
->ResizableBarOffset
= 0;
2461 if (PcdGetBool (PcdPcieResizableBarSupport
)) {
2462 Status
= LocatePciExpressCapabilityRegBlock (
2464 PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID
,
2465 &PciIoDevice
->ResizableBarOffset
,
2468 if (!EFI_ERROR (Status
)) {
2469 PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl
;
2471 Offset
= PciIoDevice
->ResizableBarOffset
+ sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER
)
2472 + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY
),
2477 sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL
),
2478 &ResizableBarControl
2480 PciIoDevice
->ResizableBarNumber
= ResizableBarControl
.Bits
.ResizableBarNumber
;
2481 PciProgramResizableBar (PciIoDevice
, PciResizableBarMax
);
2486 // Initialize the reserved resource list
2488 InitializeListHead (&PciIoDevice
->ReservedResourceList
);
2491 // Initialize the driver list
2493 InitializeListHead (&PciIoDevice
->OptionRomDriverList
);
2496 // Initialize the child list
2498 InitializeListHead (&PciIoDevice
->ChildList
);
2504 This routine is used to enumerate entire pci bus system
2505 in a given platform.
2507 It is only called on the second start on the same Root Bridge.
2509 @param Controller Parent bridge handler.
2511 @retval EFI_SUCCESS PCI enumeration finished successfully.
2512 @retval other Some error occurred when enumerating the pci bus system.
2516 PciEnumeratorLight (
2517 IN EFI_HANDLE Controller
2521 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2522 PCI_IO_DEVICE
*RootBridgeDev
;
2525 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
2528 MaxBus
= PCI_MAX_BUS
;
2532 // If this root bridge has been already enumerated, then return successfully
2534 if (GetRootBridgeByHandle (Controller
) != NULL
) {
2539 // Open pci root bridge io protocol
2541 Status
= gBS
->OpenProtocol (
2543 &gEfiPciRootBridgeIoProtocolGuid
,
2544 (VOID
**)&PciRootBridgeIo
,
2545 gPciBusDriverBinding
.DriverBindingHandle
,
2547 EFI_OPEN_PROTOCOL_BY_DRIVER
2549 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
2553 Status
= PciRootBridgeIo
->Configuration (PciRootBridgeIo
, (VOID
**)&Descriptors
);
2555 if (EFI_ERROR (Status
)) {
2559 while (PciGetBusRange (&Descriptors
, &MinBus
, &MaxBus
, NULL
) == EFI_SUCCESS
) {
2561 // Create a device node for root bridge device with a NULL host bridge controller handle
2563 RootBridgeDev
= CreateRootBridge (Controller
);
2565 if (RootBridgeDev
== NULL
) {
2571 // Record the root bridge-io protocol
2573 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2575 Status
= PciPciDeviceInfoCollector (
2580 if (!EFI_ERROR (Status
)) {
2582 // Remove those PCI devices which are rejected when full enumeration
2584 RemoveRejectedPciDevices (RootBridgeDev
->Handle
, RootBridgeDev
);
2587 // Process option rom light
2589 ProcessOptionRomLight (RootBridgeDev
);
2592 // Determine attributes for all devices under this root bridge
2594 DetermineDeviceAttribute (RootBridgeDev
);
2597 // If successfully, insert the node into device pool
2599 InsertRootBridge (RootBridgeDev
);
2602 // If unsuccessfully, destroy the entire node
2604 DestroyRootBridge (RootBridgeDev
);
2614 Get bus range from PCI resource descriptor list.
2616 @param Descriptors A pointer to the address space descriptor.
2617 @param MinBus The min bus returned.
2618 @param MaxBus The max bus returned.
2619 @param BusRange The bus range returned.
2621 @retval EFI_SUCCESS Successfully got bus range.
2622 @retval EFI_NOT_FOUND Can not find the specific bus.
2627 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
**Descriptors
,
2630 OUT UINT16
*BusRange
2633 while ((*Descriptors
)->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
2634 if ((*Descriptors
)->ResType
== ACPI_ADDRESS_SPACE_TYPE_BUS
) {
2635 if (MinBus
!= NULL
) {
2636 *MinBus
= (UINT16
)(*Descriptors
)->AddrRangeMin
;
2639 if (MaxBus
!= NULL
) {
2640 *MaxBus
= (UINT16
)(*Descriptors
)->AddrRangeMax
;
2643 if (BusRange
!= NULL
) {
2644 *BusRange
= (UINT16
)(*Descriptors
)->AddrLen
;
2653 return EFI_NOT_FOUND
;
2657 This routine can be used to start the root bridge.
2659 @param RootBridgeDev Pci device instance.
2661 @retval EFI_SUCCESS This device started.
2662 @retval other Failed to get PCI Root Bridge I/O protocol.
2666 StartManagingRootBridge (
2667 IN PCI_IO_DEVICE
*RootBridgeDev
2670 EFI_HANDLE RootBridgeHandle
;
2672 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2675 // Get the root bridge handle
2677 RootBridgeHandle
= RootBridgeDev
->Handle
;
2678 PciRootBridgeIo
= NULL
;
2681 // Get the pci root bridge io protocol
2683 Status
= gBS
->OpenProtocol (
2685 &gEfiPciRootBridgeIoProtocolGuid
,
2686 (VOID
**)&PciRootBridgeIo
,
2687 gPciBusDriverBinding
.DriverBindingHandle
,
2689 EFI_OPEN_PROTOCOL_BY_DRIVER
2692 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
2697 // Store the PciRootBridgeIo protocol into root bridge private data
2699 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2705 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2707 @param PciIoDevice Pci device instance.
2709 @retval TRUE This device should be rejected.
2710 @retval FALSE This device shouldn't be rejected.
2714 IsPciDeviceRejected (
2715 IN PCI_IO_DEVICE
*PciIoDevice
2725 // PPB should be skip!
2727 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
2731 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
2733 // Only test base registers for P2C
2735 for (BarOffset
= 0x1C; BarOffset
<= 0x38; BarOffset
+= 2 * sizeof (UINT32
)) {
2736 Mask
= (BarOffset
< 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2737 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2738 if (EFI_ERROR (Status
)) {
2742 TestValue
= TestValue
& Mask
;
2743 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2745 // The bar isn't programed, so it should be rejected
2754 for (BarOffset
= 0x14; BarOffset
<= 0x24; BarOffset
+= sizeof (UINT32
)) {
2758 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2759 if (EFI_ERROR (Status
)) {
2763 if ((TestValue
& 0x01) != 0) {
2768 TestValue
= TestValue
& Mask
;
2769 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2777 TestValue
= TestValue
& Mask
;
2779 if ((TestValue
& 0x07) == 0x04) {
2783 BarOffset
+= sizeof (UINT32
);
2784 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2786 // Test its high 32-Bit BAR
2788 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2789 if (TestValue
== OldValue
) {
2797 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2808 Reset all bus number from specific bridge.
2810 @param Bridge Parent specific bridge.
2811 @param StartBusNumber Start bus number.
2815 ResetAllPpbBusNumber (
2816 IN PCI_IO_DEVICE
*Bridge
,
2817 IN UINT8 StartBusNumber
2827 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2829 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
2831 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
2832 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
2834 // Check to see whether a pci device is present
2836 Status
= PciDevicePresent (
2844 if (EFI_ERROR (Status
) && (Func
== 0)) {
2846 // go to next device if there is no Function 0
2851 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
))) {
2853 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
2854 Status
= PciRootBridgeIo
->Pci
.Read (
2861 SecondaryBus
= (UINT8
)(Register
>> 8);
2863 if (SecondaryBus
!= 0) {
2864 ResetAllPpbBusNumber (Bridge
, SecondaryBus
);
2868 // Reset register 18h, 19h, 1Ah on PCI Bridge
2870 Register
&= 0xFF000000;
2871 Status
= PciRootBridgeIo
->Pci
.Write (
2880 if ((Func
== 0) && !IS_PCI_MULTI_FUNC (&Pci
)) {
2882 // Skip sub functions, this is not a multi function device
2884 Func
= PCI_MAX_FUNC
;