/** @file | |
Supporting functions implementation for PCI devices management. | |
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> | |
(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "PciBus.h" | |
// | |
// This device structure is serviced as a header. | |
// Its next field points to the first root bridge device node. | |
// | |
LIST_ENTRY mPciDevicePool; | |
/** | |
Initialize the PCI devices pool. | |
**/ | |
VOID | |
InitializePciDevicePool ( | |
VOID | |
) | |
{ | |
InitializeListHead (&mPciDevicePool); | |
} | |
/** | |
Insert a root bridge into PCI device pool. | |
@param RootBridge A pointer to the PCI_IO_DEVICE. | |
**/ | |
VOID | |
InsertRootBridge ( | |
IN PCI_IO_DEVICE *RootBridge | |
) | |
{ | |
InsertTailList (&mPciDevicePool, &(RootBridge->Link)); | |
} | |
/** | |
This function is used to insert a PCI device node under | |
a bridge. | |
@param Bridge The PCI bridge. | |
@param PciDeviceNode The PCI device needs inserting. | |
**/ | |
VOID | |
InsertPciDevice ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN PCI_IO_DEVICE *PciDeviceNode | |
) | |
{ | |
InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link)); | |
PciDeviceNode->Parent = Bridge; | |
} | |
/** | |
Destroy root bridge and remove it from device tree. | |
@param RootBridge The bridge want to be removed. | |
**/ | |
VOID | |
DestroyRootBridge ( | |
IN PCI_IO_DEVICE *RootBridge | |
) | |
{ | |
DestroyPciDeviceTree (RootBridge); | |
FreePciDevice (RootBridge); | |
} | |
/** | |
Destroy a pci device node. | |
All direct or indirect allocated resource for this node will be freed. | |
@param PciIoDevice A pointer to the PCI_IO_DEVICE to be destroyed. | |
**/ | |
VOID | |
FreePciDevice ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
ASSERT (PciIoDevice != NULL); | |
// | |
// Assume all children have been removed underneath this device | |
// | |
if (PciIoDevice->ResourcePaddingDescriptors != NULL) { | |
FreePool (PciIoDevice->ResourcePaddingDescriptors); | |
} | |
if (PciIoDevice->DevicePath != NULL) { | |
FreePool (PciIoDevice->DevicePath); | |
} | |
if (PciIoDevice->BusNumberRanges != NULL) { | |
FreePool (PciIoDevice->BusNumberRanges); | |
} | |
FreePool (PciIoDevice); | |
} | |
/** | |
Destroy all the pci device node under the bridge. | |
Bridge itself is not included. | |
@param Bridge A pointer to the PCI_IO_DEVICE. | |
**/ | |
VOID | |
DestroyPciDeviceTree ( | |
IN PCI_IO_DEVICE *Bridge | |
) | |
{ | |
LIST_ENTRY *CurrentLink; | |
PCI_IO_DEVICE *Temp; | |
while (!IsListEmpty (&Bridge->ChildList)) { | |
CurrentLink = Bridge->ChildList.ForwardLink; | |
// | |
// Remove this node from the linked list | |
// | |
RemoveEntryList (CurrentLink); | |
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (!IsListEmpty (&Temp->ChildList)) { | |
DestroyPciDeviceTree (Temp); | |
} | |
FreePciDevice (Temp); | |
} | |
} | |
/** | |
Destroy all device nodes under the root bridge | |
specified by Controller. | |
The root bridge itself is also included. | |
@param Controller Root bridge handle. | |
@retval EFI_SUCCESS Destroy all device nodes successfully. | |
@retval EFI_NOT_FOUND Cannot find any PCI device under specified | |
root bridge. | |
**/ | |
EFI_STATUS | |
DestroyRootBridgeByHandle ( | |
IN EFI_HANDLE Controller | |
) | |
{ | |
LIST_ENTRY *CurrentLink; | |
PCI_IO_DEVICE *Temp; | |
CurrentLink = mPciDevicePool.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { | |
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (Temp->Handle == Controller) { | |
RemoveEntryList (CurrentLink); | |
DestroyPciDeviceTree (Temp); | |
FreePciDevice (Temp); | |
return EFI_SUCCESS; | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
This function registers the PCI IO device. | |
It creates a handle for this PCI IO device (if the handle does not exist), attaches | |
appropriate protocols onto the handle, does necessary initialization, and sets up | |
parent/child relationship with its bus controller. | |
@param Controller An EFI handle for the PCI bus controller. | |
@param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered. | |
@param Handle A pointer to hold the returned EFI handle for the PCI IO device. | |
@retval EFI_SUCCESS The PCI device is successfully registered. | |
@retval other An error occurred when registering the PCI device. | |
**/ | |
EFI_STATUS | |
RegisterPciDevice ( | |
IN EFI_HANDLE Controller, | |
IN PCI_IO_DEVICE *PciIoDevice, | |
OUT EFI_HANDLE *Handle OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *PlatformOpRomBuffer; | |
UINTN PlatformOpRomSize; | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
UINT8 Data8; | |
BOOLEAN HasEfiImage; | |
// | |
// Install the pciio protocol, device path protocol | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&PciIoDevice->Handle, | |
&gEfiDevicePathProtocolGuid, | |
PciIoDevice->DevicePath, | |
&gEfiPciIoProtocolGuid, | |
&PciIoDevice->PciIo, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Force Interrupt line to "Unknown" or "No Connection" | |
// | |
PciIo = &(PciIoDevice->PciIo); | |
Data8 = PCI_INT_LINE_UNKNOWN; | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8); | |
// | |
// Process OpRom | |
// | |
if (!PciIoDevice->AllOpRomProcessed) { | |
// | |
// Get the OpRom provided by platform | |
// | |
if (gPciPlatformProtocol != NULL) { | |
Status = gPciPlatformProtocol->GetPciRom ( | |
gPciPlatformProtocol, | |
PciIoDevice->Handle, | |
&PlatformOpRomBuffer, | |
&PlatformOpRomSize | |
); | |
if (!EFI_ERROR (Status)) { | |
PciIoDevice->EmbeddedRom = FALSE; | |
PciIoDevice->RomSize = (UINT32)PlatformOpRomSize; | |
PciIoDevice->PciIo.RomSize = PlatformOpRomSize; | |
PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer; | |
// | |
// For OpROM read from gPciPlatformProtocol: | |
// Add the Rom Image to internal database for later PCI light enumeration | |
// | |
PciRomAddImageMapping ( | |
NULL, | |
PciIoDevice->PciRootBridgeIo->SegmentNumber, | |
PciIoDevice->BusNumber, | |
PciIoDevice->DeviceNumber, | |
PciIoDevice->FunctionNumber, | |
PciIoDevice->PciIo.RomImage, | |
PciIoDevice->PciIo.RomSize | |
); | |
} | |
} else if (gPciOverrideProtocol != NULL) { | |
Status = gPciOverrideProtocol->GetPciRom ( | |
gPciOverrideProtocol, | |
PciIoDevice->Handle, | |
&PlatformOpRomBuffer, | |
&PlatformOpRomSize | |
); | |
if (!EFI_ERROR (Status)) { | |
PciIoDevice->EmbeddedRom = FALSE; | |
PciIoDevice->RomSize = (UINT32)PlatformOpRomSize; | |
PciIoDevice->PciIo.RomSize = PlatformOpRomSize; | |
PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer; | |
// | |
// For OpROM read from gPciOverrideProtocol: | |
// Add the Rom Image to internal database for later PCI light enumeration | |
// | |
PciRomAddImageMapping ( | |
NULL, | |
PciIoDevice->PciRootBridgeIo->SegmentNumber, | |
PciIoDevice->BusNumber, | |
PciIoDevice->DeviceNumber, | |
PciIoDevice->FunctionNumber, | |
PciIoDevice->PciIo.RomImage, | |
PciIoDevice->PciIo.RomSize | |
); | |
} | |
} | |
} | |
// | |
// Determine if there are EFI images in the option rom | |
// | |
HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize); | |
if (HasEfiImage) { | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&PciIoDevice->Handle, | |
&gEfiLoadFile2ProtocolGuid, | |
&PciIoDevice->LoadFile2, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->UninstallMultipleProtocolInterfaces ( | |
PciIoDevice->Handle, | |
&gEfiDevicePathProtocolGuid, | |
PciIoDevice->DevicePath, | |
&gEfiPciIoProtocolGuid, | |
&PciIoDevice->PciIo, | |
NULL | |
); | |
return Status; | |
} | |
} | |
if (!PciIoDevice->AllOpRomProcessed) { | |
PciIoDevice->AllOpRomProcessed = TRUE; | |
// | |
// Dispatch the EFI OpRom for the PCI device. | |
// The OpRom is got from platform in the above code | |
// or loaded from device in the previous round of bus enumeration | |
// | |
if (HasEfiImage) { | |
ProcessOpRomImage (PciIoDevice); | |
} | |
} | |
if (PciIoDevice->BusOverride) { | |
// | |
// Install Bus Specific Driver Override Protocol | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&PciIoDevice->Handle, | |
&gEfiBusSpecificDriverOverrideProtocolGuid, | |
&PciIoDevice->PciDriverOverride, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->UninstallMultipleProtocolInterfaces ( | |
PciIoDevice->Handle, | |
&gEfiDevicePathProtocolGuid, | |
PciIoDevice->DevicePath, | |
&gEfiPciIoProtocolGuid, | |
&PciIoDevice->PciIo, | |
NULL | |
); | |
if (HasEfiImage) { | |
gBS->UninstallMultipleProtocolInterfaces ( | |
PciIoDevice->Handle, | |
&gEfiLoadFile2ProtocolGuid, | |
&PciIoDevice->LoadFile2, | |
NULL | |
); | |
} | |
return Status; | |
} | |
} | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiPciRootBridgeIoProtocolGuid, | |
(VOID **)&(PciIoDevice->PciRootBridgeIo), | |
gPciBusDriverBinding.DriverBindingHandle, | |
PciIoDevice->Handle, | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (Handle != NULL) { | |
*Handle = PciIoDevice->Handle; | |
} | |
// | |
// Indicate the pci device is registered | |
// | |
PciIoDevice->Registered = TRUE; | |
return EFI_SUCCESS; | |
} | |
/** | |
This function is used to remove the whole PCI devices on the specified bridge from | |
the root bridge. | |
@param RootBridgeHandle The root bridge device handle. | |
@param Bridge The bridge device to be removed. | |
**/ | |
VOID | |
RemoveAllPciDeviceOnBridge ( | |
EFI_HANDLE RootBridgeHandle, | |
PCI_IO_DEVICE *Bridge | |
) | |
{ | |
LIST_ENTRY *CurrentLink; | |
PCI_IO_DEVICE *Temp; | |
while (!IsListEmpty (&Bridge->ChildList)) { | |
CurrentLink = Bridge->ChildList.ForwardLink; | |
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
// | |
// Check if the current node has been deregistered before | |
// If it is not, then deregister it | |
// | |
if (Temp->Registered) { | |
DeRegisterPciDevice (RootBridgeHandle, Temp->Handle); | |
} | |
// | |
// Remove this node from the linked list | |
// | |
RemoveEntryList (CurrentLink); | |
if (!IsListEmpty (&Temp->ChildList)) { | |
RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp); | |
} | |
FreePciDevice (Temp); | |
} | |
} | |
/** | |
This function is used to de-register the PCI IO device. | |
That includes un-installing PciIo protocol from the specified PCI | |
device handle. | |
@param Controller An EFI handle for the PCI bus controller. | |
@param Handle PCI device handle. | |
@retval EFI_SUCCESS The PCI device is successfully de-registered. | |
@retval other An error occurred when de-registering the PCI device. | |
**/ | |
EFI_STATUS | |
DeRegisterPciDevice ( | |
IN EFI_HANDLE Controller, | |
IN EFI_HANDLE Handle | |
) | |
{ | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
EFI_STATUS Status; | |
PCI_IO_DEVICE *PciIoDevice; | |
PCI_IO_DEVICE *Node; | |
LIST_ENTRY *CurrentLink; | |
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
Status = gBS->OpenProtocol ( | |
Handle, | |
&gEfiPciIoProtocolGuid, | |
(VOID **)&PciIo, | |
gPciBusDriverBinding.DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (!EFI_ERROR (Status)) { | |
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); | |
// | |
// If it is already de-registered | |
// | |
if (!PciIoDevice->Registered) { | |
return EFI_SUCCESS; | |
} | |
// | |
// If it is PPB, first de-register its children | |
// | |
if (!IsListEmpty (&PciIoDevice->ChildList)) { | |
CurrentLink = PciIoDevice->ChildList.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { | |
Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
Status = DeRegisterPciDevice (Controller, Node->Handle); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
} | |
// | |
// Close the child handle | |
// | |
Status = gBS->CloseProtocol ( | |
Controller, | |
&gEfiPciRootBridgeIoProtocolGuid, | |
gPciBusDriverBinding.DriverBindingHandle, | |
Handle | |
); | |
// | |
// Un-install the Device Path protocol and PCI I/O protocol | |
// and Bus Specific Driver Override protocol if needed. | |
// | |
if (PciIoDevice->BusOverride) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
Handle, | |
&gEfiDevicePathProtocolGuid, | |
PciIoDevice->DevicePath, | |
&gEfiPciIoProtocolGuid, | |
&PciIoDevice->PciIo, | |
&gEfiBusSpecificDriverOverrideProtocolGuid, | |
&PciIoDevice->PciDriverOverride, | |
NULL | |
); | |
} else { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
Handle, | |
&gEfiDevicePathProtocolGuid, | |
PciIoDevice->DevicePath, | |
&gEfiPciIoProtocolGuid, | |
&PciIoDevice->PciIo, | |
NULL | |
); | |
} | |
if (!EFI_ERROR (Status)) { | |
// | |
// Try to uninstall LoadFile2 protocol if exists | |
// | |
Status = gBS->OpenProtocol ( | |
Handle, | |
&gEfiLoadFile2ProtocolGuid, | |
NULL, | |
gPciBusDriverBinding.DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
Handle, | |
&gEfiLoadFile2ProtocolGuid, | |
&PciIoDevice->LoadFile2, | |
NULL | |
); | |
} | |
// | |
// Restore Status | |
// | |
Status = EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
gBS->OpenProtocol ( | |
Controller, | |
&gEfiPciRootBridgeIoProtocolGuid, | |
(VOID **)&PciRootBridgeIo, | |
gPciBusDriverBinding.DriverBindingHandle, | |
Handle, | |
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
); | |
return Status; | |
} | |
// | |
// The Device Driver should disable this device after disconnect | |
// so the Pci Bus driver will not touch this device any more. | |
// Restore the register field to the original value | |
// | |
PciIoDevice->Registered = FALSE; | |
PciIoDevice->Handle = NULL; | |
} else { | |
// | |
// Handle may be closed before | |
// | |
return EFI_SUCCESS; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge. | |
@param Controller The root bridge handle. | |
@param RootBridge A pointer to the PCI_IO_DEVICE. | |
@param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL. | |
@param NumberOfChildren Children number. | |
@param ChildHandleBuffer A pointer to the child handle buffer. | |
@retval EFI_NOT_READY Device is not allocated. | |
@retval EFI_UNSUPPORTED Device only support PCI-PCI bridge. | |
@retval EFI_NOT_FOUND Can not find the specific device. | |
@retval EFI_SUCCESS Success to start Pci devices on bridge. | |
**/ | |
EFI_STATUS | |
StartPciDevicesOnBridge ( | |
IN EFI_HANDLE Controller, | |
IN PCI_IO_DEVICE *RootBridge, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, | |
IN OUT UINT8 *NumberOfChildren, | |
IN OUT EFI_HANDLE *ChildHandleBuffer | |
) | |
{ | |
PCI_IO_DEVICE *PciIoDevice; | |
EFI_DEV_PATH_PTR Node; | |
EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; | |
EFI_STATUS Status; | |
LIST_ENTRY *CurrentLink; | |
UINT64 Supports; | |
PciIoDevice = NULL; | |
CurrentLink = RootBridge->ChildList.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) { | |
PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (RemainingDevicePath != NULL) { | |
Node.DevPath = RemainingDevicePath; | |
if ((Node.Pci->Device != PciIoDevice->DeviceNumber) || | |
(Node.Pci->Function != PciIoDevice->FunctionNumber)) | |
{ | |
CurrentLink = CurrentLink->ForwardLink; | |
continue; | |
} | |
// | |
// Check if the device has been assigned with required resource | |
// | |
if (!PciIoDevice->Allocated) { | |
return EFI_NOT_READY; | |
} | |
// | |
// Check if the current node has been registered before | |
// If it is not, register it | |
// | |
if (!PciIoDevice->Registered) { | |
Status = RegisterPciDevice ( | |
Controller, | |
PciIoDevice, | |
NULL | |
); | |
} | |
if ((NumberOfChildren != NULL) && (ChildHandleBuffer != NULL) && PciIoDevice->Registered) { | |
ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle; | |
(*NumberOfChildren)++; | |
} | |
// | |
// Get the next device path | |
// | |
CurrentDevicePath = NextDevicePathNode (RemainingDevicePath); | |
if (IsDevicePathEnd (CurrentDevicePath)) { | |
return EFI_SUCCESS; | |
} | |
// | |
// If it is a PPB | |
// | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { | |
Status = StartPciDevicesOnBridge ( | |
Controller, | |
PciIoDevice, | |
CurrentDevicePath, | |
NumberOfChildren, | |
ChildHandleBuffer | |
); | |
PciIoDevice->PciIo.Attributes ( | |
&(PciIoDevice->PciIo), | |
EfiPciIoAttributeOperationSupported, | |
0, | |
&Supports | |
); | |
Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; | |
PciIoDevice->PciIo.Attributes ( | |
&(PciIoDevice->PciIo), | |
EfiPciIoAttributeOperationEnable, | |
Supports, | |
NULL | |
); | |
return Status; | |
} else { | |
// | |
// Currently, the PCI bus driver only support PCI-PCI bridge | |
// | |
return EFI_UNSUPPORTED; | |
} | |
} else { | |
// | |
// If remaining device path is NULL, | |
// try to enable all the pci devices under this bridge | |
// | |
if (!PciIoDevice->Registered && PciIoDevice->Allocated) { | |
Status = RegisterPciDevice ( | |
Controller, | |
PciIoDevice, | |
NULL | |
); | |
} | |
if ((NumberOfChildren != NULL) && (ChildHandleBuffer != NULL) && PciIoDevice->Registered) { | |
ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle; | |
(*NumberOfChildren)++; | |
} | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { | |
Status = StartPciDevicesOnBridge ( | |
Controller, | |
PciIoDevice, | |
RemainingDevicePath, | |
NumberOfChildren, | |
ChildHandleBuffer | |
); | |
PciIoDevice->PciIo.Attributes ( | |
&(PciIoDevice->PciIo), | |
EfiPciIoAttributeOperationSupported, | |
0, | |
&Supports | |
); | |
Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; | |
PciIoDevice->PciIo.Attributes ( | |
&(PciIoDevice->PciIo), | |
EfiPciIoAttributeOperationEnable, | |
Supports, | |
NULL | |
); | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
} | |
if (PciIoDevice == NULL) { | |
return EFI_NOT_FOUND; | |
} else { | |
return EFI_SUCCESS; | |
} | |
} | |
/** | |
Start to manage all the PCI devices it found previously under | |
the entire host bridge. | |
@param Controller The root bridge handle. | |
@retval EFI_NOT_READY Device is not allocated. | |
@retval EFI_SUCCESS Success to start Pci device on host bridge. | |
**/ | |
EFI_STATUS | |
StartPciDevices ( | |
IN EFI_HANDLE Controller | |
) | |
{ | |
PCI_IO_DEVICE *RootBridge; | |
EFI_HANDLE ThisHostBridge; | |
LIST_ENTRY *CurrentLink; | |
RootBridge = GetRootBridgeByHandle (Controller); | |
ASSERT (RootBridge != NULL); | |
ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle; | |
CurrentLink = mPciDevicePool.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { | |
RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
// | |
// Locate the right root bridge to start | |
// | |
if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) { | |
StartPciDevicesOnBridge ( | |
RootBridge->Handle, | |
RootBridge, | |
NULL, | |
NULL, | |
NULL | |
); | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Create root bridge device. | |
@param RootBridgeHandle Specified root bridge handle. | |
@return The crated root bridge device instance, NULL means no | |
root bridge device instance created. | |
**/ | |
PCI_IO_DEVICE * | |
CreateRootBridge ( | |
IN EFI_HANDLE RootBridgeHandle | |
) | |
{ | |
EFI_STATUS Status; | |
PCI_IO_DEVICE *Dev; | |
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE)); | |
if (Dev == NULL) { | |
return NULL; | |
} | |
Dev->Signature = PCI_IO_DEVICE_SIGNATURE; | |
Dev->Handle = RootBridgeHandle; | |
InitializeListHead (&Dev->ChildList); | |
Status = gBS->OpenProtocol ( | |
RootBridgeHandle, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **)&ParentDevicePath, | |
gPciBusDriverBinding.DriverBindingHandle, | |
RootBridgeHandle, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (Dev); | |
return NULL; | |
} | |
// | |
// Record the root bridge parent device path | |
// | |
Dev->DevicePath = DuplicateDevicePath (ParentDevicePath); | |
// | |
// Get the pci root bridge io protocol | |
// | |
Status = gBS->OpenProtocol ( | |
RootBridgeHandle, | |
&gEfiPciRootBridgeIoProtocolGuid, | |
(VOID **)&PciRootBridgeIo, | |
gPciBusDriverBinding.DriverBindingHandle, | |
RootBridgeHandle, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
FreePciDevice (Dev); | |
return NULL; | |
} | |
Dev->PciRootBridgeIo = PciRootBridgeIo; | |
// | |
// Initialize the PCI I/O instance structure | |
// | |
InitializePciIoInstance (Dev); | |
InitializePciDriverOverrideInstance (Dev); | |
InitializePciLoadFile2 (Dev); | |
// | |
// Initialize reserved resource list and | |
// option rom driver list | |
// | |
InitializeListHead (&Dev->ReservedResourceList); | |
InitializeListHead (&Dev->OptionRomDriverList); | |
return Dev; | |
} | |
/** | |
Get root bridge device instance by specific root bridge handle. | |
@param RootBridgeHandle Given root bridge handle. | |
@return The root bridge device instance, NULL means no root bridge | |
device instance found. | |
**/ | |
PCI_IO_DEVICE * | |
GetRootBridgeByHandle ( | |
EFI_HANDLE RootBridgeHandle | |
) | |
{ | |
PCI_IO_DEVICE *RootBridgeDev; | |
LIST_ENTRY *CurrentLink; | |
CurrentLink = mPciDevicePool.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { | |
RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (RootBridgeDev->Handle == RootBridgeHandle) { | |
return RootBridgeDev; | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
return NULL; | |
} | |
/** | |
Judge whether Pci device existed. | |
@param Bridge Parent bridge instance. | |
@param PciIoDevice Device instance. | |
@retval TRUE Pci device existed. | |
@retval FALSE Pci device did not exist. | |
**/ | |
BOOLEAN | |
PciDeviceExisted ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
PCI_IO_DEVICE *Temp; | |
LIST_ENTRY *CurrentLink; | |
CurrentLink = Bridge->ChildList.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { | |
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (Temp == PciIoDevice) { | |
return TRUE; | |
} | |
if (!IsListEmpty (&Temp->ChildList)) { | |
if (PciDeviceExisted (Temp, PciIoDevice)) { | |
return TRUE; | |
} | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
return FALSE; | |
} | |
/** | |
Get the active VGA device on the specified Host Bridge. | |
@param HostBridgeHandle Host Bridge handle. | |
@return The active VGA device on the specified Host Bridge. | |
**/ | |
PCI_IO_DEVICE * | |
LocateVgaDeviceOnHostBridge ( | |
IN EFI_HANDLE HostBridgeHandle | |
) | |
{ | |
LIST_ENTRY *CurrentLink; | |
PCI_IO_DEVICE *PciIoDevice; | |
CurrentLink = mPciDevicePool.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { | |
PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (PciIoDevice->PciRootBridgeIo->ParentHandle == HostBridgeHandle) { | |
PciIoDevice = LocateVgaDevice (PciIoDevice); | |
if (PciIoDevice != NULL) { | |
return PciIoDevice; | |
} | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
return NULL; | |
} | |
/** | |
Locate the active VGA device under the bridge. | |
@param Bridge PCI IO instance for the bridge. | |
@return The active VGA device. | |
**/ | |
PCI_IO_DEVICE * | |
LocateVgaDevice ( | |
IN PCI_IO_DEVICE *Bridge | |
) | |
{ | |
LIST_ENTRY *CurrentLink; | |
PCI_IO_DEVICE *PciIoDevice; | |
CurrentLink = Bridge->ChildList.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { | |
PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (IS_PCI_VGA (&PciIoDevice->Pci) && | |
((PciIoDevice->Attributes & | |
(EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | | |
EFI_PCI_IO_ATTRIBUTE_VGA_IO | | |
EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0)) | |
{ | |
return PciIoDevice; | |
} | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { | |
PciIoDevice = LocateVgaDevice (PciIoDevice); | |
if (PciIoDevice != NULL) { | |
return PciIoDevice; | |
} | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
return NULL; | |
} |