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