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