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