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