1 /** @file 2 Supporting functions implementaion for PCI devices management. 3 4 Copyright (c) 2006 - 2015, 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 // This device structure is serviced as a header. 19 // Its next field points to the first root bridge device node. 20 // 21 LIST_ENTRY mPciDevicePool; 22 23 /** 24 Initialize the PCI devices pool. 25 26 **/ 27 VOID 28 InitializePciDevicePool ( 29 VOID 30 ) 31 { 32 InitializeListHead (&mPciDevicePool); 33 } 34 35 /** 36 Insert a root bridge into PCI device pool. 37 38 @param RootBridge A pointer to the PCI_IO_DEVICE. 39 40 **/ 41 VOID 42 InsertRootBridge ( 43 IN PCI_IO_DEVICE *RootBridge 44 ) 45 { 46 InsertTailList (&mPciDevicePool, &(RootBridge->Link)); 47 } 48 49 /** 50 This function is used to insert a PCI device node under 51 a bridge. 52 53 @param Bridge The PCI bridge. 54 @param PciDeviceNode The PCI device needs inserting. 55 56 **/ 57 VOID 58 InsertPciDevice ( 59 IN PCI_IO_DEVICE *Bridge, 60 IN PCI_IO_DEVICE *PciDeviceNode 61 ) 62 { 63 InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link)); 64 PciDeviceNode->Parent = Bridge; 65 } 66 67 /** 68 Destroy root bridge and remove it from deivce tree. 69 70 @param RootBridge The bridge want to be removed. 71 72 **/ 73 VOID 74 DestroyRootBridge ( 75 IN PCI_IO_DEVICE *RootBridge 76 ) 77 { 78 DestroyPciDeviceTree (RootBridge); 79 80 FreePciDevice (RootBridge); 81 } 82 83 /** 84 Destroy a pci device node. 85 86 All direct or indirect allocated resource for this node will be freed. 87 88 @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried. 89 90 **/ 91 VOID 92 FreePciDevice ( 93 IN PCI_IO_DEVICE *PciIoDevice 94 ) 95 { 96 ASSERT (PciIoDevice != NULL); 97 // 98 // Assume all children have been removed underneath this device 99 // 100 if (PciIoDevice->ResourcePaddingDescriptors != NULL) { 101 FreePool (PciIoDevice->ResourcePaddingDescriptors); 102 } 103 104 if (PciIoDevice->DevicePath != NULL) { 105 FreePool (PciIoDevice->DevicePath); 106 } 107 108 FreePool (PciIoDevice); 109 } 110 111 /** 112 Destroy all the pci device node under the bridge. 113 Bridge itself is not included. 114 115 @param Bridge A pointer to the PCI_IO_DEVICE. 116 117 **/ 118 VOID 119 DestroyPciDeviceTree ( 120 IN PCI_IO_DEVICE *Bridge 121 ) 122 { 123 LIST_ENTRY *CurrentLink; 124 PCI_IO_DEVICE *Temp; 125 126 while (!IsListEmpty (&Bridge->ChildList)) { 127 128 CurrentLink = Bridge->ChildList.ForwardLink; 129 130 // 131 // Remove this node from the linked list 132 // 133 RemoveEntryList (CurrentLink); 134 135 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 136 137 if (!IsListEmpty (&Temp->ChildList)) { 138 DestroyPciDeviceTree (Temp); 139 } 140 141 FreePciDevice (Temp); 142 } 143 } 144 145 /** 146 Destroy all device nodes under the root bridge 147 specified by Controller. 148 149 The root bridge itself is also included. 150 151 @param Controller Root bridge handle. 152 153 @retval EFI_SUCCESS Destory all devcie nodes successfully. 154 @retval EFI_NOT_FOUND Cannot find any PCI device under specified 155 root bridge. 156 157 **/ 158 EFI_STATUS 159 DestroyRootBridgeByHandle ( 160 IN EFI_HANDLE Controller 161 ) 162 { 163 164 LIST_ENTRY *CurrentLink; 165 PCI_IO_DEVICE *Temp; 166 167 CurrentLink = mPciDevicePool.ForwardLink; 168 169 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { 170 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 171 172 if (Temp->Handle == Controller) { 173 174 RemoveEntryList (CurrentLink); 175 176 DestroyPciDeviceTree (Temp); 177 178 FreePciDevice (Temp); 179 180 return EFI_SUCCESS; 181 } 182 183 CurrentLink = CurrentLink->ForwardLink; 184 } 185 186 return EFI_NOT_FOUND; 187 } 188 189 /** 190 This function registers the PCI IO device. 191 192 It creates a handle for this PCI IO device (if the handle does not exist), attaches 193 appropriate protocols onto the handle, does necessary initialization, and sets up 194 parent/child relationship with its bus controller. 195 196 @param Controller An EFI handle for the PCI bus controller. 197 @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered. 198 @param Handle A pointer to hold the returned EFI handle for the PCI IO device. 199 200 @retval EFI_SUCCESS The PCI device is successfully registered. 201 @retval other An error occurred when registering the PCI device. 202 203 **/ 204 EFI_STATUS 205 RegisterPciDevice ( 206 IN EFI_HANDLE Controller, 207 IN PCI_IO_DEVICE *PciIoDevice, 208 OUT EFI_HANDLE *Handle OPTIONAL 209 ) 210 { 211 EFI_STATUS Status; 212 VOID *PlatformOpRomBuffer; 213 UINTN PlatformOpRomSize; 214 UINT8 PciExpressCapRegOffset; 215 EFI_PCI_IO_PROTOCOL *PciIo; 216 UINT8 Data8; 217 BOOLEAN HasEfiImage; 218 219 // 220 // Install the pciio protocol, device path protocol 221 // 222 Status = gBS->InstallMultipleProtocolInterfaces ( 223 &PciIoDevice->Handle, 224 &gEfiDevicePathProtocolGuid, 225 PciIoDevice->DevicePath, 226 &gEfiPciIoProtocolGuid, 227 &PciIoDevice->PciIo, 228 NULL 229 ); 230 if (EFI_ERROR (Status)) { 231 return Status; 232 } 233 234 // 235 // Detect if PCI Express Device 236 // 237 PciExpressCapRegOffset = 0; 238 Status = LocateCapabilityRegBlock ( 239 PciIoDevice, 240 EFI_PCI_CAPABILITY_ID_PCIEXP, 241 &PciExpressCapRegOffset, 242 NULL 243 ); 244 if (!EFI_ERROR (Status)) { 245 PciIoDevice->IsPciExp = TRUE; 246 } 247 248 // 249 // Force Interrupt line to "Unknown" or "No Connection" 250 // 251 PciIo = &(PciIoDevice->PciIo); 252 Data8 = PCI_INT_LINE_UNKNOWN; 253 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8); 254 255 // 256 // Process OpRom 257 // 258 if (!PciIoDevice->AllOpRomProcessed) { 259 260 // 261 // Get the OpRom provided by platform 262 // 263 if (gPciPlatformProtocol != NULL) { 264 Status = gPciPlatformProtocol->GetPciRom ( 265 gPciPlatformProtocol, 266 PciIoDevice->Handle, 267 &PlatformOpRomBuffer, 268 &PlatformOpRomSize 269 ); 270 if (!EFI_ERROR (Status)) { 271 PciIoDevice->EmbeddedRom = FALSE; 272 PciIoDevice->RomSize = PlatformOpRomSize; 273 PciIoDevice->PciIo.RomSize = PlatformOpRomSize; 274 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer; 275 // 276 // For OpROM read from gPciPlatformProtocol: 277 // Add the Rom Image to internal database for later PCI light enumeration 278 // 279 PciRomAddImageMapping ( 280 NULL, 281 PciIoDevice->PciRootBridgeIo->SegmentNumber, 282 PciIoDevice->BusNumber, 283 PciIoDevice->DeviceNumber, 284 PciIoDevice->FunctionNumber, 285 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage, 286 PciIoDevice->PciIo.RomSize 287 ); 288 } 289 } else if (gPciOverrideProtocol != NULL) { 290 Status = gPciOverrideProtocol->GetPciRom ( 291 gPciOverrideProtocol, 292 PciIoDevice->Handle, 293 &PlatformOpRomBuffer, 294 &PlatformOpRomSize 295 ); 296 if (!EFI_ERROR (Status)) { 297 PciIoDevice->EmbeddedRom = FALSE; 298 PciIoDevice->RomSize = PlatformOpRomSize; 299 PciIoDevice->PciIo.RomSize = PlatformOpRomSize; 300 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer; 301 // 302 // For OpROM read from gPciOverrideProtocol: 303 // Add the Rom Image to internal database for later PCI light enumeration 304 // 305 PciRomAddImageMapping ( 306 NULL, 307 PciIoDevice->PciRootBridgeIo->SegmentNumber, 308 PciIoDevice->BusNumber, 309 PciIoDevice->DeviceNumber, 310 PciIoDevice->FunctionNumber, 311 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage, 312 PciIoDevice->PciIo.RomSize 313 ); 314 } 315 } 316 } 317 318 // 319 // Determine if there are EFI images in the option rom 320 // 321 HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize); 322 323 if (HasEfiImage) { 324 Status = gBS->InstallMultipleProtocolInterfaces ( 325 &PciIoDevice->Handle, 326 &gEfiLoadFile2ProtocolGuid, 327 &PciIoDevice->LoadFile2, 328 NULL 329 ); 330 if (EFI_ERROR (Status)) { 331 gBS->UninstallMultipleProtocolInterfaces ( 332 &PciIoDevice->Handle, 333 &gEfiDevicePathProtocolGuid, 334 PciIoDevice->DevicePath, 335 &gEfiPciIoProtocolGuid, 336 &PciIoDevice->PciIo, 337 NULL 338 ); 339 return Status; 340 } 341 } 342 343 344 if (!PciIoDevice->AllOpRomProcessed) { 345 346 PciIoDevice->AllOpRomProcessed = TRUE; 347 348 // 349 // Dispatch the EFI OpRom for the PCI device. 350 // The OpRom is got from platform in the above code 351 // or loaded from device in the previous round of bus enumeration 352 // 353 if (HasEfiImage) { 354 ProcessOpRomImage (PciIoDevice); 355 } 356 } 357 358 if (PciIoDevice->BusOverride) { 359 // 360 // Install Bus Specific Driver Override Protocol 361 // 362 Status = gBS->InstallMultipleProtocolInterfaces ( 363 &PciIoDevice->Handle, 364 &gEfiBusSpecificDriverOverrideProtocolGuid, 365 &PciIoDevice->PciDriverOverride, 366 NULL 367 ); 368 if (EFI_ERROR (Status)) { 369 gBS->UninstallMultipleProtocolInterfaces ( 370 &PciIoDevice->Handle, 371 &gEfiDevicePathProtocolGuid, 372 PciIoDevice->DevicePath, 373 &gEfiPciIoProtocolGuid, 374 &PciIoDevice->PciIo, 375 NULL 376 ); 377 if (HasEfiImage) { 378 gBS->UninstallMultipleProtocolInterfaces ( 379 &PciIoDevice->Handle, 380 &gEfiLoadFile2ProtocolGuid, 381 &PciIoDevice->LoadFile2, 382 NULL 383 ); 384 } 385 386 return Status; 387 } 388 } 389 390 Status = gBS->OpenProtocol ( 391 Controller, 392 &gEfiPciRootBridgeIoProtocolGuid, 393 (VOID **) &(PciIoDevice->PciRootBridgeIo), 394 gPciBusDriverBinding.DriverBindingHandle, 395 PciIoDevice->Handle, 396 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 397 ); 398 if (EFI_ERROR (Status)) { 399 return Status; 400 } 401 402 if (Handle != NULL) { 403 *Handle = PciIoDevice->Handle; 404 } 405 406 // 407 // Indicate the pci device is registered 408 // 409 PciIoDevice->Registered = TRUE; 410 411 return EFI_SUCCESS; 412 } 413 414 /** 415 This function is used to remove the whole PCI devices on the specified bridge from 416 the root bridge. 417 418 @param RootBridgeHandle The root bridge device handle. 419 @param Bridge The bridge device to be removed. 420 421 **/ 422 VOID 423 RemoveAllPciDeviceOnBridge ( 424 EFI_HANDLE RootBridgeHandle, 425 PCI_IO_DEVICE *Bridge 426 ) 427 { 428 LIST_ENTRY *CurrentLink; 429 PCI_IO_DEVICE *Temp; 430 431 while (!IsListEmpty (&Bridge->ChildList)) { 432 433 CurrentLink = Bridge->ChildList.ForwardLink; 434 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 435 436 // 437 // Check if the current node has been deregistered before 438 // If it is not, then deregister it 439 // 440 if (Temp->Registered) { 441 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle); 442 } 443 444 // 445 // Remove this node from the linked list 446 // 447 RemoveEntryList (CurrentLink); 448 449 if (!IsListEmpty (&Temp->ChildList)) { 450 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp); 451 } 452 453 FreePciDevice (Temp); 454 } 455 } 456 457 /** 458 This function is used to de-register the PCI IO device. 459 460 That includes un-installing PciIo protocol from the specified PCI 461 device handle. 462 463 @param Controller An EFI handle for the PCI bus controller. 464 @param Handle PCI device handle. 465 466 @retval EFI_SUCCESS The PCI device is successfully de-registered. 467 @retval other An error occurred when de-registering the PCI device. 468 469 **/ 470 EFI_STATUS 471 DeRegisterPciDevice ( 472 IN EFI_HANDLE Controller, 473 IN EFI_HANDLE Handle 474 ) 475 476 { 477 EFI_PCI_IO_PROTOCOL *PciIo; 478 EFI_STATUS Status; 479 PCI_IO_DEVICE *PciIoDevice; 480 PCI_IO_DEVICE *Node; 481 LIST_ENTRY *CurrentLink; 482 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; 483 484 Status = gBS->OpenProtocol ( 485 Handle, 486 &gEfiPciIoProtocolGuid, 487 (VOID **) &PciIo, 488 gPciBusDriverBinding.DriverBindingHandle, 489 Controller, 490 EFI_OPEN_PROTOCOL_GET_PROTOCOL 491 ); 492 if (!EFI_ERROR (Status)) { 493 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); 494 495 // 496 // If it is already de-registered 497 // 498 if (!PciIoDevice->Registered) { 499 return EFI_SUCCESS; 500 } 501 502 // 503 // If it is PPB, first de-register its children 504 // 505 506 if (!IsListEmpty (&PciIoDevice->ChildList)) { 507 508 CurrentLink = PciIoDevice->ChildList.ForwardLink; 509 510 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { 511 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 512 Status = DeRegisterPciDevice (Controller, Node->Handle); 513 514 if (EFI_ERROR (Status)) { 515 return Status; 516 } 517 518 CurrentLink = CurrentLink->ForwardLink; 519 } 520 } 521 522 // 523 // Close the child handle 524 // 525 Status = gBS->CloseProtocol ( 526 Controller, 527 &gEfiPciRootBridgeIoProtocolGuid, 528 gPciBusDriverBinding.DriverBindingHandle, 529 Handle 530 ); 531 532 // 533 // Un-install the Device Path protocol and PCI I/O protocol 534 // and Bus Specific Driver Override protocol if needed. 535 // 536 if (PciIoDevice->BusOverride) { 537 Status = gBS->UninstallMultipleProtocolInterfaces ( 538 Handle, 539 &gEfiDevicePathProtocolGuid, 540 PciIoDevice->DevicePath, 541 &gEfiPciIoProtocolGuid, 542 &PciIoDevice->PciIo, 543 &gEfiBusSpecificDriverOverrideProtocolGuid, 544 &PciIoDevice->PciDriverOverride, 545 NULL 546 ); 547 } else { 548 Status = gBS->UninstallMultipleProtocolInterfaces ( 549 Handle, 550 &gEfiDevicePathProtocolGuid, 551 PciIoDevice->DevicePath, 552 &gEfiPciIoProtocolGuid, 553 &PciIoDevice->PciIo, 554 NULL 555 ); 556 } 557 558 if (!EFI_ERROR (Status)) { 559 // 560 // Try to uninstall LoadFile2 protocol if exists 561 // 562 Status = gBS->OpenProtocol ( 563 Handle, 564 &gEfiLoadFile2ProtocolGuid, 565 NULL, 566 gPciBusDriverBinding.DriverBindingHandle, 567 Controller, 568 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 569 ); 570 if (!EFI_ERROR (Status)) { 571 Status = gBS->UninstallMultipleProtocolInterfaces ( 572 Handle, 573 &gEfiLoadFile2ProtocolGuid, 574 &PciIoDevice->LoadFile2, 575 NULL 576 ); 577 } 578 // 579 // Restore Status 580 // 581 Status = EFI_SUCCESS; 582 } 583 584 585 if (EFI_ERROR (Status)) { 586 gBS->OpenProtocol ( 587 Controller, 588 &gEfiPciRootBridgeIoProtocolGuid, 589 (VOID **) &PciRootBridgeIo, 590 gPciBusDriverBinding.DriverBindingHandle, 591 Handle, 592 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 593 ); 594 return Status; 595 } 596 597 // 598 // The Device Driver should disable this device after disconnect 599 // so the Pci Bus driver will not touch this device any more. 600 // Restore the register field to the original value 601 // 602 PciIoDevice->Registered = FALSE; 603 PciIoDevice->Handle = NULL; 604 } else { 605 606 // 607 // Handle may be closed before 608 // 609 return EFI_SUCCESS; 610 } 611 612 return EFI_SUCCESS; 613 } 614 615 /** 616 Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge. 617 618 @param Controller The root bridge handle. 619 @param RootBridge A pointer to the PCI_IO_DEVICE. 620 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL. 621 @param NumberOfChildren Children number. 622 @param ChildHandleBuffer A pointer to the child handle buffer. 623 624 @retval EFI_NOT_READY Device is not allocated. 625 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge. 626 @retval EFI_NOT_FOUND Can not find the specific device. 627 @retval EFI_SUCCESS Success to start Pci devices on bridge. 628 629 **/ 630 EFI_STATUS 631 StartPciDevicesOnBridge ( 632 IN EFI_HANDLE Controller, 633 IN PCI_IO_DEVICE *RootBridge, 634 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, 635 IN OUT UINT8 *NumberOfChildren, 636 IN OUT EFI_HANDLE *ChildHandleBuffer 637 ) 638 639 { 640 PCI_IO_DEVICE *PciIoDevice; 641 EFI_DEV_PATH_PTR Node; 642 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; 643 EFI_STATUS Status; 644 LIST_ENTRY *CurrentLink; 645 UINT64 Supports; 646 647 PciIoDevice = NULL; 648 CurrentLink = RootBridge->ChildList.ForwardLink; 649 650 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) { 651 652 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 653 if (RemainingDevicePath != NULL) { 654 655 Node.DevPath = RemainingDevicePath; 656 657 if (Node.Pci->Device != PciIoDevice->DeviceNumber || 658 Node.Pci->Function != PciIoDevice->FunctionNumber) { 659 CurrentLink = CurrentLink->ForwardLink; 660 continue; 661 } 662 663 // 664 // Check if the device has been assigned with required resource 665 // 666 if (!PciIoDevice->Allocated) { 667 return EFI_NOT_READY; 668 } 669 670 // 671 // Check if the current node has been registered before 672 // If it is not, register it 673 // 674 if (!PciIoDevice->Registered) { 675 Status = RegisterPciDevice ( 676 Controller, 677 PciIoDevice, 678 NULL 679 ); 680 681 } 682 683 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) { 684 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle; 685 (*NumberOfChildren)++; 686 } 687 688 // 689 // Get the next device path 690 // 691 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath); 692 if (IsDevicePathEnd (CurrentDevicePath)) { 693 return EFI_SUCCESS; 694 } 695 696 // 697 // If it is a PPB 698 // 699 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { 700 Status = StartPciDevicesOnBridge ( 701 Controller, 702 PciIoDevice, 703 CurrentDevicePath, 704 NumberOfChildren, 705 ChildHandleBuffer 706 ); 707 708 PciIoDevice->PciIo.Attributes ( 709 &(PciIoDevice->PciIo), 710 EfiPciIoAttributeOperationSupported, 711 0, 712 &Supports 713 ); 714 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; 715 PciIoDevice->PciIo.Attributes ( 716 &(PciIoDevice->PciIo), 717 EfiPciIoAttributeOperationEnable, 718 Supports, 719 NULL 720 ); 721 722 return Status; 723 } else { 724 725 // 726 // Currently, the PCI bus driver only support PCI-PCI bridge 727 // 728 return EFI_UNSUPPORTED; 729 } 730 731 } else { 732 733 // 734 // If remaining device path is NULL, 735 // try to enable all the pci devices under this bridge 736 // 737 if (!PciIoDevice->Registered && PciIoDevice->Allocated) { 738 Status = RegisterPciDevice ( 739 Controller, 740 PciIoDevice, 741 NULL 742 ); 743 744 } 745 746 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) { 747 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle; 748 (*NumberOfChildren)++; 749 } 750 751 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { 752 Status = StartPciDevicesOnBridge ( 753 Controller, 754 PciIoDevice, 755 RemainingDevicePath, 756 NumberOfChildren, 757 ChildHandleBuffer 758 ); 759 760 PciIoDevice->PciIo.Attributes ( 761 &(PciIoDevice->PciIo), 762 EfiPciIoAttributeOperationSupported, 763 0, 764 &Supports 765 ); 766 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; 767 PciIoDevice->PciIo.Attributes ( 768 &(PciIoDevice->PciIo), 769 EfiPciIoAttributeOperationEnable, 770 Supports, 771 NULL 772 ); 773 774 } 775 776 CurrentLink = CurrentLink->ForwardLink; 777 } 778 } 779 780 if (PciIoDevice == NULL) { 781 return EFI_NOT_FOUND; 782 } else { 783 return EFI_SUCCESS; 784 } 785 } 786 787 /** 788 Start to manage all the PCI devices it found previously under 789 the entire host bridge. 790 791 @param Controller The root bridge handle. 792 793 @retval EFI_NOT_READY Device is not allocated. 794 @retval EFI_SUCCESS Success to start Pci device on host bridge. 795 796 **/ 797 EFI_STATUS 798 StartPciDevices ( 799 IN EFI_HANDLE Controller 800 ) 801 { 802 PCI_IO_DEVICE *RootBridge; 803 EFI_HANDLE ThisHostBridge; 804 LIST_ENTRY *CurrentLink; 805 806 RootBridge = GetRootBridgeByHandle (Controller); 807 ASSERT (RootBridge != NULL); 808 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle; 809 810 CurrentLink = mPciDevicePool.ForwardLink; 811 812 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { 813 814 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 815 // 816 // Locate the right root bridge to start 817 // 818 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) { 819 StartPciDevicesOnBridge ( 820 RootBridge->Handle, 821 RootBridge, 822 NULL, 823 NULL, 824 NULL 825 ); 826 } 827 828 CurrentLink = CurrentLink->ForwardLink; 829 } 830 831 return EFI_SUCCESS; 832 } 833 834 /** 835 Create root bridge device. 836 837 @param RootBridgeHandle Specified root bridge hanle. 838 839 @return The crated root bridge device instance, NULL means no 840 root bridge device instance created. 841 842 **/ 843 PCI_IO_DEVICE * 844 CreateRootBridge ( 845 IN EFI_HANDLE RootBridgeHandle 846 ) 847 { 848 EFI_STATUS Status; 849 PCI_IO_DEVICE *Dev; 850 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 851 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; 852 853 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE)); 854 if (Dev == NULL) { 855 return NULL; 856 } 857 858 Dev->Signature = PCI_IO_DEVICE_SIGNATURE; 859 Dev->Handle = RootBridgeHandle; 860 InitializeListHead (&Dev->ChildList); 861 862 Status = gBS->OpenProtocol ( 863 RootBridgeHandle, 864 &gEfiDevicePathProtocolGuid, 865 (VOID **) &ParentDevicePath, 866 gPciBusDriverBinding.DriverBindingHandle, 867 RootBridgeHandle, 868 EFI_OPEN_PROTOCOL_GET_PROTOCOL 869 ); 870 871 if (EFI_ERROR (Status)) { 872 FreePool (Dev); 873 return NULL; 874 } 875 876 // 877 // Record the root bridge parent device path 878 // 879 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath); 880 881 // 882 // Get the pci root bridge io protocol 883 // 884 Status = gBS->OpenProtocol ( 885 RootBridgeHandle, 886 &gEfiPciRootBridgeIoProtocolGuid, 887 (VOID **) &PciRootBridgeIo, 888 gPciBusDriverBinding.DriverBindingHandle, 889 RootBridgeHandle, 890 EFI_OPEN_PROTOCOL_GET_PROTOCOL 891 ); 892 893 if (EFI_ERROR (Status)) { 894 FreePciDevice (Dev); 895 return NULL; 896 } 897 898 Dev->PciRootBridgeIo = PciRootBridgeIo; 899 900 // 901 // Initialize the PCI I/O instance structure 902 // 903 InitializePciIoInstance (Dev); 904 InitializePciDriverOverrideInstance (Dev); 905 InitializePciLoadFile2 (Dev); 906 907 // 908 // Initialize reserved resource list and 909 // option rom driver list 910 // 911 InitializeListHead (&Dev->ReservedResourceList); 912 InitializeListHead (&Dev->OptionRomDriverList); 913 914 return Dev; 915 } 916 917 /** 918 Get root bridge device instance by specific root bridge handle. 919 920 @param RootBridgeHandle Given root bridge handle. 921 922 @return The root bridge device instance, NULL means no root bridge 923 device instance found. 924 925 **/ 926 PCI_IO_DEVICE * 927 GetRootBridgeByHandle ( 928 EFI_HANDLE RootBridgeHandle 929 ) 930 { 931 PCI_IO_DEVICE *RootBridgeDev; 932 LIST_ENTRY *CurrentLink; 933 934 CurrentLink = mPciDevicePool.ForwardLink; 935 936 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { 937 938 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 939 if (RootBridgeDev->Handle == RootBridgeHandle) { 940 return RootBridgeDev; 941 } 942 943 CurrentLink = CurrentLink->ForwardLink; 944 } 945 946 return NULL; 947 } 948 949 /** 950 Judege whether Pci device existed. 951 952 @param Bridge Parent bridege instance. 953 @param PciIoDevice Device instance. 954 955 @retval TRUE Pci device existed. 956 @retval FALSE Pci device did not exist. 957 958 **/ 959 BOOLEAN 960 PciDeviceExisted ( 961 IN PCI_IO_DEVICE *Bridge, 962 IN PCI_IO_DEVICE *PciIoDevice 963 ) 964 { 965 966 PCI_IO_DEVICE *Temp; 967 LIST_ENTRY *CurrentLink; 968 969 CurrentLink = Bridge->ChildList.ForwardLink; 970 971 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { 972 973 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 974 975 if (Temp == PciIoDevice) { 976 return TRUE; 977 } 978 979 if (!IsListEmpty (&Temp->ChildList)) { 980 if (PciDeviceExisted (Temp, PciIoDevice)) { 981 return TRUE; 982 } 983 } 984 985 CurrentLink = CurrentLink->ForwardLink; 986 } 987 988 return FALSE; 989 } 990 991 /** 992 Get the active VGA device on the same segment. 993 994 @param VgaDevice PCI IO instance for the VGA device. 995 996 @return The active VGA device on the same segment. 997 998 **/ 999 PCI_IO_DEVICE * 1000 ActiveVGADeviceOnTheSameSegment ( 1001 IN PCI_IO_DEVICE *VgaDevice 1002 ) 1003 { 1004 LIST_ENTRY *CurrentLink; 1005 PCI_IO_DEVICE *Temp; 1006 1007 CurrentLink = mPciDevicePool.ForwardLink; 1008 1009 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { 1010 1011 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 1012 1013 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) { 1014 1015 Temp = ActiveVGADeviceOnTheRootBridge (Temp); 1016 1017 if (Temp != NULL) { 1018 return Temp; 1019 } 1020 } 1021 1022 CurrentLink = CurrentLink->ForwardLink; 1023 } 1024 1025 return NULL; 1026 } 1027 1028 /** 1029 Get the active VGA device on the root bridge. 1030 1031 @param RootBridge PCI IO instance for the root bridge. 1032 1033 @return The active VGA device. 1034 1035 **/ 1036 PCI_IO_DEVICE * 1037 ActiveVGADeviceOnTheRootBridge ( 1038 IN PCI_IO_DEVICE *RootBridge 1039 ) 1040 { 1041 LIST_ENTRY *CurrentLink; 1042 PCI_IO_DEVICE *Temp; 1043 1044 CurrentLink = RootBridge->ChildList.ForwardLink; 1045 1046 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) { 1047 1048 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 1049 1050 if (IS_PCI_VGA(&Temp->Pci) && 1051 (Temp->Attributes & 1052 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | 1053 EFI_PCI_IO_ATTRIBUTE_VGA_IO | 1054 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) { 1055 return Temp; 1056 } 1057 1058 if (IS_PCI_BRIDGE (&Temp->Pci)) { 1059 1060 Temp = ActiveVGADeviceOnTheRootBridge (Temp); 1061 1062 if (Temp != NULL) { 1063 return Temp; 1064 } 1065 } 1066 1067 CurrentLink = CurrentLink->ForwardLink; 1068 } 1069 1070 return NULL; 1071 } 1072 1073 1074 /** 1075 Get HPC PCI address according to its device path. 1076 1077 @param RootBridge Root bridege Io instance. 1078 @param RemainingDevicePath Given searching device path. 1079 @param PciAddress Buffer holding searched result. 1080 1081 @retval EFI_SUCCESS PCI address was stored in PciAddress 1082 @retval EFI_NOT_FOUND Can not find the specific device path. 1083 1084 **/ 1085 EFI_STATUS 1086 GetHpcPciAddressFromRootBridge ( 1087 IN PCI_IO_DEVICE *RootBridge, 1088 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, 1089 OUT UINT64 *PciAddress 1090 ) 1091 { 1092 EFI_DEV_PATH_PTR Node; 1093 PCI_IO_DEVICE *Temp; 1094 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; 1095 LIST_ENTRY *CurrentLink; 1096 BOOLEAN MisMatch; 1097 1098 MisMatch = FALSE; 1099 1100 CurrentDevicePath = RemainingDevicePath; 1101 Node.DevPath = CurrentDevicePath; 1102 Temp = NULL; 1103 1104 while (!IsDevicePathEnd (CurrentDevicePath)) { 1105 1106 CurrentLink = RootBridge->ChildList.ForwardLink; 1107 Node.DevPath = CurrentDevicePath; 1108 1109 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) { 1110 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 1111 1112 if (Node.Pci->Device == Temp->DeviceNumber && 1113 Node.Pci->Function == Temp->FunctionNumber) { 1114 RootBridge = Temp; 1115 break; 1116 } 1117 1118 CurrentLink = CurrentLink->ForwardLink; 1119 } 1120 1121 // 1122 // Check if we find the bridge 1123 // 1124 if (CurrentLink == &RootBridge->ChildList) { 1125 1126 MisMatch = TRUE; 1127 break; 1128 1129 } 1130 1131 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath); 1132 } 1133 1134 if (MisMatch) { 1135 1136 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath); 1137 1138 if (IsDevicePathEnd (CurrentDevicePath)) { 1139 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0); 1140 return EFI_SUCCESS; 1141 } 1142 1143 return EFI_NOT_FOUND; 1144 } 1145 1146 if (Temp != NULL) { 1147 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0); 1148 } else { 1149 return EFI_NOT_FOUND; 1150 } 1151 1152 return EFI_SUCCESS; 1153 1154 } 1155 1156