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