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