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