--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006 - 2007, 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
+Module Name:\r
+\r
+ PciDeviceSupport.c\r
+\r
+Abstract:\r
+\r
+ This file provides routine to support Pci device node manipulation\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "pcibus.h"\r
+#include "PciDeviceSupport.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 gPciDevicePool;\r
+\r
+EFI_STATUS\r
+InitializePciDevicePool (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize the gPciDevicePool\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ InitializeListHead (&gPciDevicePool);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InsertRootBridge (\r
+ PCI_IO_DEVICE *RootBridge\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Insert a root bridge into PCI device pool\r
+\r
+Arguments:\r
+\r
+ RootBridge - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+\r
+ InsertTailList (&gPciDevicePool, &(RootBridge->Link));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InsertPciDevice (\r
+ PCI_IO_DEVICE *Bridge,\r
+ PCI_IO_DEVICE *PciDeviceNode\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function is used to insert a PCI device node under\r
+ a bridge\r
+\r
+Arguments:\r
+ Bridge - A pointer to the PCI_IO_DEVICE.\r
+ PciDeviceNode - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+\r
+ InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));\r
+ PciDeviceNode->Parent = Bridge;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DestroyRootBridge (\r
+ IN PCI_IO_DEVICE *RootBridge\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+\r
+Arguments:\r
+\r
+ RootBridge - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ DestroyPciDeviceTree (RootBridge);\r
+\r
+ FreePciDevice (RootBridge);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FreePciDevice (\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Destroy a pci device node.\r
+ Also all direct or indirect allocated resource for this node will be freed.\r
+\r
+Arguments:\r
+\r
+ PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+\r
+ //\r
+ // Assume all children have been removed underneath this device\r
+ //\r
+ if (PciIoDevice->ResourcePaddingDescriptors != NULL) {\r
+ gBS->FreePool (PciIoDevice->ResourcePaddingDescriptors);\r
+ }\r
+\r
+ if (PciIoDevice->DevicePath != NULL) {\r
+ gBS->FreePool (PciIoDevice->DevicePath);\r
+ }\r
+\r
+ gBS->FreePool (PciIoDevice);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DestroyPciDeviceTree (\r
+ IN PCI_IO_DEVICE *Bridge\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Destroy all the pci device node under the bridge.\r
+ Bridge itself is not included.\r
+\r
+Arguments:\r
+\r
+ Bridge - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\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
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DestroyRootBridgeByHandle (\r
+ EFI_HANDLE Controller\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Destroy all device nodes under the root bridge\r
+ specified by Controller.\r
+ The root bridge itself is also included.\r
+\r
+Arguments:\r
+\r
+ Controller - An efi handle.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+{\r
+\r
+ LIST_ENTRY *CurrentLink;\r
+ PCI_IO_DEVICE *Temp;\r
+\r
+ CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+ while (CurrentLink && CurrentLink != &gPciDevicePool) {\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
+EFI_STATUS\r
+RegisterPciDevice (\r
+ IN EFI_HANDLE Controller,\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ OUT EFI_HANDLE *Handle OPTIONAL\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function registers the PCI IO device. It creates a handle for this PCI IO device\r
+ (if the handle does not exist), attaches appropriate protocols onto the handle, does\r
+ necessary initialization, and sets up parent/child relationship with its bus controller.\r
+\r
+Arguments:\r
+\r
+ Controller - An EFI handle for the PCI bus controller.\r
+ PciIoDevice - A PCI_IO_DEVICE pointer to the PCI IO device to be registered.\r
+ Handle - A pointer to hold the EFI handle for the PCI IO device.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The PCI device is successfully registered.\r
+ Others - An error occurred when registering the PCI device.\r
+\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
+\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
+ PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
+\r
+ //\r
+ // Process Platform OpRom\r
+ //\r
+ if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) {\r
+ PciIoDevice->AllOpRomProcessed = TRUE;\r
+\r
+ Status = gPciPlatformProtocol->GetPciRom (\r
+ gPciPlatformProtocol,\r
+ PciIoDevice->Handle,\r
+ &PlatformOpRomBuffer,\r
+ &PlatformOpRomSize\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ //\r
+ // Have Platform OpRom\r
+ //\r
+ PciIoDevice->RomSize = PlatformOpRomSize;\r
+ PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
+ PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
+\r
+ //\r
+ // Process Image\r
+ //\r
+ ProcessOpRomImage (PciIoDevice);\r
+ }\r
+ }\r
+\r
+ if (PciIoDevice->BusOverride) {\r
+ //\r
+ // Install BusSpecificDriverOverride 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
+\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
+ //\r
+ // Install Pccard Hotplug GUID for Pccard device so that\r
+ // to notify CardBus driver to stop the device when de-register happens\r
+ //\r
+ InstallPciHotplugGuid (PciIoDevice);\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
+EFI_STATUS\r
+RemoveAllPciDeviceOnBridge (\r
+ EFI_HANDLE RootBridgeHandle,\r
+ PCI_IO_DEVICE *Bridge\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function is used to remove the whole PCI devices from the bridge.\r
+\r
+Arguments:\r
+\r
+ RootBridgeHandle - An efi handle.\r
+ Bridge - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\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
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DeRegisterPciDevice (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE Handle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function is used to de-register the PCI device from the EFI,\r
+ That includes un-installing PciIo protocol from the specified PCI\r
+ device handle.\r
+\r
+Arguments:\r
+\r
+ Controller - An efi handle.\r
+ Handle - An efi handle.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\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 && 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
+ // Uninstall Pccard Hotplug GUID for Pccard device\r
+ //\r
+ UninstallPciHotplugGuid (PciIoDevice);\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 io protocol\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
+ 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
+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
+Routine Description:\r
+\r
+ Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
+\r
+Arguments:\r
+\r
+ Controller - An efi handle.\r
+ RootBridge - A pointer to the PCI_IO_DEVICE.\r
+ RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
+ NumberOfChildren - Children number.\r
+ ChildHandleBuffer - A pointer to the child handle buffer.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_NOT_READY - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+// TODO: EFI_UNSUPPORTED - add return value to function comment\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+{\r
+ PCI_IO_DEVICE *Temp;\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
+ CurrentLink = RootBridge->ChildList.ForwardLink;\r
+\r
+ while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
+\r
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+ if (RemainingDevicePath != NULL) {\r
+\r
+ Node.DevPath = RemainingDevicePath;\r
+\r
+ if (Node.Pci->Device != Temp->DeviceNumber ||\r
+ Node.Pci->Function != Temp->FunctionNumber) {\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check if the device has been assigned with required resource\r
+ //\r
+ if (!Temp->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 (!Temp->Registered) {\r
+ PciIoDevice = Temp;\r
+\r
+ Status = RegisterPciDevice (\r
+ Controller,\r
+ PciIoDevice,\r
+ NULL\r
+ );\r
+\r
+ }\r
+\r
+ if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
+ ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
+ (*NumberOfChildren)++;\r
+ }\r
+\r
+ //\r
+ // Get the next device path\r
+ //\r
+ CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);\r
+ if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // If it is a PPB\r
+ //\r
+ if (!IsListEmpty (&Temp->ChildList)) {\r
+ Status = StartPciDevicesOnBridge (\r
+ Controller,\r
+ Temp,\r
+ CurrentDevicePath,\r
+ NumberOfChildren,\r
+ ChildHandleBuffer\r
+ );\r
+\r
+ Temp->PciIo.Attributes (\r
+ &(Temp->PciIo),\r
+ EfiPciIoAttributeOperationSupported,\r
+ 0,\r
+ &Supports\r
+ );\r
+ Supports &= EFI_PCI_DEVICE_ENABLE;\r
+ Temp->PciIo.Attributes (\r
+ &(Temp->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
+\r
+ if (!Temp->Registered && Temp->Allocated) {\r
+\r
+ PciIoDevice = Temp;\r
+\r
+ Status = RegisterPciDevice (\r
+ Controller,\r
+ PciIoDevice,\r
+ NULL\r
+ );\r
+\r
+ }\r
+\r
+ if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
+ ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
+ (*NumberOfChildren)++;\r
+ }\r
+\r
+ if (!IsListEmpty (&Temp->ChildList)) {\r
+ Status = StartPciDevicesOnBridge (\r
+ Controller,\r
+ Temp,\r
+ RemainingDevicePath,\r
+ NumberOfChildren,\r
+ ChildHandleBuffer\r
+ );\r
+\r
+ Temp->PciIo.Attributes (\r
+ &(Temp->PciIo),\r
+ EfiPciIoAttributeOperationSupported,\r
+ 0,\r
+ &Supports\r
+ );\r
+ Supports &= EFI_PCI_DEVICE_ENABLE;\r
+ Temp->PciIo.Attributes (\r
+ &(Temp->PciIo),\r
+ EfiPciIoAttributeOperationEnable,\r
+ Supports,\r
+ NULL\r
+ );\r
+\r
+ }\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+StartPciDevices (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Start to manage the PCI device according to RemainingDevicePath\r
+ If RemainingDevicePath == NULL, the PCI bus driver will start\r
+ to manage all the PCI devices it found previously\r
+\r
+Arguments:\r
+ Controller - An efi handle.\r
+ RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_UNSUPPORTED - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ EFI_DEV_PATH_PTR Node;\r
+ PCI_IO_DEVICE *RootBridge;\r
+ LIST_ENTRY *CurrentLink;\r
+\r
+ if (RemainingDevicePath != NULL) {\r
+\r
+ //\r
+ // Check if the RemainingDevicePath is valid\r
+ //\r
+ Node.DevPath = RemainingDevicePath;\r
+ if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
+ ((Node.DevPath->SubType != HW_PCI_DP) &&\r
+ (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+ while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
+\r
+ RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+ //\r
+ // Locate the right root bridge to start\r
+ //\r
+ if (RootBridge->Handle == Controller) {\r
+ StartPciDevicesOnBridge (\r
+ Controller,\r
+ RootBridge,\r
+ RemainingDevicePath,\r
+ NULL,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+PCI_IO_DEVICE *\r
+CreateRootBridge (\r
+ IN EFI_HANDLE RootBridgeHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+\r
+Arguments:\r
+ RootBridgeHandle - An efi handle.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\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 = NULL;\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ sizeof (PCI_IO_DEVICE),\r
+ (VOID **) &Dev\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem (Dev, sizeof (PCI_IO_DEVICE));\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
+ gBS->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
+ Status = InitializePciIoInstance (Dev);\r
+ Status = InitializePciDriverOverrideInstance (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
+PCI_IO_DEVICE *\r
+GetRootBridgeByHandle (\r
+ EFI_HANDLE RootBridgeHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+\r
+Arguments:\r
+\r
+ RootBridgeHandle - An efi handle.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ PCI_IO_DEVICE *RootBridgeDev;\r
+ LIST_ENTRY *CurrentLink;\r
+\r
+ CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+ while (CurrentLink && CurrentLink != &gPciDevicePool) {\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
+BOOLEAN\r
+RootBridgeExisted (\r
+ IN EFI_HANDLE RootBridgeHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function searches if RootBridgeHandle has already existed\r
+ in current device pool.\r
+\r
+ If so, it means the given root bridge has been already enumerated.\r
+\r
+Arguments:\r
+\r
+ RootBridgeHandle - An efi handle.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ PCI_IO_DEVICE *Bridge;\r
+\r
+ Bridge = GetRootBridgeByHandle (RootBridgeHandle);\r
+\r
+ if (Bridge != NULL) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+BOOLEAN\r
+PciDeviceExisted (\r
+ IN PCI_IO_DEVICE *Bridge,\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+ Bridge - A pointer to the PCI_IO_DEVICE.\r
+ PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+\r
+ PCI_IO_DEVICE *Temp;\r
+ LIST_ENTRY *CurrentLink;\r
+\r
+ CurrentLink = Bridge->ChildList.ForwardLink;\r
+\r
+ while (CurrentLink && 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
+PCI_IO_DEVICE *\r
+ActiveVGADeviceOnTheSameSegment (\r
+ IN PCI_IO_DEVICE *VgaDevice\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+ VgaDevice - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ LIST_ENTRY *CurrentLink;\r
+ PCI_IO_DEVICE *Temp;\r
+\r
+ CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+ while (CurrentLink && CurrentLink != &gPciDevicePool) {\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
+PCI_IO_DEVICE *\r
+ActiveVGADeviceOnTheRootBridge (\r
+ IN PCI_IO_DEVICE *RootBridge\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+ RootBridge - A pointer to the PCI_IO_DEVICE.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ LIST_ENTRY *CurrentLink;\r
+ PCI_IO_DEVICE *Temp;\r
+\r
+ CurrentLink = RootBridge->ChildList.ForwardLink;\r
+\r
+ while (CurrentLink && 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))) {\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
+EFI_STATUS\r
+GetHpcPciAddress (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
+ OUT UINT64 *PciAddress\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+ PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
+ PciAddress - A pointer to the pci address.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
+ EFI_DEV_PATH_PTR Node;\r
+ LIST_ENTRY *CurrentLink;\r
+ PCI_IO_DEVICE *RootBridge;\r
+ EFI_STATUS Status;\r
+\r
+ CurrentDevicePath = HpcDevicePath;\r
+\r
+ //\r
+ // Get the remaining device path for this PCI device, if it is a PCI device\r
+ //\r
+ while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+\r
+ Node.DevPath = CurrentDevicePath;\r
+\r
+ //\r
+ // Check if it is PCI device Path?\r
+ //\r
+ if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
+ ((Node.DevPath->SubType != HW_PCI_DP) &&\r
+ (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {\r
+ CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
+ continue;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Check if it is not PCI device path\r
+ //\r
+ if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ CurrentLink = gPciDevicePool.ForwardLink;\r
+\r
+ while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
+\r
+ RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+ //\r
+ // Locate the right root bridge to start\r
+ //\r
+ if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {\r
+ Status = GetHpcPciAddressFromRootBridge (\r
+ RootBridge,\r
+ CurrentDevicePath,\r
+ PciAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ }\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\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
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+ PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
+ PciAddress - A pointer to the pci address.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+// TODO: RootBridge - add argument and description to function comment\r
+// TODO: RemainingDevicePath - add argument and description to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\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 (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
+\r
+ CurrentLink = RootBridge->ChildList.ForwardLink;\r
+ Node.DevPath = CurrentDevicePath;\r
+\r
+ while (CurrentLink && 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 = EfiNextDevicePathNode (CurrentDevicePath);\r
+ }\r
+\r
+ if (MisMatch) {\r
+\r
+ CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
+\r
+ if (EfiIsDevicePathEnd (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
+ *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r