2 PCI resouces support functions implemntation for PCI Bus module.
4 Copyright (c) 2006 - 2011, 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
) {
1477 EfiPciIoWidthUint32
,
1478 (Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
,
1483 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1484 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1490 Address32
= ((UINT32
) (Address
)) >> 8;
1502 EfiPciIoWidthUint16
,
1508 Address32
= (UINT32
) (Address
+ Node
->Length
- 1);
1509 Address32
= ((UINT32
) (Address32
)) >> 8;
1521 EfiPciIoWidthUint16
,
1527 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1528 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1531 case PPB_MEM32_RANGE
:
1533 Address32
= ((UINT32
) (Address
)) >> 16;
1536 EfiPciIoWidthUint16
,
1542 Address32
= (UINT32
) (Address
+ Node
->Length
- 1);
1543 Address32
= ((UINT32
) (Address32
)) >> 16;
1546 EfiPciIoWidthUint16
,
1552 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1553 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1556 case PPB_PMEM32_RANGE
:
1557 case PPB_PMEM64_RANGE
:
1559 Address32
= ((UINT32
) (Address
)) >> 16;
1562 EfiPciIoWidthUint16
,
1568 Address32
= (UINT32
) (Address
+ Node
->Length
- 1);
1569 Address32
= ((UINT32
) (Address32
)) >> 16;
1572 EfiPciIoWidthUint16
,
1578 Address32
= (UINT32
) RShiftU64 (Address
, 32);
1581 EfiPciIoWidthUint32
,
1587 Address32
= (UINT32
) RShiftU64 ((Address
+ Node
->Length
- 1), 32);
1590 EfiPciIoWidthUint32
,
1596 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1597 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1606 Program parent bridge for Option Rom.
1608 @param PciDevice Pci deivce instance.
1609 @param OptionRomBase Base address for Optiona Rom.
1610 @param Enable Enable or disable PCI memory.
1614 ProgrameUpstreamBridgeForRom (
1615 IN PCI_IO_DEVICE
*PciDevice
,
1616 IN UINT32 OptionRomBase
,
1620 PCI_IO_DEVICE
*Parent
;
1621 PCI_RESOURCE_NODE Node
;
1623 // For root bridge, just return.
1625 Parent
= PciDevice
->Parent
;
1626 ZeroMem (&Node
, sizeof (Node
));
1627 while (Parent
!= NULL
) {
1628 if (!IS_PCI_BRIDGE (&Parent
->Pci
)) {
1632 Node
.PciDev
= Parent
;
1633 Node
.Length
= PciDevice
->RomSize
;
1635 Node
.Bar
= PPB_MEM32_RANGE
;
1636 Node
.ResType
= PciBarTypeMem32
;
1640 // Program PPB to only open a single <= 16MB apperture
1643 ProgramPpbApperture (OptionRomBase
, &Node
);
1644 PCI_ENABLE_COMMAND_REGISTER (Parent
, EFI_PCI_COMMAND_MEMORY_SPACE
);
1646 InitializePpb (Parent
);
1647 PCI_DISABLE_COMMAND_REGISTER (Parent
, EFI_PCI_COMMAND_MEMORY_SPACE
);
1650 Parent
= Parent
->Parent
;
1655 Test whether resource exists for a bridge.
1657 @param Bridge Point to resource node for a bridge.
1659 @retval TRUE There is resource on the given bridge.
1660 @retval FALSE There isn't resource on the given bridge.
1664 ResourceRequestExisted (
1665 IN PCI_RESOURCE_NODE
*Bridge
1668 if (Bridge
!= NULL
) {
1669 if (!IsListEmpty (&Bridge
->ChildList
) || Bridge
->Length
!= 0) {
1678 Initialize resource pool structure.
1680 @param ResourcePool Point to resource pool structure. This pool
1681 is reset to all zero when returned.
1682 @param ResourceType Type of resource.
1686 InitializeResourcePool (
1687 IN OUT PCI_RESOURCE_NODE
*ResourcePool
,
1688 IN PCI_BAR_TYPE ResourceType
1691 ZeroMem (ResourcePool
, sizeof (PCI_RESOURCE_NODE
));
1692 ResourcePool
->ResType
= ResourceType
;
1693 ResourcePool
->Signature
= PCI_RESOURCE_SIGNATURE
;
1694 InitializeListHead (&ResourcePool
->ChildList
);
1698 Destory given resource tree.
1700 @param Bridge PCI resource root node of resource tree.
1704 DestroyResourceTree (
1705 IN PCI_RESOURCE_NODE
*Bridge
1708 PCI_RESOURCE_NODE
*Temp
;
1709 LIST_ENTRY
*CurrentLink
;
1711 while (!IsListEmpty (&Bridge
->ChildList
)) {
1713 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
1715 Temp
= RESOURCE_NODE_FROM_LINK (CurrentLink
);
1718 RemoveEntryList (CurrentLink
);
1720 if (IS_PCI_BRIDGE (&(Temp
->PciDev
->Pci
))) {
1721 DestroyResourceTree (Temp
);
1729 Insert resource padding for P2C.
1731 @param PciDev Pci device instance.
1732 @param IoNode Resource info node for IO.
1733 @param Mem32Node Resource info node for 32-bit memory.
1734 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1735 @param Mem64Node Resource info node for 64-bit memory.
1736 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1740 ResourcePaddingForCardBusBridge (
1741 IN PCI_IO_DEVICE
*PciDev
,
1742 IN PCI_RESOURCE_NODE
*IoNode
,
1743 IN PCI_RESOURCE_NODE
*Mem32Node
,
1744 IN PCI_RESOURCE_NODE
*PMem32Node
,
1745 IN PCI_RESOURCE_NODE
*Mem64Node
,
1746 IN PCI_RESOURCE_NODE
*PMem64Node
1749 PCI_RESOURCE_NODE
*Node
;
1754 // Memory Base/Limit Register 0
1755 // Bar 1 denodes memory range 0
1757 Node
= CreateResourceNode (
1766 InsertResourceNode (
1772 // Memory Base/Limit Register 1
1773 // Bar 2 denodes memory range1
1775 Node
= CreateResourceNode (
1784 InsertResourceNode (
1791 // Bar 3 denodes io range 0
1793 Node
= CreateResourceNode (
1802 InsertResourceNode (
1809 // Bar 4 denodes io range 0
1811 Node
= CreateResourceNode (
1820 InsertResourceNode (
1827 Program PCI Card device register for given resource node.
1829 @param Base Base address of PCI Card device to be programmed.
1830 @param Node Given resource node.
1836 IN PCI_RESOURCE_NODE
*Node
1839 EFI_PCI_IO_PROTOCOL
*PciIo
;
1842 UINT16 BridgeControl
;
1845 PciIo
= &(Node
->PciDev
->PciIo
);
1847 Address
= Base
+ Node
->Offset
;
1850 // Indicate pci bus driver has allocated
1851 // resource for this device
1852 // It might be a temporary solution here since
1853 // pci device could have multiple bar
1855 Node
->PciDev
->Allocated
= TRUE
;
1857 switch (Node
->Bar
) {
1862 EfiPciIoWidthUint32
,
1863 (Node
->PciDev
->PciBar
[Node
->Bar
]).Offset
,
1868 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1869 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1875 EfiPciIoWidthUint32
,
1876 PCI_CARD_MEMORY_BASE_0
,
1881 TempAddress
= Address
+ Node
->Length
- 1;
1884 EfiPciIoWidthUint32
,
1885 PCI_CARD_MEMORY_LIMIT_0
,
1890 if (Node
->ResType
== PciBarTypeMem32
) {
1892 // Set non-prefetchable bit
1896 EfiPciIoWidthUint16
,
1897 PCI_CARD_BRIDGE_CONTROL
,
1902 BridgeControl
&= (UINT16
) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE
;
1905 EfiPciIoWidthUint16
,
1906 PCI_CARD_BRIDGE_CONTROL
,
1913 // Set pre-fetchable bit
1917 EfiPciIoWidthUint16
,
1918 PCI_CARD_BRIDGE_CONTROL
,
1923 BridgeControl
|= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE
;
1926 EfiPciIoWidthUint16
,
1927 PCI_CARD_BRIDGE_CONTROL
,
1933 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
1934 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
1935 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
1942 EfiPciIoWidthUint32
,
1943 PCI_CARD_MEMORY_BASE_1
,
1948 TempAddress
= Address
+ Node
->Length
- 1;
1952 EfiPciIoWidthUint32
,
1953 PCI_CARD_MEMORY_LIMIT_1
,
1958 if (Node
->ResType
== PciBarTypeMem32
) {
1961 // Set non-prefetchable bit
1965 EfiPciIoWidthUint16
,
1966 PCI_CARD_BRIDGE_CONTROL
,
1971 BridgeControl
&= (UINT16
) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE
);
1974 EfiPciIoWidthUint16
,
1975 PCI_CARD_BRIDGE_CONTROL
,
1983 // Set pre-fetchable bit
1987 EfiPciIoWidthUint16
,
1988 PCI_CARD_BRIDGE_CONTROL
,
1993 BridgeControl
|= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE
;
1996 EfiPciIoWidthUint16
,
1997 PCI_CARD_BRIDGE_CONTROL
,
2003 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
2004 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
2005 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
2011 EfiPciIoWidthUint32
,
2012 PCI_CARD_IO_BASE_0_LOWER
,
2017 TempAddress
= Address
+ Node
->Length
- 1;
2020 EfiPciIoWidthUint32
,
2021 PCI_CARD_IO_LIMIT_0_LOWER
,
2026 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
2027 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
2028 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
2035 EfiPciIoWidthUint32
,
2036 PCI_CARD_IO_BASE_1_LOWER
,
2041 TempAddress
= Address
+ Node
->Length
- 1;
2044 EfiPciIoWidthUint32
,
2045 PCI_CARD_IO_LIMIT_1_LOWER
,
2050 Node
->PciDev
->PciBar
[Node
->Bar
].BaseAddress
= Address
;
2051 Node
->PciDev
->PciBar
[Node
->Bar
].Length
= Node
->Length
;
2052 Node
->PciDev
->PciBar
[Node
->Bar
].BarType
= Node
->ResType
;
2061 Create padding resource node.
2063 @param PciDev Pci device instance.
2064 @param IoNode Resource info node for IO.
2065 @param Mem32Node Resource info node for 32-bit memory.
2066 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
2067 @param Mem64Node Resource info node for 64-bit memory.
2068 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
2072 ApplyResourcePadding (
2073 IN PCI_IO_DEVICE
*PciDev
,
2074 IN PCI_RESOURCE_NODE
*IoNode
,
2075 IN PCI_RESOURCE_NODE
*Mem32Node
,
2076 IN PCI_RESOURCE_NODE
*PMem32Node
,
2077 IN PCI_RESOURCE_NODE
*Mem64Node
,
2078 IN PCI_RESOURCE_NODE
*PMem64Node
2081 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Ptr
;
2082 PCI_RESOURCE_NODE
*Node
;
2083 UINT8 DummyBarIndex
;
2086 Ptr
= PciDev
->ResourcePaddingDescriptors
;
2088 while (((EFI_ACPI_END_TAG_DESCRIPTOR
*) Ptr
)->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
2090 if (Ptr
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
&& Ptr
->ResType
== ACPI_ADDRESS_SPACE_TYPE_IO
) {
2091 if (Ptr
->AddrLen
!= 0) {
2093 Node
= CreateResourceNode (
2101 InsertResourceNode (
2111 if (Ptr
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
&& Ptr
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
2113 if (Ptr
->AddrSpaceGranularity
== 32) {
2118 if (Ptr
->SpecificFlag
== 0x6) {
2119 if (Ptr
->AddrLen
!= 0) {
2120 Node
= CreateResourceNode (
2128 InsertResourceNode (
2141 if (Ptr
->SpecificFlag
== 0) {
2142 if (Ptr
->AddrLen
!= 0) {
2143 Node
= CreateResourceNode (
2151 InsertResourceNode (
2162 if (Ptr
->AddrSpaceGranularity
== 64) {
2167 if (Ptr
->SpecificFlag
== 0x6) {
2168 if (Ptr
->AddrLen
!= 0) {
2169 Node
= CreateResourceNode (
2177 InsertResourceNode (
2190 if (Ptr
->SpecificFlag
== 0) {
2191 if (Ptr
->AddrLen
!= 0) {
2192 Node
= CreateResourceNode (
2200 InsertResourceNode (
2217 Get padding resource for PCI-PCI bridge.
2219 @param PciIoDevice PCI-PCI bridge device instance.
2221 @note Feature flag PcdPciBusHotplugDeviceSupport determines
2222 whether need to pad resource for them.
2225 GetResourcePaddingPpb (
2226 IN PCI_IO_DEVICE
*PciIoDevice
2229 if (gPciHotPlugInit
!= NULL
&& FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
2230 if (PciIoDevice
->ResourcePaddingDescriptors
== NULL
) {
2231 GetResourcePaddingForHpb (PciIoDevice
);