]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciResourceSupport.c
1 /** @file
2 PCI resources support functions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PciBus.h"
10
11 //
12 // The default policy for the PCI bus driver is NOT to reserve I/O ranges for both ISA aliases and VGA aliases.
13 //
14 BOOLEAN mReserveIsaAliases = FALSE;
15 BOOLEAN mReserveVgaAliases = FALSE;
16 BOOLEAN mPolicyDetermined = FALSE;
17
18 /**
19 The function is used to skip VGA range.
20
21 @param Start Returned start address including VGA range.
22 @param Length The length of VGA range.
23
24 **/
25 VOID
26 SkipVGAAperture (
27 OUT UINT64 *Start,
28 IN UINT64 Length
29 )
30 {
31 UINT64 Original;
32 UINT64 Mask;
33 UINT64 StartOffset;
34 UINT64 LimitOffset;
35
36 ASSERT (Start != NULL);
37 //
38 // For legacy VGA, bit 10 to bit 15 is not decoded
39 //
40 Mask = 0x3FF;
41
42 Original = *Start;
43 StartOffset = Original & Mask;
44 LimitOffset = ((*Start) + Length - 1) & Mask;
45 if (LimitOffset >= VGABASE1) {
46 *Start = *Start - StartOffset + VGALIMIT2 + 1;
47 }
48 }
49
50 /**
51 This function is used to skip ISA aliasing aperture.
52
53 @param Start Returned start address including ISA aliasing aperture.
54 @param Length The length of ISA aliasing aperture.
55
56 **/
57 VOID
58 SkipIsaAliasAperture (
59 OUT UINT64 *Start,
60 IN UINT64 Length
61 )
62 {
63 UINT64 Original;
64 UINT64 Mask;
65 UINT64 StartOffset;
66 UINT64 LimitOffset;
67
68 ASSERT (Start != NULL);
69
70 //
71 // For legacy ISA, bit 10 to bit 15 is not decoded
72 //
73 Mask = 0x3FF;
74
75 Original = *Start;
76 StartOffset = Original & Mask;
77 LimitOffset = ((*Start) + Length - 1) & Mask;
78
79 if (LimitOffset >= ISABASE) {
80 *Start = *Start - StartOffset + ISALIMIT + 1;
81 }
82 }
83
84 /**
85 This function inserts a resource node into the resource list.
86 The resource list is sorted in descend order.
87
88 @param Bridge PCI resource node for bridge.
89 @param ResNode Resource node want to be inserted.
90
91 **/
92 VOID
93 InsertResourceNode (
94 IN OUT PCI_RESOURCE_NODE *Bridge,
95 IN PCI_RESOURCE_NODE *ResNode
96 )
97 {
98 LIST_ENTRY *CurrentLink;
99 PCI_RESOURCE_NODE *Temp;
100 UINT64 ResNodeAlignRest;
101 UINT64 TempAlignRest;
102
103 ASSERT (Bridge != NULL);
104 ASSERT (ResNode != NULL);
105
106 InsertHeadList (&Bridge->ChildList, &ResNode->Link);
107
108 CurrentLink = Bridge->ChildList.ForwardLink->ForwardLink;
109 while (CurrentLink != &Bridge->ChildList) {
110 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
111
112 if (ResNode->Alignment > Temp->Alignment) {
113 break;
114 } else if (ResNode->Alignment == Temp->Alignment) {
115 ResNodeAlignRest = ResNode->Length & ResNode->Alignment;
116 TempAlignRest = Temp->Length & Temp->Alignment;
117 if ((ResNodeAlignRest == 0) || (ResNodeAlignRest >= TempAlignRest)) {
118 break;
119 }
120 }
121
122 SwapListEntries (&ResNode->Link, CurrentLink);
123
124 CurrentLink = ResNode->Link.ForwardLink;
125 }
126 }
127
128 /**
129 This routine is used to merge two different resource trees in need of
130 resource degradation.
131
132 For example, if an upstream PPB doesn't support,
133 prefetchable memory decoding, the PCI bus driver will choose to call this function
134 to merge prefetchable memory resource list into normal memory list.
135
136 If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
137 type.
138 If Dst is NULL or Res is NULL, ASSERT ().
139
140 @param Dst Point to destination resource tree.
141 @param Res Point to source resource tree.
142 @param TypeMerge If the TypeMerge is TRUE, Res resource type is changed to the type of
143 destination resource type.
144
145 **/
146 VOID
147 MergeResourceTree (
148 IN PCI_RESOURCE_NODE *Dst,
149 IN PCI_RESOURCE_NODE *Res,
150 IN BOOLEAN TypeMerge
151 )
152 {
153 LIST_ENTRY *CurrentLink;
154 PCI_RESOURCE_NODE *Temp;
155
156 ASSERT (Dst != NULL);
157 ASSERT (Res != NULL);
158
159 while (!IsListEmpty (&Res->ChildList)) {
160 CurrentLink = Res->ChildList.ForwardLink;
161
162 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
163
164 if (TypeMerge) {
165 Temp->ResType = Dst->ResType;
166 }
167
168 RemoveEntryList (CurrentLink);
169 InsertResourceNode (Dst, Temp);
170 }
171 }
172
173 /**
174 This function is used to calculate the IO16 aperture
175 for a bridge.
176
177 @param Bridge PCI resource node for bridge.
178
179 **/
180 VOID
181 CalculateApertureIo16 (
182 IN PCI_RESOURCE_NODE *Bridge
183 )
184 {
185 EFI_STATUS Status;
186 UINT64 Aperture;
187 LIST_ENTRY *CurrentLink;
188 PCI_RESOURCE_NODE *Node;
189 UINT64 Offset;
190 EFI_PCI_PLATFORM_POLICY PciPolicy;
191 UINT64 PaddingAperture;
192
193 if (!mPolicyDetermined) {
194 //
195 // Check PciPlatform policy
196 //
197 Status = EFI_NOT_FOUND;
198 PciPolicy = 0;
199 if (gPciPlatformProtocol != NULL) {
200 Status = gPciPlatformProtocol->GetPlatformPolicy (
201 gPciPlatformProtocol,
202 &PciPolicy
203 );
204 }
205
206 if (EFI_ERROR (Status) && (gPciOverrideProtocol != NULL)) {
207 Status = gPciOverrideProtocol->GetPlatformPolicy (
208 gPciOverrideProtocol,
209 &PciPolicy
210 );
211 }
212
213 if (!EFI_ERROR (Status)) {
214 if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) {
215 mReserveIsaAliases = TRUE;
216 }
217
218 if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) {
219 mReserveVgaAliases = TRUE;
220 }
221 }
222
223 mPolicyDetermined = TRUE;
224 }
225
226 Aperture = 0;
227 PaddingAperture = 0;
228
229 if (Bridge == NULL) {
230 return;
231 }
232
233 //
234 // Assume the bridge is aligned
235 //
236 for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
237 ; !IsNull (&Bridge->ChildList, CurrentLink)
238 ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
239 )
240 {
241 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
242 if (Node->ResourceUsage == PciResUsagePadding) {
243 ASSERT (PaddingAperture == 0);
244 PaddingAperture = Node->Length;
245 continue;
246 }
247
248 //
249 // Consider the aperture alignment
250 //
251 Offset = Aperture & (Node->Alignment);
252
253 if (Offset != 0) {
254 Aperture = Aperture + (Node->Alignment + 1) - Offset;
255 }
256
257 //
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.
261 //
262 if (mReserveIsaAliases || mReserveVgaAliases) {
263 if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
264 //
265 // Check if there is need to support ISA/VGA decoding
266 // If so, we need to avoid isa/vga aliasing range
267 //
268 if (mReserveIsaAliases) {
269 SkipIsaAliasAperture (
270 &Aperture,
271 Node->Length
272 );
273 Offset = Aperture & (Node->Alignment);
274 if (Offset != 0) {
275 Aperture = Aperture + (Node->Alignment + 1) - Offset;
276 }
277 } else if (mReserveVgaAliases) {
278 SkipVGAAperture (
279 &Aperture,
280 Node->Length
281 );
282 Offset = Aperture & (Node->Alignment);
283 if (Offset != 0) {
284 Aperture = Aperture + (Node->Alignment + 1) - Offset;
285 }
286 }
287 }
288 }
289
290 Node->Offset = Aperture;
291
292 //
293 // Increment aperture by the length of node
294 //
295 Aperture += Node->Length;
296 }
297
298 //
299 // Adjust the aperture with the bridge's alignment
300 //
301 Offset = Aperture & (Bridge->Alignment);
302
303 if (Offset != 0) {
304 Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
305 }
306
307 Bridge->Length = Aperture;
308 //
309 // At last, adjust the bridge's alignment to the first child's alignment
310 // if the bridge has at least one child
311 //
312 CurrentLink = Bridge->ChildList.ForwardLink;
313 if (CurrentLink != &Bridge->ChildList) {
314 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
315 if (Node->Alignment > Bridge->Alignment) {
316 Bridge->Alignment = Node->Alignment;
317 }
318 }
319
320 //
321 // Hotplug controller needs padding resources.
322 // Use the larger one between the padding resource and actual occupied resource.
323 //
324 Bridge->Length = MAX (Bridge->Length, PaddingAperture);
325 }
326
327 /**
328 This function is used to calculate the resource aperture
329 for a given bridge device.
330
331 @param Bridge PCI resource node for given bridge device.
332
333 **/
334 VOID
335 CalculateResourceAperture (
336 IN PCI_RESOURCE_NODE *Bridge
337 )
338 {
339 UINT64 Aperture[2];
340 LIST_ENTRY *CurrentLink;
341 PCI_RESOURCE_NODE *Node;
342
343 if (Bridge == NULL) {
344 return;
345 }
346
347 if (Bridge->ResType == PciBarTypeIo16) {
348 CalculateApertureIo16 (Bridge);
349 return;
350 }
351
352 Aperture[PciResUsageTypical] = 0;
353 Aperture[PciResUsagePadding] = 0;
354 //
355 // Assume the bridge is aligned
356 //
357 for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
358 ; !IsNull (&Bridge->ChildList, CurrentLink)
359 ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
360 )
361 {
362 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
363
364 //
365 // It's possible for a bridge to contain multiple padding resource
366 // nodes due to DegradeResource().
367 //
368 ASSERT (
369 (Node->ResourceUsage == PciResUsageTypical) ||
370 (Node->ResourceUsage == PciResUsagePadding)
371 );
372 ASSERT (Node->ResourceUsage < ARRAY_SIZE (Aperture));
373 //
374 // Recode current aperture as a offset
375 // Apply padding resource to meet alignment requirement
376 // Node offset will be used in future real allocation
377 //
378 Node->Offset = ALIGN_VALUE (Aperture[Node->ResourceUsage], Node->Alignment + 1);
379
380 //
381 // Record the total aperture.
382 //
383 Aperture[Node->ResourceUsage] = Node->Offset + Node->Length;
384 }
385
386 //
387 // Adjust the aperture with the bridge's alignment
388 //
389 Aperture[PciResUsageTypical] = ALIGN_VALUE (Aperture[PciResUsageTypical], Bridge->Alignment + 1);
390 Aperture[PciResUsagePadding] = ALIGN_VALUE (Aperture[PciResUsagePadding], Bridge->Alignment + 1);
391
392 //
393 // Hotplug controller needs padding resources.
394 // Use the larger one between the padding resource and actual occupied resource.
395 //
396 Bridge->Length = MAX (Aperture[PciResUsageTypical], Aperture[PciResUsagePadding]);
397
398 //
399 // Adjust the bridge's alignment to the MAX (first) alignment of all children.
400 //
401 CurrentLink = Bridge->ChildList.ForwardLink;
402 if (CurrentLink != &Bridge->ChildList) {
403 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
404 if (Node->Alignment > Bridge->Alignment) {
405 Bridge->Alignment = Node->Alignment;
406 }
407 }
408 }
409
410 /**
411 Get IO/Memory resource info for given PCI device.
412
413 @param PciDev Pci device instance.
414 @param IoNode Resource info node for IO .
415 @param Mem32Node Resource info node for 32-bit memory.
416 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
417 @param Mem64Node Resource info node for 64-bit memory.
418 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
419
420 **/
421 VOID
422 GetResourceFromDevice (
423 IN PCI_IO_DEVICE *PciDev,
424 IN OUT PCI_RESOURCE_NODE *IoNode,
425 IN OUT PCI_RESOURCE_NODE *Mem32Node,
426 IN OUT PCI_RESOURCE_NODE *PMem32Node,
427 IN OUT PCI_RESOURCE_NODE *Mem64Node,
428 IN OUT PCI_RESOURCE_NODE *PMem64Node
429 )
430 {
431 UINT8 Index;
432 PCI_RESOURCE_NODE *Node;
433 BOOLEAN ResourceRequested;
434
435 Node = NULL;
436 ResourceRequested = FALSE;
437
438 for (Index = 0; Index < PCI_MAX_BAR; Index++) {
439 switch ((PciDev->PciBar)[Index].BarType) {
440 case PciBarTypeMem32:
441 case PciBarTypeOpRom:
442
443 Node = CreateResourceNode (
444 PciDev,
445 (PciDev->PciBar)[Index].Length,
446 (PciDev->PciBar)[Index].Alignment,
447 Index,
448 (PciDev->PciBar)[Index].BarType,
449 PciResUsageTypical
450 );
451
452 InsertResourceNode (
453 Mem32Node,
454 Node
455 );
456
457 ResourceRequested = TRUE;
458 break;
459
460 case PciBarTypeMem64:
461
462 Node = CreateResourceNode (
463 PciDev,
464 (PciDev->PciBar)[Index].Length,
465 (PciDev->PciBar)[Index].Alignment,
466 Index,
467 PciBarTypeMem64,
468 PciResUsageTypical
469 );
470
471 InsertResourceNode (
472 Mem64Node,
473 Node
474 );
475
476 ResourceRequested = TRUE;
477 break;
478
479 case PciBarTypePMem64:
480
481 Node = CreateResourceNode (
482 PciDev,
483 (PciDev->PciBar)[Index].Length,
484 (PciDev->PciBar)[Index].Alignment,
485 Index,
486 PciBarTypePMem64,
487 PciResUsageTypical
488 );
489
490 InsertResourceNode (
491 PMem64Node,
492 Node
493 );
494
495 ResourceRequested = TRUE;
496 break;
497
498 case PciBarTypePMem32:
499
500 Node = CreateResourceNode (
501 PciDev,
502 (PciDev->PciBar)[Index].Length,
503 (PciDev->PciBar)[Index].Alignment,
504 Index,
505 PciBarTypePMem32,
506 PciResUsageTypical
507 );
508
509 InsertResourceNode (
510 PMem32Node,
511 Node
512 );
513 ResourceRequested = TRUE;
514 break;
515
516 case PciBarTypeIo16:
517 case PciBarTypeIo32:
518
519 Node = CreateResourceNode (
520 PciDev,
521 (PciDev->PciBar)[Index].Length,
522 (PciDev->PciBar)[Index].Alignment,
523 Index,
524 PciBarTypeIo16,
525 PciResUsageTypical
526 );
527
528 InsertResourceNode (
529 IoNode,
530 Node
531 );
532 ResourceRequested = TRUE;
533 break;
534
535 case PciBarTypeUnknown:
536 break;
537
538 default:
539 break;
540 }
541 }
542
543 //
544 // Add VF resource
545 //
546 for (Index = 0; Index < PCI_MAX_BAR; Index++) {
547 switch ((PciDev->VfPciBar)[Index].BarType) {
548 case PciBarTypeMem32:
549
550 Node = CreateVfResourceNode (
551 PciDev,
552 (PciDev->VfPciBar)[Index].Length,
553 (PciDev->VfPciBar)[Index].Alignment,
554 Index,
555 PciBarTypeMem32,
556 PciResUsageTypical
557 );
558
559 InsertResourceNode (
560 Mem32Node,
561 Node
562 );
563
564 break;
565
566 case PciBarTypeMem64:
567
568 Node = CreateVfResourceNode (
569 PciDev,
570 (PciDev->VfPciBar)[Index].Length,
571 (PciDev->VfPciBar)[Index].Alignment,
572 Index,
573 PciBarTypeMem64,
574 PciResUsageTypical
575 );
576
577 InsertResourceNode (
578 Mem64Node,
579 Node
580 );
581
582 break;
583
584 case PciBarTypePMem64:
585
586 Node = CreateVfResourceNode (
587 PciDev,
588 (PciDev->VfPciBar)[Index].Length,
589 (PciDev->VfPciBar)[Index].Alignment,
590 Index,
591 PciBarTypePMem64,
592 PciResUsageTypical
593 );
594
595 InsertResourceNode (
596 PMem64Node,
597 Node
598 );
599
600 break;
601
602 case PciBarTypePMem32:
603
604 Node = CreateVfResourceNode (
605 PciDev,
606 (PciDev->VfPciBar)[Index].Length,
607 (PciDev->VfPciBar)[Index].Alignment,
608 Index,
609 PciBarTypePMem32,
610 PciResUsageTypical
611 );
612
613 InsertResourceNode (
614 PMem32Node,
615 Node
616 );
617 break;
618
619 case PciBarTypeIo16:
620 case PciBarTypeIo32:
621 break;
622
623 case PciBarTypeUnknown:
624 break;
625
626 default:
627 break;
628 }
629 }
630
631 // If there is no resource requested from this device,
632 // then we indicate this device has been allocated naturally.
633 //
634 if (!ResourceRequested) {
635 PciDev->Allocated = TRUE;
636 }
637 }
638
639 /**
640 This function is used to create a resource node.
641
642 @param PciDev Pci device instance.
643 @param Length Length of Io/Memory resource.
644 @param Alignment Alignment of resource.
645 @param Bar Bar index.
646 @param ResType Type of resource: IO/Memory.
647 @param ResUsage Resource usage.
648
649 @return PCI resource node created for given PCI device.
650 NULL means PCI resource node is not created.
651
652 **/
653 PCI_RESOURCE_NODE *
654 CreateResourceNode (
655 IN PCI_IO_DEVICE *PciDev,
656 IN UINT64 Length,
657 IN UINT64 Alignment,
658 IN UINT8 Bar,
659 IN PCI_BAR_TYPE ResType,
660 IN PCI_RESOURCE_USAGE ResUsage
661 )
662 {
663 PCI_RESOURCE_NODE *Node;
664
665 Node = NULL;
666
667 Node = AllocateZeroPool (sizeof (PCI_RESOURCE_NODE));
668 ASSERT (Node != NULL);
669 if (Node == NULL) {
670 return NULL;
671 }
672
673 Node->Signature = PCI_RESOURCE_SIGNATURE;
674 Node->PciDev = PciDev;
675 Node->Length = Length;
676 Node->Alignment = Alignment;
677 Node->Bar = Bar;
678 Node->ResType = ResType;
679 Node->Reserved = FALSE;
680 Node->ResourceUsage = ResUsage;
681 InitializeListHead (&Node->ChildList);
682
683 return Node;
684 }
685
686 /**
687 This function is used to create a IOV VF resource node.
688
689 @param PciDev Pci device instance.
690 @param Length Length of Io/Memory resource.
691 @param Alignment Alignment of resource.
692 @param Bar Bar index.
693 @param ResType Type of resource: IO/Memory.
694 @param ResUsage Resource usage.
695
696 @return PCI resource node created for given VF PCI device.
697 NULL means PCI resource node is not created.
698
699 **/
700 PCI_RESOURCE_NODE *
701 CreateVfResourceNode (
702 IN PCI_IO_DEVICE *PciDev,
703 IN UINT64 Length,
704 IN UINT64 Alignment,
705 IN UINT8 Bar,
706 IN PCI_BAR_TYPE ResType,
707 IN PCI_RESOURCE_USAGE ResUsage
708 )
709 {
710 PCI_RESOURCE_NODE *Node;
711
712 Node = CreateResourceNode (PciDev, Length, Alignment, Bar, ResType, ResUsage);
713 if (Node == NULL) {
714 return Node;
715 }
716
717 Node->Virtual = TRUE;
718
719 return Node;
720 }
721
722 /**
723 This function is used to extract resource request from
724 device node list.
725
726 @param Bridge Pci device instance.
727 @param IoNode Resource info node for IO.
728 @param Mem32Node Resource info node for 32-bit memory.
729 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
730 @param Mem64Node Resource info node for 64-bit memory.
731 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
732
733 **/
734 VOID
735 CreateResourceMap (
736 IN PCI_IO_DEVICE *Bridge,
737 IN OUT PCI_RESOURCE_NODE *IoNode,
738 IN OUT PCI_RESOURCE_NODE *Mem32Node,
739 IN OUT PCI_RESOURCE_NODE *PMem32Node,
740 IN OUT PCI_RESOURCE_NODE *Mem64Node,
741 IN OUT PCI_RESOURCE_NODE *PMem64Node
742 )
743 {
744 PCI_IO_DEVICE *Temp;
745 PCI_RESOURCE_NODE *IoBridge;
746 PCI_RESOURCE_NODE *Mem32Bridge;
747 PCI_RESOURCE_NODE *PMem32Bridge;
748 PCI_RESOURCE_NODE *Mem64Bridge;
749 PCI_RESOURCE_NODE *PMem64Bridge;
750 LIST_ENTRY *CurrentLink;
751
752 CurrentLink = Bridge->ChildList.ForwardLink;
753
754 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
755 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
756
757 //
758 // Create resource nodes for this device by scanning the
759 // Bar array in the device private data
760 // If the upstream bridge doesn't support this device,
761 // no any resource node will be created for this device
762 //
763 GetResourceFromDevice (
764 Temp,
765 IoNode,
766 Mem32Node,
767 PMem32Node,
768 Mem64Node,
769 PMem64Node
770 );
771
772 if (IS_PCI_BRIDGE (&Temp->Pci)) {
773 //
774 // If the device has children, create a bridge resource node for this PPB
775 // Note: For PPB, memory aperture is aligned with 1MB and IO aperture
776 // is aligned with 4KB (smaller alignments may be supported).
777 //
778 IoBridge = CreateResourceNode (
779 Temp,
780 0,
781 Temp->BridgeIoAlignment,
782 PPB_IO_RANGE,
783 PciBarTypeIo16,
784 PciResUsageTypical
785 );
786
787 Mem32Bridge = CreateResourceNode (
788 Temp,
789 0,
790 0xFFFFF,
791 PPB_MEM32_RANGE,
792 PciBarTypeMem32,
793 PciResUsageTypical
794 );
795
796 PMem32Bridge = CreateResourceNode (
797 Temp,
798 0,
799 0xFFFFF,
800 PPB_PMEM32_RANGE,
801 PciBarTypePMem32,
802 PciResUsageTypical
803 );
804
805 Mem64Bridge = CreateResourceNode (
806 Temp,
807 0,
808 0xFFFFF,
809 PPB_MEM64_RANGE,
810 PciBarTypeMem64,
811 PciResUsageTypical
812 );
813
814 PMem64Bridge = CreateResourceNode (
815 Temp,
816 0,
817 0xFFFFF,
818 PPB_PMEM64_RANGE,
819 PciBarTypePMem64,
820 PciResUsageTypical
821 );
822
823 //
824 // Recursively create resource map on this bridge
825 //
826 CreateResourceMap (
827 Temp,
828 IoBridge,
829 Mem32Bridge,
830 PMem32Bridge,
831 Mem64Bridge,
832 PMem64Bridge
833 );
834
835 if (ResourceRequestExisted (IoBridge)) {
836 InsertResourceNode (
837 IoNode,
838 IoBridge
839 );
840 } else {
841 FreePool (IoBridge);
842 IoBridge = NULL;
843 }
844
845 //
846 // If there is node under this resource bridge,
847 // then calculate bridge's aperture of this type
848 // and insert it into the respective resource tree.
849 // If no, delete this resource bridge
850 //
851 if (ResourceRequestExisted (Mem32Bridge)) {
852 InsertResourceNode (
853 Mem32Node,
854 Mem32Bridge
855 );
856 } else {
857 FreePool (Mem32Bridge);
858 Mem32Bridge = NULL;
859 }
860
861 //
862 // If there is node under this resource bridge,
863 // then calculate bridge's aperture of this type
864 // and insert it into the respective resource tree.
865 // If no, delete this resource bridge
866 //
867 if (ResourceRequestExisted (PMem32Bridge)) {
868 InsertResourceNode (
869 PMem32Node,
870 PMem32Bridge
871 );
872 } else {
873 FreePool (PMem32Bridge);
874 PMem32Bridge = NULL;
875 }
876
877 //
878 // If there is node under this resource bridge,
879 // then calculate bridge's aperture of this type
880 // and insert it into the respective resource tree.
881 // If no, delete this resource bridge
882 //
883 if (ResourceRequestExisted (Mem64Bridge)) {
884 InsertResourceNode (
885 Mem64Node,
886 Mem64Bridge
887 );
888 } else {
889 FreePool (Mem64Bridge);
890 Mem64Bridge = NULL;
891 }
892
893 //
894 // If there is node under this resource bridge,
895 // then calculate bridge's aperture of this type
896 // and insert it into the respective resource tree.
897 // If no, delete this resource bridge
898 //
899 if (ResourceRequestExisted (PMem64Bridge)) {
900 InsertResourceNode (
901 PMem64Node,
902 PMem64Bridge
903 );
904 } else {
905 FreePool (PMem64Bridge);
906 PMem64Bridge = NULL;
907 }
908 }
909
910 //
911 // If it is P2C, apply hard coded resource padding
912 //
913 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
914 ResourcePaddingForCardBusBridge (
915 Temp,
916 IoNode,
917 Mem32Node,
918 PMem32Node,
919 Mem64Node,
920 PMem64Node
921 );
922 }
923
924 CurrentLink = CurrentLink->ForwardLink;
925 }
926
927 //
928 // To do some platform specific resource padding ...
929 //
930 ResourcePaddingPolicy (
931 Bridge,
932 IoNode,
933 Mem32Node,
934 PMem32Node,
935 Mem64Node,
936 PMem64Node
937 );
938
939 //
940 // Degrade resource if necessary
941 //
942 DegradeResource (
943 Bridge,
944 Mem32Node,
945 PMem32Node,
946 Mem64Node,
947 PMem64Node
948 );
949
950 //
951 // Calculate resource aperture for this bridge device
952 //
953 CalculateResourceAperture (Mem32Node);
954 CalculateResourceAperture (PMem32Node);
955 CalculateResourceAperture (Mem64Node);
956 CalculateResourceAperture (PMem64Node);
957 CalculateResourceAperture (IoNode);
958 }
959
960 /**
961 This function is used to do the resource padding for a specific platform.
962
963 @param PciDev Pci device instance.
964 @param IoNode Resource info node for IO.
965 @param Mem32Node Resource info node for 32-bit memory.
966 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
967 @param Mem64Node Resource info node for 64-bit memory.
968 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
969
970 **/
971 VOID
972 ResourcePaddingPolicy (
973 IN PCI_IO_DEVICE *PciDev,
974 IN PCI_RESOURCE_NODE *IoNode,
975 IN PCI_RESOURCE_NODE *Mem32Node,
976 IN PCI_RESOURCE_NODE *PMem32Node,
977 IN PCI_RESOURCE_NODE *Mem64Node,
978 IN PCI_RESOURCE_NODE *PMem64Node
979 )
980 {
981 //
982 // Create padding resource node
983 //
984 if (PciDev->ResourcePaddingDescriptors != NULL) {
985 ApplyResourcePadding (
986 PciDev,
987 IoNode,
988 Mem32Node,
989 PMem32Node,
990 Mem64Node,
991 PMem64Node
992 );
993 }
994 }
995
996 /**
997 This function is used to degrade resource if the upstream bridge
998 doesn't support certain resource. Degradation path is
999 PMEM64 -> MEM64 -> MEM32
1000 PMEM64 -> PMEM32 -> MEM32
1001 IO32 -> IO16.
1002
1003 @param Bridge Pci device instance.
1004 @param Mem32Node Resource info node for 32-bit memory.
1005 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1006 @param Mem64Node Resource info node for 64-bit memory.
1007 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1008
1009 **/
1010 VOID
1011 DegradeResource (
1012 IN PCI_IO_DEVICE *Bridge,
1013 IN PCI_RESOURCE_NODE *Mem32Node,
1014 IN PCI_RESOURCE_NODE *PMem32Node,
1015 IN PCI_RESOURCE_NODE *Mem64Node,
1016 IN PCI_RESOURCE_NODE *PMem64Node
1017 )
1018 {
1019 PCI_IO_DEVICE *PciIoDevice;
1020 LIST_ENTRY *ChildDeviceLink;
1021 LIST_ENTRY *ChildNodeLink;
1022 LIST_ENTRY *NextChildNodeLink;
1023 PCI_RESOURCE_NODE *ResourceNode;
1024
1025 if (FeaturePcdGet (PcdPciDegradeResourceForOptionRom)) {
1026 //
1027 // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64
1028 // requests in case that if a legacy option ROM image can not access 64-bit resources.
1029 //
1030 ChildDeviceLink = Bridge->ChildList.ForwardLink;
1031 while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList) {
1032 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink);
1033 if (PciIoDevice->RomSize != 0) {
1034 if (!IsListEmpty (&Mem64Node->ChildList)) {
1035 ChildNodeLink = Mem64Node->ChildList.ForwardLink;
1036 while (ChildNodeLink != &Mem64Node->ChildList) {
1037 ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
1038 NextChildNodeLink = ChildNodeLink->ForwardLink;
1039
1040 if ((ResourceNode->PciDev == PciIoDevice) &&
1041 (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed)
1042 )
1043 {
1044 RemoveEntryList (ChildNodeLink);
1045 InsertResourceNode (Mem32Node, ResourceNode);
1046 }
1047
1048 ChildNodeLink = NextChildNodeLink;
1049 }
1050 }
1051
1052 if (!IsListEmpty (&PMem64Node->ChildList)) {
1053 ChildNodeLink = PMem64Node->ChildList.ForwardLink;
1054 while (ChildNodeLink != &PMem64Node->ChildList) {
1055 ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
1056 NextChildNodeLink = ChildNodeLink->ForwardLink;
1057
1058 if ((ResourceNode->PciDev == PciIoDevice) &&
1059 (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed)
1060 )
1061 {
1062 RemoveEntryList (ChildNodeLink);
1063 InsertResourceNode (PMem32Node, ResourceNode);
1064 }
1065
1066 ChildNodeLink = NextChildNodeLink;
1067 }
1068 }
1069 }
1070
1071 ChildDeviceLink = ChildDeviceLink->ForwardLink;
1072 }
1073 }
1074
1075 //
1076 // If firmware is in 32-bit mode,
1077 // then degrade PMEM64/MEM64 requests
1078 //
1079 if (sizeof (UINTN) <= 4) {
1080 MergeResourceTree (
1081 Mem32Node,
1082 Mem64Node,
1083 TRUE
1084 );
1085
1086 MergeResourceTree (
1087 PMem32Node,
1088 PMem64Node,
1089 TRUE
1090 );
1091 } else {
1092 //
1093 // if the bridge does not support MEM64, degrade MEM64 to MEM32
1094 //
1095 if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
1096 MergeResourceTree (
1097 Mem32Node,
1098 Mem64Node,
1099 TRUE
1100 );
1101 }
1102
1103 //
1104 // if the bridge does not support PMEM64, degrade PMEM64 to PMEM32
1105 //
1106 if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
1107 MergeResourceTree (
1108 PMem32Node,
1109 PMem64Node,
1110 TRUE
1111 );
1112 }
1113
1114 //
1115 // if both PMEM64 and PMEM32 requests from child devices, which can not be satisfied
1116 // by a P2P bridge simultaneously, keep PMEM64 and degrade PMEM32 to MEM32.
1117 //
1118 if (!IsListEmpty (&PMem64Node->ChildList) && (Bridge->Parent != NULL)) {
1119 MergeResourceTree (
1120 Mem32Node,
1121 PMem32Node,
1122 TRUE
1123 );
1124 }
1125 }
1126
1127 //
1128 // If bridge doesn't support Pmem32
1129 // degrade it to mem32
1130 //
1131 if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
1132 MergeResourceTree (
1133 Mem32Node,
1134 PMem32Node,
1135 TRUE
1136 );
1137 }
1138
1139 //
1140 // if root bridge supports combined Pmem Mem decoding
1141 // merge these two type of resource
1142 //
1143 if (BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {
1144 MergeResourceTree (
1145 Mem32Node,
1146 PMem32Node,
1147 FALSE
1148 );
1149
1150 //
1151 // No need to check if to degrade MEM64 after merge, because
1152 // if there are PMEM64 still here, 64-bit decode should be supported
1153 // by the root bride.
1154 //
1155 MergeResourceTree (
1156 Mem64Node,
1157 PMem64Node,
1158 FALSE
1159 );
1160 }
1161 }
1162
1163 /**
1164 Test whether bridge device support decode resource.
1165
1166 @param Bridge Bridge device instance.
1167 @param Decode Decode type according to resource type.
1168
1169 @return TRUE The bridge device support decode resource.
1170 @return FALSE The bridge device don't support decode resource.
1171
1172 **/
1173 BOOLEAN
1174 BridgeSupportResourceDecode (
1175 IN PCI_IO_DEVICE *Bridge,
1176 IN UINT32 Decode
1177 )
1178 {
1179 if (((Bridge->Decodes) & Decode) != 0) {
1180 return TRUE;
1181 }
1182
1183 return FALSE;
1184 }
1185
1186 /**
1187 This function is used to program the resource allocated
1188 for each resource node under specified bridge.
1189
1190 @param Base Base address of resource to be programmed.
1191 @param Bridge PCI resource node for the bridge device.
1192
1193 @retval EFI_SUCCESS Successfully to program all resources
1194 on given PCI bridge device.
1195 @retval EFI_OUT_OF_RESOURCES Base is all one.
1196
1197 **/
1198 EFI_STATUS
1199 ProgramResource (
1200 IN UINT64 Base,
1201 IN PCI_RESOURCE_NODE *Bridge
1202 )
1203 {
1204 LIST_ENTRY *CurrentLink;
1205 PCI_RESOURCE_NODE *Node;
1206 EFI_STATUS Status;
1207
1208 if (Base == gAllOne) {
1209 return EFI_OUT_OF_RESOURCES;
1210 }
1211
1212 CurrentLink = Bridge->ChildList.ForwardLink;
1213
1214 while (CurrentLink != &Bridge->ChildList) {
1215 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
1216
1217 if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {
1218 if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
1219 //
1220 // Program the PCI Card Bus device
1221 //
1222 ProgramP2C (Base, Node);
1223 } else {
1224 //
1225 // Program the PCI device BAR
1226 //
1227 ProgramBar (Base, Node);
1228 }
1229 } else {
1230 //
1231 // Program the PCI devices under this bridge
1232 //
1233 Status = ProgramResource (Base + Node->Offset, Node);
1234 if (EFI_ERROR (Status)) {
1235 return Status;
1236 }
1237
1238 ProgramPpbApperture (Base, Node);
1239 }
1240
1241 CurrentLink = CurrentLink->ForwardLink;
1242 }
1243
1244 return EFI_SUCCESS;
1245 }
1246
1247 /**
1248 Program Bar register for PCI device.
1249
1250 @param Base Base address for PCI device resource to be programmed.
1251 @param Node Point to resource node structure.
1252
1253 **/
1254 VOID
1255 ProgramBar (
1256 IN UINT64 Base,
1257 IN PCI_RESOURCE_NODE *Node
1258 )
1259 {
1260 EFI_PCI_IO_PROTOCOL *PciIo;
1261 UINT64 Address;
1262 UINT32 Address32;
1263
1264 ASSERT (Node->Bar < PCI_MAX_BAR);
1265
1266 //
1267 // Check VF BAR
1268 //
1269 if (Node->Virtual) {
1270 ProgramVfBar (Base, Node);
1271 return;
1272 }
1273
1274 Address = 0;
1275 PciIo = &(Node->PciDev->PciIo);
1276
1277 Address = Base + Node->Offset;
1278
1279 //
1280 // Indicate pci bus driver has allocated
1281 // resource for this device
1282 // It might be a temporary solution here since
1283 // pci device could have multiple bar
1284 //
1285 Node->PciDev->Allocated = TRUE;
1286
1287 switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
1288 case PciBarTypeIo16:
1289 case PciBarTypeIo32:
1290 case PciBarTypeMem32:
1291 case PciBarTypePMem32:
1292
1293 PciIo->Pci.Write (
1294 PciIo,
1295 EfiPciIoWidthUint32,
1296 (Node->PciDev->PciBar[Node->Bar]).Offset,
1297 1,
1298 &Address
1299 );
1300 //
1301 // Continue to the case PciBarTypeOpRom to set the BaseAddress.
1302 // PciBarTypeOpRom is a virtual BAR only in root bridge, to capture
1303 // the MEM32 resource requirement for Option ROM shadow.
1304 //
1305
1306 case PciBarTypeOpRom:
1307 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1308
1309 break;
1310
1311 case PciBarTypeMem64:
1312 case PciBarTypePMem64:
1313
1314 Address32 = (UINT32)(Address & 0x00000000FFFFFFFF);
1315
1316 PciIo->Pci.Write (
1317 PciIo,
1318 EfiPciIoWidthUint32,
1319 (Node->PciDev->PciBar[Node->Bar]).Offset,
1320 1,
1321 &Address32
1322 );
1323
1324 Address32 = (UINT32)RShiftU64 (Address, 32);
1325
1326 PciIo->Pci.Write (
1327 PciIo,
1328 EfiPciIoWidthUint32,
1329 (UINT8)((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
1330 1,
1331 &Address32
1332 );
1333
1334 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1335
1336 break;
1337
1338 default:
1339 break;
1340 }
1341 }
1342
1343 /**
1344 Program IOV VF Bar register for PCI device.
1345
1346 @param Base Base address for PCI device resource to be programmed.
1347 @param Node Point to resource node structure.
1348
1349 **/
1350 EFI_STATUS
1351 ProgramVfBar (
1352 IN UINT64 Base,
1353 IN PCI_RESOURCE_NODE *Node
1354 )
1355 {
1356 EFI_PCI_IO_PROTOCOL *PciIo;
1357 UINT64 Address;
1358 UINT32 Address32;
1359
1360 ASSERT (Node->Bar < PCI_MAX_BAR);
1361 ASSERT (Node->Virtual);
1362
1363 Address = 0;
1364 PciIo = &(Node->PciDev->PciIo);
1365
1366 Address = Base + Node->Offset;
1367
1368 //
1369 // Indicate pci bus driver has allocated
1370 // resource for this device
1371 // It might be a temporary solution here since
1372 // pci device could have multiple bar
1373 //
1374 Node->PciDev->Allocated = TRUE;
1375
1376 switch ((Node->PciDev->VfPciBar[Node->Bar]).BarType) {
1377 case PciBarTypeMem32:
1378 case PciBarTypePMem32:
1379
1380 PciIo->Pci.Write (
1381 PciIo,
1382 EfiPciIoWidthUint32,
1383 (Node->PciDev->VfPciBar[Node->Bar]).Offset,
1384 1,
1385 &Address
1386 );
1387
1388 Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
1389 break;
1390
1391 case PciBarTypeMem64:
1392 case PciBarTypePMem64:
1393
1394 Address32 = (UINT32)(Address & 0x00000000FFFFFFFF);
1395
1396 PciIo->Pci.Write (
1397 PciIo,
1398 EfiPciIoWidthUint32,
1399 (Node->PciDev->VfPciBar[Node->Bar]).Offset,
1400 1,
1401 &Address32
1402 );
1403
1404 Address32 = (UINT32)RShiftU64 (Address, 32);
1405
1406 PciIo->Pci.Write (
1407 PciIo,
1408 EfiPciIoWidthUint32,
1409 ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4),
1410 1,
1411 &Address32
1412 );
1413
1414 Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
1415 break;
1416
1417 case PciBarTypeIo16:
1418 case PciBarTypeIo32:
1419 break;
1420
1421 default:
1422 break;
1423 }
1424
1425 return EFI_SUCCESS;
1426 }
1427
1428 /**
1429 Program PCI-PCI bridge aperture.
1430
1431 @param Base Base address for resource.
1432 @param Node Point to resource node structure.
1433
1434 **/
1435 VOID
1436 ProgramPpbApperture (
1437 IN UINT64 Base,
1438 IN PCI_RESOURCE_NODE *Node
1439 )
1440 {
1441 EFI_PCI_IO_PROTOCOL *PciIo;
1442 UINT64 Address;
1443 UINT32 Address32;
1444
1445 Address = 0;
1446 //
1447 // If no device resource of this PPB, return anyway
1448 // Aperture is set default in the initialization code
1449 //
1450 if ((Node->Length == 0) || (Node->ResourceUsage == PciResUsagePadding)) {
1451 //
1452 // For padding resource node, just ignore when programming
1453 //
1454 return;
1455 }
1456
1457 PciIo = &(Node->PciDev->PciIo);
1458 Address = Base + Node->Offset;
1459
1460 //
1461 // Indicate the PPB resource has been allocated
1462 //
1463 Node->PciDev->Allocated = TRUE;
1464
1465 switch (Node->Bar) {
1466 case PPB_BAR_0:
1467 case PPB_BAR_1:
1468 switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
1469 case PciBarTypeIo16:
1470 case PciBarTypeIo32:
1471 case PciBarTypeMem32:
1472 case PciBarTypePMem32:
1473
1474 PciIo->Pci.Write (
1475 PciIo,
1476 EfiPciIoWidthUint32,
1477 (Node->PciDev->PciBar[Node->Bar]).Offset,
1478 1,
1479 &Address
1480 );
1481
1482 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1483 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1484 break;
1485
1486 case PciBarTypeMem64:
1487 case PciBarTypePMem64:
1488
1489 Address32 = (UINT32)(Address & 0x00000000FFFFFFFF);
1490
1491 PciIo->Pci.Write (
1492 PciIo,
1493 EfiPciIoWidthUint32,
1494 (Node->PciDev->PciBar[Node->Bar]).Offset,
1495 1,
1496 &Address32
1497 );
1498
1499 Address32 = (UINT32)RShiftU64 (Address, 32);
1500
1501 PciIo->Pci.Write (
1502 PciIo,
1503 EfiPciIoWidthUint32,
1504 (UINT8)((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
1505 1,
1506 &Address32
1507 );
1508
1509 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1510 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1511 break;
1512
1513 default:
1514 break;
1515 }
1516
1517 break;
1518
1519 case PPB_IO_RANGE:
1520
1521 Address32 = ((UINT32)(Address)) >> 8;
1522 PciIo->Pci.Write (
1523 PciIo,
1524 EfiPciIoWidthUint8,
1525 0x1C,
1526 1,
1527 &Address32
1528 );
1529
1530 Address32 >>= 8;
1531 PciIo->Pci.Write (
1532 PciIo,
1533 EfiPciIoWidthUint16,
1534 0x30,
1535 1,
1536 &Address32
1537 );
1538
1539 Address32 = (UINT32)(Address + Node->Length - 1);
1540 Address32 = ((UINT32)(Address32)) >> 8;
1541 PciIo->Pci.Write (
1542 PciIo,
1543 EfiPciIoWidthUint8,
1544 0x1D,
1545 1,
1546 &Address32
1547 );
1548
1549 Address32 >>= 8;
1550 PciIo->Pci.Write (
1551 PciIo,
1552 EfiPciIoWidthUint16,
1553 0x32,
1554 1,
1555 &Address32
1556 );
1557
1558 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1559 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1560 break;
1561
1562 case PPB_MEM32_RANGE:
1563
1564 Address32 = ((UINT32)(Address)) >> 16;
1565 PciIo->Pci.Write (
1566 PciIo,
1567 EfiPciIoWidthUint16,
1568 0x20,
1569 1,
1570 &Address32
1571 );
1572
1573 Address32 = (UINT32)(Address + Node->Length - 1);
1574 Address32 = ((UINT32)(Address32)) >> 16;
1575 PciIo->Pci.Write (
1576 PciIo,
1577 EfiPciIoWidthUint16,
1578 0x22,
1579 1,
1580 &Address32
1581 );
1582
1583 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1584 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1585 break;
1586
1587 case PPB_PMEM32_RANGE:
1588 case PPB_PMEM64_RANGE:
1589
1590 Address32 = ((UINT32)(Address)) >> 16;
1591 PciIo->Pci.Write (
1592 PciIo,
1593 EfiPciIoWidthUint16,
1594 0x24,
1595 1,
1596 &Address32
1597 );
1598
1599 Address32 = (UINT32)(Address + Node->Length - 1);
1600 Address32 = ((UINT32)(Address32)) >> 16;
1601 PciIo->Pci.Write (
1602 PciIo,
1603 EfiPciIoWidthUint16,
1604 0x26,
1605 1,
1606 &Address32
1607 );
1608
1609 Address32 = (UINT32)RShiftU64 (Address, 32);
1610 PciIo->Pci.Write (
1611 PciIo,
1612 EfiPciIoWidthUint32,
1613 0x28,
1614 1,
1615 &Address32
1616 );
1617
1618 Address32 = (UINT32)RShiftU64 ((Address + Node->Length - 1), 32);
1619 PciIo->Pci.Write (
1620 PciIo,
1621 EfiPciIoWidthUint32,
1622 0x2C,
1623 1,
1624 &Address32
1625 );
1626
1627 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1628 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1629 break;
1630
1631 default:
1632 break;
1633 }
1634 }
1635
1636 /**
1637 Program parent bridge for Option Rom.
1638
1639 @param PciDevice Pci device instance.
1640 @param OptionRomBase Base address for Option Rom.
1641 @param Enable Enable or disable PCI memory.
1642
1643 **/
1644 VOID
1645 ProgramUpstreamBridgeForRom (
1646 IN PCI_IO_DEVICE *PciDevice,
1647 IN UINT32 OptionRomBase,
1648 IN BOOLEAN Enable
1649 )
1650 {
1651 PCI_IO_DEVICE *Parent;
1652 EFI_PCI_IO_PROTOCOL *PciIo;
1653 UINT16 Base;
1654 UINT16 Limit;
1655
1656 //
1657 // For root bridge, just return.
1658 //
1659 Parent = PciDevice->Parent;
1660 while (Parent != NULL) {
1661 if (!IS_PCI_BRIDGE (&Parent->Pci)) {
1662 break;
1663 }
1664
1665 PciIo = &Parent->PciIo;
1666
1667 //
1668 // Program PPB to only open a single <= 16MB aperture
1669 //
1670 if (Enable) {
1671 //
1672 // Only cover MMIO for Option ROM.
1673 //
1674 Base = (UINT16)(OptionRomBase >> 16);
1675 Limit = (UINT16)((OptionRomBase + PciDevice->RomSize - 1) >> 16);
1676 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base);
1677 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit);
1678
1679 PCI_ENABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
1680 } else {
1681 //
1682 // Cover 32bit MMIO for devices below the bridge.
1683 //
1684 if (Parent->PciBar[PPB_MEM32_RANGE].Length == 0) {
1685 //
1686 // When devices under the bridge contains Option ROM and doesn't require 32bit MMIO.
1687 //
1688 Base = (UINT16)gAllOne;
1689 Limit = (UINT16)gAllZero;
1690 } else {
1691 Base = (UINT16)((UINT32)Parent->PciBar[PPB_MEM32_RANGE].BaseAddress >> 16);
1692 Limit = (UINT16)((UINT32)(Parent->PciBar[PPB_MEM32_RANGE].BaseAddress
1693 + Parent->PciBar[PPB_MEM32_RANGE].Length - 1) >> 16);
1694 }
1695
1696 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base);
1697 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit);
1698
1699 PCI_DISABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
1700 }
1701
1702 Parent = Parent->Parent;
1703 }
1704 }
1705
1706 /**
1707 Test whether resource exists for a bridge.
1708
1709 @param Bridge Point to resource node for a bridge.
1710
1711 @retval TRUE There is resource on the given bridge.
1712 @retval FALSE There isn't resource on the given bridge.
1713
1714 **/
1715 BOOLEAN
1716 ResourceRequestExisted (
1717 IN PCI_RESOURCE_NODE *Bridge
1718 )
1719 {
1720 if (Bridge != NULL) {
1721 if (!IsListEmpty (&Bridge->ChildList) || (Bridge->Length != 0)) {
1722 return TRUE;
1723 }
1724 }
1725
1726 return FALSE;
1727 }
1728
1729 /**
1730 Initialize resource pool structure.
1731
1732 @param ResourcePool Point to resource pool structure. This pool
1733 is reset to all zero when returned.
1734 @param ResourceType Type of resource.
1735
1736 **/
1737 VOID
1738 InitializeResourcePool (
1739 IN OUT PCI_RESOURCE_NODE *ResourcePool,
1740 IN PCI_BAR_TYPE ResourceType
1741 )
1742 {
1743 ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
1744 ResourcePool->ResType = ResourceType;
1745 ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
1746 InitializeListHead (&ResourcePool->ChildList);
1747 }
1748
1749 /**
1750 Destroy given resource tree.
1751
1752 @param Bridge PCI resource root node of resource tree.
1753
1754 **/
1755 VOID
1756 DestroyResourceTree (
1757 IN PCI_RESOURCE_NODE *Bridge
1758 )
1759 {
1760 PCI_RESOURCE_NODE *Temp;
1761 LIST_ENTRY *CurrentLink;
1762
1763 while (!IsListEmpty (&Bridge->ChildList)) {
1764 CurrentLink = Bridge->ChildList.ForwardLink;
1765
1766 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1767 ASSERT (Temp);
1768
1769 RemoveEntryList (CurrentLink);
1770
1771 if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
1772 DestroyResourceTree (Temp);
1773 }
1774
1775 FreePool (Temp);
1776 }
1777 }
1778
1779 /**
1780 Insert resource padding for P2C.
1781
1782 @param PciDev Pci device instance.
1783 @param IoNode Resource info node for IO.
1784 @param Mem32Node Resource info node for 32-bit memory.
1785 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1786 @param Mem64Node Resource info node for 64-bit memory.
1787 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1788
1789 **/
1790 VOID
1791 ResourcePaddingForCardBusBridge (
1792 IN PCI_IO_DEVICE *PciDev,
1793 IN PCI_RESOURCE_NODE *IoNode,
1794 IN PCI_RESOURCE_NODE *Mem32Node,
1795 IN PCI_RESOURCE_NODE *PMem32Node,
1796 IN PCI_RESOURCE_NODE *Mem64Node,
1797 IN PCI_RESOURCE_NODE *PMem64Node
1798 )
1799 {
1800 PCI_RESOURCE_NODE *Node;
1801
1802 Node = NULL;
1803
1804 //
1805 // Memory Base/Limit Register 0
1806 // Bar 1 decodes memory range 0
1807 //
1808 Node = CreateResourceNode (
1809 PciDev,
1810 0x2000000,
1811 0x1ffffff,
1812 1,
1813 PciBarTypeMem32,
1814 PciResUsagePadding
1815 );
1816
1817 InsertResourceNode (
1818 Mem32Node,
1819 Node
1820 );
1821
1822 //
1823 // Memory Base/Limit Register 1
1824 // Bar 2 decodes memory range1
1825 //
1826 Node = CreateResourceNode (
1827 PciDev,
1828 0x2000000,
1829 0x1ffffff,
1830 2,
1831 PciBarTypePMem32,
1832 PciResUsagePadding
1833 );
1834
1835 InsertResourceNode (
1836 PMem32Node,
1837 Node
1838 );
1839
1840 //
1841 // Io Base/Limit
1842 // Bar 3 decodes io range 0
1843 //
1844 Node = CreateResourceNode (
1845 PciDev,
1846 0x100,
1847 0xff,
1848 3,
1849 PciBarTypeIo16,
1850 PciResUsagePadding
1851 );
1852
1853 InsertResourceNode (
1854 IoNode,
1855 Node
1856 );
1857
1858 //
1859 // Io Base/Limit
1860 // Bar 4 decodes io range 0
1861 //
1862 Node = CreateResourceNode (
1863 PciDev,
1864 0x100,
1865 0xff,
1866 4,
1867 PciBarTypeIo16,
1868 PciResUsagePadding
1869 );
1870
1871 InsertResourceNode (
1872 IoNode,
1873 Node
1874 );
1875 }
1876
1877 /**
1878 Program PCI Card device register for given resource node.
1879
1880 @param Base Base address of PCI Card device to be programmed.
1881 @param Node Given resource node.
1882
1883 **/
1884 VOID
1885 ProgramP2C (
1886 IN UINT64 Base,
1887 IN PCI_RESOURCE_NODE *Node
1888 )
1889 {
1890 EFI_PCI_IO_PROTOCOL *PciIo;
1891 UINT64 Address;
1892 UINT64 TempAddress;
1893 UINT16 BridgeControl;
1894
1895 Address = 0;
1896 PciIo = &(Node->PciDev->PciIo);
1897
1898 Address = Base + Node->Offset;
1899
1900 //
1901 // Indicate pci bus driver has allocated
1902 // resource for this device
1903 // It might be a temporary solution here since
1904 // pci device could have multiple bar
1905 //
1906 Node->PciDev->Allocated = TRUE;
1907
1908 switch (Node->Bar) {
1909 case P2C_BAR_0:
1910 PciIo->Pci.Write (
1911 PciIo,
1912 EfiPciIoWidthUint32,
1913 (Node->PciDev->PciBar[Node->Bar]).Offset,
1914 1,
1915 &Address
1916 );
1917
1918 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1919 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1920 break;
1921
1922 case P2C_MEM_1:
1923 PciIo->Pci.Write (
1924 PciIo,
1925 EfiPciIoWidthUint32,
1926 PCI_CARD_MEMORY_BASE_0,
1927 1,
1928 &Address
1929 );
1930
1931 TempAddress = Address + Node->Length - 1;
1932 PciIo->Pci.Write (
1933 PciIo,
1934 EfiPciIoWidthUint32,
1935 PCI_CARD_MEMORY_LIMIT_0,
1936 1,
1937 &TempAddress
1938 );
1939
1940 if (Node->ResType == PciBarTypeMem32) {
1941 //
1942 // Set non-prefetchable bit
1943 //
1944 PciIo->Pci.Read (
1945 PciIo,
1946 EfiPciIoWidthUint16,
1947 PCI_CARD_BRIDGE_CONTROL,
1948 1,
1949 &BridgeControl
1950 );
1951
1952 BridgeControl &= (UINT16) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
1953 PciIo->Pci.Write (
1954 PciIo,
1955 EfiPciIoWidthUint16,
1956 PCI_CARD_BRIDGE_CONTROL,
1957 1,
1958 &BridgeControl
1959 );
1960 } else {
1961 //
1962 // Set prefetchable bit
1963 //
1964 PciIo->Pci.Read (
1965 PciIo,
1966 EfiPciIoWidthUint16,
1967 PCI_CARD_BRIDGE_CONTROL,
1968 1,
1969 &BridgeControl
1970 );
1971
1972 BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
1973 PciIo->Pci.Write (
1974 PciIo,
1975 EfiPciIoWidthUint16,
1976 PCI_CARD_BRIDGE_CONTROL,
1977 1,
1978 &BridgeControl
1979 );
1980 }
1981
1982 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1983 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1984 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
1985
1986 break;
1987
1988 case P2C_MEM_2:
1989 PciIo->Pci.Write (
1990 PciIo,
1991 EfiPciIoWidthUint32,
1992 PCI_CARD_MEMORY_BASE_1,
1993 1,
1994 &Address
1995 );
1996
1997 TempAddress = Address + Node->Length - 1;
1998
1999 PciIo->Pci.Write (
2000 PciIo,
2001 EfiPciIoWidthUint32,
2002 PCI_CARD_MEMORY_LIMIT_1,
2003 1,
2004 &TempAddress
2005 );
2006
2007 if (Node->ResType == PciBarTypeMem32) {
2008 //
2009 // Set non-prefetchable bit
2010 //
2011 PciIo->Pci.Read (
2012 PciIo,
2013 EfiPciIoWidthUint16,
2014 PCI_CARD_BRIDGE_CONTROL,
2015 1,
2016 &BridgeControl
2017 );
2018
2019 BridgeControl &= (UINT16) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE);
2020 PciIo->Pci.Write (
2021 PciIo,
2022 EfiPciIoWidthUint16,
2023 PCI_CARD_BRIDGE_CONTROL,
2024 1,
2025 &BridgeControl
2026 );
2027 } else {
2028 //
2029 // Set prefetchable bit
2030 //
2031 PciIo->Pci.Read (
2032 PciIo,
2033 EfiPciIoWidthUint16,
2034 PCI_CARD_BRIDGE_CONTROL,
2035 1,
2036 &BridgeControl
2037 );
2038
2039 BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE;
2040 PciIo->Pci.Write (
2041 PciIo,
2042 EfiPciIoWidthUint16,
2043 PCI_CARD_BRIDGE_CONTROL,
2044 1,
2045 &BridgeControl
2046 );
2047 }
2048
2049 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2050 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2051 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2052 break;
2053
2054 case P2C_IO_1:
2055 PciIo->Pci.Write (
2056 PciIo,
2057 EfiPciIoWidthUint32,
2058 PCI_CARD_IO_BASE_0_LOWER,
2059 1,
2060 &Address
2061 );
2062
2063 TempAddress = Address + Node->Length - 1;
2064 PciIo->Pci.Write (
2065 PciIo,
2066 EfiPciIoWidthUint32,
2067 PCI_CARD_IO_LIMIT_0_LOWER,
2068 1,
2069 &TempAddress
2070 );
2071
2072 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2073 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2074 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2075
2076 break;
2077
2078 case P2C_IO_2:
2079 PciIo->Pci.Write (
2080 PciIo,
2081 EfiPciIoWidthUint32,
2082 PCI_CARD_IO_BASE_1_LOWER,
2083 1,
2084 &Address
2085 );
2086
2087 TempAddress = Address + Node->Length - 1;
2088 PciIo->Pci.Write (
2089 PciIo,
2090 EfiPciIoWidthUint32,
2091 PCI_CARD_IO_LIMIT_1_LOWER,
2092 1,
2093 &TempAddress
2094 );
2095
2096 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2097 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2098 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2099 break;
2100
2101 default:
2102 break;
2103 }
2104 }
2105
2106 /**
2107 Create padding resource node.
2108
2109 @param PciDev Pci device instance.
2110 @param IoNode Resource info node for IO.
2111 @param Mem32Node Resource info node for 32-bit memory.
2112 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
2113 @param Mem64Node Resource info node for 64-bit memory.
2114 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
2115
2116 **/
2117 VOID
2118 ApplyResourcePadding (
2119 IN PCI_IO_DEVICE *PciDev,
2120 IN PCI_RESOURCE_NODE *IoNode,
2121 IN PCI_RESOURCE_NODE *Mem32Node,
2122 IN PCI_RESOURCE_NODE *PMem32Node,
2123 IN PCI_RESOURCE_NODE *Mem64Node,
2124 IN PCI_RESOURCE_NODE *PMem64Node
2125 )
2126 {
2127 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
2128 PCI_RESOURCE_NODE *Node;
2129 UINT8 DummyBarIndex;
2130
2131 DummyBarIndex = 0;
2132 Ptr = PciDev->ResourcePaddingDescriptors;
2133
2134 while (((EFI_ACPI_END_TAG_DESCRIPTOR *)Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {
2135 if ((Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {
2136 if (Ptr->AddrLen != 0) {
2137 Node = CreateResourceNode (
2138 PciDev,
2139 Ptr->AddrLen,
2140 Ptr->AddrRangeMax,
2141 DummyBarIndex,
2142 PciBarTypeIo16,
2143 PciResUsagePadding
2144 );
2145 InsertResourceNode (
2146 IoNode,
2147 Node
2148 );
2149 }
2150
2151 Ptr++;
2152 continue;
2153 }
2154
2155 if ((Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {
2156 if (Ptr->AddrSpaceGranularity == 32) {
2157 //
2158 // prefetchable
2159 //
2160 if (Ptr->SpecificFlag == 0x6) {
2161 if (Ptr->AddrLen != 0) {
2162 Node = CreateResourceNode (
2163 PciDev,
2164 Ptr->AddrLen,
2165 Ptr->AddrRangeMax,
2166 DummyBarIndex,
2167 PciBarTypePMem32,
2168 PciResUsagePadding
2169 );
2170 InsertResourceNode (
2171 PMem32Node,
2172 Node
2173 );
2174 }
2175
2176 Ptr++;
2177 continue;
2178 }
2179
2180 //
2181 // Non-prefetchable
2182 //
2183 if (Ptr->SpecificFlag == 0) {
2184 if (Ptr->AddrLen != 0) {
2185 Node = CreateResourceNode (
2186 PciDev,
2187 Ptr->AddrLen,
2188 Ptr->AddrRangeMax,
2189 DummyBarIndex,
2190 PciBarTypeMem32,
2191 PciResUsagePadding
2192 );
2193 InsertResourceNode (
2194 Mem32Node,
2195 Node
2196 );
2197 }
2198
2199 Ptr++;
2200 continue;
2201 }
2202 }
2203
2204 if (Ptr->AddrSpaceGranularity == 64) {
2205 //
2206 // prefetchable
2207 //
2208 if (Ptr->SpecificFlag == 0x6) {
2209 if (Ptr->AddrLen != 0) {
2210 Node = CreateResourceNode (
2211 PciDev,
2212 Ptr->AddrLen,
2213 Ptr->AddrRangeMax,
2214 DummyBarIndex,
2215 PciBarTypePMem64,
2216 PciResUsagePadding
2217 );
2218 InsertResourceNode (
2219 PMem64Node,
2220 Node
2221 );
2222 }
2223
2224 Ptr++;
2225 continue;
2226 }
2227
2228 //
2229 // Non-prefetchable
2230 //
2231 if (Ptr->SpecificFlag == 0) {
2232 if (Ptr->AddrLen != 0) {
2233 Node = CreateResourceNode (
2234 PciDev,
2235 Ptr->AddrLen,
2236 Ptr->AddrRangeMax,
2237 DummyBarIndex,
2238 PciBarTypeMem64,
2239 PciResUsagePadding
2240 );
2241 InsertResourceNode (
2242 Mem64Node,
2243 Node
2244 );
2245 }
2246
2247 Ptr++;
2248 continue;
2249 }
2250 }
2251 }
2252
2253 Ptr++;
2254 }
2255 }
2256
2257 /**
2258 Get padding resource for PCI-PCI bridge.
2259
2260 @param PciIoDevice PCI-PCI bridge device instance.
2261
2262 @note Feature flag PcdPciBusHotplugDeviceSupport determines
2263 whether need to pad resource for them.
2264 **/
2265 VOID
2266 GetResourcePaddingPpb (
2267 IN PCI_IO_DEVICE *PciIoDevice
2268 )
2269 {
2270 if ((gPciHotPlugInit != NULL) && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
2271 if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
2272 GetResourcePaddingForHpb (PciIoDevice);
2273 }
2274 }
2275 }