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