Home | History | Annotate | Download | only in PciBusDxe
      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