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