+++ /dev/null
-/** @file\r
- Supporting functions implementaion for PCI devices management.\r
-\r
-Copyright (c) 2006 - 2009, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "PciBus.h"\r
-\r
-//\r
-// This device structure is serviced as a header.\r
-// Its next field points to the first root bridge device node.\r
-//\r
-LIST_ENTRY mPciDevicePool;\r
-\r
-/**\r
- Initialize the PCI devices pool.\r
-\r
-**/\r
-VOID\r
-InitializePciDevicePool (\r
- VOID\r
- )\r
-{\r
- InitializeListHead (&mPciDevicePool);\r
-}\r
-\r
-/**\r
- Insert a root bridge into PCI device pool.\r
-\r
- @param RootBridge A pointer to the PCI_IO_DEVICE.\r
-\r
-**/\r
-VOID\r
-InsertRootBridge (\r
- IN PCI_IO_DEVICE *RootBridge\r
- )\r
-{\r
- InsertTailList (&mPciDevicePool, &(RootBridge->Link));\r
-}\r
-\r
-/**\r
- This function is used to insert a PCI device node under\r
- a bridge.\r
-\r
- @param Bridge The PCI bridge.\r
- @param PciDeviceNode The PCI device needs inserting.\r
-\r
-**/\r
-VOID\r
-InsertPciDevice (\r
- IN PCI_IO_DEVICE *Bridge,\r
- IN PCI_IO_DEVICE *PciDeviceNode\r
- )\r
-{\r
- InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));\r
- PciDeviceNode->Parent = Bridge;\r
-}\r
-\r
-/**\r
- Destroy root bridge and remove it from deivce tree.\r
-\r
- @param RootBridge The bridge want to be removed.\r
-\r
-**/\r
-VOID\r
-DestroyRootBridge (\r
- IN PCI_IO_DEVICE *RootBridge\r
- )\r
-{\r
- DestroyPciDeviceTree (RootBridge);\r
-\r
- FreePciDevice (RootBridge);\r
-}\r
-\r
-/**\r
- Destroy a pci device node.\r
-\r
- All direct or indirect allocated resource for this node will be freed.\r
-\r
- @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried.\r
-\r
-**/\r
-VOID\r
-FreePciDevice (\r
- IN PCI_IO_DEVICE *PciIoDevice\r
- )\r
-{\r
- ASSERT (PciIoDevice != NULL);\r
- //\r
- // Assume all children have been removed underneath this device\r
- //\r
- if (PciIoDevice->ResourcePaddingDescriptors != NULL) {\r
- FreePool (PciIoDevice->ResourcePaddingDescriptors);\r
- }\r
-\r
- if (PciIoDevice->DevicePath != NULL) {\r
- FreePool (PciIoDevice->DevicePath);\r
- }\r
-\r
- FreePool (PciIoDevice);\r
-}\r
-\r
-/**\r
- Destroy all the pci device node under the bridge.\r
- Bridge itself is not included.\r
-\r
- @param Bridge A pointer to the PCI_IO_DEVICE.\r
-\r
-**/\r
-VOID\r
-DestroyPciDeviceTree (\r
- IN PCI_IO_DEVICE *Bridge\r
- )\r
-{\r
- LIST_ENTRY *CurrentLink;\r
- PCI_IO_DEVICE *Temp;\r
-\r
- while (!IsListEmpty (&Bridge->ChildList)) {\r
-\r
- CurrentLink = Bridge->ChildList.ForwardLink;\r
-\r
- //\r
- // Remove this node from the linked list\r
- //\r
- RemoveEntryList (CurrentLink);\r
-\r
- Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
-\r
- if (!IsListEmpty (&Temp->ChildList)) {\r
- DestroyPciDeviceTree (Temp);\r
- }\r
-\r
- FreePciDevice (Temp);\r
- }\r
-}\r
-\r
-/**\r
- Destroy all device nodes under the root bridge\r
- specified by Controller.\r
-\r
- The root bridge itself is also included.\r
-\r
- @param Controller Root bridge handle.\r
-\r
- @retval EFI_SUCCESS Destory all devcie nodes successfully.\r
- @retval EFI_NOT_FOUND Cannot find any PCI device under specified\r
- root bridge.\r
-\r
-**/\r
-EFI_STATUS\r
-DestroyRootBridgeByHandle (\r
- IN EFI_HANDLE Controller\r
- )\r
-{\r
-\r
- LIST_ENTRY *CurrentLink;\r
- PCI_IO_DEVICE *Temp;\r
-\r
- CurrentLink = mPciDevicePool.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
- Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
-\r
- if (Temp->Handle == Controller) {\r
-\r
- RemoveEntryList (CurrentLink);\r
-\r
- DestroyPciDeviceTree (Temp);\r
-\r
- FreePciDevice (Temp);\r
-\r
- return EFI_SUCCESS;\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- This function registers the PCI IO device.\r
-\r
- It creates a handle for this PCI IO device (if the handle does not exist), attaches\r
- appropriate protocols onto the handle, does necessary initialization, and sets up\r
- parent/child relationship with its bus controller.\r
-\r
- @param Controller An EFI handle for the PCI bus controller.\r
- @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.\r
- @param Handle A pointer to hold the returned EFI handle for the PCI IO device.\r
-\r
- @retval EFI_SUCCESS The PCI device is successfully registered.\r
- @retval other An error occurred when registering the PCI device.\r
-\r
-**/\r
-EFI_STATUS\r
-RegisterPciDevice (\r
- IN EFI_HANDLE Controller,\r
- IN PCI_IO_DEVICE *PciIoDevice,\r
- OUT EFI_HANDLE *Handle OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VOID *PlatformOpRomBuffer;\r
- UINTN PlatformOpRomSize;\r
- UINT8 PciExpressCapRegOffset;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- UINT8 Data8;\r
- BOOLEAN HasEfiImage;\r
- PCI_IO_DEVICE *ParrentPciIoDevice;\r
- EFI_PCI_IO_PROTOCOL *ParrentPciIo;\r
- UINT16 Data16;\r
- UINT32 Data32;\r
-\r
- //\r
- // Install the pciio protocol, device path protocol\r
- //\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &PciIoDevice->Handle,\r
- &gEfiDevicePathProtocolGuid,\r
- PciIoDevice->DevicePath,\r
- &gEfiPciIoProtocolGuid,\r
- &PciIoDevice->PciIo,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Detect if PCI Express Device\r
- //\r
- PciExpressCapRegOffset = 0;\r
- Status = LocateCapabilityRegBlock (\r
- PciIoDevice,\r
- EFI_PCI_CAPABILITY_ID_PCIEXP,\r
- &PciExpressCapRegOffset,\r
- NULL\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- PciIoDevice->IsPciExp = TRUE;\r
- }\r
-\r
- //\r
- // Force Interrupt line to "Unknown" or "No Connection"\r
- //\r
- PciIo = &(PciIoDevice->PciIo);\r
- Data8 = PCI_INT_LINE_UNKNOWN;\r
- PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
- \r
- //\r
- // PCI-IOV programming\r
- //\r
- if (((FeaturePcdGet(PcdAriSupport) & EFI_PCI_IOV_POLICY_ARI) != 0) && (PciIoDevice->AriCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport) & EFI_PCI_IOV_POLICY_SRIOV) != 0) &&\r
- (PciIoDevice->SrIovCapabilityOffset != 0)) {\r
- //\r
- // Check its parrent ARI forwarding capability\r
- //\r
- ParrentPciIoDevice = PciIoDevice->Parent;\r
- ParrentPciIo = &(ParrentPciIoDevice->PciIo);\r
- ParrentPciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET, 1, &Data32);\r
- if (Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) {\r
- //\r
- // ARI forward support in bridge, so enable it.\r
- //\r
- ParrentPciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 1, &Data32);\r
- Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
- ParrentPciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 1, &Data32);\r
-\r
- //\r
- // Set ARI Capable Hierarchy for device\r
- //\r
- PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 1, &Data16);\r
- Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
- PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 1, &Data16);\r
- }\r
- }\r
- \r
- //\r
- // Process OpRom\r
- //\r
- if (!PciIoDevice->AllOpRomProcessed) {\r
-\r
- //\r
- // Get the OpRom provided by platform\r
- //\r
- if (gPciPlatformProtocol != NULL) {\r
- Status = gPciPlatformProtocol->GetPciRom (\r
- gPciPlatformProtocol,\r
- PciIoDevice->Handle,\r
- &PlatformOpRomBuffer,\r
- &PlatformOpRomSize\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- PciIoDevice->RomSize = PlatformOpRomSize;\r
- PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
- PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
- //\r
- // For OpROM read from gPciPlatformProtocol:\r
- // Add the Rom Image to internal database for later PCI light enumeration\r
- //\r
- PciRomAddImageMapping (\r
- NULL,\r
- PciIoDevice->PciRootBridgeIo->SegmentNumber,\r
- PciIoDevice->BusNumber,\r
- PciIoDevice->DeviceNumber,\r
- PciIoDevice->FunctionNumber,\r
- (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,\r
- PciIoDevice->PciIo.RomSize\r
- );\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Determine if there are EFI images in the option rom\r
- //\r
- HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);\r
-\r
- if (HasEfiImage) {\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &PciIoDevice->Handle,\r
- &gEfiLoadFile2ProtocolGuid,\r
- &PciIoDevice->LoadFile2,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- gBS->UninstallMultipleProtocolInterfaces (\r
- &PciIoDevice->Handle,\r
- &gEfiDevicePathProtocolGuid,\r
- PciIoDevice->DevicePath,\r
- &gEfiPciIoProtocolGuid,\r
- &PciIoDevice->PciIo,\r
- NULL\r
- );\r
- return Status;\r
- }\r
- }\r
-\r
-\r
- if (!PciIoDevice->AllOpRomProcessed) {\r
-\r
- PciIoDevice->AllOpRomProcessed = TRUE;\r
-\r
- //\r
- // Dispatch the EFI OpRom for the PCI device.\r
- // The OpRom is got from platform in the above code\r
- // or loaded from device in the previous round of bus enumeration\r
- //\r
- if (HasEfiImage) {\r
- ProcessOpRomImage (PciIoDevice);\r
- }\r
- }\r
-\r
- if (PciIoDevice->BusOverride) {\r
- //\r
- // Install Bus Specific Driver Override Protocol\r
- //\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &PciIoDevice->Handle,\r
- &gEfiBusSpecificDriverOverrideProtocolGuid,\r
- &PciIoDevice->PciDriverOverride,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- gBS->UninstallMultipleProtocolInterfaces (\r
- &PciIoDevice->Handle,\r
- &gEfiDevicePathProtocolGuid,\r
- PciIoDevice->DevicePath,\r
- &gEfiPciIoProtocolGuid,\r
- &PciIoDevice->PciIo,\r
- NULL\r
- );\r
- if (HasEfiImage) {\r
- gBS->UninstallMultipleProtocolInterfaces (\r
- &PciIoDevice->Handle,\r
- &gEfiLoadFile2ProtocolGuid,\r
- &PciIoDevice->LoadFile2,\r
- NULL\r
- );\r
- }\r
-\r
- return Status;\r
- }\r
- }\r
-\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiPciRootBridgeIoProtocolGuid,\r
- (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
- gPciBusDriverBinding.DriverBindingHandle,\r
- PciIoDevice->Handle,\r
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if (Handle != NULL) {\r
- *Handle = PciIoDevice->Handle;\r
- }\r
-\r
- //\r
- // Indicate the pci device is registered\r
- //\r
- PciIoDevice->Registered = TRUE;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to remove the whole PCI devices on the specified bridge from\r
- the root bridge.\r
-\r
- @param RootBridgeHandle The root bridge device handle.\r
- @param Bridge The bridge device to be removed.\r
-\r
-**/\r
-VOID\r
-RemoveAllPciDeviceOnBridge (\r
- EFI_HANDLE RootBridgeHandle,\r
- PCI_IO_DEVICE *Bridge\r
- )\r
-{\r
- LIST_ENTRY *CurrentLink;\r
- PCI_IO_DEVICE *Temp;\r
-\r
- while (!IsListEmpty (&Bridge->ChildList)) {\r
-\r
- CurrentLink = Bridge->ChildList.ForwardLink;\r
- Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
-\r
- //\r
- // Check if the current node has been deregistered before\r
- // If it is not, then deregister it\r
- //\r
- if (Temp->Registered) {\r
- DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
- }\r
-\r
- //\r
- // Remove this node from the linked list\r
- //\r
- RemoveEntryList (CurrentLink);\r
-\r
- if (!IsListEmpty (&Temp->ChildList)) {\r
- RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
- }\r
-\r
- FreePciDevice (Temp);\r
- }\r
-}\r
-\r
-/**\r
- This function is used to de-register the PCI IO device.\r
-\r
- That includes un-installing PciIo protocol from the specified PCI\r
- device handle.\r
-\r
- @param Controller An EFI handle for the PCI bus controller.\r
- @param Handle PCI device handle.\r
-\r
- @retval EFI_SUCCESS The PCI device is successfully de-registered.\r
- @retval other An error occurred when de-registering the PCI device.\r
-\r
-**/\r
-EFI_STATUS\r
-DeRegisterPciDevice (\r
- IN EFI_HANDLE Controller,\r
- IN EFI_HANDLE Handle\r
- )\r
-\r
-{\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- EFI_STATUS Status;\r
- PCI_IO_DEVICE *PciIoDevice;\r
- PCI_IO_DEVICE *Node;\r
- LIST_ENTRY *CurrentLink;\r
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
-\r
- Status = gBS->OpenProtocol (\r
- Handle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo,\r
- gPciBusDriverBinding.DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
-\r
- //\r
- // If it is already de-registered\r
- //\r
- if (!PciIoDevice->Registered) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // If it is PPB, first de-register its children\r
- //\r
-\r
- if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
-\r
- CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
- Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
- Status = DeRegisterPciDevice (Controller, Node->Handle);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
- }\r
-\r
- //\r
- // Close the child handle\r
- //\r
- Status = gBS->CloseProtocol (\r
- Controller,\r
- &gEfiPciRootBridgeIoProtocolGuid,\r
- gPciBusDriverBinding.DriverBindingHandle,\r
- Handle\r
- );\r
-\r
- //\r
- // Un-install the Device Path protocol and PCI I/O protocol\r
- // and Bus Specific Driver Override protocol if needed.\r
- //\r
- if (PciIoDevice->BusOverride) {\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- Handle,\r
- &gEfiDevicePathProtocolGuid,\r
- PciIoDevice->DevicePath,\r
- &gEfiPciIoProtocolGuid,\r
- &PciIoDevice->PciIo,\r
- &gEfiBusSpecificDriverOverrideProtocolGuid,\r
- &PciIoDevice->PciDriverOverride,\r
- NULL\r
- );\r
- } else {\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- Handle,\r
- &gEfiDevicePathProtocolGuid,\r
- PciIoDevice->DevicePath,\r
- &gEfiPciIoProtocolGuid,\r
- &PciIoDevice->PciIo,\r
- NULL\r
- );\r
- }\r
-\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Try to uninstall LoadFile2 protocol if exists\r
- //\r
- Status = gBS->OpenProtocol (\r
- Handle,\r
- &gEfiLoadFile2ProtocolGuid,\r
- NULL,\r
- gPciBusDriverBinding.DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- Handle,\r
- &gEfiLoadFile2ProtocolGuid,\r
- &PciIoDevice->LoadFile2,\r
- NULL\r
- );\r
- }\r
- //\r
- // Restore Status\r
- //\r
- Status = EFI_SUCCESS;\r
- }\r
-\r
-\r
- if (EFI_ERROR (Status)) {\r
- gBS->OpenProtocol (\r
- Controller,\r
- &gEfiPciRootBridgeIoProtocolGuid,\r
- (VOID **) &PciRootBridgeIo,\r
- gPciBusDriverBinding.DriverBindingHandle,\r
- Handle,\r
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
- );\r
- return Status;\r
- }\r
-\r
- //\r
- // The Device Driver should disable this device after disconnect\r
- // so the Pci Bus driver will not touch this device any more.\r
- // Restore the register field to the original value\r
- //\r
- PciIoDevice->Registered = FALSE;\r
- PciIoDevice->Handle = NULL;\r
- } else {\r
-\r
- //\r
- // Handle may be closed before\r
- //\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.\r
-\r
- @param Controller The root bridge handle.\r
- @param RootBridge A pointer to the PCI_IO_DEVICE.\r
- @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
- @param NumberOfChildren Children number.\r
- @param ChildHandleBuffer A pointer to the child handle buffer.\r
-\r
- @retval EFI_NOT_READY Device is not allocated.\r
- @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.\r
- @retval EFI_NOT_FOUND Can not find the specific device.\r
- @retval EFI_SUCCESS Success to start Pci devices on bridge.\r
-\r
-**/\r
-EFI_STATUS\r
-StartPciDevicesOnBridge (\r
- IN EFI_HANDLE Controller,\r
- IN PCI_IO_DEVICE *RootBridge,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
- IN OUT UINT8 *NumberOfChildren,\r
- IN OUT EFI_HANDLE *ChildHandleBuffer\r
- )\r
-\r
-{\r
- PCI_IO_DEVICE *PciIoDevice;\r
- EFI_DEV_PATH_PTR Node;\r
- EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
- EFI_STATUS Status;\r
- LIST_ENTRY *CurrentLink;\r
- UINT64 Supports;\r
-\r
- PciIoDevice = NULL;\r
- CurrentLink = RootBridge->ChildList.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
-\r
- PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
- if (RemainingDevicePath != NULL) {\r
-\r
- Node.DevPath = RemainingDevicePath;\r
-\r
- if (Node.Pci->Device != PciIoDevice->DeviceNumber ||\r
- Node.Pci->Function != PciIoDevice->FunctionNumber) {\r
- CurrentLink = CurrentLink->ForwardLink;\r
- continue;\r
- }\r
-\r
- //\r
- // Check if the device has been assigned with required resource\r
- //\r
- if (!PciIoDevice->Allocated) {\r
- return EFI_NOT_READY;\r
- }\r
-\r
- //\r
- // Check if the current node has been registered before\r
- // If it is not, register it\r
- //\r
- if (!PciIoDevice->Registered) {\r
- Status = RegisterPciDevice (\r
- Controller,\r
- PciIoDevice,\r
- NULL\r
- );\r
-\r
- }\r
-\r
- if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
- ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
- (*NumberOfChildren)++;\r
- }\r
-\r
- //\r
- // Get the next device path\r
- //\r
- CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);\r
- if (IsDevicePathEnd (CurrentDevicePath)) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // If it is a PPB\r
- //\r
- if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
- Status = StartPciDevicesOnBridge (\r
- Controller,\r
- PciIoDevice,\r
- CurrentDevicePath,\r
- NumberOfChildren,\r
- ChildHandleBuffer\r
- );\r
-\r
- PciIoDevice->PciIo.Attributes (\r
- &(PciIoDevice->PciIo),\r
- EfiPciIoAttributeOperationSupported,\r
- 0,\r
- &Supports\r
- );\r
- Supports &= EFI_PCI_DEVICE_ENABLE;\r
- PciIoDevice->PciIo.Attributes (\r
- &(PciIoDevice->PciIo),\r
- EfiPciIoAttributeOperationEnable,\r
- Supports,\r
- NULL\r
- );\r
-\r
- return Status;\r
- } else {\r
-\r
- //\r
- // Currently, the PCI bus driver only support PCI-PCI bridge\r
- //\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- } else {\r
-\r
- //\r
- // If remaining device path is NULL,\r
- // try to enable all the pci devices under this bridge\r
- //\r
- if (!PciIoDevice->Registered && PciIoDevice->Allocated) {\r
- Status = RegisterPciDevice (\r
- Controller,\r
- PciIoDevice,\r
- NULL\r
- );\r
-\r
- }\r
-\r
- if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
- ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
- (*NumberOfChildren)++;\r
- }\r
-\r
- if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
- Status = StartPciDevicesOnBridge (\r
- Controller,\r
- PciIoDevice,\r
- RemainingDevicePath,\r
- NumberOfChildren,\r
- ChildHandleBuffer\r
- );\r
-\r
- PciIoDevice->PciIo.Attributes (\r
- &(PciIoDevice->PciIo),\r
- EfiPciIoAttributeOperationSupported,\r
- 0,\r
- &Supports\r
- );\r
- Supports &= EFI_PCI_DEVICE_ENABLE;\r
- PciIoDevice->PciIo.Attributes (\r
- &(PciIoDevice->PciIo),\r
- EfiPciIoAttributeOperationEnable,\r
- Supports,\r
- NULL\r
- );\r
-\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
- }\r
-\r
- if (PciIoDevice == NULL) {\r
- return EFI_NOT_FOUND;\r
- } else {\r
- return EFI_SUCCESS;\r
- }\r
-}\r
-\r
-/**\r
- Start to manage all the PCI devices it found previously under\r
- the entire host bridge.\r
-\r
- @param Controller The root bridge handle.\r
-\r
- @retval EFI_NOT_READY Device is not allocated.\r
- @retval EFI_SUCCESS Success to start Pci device on host bridge.\r
-\r
-**/\r
-EFI_STATUS\r
-StartPciDevices (\r
- IN EFI_HANDLE Controller\r
- )\r
-{\r
- PCI_IO_DEVICE *RootBridge;\r
- EFI_HANDLE ThisHostBridge;\r
- LIST_ENTRY *CurrentLink;\r
-\r
- RootBridge = GetRootBridgeByHandle (Controller);\r
- ASSERT (RootBridge != NULL);\r
- ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
-\r
- CurrentLink = mPciDevicePool.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
-\r
- RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
- //\r
- // Locate the right root bridge to start\r
- //\r
- if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
- StartPciDevicesOnBridge (\r
- RootBridge->Handle,\r
- RootBridge,\r
- NULL,\r
- NULL,\r
- NULL\r
- );\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Create root bridge device.\r
-\r
- @param RootBridgeHandle Specified root bridge hanle.\r
-\r
- @return The crated root bridge device instance, NULL means no\r
- root bridge device instance created.\r
-\r
-**/\r
-PCI_IO_DEVICE *\r
-CreateRootBridge (\r
- IN EFI_HANDLE RootBridgeHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- PCI_IO_DEVICE *Dev;\r
- EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
-\r
- Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
- if (Dev == NULL) {\r
- return NULL;\r
- }\r
-\r
- Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
- Dev->Handle = RootBridgeHandle;\r
- InitializeListHead (&Dev->ChildList);\r
-\r
- Status = gBS->OpenProtocol (\r
- RootBridgeHandle,\r
- &gEfiDevicePathProtocolGuid,\r
- (VOID **) &ParentDevicePath,\r
- gPciBusDriverBinding.DriverBindingHandle,\r
- RootBridgeHandle,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- FreePool (Dev);\r
- return NULL;\r
- }\r
-\r
- //\r
- // Record the root bridge parent device path\r
- //\r
- Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
-\r
- //\r
- // Get the pci root bridge io protocol\r
- //\r
- Status = gBS->OpenProtocol (\r
- RootBridgeHandle,\r
- &gEfiPciRootBridgeIoProtocolGuid,\r
- (VOID **) &PciRootBridgeIo,\r
- gPciBusDriverBinding.DriverBindingHandle,\r
- RootBridgeHandle,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- FreePciDevice (Dev);\r
- return NULL;\r
- }\r
-\r
- Dev->PciRootBridgeIo = PciRootBridgeIo;\r
-\r
- //\r
- // Initialize the PCI I/O instance structure\r
- //\r
- InitializePciIoInstance (Dev);\r
- InitializePciDriverOverrideInstance (Dev);\r
- InitializePciLoadFile2 (Dev);\r
-\r
- //\r
- // Initialize reserved resource list and\r
- // option rom driver list\r
- //\r
- InitializeListHead (&Dev->ReservedResourceList);\r
- InitializeListHead (&Dev->OptionRomDriverList);\r
-\r
- return Dev;\r
-}\r
-\r
-/**\r
- Get root bridge device instance by specific root bridge handle.\r
-\r
- @param RootBridgeHandle Given root bridge handle.\r
-\r
- @return The root bridge device instance, NULL means no root bridge\r
- device instance found.\r
-\r
-**/\r
-PCI_IO_DEVICE *\r
-GetRootBridgeByHandle (\r
- EFI_HANDLE RootBridgeHandle\r
- )\r
-{\r
- PCI_IO_DEVICE *RootBridgeDev;\r
- LIST_ENTRY *CurrentLink;\r
-\r
- CurrentLink = mPciDevicePool.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
-\r
- RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
- if (RootBridgeDev->Handle == RootBridgeHandle) {\r
- return RootBridgeDev;\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- Judege whether Pci device existed.\r
-\r
- @param Bridge Parent bridege instance.\r
- @param PciIoDevice Device instance.\r
-\r
- @retval TRUE Pci device existed.\r
- @retval FALSE Pci device did not exist.\r
-\r
-**/\r
-BOOLEAN\r
-PciDeviceExisted (\r
- IN PCI_IO_DEVICE *Bridge,\r
- IN PCI_IO_DEVICE *PciIoDevice\r
- )\r
-{\r
-\r
- PCI_IO_DEVICE *Temp;\r
- LIST_ENTRY *CurrentLink;\r
-\r
- CurrentLink = Bridge->ChildList.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
-\r
- Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
-\r
- if (Temp == PciIoDevice) {\r
- return TRUE;\r
- }\r
-\r
- if (!IsListEmpty (&Temp->ChildList)) {\r
- if (PciDeviceExisted (Temp, PciIoDevice)) {\r
- return TRUE;\r
- }\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-/**\r
- Get the active VGA device on the same segment.\r
-\r
- @param VgaDevice PCI IO instance for the VGA device.\r
-\r
- @return The active VGA device on the same segment.\r
-\r
-**/\r
-PCI_IO_DEVICE *\r
-ActiveVGADeviceOnTheSameSegment (\r
- IN PCI_IO_DEVICE *VgaDevice\r
- )\r
-{\r
- LIST_ENTRY *CurrentLink;\r
- PCI_IO_DEVICE *Temp;\r
-\r
- CurrentLink = mPciDevicePool.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
-\r
- Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
-\r
- if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
-\r
- Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
-\r
- if (Temp != NULL) {\r
- return Temp;\r
- }\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- Get the active VGA device on the root bridge.\r
-\r
- @param RootBridge PCI IO instance for the root bridge.\r
-\r
- @return The active VGA device.\r
-\r
-**/\r
-PCI_IO_DEVICE *\r
-ActiveVGADeviceOnTheRootBridge (\r
- IN PCI_IO_DEVICE *RootBridge\r
- )\r
-{\r
- LIST_ENTRY *CurrentLink;\r
- PCI_IO_DEVICE *Temp;\r
-\r
- CurrentLink = RootBridge->ChildList.ForwardLink;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
-\r
- Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
-\r
- if (IS_PCI_VGA(&Temp->Pci) &&\r
- (Temp->Attributes &\r
- (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
- EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
- EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {\r
- return Temp;\r
- }\r
-\r
- if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
-\r
- Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
-\r
- if (Temp != NULL) {\r
- return Temp;\r
- }\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-\r
-/**\r
- Get HPC PCI address according to its device path.\r
-\r
- @param RootBridge Root bridege Io instance.\r
- @param RemainingDevicePath Given searching device path.\r
- @param PciAddress Buffer holding searched result.\r
-\r
- @retval EFI_SUCCESS PCI address was stored in PciAddress\r
- @retval EFI_NOT_FOUND Can not find the specific device path.\r
-\r
-**/\r
-EFI_STATUS\r
-GetHpcPciAddressFromRootBridge (\r
- IN PCI_IO_DEVICE *RootBridge,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
- OUT UINT64 *PciAddress\r
- )\r
-{\r
- EFI_DEV_PATH_PTR Node;\r
- PCI_IO_DEVICE *Temp;\r
- EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
- LIST_ENTRY *CurrentLink;\r
- BOOLEAN MisMatch;\r
-\r
- MisMatch = FALSE;\r
-\r
- CurrentDevicePath = RemainingDevicePath;\r
- Node.DevPath = CurrentDevicePath;\r
- Temp = NULL;\r
-\r
- while (!IsDevicePathEnd (CurrentDevicePath)) {\r
-\r
- CurrentLink = RootBridge->ChildList.ForwardLink;\r
- Node.DevPath = CurrentDevicePath;\r
-\r
- while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
- Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
-\r
- if (Node.Pci->Device == Temp->DeviceNumber &&\r
- Node.Pci->Function == Temp->FunctionNumber) {\r
- RootBridge = Temp;\r
- break;\r
- }\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
- }\r
-\r
- //\r
- // Check if we find the bridge\r
- //\r
- if (CurrentLink == &RootBridge->ChildList) {\r
-\r
- MisMatch = TRUE;\r
- break;\r
-\r
- }\r
-\r
- CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
- }\r
-\r
- if (MisMatch) {\r
-\r
- CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
-\r
- if (IsDevicePathEnd (CurrentDevicePath)) {\r
- *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- if (Temp != NULL) {\r
- *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
- } else {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-\r
-}\r
-\r