2 PCI emumeration support functions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 This routine is used to check whether the pci device is present.
20 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
21 @param Pci Output buffer for PCI device configuration space.
22 @param Bus PCI bus NO.
23 @param Device PCI device NO.
24 @param Func PCI Func NO.
26 @retval EFI_NOT_FOUND PCI device not present.
27 @retval EFI_SUCCESS PCI device is found.
32 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
43 // Create PCI address map in terms of Bus, Device and Func
45 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Func
, 0);
48 // Read the Vendor ID register
50 Status
= PciRootBridgeIo
->Pci
.Read (
58 if (!EFI_ERROR (Status
) && (Pci
->Hdr
).VendorId
!= 0xffff) {
60 // Read the entire config header for the device
62 Status
= PciRootBridgeIo
->Pci
.Read (
66 sizeof (PCI_TYPE00
) / sizeof (UINT32
),
77 Collect all the resource information under this root bridge.
79 A database that records all the information about pci device subject to this
80 root bridge will then be created.
82 @param Bridge Parent bridge instance.
83 @param StartBusNumber Bus number of begining.
85 @retval EFI_SUCCESS PCI device is found.
86 @retval other Some error occurred when reading PCI bridge information.
90 PciPciDeviceInfoCollector (
91 IN PCI_IO_DEVICE
*Bridge
,
92 IN UINT8 StartBusNumber
100 PCI_IO_DEVICE
*PciIoDevice
;
101 EFI_PCI_IO_PROTOCOL
*PciIo
;
103 Status
= EFI_SUCCESS
;
106 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
108 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
111 // Check to see whether PCI device is present
113 Status
= PciDevicePresent (
114 Bridge
->PciRootBridgeIo
,
116 (UINT8
) StartBusNumber
,
120 if (!EFI_ERROR (Status
)) {
123 // Call back to host bridge function
125 PreprocessController (Bridge
, (UINT8
) StartBusNumber
, Device
, Func
, EfiPciBeforeResourceCollection
);
128 // Collect all the information about the PCI device discovered
130 Status
= PciSearchDevice (
133 (UINT8
) StartBusNumber
,
140 // Recursively scan PCI busses on the other side of PCI-PCI bridges
143 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
) || IS_CARDBUS_BRIDGE (&Pci
))) {
146 // If it is PPB, we need to get the secondary bus to continue the enumeration
148 PciIo
= &(PciIoDevice
->PciIo
);
150 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
, 1, &SecBus
);
152 if (EFI_ERROR (Status
)) {
157 // Get resource padding for PPB
159 GetResourcePaddingPpb (PciIoDevice
);
162 // Deep enumerate the next level bus
164 Status
= PciPciDeviceInfoCollector (
171 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
174 // Skip sub functions, this is not a multi function device
187 Seach required device and create PCI device instance.
189 @param Bridge Parent bridge instance.
190 @param Pci Input PCI device information block.
191 @param Bus PCI bus NO.
192 @param Device PCI device NO.
193 @param Func PCI func NO.
194 @param PciDevice Output of searched PCI device instance.
196 @retval EFI_SUCCESS Successfully created PCI device instance.
197 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
202 IN PCI_IO_DEVICE
*Bridge
,
207 OUT PCI_IO_DEVICE
**PciDevice
210 PCI_IO_DEVICE
*PciIoDevice
;
214 if (!IS_PCI_BRIDGE (Pci
)) {
216 if (IS_CARDBUS_BRIDGE (Pci
)) {
217 PciIoDevice
= GatherP2CInfo (
224 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
225 InitializeP2C (PciIoDevice
);
230 // Create private data for Pci Device
232 PciIoDevice
= GatherDeviceInfo (
245 // Create private data for PPB
247 PciIoDevice
= GatherPpbInfo (
256 // Special initialization for PPB including making the PPB quiet
258 if ((PciIoDevice
!= NULL
) && gFullEnumeration
) {
259 InitializePpb (PciIoDevice
);
263 if (PciIoDevice
== NULL
) {
264 return EFI_OUT_OF_RESOURCES
;
268 // Update the bar information for this PCI device so as to support some specific device
270 UpdatePciInfo (PciIoDevice
);
272 if (PciIoDevice
->DevicePath
== NULL
) {
273 return EFI_OUT_OF_RESOURCES
;
277 // Detect this function has option rom
279 if (gFullEnumeration
) {
281 if (!IS_CARDBUS_BRIDGE (Pci
)) {
283 GetOpRomInfo (PciIoDevice
);
287 ResetPowerManagementFeature (PciIoDevice
);
292 // Insert it into a global tree for future reference
294 InsertPciDevice (Bridge
, PciIoDevice
);
297 // Determine PCI device attributes
300 if (PciDevice
!= NULL
) {
301 *PciDevice
= PciIoDevice
;
308 Create PCI device instance for PCI device.
310 @param Bridge Parent bridge instance.
311 @param Pci Input PCI device information block.
312 @param Bus PCI device Bus NO.
313 @param Device PCI device Device NO.
314 @param Func PCI device's func NO.
316 @return Created PCI device instance.
321 IN PCI_IO_DEVICE
*Bridge
,
330 PCI_IO_DEVICE
*PciIoDevice
;
331 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
333 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
334 PciIoDevice
= CreatePciIoDevice (
342 if (PciIoDevice
== NULL
) {
347 // Create a device path for this PCI device and store it into its private data
349 CreatePciDevicePath (
355 // If it is a full enumeration, disconnect the device in advance
357 if (gFullEnumeration
) {
359 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
364 // Start to parse the bars
366 for (Offset
= 0x10, BarIndex
= 0; Offset
<= 0x24 && BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
367 Offset
= PciParseBar (PciIoDevice
, Offset
, BarIndex
);
371 // Parse the SR-IOV VF bars
373 if ((PciIoDevice
->SrIovCapabilityOffset
!= 0) && ((FeaturePcdGet(PcdSrIovSupport
)& EFI_PCI_IOV_POLICY_SRIOV
) != 0)) {
374 for (Offset
= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0
, BarIndex
= 0;
375 Offset
<= PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5
;
378 ASSERT (BarIndex
< PCI_MAX_BAR
);
379 Offset
= PciIovParseVfBar (PciIoDevice
, Offset
, BarIndex
);
386 Create PCI device instance for PCI-PCI bridge.
388 @param Bridge Parent bridge instance.
389 @param Pci Input PCI device information block.
390 @param Bus PCI device Bus NO.
391 @param Device PCI device Device NO.
392 @param Func PCI device's func NO.
394 @return Created PCI device instance.
399 IN PCI_IO_DEVICE
*Bridge
,
406 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
407 PCI_IO_DEVICE
*PciIoDevice
;
410 EFI_PCI_IO_PROTOCOL
*PciIo
;
413 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
414 PciIoDevice
= CreatePciIoDevice (
422 if (PciIoDevice
== NULL
) {
427 // Create a device path for this PCI device and store it into its private data
429 CreatePciDevicePath (
434 if (gFullEnumeration
) {
435 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
438 // Initalize the bridge control register
440 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED
);
445 // PPB can have two BARs
447 if (PciParseBar (PciIoDevice
, 0x10, PPB_BAR_0
) == 0x14) {
451 PciParseBar (PciIoDevice
, 0x14, PPB_BAR_1
);
454 PciIo
= &PciIoDevice
->PciIo
;
457 // Test whether it support 32 decode or not
459 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
460 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &gAllOne
);
461 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Value
);
462 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &Temp
);
465 if ((Value
& 0x01) != 0) {
466 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
468 PciIoDevice
->Decodes
|= EFI_BRIDGE_IO16_DECODE_SUPPORTED
;
472 Status
= BarExisted (
480 // Test if it supports 64 memory or not
482 if (!EFI_ERROR (Status
)) {
484 Status
= BarExisted (
491 if (!EFI_ERROR (Status
)) {
492 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
493 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED
;
495 PciIoDevice
->Decodes
|= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
;
500 // Memory 32 code is required for ppb
502 PciIoDevice
->Decodes
|= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
;
504 GetResourcePaddingPpb (PciIoDevice
);
511 Create PCI device instance for PCI Card bridge device.
513 @param Bridge Parent bridge instance.
514 @param Pci Input PCI device information block.
515 @param Bus PCI device Bus NO.
516 @param Device PCI device Device NO.
517 @param Func PCI device's func NO.
519 @return Created PCI device instance.
524 IN PCI_IO_DEVICE
*Bridge
,
531 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
532 PCI_IO_DEVICE
*PciIoDevice
;
534 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
535 PciIoDevice
= CreatePciIoDevice (
543 if (PciIoDevice
== NULL
) {
548 // Create a device path for this PCI device and store it into its private data
550 CreatePciDevicePath (
555 if (gFullEnumeration
) {
556 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_BITS_OWNED
);
559 // Initalize the bridge control register
561 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED
);
565 // P2C only has one bar that is in 0x10
567 PciParseBar (PciIoDevice
, 0x10, P2C_BAR_0
);
570 // Read PciBar information from the bar register
572 GetBackPcCardBar (PciIoDevice
);
573 PciIoDevice
->Decodes
= EFI_BRIDGE_MEM32_DECODE_SUPPORTED
|
574 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
|
575 EFI_BRIDGE_IO32_DECODE_SUPPORTED
;
581 Create device path for pci deivce.
583 @param ParentDevicePath Parent bridge's path.
584 @param PciIoDevice Pci device instance.
586 @return Device path protocol instance for specific pci device.
589 EFI_DEVICE_PATH_PROTOCOL
*
590 CreatePciDevicePath (
591 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
592 IN PCI_IO_DEVICE
*PciIoDevice
596 PCI_DEVICE_PATH PciNode
;
599 // Create PCI device path
601 PciNode
.Header
.Type
= HARDWARE_DEVICE_PATH
;
602 PciNode
.Header
.SubType
= HW_PCI_DP
;
603 SetDevicePathNodeLength (&PciNode
.Header
, sizeof (PciNode
));
605 PciNode
.Device
= PciIoDevice
->DeviceNumber
;
606 PciNode
.Function
= PciIoDevice
->FunctionNumber
;
607 PciIoDevice
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, &PciNode
.Header
);
609 return PciIoDevice
->DevicePath
;
613 Check whether the PCI IOV VF bar is existed or not.
615 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
616 @param Offset The offset.
617 @param BarLengthValue The bar length value returned.
618 @param OriginalBarValue The original bar value returned.
620 @retval EFI_NOT_FOUND The bar doesn't exist.
621 @retval EFI_SUCCESS The bar exist.
626 IN PCI_IO_DEVICE
*PciIoDevice
,
628 OUT UINT32
*BarLengthValue
,
629 OUT UINT32
*OriginalBarValue
632 EFI_PCI_IO_PROTOCOL
*PciIo
;
633 UINT32 OriginalValue
;
638 // Ensure it is called properly
640 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
641 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
642 return EFI_NOT_FOUND
;
645 PciIo
= &PciIoDevice
->PciIo
;
648 // Preserve the original value
651 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
654 // Raise TPL to high level to disable timer interrupt while the BAR is probed
656 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
658 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &gAllOne
);
659 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &Value
);
662 // Write back the original value
664 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT32
)Offset
, 1, &OriginalValue
);
667 // Restore TPL to its original level
669 gBS
->RestoreTPL (OldTpl
);
671 if (BarLengthValue
!= NULL
) {
672 *BarLengthValue
= Value
;
675 if (OriginalBarValue
!= NULL
) {
676 *OriginalBarValue
= OriginalValue
;
680 return EFI_NOT_FOUND
;
687 Check whether the bar is existed or not.
689 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
690 @param Offset The offset.
691 @param BarLengthValue The bar length value returned.
692 @param OriginalBarValue The original bar value returned.
694 @retval EFI_NOT_FOUND The bar doesn't exist.
695 @retval EFI_SUCCESS The bar exist.
700 IN PCI_IO_DEVICE
*PciIoDevice
,
702 OUT UINT32
*BarLengthValue
,
703 OUT UINT32
*OriginalBarValue
706 EFI_PCI_IO_PROTOCOL
*PciIo
;
707 UINT32 OriginalValue
;
711 PciIo
= &PciIoDevice
->PciIo
;
714 // Preserve the original value
716 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &OriginalValue
);
719 // Raise TPL to high level to disable timer interrupt while the BAR is probed
721 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
723 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &gAllOne
);
724 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &Value
);
727 // Write back the original value
729 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, (UINT8
) Offset
, 1, &OriginalValue
);
732 // Restore TPL to its original level
734 gBS
->RestoreTPL (OldTpl
);
736 if (BarLengthValue
!= NULL
) {
737 *BarLengthValue
= Value
;
740 if (OriginalBarValue
!= NULL
) {
741 *OriginalBarValue
= OriginalValue
;
745 return EFI_NOT_FOUND
;
752 Test whether the device can support given attributes.
754 @param PciIoDevice Pci device instance.
755 @param Command Input command register value, and
756 returned supported register value.
757 @param BridgeControl Inout bridge control value for PPB or P2C, and
758 returned supported bridge control value.
759 @param OldCommand Returned and stored old command register offset.
760 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
764 PciTestSupportedAttribute (
765 IN PCI_IO_DEVICE
*PciIoDevice
,
766 IN OUT UINT16
*Command
,
767 IN OUT UINT16
*BridgeControl
,
768 OUT UINT16
*OldCommand
,
769 OUT UINT16
*OldBridgeControl
775 // Preserve the original value
777 PCI_READ_COMMAND_REGISTER (PciIoDevice
, OldCommand
);
780 // Raise TPL to high level to disable timer interrupt while the BAR is probed
782 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
784 PCI_SET_COMMAND_REGISTER (PciIoDevice
, *Command
);
785 PCI_READ_COMMAND_REGISTER (PciIoDevice
, Command
);
788 // Write back the original value
790 PCI_SET_COMMAND_REGISTER (PciIoDevice
, *OldCommand
);
793 // Restore TPL to its original level
795 gBS
->RestoreTPL (OldTpl
);
797 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
) || IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
800 // Preserve the original value
802 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, OldBridgeControl
);
805 // Raise TPL to high level to disable timer interrupt while the BAR is probed
807 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
809 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *BridgeControl
);
810 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice
, BridgeControl
);
813 // Write back the original value
815 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice
, *OldBridgeControl
);
818 // Restore TPL to its original level
820 gBS
->RestoreTPL (OldTpl
);
823 *OldBridgeControl
= 0;
829 Set the supported or current attributes of a PCI device.
831 @param PciIoDevice Structure pointer for PCI device.
832 @param Command Command register value.
833 @param BridgeControl Bridge control value for PPB or P2C.
834 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
838 PciSetDeviceAttribute (
839 IN PCI_IO_DEVICE
*PciIoDevice
,
841 IN UINT16 BridgeControl
,
849 if ((Command
& EFI_PCI_COMMAND_IO_SPACE
) != 0) {
850 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IO
;
853 if ((Command
& EFI_PCI_COMMAND_MEMORY_SPACE
) != 0) {
854 Attributes
|= EFI_PCI_IO_ATTRIBUTE_MEMORY
;
857 if ((Command
& EFI_PCI_COMMAND_BUS_MASTER
) != 0) {
858 Attributes
|= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
;
861 if ((Command
& EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
) != 0) {
862 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
865 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_ISA
) != 0) {
866 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_IO
;
869 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA
) != 0) {
870 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO
;
871 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
872 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
;
875 if ((BridgeControl
& EFI_PCI_BRIDGE_CONTROL_VGA_16
) != 0) {
876 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
;
877 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16
;
880 if (Option
== EFI_SET_SUPPORTS
) {
882 Attributes
|= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
|
883 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED
|
884 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE
|
885 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE
|
886 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
|
887 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
;
889 if ((Attributes
& EFI_PCI_IO_ATTRIBUTE_IO
) != 0) {
890 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO
;
891 Attributes
|= EFI_PCI_IO_ATTRIBUTE_ISA_IO
;
894 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
) || IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
896 // For bridge, it should support IDE attributes
898 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
899 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
902 if (IS_PCI_IDE (&PciIoDevice
->Pci
)) {
903 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
;
904 Attributes
|= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
;
907 if (IS_PCI_VGA (&PciIoDevice
->Pci
)) {
908 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
;
909 Attributes
|= EFI_PCI_IO_ATTRIBUTE_VGA_IO
;
913 PciIoDevice
->Supports
= Attributes
;
914 PciIoDevice
->Supports
&= ( (PciIoDevice
->Parent
->Supports
) | \
915 EFI_PCI_IO_ATTRIBUTE_IO
| EFI_PCI_IO_ATTRIBUTE_MEMORY
| \
916 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
);
919 PciIoDevice
->Attributes
= Attributes
;
924 Determine if the device can support Fast Back to Back attribute.
926 @param PciIoDevice Pci device instance.
927 @param StatusIndex Status register value.
929 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
930 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
934 GetFastBackToBackSupport (
935 IN PCI_IO_DEVICE
*PciIoDevice
,
939 EFI_PCI_IO_PROTOCOL
*PciIo
;
941 UINT32 StatusRegister
;
944 // Read the status register
946 PciIo
= &PciIoDevice
->PciIo
;
947 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, StatusIndex
, 1, &StatusRegister
);
948 if (EFI_ERROR (Status
)) {
949 return EFI_UNSUPPORTED
;
953 // Check the Fast B2B bit
955 if ((StatusRegister
& EFI_PCI_FAST_BACK_TO_BACK_CAPABLE
) != 0) {
958 return EFI_UNSUPPORTED
;
963 Process the option ROM for all the children of the specified parent PCI device.
964 It can only be used after the first full Option ROM process.
966 @param PciIoDevice Pci device instance.
970 ProcessOptionRomLight (
971 IN PCI_IO_DEVICE
*PciIoDevice
975 LIST_ENTRY
*CurrentLink
;
978 // For RootBridge, PPB , P2C, go recursively to traverse all its children
980 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
981 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
983 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
985 if (!IsListEmpty (&Temp
->ChildList
)) {
986 ProcessOptionRomLight (Temp
);
989 PciRomGetImageMapping (Temp
);
992 // The OpRom has already been processed in the first round
994 Temp
->AllOpRomProcessed
= TRUE
;
996 CurrentLink
= CurrentLink
->ForwardLink
;
1001 Determine the related attributes of all devices under a Root Bridge.
1003 @param PciIoDevice PCI device instance.
1007 DetermineDeviceAttribute (
1008 IN PCI_IO_DEVICE
*PciIoDevice
1012 UINT16 BridgeControl
;
1014 UINT16 OldBridgeControl
;
1015 BOOLEAN FastB2BSupport
;
1016 PCI_IO_DEVICE
*Temp
;
1017 LIST_ENTRY
*CurrentLink
;
1021 // For Root Bridge, just copy it by RootBridgeIo proctocol
1022 // so as to keep consistent with the actual attribute
1024 if (PciIoDevice
->Parent
== NULL
) {
1025 Status
= PciIoDevice
->PciRootBridgeIo
->GetAttributes (
1026 PciIoDevice
->PciRootBridgeIo
,
1027 &PciIoDevice
->Supports
,
1028 &PciIoDevice
->Attributes
1030 if (EFI_ERROR (Status
)) {
1036 // Set the attributes to be checked for common PCI devices and PPB or P2C
1037 // Since some devices only support part of them, it is better to set the
1038 // attribute according to its command or bridge control register
1040 Command
= EFI_PCI_COMMAND_IO_SPACE
|
1041 EFI_PCI_COMMAND_MEMORY_SPACE
|
1042 EFI_PCI_COMMAND_BUS_MASTER
|
1043 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP
;
1045 BridgeControl
= EFI_PCI_BRIDGE_CONTROL_ISA
| EFI_PCI_BRIDGE_CONTROL_VGA
| EFI_PCI_BRIDGE_CONTROL_VGA_16
;
1048 // Test whether the device can support attributes above
1050 PciTestSupportedAttribute (PciIoDevice
, &Command
, &BridgeControl
, &OldCommand
, &OldBridgeControl
);
1053 // Set the supported attributes for specified PCI device
1055 PciSetDeviceAttribute (PciIoDevice
, Command
, BridgeControl
, EFI_SET_SUPPORTS
);
1058 // Set the current attributes for specified PCI device
1060 PciSetDeviceAttribute (PciIoDevice
, OldCommand
, OldBridgeControl
, EFI_SET_ATTRIBUTES
);
1063 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL
1065 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice
, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE
);
1068 FastB2BSupport
= TRUE
;
1071 // P2C can not support FB2B on the secondary side
1073 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
1074 FastB2BSupport
= FALSE
;
1078 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1080 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1081 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1083 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1084 Status
= DetermineDeviceAttribute (Temp
);
1085 if (EFI_ERROR (Status
)) {
1089 // Detect Fast Bact to Bact support for the device under the bridge
1091 Status
= GetFastBackToBackSupport (Temp
, PCI_PRIMARY_STATUS_OFFSET
);
1092 if (FastB2BSupport
&& EFI_ERROR (Status
)) {
1093 FastB2BSupport
= FALSE
;
1096 CurrentLink
= CurrentLink
->ForwardLink
;
1099 // Set or clear Fast Back to Back bit for the whole bridge
1101 if (!IsListEmpty (&PciIoDevice
->ChildList
)) {
1103 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
1105 Status
= GetFastBackToBackSupport (PciIoDevice
, PCI_BRIDGE_STATUS_REGISTER_OFFSET
);
1107 if (EFI_ERROR (Status
) || (!FastB2BSupport
)) {
1108 FastB2BSupport
= FALSE
;
1109 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1111 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice
, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK
);
1115 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
1116 while (CurrentLink
!= NULL
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
1117 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1118 if (FastB2BSupport
) {
1119 PCI_ENABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1121 PCI_DISABLE_COMMAND_REGISTER (Temp
, EFI_PCI_COMMAND_FAST_BACK_TO_BACK
);
1124 CurrentLink
= CurrentLink
->ForwardLink
;
1128 // End for IsListEmpty
1134 This routine is used to update the bar information for those incompatible PCI device.
1136 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1139 @retval EFI_SUCCESS Successfully updated bar information.
1140 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1145 IN OUT PCI_IO_DEVICE
*PciIoDevice
1152 VOID
*Configuration
;
1153 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Ptr
;
1155 Configuration
= NULL
;
1156 Status
= EFI_SUCCESS
;
1158 if (gEfiIncompatiblePciDeviceSupport
== NULL
) {
1160 // It can only be supported after the Incompatible PCI Device
1161 // Support Protocol has been installed
1163 Status
= gBS
->LocateProtocol (
1164 &gEfiIncompatiblePciDeviceSupportProtocolGuid
,
1166 (VOID
**) &gEfiIncompatiblePciDeviceSupport
1169 if (Status
== EFI_SUCCESS
) {
1171 // Check whether the device belongs to incompatible devices from protocol or not
1172 // If it is , then get its special requirement in the ACPI table
1174 Status
= gEfiIncompatiblePciDeviceSupport
->CheckDevice (
1175 gEfiIncompatiblePciDeviceSupport
,
1176 PciIoDevice
->Pci
.Hdr
.VendorId
,
1177 PciIoDevice
->Pci
.Hdr
.DeviceId
,
1178 PciIoDevice
->Pci
.Hdr
.RevisionID
,
1179 PciIoDevice
->Pci
.Device
.SubsystemVendorID
,
1180 PciIoDevice
->Pci
.Device
.SubsystemID
,
1186 if (EFI_ERROR (Status
) || Configuration
== NULL
) {
1187 return EFI_UNSUPPORTED
;
1191 // Update PCI device information from the ACPI table
1193 Ptr
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
;
1195 while (Ptr
->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
1197 if (Ptr
->Desc
!= ACPI_ADDRESS_SPACE_DESCRIPTOR
) {
1199 // The format is not support
1204 BarIndex
= (UINTN
) Ptr
->AddrTranslationOffset
;
1205 BarEndIndex
= BarIndex
;
1208 // Update all the bars in the device
1210 if (BarIndex
== PCI_BAR_ALL
) {
1212 BarEndIndex
= PCI_MAX_BAR
- 1;
1215 if (BarIndex
> PCI_MAX_BAR
) {
1220 for (; BarIndex
<= BarEndIndex
; BarIndex
++) {
1222 switch (Ptr
->ResType
) {
1223 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
1226 // Make sure the bar is memory type
1228 if (CheckBarType (PciIoDevice
, (UINT8
) BarIndex
, PciBarTypeMem
)) {
1233 case ACPI_ADDRESS_SPACE_TYPE_IO
:
1236 // Make sure the bar is IO type
1238 if (CheckBarType (PciIoDevice
, (UINT8
) BarIndex
, PciBarTypeIo
)) {
1247 // Update the new alignment for the device
1249 SetNewAlign (&(PciIoDevice
->PciBar
[BarIndex
].Alignment
), Ptr
->AddrRangeMax
);
1252 // Update the new length for the device
1254 if (Ptr
->AddrLen
!= PCI_BAR_NOCHANGE
) {
1255 PciIoDevice
->PciBar
[BarIndex
].Length
= Ptr
->AddrLen
;
1263 FreePool (Configuration
);
1269 This routine will update the alignment with the new alignment.
1271 @param Alignment Input Old alignment. Output updated alignment.
1272 @param NewAlignment New alignment.
1277 IN OUT UINT64
*Alignment
,
1278 IN UINT64 NewAlignment
1281 UINT64 OldAlignment
;
1285 // The new alignment is the same as the original,
1288 if (NewAlignment
== PCI_BAR_OLD_ALIGN
) {
1292 // Check the validity of the parameter
1294 if (NewAlignment
!= PCI_BAR_EVEN_ALIGN
&&
1295 NewAlignment
!= PCI_BAR_SQUAD_ALIGN
&&
1296 NewAlignment
!= PCI_BAR_DQUAD_ALIGN
) {
1297 *Alignment
= NewAlignment
;
1301 OldAlignment
= (*Alignment
) + 1;
1305 // Get the first non-zero hex value of the length
1307 while ((OldAlignment
& 0x0F) == 0x00) {
1308 OldAlignment
= RShiftU64 (OldAlignment
, 4);
1313 // Adjust the alignment to even, quad or double quad boundary
1315 if (NewAlignment
== PCI_BAR_EVEN_ALIGN
) {
1316 if ((OldAlignment
& 0x01) != 0) {
1317 OldAlignment
= OldAlignment
+ 2 - (OldAlignment
& 0x01);
1319 } else if (NewAlignment
== PCI_BAR_SQUAD_ALIGN
) {
1320 if ((OldAlignment
& 0x03) != 0) {
1321 OldAlignment
= OldAlignment
+ 4 - (OldAlignment
& 0x03);
1323 } else if (NewAlignment
== PCI_BAR_DQUAD_ALIGN
) {
1324 if ((OldAlignment
& 0x07) != 0) {
1325 OldAlignment
= OldAlignment
+ 8 - (OldAlignment
& 0x07);
1330 // Update the old value
1332 NewAlignment
= LShiftU64 (OldAlignment
, ShiftBit
) - 1;
1333 *Alignment
= NewAlignment
;
1339 Parse PCI IOV VF bar information and fill them into PCI device instance.
1341 @param PciIoDevice Pci device instance.
1342 @param Offset Bar offset.
1343 @param BarIndex Bar index.
1345 @return Next bar offset.
1350 IN PCI_IO_DEVICE
*PciIoDevice
,
1356 UINT32 OriginalValue
;
1363 // Ensure it is called properly
1365 ASSERT (PciIoDevice
->SrIovCapabilityOffset
!= 0);
1366 if (PciIoDevice
->SrIovCapabilityOffset
== 0) {
1373 Status
= VfBarExisted (
1380 if (EFI_ERROR (Status
)) {
1381 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1382 PciIoDevice
->VfPciBar
[BarIndex
].Length
= 0;
1383 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1386 // Scan all the BARs anyway
1388 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT8
) Offset
;
1392 PciIoDevice
->VfPciBar
[BarIndex
].Offset
= (UINT8
) Offset
;
1395 // Device I/Os. Impossible
1404 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1406 switch (Value
& 0x07) {
1409 //memory space; anywhere in 32 bit address space
1413 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1415 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1418 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1419 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1424 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1428 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1429 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1435 // memory space; anywhere in 64 bit address space
1439 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1441 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1445 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1446 // is regarded as an extension for the first bar. As a result
1447 // the sizing will be conducted on combined 64 bit value
1448 // Here just store the masked first 32bit value for future size
1451 PciIoDevice
->VfPciBar
[BarIndex
].Length
= Value
& Mask
;
1452 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1454 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1455 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1459 // Increment the offset to point to next DWORD
1463 Status
= VfBarExisted (
1470 if (EFI_ERROR (Status
)) {
1475 // Fix the length to support some spefic 64 bit BAR
1479 for (Data
= Value
; Data
!= 0; Data
>>= 1) {
1482 Value
|= ((UINT32
)(-1) << Index
);
1485 // Calculate the size of 64bit bar
1487 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
) OriginalValue
, 32);
1489 PciIoDevice
->VfPciBar
[BarIndex
].Length
= PciIoDevice
->VfPciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
) Value
, 32);
1490 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(PciIoDevice
->VfPciBar
[BarIndex
].Length
)) + 1;
1491 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1496 PciIoDevice
->VfPciBar
[BarIndex
].Length
= MultU64x32 (PciIoDevice
->VfPciBar
[BarIndex
].Length
, PciIoDevice
->InitialVFs
);
1500 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1501 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1510 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1511 PciIoDevice
->VfPciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1512 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->VfPciBar
[BarIndex
].Length
- 1;
1514 if (PciIoDevice
->VfPciBar
[BarIndex
].Alignment
< PciIoDevice
->SystemPageSize
- 1) {
1515 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= PciIoDevice
->SystemPageSize
- 1;
1523 // Check the length again so as to keep compatible with some special bars
1525 if (PciIoDevice
->VfPciBar
[BarIndex
].Length
== 0) {
1526 PciIoDevice
->VfPciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1527 PciIoDevice
->VfPciBar
[BarIndex
].BaseAddress
= 0;
1528 PciIoDevice
->VfPciBar
[BarIndex
].Alignment
= 0;
1532 // Increment number of bar
1538 Parse PCI bar information and fill them into PCI device instance.
1540 @param PciIoDevice Pci device instance.
1541 @param Offset Bar offset.
1542 @param BarIndex Bar index.
1544 @return Next bar offset.
1549 IN PCI_IO_DEVICE
*PciIoDevice
,
1555 UINT32 OriginalValue
;
1564 Status
= BarExisted (
1571 if (EFI_ERROR (Status
)) {
1572 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= 0;
1573 PciIoDevice
->PciBar
[BarIndex
].Length
= 0;
1574 PciIoDevice
->PciBar
[BarIndex
].Alignment
= 0;
1577 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1579 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
) Offset
;
1583 PciIoDevice
->PciBar
[BarIndex
].Offset
= (UINT8
) Offset
;
1584 if ((Value
& 0x01) != 0) {
1590 if ((Value
& 0xFFFF0000) != 0) {
1594 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo32
;
1595 PciIoDevice
->PciBar
[BarIndex
].Length
= ((~(Value
& Mask
)) + 1);
1596 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1602 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeIo16
;
1603 PciIoDevice
->PciBar
[BarIndex
].Length
= 0x0000FFFF & ((~(Value
& Mask
)) + 1);
1604 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1608 // Workaround. Some platforms inplement IO bar with 0 length
1609 // Need to treat it as no-bar
1611 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1612 PciIoDevice
->PciBar
[BarIndex
].BarType
= (PCI_BAR_TYPE
) 0;
1615 PciIoDevice
->PciBar
[BarIndex
].Prefetchable
= FALSE
;
1616 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1622 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= OriginalValue
& Mask
;
1624 switch (Value
& 0x07) {
1627 //memory space; anywhere in 32 bit address space
1630 if ((Value
& 0x08) != 0) {
1631 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem32
;
1633 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem32
;
1636 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1637 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1639 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1641 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1643 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1648 // memory space; anywhere in 64 bit address space
1651 if ((Value
& 0x08) != 0) {
1652 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypePMem64
;
1654 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeMem64
;
1658 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1659 // is regarded as an extension for the first bar. As a result
1660 // the sizing will be conducted on combined 64 bit value
1661 // Here just store the masked first 32bit value for future size
1664 PciIoDevice
->PciBar
[BarIndex
].Length
= Value
& Mask
;
1665 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1668 // Increment the offset to point to next DWORD
1672 Status
= BarExisted (
1679 if (EFI_ERROR (Status
)) {
1681 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
1683 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1685 // some device implement MMIO bar with 0 length, need to treat it as no-bar
1687 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1693 // Fix the length to support some spefic 64 bit BAR
1697 for (Data
= Value
; Data
!= 0; Data
>>= 1) {
1700 Value
|= ((UINT32
)(-1) << Index
);
1703 // Calculate the size of 64bit bar
1705 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
|= LShiftU64 ((UINT64
) OriginalValue
, 32);
1707 PciIoDevice
->PciBar
[BarIndex
].Length
= PciIoDevice
->PciBar
[BarIndex
].Length
| LShiftU64 ((UINT64
) Value
, 32);
1708 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(PciIoDevice
->PciBar
[BarIndex
].Length
)) + 1;
1709 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1711 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1713 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1715 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1724 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1725 PciIoDevice
->PciBar
[BarIndex
].Length
= (~(Value
& Mask
)) + 1;
1726 if (PciIoDevice
->PciBar
[BarIndex
].Length
< (SIZE_4KB
)) {
1728 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1730 PciIoDevice
->PciBar
[BarIndex
].Alignment
= (SIZE_4KB
- 1);
1732 PciIoDevice
->PciBar
[BarIndex
].Alignment
= PciIoDevice
->PciBar
[BarIndex
].Length
- 1;
1739 // Check the length again so as to keep compatible with some special bars
1741 if (PciIoDevice
->PciBar
[BarIndex
].Length
== 0) {
1742 PciIoDevice
->PciBar
[BarIndex
].BarType
= PciBarTypeUnknown
;
1743 PciIoDevice
->PciBar
[BarIndex
].BaseAddress
= 0;
1744 PciIoDevice
->PciBar
[BarIndex
].Alignment
= 0;
1748 // Increment number of bar
1754 This routine is used to initialize the bar of a PCI device.
1756 @param PciIoDevice Pci device instance.
1758 @note It can be called typically when a device is going to be rejected.
1762 InitializePciDevice (
1763 IN PCI_IO_DEVICE
*PciIoDevice
1766 EFI_PCI_IO_PROTOCOL
*PciIo
;
1769 PciIo
= &(PciIoDevice
->PciIo
);
1772 // Put all the resource apertures
1773 // Resource base is set to all ones so as to indicate its resource
1774 // has not been alloacted
1776 for (Offset
= 0x10; Offset
<= 0x24; Offset
+= sizeof (UINT32
)) {
1777 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllOne
);
1782 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1784 @param PciIoDevice PCI-PCI bridge device instance.
1789 IN PCI_IO_DEVICE
*PciIoDevice
1792 EFI_PCI_IO_PROTOCOL
*PciIo
;
1794 PciIo
= &(PciIoDevice
->PciIo
);
1797 // Put all the resource apertures including IO16
1798 // Io32, pMem32, pMem64 to quiescent state
1799 // Resource base all ones, Resource limit all zeros
1801 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1C, 1, &gAllOne
);
1802 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x1D, 1, &gAllZero
);
1804 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x20, 1, &gAllOne
);
1805 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x22, 1, &gAllZero
);
1807 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x24, 1, &gAllOne
);
1808 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x26, 1, &gAllZero
);
1810 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x28, 1, &gAllOne
);
1811 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x2C, 1, &gAllZero
);
1814 // Don't support use io32 as for now
1816 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x30, 1, &gAllOne
);
1817 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x32, 1, &gAllZero
);
1820 // Force Interrupt line to zero for cards that come up randomly
1822 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x3C, 1, &gAllZero
);
1826 This routine is used to initialize the bar of a PCI Card Bridge device.
1828 @param PciIoDevice PCI Card bridge device.
1833 IN PCI_IO_DEVICE
*PciIoDevice
1836 EFI_PCI_IO_PROTOCOL
*PciIo
;
1838 PciIo
= &(PciIoDevice
->PciIo
);
1841 // Put all the resource apertures including IO16
1842 // Io32, pMem32, pMem64 to quiescent state(
1843 // Resource base all ones, Resource limit all zeros
1845 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x1c, 1, &gAllOne
);
1846 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x20, 1, &gAllZero
);
1848 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x24, 1, &gAllOne
);
1849 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x28, 1, &gAllZero
);
1851 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x2c, 1, &gAllOne
);
1852 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x30, 1, &gAllZero
);
1854 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x34, 1, &gAllOne
);
1855 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 0x38, 1, &gAllZero
);
1858 // Force Interrupt line to zero for cards that come up randomly
1860 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x3C, 1, &gAllZero
);
1864 Create and initiliaze general PCI I/O device instance for
1865 PCI device/bridge device/hotplug bridge device.
1867 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1868 @param Pci Input Pci information block.
1869 @param Bus Device Bus NO.
1870 @param Device Device device NO.
1871 @param Func Device func NO.
1873 @return Instance of PCI device. NULL means no instance created.
1878 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
1885 PCI_IO_DEVICE
*PciIoDevice
;
1886 EFI_PCI_IO_PROTOCOL
*PciIo
;
1889 PciIoDevice
= AllocateZeroPool (sizeof (PCI_IO_DEVICE
));
1890 if (PciIoDevice
== NULL
) {
1894 PciIoDevice
->Signature
= PCI_IO_DEVICE_SIGNATURE
;
1895 PciIoDevice
->Handle
= NULL
;
1896 PciIoDevice
->PciRootBridgeIo
= PciRootBridgeIo
;
1897 PciIoDevice
->DevicePath
= NULL
;
1898 PciIoDevice
->BusNumber
= Bus
;
1899 PciIoDevice
->DeviceNumber
= Device
;
1900 PciIoDevice
->FunctionNumber
= Func
;
1901 PciIoDevice
->Decodes
= 0;
1903 if (gFullEnumeration
) {
1904 PciIoDevice
->Allocated
= FALSE
;
1906 PciIoDevice
->Allocated
= TRUE
;
1909 PciIoDevice
->Registered
= FALSE
;
1910 PciIoDevice
->Attributes
= 0;
1911 PciIoDevice
->Supports
= 0;
1912 PciIoDevice
->BusOverride
= FALSE
;
1913 PciIoDevice
->AllOpRomProcessed
= FALSE
;
1915 PciIoDevice
->IsPciExp
= FALSE
;
1917 CopyMem (&(PciIoDevice
->Pci
), Pci
, sizeof (PCI_TYPE01
));
1920 // Initialize the PCI I/O instance structure
1922 InitializePciIoInstance (PciIoDevice
);
1923 InitializePciDriverOverrideInstance (PciIoDevice
);
1924 InitializePciLoadFile2 (PciIoDevice
);
1925 PciIo
= &PciIoDevice
->PciIo
;
1928 // Detect if PCI Express Device
1930 PciIoDevice
->PciExpressCapabilityOffset
= 0;
1931 Status
= LocateCapabilityRegBlock (
1933 EFI_PCI_CAPABILITY_ID_PCIEXP
,
1934 &PciIoDevice
->PciExpressCapabilityOffset
,
1937 if (!EFI_ERROR (Status
)) {
1938 PciIoDevice
->IsPciExp
= TRUE
;
1942 // Initialize for PCI IOV
1946 // Check ARI for function 0 only
1948 Status
= LocatePciExpressCapabilityRegBlock (
1950 EFI_PCIE_CAPABILITY_ID_ARI
,
1951 &PciIoDevice
->AriCapabilityOffset
,
1954 if (!EFI_ERROR (Status
)) {
1957 "PCI-IOV B%x.D%x.F%x - ARI Cap offset - 0x%x\n",
1961 (UINTN
)PciIoDevice
->AriCapabilityOffset
1965 Status
= LocatePciExpressCapabilityRegBlock (
1967 EFI_PCIE_CAPABILITY_ID_SRIOV
,
1968 &PciIoDevice
->SrIovCapabilityOffset
,
1971 if (!EFI_ERROR (Status
)) {
1974 "PCI-IOV B%x.D%x.F%x - SRIOV Cap offset - 0x%x\n",
1978 (UINTN
)PciIoDevice
->SrIovCapabilityOffset
1982 Status
= LocatePciExpressCapabilityRegBlock (
1984 EFI_PCIE_CAPABILITY_ID_MRIOV
,
1985 &PciIoDevice
->MrIovCapabilityOffset
,
1988 if (!EFI_ERROR (Status
)) {
1991 "PCI-IOV B%x.D%x.F%x - MRIOV Cap offset - 0x%x\n",
1995 (UINTN
)PciIoDevice
->MrIovCapabilityOffset
2000 // Calculate SystemPageSize
2002 if ((PciIoDevice
->SrIovCapabilityOffset
!= 0) && ((FeaturePcdGet(PcdSrIovSupport
)& EFI_PCI_IOV_POLICY_SRIOV
) != 0)) {
2006 EfiPciIoWidthUint32
,
2007 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE
,
2009 &PciIoDevice
->SystemPageSize
2011 DEBUG ((EFI_D_INFO
, "PCI-IOV B%x.D%x.F%x - SupportedPageSize - 0x%x\n", (UINTN
)Bus
, (UINTN
)Device
, (UINTN
)Func
, PciIoDevice
->SystemPageSize
));
2013 PciIoDevice
->SystemPageSize
= (PcdGet32(PcdSrIovSystemPageSize
) & PciIoDevice
->SystemPageSize
);
2014 ASSERT (PciIoDevice
->SystemPageSize
!= 0);
2018 EfiPciIoWidthUint32
,
2019 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE
,
2021 &PciIoDevice
->SystemPageSize
2023 DEBUG ((EFI_D_INFO
, "PCI-IOV B%x.D%x.F%x - SystemPageSize - 0x%x\n", (UINTN
)Bus
, (UINTN
)Device
, (UINTN
)Func
, PciIoDevice
->SystemPageSize
));
2025 // Adjust SystemPageSize for Alignment usage later
2027 PciIoDevice
->SystemPageSize
<<= 12;
2030 // Calculate BusReservation for PCI IOV
2032 if ((PciIoDevice
->SrIovCapabilityOffset
!= 0) && ((FeaturePcdGet(PcdSrIovSupport
)& EFI_PCI_IOV_POLICY_SRIOV
) != 0)) {
2034 UINT16 FirstVFOffset
;
2039 // Read First FirstVFOffset, InitialVFs, and VFStride
2043 EfiPciIoWidthUint16
,
2044 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF
,
2048 DEBUG ((EFI_D_INFO
, "PCI-IOV B%x.D%x.F%x - FirstVFOffset - 0x%x\n", (UINTN
)Bus
, (UINTN
)Device
, (UINTN
)Func
, (UINTN
)FirstVFOffset
));
2052 EfiPciIoWidthUint16
,
2053 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS
,
2055 &PciIoDevice
->InitialVFs
2057 DEBUG ((EFI_D_INFO
, "PCI-IOV B%x.D%x.F%x - InitialVFs - 0x%x\n", (UINTN
)Bus
, (UINTN
)Device
, (UINTN
)Func
, (UINTN
)PciIoDevice
->InitialVFs
));
2061 EfiPciIoWidthUint16
,
2062 PciIoDevice
->SrIovCapabilityOffset
+ EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE
,
2066 DEBUG ((EFI_D_INFO
, "PCI-IOV B%x.D%x.F%x - VFStride - 0x%x\n", (UINTN
)Bus
, (UINTN
)Device
, (UINTN
)Func
, (UINTN
)VFStride
));
2071 PFRID
= EFI_PCI_RID(Bus
, Device
, Func
);
2072 LastVF
= PFRID
+ FirstVFOffset
+ (PciIoDevice
->InitialVFs
- 1) * VFStride
;
2075 // Calculate ReservedBusNum for this PF
2077 PciIoDevice
->ReservedBusNum
= (UINT16
)(EFI_PCI_BUS_OF_RID (LastVF
) - Bus
+ 1);
2078 DEBUG ((EFI_D_INFO
, "PCI-IOV B%x.D%x.F%x - reserved bus number - 0x%x\n", (UINTN
)Bus
, (UINTN
)Device
, (UINTN
)Func
, (UINTN
)PciIoDevice
->ReservedBusNum
));
2083 // Initialize the reserved resource list
2085 InitializeListHead (&PciIoDevice
->ReservedResourceList
);
2088 // Initialize the driver list
2090 InitializeListHead (&PciIoDevice
->OptionRomDriverList
);
2093 // Initialize the child list
2095 InitializeListHead (&PciIoDevice
->ChildList
);
2101 This routine is used to enumerate entire pci bus system
2102 in a given platform.
2104 It is only called on the second start on the same Root Bridge.
2106 @param Controller Parent bridge handler.
2108 @retval EFI_SUCCESS PCI enumeration finished successfully.
2109 @retval other Some error occurred when enumerating the pci bus system.
2113 PciEnumeratorLight (
2114 IN EFI_HANDLE Controller
2119 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2120 PCI_IO_DEVICE
*RootBridgeDev
;
2123 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
2126 MaxBus
= PCI_MAX_BUS
;
2130 // If this root bridge has been already enumerated, then return successfully
2132 if (GetRootBridgeByHandle (Controller
) != NULL
) {
2137 // Open pci root bridge io protocol
2139 Status
= gBS
->OpenProtocol (
2141 &gEfiPciRootBridgeIoProtocolGuid
,
2142 (VOID
**) &PciRootBridgeIo
,
2143 gPciBusDriverBinding
.DriverBindingHandle
,
2145 EFI_OPEN_PROTOCOL_BY_DRIVER
2147 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
2151 Status
= PciRootBridgeIo
->Configuration (PciRootBridgeIo
, (VOID
**) &Descriptors
);
2153 if (EFI_ERROR (Status
)) {
2157 while (PciGetBusRange (&Descriptors
, &MinBus
, &MaxBus
, NULL
) == EFI_SUCCESS
) {
2160 // Create a device node for root bridge device with a NULL host bridge controller handle
2162 RootBridgeDev
= CreateRootBridge (Controller
);
2164 if (RootBridgeDev
== NULL
) {
2170 // Record the root bridgeio protocol
2172 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2174 Status
= PciPciDeviceInfoCollector (
2179 if (!EFI_ERROR (Status
)) {
2182 // Remove those PCI devices which are rejected when full enumeration
2184 RemoveRejectedPciDevices (RootBridgeDev
->Handle
, RootBridgeDev
);
2187 // Process option rom light
2189 ProcessOptionRomLight (RootBridgeDev
);
2192 // Determine attributes for all devices under this root bridge
2194 DetermineDeviceAttribute (RootBridgeDev
);
2197 // If successfully, insert the node into device pool
2199 InsertRootBridge (RootBridgeDev
);
2203 // If unsuccessly, destroy the entire node
2205 DestroyRootBridge (RootBridgeDev
);
2215 Get bus range from PCI resource descriptor list.
2217 @param Descriptors A pointer to the address space descriptor.
2218 @param MinBus The min bus returned.
2219 @param MaxBus The max bus returned.
2220 @param BusRange The bus range returned.
2222 @retval EFI_SUCCESS Successfully got bus range.
2223 @retval EFI_NOT_FOUND Can not find the specific bus.
2228 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
**Descriptors
,
2231 OUT UINT16
*BusRange
2234 while ((*Descriptors
)->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
2235 if ((*Descriptors
)->ResType
== ACPI_ADDRESS_SPACE_TYPE_BUS
) {
2236 if (MinBus
!= NULL
) {
2237 *MinBus
= (UINT16
) (*Descriptors
)->AddrRangeMin
;
2240 if (MaxBus
!= NULL
) {
2241 *MaxBus
= (UINT16
) (*Descriptors
)->AddrRangeMax
;
2244 if (BusRange
!= NULL
) {
2245 *BusRange
= (UINT16
) (*Descriptors
)->AddrLen
;
2254 return EFI_NOT_FOUND
;
2258 This routine can be used to start the root bridge.
2260 @param RootBridgeDev Pci device instance.
2262 @retval EFI_SUCCESS This device started.
2263 @retval other Failed to get PCI Root Bridge I/O protocol.
2267 StartManagingRootBridge (
2268 IN PCI_IO_DEVICE
*RootBridgeDev
2271 EFI_HANDLE RootBridgeHandle
;
2273 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2276 // Get the root bridge handle
2278 RootBridgeHandle
= RootBridgeDev
->Handle
;
2279 PciRootBridgeIo
= NULL
;
2282 // Get the pci root bridge io protocol
2284 Status
= gBS
->OpenProtocol (
2286 &gEfiPciRootBridgeIoProtocolGuid
,
2287 (VOID
**) &PciRootBridgeIo
,
2288 gPciBusDriverBinding
.DriverBindingHandle
,
2290 EFI_OPEN_PROTOCOL_BY_DRIVER
2293 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
2298 // Store the PciRootBridgeIo protocol into root bridge private data
2300 RootBridgeDev
->PciRootBridgeIo
= PciRootBridgeIo
;
2307 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2309 @param PciIoDevice Pci device instance.
2311 @retval TRUE This device should be rejected.
2312 @retval FALSE This device shouldn't be rejected.
2316 IsPciDeviceRejected (
2317 IN PCI_IO_DEVICE
*PciIoDevice
2327 // PPB should be skip!
2329 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
2333 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Pci
)) {
2335 // Only test base registers for P2C
2337 for (BarOffset
= 0x1C; BarOffset
<= 0x38; BarOffset
+= 2 * sizeof (UINT32
)) {
2339 Mask
= (BarOffset
< 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2340 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2341 if (EFI_ERROR (Status
)) {
2345 TestValue
= TestValue
& Mask
;
2346 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2348 // The bar isn't programed, so it should be rejected
2357 for (BarOffset
= 0x14; BarOffset
<= 0x24; BarOffset
+= sizeof (UINT32
)) {
2361 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2362 if (EFI_ERROR (Status
)) {
2366 if ((TestValue
& 0x01) != 0) {
2372 TestValue
= TestValue
& Mask
;
2373 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2383 TestValue
= TestValue
& Mask
;
2385 if ((TestValue
& 0x07) == 0x04) {
2390 BarOffset
+= sizeof (UINT32
);
2391 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2394 // Test its high 32-Bit BAR
2396 Status
= BarExisted (PciIoDevice
, BarOffset
, &TestValue
, &OldValue
);
2397 if (TestValue
== OldValue
) {
2407 if ((TestValue
!= 0) && (TestValue
== (OldValue
& Mask
))) {
2418 Reset all bus number from specific bridge.
2420 @param Bridge Parent specific bridge.
2421 @param StartBusNumber Start bus number.
2425 ResetAllPpbBusNumber (
2426 IN PCI_IO_DEVICE
*Bridge
,
2427 IN UINT8 StartBusNumber
2437 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
2439 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
2441 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
2442 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
2445 // Check to see whether a pci device is present
2447 Status
= PciDevicePresent (
2455 if (!EFI_ERROR (Status
) && (IS_PCI_BRIDGE (&Pci
))) {
2458 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
2459 Status
= PciRootBridgeIo
->Pci
.Read (
2466 SecondaryBus
= (UINT8
)(Register
>> 8);
2468 if (SecondaryBus
!= 0) {
2469 ResetAllPpbBusNumber (Bridge
, SecondaryBus
);
2473 // Reset register 18h, 19h, 1Ah on PCI Bridge
2475 Register
&= 0xFF000000;
2476 Status
= PciRootBridgeIo
->Pci
.Write (
2485 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
2487 // Skip sub functions, this is not a multi function device
2489 Func
= PCI_MAX_FUNC
;