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