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