2 PCI resouces support functions implemntation for PCI Bus module.
4 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
5 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 // The default policy for the PCI bus driver is NOT to reserve I/O ranges for both ISA aliases and VGA aliases.
20 BOOLEAN mReserveIsaAliases
= FALSE
;
21 BOOLEAN mReserveVgaAliases
= FALSE
;
22 BOOLEAN mPolicyDetermined
= FALSE
;
25 The function is used to skip VGA range.
27 @param Start Returned start address including VGA range.
28 @param Length The length of VGA range.
42 ASSERT (Start
!= NULL
);
44 // For legacy VGA, bit 10 to bit 15 is not decoded
49 StartOffset
= Original
& Mask
;
50 LimitOffset
= ((*Start
) + Length
- 1) & Mask
;
51 if (LimitOffset
>= VGABASE1
) {
52 *Start
= *Start
- StartOffset
+ VGALIMIT2
+ 1;
57 This function is used to skip ISA aliasing aperture.
59 @param Start Returned start address including ISA aliasing aperture.
60 @param Length The length of ISA aliasing aperture.
64 SkipIsaAliasAperture (
75 ASSERT (Start
!= NULL
);
78 // For legacy ISA, bit 10 to bit 15 is not decoded
83 StartOffset
= Original
& Mask
;
84 LimitOffset
= ((*Start
) + Length
- 1) & Mask
;
86 if (LimitOffset
>= ISABASE
) {
87 *Start
= *Start
- StartOffset
+ ISALIMIT
+ 1;
92 This function inserts a resource node into the resource list.
93 The resource list is sorted in descend order.
95 @param Bridge PCI resource node for bridge.
96 @param ResNode Resource node want to be inserted.
101 IN OUT PCI_RESOURCE_NODE
*Bridge
,
102 IN PCI_RESOURCE_NODE
*ResNode
105 LIST_ENTRY
*CurrentLink
;
106 PCI_RESOURCE_NODE
*Temp
;
107 UINT64 ResNodeAlignRest
;
108 UINT64 TempAlignRest
;
110 ASSERT (Bridge
!= NULL
);
111 ASSERT (ResNode
!= NULL
);
113 InsertHeadList (&Bridge
->ChildList
, &ResNode
->Link
);
115 CurrentLink
= Bridge
->ChildList
.ForwardLink
->ForwardLink
;
116 while (CurrentLink
!= &Bridge
->ChildList
) {
117 Temp
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
119 if (ResNode
->Alignment
> Temp
->Alignment
) {
121 } else if (ResNode
->Alignment
== Temp
->Alignment
) {
122 ResNodeAlignRest
= ResNode
->Length
& ResNode
->Alignment
;
123 TempAlignRest
= Temp
->Length
& Temp
->Alignment
;
124 if ((ResNodeAlignRest
== 0) || (ResNodeAlignRest
>= TempAlignRest
)) {
129 SwapListEntries (&ResNode
->Link
, CurrentLink
);
131 CurrentLink
= ResNode
->Link
.ForwardLink
;
136 This routine is used to merge two different resource trees in need of
139 For example, if an upstream PPB doesn't support,
140 prefetchable memory decoding, the PCI bus driver will choose to call this function
141 to merge prefectchable memory resource list into normal memory list.
143 If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
145 If Dst is NULL or Res is NULL, ASSERT ().
147 @param Dst Point to destination resource tree.
148 @param Res Point to source resource tree.
149 @param TypeMerge If the TypeMerge is TRUE, Res resource type is changed to the type of
150 destination resource type.
155 IN PCI_RESOURCE_NODE
*Dst
,
156 IN PCI_RESOURCE_NODE
*Res
,
161 LIST_ENTRY
*CurrentLink
;
162 PCI_RESOURCE_NODE
*Temp
;
164 ASSERT (Dst
!= NULL
);
165 ASSERT (Res
!= NULL
);
167 while (!IsListEmpty (&Res
->ChildList
)) {
168 CurrentLink
= Res
->ChildList
.ForwardLink
;
170 Temp
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
173 Temp
->ResType
= Dst
->ResType
;
176 RemoveEntryList (CurrentLink
);
177 InsertResourceNode (Dst
, Temp
);
182 This function is used to calculate the IO16 aperture
185 @param Bridge PCI resource node for bridge.
189 CalculateApertureIo16 (
190 IN PCI_RESOURCE_NODE
*Bridge
195 LIST_ENTRY
*CurrentLink
;
196 PCI_RESOURCE_NODE
*Node
;
198 EFI_PCI_PLATFORM_POLICY PciPolicy
;
200 if (!mPolicyDetermined
) {
202 // Check PciPlatform policy
204 Status
= EFI_NOT_FOUND
;
206 if (gPciPlatformProtocol
!= NULL
) {
207 Status
= gPciPlatformProtocol
->GetPlatformPolicy (
208 gPciPlatformProtocol
,
213 if (EFI_ERROR (Status
) && gPciOverrideProtocol
!= NULL
) {
214 Status
= gPciOverrideProtocol
->GetPlatformPolicy (
215 gPciOverrideProtocol
,
220 if (!EFI_ERROR (Status
)) {
221 if ((PciPolicy
& EFI_RESERVE_ISA_IO_ALIAS
) != 0) {
222 mReserveIsaAliases
= TRUE
;
224 if ((PciPolicy
& EFI_RESERVE_VGA_IO_ALIAS
) != 0) {
225 mReserveVgaAliases
= TRUE
;
228 mPolicyDetermined
= TRUE
;
233 if (Bridge
== NULL
) {
237 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
240 // Assume the bridge is aligned
242 while (CurrentLink
!= &Bridge
->ChildList
) {
244 Node
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
247 // Consider the aperture alignment
249 Offset
= Aperture
& (Node
->Alignment
);
253 Aperture
= Aperture
+ (Node
->Alignment
+ 1) - Offset
;
258 // IsaEnable and VGAEnable can not be implemented now.
259 // If both of them are enabled, then the IO resource would
260 // become too limited to meet the requirement of most of devices.
262 if (mReserveIsaAliases
|| mReserveVgaAliases
) {
263 if (!IS_PCI_BRIDGE (&(Node
->PciDev
->Pci
)) && !IS_CARDBUS_BRIDGE (&(Node
->PciDev
->Pci
))) {
265 // Check if there is need to support ISA/VGA decoding
266 // If so, we need to avoid isa/vga aliasing range
268 if (mReserveIsaAliases
) {
269 SkipIsaAliasAperture (
273 Offset
= Aperture
& (Node
->Alignment
);
275 Aperture
= Aperture
+ (Node
->Alignment
+ 1) - Offset
;
277 } else if (mReserveVgaAliases
) {
282 Offset
= Aperture
& (Node
->Alignment
);
284 Aperture
= Aperture
+ (Node
->Alignment
+ 1) - Offset
;
290 Node
->Offset
= Aperture
;
293 // Increment aperture by the length of node
295 Aperture
+= Node
->Length
;
297 CurrentLink
= CurrentLink
->ForwardLink
;
301 // At last, adjust the aperture with the bridge's
304 Offset
= Aperture
& (Bridge
->Alignment
);
307 Aperture
= Aperture
+ (Bridge
->Alignment
+ 1) - Offset
;
310 Bridge
->Length
= Aperture
;
312 // At last, adjust the bridge's alignment to the first child's alignment
313 // if the bridge has at least one child
315 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
316 if (CurrentLink
!= &Bridge
->ChildList
) {
317 Node
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
318 if (Node
->Alignment
> Bridge
->Alignment
) {
319 Bridge
->Alignment
= Node
->Alignment
;
325 This function is used to calculate the resource aperture
326 for a given bridge device.
328 @param Bridge PCI resouce node for given bridge device.
332 CalculateResourceAperture (
333 IN PCI_RESOURCE_NODE
*Bridge
337 LIST_ENTRY
*CurrentLink
;
338 PCI_RESOURCE_NODE
*Node
;
344 if (Bridge
== NULL
) {
348 if (Bridge
->ResType
== PciBarTypeIo16
) {
350 CalculateApertureIo16 (Bridge
);
354 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
357 // Assume the bridge is aligned
359 while (CurrentLink
!= &Bridge
->ChildList
) {
361 Node
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
364 // Apply padding resource if available
366 Offset
= Aperture
& (Node
->Alignment
);
370 Aperture
= Aperture
+ (Node
->Alignment
+ 1) - Offset
;
375 // Recode current aperture as a offset
376 // this offset will be used in future real allocation
378 Node
->Offset
= Aperture
;
381 // Increment aperture by the length of node
383 Aperture
+= Node
->Length
;
386 // Consider the aperture alignment
388 CurrentLink
= CurrentLink
->ForwardLink
;
392 // At last, adjust the aperture with the bridge's
395 Offset
= Aperture
& (Bridge
->Alignment
);
397 Aperture
= Aperture
+ (Bridge
->Alignment
+ 1) - Offset
;
401 // If the bridge has already padded the resource and the
402 // amount of padded resource is larger, then keep the
405 if (Bridge
->Length
< Aperture
) {
406 Bridge
->Length
= Aperture
;
410 // At last, adjust the bridge's alignment to the first child's alignment
411 // if the bridge has at least one child
413 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
414 if (CurrentLink
!= &Bridge
->ChildList
) {
415 Node
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
416 if (Node
->Alignment
> Bridge
->Alignment
) {
417 Bridge
->Alignment
= Node
->Alignment
;
423 Get IO/Memory resource infor for given PCI device.
425 @param PciDev Pci device instance.
426 @param IoNode Resource info node for IO .
427 @param Mem32Node Resource info node for 32-bit memory.
428 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
429 @param Mem64Node Resource info node for 64-bit memory.
430 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
434 GetResourceFromDevice (
435 IN PCI_IO_DEVICE
*PciDev
,
436 IN OUT PCI_RESOURCE_NODE
*IoNode
,
437 IN OUT PCI_RESOURCE_NODE
*Mem32Node
,
438 IN OUT PCI_RESOURCE_NODE
*PMem32Node
,
439 IN OUT PCI_RESOURCE_NODE
*Mem64Node
,
440 IN OUT PCI_RESOURCE_NODE
*PMem64Node
445 PCI_RESOURCE_NODE
*Node
;
446 BOOLEAN ResourceRequested
;
449 ResourceRequested
= FALSE
;
451 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
453 switch ((PciDev
->PciBar
)[Index
].BarType
) {
455 case PciBarTypeMem32
:
457 Node
= CreateResourceNode (
459 (PciDev
->PciBar
)[Index
].Length
,
460 (PciDev
->PciBar
)[Index
].Alignment
,
471 ResourceRequested
= TRUE
;
474 case PciBarTypeMem64
:
476 Node
= CreateResourceNode (
478 (PciDev
->PciBar
)[Index
].Length
,
479 (PciDev
->PciBar
)[Index
].Alignment
,
490 ResourceRequested
= TRUE
;
493 case PciBarTypePMem64
:
495 Node
= CreateResourceNode (
497 (PciDev
->PciBar
)[Index
].Length
,
498 (PciDev
->PciBar
)[Index
].Alignment
,
509 ResourceRequested
= TRUE
;
512 case PciBarTypePMem32
:
514 Node
= CreateResourceNode (
516 (PciDev
->PciBar
)[Index
].Length
,
517 (PciDev
->PciBar
)[Index
].Alignment
,
527 ResourceRequested
= TRUE
;
533 Node
= CreateResourceNode (
535 (PciDev
->PciBar
)[Index
].Length
,
536 (PciDev
->PciBar
)[Index
].Alignment
,
546 ResourceRequested
= TRUE
;
549 case PciBarTypeUnknown
:
560 for (Index
= 0; Index
< PCI_MAX_BAR
; Index
++) {
562 switch ((PciDev
->VfPciBar
)[Index
].BarType
) {
564 case PciBarTypeMem32
:
566 Node
= CreateVfResourceNode (
568 (PciDev
->VfPciBar
)[Index
].Length
,
569 (PciDev
->VfPciBar
)[Index
].Alignment
,
582 case PciBarTypeMem64
:
584 Node
= CreateVfResourceNode (
586 (PciDev
->VfPciBar
)[Index
].Length
,
587 (PciDev
->VfPciBar
)[Index
].Alignment
,
600 case PciBarTypePMem64
:
602 Node
= CreateVfResourceNode (
604 (PciDev
->VfPciBar
)[Index
].Length
,
605 (PciDev
->VfPciBar
)[Index
].Alignment
,
618 case PciBarTypePMem32
:
620 Node
= CreateVfResourceNode (
622 (PciDev
->VfPciBar
)[Index
].Length
,
623 (PciDev
->VfPciBar
)[Index
].Alignment
,
639 case PciBarTypeUnknown
:
646 // If there is no resource requested from this device,
647 // then we indicate this device has been allocated naturally.
649 if (!ResourceRequested
) {
650 PciDev
->Allocated
= TRUE
;
655 This function is used to create a resource node.
657 @param PciDev Pci device instance.
658 @param Length Length of Io/Memory resource.
659 @param Alignment Alignment of resource.
660 @param Bar Bar index.
661 @param ResType Type of resource: IO/Memory.
662 @param ResUsage Resource usage.
664 @return PCI resource node created for given PCI device.
665 NULL means PCI resource node is not created.
670 IN PCI_IO_DEVICE
*PciDev
,
674 IN PCI_BAR_TYPE ResType
,
675 IN PCI_RESOURCE_USAGE ResUsage
678 PCI_RESOURCE_NODE
*Node
;
682 Node
= AllocateZeroPool (sizeof (PCI_RESOURCE_NODE
));
683 ASSERT (Node
!= NULL
);
688 Node
->Signature
= PCI_RESOURCE_SIGNATURE
;
689 Node
->PciDev
= PciDev
;
690 Node
->Length
= Length
;
691 Node
->Alignment
= Alignment
;
693 Node
->ResType
= ResType
;
694 Node
->Reserved
= FALSE
;
695 Node
->ResourceUsage
= ResUsage
;
696 InitializeListHead (&Node
->ChildList
);
702 This function is used to create a IOV VF resource node.
704 @param PciDev Pci device instance.
705 @param Length Length of Io/Memory resource.
706 @param Alignment Alignment of resource.
707 @param Bar Bar index.
708 @param ResType Type of resource: IO/Memory.
709 @param ResUsage Resource usage.
711 @return PCI resource node created for given VF PCI device.
712 NULL means PCI resource node is not created.
716 CreateVfResourceNode (
717 IN PCI_IO_DEVICE
*PciDev
,
721 IN PCI_BAR_TYPE ResType
,
722 IN PCI_RESOURCE_USAGE ResUsage
725 PCI_RESOURCE_NODE
*Node
;
727 Node
= CreateResourceNode (PciDev
, Length
, Alignment
, Bar
, ResType
, ResUsage
);
732 Node
->Virtual
= TRUE
;
738 This function is used to extract resource request from
741 @param Bridge Pci device instance.
742 @param IoNode Resource info node for IO.
743 @param Mem32Node Resource info node for 32-bit memory.
744 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
745 @param Mem64Node Resource info node for 64-bit memory.
746 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
751 IN PCI_IO_DEVICE
*Bridge
,
752 IN OUT PCI_RESOURCE_NODE
*IoNode
,
753 IN OUT PCI_RESOURCE_NODE
*Mem32Node
,
754 IN OUT PCI_RESOURCE_NODE
*PMem32Node
,
755 IN OUT PCI_RESOURCE_NODE
*Mem64Node
,
756 IN OUT PCI_RESOURCE_NODE
*PMem64Node
760 PCI_RESOURCE_NODE
*IoBridge
;
761 PCI_RESOURCE_NODE
*Mem32Bridge
;
762 PCI_RESOURCE_NODE
*PMem32Bridge
;
763 PCI_RESOURCE_NODE
*Mem64Bridge
;
764 PCI_RESOURCE_NODE
*PMem64Bridge
;
765 LIST_ENTRY
*CurrentLink
;
767 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
769 while (CurrentLink
!= NULL
&& CurrentLink
!= &Bridge
->ChildList
) {
771 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
774 // Create resource nodes for this device by scanning the
775 // Bar array in the device private data
776 // If the upstream bridge doesn't support this device,
777 // no any resource node will be created for this device
779 GetResourceFromDevice (
788 if (IS_PCI_BRIDGE (&Temp
->Pci
)) {
791 // If the device has children, create a bridge resource node for this PPB
792 // Note: For PPB, memory aperture is aligned with 1MB and IO aperture
793 // is aligned with 4KB (smaller alignments may be supported).
795 IoBridge
= CreateResourceNode (
798 Temp
->BridgeIoAlignment
,
804 Mem32Bridge
= CreateResourceNode (
813 PMem32Bridge
= CreateResourceNode (
822 Mem64Bridge
= CreateResourceNode (
831 PMem64Bridge
= CreateResourceNode (
841 // Recursively create resouce map on this bridge
852 if (ResourceRequestExisted (IoBridge
)) {
863 // If there is node under this resource bridge,
864 // then calculate bridge's aperture of this type
865 // and insert it into the respective resource tree.
866 // If no, delete this resource bridge
868 if (ResourceRequestExisted (Mem32Bridge
)) {
874 FreePool (Mem32Bridge
);
879 // If there is node under this resource bridge,
880 // then calculate bridge's aperture of this type
881 // and insert it into the respective resource tree.
882 // If no, delete this resource bridge
884 if (ResourceRequestExisted (PMem32Bridge
)) {
890 FreePool (PMem32Bridge
);
895 // If there is node under this resource bridge,
896 // then calculate bridge's aperture of this type
897 // and insert it into the respective resource tree.
898 // If no, delete this resource bridge
900 if (ResourceRequestExisted (Mem64Bridge
)) {
906 FreePool (Mem64Bridge
);
911 // If there is node under this resource bridge,
912 // then calculate bridge's aperture of this type
913 // and insert it into the respective resource tree.
914 // If no, delete this resource bridge
916 if (ResourceRequestExisted (PMem64Bridge
)) {
922 FreePool (PMem64Bridge
);
929 // If it is P2C, apply hard coded resource padding
931 if (IS_CARDBUS_BRIDGE (&Temp
->Pci
)) {
932 ResourcePaddingForCardBusBridge (
942 CurrentLink
= CurrentLink
->ForwardLink
;
946 // To do some platform specific resource padding ...
948 ResourcePaddingPolicy (
958 // Degrade resource if necessary
969 // Calculate resource aperture for this bridge device
971 CalculateResourceAperture (Mem32Node
);
972 CalculateResourceAperture (PMem32Node
);
973 CalculateResourceAperture (Mem64Node
);
974 CalculateResourceAperture (PMem64Node
);
975 CalculateResourceAperture (IoNode
);
979 This function is used to do the resource padding for a specific platform.
981 @param PciDev Pci device instance.
982 @param IoNode Resource info node for IO.
983 @param Mem32Node Resource info node for 32-bit memory.
984 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
985 @param Mem64Node Resource info node for 64-bit memory.
986 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
990 ResourcePaddingPolicy (
991 IN PCI_IO_DEVICE
*PciDev
,
992 IN PCI_RESOURCE_NODE
*IoNode
,
993 IN PCI_RESOURCE_NODE
*Mem32Node
,
994 IN PCI_RESOURCE_NODE
*PMem32Node
,
995 IN PCI_RESOURCE_NODE
*Mem64Node
,
996 IN PCI_RESOURCE_NODE
*PMem64Node
1000 // Create padding resource node
1002 if (PciDev
->ResourcePaddingDescriptors
!= NULL
) {
1003 ApplyResourcePadding (
1015 This function is used to degrade resource if the upstream bridge
1016 doesn't support certain resource. Degradation path is
1017 PMEM64 -> MEM64 -> MEM32
1018 PMEM64 -> PMEM32 -> MEM32
1021 @param Bridge Pci device instance.
1022 @param Mem32Node Resource info node for 32-bit memory.
1023 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1024 @param Mem64Node Resource info node for 64-bit memory.
1025 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1030 IN PCI_IO_DEVICE
*Bridge
,
1031 IN PCI_RESOURCE_NODE
*Mem32Node
,
1032 IN PCI_RESOURCE_NODE
*PMem32Node
,
1033 IN PCI_RESOURCE_NODE
*Mem64Node
,
1034 IN PCI_RESOURCE_NODE
*PMem64Node
1037 PCI_IO_DEVICE
*Temp
;
1038 LIST_ENTRY
*ChildDeviceLink
;
1039 LIST_ENTRY
*ChildNodeLink
;
1040 LIST_ENTRY
*NextChildNodeLink
;
1041 PCI_RESOURCE_NODE
*TempNode
;
1044 // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64
1045 // requests in case that if a legacy option ROM image can not access 64-bit resources.
1047 ChildDeviceLink
= Bridge
->ChildList
.ForwardLink
;
1048 while (ChildDeviceLink
!= NULL
&& ChildDeviceLink
!= &Bridge
->ChildList
) {
1049 Temp
= PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink
);
1050 if (Temp
->RomSize
!= 0) {
1051 if (!IsListEmpty (&Mem64Node
->ChildList
)) {
1052 ChildNodeLink
= Mem64Node
->ChildList
.ForwardLink
;
1053 while (ChildNodeLink
!= &Mem64Node
->ChildList
) {
1054 TempNode
= RESOURCE_NODE_FROM_LINK (ChildNodeLink
);
1055 NextChildNodeLink
= ChildNodeLink
->ForwardLink
;
1057 if (TempNode
->PciDev
== Temp
) {
1058 RemoveEntryList (ChildNodeLink
);
1059 InsertResourceNode (Mem32Node
, TempNode
);
1061 ChildNodeLink
= NextChildNodeLink
;
1065 if (!IsListEmpty (&PMem64Node
->ChildList
)) {
1066 ChildNodeLink
= PMem64Node
->ChildList
.ForwardLink
;
1067 while (ChildNodeLink
!= &PMem64Node
->ChildList
) {
1068 TempNode
= RESOURCE_NODE_FROM_LINK (ChildNodeLink
);
1069 NextChildNodeLink
= ChildNodeLink
->ForwardLink
;
1071 if (TempNode
->PciDev
== Temp
) {
1072 RemoveEntryList (ChildNodeLink
);
1073 InsertResourceNode (PMem32Node
, TempNode
);
1075 ChildNodeLink
= NextChildNodeLink
;
1080 ChildDeviceLink
= ChildDeviceLink
->ForwardLink
;
1084 // If firmware is in 32-bit mode,
1085 // then degrade PMEM64/MEM64 requests
1087 if (sizeof (UINTN
) <= 4) {
1101 // if the bridge does not support MEM64, degrade MEM64 to MEM32
1103 if (!BridgeSupportResourceDecode (Bridge
, EFI_BRIDGE_MEM64_DECODE_SUPPORTED
)) {
1112 // if the bridge does not support PMEM64, degrade PMEM64 to PMEM32
1114 if (!BridgeSupportResourceDecode (Bridge
, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED
)) {
1123 // if both PMEM64 and PMEM32 requests from child devices, which can not be satisfied
1124 // by a P2P bridge simultaneously, keep PMEM64 and degrade PMEM32 to MEM32.
1126 if (!IsListEmpty (&PMem64Node
->ChildList
) && Bridge
->Parent
!= NULL
) {
1136 // If bridge doesn't support Pmem32
1137 // degrade it to mem32
1139 if (!BridgeSupportResourceDecode (Bridge
, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED
)) {
1148 // if root bridge supports combined Pmem Mem decoding
1149 // merge these two type of resource
1151 if (BridgeSupportResourceDecode (Bridge
, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED
)) {
1159 // No need to check if to degrade MEM64 after merge, because
1160 // if there are PMEM64 still here, 64-bit decode should be supported
1161 // by the root bride.
1172 Test whether bridge device support decode resource.
1174 @param Bridge Bridge device instance.
1175 @param Decode Decode type according to resource type.
1177 @return TRUE The bridge device support decode resource.
1178 @return FALSE The bridge device don't support decode resource.
1182 BridgeSupportResourceDecode (
1183 IN PCI_IO_DEVICE
*Bridge
,
1187 if (((Bridge
->Decodes
) & Decode
) != 0) {
1195 This function is used to program the resource allocated
1196 for each resource node under specified bridge.
1198 @param Base Base address of resource to be progammed.
1199 @param Bridge PCI resource node for the bridge device.
1201 @retval EFI_SUCCESS Successfully to program all resouces
1202 on given PCI bridge device.
1203 @retval EFI_OUT_OF_RESOURCES Base is all one.
1209 IN PCI_RESOURCE_NODE
*Bridge
1212 LIST_ENTRY
*CurrentLink
;
1213 PCI_RESOURCE_NODE
*Node
;
1216 if (Base
== gAllOne
) {
1217 return EFI_OUT_OF_RESOURCES
;
1220 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
1222 while (CurrentLink
!= &Bridge
->ChildList
) {
1224 Node
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
1226 if (!IS_PCI_BRIDGE (&(Node
->PciDev
->Pci
))) {
1228 if (IS_CARDBUS_BRIDGE (&(Node
->PciDev
->Pci
))) {
1230 // Program the PCI Card Bus device
1232 ProgramP2C (Base
, Node
);
1235 // Program the PCI device BAR
1237 ProgramBar (Base
, Node
);
1241 // Program the PCI devices under this bridge
1243 Status
= ProgramResource (Base
+ Node
->Offset
, Node
);
1244 if (EFI_ERROR (Status
)) {
1248 ProgramPpbApperture (Base
, Node
);
1251 CurrentLink
= CurrentLink
->ForwardLink
;
1258 Program Bar register for PCI device.
1260 @param Base Base address for PCI device resource to be progammed.
1261 @param Node Point to resoure node structure.
1267 IN PCI_RESOURCE_NODE
*Node
1270 EFI_PCI_IO_PROTOCOL
*PciIo
;
1274 ASSERT (Node
->Bar
< PCI_MAX_BAR
);
1279 if (Node
->Virtual
) {
1280 ProgramVfBar (Base
, Node
);
1285 PciIo
= &(Node
->PciDev
->PciIo
);
1287 Address
= Base
+ Node
->Offset
;
1290 // Indicate pci bus driver has allocated
1291 // resource for this device
1292 // It might be a temporary solution here since
1293 // pci device could have multiple bar
1295 Node
->PciDev
->Allocated
= TRUE
;
1297 switch ((Node
->PciDev
->PciBar
[Node
->Bar
]).BarType
) {
1299 case PciBarTypeIo16
:
1300 case PciBarTypeIo32
:
1301 case PciBarTypeMem32
:
1302 case PciBarTypePMem32
:
1306 EfiPciIoWidthUint32
,
1307 (Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
,
1312 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1316 case PciBarTypeMem64
:
1317 case PciBarTypePMem64
:
1319 Address32
= (UINT32
) (Address
& 0x00000000FFFFFFFF);
1323 EfiPciIoWidthUint32
,
1324 (Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
,
1329 Address32
= (UINT32
) RShiftU64 (Address
, 32);
1333 EfiPciIoWidthUint32
,
1334 (UINT8
) ((Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
+ 4),
1339 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1349 Program IOV VF Bar register for PCI device.
1351 @param Base Base address for PCI device resource to be progammed.
1352 @param Node Point to resoure node structure.
1358 IN PCI_RESOURCE_NODE
*Node
1361 EFI_PCI_IO_PROTOCOL
*PciIo
;
1365 ASSERT (Node
->Bar
< PCI_MAX_BAR
);
1366 ASSERT (Node
->Virtual
);
1369 PciIo
= &(Node
->PciDev
->PciIo
);
1371 Address
= Base
+ Node
->Offset
;
1374 // Indicate pci bus driver has allocated
1375 // resource for this device
1376 // It might be a temporary solution here since
1377 // pci device could have multiple bar
1379 Node
->PciDev
->Allocated
= TRUE
;
1381 switch ((Node
->PciDev
->VfPciBar
[Node
->Bar
]).BarType
) {
1383 case PciBarTypeMem32
:
1384 case PciBarTypePMem32
:
1388 EfiPciIoWidthUint32
,
1389 (Node
->PciDev
->VfPciBar
[Node
->Bar
]).Offset
,
1394 Node
->PciDev
->VfPciBar
[Node
->Bar
].BaseAddress
= Address
;
1397 case PciBarTypeMem64
:
1398 case PciBarTypePMem64
:
1400 Address32
= (UINT32
) (Address
& 0x00000000FFFFFFFF);
1404 EfiPciIoWidthUint32
,
1405 (Node
->PciDev
->VfPciBar
[Node
->Bar
]).Offset
,
1410 Address32
= (UINT32
) RShiftU64 (Address
, 32);
1414 EfiPciIoWidthUint32
,
1415 ((Node
->PciDev
->VfPciBar
[Node
->Bar
]).Offset
+ 4),
1420 Node
->PciDev
->VfPciBar
[Node
->Bar
].BaseAddress
= Address
;
1423 case PciBarTypeIo16
:
1424 case PciBarTypeIo32
:
1435 Program PCI-PCI bridge apperture.
1437 @param Base Base address for resource.
1438 @param Node Point to resoure node structure.
1442 ProgramPpbApperture (
1444 IN PCI_RESOURCE_NODE
*Node
1447 EFI_PCI_IO_PROTOCOL
*PciIo
;
1453 // If no device resource of this PPB, return anyway
1454 // Apperture is set default in the initialization code
1456 if (Node
->Length
== 0 || Node
->ResourceUsage
== PciResUsagePadding
) {
1458 // For padding resource node, just ignore when programming
1463 PciIo
= &(Node
->PciDev
->PciIo
);
1464 Address
= Base
+ Node
->Offset
;
1467 // Indicate the PPB resource has been allocated
1469 Node
->PciDev
->Allocated
= TRUE
;
1471 switch (Node
->Bar
) {
1475 switch ((Node
->PciDev
->PciBar
[Node
->Bar
]).BarType
) {
1477 case PciBarTypeIo16
:
1478 case PciBarTypeIo32
:
1479 case PciBarTypeMem32
:
1480 case PciBarTypePMem32
:
1484 EfiPciIoWidthUint32
,
1485 (Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
,
1490 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1491 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1494 case PciBarTypeMem64
:
1495 case PciBarTypePMem64
:
1497 Address32
= (UINT32
) (Address
& 0x00000000FFFFFFFF);
1501 EfiPciIoWidthUint32
,
1502 (Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
,
1507 Address32
= (UINT32
) RShiftU64 (Address
, 32);
1511 EfiPciIoWidthUint32
,
1512 (UINT8
) ((Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
+ 4),
1517 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1518 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1528 Address32
= ((UINT32
) (Address
)) >> 8;
1540 EfiPciIoWidthUint16
,
1546 Address32
= (UINT32
) (Address
+ Node
->Length
- 1);
1547 Address32
= ((UINT32
) (Address32
)) >> 8;
1559 EfiPciIoWidthUint16
,
1565 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1566 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1569 case PPB_MEM32_RANGE
:
1571 Address32
= ((UINT32
) (Address
)) >> 16;
1574 EfiPciIoWidthUint16
,
1580 Address32
= (UINT32
) (Address
+ Node
->Length
- 1);
1581 Address32
= ((UINT32
) (Address32
)) >> 16;
1584 EfiPciIoWidthUint16
,
1590 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1591 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1594 case PPB_PMEM32_RANGE
:
1595 case PPB_PMEM64_RANGE
:
1597 Address32
= ((UINT32
) (Address
)) >> 16;
1600 EfiPciIoWidthUint16
,
1606 Address32
= (UINT32
) (Address
+ Node
->Length
- 1);
1607 Address32
= ((UINT32
) (Address32
)) >> 16;
1610 EfiPciIoWidthUint16
,
1616 Address32
= (UINT32
) RShiftU64 (Address
, 32);
1619 EfiPciIoWidthUint32
,
1625 Address32
= (UINT32
) RShiftU64 ((Address
+ Node
->Length
- 1), 32);
1628 EfiPciIoWidthUint32
,
1634 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1635 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1644 Program parent bridge for Option Rom.
1646 @param PciDevice Pci deivce instance.
1647 @param OptionRomBase Base address for Optiona Rom.
1648 @param Enable Enable or disable PCI memory.
1652 ProgrameUpstreamBridgeForRom (
1653 IN PCI_IO_DEVICE
*PciDevice
,
1654 IN UINT32 OptionRomBase
,
1658 PCI_IO_DEVICE
*Parent
;
1659 PCI_RESOURCE_NODE Node
;
1661 // For root bridge, just return.
1663 Parent
= PciDevice
->Parent
;
1664 ZeroMem (&Node
, sizeof (Node
));
1665 while (Parent
!= NULL
) {
1666 if (!IS_PCI_BRIDGE (&Parent
->Pci
)) {
1670 Node
.PciDev
= Parent
;
1671 Node
.Length
= PciDevice
->RomSize
;
1673 Node
.Bar
= PPB_MEM32_RANGE
;
1674 Node
.ResType
= PciBarTypeMem32
;
1678 // Program PPB to only open a single <= 16MB apperture
1681 ProgramPpbApperture (OptionRomBase
, &Node
);
1682 PCI_ENABLE_COMMAND_REGISTER (Parent
, EFI_PCI_COMMAND_MEMORY_SPACE
);
1684 InitializePpb (Parent
);
1685 PCI_DISABLE_COMMAND_REGISTER (Parent
, EFI_PCI_COMMAND_MEMORY_SPACE
);
1688 Parent
= Parent
->Parent
;
1693 Test whether resource exists for a bridge.
1695 @param Bridge Point to resource node for a bridge.
1697 @retval TRUE There is resource on the given bridge.
1698 @retval FALSE There isn't resource on the given bridge.
1702 ResourceRequestExisted (
1703 IN PCI_RESOURCE_NODE
*Bridge
1706 if (Bridge
!= NULL
) {
1707 if (!IsListEmpty (&Bridge
->ChildList
) || Bridge
->Length
!= 0) {
1716 Initialize resource pool structure.
1718 @param ResourcePool Point to resource pool structure. This pool
1719 is reset to all zero when returned.
1720 @param ResourceType Type of resource.
1724 InitializeResourcePool (
1725 IN OUT PCI_RESOURCE_NODE
*ResourcePool
,
1726 IN PCI_BAR_TYPE ResourceType
1729 ZeroMem (ResourcePool
, sizeof (PCI_RESOURCE_NODE
));
1730 ResourcePool
->ResType
= ResourceType
;
1731 ResourcePool
->Signature
= PCI_RESOURCE_SIGNATURE
;
1732 InitializeListHead (&ResourcePool
->ChildList
);
1736 Destory given resource tree.
1738 @param Bridge PCI resource root node of resource tree.
1742 DestroyResourceTree (
1743 IN PCI_RESOURCE_NODE
*Bridge
1746 PCI_RESOURCE_NODE
*Temp
;
1747 LIST_ENTRY
*CurrentLink
;
1749 while (!IsListEmpty (&Bridge
->ChildList
)) {
1751 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
1753 Temp
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
1756 RemoveEntryList (CurrentLink
);
1758 if (IS_PCI_BRIDGE (&(Temp
->PciDev
->Pci
))) {
1759 DestroyResourceTree (Temp
);
1767 Insert resource padding for P2C.
1769 @param PciDev Pci device instance.
1770 @param IoNode Resource info node for IO.
1771 @param Mem32Node Resource info node for 32-bit memory.
1772 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1773 @param Mem64Node Resource info node for 64-bit memory.
1774 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1778 ResourcePaddingForCardBusBridge (
1779 IN PCI_IO_DEVICE
*PciDev
,
1780 IN PCI_RESOURCE_NODE
*IoNode
,
1781 IN PCI_RESOURCE_NODE
*Mem32Node
,
1782 IN PCI_RESOURCE_NODE
*PMem32Node
,
1783 IN PCI_RESOURCE_NODE
*Mem64Node
,
1784 IN PCI_RESOURCE_NODE
*PMem64Node
1787 PCI_RESOURCE_NODE
*Node
;
1792 // Memory Base/Limit Register 0
1793 // Bar 1 denodes memory range 0
1795 Node
= CreateResourceNode (
1804 InsertResourceNode (
1810 // Memory Base/Limit Register 1
1811 // Bar 2 denodes memory range1
1813 Node
= CreateResourceNode (
1822 InsertResourceNode (
1829 // Bar 3 denodes io range 0
1831 Node
= CreateResourceNode (
1840 InsertResourceNode (
1847 // Bar 4 denodes io range 0
1849 Node
= CreateResourceNode (
1858 InsertResourceNode (
1865 Program PCI Card device register for given resource node.
1867 @param Base Base address of PCI Card device to be programmed.
1868 @param Node Given resource node.
1874 IN PCI_RESOURCE_NODE
*Node
1877 EFI_PCI_IO_PROTOCOL
*PciIo
;
1880 UINT16 BridgeControl
;
1883 PciIo
= &(Node
->PciDev
->PciIo
);
1885 Address
= Base
+ Node
->Offset
;
1888 // Indicate pci bus driver has allocated
1889 // resource for this device
1890 // It might be a temporary solution here since
1891 // pci device could have multiple bar
1893 Node
->PciDev
->Allocated
= TRUE
;
1895 switch (Node
->Bar
) {
1900 EfiPciIoWidthUint32
,
1901 (Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
,
1906 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1907 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1913 EfiPciIoWidthUint32
,
1914 PCI_CARD_MEMORY_BASE_0
,
1919 TempAddress
= Address
+ Node
->Length
- 1;
1922 EfiPciIoWidthUint32
,
1923 PCI_CARD_MEMORY_LIMIT_0
,
1928 if (Node
->ResType
== PciBarTypeMem32
) {
1930 // Set non-prefetchable bit
1934 EfiPciIoWidthUint16
,
1935 PCI_CARD_BRIDGE_CONTROL
,
1940 BridgeControl
&= (UINT16
) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE
;
1943 EfiPciIoWidthUint16
,
1944 PCI_CARD_BRIDGE_CONTROL
,
1951 // Set pre-fetchable bit
1955 EfiPciIoWidthUint16
,
1956 PCI_CARD_BRIDGE_CONTROL
,
1961 BridgeControl
|= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE
;
1964 EfiPciIoWidthUint16
,
1965 PCI_CARD_BRIDGE_CONTROL
,
1971 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1972 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1973 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
1980 EfiPciIoWidthUint32
,
1981 PCI_CARD_MEMORY_BASE_1
,
1986 TempAddress
= Address
+ Node
->Length
- 1;
1990 EfiPciIoWidthUint32
,
1991 PCI_CARD_MEMORY_LIMIT_1
,
1996 if (Node
->ResType
== PciBarTypeMem32
) {
1999 // Set non-prefetchable bit
2003 EfiPciIoWidthUint16
,
2004 PCI_CARD_BRIDGE_CONTROL
,
2009 BridgeControl
&= (UINT16
) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE
);
2012 EfiPciIoWidthUint16
,
2013 PCI_CARD_BRIDGE_CONTROL
,
2021 // Set pre-fetchable bit
2025 EfiPciIoWidthUint16
,
2026 PCI_CARD_BRIDGE_CONTROL
,
2031 BridgeControl
|= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE
;
2034 EfiPciIoWidthUint16
,
2035 PCI_CARD_BRIDGE_CONTROL
,
2041 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
2042 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
2043 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
2049 EfiPciIoWidthUint32
,
2050 PCI_CARD_IO_BASE_0_LOWER
,
2055 TempAddress
= Address
+ Node
->Length
- 1;
2058 EfiPciIoWidthUint32
,
2059 PCI_CARD_IO_LIMIT_0_LOWER
,
2064 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
2065 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
2066 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
2073 EfiPciIoWidthUint32
,
2074 PCI_CARD_IO_BASE_1_LOWER
,
2079 TempAddress
= Address
+ Node
->Length
- 1;
2082 EfiPciIoWidthUint32
,
2083 PCI_CARD_IO_LIMIT_1_LOWER
,
2088 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
2089 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
2090 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
2099 Create padding resource node.
2101 @param PciDev Pci device instance.
2102 @param IoNode Resource info node for IO.
2103 @param Mem32Node Resource info node for 32-bit memory.
2104 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
2105 @param Mem64Node Resource info node for 64-bit memory.
2106 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
2110 ApplyResourcePadding (
2111 IN PCI_IO_DEVICE
*PciDev
,
2112 IN PCI_RESOURCE_NODE
*IoNode
,
2113 IN PCI_RESOURCE_NODE
*Mem32Node
,
2114 IN PCI_RESOURCE_NODE
*PMem32Node
,
2115 IN PCI_RESOURCE_NODE
*Mem64Node
,
2116 IN PCI_RESOURCE_NODE
*PMem64Node
2119 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Ptr
;
2120 PCI_RESOURCE_NODE
*Node
;
2121 UINT8 DummyBarIndex
;
2124 Ptr
= PciDev
->ResourcePaddingDescriptors
;
2126 while (((EFI_ACPI_END_TAG_DESCRIPTOR
*) Ptr
)->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
2128 if (Ptr
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
&& Ptr
->ResType
== ACPI_ADDRESS_SPACE_TYPE_IO
) {
2129 if (Ptr
->AddrLen
!= 0) {
2131 Node
= CreateResourceNode (
2139 InsertResourceNode (
2149 if (Ptr
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
&& Ptr
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
2151 if (Ptr
->AddrSpaceGranularity
== 32) {
2156 if (Ptr
->SpecificFlag
== 0x6) {
2157 if (Ptr
->AddrLen
!= 0) {
2158 Node
= CreateResourceNode (
2166 InsertResourceNode (
2179 if (Ptr
->SpecificFlag
== 0) {
2180 if (Ptr
->AddrLen
!= 0) {
2181 Node
= CreateResourceNode (
2189 InsertResourceNode (
2200 if (Ptr
->AddrSpaceGranularity
== 64) {
2205 if (Ptr
->SpecificFlag
== 0x6) {
2206 if (Ptr
->AddrLen
!= 0) {
2207 Node
= CreateResourceNode (
2215 InsertResourceNode (
2228 if (Ptr
->SpecificFlag
== 0) {
2229 if (Ptr
->AddrLen
!= 0) {
2230 Node
= CreateResourceNode (
2238 InsertResourceNode (
2255 Get padding resource for PCI-PCI bridge.
2257 @param PciIoDevice PCI-PCI bridge device instance.
2259 @note Feature flag PcdPciBusHotplugDeviceSupport determines
2260 whether need to pad resource for them.
2263 GetResourcePaddingPpb (
2264 IN PCI_IO_DEVICE
*PciIoDevice
2267 if (gPciHotPlugInit
!= NULL
&& FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
2268 if (PciIoDevice
->ResourcePaddingDescriptors
== NULL
) {
2269 GetResourcePaddingForHpb (PciIoDevice
);