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