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