]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c
Print resource allocation/bar programming when PciBus driver does PCI BUS enumeration.
[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 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
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
200 if (!mPolicyDetermined) {
201 //
202 // Check PciPlatform policy
203 //
204 Status = EFI_NOT_FOUND;
205 PciPolicy = 0;
206 if (gPciPlatformProtocol != NULL) {
207 Status = gPciPlatformProtocol->GetPlatformPolicy (
208 gPciPlatformProtocol,
209 &PciPolicy
210 );
211 }
212
213 if (EFI_ERROR (Status) && gPciOverrideProtocol != NULL) {
214 Status = gPciOverrideProtocol->GetPlatformPolicy (
215 gPciOverrideProtocol,
216 &PciPolicy
217 );
218 }
219
220 if (!EFI_ERROR (Status)) {
221 if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) {
222 mReserveIsaAliases = TRUE;
223 }
224 if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) {
225 mReserveVgaAliases = TRUE;
226 }
227 }
228 mPolicyDetermined = TRUE;
229 }
230
231 Aperture = 0;
232
233 if (Bridge == NULL) {
234 return ;
235 }
236
237 CurrentLink = Bridge->ChildList.ForwardLink;
238
239 //
240 // Assume the bridge is aligned
241 //
242 while (CurrentLink != &Bridge->ChildList) {
243
244 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
245
246 //
247 // Consider the aperture alignment
248 //
249 Offset = Aperture & (Node->Alignment);
250
251 if (Offset != 0) {
252
253 Aperture = Aperture + (Node->Alignment + 1) - Offset;
254
255 }
256
257 //
258 // IsaEnable and VGAEnable can not be implemented now.
259 // If both of them are enabled, then the IO resource would
260 // become too limited to meet the requirement of most of devices.
261 //
262 if (mReserveIsaAliases || mReserveVgaAliases) {
263 if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
264 //
265 // Check if there is need to support ISA/VGA decoding
266 // If so, we need to avoid isa/vga aliasing range
267 //
268 if (mReserveIsaAliases) {
269 SkipIsaAliasAperture (
270 &Aperture,
271 Node->Length
272 );
273 Offset = Aperture & (Node->Alignment);
274 if (Offset != 0) {
275 Aperture = Aperture + (Node->Alignment + 1) - Offset;
276 }
277 } else if (mReserveVgaAliases) {
278 SkipVGAAperture (
279 &Aperture,
280 Node->Length
281 );
282 Offset = Aperture & (Node->Alignment);
283 if (Offset != 0) {
284 Aperture = Aperture + (Node->Alignment + 1) - Offset;
285 }
286 }
287 }
288 }
289
290 Node->Offset = Aperture;
291
292 //
293 // Increment aperture by the length of node
294 //
295 Aperture += Node->Length;
296
297 CurrentLink = CurrentLink->ForwardLink;
298 }
299
300 //
301 // At last, adjust the aperture with the bridge's
302 // alignment
303 //
304 Offset = Aperture & (Bridge->Alignment);
305
306 if (Offset != 0) {
307 Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
308 }
309
310 Bridge->Length = Aperture;
311 //
312 // At last, adjust the bridge's alignment to the first child's alignment
313 // if the bridge has at least one child
314 //
315 CurrentLink = Bridge->ChildList.ForwardLink;
316 if (CurrentLink != &Bridge->ChildList) {
317 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
318 if (Node->Alignment > Bridge->Alignment) {
319 Bridge->Alignment = Node->Alignment;
320 }
321 }
322 }
323
324 /**
325 This function is used to calculate the resource aperture
326 for a given bridge device.
327
328 @param Bridge PCI resouce node for given bridge device.
329
330 **/
331 VOID
332 CalculateResourceAperture (
333 IN PCI_RESOURCE_NODE *Bridge
334 )
335 {
336 UINT64 Aperture;
337 LIST_ENTRY *CurrentLink;
338 PCI_RESOURCE_NODE *Node;
339
340 UINT64 Offset;
341
342 Aperture = 0;
343
344 if (Bridge == NULL) {
345 return ;
346 }
347
348 if (Bridge->ResType == PciBarTypeIo16) {
349
350 CalculateApertureIo16 (Bridge);
351 return ;
352 }
353
354 CurrentLink = Bridge->ChildList.ForwardLink;
355
356 //
357 // Assume the bridge is aligned
358 //
359 while (CurrentLink != &Bridge->ChildList) {
360
361 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
362
363 //
364 // Apply padding resource if available
365 //
366 Offset = Aperture & (Node->Alignment);
367
368 if (Offset != 0) {
369
370 Aperture = Aperture + (Node->Alignment + 1) - Offset;
371
372 }
373
374 //
375 // Recode current aperture as a offset
376 // this offset will be used in future real allocation
377 //
378 Node->Offset = Aperture;
379
380 //
381 // Increment aperture by the length of node
382 //
383 Aperture += Node->Length;
384
385 //
386 // Consider the aperture alignment
387 //
388 CurrentLink = CurrentLink->ForwardLink;
389 }
390
391 //
392 // At last, adjust the aperture with the bridge's
393 // alignment
394 //
395 Offset = Aperture & (Bridge->Alignment);
396 if (Offset != 0) {
397 Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
398 }
399
400 //
401 // If the bridge has already padded the resource and the
402 // amount of padded resource is larger, then keep the
403 // padded resource
404 //
405 if (Bridge->Length < Aperture) {
406 Bridge->Length = Aperture;
407 }
408
409 //
410 // At last, adjust the bridge's alignment to the first child's alignment
411 // if the bridge has at least one child
412 //
413 CurrentLink = Bridge->ChildList.ForwardLink;
414 if (CurrentLink != &Bridge->ChildList) {
415 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
416 if (Node->Alignment > Bridge->Alignment) {
417 Bridge->Alignment = Node->Alignment;
418 }
419 }
420 }
421
422 /**
423 Get IO/Memory resource infor for given PCI device.
424
425 @param PciDev Pci device instance.
426 @param IoNode Resource info node for IO .
427 @param Mem32Node Resource info node for 32-bit memory.
428 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
429 @param Mem64Node Resource info node for 64-bit memory.
430 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
431
432 **/
433 VOID
434 GetResourceFromDevice (
435 IN PCI_IO_DEVICE *PciDev,
436 IN OUT PCI_RESOURCE_NODE *IoNode,
437 IN OUT PCI_RESOURCE_NODE *Mem32Node,
438 IN OUT PCI_RESOURCE_NODE *PMem32Node,
439 IN OUT PCI_RESOURCE_NODE *Mem64Node,
440 IN OUT PCI_RESOURCE_NODE *PMem64Node
441 )
442 {
443
444 UINT8 Index;
445 PCI_RESOURCE_NODE *Node;
446 BOOLEAN ResourceRequested;
447
448 Node = NULL;
449 ResourceRequested = FALSE;
450
451 for (Index = 0; Index < PCI_MAX_BAR; Index++) {
452
453 switch ((PciDev->PciBar)[Index].BarType) {
454
455 case PciBarTypeMem32:
456
457 Node = CreateResourceNode (
458 PciDev,
459 (PciDev->PciBar)[Index].Length,
460 (PciDev->PciBar)[Index].Alignment,
461 Index,
462 PciBarTypeMem32,
463 PciResUsageTypical
464 );
465
466 InsertResourceNode (
467 Mem32Node,
468 Node
469 );
470
471 ResourceRequested = TRUE;
472 break;
473
474 case PciBarTypeMem64:
475
476 Node = CreateResourceNode (
477 PciDev,
478 (PciDev->PciBar)[Index].Length,
479 (PciDev->PciBar)[Index].Alignment,
480 Index,
481 PciBarTypeMem64,
482 PciResUsageTypical
483 );
484
485 InsertResourceNode (
486 Mem64Node,
487 Node
488 );
489
490 ResourceRequested = TRUE;
491 break;
492
493 case PciBarTypePMem64:
494
495 Node = CreateResourceNode (
496 PciDev,
497 (PciDev->PciBar)[Index].Length,
498 (PciDev->PciBar)[Index].Alignment,
499 Index,
500 PciBarTypePMem64,
501 PciResUsageTypical
502 );
503
504 InsertResourceNode (
505 PMem64Node,
506 Node
507 );
508
509 ResourceRequested = TRUE;
510 break;
511
512 case PciBarTypePMem32:
513
514 Node = CreateResourceNode (
515 PciDev,
516 (PciDev->PciBar)[Index].Length,
517 (PciDev->PciBar)[Index].Alignment,
518 Index,
519 PciBarTypePMem32,
520 PciResUsageTypical
521 );
522
523 InsertResourceNode (
524 PMem32Node,
525 Node
526 );
527 ResourceRequested = TRUE;
528 break;
529
530 case PciBarTypeIo16:
531 case PciBarTypeIo32:
532
533 Node = CreateResourceNode (
534 PciDev,
535 (PciDev->PciBar)[Index].Length,
536 (PciDev->PciBar)[Index].Alignment,
537 Index,
538 PciBarTypeIo16,
539 PciResUsageTypical
540 );
541
542 InsertResourceNode (
543 IoNode,
544 Node
545 );
546 ResourceRequested = TRUE;
547 break;
548
549 case PciBarTypeUnknown:
550 break;
551
552 default:
553 break;
554 }
555 }
556
557 //
558 // Add VF resource
559 //
560 for (Index = 0; Index < PCI_MAX_BAR; Index++) {
561
562 switch ((PciDev->VfPciBar)[Index].BarType) {
563
564 case PciBarTypeMem32:
565
566 Node = CreateVfResourceNode (
567 PciDev,
568 (PciDev->VfPciBar)[Index].Length,
569 (PciDev->VfPciBar)[Index].Alignment,
570 Index,
571 PciBarTypeMem32,
572 PciResUsageTypical
573 );
574
575 InsertResourceNode (
576 Mem32Node,
577 Node
578 );
579
580 break;
581
582 case PciBarTypeMem64:
583
584 Node = CreateVfResourceNode (
585 PciDev,
586 (PciDev->VfPciBar)[Index].Length,
587 (PciDev->VfPciBar)[Index].Alignment,
588 Index,
589 PciBarTypeMem64,
590 PciResUsageTypical
591 );
592
593 InsertResourceNode (
594 Mem64Node,
595 Node
596 );
597
598 break;
599
600 case PciBarTypePMem64:
601
602 Node = CreateVfResourceNode (
603 PciDev,
604 (PciDev->VfPciBar)[Index].Length,
605 (PciDev->VfPciBar)[Index].Alignment,
606 Index,
607 PciBarTypePMem64,
608 PciResUsageTypical
609 );
610
611 InsertResourceNode (
612 PMem64Node,
613 Node
614 );
615
616 break;
617
618 case PciBarTypePMem32:
619
620 Node = CreateVfResourceNode (
621 PciDev,
622 (PciDev->VfPciBar)[Index].Length,
623 (PciDev->VfPciBar)[Index].Alignment,
624 Index,
625 PciBarTypePMem32,
626 PciResUsageTypical
627 );
628
629 InsertResourceNode (
630 PMem32Node,
631 Node
632 );
633 break;
634
635 case PciBarTypeIo16:
636 case PciBarTypeIo32:
637 break;
638
639 case PciBarTypeUnknown:
640 break;
641
642 default:
643 break;
644 }
645 }
646 // If there is no resource requested from this device,
647 // then we indicate this device has been allocated naturally.
648 //
649 if (!ResourceRequested) {
650 PciDev->Allocated = TRUE;
651 }
652 }
653
654 /**
655 This function is used to create a resource node.
656
657 @param PciDev Pci device instance.
658 @param Length Length of Io/Memory resource.
659 @param Alignment Alignment of resource.
660 @param Bar Bar index.
661 @param ResType Type of resource: IO/Memory.
662 @param ResUsage Resource usage.
663
664 @return PCI resource node created for given PCI device.
665 NULL means PCI resource node is not created.
666
667 **/
668 PCI_RESOURCE_NODE *
669 CreateResourceNode (
670 IN PCI_IO_DEVICE *PciDev,
671 IN UINT64 Length,
672 IN UINT64 Alignment,
673 IN UINT8 Bar,
674 IN PCI_BAR_TYPE ResType,
675 IN PCI_RESOURCE_USAGE ResUsage
676 )
677 {
678 PCI_RESOURCE_NODE *Node;
679
680 Node = NULL;
681
682 Node = AllocateZeroPool (sizeof (PCI_RESOURCE_NODE));
683 ASSERT (Node != NULL);
684 if (Node == NULL) {
685 return NULL;
686 }
687
688 Node->Signature = PCI_RESOURCE_SIGNATURE;
689 Node->PciDev = PciDev;
690 Node->Length = Length;
691 Node->Alignment = Alignment;
692 Node->Bar = Bar;
693 Node->ResType = ResType;
694 Node->Reserved = FALSE;
695 Node->ResourceUsage = ResUsage;
696 InitializeListHead (&Node->ChildList);
697
698 return Node;
699 }
700
701 /**
702 This function is used to create a IOV VF resource node.
703
704 @param PciDev Pci device instance.
705 @param Length Length of Io/Memory resource.
706 @param Alignment Alignment of resource.
707 @param Bar Bar index.
708 @param ResType Type of resource: IO/Memory.
709 @param ResUsage Resource usage.
710
711 @return PCI resource node created for given VF PCI device.
712 NULL means PCI resource node is not created.
713
714 **/
715 PCI_RESOURCE_NODE *
716 CreateVfResourceNode (
717 IN PCI_IO_DEVICE *PciDev,
718 IN UINT64 Length,
719 IN UINT64 Alignment,
720 IN UINT8 Bar,
721 IN PCI_BAR_TYPE ResType,
722 IN PCI_RESOURCE_USAGE ResUsage
723 )
724 {
725 PCI_RESOURCE_NODE *Node;
726
727 Node = CreateResourceNode (PciDev, Length, Alignment, Bar, ResType, ResUsage);
728 if (Node == NULL) {
729 return Node;
730 }
731
732 Node->Virtual = TRUE;
733
734 return Node;
735 }
736
737 /**
738 This function is used to extract resource request from
739 device node list.
740
741 @param Bridge Pci device instance.
742 @param IoNode Resource info node for IO.
743 @param Mem32Node Resource info node for 32-bit memory.
744 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
745 @param Mem64Node Resource info node for 64-bit memory.
746 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
747
748 **/
749 VOID
750 CreateResourceMap (
751 IN PCI_IO_DEVICE *Bridge,
752 IN OUT PCI_RESOURCE_NODE *IoNode,
753 IN OUT PCI_RESOURCE_NODE *Mem32Node,
754 IN OUT PCI_RESOURCE_NODE *PMem32Node,
755 IN OUT PCI_RESOURCE_NODE *Mem64Node,
756 IN OUT PCI_RESOURCE_NODE *PMem64Node
757 )
758 {
759 PCI_IO_DEVICE *Temp;
760 PCI_RESOURCE_NODE *IoBridge;
761 PCI_RESOURCE_NODE *Mem32Bridge;
762 PCI_RESOURCE_NODE *PMem32Bridge;
763 PCI_RESOURCE_NODE *Mem64Bridge;
764 PCI_RESOURCE_NODE *PMem64Bridge;
765 LIST_ENTRY *CurrentLink;
766
767 CurrentLink = Bridge->ChildList.ForwardLink;
768
769 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
770
771 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
772
773 //
774 // Create resource nodes for this device by scanning the
775 // Bar array in the device private data
776 // If the upstream bridge doesn't support this device,
777 // no any resource node will be created for this device
778 //
779 GetResourceFromDevice (
780 Temp,
781 IoNode,
782 Mem32Node,
783 PMem32Node,
784 Mem64Node,
785 PMem64Node
786 );
787
788 if (IS_PCI_BRIDGE (&Temp->Pci)) {
789
790 //
791 // If the device has children, create a bridge resource node for this PPB
792 // Note: For PPB, memory aperture is aligned with 1MB and IO aperture
793 // is aligned with 4KB (smaller alignments may be supported).
794 //
795 IoBridge = CreateResourceNode (
796 Temp,
797 0,
798 Temp->BridgeIoAlignment,
799 PPB_IO_RANGE,
800 PciBarTypeIo16,
801 PciResUsageTypical
802 );
803
804 Mem32Bridge = CreateResourceNode (
805 Temp,
806 0,
807 0xFFFFF,
808 PPB_MEM32_RANGE,
809 PciBarTypeMem32,
810 PciResUsageTypical
811 );
812
813 PMem32Bridge = CreateResourceNode (
814 Temp,
815 0,
816 0xFFFFF,
817 PPB_PMEM32_RANGE,
818 PciBarTypePMem32,
819 PciResUsageTypical
820 );
821
822 Mem64Bridge = CreateResourceNode (
823 Temp,
824 0,
825 0xFFFFF,
826 PPB_MEM64_RANGE,
827 PciBarTypeMem64,
828 PciResUsageTypical
829 );
830
831 PMem64Bridge = CreateResourceNode (
832 Temp,
833 0,
834 0xFFFFF,
835 PPB_PMEM64_RANGE,
836 PciBarTypePMem64,
837 PciResUsageTypical
838 );
839
840 //
841 // Recursively create resouce map on this bridge
842 //
843 CreateResourceMap (
844 Temp,
845 IoBridge,
846 Mem32Bridge,
847 PMem32Bridge,
848 Mem64Bridge,
849 PMem64Bridge
850 );
851
852 if (ResourceRequestExisted (IoBridge)) {
853 InsertResourceNode (
854 IoNode,
855 IoBridge
856 );
857 } else {
858 FreePool (IoBridge);
859 IoBridge = NULL;
860 }
861
862 //
863 // If there is node under this resource bridge,
864 // then calculate bridge's aperture of this type
865 // and insert it into the respective resource tree.
866 // If no, delete this resource bridge
867 //
868 if (ResourceRequestExisted (Mem32Bridge)) {
869 InsertResourceNode (
870 Mem32Node,
871 Mem32Bridge
872 );
873 } else {
874 FreePool (Mem32Bridge);
875 Mem32Bridge = NULL;
876 }
877
878 //
879 // If there is node under this resource bridge,
880 // then calculate bridge's aperture of this type
881 // and insert it into the respective resource tree.
882 // If no, delete this resource bridge
883 //
884 if (ResourceRequestExisted (PMem32Bridge)) {
885 InsertResourceNode (
886 PMem32Node,
887 PMem32Bridge
888 );
889 } else {
890 FreePool (PMem32Bridge);
891 PMem32Bridge = NULL;
892 }
893
894 //
895 // If there is node under this resource bridge,
896 // then calculate bridge's aperture of this type
897 // and insert it into the respective resource tree.
898 // If no, delete this resource bridge
899 //
900 if (ResourceRequestExisted (Mem64Bridge)) {
901 InsertResourceNode (
902 Mem64Node,
903 Mem64Bridge
904 );
905 } else {
906 FreePool (Mem64Bridge);
907 Mem64Bridge = NULL;
908 }
909
910 //
911 // If there is node under this resource bridge,
912 // then calculate bridge's aperture of this type
913 // and insert it into the respective resource tree.
914 // If no, delete this resource bridge
915 //
916 if (ResourceRequestExisted (PMem64Bridge)) {
917 InsertResourceNode (
918 PMem64Node,
919 PMem64Bridge
920 );
921 } else {
922 FreePool (PMem64Bridge);
923 PMem64Bridge = NULL;
924 }
925
926 }
927
928 //
929 // If it is P2C, apply hard coded resource padding
930 //
931 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
932 ResourcePaddingForCardBusBridge (
933 Temp,
934 IoNode,
935 Mem32Node,
936 PMem32Node,
937 Mem64Node,
938 PMem64Node
939 );
940 }
941
942 CurrentLink = CurrentLink->ForwardLink;
943 }
944
945 //
946 // To do some platform specific resource padding ...
947 //
948 ResourcePaddingPolicy (
949 Bridge,
950 IoNode,
951 Mem32Node,
952 PMem32Node,
953 Mem64Node,
954 PMem64Node
955 );
956
957 //
958 // Degrade resource if necessary
959 //
960 DegradeResource (
961 Bridge,
962 Mem32Node,
963 PMem32Node,
964 Mem64Node,
965 PMem64Node
966 );
967
968 //
969 // Calculate resource aperture for this bridge device
970 //
971 CalculateResourceAperture (Mem32Node);
972 CalculateResourceAperture (PMem32Node);
973 CalculateResourceAperture (Mem64Node);
974 CalculateResourceAperture (PMem64Node);
975 CalculateResourceAperture (IoNode);
976 }
977
978 /**
979 This function is used to do the resource padding for a specific platform.
980
981 @param PciDev Pci device instance.
982 @param IoNode Resource info node for IO.
983 @param Mem32Node Resource info node for 32-bit memory.
984 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
985 @param Mem64Node Resource info node for 64-bit memory.
986 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
987
988 **/
989 VOID
990 ResourcePaddingPolicy (
991 IN PCI_IO_DEVICE *PciDev,
992 IN PCI_RESOURCE_NODE *IoNode,
993 IN PCI_RESOURCE_NODE *Mem32Node,
994 IN PCI_RESOURCE_NODE *PMem32Node,
995 IN PCI_RESOURCE_NODE *Mem64Node,
996 IN PCI_RESOURCE_NODE *PMem64Node
997 )
998 {
999 //
1000 // Create padding resource node
1001 //
1002 if (PciDev->ResourcePaddingDescriptors != NULL) {
1003 ApplyResourcePadding (
1004 PciDev,
1005 IoNode,
1006 Mem32Node,
1007 PMem32Node,
1008 Mem64Node,
1009 PMem64Node
1010 );
1011 }
1012 }
1013
1014 /**
1015 This function is used to degrade resource if the upstream bridge
1016 doesn't support certain resource. Degradation path is
1017 PMEM64 -> MEM64 -> MEM32
1018 PMEM64 -> PMEM32 -> MEM32
1019 IO32 -> IO16.
1020
1021 @param Bridge Pci device instance.
1022 @param Mem32Node Resource info node for 32-bit memory.
1023 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1024 @param Mem64Node Resource info node for 64-bit memory.
1025 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1026
1027 **/
1028 VOID
1029 DegradeResource (
1030 IN PCI_IO_DEVICE *Bridge,
1031 IN PCI_RESOURCE_NODE *Mem32Node,
1032 IN PCI_RESOURCE_NODE *PMem32Node,
1033 IN PCI_RESOURCE_NODE *Mem64Node,
1034 IN PCI_RESOURCE_NODE *PMem64Node
1035 )
1036 {
1037 PCI_IO_DEVICE *Temp;
1038 LIST_ENTRY *ChildDeviceLink;
1039 LIST_ENTRY *ChildNodeLink;
1040 LIST_ENTRY *NextChildNodeLink;
1041 PCI_RESOURCE_NODE *TempNode;
1042
1043 //
1044 // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64
1045 // requests in case that if a legacy option ROM image can not access 64-bit resources.
1046 //
1047 ChildDeviceLink = Bridge->ChildList.ForwardLink;
1048 while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList) {
1049 Temp = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink);
1050 if (Temp->RomSize != 0) {
1051 if (!IsListEmpty (&Mem64Node->ChildList)) {
1052 ChildNodeLink = Mem64Node->ChildList.ForwardLink;
1053 while (ChildNodeLink != &Mem64Node->ChildList) {
1054 TempNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
1055 NextChildNodeLink = ChildNodeLink->ForwardLink;
1056
1057 if (TempNode->PciDev == Temp) {
1058 RemoveEntryList (ChildNodeLink);
1059 InsertResourceNode (Mem32Node, TempNode);
1060 }
1061 ChildNodeLink = NextChildNodeLink;
1062 }
1063 }
1064
1065 if (!IsListEmpty (&PMem64Node->ChildList)) {
1066 ChildNodeLink = PMem64Node->ChildList.ForwardLink;
1067 while (ChildNodeLink != &PMem64Node->ChildList) {
1068 TempNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
1069 NextChildNodeLink = ChildNodeLink->ForwardLink;
1070
1071 if (TempNode->PciDev == Temp) {
1072 RemoveEntryList (ChildNodeLink);
1073 InsertResourceNode (PMem32Node, TempNode);
1074 }
1075 ChildNodeLink = NextChildNodeLink;
1076 }
1077 }
1078
1079 }
1080 ChildDeviceLink = ChildDeviceLink->ForwardLink;
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 progammed.
1199 @param Bridge PCI resource node for the bridge device.
1200
1201 @retval EFI_SUCCESS Successfully to program all resouces
1202 on given PCI bridge device.
1203 @retval EFI_OUT_OF_RESOURCES Base is all one.
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 progammed.
1261 @param Node Point to resoure 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 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1313
1314 break;
1315
1316 case PciBarTypeMem64:
1317 case PciBarTypePMem64:
1318
1319 Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
1320
1321 PciIo->Pci.Write (
1322 PciIo,
1323 EfiPciIoWidthUint32,
1324 (Node->PciDev->PciBar[Node->Bar]).Offset,
1325 1,
1326 &Address32
1327 );
1328
1329 Address32 = (UINT32) RShiftU64 (Address, 32);
1330
1331 PciIo->Pci.Write (
1332 PciIo,
1333 EfiPciIoWidthUint32,
1334 (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
1335 1,
1336 &Address32
1337 );
1338
1339 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1340
1341 break;
1342
1343 default:
1344 break;
1345 }
1346 }
1347
1348 /**
1349 Program IOV VF Bar register for PCI device.
1350
1351 @param Base Base address for PCI device resource to be progammed.
1352 @param Node Point to resoure node structure.
1353
1354 **/
1355 EFI_STATUS
1356 ProgramVfBar (
1357 IN UINT64 Base,
1358 IN PCI_RESOURCE_NODE *Node
1359 )
1360 {
1361 EFI_PCI_IO_PROTOCOL *PciIo;
1362 UINT64 Address;
1363 UINT32 Address32;
1364
1365 ASSERT (Node->Bar < PCI_MAX_BAR);
1366 ASSERT (Node->Virtual);
1367
1368 Address = 0;
1369 PciIo = &(Node->PciDev->PciIo);
1370
1371 Address = Base + Node->Offset;
1372
1373 //
1374 // Indicate pci bus driver has allocated
1375 // resource for this device
1376 // It might be a temporary solution here since
1377 // pci device could have multiple bar
1378 //
1379 Node->PciDev->Allocated = TRUE;
1380
1381 switch ((Node->PciDev->VfPciBar[Node->Bar]).BarType) {
1382
1383 case PciBarTypeMem32:
1384 case PciBarTypePMem32:
1385
1386 PciIo->Pci.Write (
1387 PciIo,
1388 EfiPciIoWidthUint32,
1389 (Node->PciDev->VfPciBar[Node->Bar]).Offset,
1390 1,
1391 &Address
1392 );
1393
1394 Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
1395 break;
1396
1397 case PciBarTypeMem64:
1398 case PciBarTypePMem64:
1399
1400 Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
1401
1402 PciIo->Pci.Write (
1403 PciIo,
1404 EfiPciIoWidthUint32,
1405 (Node->PciDev->VfPciBar[Node->Bar]).Offset,
1406 1,
1407 &Address32
1408 );
1409
1410 Address32 = (UINT32) RShiftU64 (Address, 32);
1411
1412 PciIo->Pci.Write (
1413 PciIo,
1414 EfiPciIoWidthUint32,
1415 ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4),
1416 1,
1417 &Address32
1418 );
1419
1420 Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
1421 break;
1422
1423 case PciBarTypeIo16:
1424 case PciBarTypeIo32:
1425 break;
1426
1427 default:
1428 break;
1429 }
1430
1431 return EFI_SUCCESS;
1432 }
1433
1434 /**
1435 Program PCI-PCI bridge apperture.
1436
1437 @param Base Base address for resource.
1438 @param Node Point to resoure node structure.
1439
1440 **/
1441 VOID
1442 ProgramPpbApperture (
1443 IN UINT64 Base,
1444 IN PCI_RESOURCE_NODE *Node
1445 )
1446 {
1447 EFI_PCI_IO_PROTOCOL *PciIo;
1448 UINT64 Address;
1449 UINT32 Address32;
1450
1451 Address = 0;
1452 //
1453 // If no device resource of this PPB, return anyway
1454 // Apperture is set default in the initialization code
1455 //
1456 if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {
1457 //
1458 // For padding resource node, just ignore when programming
1459 //
1460 return ;
1461 }
1462
1463 PciIo = &(Node->PciDev->PciIo);
1464 Address = Base + Node->Offset;
1465
1466 //
1467 // Indicate the PPB resource has been allocated
1468 //
1469 Node->PciDev->Allocated = TRUE;
1470
1471 switch (Node->Bar) {
1472
1473 case PPB_BAR_0:
1474 case PPB_BAR_1:
1475 PciIo->Pci.Write (
1476 PciIo,
1477 EfiPciIoWidthUint32,
1478 (Node->PciDev->PciBar[Node->Bar]).Offset,
1479 1,
1480 &Address
1481 );
1482
1483 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1484 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1485
1486 break;
1487
1488 case PPB_IO_RANGE:
1489
1490 Address32 = ((UINT32) (Address)) >> 8;
1491 PciIo->Pci.Write (
1492 PciIo,
1493 EfiPciIoWidthUint8,
1494 0x1C,
1495 1,
1496 &Address32
1497 );
1498
1499 Address32 >>= 8;
1500 PciIo->Pci.Write (
1501 PciIo,
1502 EfiPciIoWidthUint16,
1503 0x30,
1504 1,
1505 &Address32
1506 );
1507
1508 Address32 = (UINT32) (Address + Node->Length - 1);
1509 Address32 = ((UINT32) (Address32)) >> 8;
1510 PciIo->Pci.Write (
1511 PciIo,
1512 EfiPciIoWidthUint8,
1513 0x1D,
1514 1,
1515 &Address32
1516 );
1517
1518 Address32 >>= 8;
1519 PciIo->Pci.Write (
1520 PciIo,
1521 EfiPciIoWidthUint16,
1522 0x32,
1523 1,
1524 &Address32
1525 );
1526
1527 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1528 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1529 break;
1530
1531 case PPB_MEM32_RANGE:
1532
1533 Address32 = ((UINT32) (Address)) >> 16;
1534 PciIo->Pci.Write (
1535 PciIo,
1536 EfiPciIoWidthUint16,
1537 0x20,
1538 1,
1539 &Address32
1540 );
1541
1542 Address32 = (UINT32) (Address + Node->Length - 1);
1543 Address32 = ((UINT32) (Address32)) >> 16;
1544 PciIo->Pci.Write (
1545 PciIo,
1546 EfiPciIoWidthUint16,
1547 0x22,
1548 1,
1549 &Address32
1550 );
1551
1552 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1553 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1554 break;
1555
1556 case PPB_PMEM32_RANGE:
1557 case PPB_PMEM64_RANGE:
1558
1559 Address32 = ((UINT32) (Address)) >> 16;
1560 PciIo->Pci.Write (
1561 PciIo,
1562 EfiPciIoWidthUint16,
1563 0x24,
1564 1,
1565 &Address32
1566 );
1567
1568 Address32 = (UINT32) (Address + Node->Length - 1);
1569 Address32 = ((UINT32) (Address32)) >> 16;
1570 PciIo->Pci.Write (
1571 PciIo,
1572 EfiPciIoWidthUint16,
1573 0x26,
1574 1,
1575 &Address32
1576 );
1577
1578 Address32 = (UINT32) RShiftU64 (Address, 32);
1579 PciIo->Pci.Write (
1580 PciIo,
1581 EfiPciIoWidthUint32,
1582 0x28,
1583 1,
1584 &Address32
1585 );
1586
1587 Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);
1588 PciIo->Pci.Write (
1589 PciIo,
1590 EfiPciIoWidthUint32,
1591 0x2C,
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 default:
1601 break;
1602 }
1603 }
1604
1605 /**
1606 Program parent bridge for Option Rom.
1607
1608 @param PciDevice Pci deivce instance.
1609 @param OptionRomBase Base address for Optiona Rom.
1610 @param Enable Enable or disable PCI memory.
1611
1612 **/
1613 VOID
1614 ProgrameUpstreamBridgeForRom (
1615 IN PCI_IO_DEVICE *PciDevice,
1616 IN UINT32 OptionRomBase,
1617 IN BOOLEAN Enable
1618 )
1619 {
1620 PCI_IO_DEVICE *Parent;
1621 PCI_RESOURCE_NODE Node;
1622 //
1623 // For root bridge, just return.
1624 //
1625 Parent = PciDevice->Parent;
1626 ZeroMem (&Node, sizeof (Node));
1627 while (Parent != NULL) {
1628 if (!IS_PCI_BRIDGE (&Parent->Pci)) {
1629 break;
1630 }
1631
1632 Node.PciDev = Parent;
1633 Node.Length = PciDevice->RomSize;
1634 Node.Alignment = 0;
1635 Node.Bar = PPB_MEM32_RANGE;
1636 Node.ResType = PciBarTypeMem32;
1637 Node.Offset = 0;
1638
1639 //
1640 // Program PPB to only open a single <= 16MB apperture
1641 //
1642 if (Enable) {
1643 ProgramPpbApperture (OptionRomBase, &Node);
1644 PCI_ENABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
1645 } else {
1646 InitializePpb (Parent);
1647 PCI_DISABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
1648 }
1649
1650 Parent = Parent->Parent;
1651 }
1652 }
1653
1654 /**
1655 Test whether resource exists for a bridge.
1656
1657 @param Bridge Point to resource node for a bridge.
1658
1659 @retval TRUE There is resource on the given bridge.
1660 @retval FALSE There isn't resource on the given bridge.
1661
1662 **/
1663 BOOLEAN
1664 ResourceRequestExisted (
1665 IN PCI_RESOURCE_NODE *Bridge
1666 )
1667 {
1668 if (Bridge != NULL) {
1669 if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {
1670 return TRUE;
1671 }
1672 }
1673
1674 return FALSE;
1675 }
1676
1677 /**
1678 Initialize resource pool structure.
1679
1680 @param ResourcePool Point to resource pool structure. This pool
1681 is reset to all zero when returned.
1682 @param ResourceType Type of resource.
1683
1684 **/
1685 VOID
1686 InitializeResourcePool (
1687 IN OUT PCI_RESOURCE_NODE *ResourcePool,
1688 IN PCI_BAR_TYPE ResourceType
1689 )
1690 {
1691 ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
1692 ResourcePool->ResType = ResourceType;
1693 ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
1694 InitializeListHead (&ResourcePool->ChildList);
1695 }
1696
1697 /**
1698 Destory given resource tree.
1699
1700 @param Bridge PCI resource root node of resource tree.
1701
1702 **/
1703 VOID
1704 DestroyResourceTree (
1705 IN PCI_RESOURCE_NODE *Bridge
1706 )
1707 {
1708 PCI_RESOURCE_NODE *Temp;
1709 LIST_ENTRY *CurrentLink;
1710
1711 while (!IsListEmpty (&Bridge->ChildList)) {
1712
1713 CurrentLink = Bridge->ChildList.ForwardLink;
1714
1715 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1716 ASSERT (Temp);
1717
1718 RemoveEntryList (CurrentLink);
1719
1720 if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
1721 DestroyResourceTree (Temp);
1722 }
1723
1724 FreePool (Temp);
1725 }
1726 }
1727
1728 /**
1729 Insert resource padding for P2C.
1730
1731 @param PciDev Pci device instance.
1732 @param IoNode Resource info node for IO.
1733 @param Mem32Node Resource info node for 32-bit memory.
1734 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1735 @param Mem64Node Resource info node for 64-bit memory.
1736 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1737
1738 **/
1739 VOID
1740 ResourcePaddingForCardBusBridge (
1741 IN PCI_IO_DEVICE *PciDev,
1742 IN PCI_RESOURCE_NODE *IoNode,
1743 IN PCI_RESOURCE_NODE *Mem32Node,
1744 IN PCI_RESOURCE_NODE *PMem32Node,
1745 IN PCI_RESOURCE_NODE *Mem64Node,
1746 IN PCI_RESOURCE_NODE *PMem64Node
1747 )
1748 {
1749 PCI_RESOURCE_NODE *Node;
1750
1751 Node = NULL;
1752
1753 //
1754 // Memory Base/Limit Register 0
1755 // Bar 1 denodes memory range 0
1756 //
1757 Node = CreateResourceNode (
1758 PciDev,
1759 0x2000000,
1760 0x1ffffff,
1761 1,
1762 PciBarTypeMem32,
1763 PciResUsagePadding
1764 );
1765
1766 InsertResourceNode (
1767 Mem32Node,
1768 Node
1769 );
1770
1771 //
1772 // Memory Base/Limit Register 1
1773 // Bar 2 denodes memory range1
1774 //
1775 Node = CreateResourceNode (
1776 PciDev,
1777 0x2000000,
1778 0x1ffffff,
1779 2,
1780 PciBarTypePMem32,
1781 PciResUsagePadding
1782 );
1783
1784 InsertResourceNode (
1785 PMem32Node,
1786 Node
1787 );
1788
1789 //
1790 // Io Base/Limit
1791 // Bar 3 denodes io range 0
1792 //
1793 Node = CreateResourceNode (
1794 PciDev,
1795 0x100,
1796 0xff,
1797 3,
1798 PciBarTypeIo16,
1799 PciResUsagePadding
1800 );
1801
1802 InsertResourceNode (
1803 IoNode,
1804 Node
1805 );
1806
1807 //
1808 // Io Base/Limit
1809 // Bar 4 denodes io range 0
1810 //
1811 Node = CreateResourceNode (
1812 PciDev,
1813 0x100,
1814 0xff,
1815 4,
1816 PciBarTypeIo16,
1817 PciResUsagePadding
1818 );
1819
1820 InsertResourceNode (
1821 IoNode,
1822 Node
1823 );
1824 }
1825
1826 /**
1827 Program PCI Card device register for given resource node.
1828
1829 @param Base Base address of PCI Card device to be programmed.
1830 @param Node Given resource node.
1831
1832 **/
1833 VOID
1834 ProgramP2C (
1835 IN UINT64 Base,
1836 IN PCI_RESOURCE_NODE *Node
1837 )
1838 {
1839 EFI_PCI_IO_PROTOCOL *PciIo;
1840 UINT64 Address;
1841 UINT64 TempAddress;
1842 UINT16 BridgeControl;
1843
1844 Address = 0;
1845 PciIo = &(Node->PciDev->PciIo);
1846
1847 Address = Base + Node->Offset;
1848
1849 //
1850 // Indicate pci bus driver has allocated
1851 // resource for this device
1852 // It might be a temporary solution here since
1853 // pci device could have multiple bar
1854 //
1855 Node->PciDev->Allocated = TRUE;
1856
1857 switch (Node->Bar) {
1858
1859 case P2C_BAR_0:
1860 PciIo->Pci.Write (
1861 PciIo,
1862 EfiPciIoWidthUint32,
1863 (Node->PciDev->PciBar[Node->Bar]).Offset,
1864 1,
1865 &Address
1866 );
1867
1868 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1869 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1870 break;
1871
1872 case P2C_MEM_1:
1873 PciIo->Pci.Write (
1874 PciIo,
1875 EfiPciIoWidthUint32,
1876 PCI_CARD_MEMORY_BASE_0,
1877 1,
1878 &Address
1879 );
1880
1881 TempAddress = Address + Node->Length - 1;
1882 PciIo->Pci.Write (
1883 PciIo,
1884 EfiPciIoWidthUint32,
1885 PCI_CARD_MEMORY_LIMIT_0,
1886 1,
1887 &TempAddress
1888 );
1889
1890 if (Node->ResType == PciBarTypeMem32) {
1891 //
1892 // Set non-prefetchable bit
1893 //
1894 PciIo->Pci.Read (
1895 PciIo,
1896 EfiPciIoWidthUint16,
1897 PCI_CARD_BRIDGE_CONTROL,
1898 1,
1899 &BridgeControl
1900 );
1901
1902 BridgeControl &= (UINT16) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
1903 PciIo->Pci.Write (
1904 PciIo,
1905 EfiPciIoWidthUint16,
1906 PCI_CARD_BRIDGE_CONTROL,
1907 1,
1908 &BridgeControl
1909 );
1910
1911 } else {
1912 //
1913 // Set pre-fetchable bit
1914 //
1915 PciIo->Pci.Read (
1916 PciIo,
1917 EfiPciIoWidthUint16,
1918 PCI_CARD_BRIDGE_CONTROL,
1919 1,
1920 &BridgeControl
1921 );
1922
1923 BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
1924 PciIo->Pci.Write (
1925 PciIo,
1926 EfiPciIoWidthUint16,
1927 PCI_CARD_BRIDGE_CONTROL,
1928 1,
1929 &BridgeControl
1930 );
1931 }
1932
1933 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1934 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1935 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
1936
1937 break;
1938
1939 case P2C_MEM_2:
1940 PciIo->Pci.Write (
1941 PciIo,
1942 EfiPciIoWidthUint32,
1943 PCI_CARD_MEMORY_BASE_1,
1944 1,
1945 &Address
1946 );
1947
1948 TempAddress = Address + Node->Length - 1;
1949
1950 PciIo->Pci.Write (
1951 PciIo,
1952 EfiPciIoWidthUint32,
1953 PCI_CARD_MEMORY_LIMIT_1,
1954 1,
1955 &TempAddress
1956 );
1957
1958 if (Node->ResType == PciBarTypeMem32) {
1959
1960 //
1961 // Set non-prefetchable bit
1962 //
1963 PciIo->Pci.Read (
1964 PciIo,
1965 EfiPciIoWidthUint16,
1966 PCI_CARD_BRIDGE_CONTROL,
1967 1,
1968 &BridgeControl
1969 );
1970
1971 BridgeControl &= (UINT16) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE);
1972 PciIo->Pci.Write (
1973 PciIo,
1974 EfiPciIoWidthUint16,
1975 PCI_CARD_BRIDGE_CONTROL,
1976 1,
1977 &BridgeControl
1978 );
1979
1980 } else {
1981
1982 //
1983 // Set pre-fetchable bit
1984 //
1985 PciIo->Pci.Read (
1986 PciIo,
1987 EfiPciIoWidthUint16,
1988 PCI_CARD_BRIDGE_CONTROL,
1989 1,
1990 &BridgeControl
1991 );
1992
1993 BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE;
1994 PciIo->Pci.Write (
1995 PciIo,
1996 EfiPciIoWidthUint16,
1997 PCI_CARD_BRIDGE_CONTROL,
1998 1,
1999 &BridgeControl
2000 );
2001 }
2002
2003 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2004 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2005 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2006 break;
2007
2008 case P2C_IO_1:
2009 PciIo->Pci.Write (
2010 PciIo,
2011 EfiPciIoWidthUint32,
2012 PCI_CARD_IO_BASE_0_LOWER,
2013 1,
2014 &Address
2015 );
2016
2017 TempAddress = Address + Node->Length - 1;
2018 PciIo->Pci.Write (
2019 PciIo,
2020 EfiPciIoWidthUint32,
2021 PCI_CARD_IO_LIMIT_0_LOWER,
2022 1,
2023 &TempAddress
2024 );
2025
2026 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2027 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2028 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2029
2030 break;
2031
2032 case P2C_IO_2:
2033 PciIo->Pci.Write (
2034 PciIo,
2035 EfiPciIoWidthUint32,
2036 PCI_CARD_IO_BASE_1_LOWER,
2037 1,
2038 &Address
2039 );
2040
2041 TempAddress = Address + Node->Length - 1;
2042 PciIo->Pci.Write (
2043 PciIo,
2044 EfiPciIoWidthUint32,
2045 PCI_CARD_IO_LIMIT_1_LOWER,
2046 1,
2047 &TempAddress
2048 );
2049
2050 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2051 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2052 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2053 break;
2054
2055 default:
2056 break;
2057 }
2058 }
2059
2060 /**
2061 Create padding resource node.
2062
2063 @param PciDev Pci device instance.
2064 @param IoNode Resource info node for IO.
2065 @param Mem32Node Resource info node for 32-bit memory.
2066 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
2067 @param Mem64Node Resource info node for 64-bit memory.
2068 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
2069
2070 **/
2071 VOID
2072 ApplyResourcePadding (
2073 IN PCI_IO_DEVICE *PciDev,
2074 IN PCI_RESOURCE_NODE *IoNode,
2075 IN PCI_RESOURCE_NODE *Mem32Node,
2076 IN PCI_RESOURCE_NODE *PMem32Node,
2077 IN PCI_RESOURCE_NODE *Mem64Node,
2078 IN PCI_RESOURCE_NODE *PMem64Node
2079 )
2080 {
2081 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
2082 PCI_RESOURCE_NODE *Node;
2083 UINT8 DummyBarIndex;
2084
2085 DummyBarIndex = 0;
2086 Ptr = PciDev->ResourcePaddingDescriptors;
2087
2088 while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {
2089
2090 if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
2091 if (Ptr->AddrLen != 0) {
2092
2093 Node = CreateResourceNode (
2094 PciDev,
2095 Ptr->AddrLen,
2096 Ptr->AddrRangeMax,
2097 DummyBarIndex,
2098 PciBarTypeIo16,
2099 PciResUsagePadding
2100 );
2101 InsertResourceNode (
2102 IoNode,
2103 Node
2104 );
2105 }
2106
2107 Ptr++;
2108 continue;
2109 }
2110
2111 if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
2112
2113 if (Ptr->AddrSpaceGranularity == 32) {
2114
2115 //
2116 // prefechable
2117 //
2118 if (Ptr->SpecificFlag == 0x6) {
2119 if (Ptr->AddrLen != 0) {
2120 Node = CreateResourceNode (
2121 PciDev,
2122 Ptr->AddrLen,
2123 Ptr->AddrRangeMax,
2124 DummyBarIndex,
2125 PciBarTypePMem32,
2126 PciResUsagePadding
2127 );
2128 InsertResourceNode (
2129 PMem32Node,
2130 Node
2131 );
2132 }
2133
2134 Ptr++;
2135 continue;
2136 }
2137
2138 //
2139 // Non-prefechable
2140 //
2141 if (Ptr->SpecificFlag == 0) {
2142 if (Ptr->AddrLen != 0) {
2143 Node = CreateResourceNode (
2144 PciDev,
2145 Ptr->AddrLen,
2146 Ptr->AddrRangeMax,
2147 DummyBarIndex,
2148 PciBarTypeMem32,
2149 PciResUsagePadding
2150 );
2151 InsertResourceNode (
2152 Mem32Node,
2153 Node
2154 );
2155 }
2156
2157 Ptr++;
2158 continue;
2159 }
2160 }
2161
2162 if (Ptr->AddrSpaceGranularity == 64) {
2163
2164 //
2165 // prefechable
2166 //
2167 if (Ptr->SpecificFlag == 0x6) {
2168 if (Ptr->AddrLen != 0) {
2169 Node = CreateResourceNode (
2170 PciDev,
2171 Ptr->AddrLen,
2172 Ptr->AddrRangeMax,
2173 DummyBarIndex,
2174 PciBarTypePMem64,
2175 PciResUsagePadding
2176 );
2177 InsertResourceNode (
2178 PMem64Node,
2179 Node
2180 );
2181 }
2182
2183 Ptr++;
2184 continue;
2185 }
2186
2187 //
2188 // Non-prefechable
2189 //
2190 if (Ptr->SpecificFlag == 0) {
2191 if (Ptr->AddrLen != 0) {
2192 Node = CreateResourceNode (
2193 PciDev,
2194 Ptr->AddrLen,
2195 Ptr->AddrRangeMax,
2196 DummyBarIndex,
2197 PciBarTypeMem64,
2198 PciResUsagePadding
2199 );
2200 InsertResourceNode (
2201 Mem64Node,
2202 Node
2203 );
2204 }
2205
2206 Ptr++;
2207 continue;
2208 }
2209 }
2210 }
2211
2212 Ptr++;
2213 }
2214 }
2215
2216 /**
2217 Get padding resource for PCI-PCI bridge.
2218
2219 @param PciIoDevice PCI-PCI bridge device instance.
2220
2221 @note Feature flag PcdPciBusHotplugDeviceSupport determines
2222 whether need to pad resource for them.
2223 **/
2224 VOID
2225 GetResourcePaddingPpb (
2226 IN PCI_IO_DEVICE *PciIoDevice
2227 )
2228 {
2229 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
2230 if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
2231 GetResourcePaddingForHpb (PciIoDevice);
2232 }
2233 }
2234 }
2235