]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c
Update resource degrade algorithm in PCI bus driver. (1)If any child device has both...
[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
5 All rights reserved. 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 *CurrentLink;
1052 PCI_RESOURCE_NODE *TempNode;
1053
1054 //
1055 // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64
1056 // requests in case that if a legacy option ROM image can not access 64-bit resources.
1057 //
1058 CurrentLink = Bridge->ChildList.ForwardLink;
1059 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
1060 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1061 if (Temp->RomSize != 0) {
1062 if (!IsListEmpty (&Mem64Node->ChildList)) {
1063 CurrentLink = Mem64Node->ChildList.ForwardLink;
1064 while (CurrentLink != &Mem64Node->ChildList) {
1065 TempNode = RESOURCE_NODE_FROM_LINK (CurrentLink);
1066
1067 if (TempNode->PciDev == Temp) {
1068 RemoveEntryList (CurrentLink);
1069 InsertResourceNode (Mem32Node, TempNode);
1070 }
1071 CurrentLink = TempNode->Link.ForwardLink;
1072 }
1073 }
1074
1075 if (!IsListEmpty (&PMem64Node->ChildList)) {
1076 CurrentLink = PMem64Node->ChildList.ForwardLink;
1077 while (CurrentLink != &PMem64Node->ChildList) {
1078 TempNode = RESOURCE_NODE_FROM_LINK (CurrentLink);
1079
1080 if (TempNode->PciDev == Temp) {
1081 RemoveEntryList (CurrentLink);
1082 InsertResourceNode (PMem32Node, TempNode);
1083 }
1084 CurrentLink = TempNode->Link.ForwardLink;
1085 }
1086 }
1087
1088 }
1089 CurrentLink = CurrentLink->ForwardLink;
1090 }
1091
1092 //
1093 // If firmware is in 32-bit mode,
1094 // then degrade PMEM64/MEM64 requests
1095 //
1096 if (sizeof (UINTN) <= 4) {
1097 MergeResourceTree (
1098 Mem32Node,
1099 Mem64Node,
1100 TRUE
1101 );
1102
1103 MergeResourceTree (
1104 PMem32Node,
1105 PMem64Node,
1106 TRUE
1107 );
1108 } else {
1109 //
1110 // if the bridge does not support MEM64, degrade MEM64 to MEM32
1111 //
1112 if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
1113 MergeResourceTree (
1114 Mem32Node,
1115 Mem64Node,
1116 TRUE
1117 );
1118 }
1119
1120 //
1121 // if the bridge does not support PMEM64, degrade PMEM64 to PMEM32
1122 //
1123 if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
1124 MergeResourceTree (
1125 PMem32Node,
1126 PMem64Node,
1127 TRUE
1128 );
1129 }
1130
1131 //
1132 // if both PMEM64 and PMEM32 requests from child devices, which can not be satisfied
1133 // by a P2P bridge simultaneously, keep PMEM64 and degrade PMEM32 to MEM32.
1134 //
1135 if (!IsListEmpty (&PMem64Node->ChildList) && Bridge->Parent != NULL) {
1136 MergeResourceTree (
1137 Mem32Node,
1138 PMem32Node,
1139 TRUE
1140 );
1141 }
1142 }
1143
1144 //
1145 // If bridge doesn't support Pmem32
1146 // degrade it to mem32
1147 //
1148 if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
1149 MergeResourceTree (
1150 Mem32Node,
1151 PMem32Node,
1152 TRUE
1153 );
1154 }
1155
1156 //
1157 // if root bridge supports combined Pmem Mem decoding
1158 // merge these two type of resource
1159 //
1160 if (BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {
1161 MergeResourceTree (
1162 Mem32Node,
1163 PMem32Node,
1164 FALSE
1165 );
1166
1167 //
1168 // No need to check if to degrade MEM64 after merge, because
1169 // if there are PMEM64 still here, 64-bit decode should be supported
1170 // by the root bride.
1171 //
1172 MergeResourceTree (
1173 Mem64Node,
1174 PMem64Node,
1175 FALSE
1176 );
1177 }
1178 }
1179
1180 /**
1181 Test whether bridge device support decode resource.
1182
1183 @param Bridge Bridge device instance.
1184 @param Decode Decode type according to resource type.
1185
1186 @return TRUE The bridge device support decode resource.
1187 @return FALSE The bridge device don't support decode resource.
1188
1189 **/
1190 BOOLEAN
1191 BridgeSupportResourceDecode (
1192 IN PCI_IO_DEVICE *Bridge,
1193 IN UINT32 Decode
1194 )
1195 {
1196 if (((Bridge->Decodes) & Decode) != 0) {
1197 return TRUE;
1198 }
1199
1200 return FALSE;
1201 }
1202
1203 /**
1204 This function is used to program the resource allocated
1205 for each resource node under specified bridge.
1206
1207 @param Base Base address of resource to be progammed.
1208 @param Bridge PCI resource node for the bridge device.
1209
1210 @retval EFI_SUCCESS Successfully to program all resouces
1211 on given PCI bridge device.
1212 @retval EFI_OUT_OF_RESOURCES Base is all one.
1213
1214 **/
1215 EFI_STATUS
1216 ProgramResource (
1217 IN UINT64 Base,
1218 IN PCI_RESOURCE_NODE *Bridge
1219 )
1220 {
1221 LIST_ENTRY *CurrentLink;
1222 PCI_RESOURCE_NODE *Node;
1223 EFI_STATUS Status;
1224
1225 if (Base == gAllOne) {
1226 return EFI_OUT_OF_RESOURCES;
1227 }
1228
1229 CurrentLink = Bridge->ChildList.ForwardLink;
1230
1231 while (CurrentLink != &Bridge->ChildList) {
1232
1233 Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
1234
1235 if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {
1236
1237 if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
1238 //
1239 // Program the PCI Card Bus device
1240 //
1241 ProgramP2C (Base, Node);
1242 } else {
1243 //
1244 // Program the PCI device BAR
1245 //
1246 ProgramBar (Base, Node);
1247 }
1248 } else {
1249 //
1250 // Program the PCI devices under this bridge
1251 //
1252 Status = ProgramResource (Base + Node->Offset, Node);
1253 if (EFI_ERROR (Status)) {
1254 return Status;
1255 }
1256
1257 ProgramPpbApperture (Base, Node);
1258 }
1259
1260 CurrentLink = CurrentLink->ForwardLink;
1261 }
1262
1263 return EFI_SUCCESS;
1264 }
1265
1266 /**
1267 Program Bar register for PCI device.
1268
1269 @param Base Base address for PCI device resource to be progammed.
1270 @param Node Point to resoure node structure.
1271
1272 **/
1273 VOID
1274 ProgramBar (
1275 IN UINT64 Base,
1276 IN PCI_RESOURCE_NODE *Node
1277 )
1278 {
1279 EFI_PCI_IO_PROTOCOL *PciIo;
1280 UINT64 Address;
1281 UINT32 Address32;
1282
1283 ASSERT (Node->Bar < PCI_MAX_BAR);
1284
1285 //
1286 // Check VF BAR
1287 //
1288 if (Node->Virtual) {
1289 ProgramVfBar (Base, Node);
1290 }
1291
1292 Address = 0;
1293 PciIo = &(Node->PciDev->PciIo);
1294
1295 Address = Base + Node->Offset;
1296
1297 //
1298 // Indicate pci bus driver has allocated
1299 // resource for this device
1300 // It might be a temporary solution here since
1301 // pci device could have multiple bar
1302 //
1303 Node->PciDev->Allocated = TRUE;
1304
1305 switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
1306
1307 case PciBarTypeIo16:
1308 case PciBarTypeIo32:
1309 case PciBarTypeMem32:
1310 case PciBarTypePMem32:
1311
1312 PciIo->Pci.Write (
1313 PciIo,
1314 EfiPciIoWidthUint32,
1315 (Node->PciDev->PciBar[Node->Bar]).Offset,
1316 1,
1317 &Address
1318 );
1319
1320 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1321
1322 break;
1323
1324 case PciBarTypeMem64:
1325 case PciBarTypePMem64:
1326
1327 Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
1328
1329 PciIo->Pci.Write (
1330 PciIo,
1331 EfiPciIoWidthUint32,
1332 (Node->PciDev->PciBar[Node->Bar]).Offset,
1333 1,
1334 &Address32
1335 );
1336
1337 Address32 = (UINT32) RShiftU64 (Address, 32);
1338
1339 PciIo->Pci.Write (
1340 PciIo,
1341 EfiPciIoWidthUint32,
1342 (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
1343 1,
1344 &Address32
1345 );
1346
1347 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1348
1349 break;
1350
1351 default:
1352 break;
1353 }
1354 }
1355
1356 /**
1357 Program IOV VF Bar register for PCI device.
1358
1359 @param Base Base address for PCI device resource to be progammed.
1360 @param Node Point to resoure node structure.
1361
1362 **/
1363 EFI_STATUS
1364 ProgramVfBar (
1365 IN UINT64 Base,
1366 IN PCI_RESOURCE_NODE *Node
1367 )
1368 {
1369 EFI_PCI_IO_PROTOCOL *PciIo;
1370 UINT64 Address;
1371 UINT32 Address32;
1372
1373 ASSERT (Node->Bar < PCI_MAX_BAR);
1374 ASSERT (Node->Virtual);
1375
1376 Address = 0;
1377 PciIo = &(Node->PciDev->PciIo);
1378
1379 Address = Base + Node->Offset;
1380
1381 //
1382 // Indicate pci bus driver has allocated
1383 // resource for this device
1384 // It might be a temporary solution here since
1385 // pci device could have multiple bar
1386 //
1387 Node->PciDev->Allocated = TRUE;
1388
1389 switch ((Node->PciDev->VfPciBar[Node->Bar]).BarType) {
1390
1391 case PciBarTypeMem32:
1392 case PciBarTypePMem32:
1393
1394 PciIo->Pci.Write (
1395 PciIo,
1396 EfiPciIoWidthUint32,
1397 (Node->PciDev->VfPciBar[Node->Bar]).Offset,
1398 1,
1399 &Address
1400 );
1401
1402 Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
1403
1404 DEBUG ((
1405 EFI_D_INFO,
1406 "PCI-IOV B%x.D%x.F%x - VF Bar (Offset - 0x%x) 32Mem (Address - 0x%x)\n",
1407 (UINTN)Node->PciDev->BusNumber,
1408 (UINTN)Node->PciDev->DeviceNumber,
1409 (UINTN)Node->PciDev->FunctionNumber,
1410 (UINTN)(Node->PciDev->VfPciBar[Node->Bar]).Offset,
1411 (UINTN)Address
1412 ));
1413
1414 break;
1415
1416 case PciBarTypeMem64:
1417 case PciBarTypePMem64:
1418
1419 Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
1420
1421 PciIo->Pci.Write (
1422 PciIo,
1423 EfiPciIoWidthUint32,
1424 (Node->PciDev->VfPciBar[Node->Bar]).Offset,
1425 1,
1426 &Address32
1427 );
1428
1429 Address32 = (UINT32) RShiftU64 (Address, 32);
1430
1431 PciIo->Pci.Write (
1432 PciIo,
1433 EfiPciIoWidthUint32,
1434 ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4),
1435 1,
1436 &Address32
1437 );
1438
1439 Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
1440
1441 DEBUG ((
1442 EFI_D_INFO,
1443 "PCI-IOV B%x.D%x.F%x - VF Bar (Offset - 0x%x) 64Mem (Address - 0x%lx)\n",
1444 (UINTN)Node->PciDev->BusNumber,
1445 (UINTN)Node->PciDev->DeviceNumber,
1446 (UINTN)Node->PciDev->FunctionNumber,
1447 (UINTN)(Node->PciDev->VfPciBar[Node->Bar]).Offset,
1448 (UINT64)Address
1449 ));
1450
1451 break;
1452
1453 case PciBarTypeIo16:
1454 case PciBarTypeIo32:
1455 break;
1456
1457 default:
1458 break;
1459 }
1460
1461 return EFI_SUCCESS;
1462 }
1463
1464 /**
1465 Program PCI-PCI bridge apperture.
1466
1467 @param Base Base address for resource.
1468 @param Node Point to resoure node structure.
1469
1470 **/
1471 VOID
1472 ProgramPpbApperture (
1473 IN UINT64 Base,
1474 IN PCI_RESOURCE_NODE *Node
1475 )
1476 {
1477 EFI_PCI_IO_PROTOCOL *PciIo;
1478 UINT64 Address;
1479 UINT32 Address32;
1480
1481 Address = 0;
1482 //
1483 // If no device resource of this PPB, return anyway
1484 // Apperture is set default in the initialization code
1485 //
1486 if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {
1487 //
1488 // For padding resource node, just ignore when programming
1489 //
1490 return ;
1491 }
1492
1493 PciIo = &(Node->PciDev->PciIo);
1494 Address = Base + Node->Offset;
1495
1496 //
1497 // Indicate the PPB resource has been allocated
1498 //
1499 Node->PciDev->Allocated = TRUE;
1500
1501 switch (Node->Bar) {
1502
1503 case PPB_BAR_0:
1504 case PPB_BAR_1:
1505 PciIo->Pci.Write (
1506 PciIo,
1507 EfiPciIoWidthUint32,
1508 (Node->PciDev->PciBar[Node->Bar]).Offset,
1509 1,
1510 &Address
1511 );
1512
1513 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1514 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1515
1516 break;
1517
1518 case PPB_IO_RANGE:
1519
1520 Address32 = ((UINT32) (Address)) >> 8;
1521 PciIo->Pci.Write (
1522 PciIo,
1523 EfiPciIoWidthUint8,
1524 0x1C,
1525 1,
1526 &Address32
1527 );
1528
1529 Address32 >>= 8;
1530 PciIo->Pci.Write (
1531 PciIo,
1532 EfiPciIoWidthUint16,
1533 0x30,
1534 1,
1535 &Address32
1536 );
1537
1538 Address32 = (UINT32) (Address + Node->Length - 1);
1539 Address32 = ((UINT32) (Address32)) >> 8;
1540 PciIo->Pci.Write (
1541 PciIo,
1542 EfiPciIoWidthUint8,
1543 0x1D,
1544 1,
1545 &Address32
1546 );
1547
1548 Address32 >>= 8;
1549 PciIo->Pci.Write (
1550 PciIo,
1551 EfiPciIoWidthUint16,
1552 0x32,
1553 1,
1554 &Address32
1555 );
1556
1557 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1558 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1559 break;
1560
1561 case PPB_MEM32_RANGE:
1562
1563 Address32 = ((UINT32) (Address)) >> 16;
1564 PciIo->Pci.Write (
1565 PciIo,
1566 EfiPciIoWidthUint16,
1567 0x20,
1568 1,
1569 &Address32
1570 );
1571
1572 Address32 = (UINT32) (Address + Node->Length - 1);
1573 Address32 = ((UINT32) (Address32)) >> 16;
1574 PciIo->Pci.Write (
1575 PciIo,
1576 EfiPciIoWidthUint16,
1577 0x22,
1578 1,
1579 &Address32
1580 );
1581
1582 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1583 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1584 break;
1585
1586 case PPB_PMEM32_RANGE:
1587 case PPB_PMEM64_RANGE:
1588
1589 Address32 = ((UINT32) (Address)) >> 16;
1590 PciIo->Pci.Write (
1591 PciIo,
1592 EfiPciIoWidthUint16,
1593 0x24,
1594 1,
1595 &Address32
1596 );
1597
1598 Address32 = (UINT32) (Address + Node->Length - 1);
1599 Address32 = ((UINT32) (Address32)) >> 16;
1600 PciIo->Pci.Write (
1601 PciIo,
1602 EfiPciIoWidthUint16,
1603 0x26,
1604 1,
1605 &Address32
1606 );
1607
1608 Address32 = (UINT32) RShiftU64 (Address, 32);
1609 PciIo->Pci.Write (
1610 PciIo,
1611 EfiPciIoWidthUint32,
1612 0x28,
1613 1,
1614 &Address32
1615 );
1616
1617 Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);
1618 PciIo->Pci.Write (
1619 PciIo,
1620 EfiPciIoWidthUint32,
1621 0x2C,
1622 1,
1623 &Address32
1624 );
1625
1626 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
1627 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
1628 break;
1629
1630 default:
1631 break;
1632 }
1633 }
1634
1635 /**
1636 Program parent bridge for Option Rom.
1637
1638 @param PciDevice Pci deivce instance.
1639 @param OptionRomBase Base address for Optiona Rom.
1640 @param Enable Enable or disable PCI memory.
1641
1642 **/
1643 VOID
1644 ProgrameUpstreamBridgeForRom (
1645 IN PCI_IO_DEVICE *PciDevice,
1646 IN UINT32 OptionRomBase,
1647 IN BOOLEAN Enable
1648 )
1649 {
1650 PCI_IO_DEVICE *Parent;
1651 PCI_RESOURCE_NODE Node;
1652 //
1653 // For root bridge, just return.
1654 //
1655 Parent = PciDevice->Parent;
1656 ZeroMem (&Node, sizeof (Node));
1657 while (Parent != NULL) {
1658 if (!IS_PCI_BRIDGE (&Parent->Pci)) {
1659 break;
1660 }
1661
1662 Node.PciDev = Parent;
1663 Node.Length = PciDevice->RomSize;
1664 Node.Alignment = 0;
1665 Node.Bar = PPB_MEM32_RANGE;
1666 Node.ResType = PciBarTypeMem32;
1667 Node.Offset = 0;
1668
1669 //
1670 // Program PPB to only open a single <= 16MB apperture
1671 //
1672 if (Enable) {
1673 ProgramPpbApperture (OptionRomBase, &Node);
1674 PCI_ENABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
1675 } else {
1676 InitializePpb (Parent);
1677 PCI_DISABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
1678 }
1679
1680 Parent = Parent->Parent;
1681 }
1682 }
1683
1684 /**
1685 Test whether resource exists for a bridge.
1686
1687 @param Bridge Point to resource node for a bridge.
1688
1689 @retval TRUE There is resource on the given bridge.
1690 @retval FALSE There isn't resource on the given bridge.
1691
1692 **/
1693 BOOLEAN
1694 ResourceRequestExisted (
1695 IN PCI_RESOURCE_NODE *Bridge
1696 )
1697 {
1698 if (Bridge != NULL) {
1699 if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {
1700 return TRUE;
1701 }
1702 }
1703
1704 return FALSE;
1705 }
1706
1707 /**
1708 Initialize resource pool structure.
1709
1710 @param ResourcePool Point to resource pool structure. This pool
1711 is reset to all zero when returned.
1712 @param ResourceType Type of resource.
1713
1714 **/
1715 VOID
1716 InitializeResourcePool (
1717 IN OUT PCI_RESOURCE_NODE *ResourcePool,
1718 IN PCI_BAR_TYPE ResourceType
1719 )
1720 {
1721 ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
1722 ResourcePool->ResType = ResourceType;
1723 ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
1724 InitializeListHead (&ResourcePool->ChildList);
1725 }
1726
1727
1728 /**
1729 Get all resource information for given Pci device.
1730
1731 @param PciDev Pci device instance.
1732 @param IoBridge Io resource node.
1733 @param Mem32Bridge 32-bit memory node.
1734 @param PMem32Bridge 32-bit Pmemory node.
1735 @param Mem64Bridge 64-bit memory node.
1736 @param PMem64Bridge 64-bit PMemory node.
1737 @param IoPool Link list header for Io resource.
1738 @param Mem32Pool Link list header for 32-bit memory.
1739 @param PMem32Pool Link list header for 32-bit Prefetchable memory.
1740 @param Mem64Pool Link list header for 64-bit memory.
1741 @param PMem64Pool Link list header for 64-bit Prefetchable memory.
1742
1743 **/
1744 VOID
1745 GetResourceMap (
1746 IN PCI_IO_DEVICE *PciDev,
1747 IN PCI_RESOURCE_NODE **IoBridge,
1748 IN PCI_RESOURCE_NODE **Mem32Bridge,
1749 IN PCI_RESOURCE_NODE **PMem32Bridge,
1750 IN PCI_RESOURCE_NODE **Mem64Bridge,
1751 IN PCI_RESOURCE_NODE **PMem64Bridge,
1752 IN PCI_RESOURCE_NODE *IoPool,
1753 IN PCI_RESOURCE_NODE *Mem32Pool,
1754 IN PCI_RESOURCE_NODE *PMem32Pool,
1755 IN PCI_RESOURCE_NODE *Mem64Pool,
1756 IN PCI_RESOURCE_NODE *PMem64Pool
1757 )
1758 {
1759
1760 PCI_RESOURCE_NODE *Temp;
1761 LIST_ENTRY *CurrentLink;
1762
1763 CurrentLink = IoPool->ChildList.ForwardLink;
1764
1765 //
1766 // Get Io resource map
1767 //
1768 while (CurrentLink != &IoPool->ChildList) {
1769
1770 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1771
1772 if (Temp->PciDev == PciDev) {
1773 *IoBridge = Temp;
1774 }
1775
1776 CurrentLink = CurrentLink->ForwardLink;
1777 }
1778
1779 //
1780 // Get Mem32 resource map
1781 //
1782 CurrentLink = Mem32Pool->ChildList.ForwardLink;
1783
1784 while (CurrentLink != &Mem32Pool->ChildList) {
1785
1786 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1787
1788 if (Temp->PciDev == PciDev) {
1789 *Mem32Bridge = Temp;
1790 }
1791
1792 CurrentLink = CurrentLink->ForwardLink;
1793 }
1794
1795 //
1796 // Get Pmem32 resource map
1797 //
1798 CurrentLink = PMem32Pool->ChildList.ForwardLink;
1799
1800 while (CurrentLink != &PMem32Pool->ChildList) {
1801
1802 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1803
1804 if (Temp->PciDev == PciDev) {
1805 *PMem32Bridge = Temp;
1806 }
1807
1808 CurrentLink = CurrentLink->ForwardLink;
1809 }
1810
1811 //
1812 // Get Mem64 resource map
1813 //
1814 CurrentLink = Mem64Pool->ChildList.ForwardLink;
1815
1816 while (CurrentLink != &Mem64Pool->ChildList) {
1817
1818 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1819
1820 if (Temp->PciDev == PciDev) {
1821 *Mem64Bridge = Temp;
1822 }
1823
1824 CurrentLink = CurrentLink->ForwardLink;
1825 }
1826
1827 //
1828 // Get Pmem64 resource map
1829 //
1830 CurrentLink = PMem64Pool->ChildList.ForwardLink;
1831
1832 while (CurrentLink != &PMem64Pool->ChildList) {
1833
1834 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1835
1836 if (Temp->PciDev == PciDev) {
1837 *PMem64Bridge = Temp;
1838 }
1839
1840 CurrentLink = CurrentLink->ForwardLink;
1841 }
1842 }
1843
1844 /**
1845 Destory given resource tree.
1846
1847 @param Bridge PCI resource root node of resource tree.
1848
1849 **/
1850 VOID
1851 DestroyResourceTree (
1852 IN PCI_RESOURCE_NODE *Bridge
1853 )
1854 {
1855 PCI_RESOURCE_NODE *Temp;
1856 LIST_ENTRY *CurrentLink;
1857
1858 while (!IsListEmpty (&Bridge->ChildList)) {
1859
1860 CurrentLink = Bridge->ChildList.ForwardLink;
1861
1862 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
1863 ASSERT (Temp);
1864
1865 RemoveEntryList (CurrentLink);
1866
1867 if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
1868 DestroyResourceTree (Temp);
1869 }
1870
1871 FreePool (Temp);
1872 }
1873 }
1874
1875 /**
1876 Insert resource padding for P2C.
1877
1878 @param PciDev Pci device instance.
1879 @param IoNode Resource info node for IO.
1880 @param Mem32Node Resource info node for 32-bit memory.
1881 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
1882 @param Mem64Node Resource info node for 64-bit memory.
1883 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
1884
1885 **/
1886 VOID
1887 ResourcePaddingForCardBusBridge (
1888 IN PCI_IO_DEVICE *PciDev,
1889 IN PCI_RESOURCE_NODE *IoNode,
1890 IN PCI_RESOURCE_NODE *Mem32Node,
1891 IN PCI_RESOURCE_NODE *PMem32Node,
1892 IN PCI_RESOURCE_NODE *Mem64Node,
1893 IN PCI_RESOURCE_NODE *PMem64Node
1894 )
1895 {
1896 PCI_RESOURCE_NODE *Node;
1897
1898 Node = NULL;
1899
1900 //
1901 // Memory Base/Limit Register 0
1902 // Bar 1 denodes memory range 0
1903 //
1904 Node = CreateResourceNode (
1905 PciDev,
1906 0x2000000,
1907 0x1ffffff,
1908 1,
1909 PciBarTypeMem32,
1910 PciResUsagePadding
1911 );
1912
1913 InsertResourceNode (
1914 Mem32Node,
1915 Node
1916 );
1917
1918 //
1919 // Memory Base/Limit Register 1
1920 // Bar 2 denodes memory range1
1921 //
1922 Node = CreateResourceNode (
1923 PciDev,
1924 0x2000000,
1925 0x1ffffff,
1926 2,
1927 PciBarTypePMem32,
1928 PciResUsagePadding
1929 );
1930
1931 InsertResourceNode (
1932 PMem32Node,
1933 Node
1934 );
1935
1936 //
1937 // Io Base/Limit
1938 // Bar 3 denodes io range 0
1939 //
1940 Node = CreateResourceNode (
1941 PciDev,
1942 0x100,
1943 0xff,
1944 3,
1945 PciBarTypeIo16,
1946 PciResUsagePadding
1947 );
1948
1949 InsertResourceNode (
1950 IoNode,
1951 Node
1952 );
1953
1954 //
1955 // Io Base/Limit
1956 // Bar 4 denodes io range 0
1957 //
1958 Node = CreateResourceNode (
1959 PciDev,
1960 0x100,
1961 0xff,
1962 4,
1963 PciBarTypeIo16,
1964 PciResUsagePadding
1965 );
1966
1967 InsertResourceNode (
1968 IoNode,
1969 Node
1970 );
1971 }
1972
1973 /**
1974 Program PCI Card device register for given resource node.
1975
1976 @param Base Base address of PCI Card device to be programmed.
1977 @param Node Given resource node.
1978
1979 **/
1980 VOID
1981 ProgramP2C (
1982 IN UINT64 Base,
1983 IN PCI_RESOURCE_NODE *Node
1984 )
1985 {
1986 EFI_PCI_IO_PROTOCOL *PciIo;
1987 UINT64 Address;
1988 UINT64 TempAddress;
1989 UINT16 BridgeControl;
1990
1991 Address = 0;
1992 PciIo = &(Node->PciDev->PciIo);
1993
1994 Address = Base + Node->Offset;
1995
1996 //
1997 // Indicate pci bus driver has allocated
1998 // resource for this device
1999 // It might be a temporary solution here since
2000 // pci device could have multiple bar
2001 //
2002 Node->PciDev->Allocated = TRUE;
2003
2004 switch (Node->Bar) {
2005
2006 case P2C_BAR_0:
2007 PciIo->Pci.Write (
2008 PciIo,
2009 EfiPciIoWidthUint32,
2010 (Node->PciDev->PciBar[Node->Bar]).Offset,
2011 1,
2012 &Address
2013 );
2014
2015 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2016 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2017 break;
2018
2019 case P2C_MEM_1:
2020 PciIo->Pci.Write (
2021 PciIo,
2022 EfiPciIoWidthUint32,
2023 PCI_CARD_MEMORY_BASE_0,
2024 1,
2025 &Address
2026 );
2027
2028 TempAddress = Address + Node->Length - 1;
2029 PciIo->Pci.Write (
2030 PciIo,
2031 EfiPciIoWidthUint32,
2032 PCI_CARD_MEMORY_LIMIT_0,
2033 1,
2034 &TempAddress
2035 );
2036
2037 if (Node->ResType == PciBarTypeMem32) {
2038 //
2039 // Set non-prefetchable bit
2040 //
2041 PciIo->Pci.Read (
2042 PciIo,
2043 EfiPciIoWidthUint16,
2044 PCI_CARD_BRIDGE_CONTROL,
2045 1,
2046 &BridgeControl
2047 );
2048
2049 BridgeControl &= (UINT16) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
2050 PciIo->Pci.Write (
2051 PciIo,
2052 EfiPciIoWidthUint16,
2053 PCI_CARD_BRIDGE_CONTROL,
2054 1,
2055 &BridgeControl
2056 );
2057
2058 } else {
2059 //
2060 // Set pre-fetchable bit
2061 //
2062 PciIo->Pci.Read (
2063 PciIo,
2064 EfiPciIoWidthUint16,
2065 PCI_CARD_BRIDGE_CONTROL,
2066 1,
2067 &BridgeControl
2068 );
2069
2070 BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
2071 PciIo->Pci.Write (
2072 PciIo,
2073 EfiPciIoWidthUint16,
2074 PCI_CARD_BRIDGE_CONTROL,
2075 1,
2076 &BridgeControl
2077 );
2078 }
2079
2080 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2081 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2082 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2083
2084 break;
2085
2086 case P2C_MEM_2:
2087 PciIo->Pci.Write (
2088 PciIo,
2089 EfiPciIoWidthUint32,
2090 PCI_CARD_MEMORY_BASE_1,
2091 1,
2092 &Address
2093 );
2094
2095 TempAddress = Address + Node->Length - 1;
2096
2097 PciIo->Pci.Write (
2098 PciIo,
2099 EfiPciIoWidthUint32,
2100 PCI_CARD_MEMORY_LIMIT_1,
2101 1,
2102 &TempAddress
2103 );
2104
2105 if (Node->ResType == PciBarTypeMem32) {
2106
2107 //
2108 // Set non-prefetchable bit
2109 //
2110 PciIo->Pci.Read (
2111 PciIo,
2112 EfiPciIoWidthUint16,
2113 PCI_CARD_BRIDGE_CONTROL,
2114 1,
2115 &BridgeControl
2116 );
2117
2118 BridgeControl &= (UINT16) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE);
2119 PciIo->Pci.Write (
2120 PciIo,
2121 EfiPciIoWidthUint16,
2122 PCI_CARD_BRIDGE_CONTROL,
2123 1,
2124 &BridgeControl
2125 );
2126
2127 } else {
2128
2129 //
2130 // Set pre-fetchable bit
2131 //
2132 PciIo->Pci.Read (
2133 PciIo,
2134 EfiPciIoWidthUint16,
2135 PCI_CARD_BRIDGE_CONTROL,
2136 1,
2137 &BridgeControl
2138 );
2139
2140 BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE;
2141 PciIo->Pci.Write (
2142 PciIo,
2143 EfiPciIoWidthUint16,
2144 PCI_CARD_BRIDGE_CONTROL,
2145 1,
2146 &BridgeControl
2147 );
2148 }
2149
2150 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2151 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2152 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2153 break;
2154
2155 case P2C_IO_1:
2156 PciIo->Pci.Write (
2157 PciIo,
2158 EfiPciIoWidthUint32,
2159 PCI_CARD_IO_BASE_0_LOWER,
2160 1,
2161 &Address
2162 );
2163
2164 TempAddress = Address + Node->Length - 1;
2165 PciIo->Pci.Write (
2166 PciIo,
2167 EfiPciIoWidthUint32,
2168 PCI_CARD_IO_LIMIT_0_LOWER,
2169 1,
2170 &TempAddress
2171 );
2172
2173 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2174 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2175 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2176
2177 break;
2178
2179 case P2C_IO_2:
2180 PciIo->Pci.Write (
2181 PciIo,
2182 EfiPciIoWidthUint32,
2183 PCI_CARD_IO_BASE_1_LOWER,
2184 1,
2185 &Address
2186 );
2187
2188 TempAddress = Address + Node->Length - 1;
2189 PciIo->Pci.Write (
2190 PciIo,
2191 EfiPciIoWidthUint32,
2192 PCI_CARD_IO_LIMIT_1_LOWER,
2193 1,
2194 &TempAddress
2195 );
2196
2197 Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
2198 Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
2199 Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
2200 break;
2201
2202 default:
2203 break;
2204 }
2205 }
2206
2207 /**
2208 Create padding resource node.
2209
2210 @param PciDev Pci device instance.
2211 @param IoNode Resource info node for IO.
2212 @param Mem32Node Resource info node for 32-bit memory.
2213 @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
2214 @param Mem64Node Resource info node for 64-bit memory.
2215 @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
2216
2217 **/
2218 VOID
2219 ApplyResourcePadding (
2220 IN PCI_IO_DEVICE *PciDev,
2221 IN PCI_RESOURCE_NODE *IoNode,
2222 IN PCI_RESOURCE_NODE *Mem32Node,
2223 IN PCI_RESOURCE_NODE *PMem32Node,
2224 IN PCI_RESOURCE_NODE *Mem64Node,
2225 IN PCI_RESOURCE_NODE *PMem64Node
2226 )
2227 {
2228 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
2229 PCI_RESOURCE_NODE *Node;
2230 UINT8 DummyBarIndex;
2231
2232 DummyBarIndex = 0;
2233 Ptr = PciDev->ResourcePaddingDescriptors;
2234
2235 while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {
2236
2237 if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
2238 if (Ptr->AddrLen != 0) {
2239
2240 Node = CreateResourceNode (
2241 PciDev,
2242 Ptr->AddrLen,
2243 Ptr->AddrRangeMax,
2244 DummyBarIndex,
2245 PciBarTypeIo16,
2246 PciResUsagePadding
2247 );
2248 InsertResourceNode (
2249 IoNode,
2250 Node
2251 );
2252 }
2253
2254 Ptr++;
2255 continue;
2256 }
2257
2258 if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
2259
2260 if (Ptr->AddrSpaceGranularity == 32) {
2261
2262 //
2263 // prefechable
2264 //
2265 if (Ptr->SpecificFlag == 0x6) {
2266 if (Ptr->AddrLen != 0) {
2267 Node = CreateResourceNode (
2268 PciDev,
2269 Ptr->AddrLen,
2270 Ptr->AddrRangeMax,
2271 DummyBarIndex,
2272 PciBarTypePMem32,
2273 PciResUsagePadding
2274 );
2275 InsertResourceNode (
2276 PMem32Node,
2277 Node
2278 );
2279 }
2280
2281 Ptr++;
2282 continue;
2283 }
2284
2285 //
2286 // Non-prefechable
2287 //
2288 if (Ptr->SpecificFlag == 0) {
2289 if (Ptr->AddrLen != 0) {
2290 Node = CreateResourceNode (
2291 PciDev,
2292 Ptr->AddrLen,
2293 Ptr->AddrRangeMax,
2294 DummyBarIndex,
2295 PciBarTypeMem32,
2296 PciResUsagePadding
2297 );
2298 InsertResourceNode (
2299 Mem32Node,
2300 Node
2301 );
2302 }
2303
2304 Ptr++;
2305 continue;
2306 }
2307 }
2308
2309 if (Ptr->AddrSpaceGranularity == 64) {
2310
2311 //
2312 // prefechable
2313 //
2314 if (Ptr->SpecificFlag == 0x6) {
2315 if (Ptr->AddrLen != 0) {
2316 Node = CreateResourceNode (
2317 PciDev,
2318 Ptr->AddrLen,
2319 Ptr->AddrRangeMax,
2320 DummyBarIndex,
2321 PciBarTypePMem64,
2322 PciResUsagePadding
2323 );
2324 InsertResourceNode (
2325 PMem64Node,
2326 Node
2327 );
2328 }
2329
2330 Ptr++;
2331 continue;
2332 }
2333
2334 //
2335 // Non-prefechable
2336 //
2337 if (Ptr->SpecificFlag == 0) {
2338 if (Ptr->AddrLen != 0) {
2339 Node = CreateResourceNode (
2340 PciDev,
2341 Ptr->AddrLen,
2342 Ptr->AddrRangeMax,
2343 DummyBarIndex,
2344 PciBarTypeMem64,
2345 PciResUsagePadding
2346 );
2347 InsertResourceNode (
2348 Mem64Node,
2349 Node
2350 );
2351 }
2352
2353 Ptr++;
2354 continue;
2355 }
2356 }
2357 }
2358
2359 Ptr++;
2360 }
2361 }
2362
2363 /**
2364 Get padding resource for PCI-PCI bridge.
2365
2366 @param PciIoDevice PCI-PCI bridge device instance.
2367
2368 @note Feature flag PcdPciBusHotplugDeviceSupport determines
2369 whether need to pad resource for them.
2370 **/
2371 VOID
2372 GetResourcePaddingPpb (
2373 IN PCI_IO_DEVICE *PciIoDevice
2374 )
2375 {
2376 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
2377 if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
2378 GetResourcePaddingForHpb (PciIoDevice);
2379 }
2380 }
2381 }
2382