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