mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-27 12:15:19 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
1156 lines
31 KiB
C
1156 lines
31 KiB
C
/** @file
|
|
Supporting functions implementaion for PCI devices management.
|
|
|
|
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#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 deivce 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 destoried.
|
|
|
|
**/
|
|
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);
|
|
}
|
|
|
|
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 Destory all devcie 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;
|
|
UINT8 PciExpressCapRegOffset;
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Detect if PCI Express Device
|
|
//
|
|
PciExpressCapRegOffset = 0;
|
|
Status = LocateCapabilityRegBlock (
|
|
PciIoDevice,
|
|
EFI_PCI_CAPABILITY_ID_PCIEXP,
|
|
&PciExpressCapRegOffset,
|
|
NULL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
PciIoDevice->IsPciExp = TRUE;
|
|
}
|
|
|
|
//
|
|
// 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 = 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,
|
|
(UINT64) (UINTN) 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 = 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,
|
|
(UINT64) (UINTN) 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 &= 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 &= 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 hanle.
|
|
|
|
@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;
|
|
}
|
|
|
|
/**
|
|
Judege whether Pci device existed.
|
|
|
|
@param Bridge Parent bridege 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 same segment.
|
|
|
|
@param VgaDevice PCI IO instance for the VGA device.
|
|
|
|
@return The active VGA device on the same segment.
|
|
|
|
**/
|
|
PCI_IO_DEVICE *
|
|
ActiveVGADeviceOnTheSameSegment (
|
|
IN PCI_IO_DEVICE *VgaDevice
|
|
)
|
|
{
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_IO_DEVICE *Temp;
|
|
|
|
CurrentLink = mPciDevicePool.ForwardLink;
|
|
|
|
while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
|
|
|
|
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
|
|
if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
|
|
|
|
Temp = ActiveVGADeviceOnTheRootBridge (Temp);
|
|
|
|
if (Temp != NULL) {
|
|
return Temp;
|
|
}
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Get the active VGA device on the root bridge.
|
|
|
|
@param RootBridge PCI IO instance for the root bridge.
|
|
|
|
@return The active VGA device.
|
|
|
|
**/
|
|
PCI_IO_DEVICE *
|
|
ActiveVGADeviceOnTheRootBridge (
|
|
IN PCI_IO_DEVICE *RootBridge
|
|
)
|
|
{
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_IO_DEVICE *Temp;
|
|
|
|
CurrentLink = RootBridge->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
|
|
|
|
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
|
|
if (IS_PCI_VGA(&Temp->Pci) &&
|
|
(Temp->Attributes &
|
|
(EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
|
|
EFI_PCI_IO_ATTRIBUTE_VGA_IO |
|
|
EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
|
|
return Temp;
|
|
}
|
|
|
|
if (IS_PCI_BRIDGE (&Temp->Pci)) {
|
|
|
|
Temp = ActiveVGADeviceOnTheRootBridge (Temp);
|
|
|
|
if (Temp != NULL) {
|
|
return Temp;
|
|
}
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
Get HPC PCI address according to its device path.
|
|
|
|
@param RootBridge Root bridege Io instance.
|
|
@param RemainingDevicePath Given searching device path.
|
|
@param PciAddress Buffer holding searched result.
|
|
|
|
@retval EFI_SUCCESS PCI address was stored in PciAddress
|
|
@retval EFI_NOT_FOUND Can not find the specific device path.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetHpcPciAddressFromRootBridge (
|
|
IN PCI_IO_DEVICE *RootBridge,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
|
|
OUT UINT64 *PciAddress
|
|
)
|
|
{
|
|
EFI_DEV_PATH_PTR Node;
|
|
PCI_IO_DEVICE *Temp;
|
|
EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
|
|
LIST_ENTRY *CurrentLink;
|
|
BOOLEAN MisMatch;
|
|
|
|
MisMatch = FALSE;
|
|
|
|
CurrentDevicePath = RemainingDevicePath;
|
|
Node.DevPath = CurrentDevicePath;
|
|
Temp = NULL;
|
|
|
|
while (!IsDevicePathEnd (CurrentDevicePath)) {
|
|
|
|
CurrentLink = RootBridge->ChildList.ForwardLink;
|
|
Node.DevPath = CurrentDevicePath;
|
|
|
|
while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
|
|
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
|
|
if (Node.Pci->Device == Temp->DeviceNumber &&
|
|
Node.Pci->Function == Temp->FunctionNumber) {
|
|
RootBridge = Temp;
|
|
break;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Check if we find the bridge
|
|
//
|
|
if (CurrentLink == &RootBridge->ChildList) {
|
|
|
|
MisMatch = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
|
|
}
|
|
|
|
if (MisMatch) {
|
|
|
|
CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
|
|
|
|
if (IsDevicePathEnd (CurrentDevicePath)) {
|
|
*PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (Temp != NULL) {
|
|
*PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
|
|
} else {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|