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