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>
998 lines
23 KiB
C
998 lines
23 KiB
C
/*++
|
|
|
|
Copyright (c) 2005 - 2006, 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.
|
|
|
|
Module Name:
|
|
|
|
PciDeviceSupport.c
|
|
|
|
Abstract:
|
|
|
|
This file provides routine to support Pci device node manipulation
|
|
|
|
Revision History
|
|
|
|
--*/
|
|
|
|
#include <IndustryStandard/PciBus.h>
|
|
#include <IndustryStandard/PciCommand.h>
|
|
|
|
#include <Library/MemLogLib.h>
|
|
#include <Library/PrintLib.h>
|
|
|
|
#include "PciDeviceSupport.h"
|
|
|
|
//
|
|
// This device structure is serviced as a header.
|
|
// Its Next field points to the first root bridge device node
|
|
//
|
|
#ifndef DEBUG_ALL
|
|
#define DEBUG_PCI 0
|
|
#else
|
|
#define DEBUG_PCI DEBUG_ALL
|
|
#endif
|
|
|
|
#if DEBUG_PCI==0
|
|
#define DBG(...)
|
|
#elif DEBUG_PCI == 1
|
|
#define DBG(...) MemLog(TRUE, 1, __VA_ARGS__)
|
|
#else
|
|
#define DBG(...) MemLog(TRUE, 0, __VA_ARGS__)
|
|
#endif
|
|
|
|
|
|
LIST_ENTRY gPciDevicePool;
|
|
|
|
EFI_STATUS
|
|
InitializePciDevicePool (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the gPciDevicePool
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
InitializeListHead (&gPciDevicePool);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
InsertRootBridge (
|
|
IN PCI_IO_DEVICE *RootBridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insert a root bridge into PCI device pool
|
|
|
|
Arguments:
|
|
|
|
RootBridge - A pointer to the PCI_IO_DEVICE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
InsertTailList (&gPciDevicePool, &(RootBridge->Link));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
InsertPciDevice (
|
|
PCI_IO_DEVICE *Bridge,
|
|
PCI_IO_DEVICE *PciDeviceNode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to insert a PCI device node under
|
|
a bridge
|
|
|
|
Arguments:
|
|
Bridge - A pointer to the PCI_IO_DEVICE.
|
|
PciDeviceNode - A pointer to the PCI_IO_DEVICE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DBG("Insert node %p in %p\n", PciDeviceNode, Bridge);
|
|
InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
|
|
PciDeviceNode->Parent = Bridge;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DestroyRootBridge (
|
|
IN PCI_IO_DEVICE *RootBridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
RootBridge - A pointer to the PCI_IO_DEVICE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DestroyPciDeviceTree (RootBridge);
|
|
|
|
gBS->FreePool (RootBridge);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DestroyPciDeviceTree (
|
|
IN PCI_IO_DEVICE *Bridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroy all the pci device node under the bridge.
|
|
Bridge itself is not included.
|
|
|
|
Arguments:
|
|
|
|
Bridge - A pointer to the PCI_IO_DEVICE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
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 (IS_PCI_BRIDGE (&(Temp->Pci))) {
|
|
DestroyPciDeviceTree (Temp);
|
|
}
|
|
gBS->FreePool (Temp);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DestroyRootBridgeByHandle (
|
|
EFI_HANDLE Controller
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroy all device nodes under the root bridge
|
|
specified by Controller.
|
|
The root bridge itself is also included.
|
|
|
|
Arguments:
|
|
|
|
Controller - An efi handle.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_IO_DEVICE *Temp;
|
|
|
|
CurrentLink = gPciDevicePool.ForwardLink;
|
|
|
|
while (CurrentLink && CurrentLink != &gPciDevicePool) {
|
|
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
|
|
if (Temp->Handle == Controller) {
|
|
|
|
RemoveEntryList (CurrentLink);
|
|
|
|
DestroyPciDeviceTree (Temp);
|
|
|
|
gBS->FreePool(Temp);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
DBG("RootBridge destroyed\n");
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
RegisterPciDevice (
|
|
IN EFI_HANDLE Controller,
|
|
IN PCI_IO_DEVICE *PciIoDevice,
|
|
OUT EFI_HANDLE *Handle OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
Controller - An EFI handle for the PCI bus controller.
|
|
PciIoDevice - A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
|
|
Handle - A pointer to hold the EFI handle for the PCI IO device.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - The PCI device is successfully registered.
|
|
Others - An error occurred when registering the PCI device.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 PciExpressCapRegOffset;
|
|
|
|
//
|
|
// Install the pciio protocol, device path protocol and
|
|
// Bus Specific Driver Override Protocol
|
|
//
|
|
|
|
if (PciIoDevice->BusOverride) {
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&PciIoDevice->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
PciIoDevice->DevicePath,
|
|
&gEfiPciIoProtocolGuid,
|
|
&PciIoDevice->PciIo,
|
|
&gEfiBusSpecificDriverOverrideProtocolGuid,
|
|
&PciIoDevice->PciDriverOverride,
|
|
NULL
|
|
);
|
|
} else {
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&PciIoDevice->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
PciIoDevice->DevicePath,
|
|
&gEfiPciIoProtocolGuid,
|
|
&PciIoDevice->PciIo,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DBG("PciIo protocol not installed Status=%r\n", Status);
|
|
return Status;
|
|
} else {
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Detect if PCI Express Device
|
|
//
|
|
PciExpressCapRegOffset = 0;
|
|
Status = LocateCapabilityRegBlock (
|
|
PciIoDevice,
|
|
EFI_PCI_CAPABILITY_ID_PCIEXP,
|
|
&PciExpressCapRegOffset,
|
|
NULL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
PciIoDevice->IsPciExp = TRUE;
|
|
// DEBUG ((EFI_D_ERROR, "PciExp - %x (B-%x, D-%x, F-%x)\n", PciIoDevice->IsPciExp, PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber));
|
|
DBG("PciExp - %x (B-%x, D-%x, F-%x)\n", PciIoDevice->IsPciExp, PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber);
|
|
}
|
|
|
|
//
|
|
// Indicate the pci device is registered
|
|
//
|
|
PciIoDevice->Registered = TRUE;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
DeRegisterPciDevice (
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to de-register the PCI device from the EFI,
|
|
That includes un-installing PciIo protocol from the specified PCI
|
|
device handle.
|
|
|
|
Arguments:
|
|
|
|
Controller - An efi handle.
|
|
Handle - An efi handle.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
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 (IS_PCI_BRIDGE (&(PciIoDevice->Pci))) {
|
|
|
|
CurrentLink = PciIoDevice->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
|
|
Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
Status = DeRegisterPciDevice (Controller, Node->Handle);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
}
|
|
|
|
//
|
|
// First disconnect this device
|
|
//
|
|
// PciIoDevice->PciIo.Attributes(&(PciIoDevice->PciIo),
|
|
// EfiPciIoAttributeOperationDisable,
|
|
// EFI_PCI_DEVICE_ENABLE,
|
|
// NULL
|
|
// );
|
|
|
|
//
|
|
// Close the child handle
|
|
//
|
|
Status = gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
gPciBusDriverBinding.DriverBindingHandle,
|
|
Handle
|
|
);
|
|
|
|
//
|
|
// Un-install the device path protocol and pci io protocol
|
|
//
|
|
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)) {
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EnableBridgeAttributes (
|
|
IN PCI_IO_DEVICE *PciIoDevice
|
|
)
|
|
{
|
|
PCI_TYPE01 PciData;
|
|
|
|
//
|
|
// NOTE: We should not set EFI_PCI_DEVICE_ENABLE for a bridge
|
|
// directly, because some legacy BIOS will NOT assign
|
|
// IO or Memory resource for a bridge who has no child
|
|
// device. So we add check IO or Memory here.
|
|
//
|
|
|
|
PciIoDevice->PciIo.Pci.Read (
|
|
&PciIoDevice->PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0,
|
|
sizeof (PciData),
|
|
&PciData
|
|
);
|
|
|
|
if ((((PciData.Bridge.IoBase & 0xF) == 0) &&
|
|
(PciData.Bridge.IoBase != 0 || PciData.Bridge.IoLimit != 0)) ||
|
|
(((PciData.Bridge.IoBase & 0xF) == 1) &&
|
|
((PciData.Bridge.IoBase & 0xF0) != 0 || (PciData.Bridge.IoLimit & 0xF0) != 0 || PciData.Bridge.IoBaseUpper16 != 0 || PciData.Bridge.IoLimitUpper16 != 0))) {
|
|
PciIoDevice->PciIo.Attributes(
|
|
&(PciIoDevice->PciIo),
|
|
EfiPciIoAttributeOperationEnable,
|
|
(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
|
|
NULL
|
|
);
|
|
}
|
|
if ((PciData.Bridge.MemoryBase & 0xFFF0) != 0 || (PciData.Bridge.MemoryLimit & 0xFFF0) != 0) {
|
|
PciIoDevice->PciIo.Attributes(
|
|
&(PciIoDevice->PciIo),
|
|
EfiPciIoAttributeOperationEnable,
|
|
(EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
|
|
NULL
|
|
);
|
|
}
|
|
if ((((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 0) &&
|
|
(PciData.Bridge.PrefetchableMemoryBase != 0 || PciData.Bridge.PrefetchableMemoryLimit != 0)) ||
|
|
(((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 1) &&
|
|
((PciData.Bridge.PrefetchableMemoryBase & 0xFFF0) != 0 || (PciData.Bridge.PrefetchableMemoryLimit & 0xFFF0) != 0 || PciData.Bridge.PrefetchableBaseUpper32 != 0 || PciData.Bridge.PrefetchableLimitUpper32 != 0))) {
|
|
PciIoDevice->PciIo.Attributes(
|
|
&(PciIoDevice->PciIo),
|
|
EfiPciIoAttributeOperationEnable,
|
|
(EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
|
|
NULL
|
|
);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
StartPciDevicesOnBridge (
|
|
IN EFI_HANDLE Controller,
|
|
IN PCI_IO_DEVICE *RootBridge,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge
|
|
|
|
Arguments:
|
|
|
|
Controller - An efi handle.
|
|
RootBridge - A pointer to the PCI_IO_DEVICE.
|
|
RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
|
|
NumberOfChildren - Children number.
|
|
ChildHandleBuffer - A pointer to the child handle buffer.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCI_IO_DEVICE *Temp;
|
|
PCI_IO_DEVICE *PciIoDevice;
|
|
EFI_DEV_PATH_PTR Node;
|
|
EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
CurrentLink = RootBridge->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
|
|
|
|
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
if (RemainingDevicePath != NULL) {
|
|
|
|
Node.DevPath = RemainingDevicePath;
|
|
|
|
if (Node.Pci->Device != Temp->DeviceNumber ||
|
|
Node.Pci->Function != Temp->FunctionNumber) {
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check if the device has been assigned with required resource
|
|
//
|
|
if (!Temp->Allocated) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
//
|
|
// Check if the current node has been registered before
|
|
// If it is not, register it
|
|
//
|
|
if (!Temp->Registered) {
|
|
PciIoDevice = Temp;
|
|
|
|
Status = RegisterPciDevice (
|
|
Controller,
|
|
PciIoDevice,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Get the next device path
|
|
//
|
|
CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
|
|
if (IsDevicePathEnd (CurrentDevicePath)) {
|
|
DBG("PCIdevice [%04x,%04x] started\n", Node.Pci->Device, Node.Pci->Function);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If it is a PPB
|
|
//
|
|
if (IS_PCI_BRIDGE (&(Temp->Pci))) {
|
|
Status = StartPciDevicesOnBridge (
|
|
Controller,
|
|
Temp,
|
|
CurrentDevicePath
|
|
);
|
|
EnableBridgeAttributes (Temp);
|
|
|
|
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 (!Temp->Registered && Temp->Allocated) {
|
|
|
|
PciIoDevice = Temp;
|
|
|
|
Status = RegisterPciDevice (
|
|
Controller,
|
|
PciIoDevice,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
|
|
if (IS_PCI_BRIDGE (&(Temp->Pci))) {
|
|
Status = StartPciDevicesOnBridge (
|
|
Controller,
|
|
Temp,
|
|
RemainingDevicePath
|
|
);
|
|
EnableBridgeAttributes (Temp);
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
StartPciDevices (
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start to manage the PCI device according to RemainingDevicePath
|
|
If RemainingDevicePath == NULL, the PCI bus driver will start
|
|
to manage all the PCI devices it found previously
|
|
|
|
Arguments:
|
|
Controller - An efi handle.
|
|
RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
EFI_DEV_PATH_PTR Node;
|
|
PCI_IO_DEVICE *RootBridge;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
if (RemainingDevicePath != NULL) {
|
|
|
|
//
|
|
// Check if the RemainingDevicePath is valid
|
|
//
|
|
Node.DevPath = RemainingDevicePath;
|
|
if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
|
|
Node.DevPath->SubType != HW_PCI_DP ||
|
|
DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)
|
|
) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
CurrentLink = gPciDevicePool.ForwardLink;
|
|
|
|
while (CurrentLink && CurrentLink != &gPciDevicePool) {
|
|
|
|
RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
//
|
|
// Locate the right root bridge to start
|
|
//
|
|
if (RootBridge->Handle == Controller) {
|
|
StartPciDevicesOnBridge (
|
|
Controller,
|
|
RootBridge,
|
|
RemainingDevicePath
|
|
);
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
PCI_IO_DEVICE *
|
|
CreateRootBridge (
|
|
IN EFI_HANDLE RootBridgeHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
RootBridgeHandle - An efi handle.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
PCI_IO_DEVICE *Dev;
|
|
|
|
Dev = NULL;
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
sizeof (PCI_IO_DEVICE),
|
|
(VOID **) &Dev
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
ZeroMem (Dev, sizeof (PCI_IO_DEVICE));
|
|
Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
|
|
Dev->Handle = RootBridgeHandle;
|
|
InitializeListHead (&Dev->ChildList);
|
|
|
|
return Dev;
|
|
}
|
|
|
|
PCI_IO_DEVICE *
|
|
GetRootBridgeByHandle (
|
|
EFI_HANDLE RootBridgeHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
RootBridgeHandle - An efi handle.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCI_IO_DEVICE *RootBridgeDev;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
CurrentLink = gPciDevicePool.ForwardLink;
|
|
|
|
while (CurrentLink && CurrentLink != &gPciDevicePool) {
|
|
|
|
RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
if (RootBridgeDev->Handle == RootBridgeHandle) {
|
|
return RootBridgeDev;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOLEAN
|
|
RootBridgeExisted (
|
|
IN EFI_HANDLE RootBridgeHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function searches if RootBridgeHandle has already existed
|
|
in current device pool.
|
|
|
|
If so, it means the given root bridge has been already enumerated.
|
|
|
|
Arguments:
|
|
|
|
RootBridgeHandle - An efi handle.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCI_IO_DEVICE *Bridge;
|
|
|
|
Bridge = GetRootBridgeByHandle (RootBridgeHandle);
|
|
|
|
if (Bridge != NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
PciDeviceExisted (
|
|
IN PCI_IO_DEVICE *Bridge,
|
|
IN PCI_IO_DEVICE *PciIoDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Bridge - A pointer to the PCI_IO_DEVICE.
|
|
PciIoDevice - A pointer to the PCI_IO_DEVICE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PCI_IO_DEVICE *Temp;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink && 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;
|
|
}
|
|
|
|
PCI_IO_DEVICE *
|
|
ActiveVGADeviceOnTheSameSegment (
|
|
IN PCI_IO_DEVICE *VgaDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
VgaDevice - A pointer to the PCI_IO_DEVICE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_IO_DEVICE *Temp;
|
|
|
|
CurrentLink = gPciDevicePool.ForwardLink;
|
|
|
|
while (CurrentLink && CurrentLink != &gPciDevicePool) {
|
|
|
|
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;
|
|
}
|
|
|
|
PCI_IO_DEVICE *
|
|
ActiveVGADeviceOnTheRootBridge (
|
|
IN PCI_IO_DEVICE *RootBridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
RootBridge - A pointer to the PCI_IO_DEVICE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_IO_DEVICE *Temp;
|
|
|
|
CurrentLink = RootBridge->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink && 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))) {
|
|
return Temp;
|
|
}
|
|
|
|
if (IS_PCI_BRIDGE (&Temp->Pci)) {
|
|
|
|
Temp = ActiveVGADeviceOnTheRootBridge (Temp);
|
|
|
|
if (Temp != NULL) {
|
|
return Temp;
|
|
}
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|