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