In V4: Update the copyright to 2023. In V3: Add AMD copyright. In V2: Remove the signed-off-by: Abner Chang Display PCIe Vendor ID and Device ID in DEBUG message. Signed-off-by: Jiangang He <jiangang.he@amd.com> Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Garrett Kirkendall <garrett.kirkendall@amd.com> Cc: Abner Chang <abner.chang@amd.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
		
			
				
	
	
		
			2893 lines
		
	
	
		
			83 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2893 lines
		
	
	
		
			83 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  PCI emumeration support functions implementation for PCI Bus module.
 | 
						|
 | 
						|
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
 | 
						|
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
 | 
						|
Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "PciBus.h"
 | 
						|
 | 
						|
extern CHAR16                          *mBarTypeStr[];
 | 
						|
extern EDKII_DEVICE_SECURITY_PROTOCOL  *mDeviceSecurityProtocol;
 | 
						|
 | 
						|
#define OLD_ALIGN    0xFFFFFFFFFFFFFFFFULL
 | 
						|
#define EVEN_ALIGN   0xFFFFFFFFFFFFFFFEULL
 | 
						|
#define SQUAD_ALIGN  0xFFFFFFFFFFFFFFFDULL
 | 
						|
#define DQUAD_ALIGN  0xFFFFFFFFFFFFFFFCULL
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is used to check whether the pci device is present.
 | 
						|
 | 
						|
  @param PciRootBridgeIo   Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
 | 
						|
  @param Pci               Output buffer for PCI device configuration space.
 | 
						|
  @param Bus               PCI bus NO.
 | 
						|
  @param Device            PCI device NO.
 | 
						|
  @param Func              PCI Func NO.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND    PCI device not present.
 | 
						|
  @retval EFI_SUCCESS      PCI device is found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PciDevicePresent (
 | 
						|
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,
 | 
						|
  OUT PCI_TYPE00                       *Pci,
 | 
						|
  IN  UINT8                            Bus,
 | 
						|
  IN  UINT8                            Device,
 | 
						|
  IN  UINT8                            Func
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64      Address;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create PCI address map in terms of Bus, Device and Func
 | 
						|
  //
 | 
						|
  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Read the Vendor ID register
 | 
						|
  //
 | 
						|
  Status = PciRootBridgeIo->Pci.Read (
 | 
						|
                                  PciRootBridgeIo,
 | 
						|
                                  EfiPciWidthUint32,
 | 
						|
                                  Address,
 | 
						|
                                  1,
 | 
						|
                                  Pci
 | 
						|
                                  );
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status) && ((Pci->Hdr).VendorId != 0xffff)) {
 | 
						|
    //
 | 
						|
    // Read the entire config header for the device
 | 
						|
    //
 | 
						|
    Status = PciRootBridgeIo->Pci.Read (
 | 
						|
                                    PciRootBridgeIo,
 | 
						|
                                    EfiPciWidthUint32,
 | 
						|
                                    Address,
 | 
						|
                                    sizeof (PCI_TYPE00) / sizeof (UINT32),
 | 
						|
                                    Pci
 | 
						|
                                    );
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Collect all the resource information under this root bridge.
 | 
						|
 | 
						|
  A database that records all the information about pci device subject to this
 | 
						|
  root bridge will then be created.
 | 
						|
 | 
						|
  @param Bridge         Parent bridge instance.
 | 
						|
  @param StartBusNumber Bus number of beginning.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   PCI device is found.
 | 
						|
  @retval other         Some error occurred when reading PCI bridge information.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PciPciDeviceInfoCollector (
 | 
						|
  IN PCI_IO_DEVICE  *Bridge,
 | 
						|
  IN UINT8          StartBusNumber
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  PCI_TYPE00           Pci;
 | 
						|
  UINT8                Device;
 | 
						|
  UINT8                Func;
 | 
						|
  UINT8                SecBus;
 | 
						|
  PCI_IO_DEVICE        *PciIoDevice;
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  SecBus = 0;
 | 
						|
 | 
						|
  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
 | 
						|
    for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
 | 
						|
      //
 | 
						|
      // Check to see whether PCI device is present
 | 
						|
      //
 | 
						|
      Status = PciDevicePresent (
 | 
						|
                 Bridge->PciRootBridgeIo,
 | 
						|
                 &Pci,
 | 
						|
                 (UINT8)StartBusNumber,
 | 
						|
                 (UINT8)Device,
 | 
						|
                 (UINT8)Func
 | 
						|
                 );
 | 
						|
 | 
						|
      if (EFI_ERROR (Status) && (Func == 0)) {
 | 
						|
        //
 | 
						|
        // go to next device if there is no Function 0
 | 
						|
        //
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Call back to host bridge function
 | 
						|
        //
 | 
						|
        PreprocessController (Bridge, (UINT8)StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);
 | 
						|
 | 
						|
        //
 | 
						|
        // Collect all the information about the PCI device discovered
 | 
						|
        //
 | 
						|
        Status = PciSearchDevice (
 | 
						|
                   Bridge,
 | 
						|
                   &Pci,
 | 
						|
                   (UINT8)StartBusNumber,
 | 
						|
                   Device,
 | 
						|
                   Func,
 | 
						|
                   &PciIoDevice
 | 
						|
                   );
 | 
						|
 | 
						|
        //
 | 
						|
        // Recursively scan PCI busses on the other side of PCI-PCI bridges
 | 
						|
        //
 | 
						|
        //
 | 
						|
        if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
 | 
						|
          //
 | 
						|
          // If it is PPB, we need to get the secondary bus to continue the enumeration
 | 
						|
          //
 | 
						|
          PciIo = &(PciIoDevice->PciIo);
 | 
						|
 | 
						|
          Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);
 | 
						|
 | 
						|
          if (EFI_ERROR (Status)) {
 | 
						|
            return Status;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // Ensure secondary bus number is greater than the primary bus number to avoid
 | 
						|
          // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE
 | 
						|
          //
 | 
						|
          if (SecBus <= StartBusNumber) {
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // Get resource padding for PPB
 | 
						|
          //
 | 
						|
          GetResourcePaddingPpb (PciIoDevice);
 | 
						|
 | 
						|
          //
 | 
						|
          // Deep enumerate the next level bus
 | 
						|
          //
 | 
						|
          Status = PciPciDeviceInfoCollector (
 | 
						|
                     PciIoDevice,
 | 
						|
                     (UINT8)(SecBus)
 | 
						|
                     );
 | 
						|
        }
 | 
						|
 | 
						|
        if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {
 | 
						|
          //
 | 
						|
          // Skip sub functions, this is not a multi function device
 | 
						|
          //
 | 
						|
          Func = PCI_MAX_FUNC;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Search required device and create PCI device instance.
 | 
						|
 | 
						|
  @param Bridge     Parent bridge instance.
 | 
						|
  @param Pci        Input PCI device information block.
 | 
						|
  @param Bus        PCI bus NO.
 | 
						|
  @param Device     PCI device NO.
 | 
						|
  @param Func       PCI func  NO.
 | 
						|
  @param PciDevice  Output of searched PCI device instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Successfully created PCI device instance.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Cannot get PCI device information.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PciSearchDevice (
 | 
						|
  IN  PCI_IO_DEVICE  *Bridge,
 | 
						|
  IN  PCI_TYPE00     *Pci,
 | 
						|
  IN  UINT8          Bus,
 | 
						|
  IN  UINT8          Device,
 | 
						|
  IN  UINT8          Func,
 | 
						|
  OUT PCI_IO_DEVICE  **PciDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_IO_DEVICE  *PciIoDevice;
 | 
						|
  BOOLEAN        IgnoreOptionRom;
 | 
						|
 | 
						|
  PciIoDevice     = NULL;
 | 
						|
  IgnoreOptionRom = FALSE;
 | 
						|
 | 
						|
  DEBUG ((
 | 
						|
    DEBUG_INFO,
 | 
						|
    "PciBus: Discovered %s @ [%02x|%02x|%02x]  [VID = 0x%x, DID = 0x%0x]\n",
 | 
						|
    IS_PCI_BRIDGE (Pci) ?     L"PPB" :
 | 
						|
    IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :
 | 
						|
    L"PCI",
 | 
						|
    Bus,
 | 
						|
    Device,
 | 
						|
    Func,
 | 
						|
    Pci->Hdr.VendorId,
 | 
						|
    Pci->Hdr.DeviceId
 | 
						|
    ));
 | 
						|
 | 
						|
  if (!IS_PCI_BRIDGE (Pci)) {
 | 
						|
    if (IS_CARDBUS_BRIDGE (Pci)) {
 | 
						|
      PciIoDevice = GatherP2CInfo (
 | 
						|
                      Bridge,
 | 
						|
                      Pci,
 | 
						|
                      Bus,
 | 
						|
                      Device,
 | 
						|
                      Func
 | 
						|
                      );
 | 
						|
      if ((PciIoDevice != NULL) && gFullEnumeration) {
 | 
						|
        InitializeP2C (PciIoDevice);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Create private data for Pci Device
 | 
						|
      //
 | 
						|
      PciIoDevice = GatherDeviceInfo (
 | 
						|
                      Bridge,
 | 
						|
                      Pci,
 | 
						|
                      Bus,
 | 
						|
                      Device,
 | 
						|
                      Func
 | 
						|
                      );
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Create private data for PPB
 | 
						|
    //
 | 
						|
    PciIoDevice = GatherPpbInfo (
 | 
						|
                    Bridge,
 | 
						|
                    Pci,
 | 
						|
                    Bus,
 | 
						|
                    Device,
 | 
						|
                    Func
 | 
						|
                    );
 | 
						|
 | 
						|
    //
 | 
						|
    // Special initialization for PPB including making the PPB quiet
 | 
						|
    //
 | 
						|
    if ((PciIoDevice != NULL) && gFullEnumeration) {
 | 
						|
      InitializePpb (PciIoDevice);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (PciIoDevice == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the bar information for this PCI device so as to support some specific device
 | 
						|
  //
 | 
						|
  UpdatePciInfo (PciIoDevice, &IgnoreOptionRom);
 | 
						|
 | 
						|
  if (PciIoDevice->DevicePath == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Detect this function has option rom
 | 
						|
  //
 | 
						|
  if (gFullEnumeration) {
 | 
						|
    if (!IS_CARDBUS_BRIDGE (Pci) && !IgnoreOptionRom) {
 | 
						|
      GetOpRomInfo (PciIoDevice);
 | 
						|
    }
 | 
						|
 | 
						|
    ResetPowerManagementFeature (PciIoDevice);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Insert it into a global tree for future reference
 | 
						|
  //
 | 
						|
  InsertPciDevice (Bridge, PciIoDevice);
 | 
						|
 | 
						|
  //
 | 
						|
  // Determine PCI device attributes
 | 
						|
  //
 | 
						|
 | 
						|
  if (PciDevice != NULL) {
 | 
						|
    *PciDevice = PciIoDevice;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Dump the PPB padding resource information.
 | 
						|
 | 
						|
  @param PciIoDevice     PCI IO instance.
 | 
						|
  @param ResourceType    The desired resource type to dump.
 | 
						|
                         PciBarTypeUnknown means to dump all types of resources.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DumpPpbPaddingResource (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN PCI_BAR_TYPE   ResourceType
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Descriptor;
 | 
						|
  PCI_BAR_TYPE                       Type;
 | 
						|
 | 
						|
  if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((ResourceType == PciBarTypeIo16) || (ResourceType == PciBarTypeIo32)) {
 | 
						|
    ResourceType = PciBarTypeIo;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) {
 | 
						|
    Type = PciBarTypeUnknown;
 | 
						|
    if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {
 | 
						|
      Type = PciBarTypeIo;
 | 
						|
    } else if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {
 | 
						|
      if (Descriptor->AddrSpaceGranularity == 32) {
 | 
						|
        //
 | 
						|
        // prefetchable
 | 
						|
        //
 | 
						|
        if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {
 | 
						|
          Type = PciBarTypePMem32;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Non-prefetchable
 | 
						|
        //
 | 
						|
        if (Descriptor->SpecificFlag == 0) {
 | 
						|
          Type = PciBarTypeMem32;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (Descriptor->AddrSpaceGranularity == 64) {
 | 
						|
        //
 | 
						|
        // prefetchable
 | 
						|
        //
 | 
						|
        if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {
 | 
						|
          Type = PciBarTypePMem64;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Non-prefetchable
 | 
						|
        //
 | 
						|
        if (Descriptor->SpecificFlag == 0) {
 | 
						|
          Type = PciBarTypeMem64;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) {
 | 
						|
      DEBUG ((
 | 
						|
        DEBUG_INFO,
 | 
						|
        "   Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
 | 
						|
        mBarTypeStr[Type],
 | 
						|
        Descriptor->AddrRangeMax,
 | 
						|
        Descriptor->AddrLen
 | 
						|
        ));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Dump the PCI BAR information.
 | 
						|
 | 
						|
  @param PciIoDevice     PCI IO instance.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DumpPciBars (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < PCI_MAX_BAR; Index++) {
 | 
						|
    if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_INFO,
 | 
						|
      "   BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
 | 
						|
      Index,
 | 
						|
      mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)],
 | 
						|
      PciIoDevice->PciBar[Index].Alignment,
 | 
						|
      PciIoDevice->PciBar[Index].Length,
 | 
						|
      PciIoDevice->PciBar[Index].Offset
 | 
						|
      ));
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < PCI_MAX_BAR; Index++) {
 | 
						|
    if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_INFO,
 | 
						|
      " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
 | 
						|
      Index,
 | 
						|
      mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)],
 | 
						|
      PciIoDevice->VfPciBar[Index].Alignment,
 | 
						|
      PciIoDevice->VfPciBar[Index].Length,
 | 
						|
      PciIoDevice->VfPciBar[Index].Offset
 | 
						|
      ));
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "\n"));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create PCI device instance for PCI device.
 | 
						|
 | 
						|
  @param Bridge   Parent bridge instance.
 | 
						|
  @param Pci      Input PCI device information block.
 | 
						|
  @param Bus      PCI device Bus NO.
 | 
						|
  @param Device   PCI device Device NO.
 | 
						|
  @param Func     PCI device's func NO.
 | 
						|
 | 
						|
  @return  Created PCI device instance.
 | 
						|
 | 
						|
**/
 | 
						|
PCI_IO_DEVICE *
 | 
						|
GatherDeviceInfo (
 | 
						|
  IN PCI_IO_DEVICE  *Bridge,
 | 
						|
  IN PCI_TYPE00     *Pci,
 | 
						|
  IN UINT8          Bus,
 | 
						|
  IN UINT8          Device,
 | 
						|
  IN UINT8          Func
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN          Offset;
 | 
						|
  UINTN          BarIndex;
 | 
						|
  PCI_IO_DEVICE  *PciIoDevice;
 | 
						|
 | 
						|
  PciIoDevice = CreatePciIoDevice (
 | 
						|
                  Bridge,
 | 
						|
                  Pci,
 | 
						|
                  Bus,
 | 
						|
                  Device,
 | 
						|
                  Func
 | 
						|
                  );
 | 
						|
 | 
						|
  if (PciIoDevice == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If it is a full enumeration, disconnect the device in advance
 | 
						|
  //
 | 
						|
  if (gFullEnumeration) {
 | 
						|
    PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Start to parse the bars
 | 
						|
  //
 | 
						|
  for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {
 | 
						|
    Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Parse the SR-IOV VF bars
 | 
						|
  //
 | 
						|
  if (PcdGetBool (PcdSrIovSupport) && (PciIoDevice->SrIovCapabilityOffset != 0)) {
 | 
						|
    for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;
 | 
						|
         Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;
 | 
						|
         BarIndex++)
 | 
						|
    {
 | 
						|
      ASSERT (BarIndex < PCI_MAX_BAR);
 | 
						|
      Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE (
 | 
						|
    DumpPciBars (PciIoDevice);
 | 
						|
    );
 | 
						|
  return PciIoDevice;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create PCI device instance for PCI-PCI bridge.
 | 
						|
 | 
						|
  @param Bridge   Parent bridge instance.
 | 
						|
  @param Pci      Input PCI device information block.
 | 
						|
  @param Bus      PCI device Bus NO.
 | 
						|
  @param Device   PCI device Device NO.
 | 
						|
  @param Func     PCI device's func NO.
 | 
						|
 | 
						|
  @return  Created PCI device instance.
 | 
						|
 | 
						|
**/
 | 
						|
PCI_IO_DEVICE *
 | 
						|
GatherPpbInfo (
 | 
						|
  IN PCI_IO_DEVICE  *Bridge,
 | 
						|
  IN PCI_TYPE00     *Pci,
 | 
						|
  IN UINT8          Bus,
 | 
						|
  IN UINT8          Device,
 | 
						|
  IN UINT8          Func
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_IO_DEVICE        *PciIoDevice;
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  UINT8                Value;
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
  UINT8                Temp;
 | 
						|
  UINT32               PMemBaseLimit;
 | 
						|
  UINT16               PrefetchableMemoryBase;
 | 
						|
  UINT16               PrefetchableMemoryLimit;
 | 
						|
 | 
						|
  PciIoDevice = CreatePciIoDevice (
 | 
						|
                  Bridge,
 | 
						|
                  Pci,
 | 
						|
                  Bus,
 | 
						|
                  Device,
 | 
						|
                  Func
 | 
						|
                  );
 | 
						|
 | 
						|
  if (PciIoDevice == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (gFullEnumeration) {
 | 
						|
    PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize the bridge control register
 | 
						|
    //
 | 
						|
    PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // PPB can have two BARs
 | 
						|
  //
 | 
						|
  if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
 | 
						|
    //
 | 
						|
    // Not 64-bit bar
 | 
						|
    //
 | 
						|
    PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
 | 
						|
  }
 | 
						|
 | 
						|
  PciIo = &PciIoDevice->PciIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Test whether it support 32 decode or not
 | 
						|
  //
 | 
						|
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
 | 
						|
 | 
						|
  if (Value != 0) {
 | 
						|
    if ((Value & 0x01) != 0) {
 | 
						|
      PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
 | 
						|
    } else {
 | 
						|
      PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
 | 
						|
  // PCI bridge supporting non-standard I/O window alignment less than 4K.
 | 
						|
  //
 | 
						|
 | 
						|
  PciIoDevice->BridgeIoAlignment = 0xFFF;
 | 
						|
  if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {
 | 
						|
    //
 | 
						|
    // Check any bits of bit 3-1 of I/O Base Register are writable.
 | 
						|
    // if so, it is assumed non-standard I/O window alignment is supported by this bridge.
 | 
						|
    // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.
 | 
						|
    //
 | 
						|
    Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));
 | 
						|
    PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
 | 
						|
    PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
 | 
						|
    PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
 | 
						|
    Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));
 | 
						|
    switch (Value) {
 | 
						|
      case BIT3:
 | 
						|
        PciIoDevice->BridgeIoAlignment = 0x7FF;
 | 
						|
        break;
 | 
						|
      case BIT3 | BIT2:
 | 
						|
        PciIoDevice->BridgeIoAlignment = 0x3FF;
 | 
						|
        break;
 | 
						|
      case BIT3 | BIT2 | BIT1:
 | 
						|
        PciIoDevice->BridgeIoAlignment = 0x1FF;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = BarExisted (
 | 
						|
             PciIoDevice,
 | 
						|
             0x24,
 | 
						|
             NULL,
 | 
						|
             &PMemBaseLimit
 | 
						|
             );
 | 
						|
 | 
						|
  //
 | 
						|
  // Test if it supports 64 memory or not
 | 
						|
  //
 | 
						|
  // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit
 | 
						|
  // registers:
 | 
						|
  //   0 - the bridge supports only 32 bit addresses.
 | 
						|
  //   1 - the bridge supports 64-bit addresses.
 | 
						|
  //
 | 
						|
  PrefetchableMemoryBase  = (UINT16)(PMemBaseLimit & 0xffff);
 | 
						|
  PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);
 | 
						|
  if (!EFI_ERROR (Status) &&
 | 
						|
      ((PrefetchableMemoryBase & 0x000f) == 0x0001) &&
 | 
						|
      ((PrefetchableMemoryLimit & 0x000f) == 0x0001))
 | 
						|
  {
 | 
						|
    Status = BarExisted (
 | 
						|
               PciIoDevice,
 | 
						|
               0x28,
 | 
						|
               NULL,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
 | 
						|
      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
 | 
						|
    } else {
 | 
						|
      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Memory 32 code is required for ppb
 | 
						|
  //
 | 
						|
  PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
 | 
						|
 | 
						|
  GetResourcePaddingPpb (PciIoDevice);
 | 
						|
 | 
						|
  DEBUG_CODE (
 | 
						|
    DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown);
 | 
						|
    DumpPciBars (PciIoDevice);
 | 
						|
    );
 | 
						|
 | 
						|
  return PciIoDevice;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create PCI device instance for PCI Card bridge device.
 | 
						|
 | 
						|
  @param Bridge   Parent bridge instance.
 | 
						|
  @param Pci      Input PCI device information block.
 | 
						|
  @param Bus      PCI device Bus NO.
 | 
						|
  @param Device   PCI device Device NO.
 | 
						|
  @param Func     PCI device's func NO.
 | 
						|
 | 
						|
  @return  Created PCI device instance.
 | 
						|
 | 
						|
**/
 | 
						|
PCI_IO_DEVICE *
 | 
						|
GatherP2CInfo (
 | 
						|
  IN PCI_IO_DEVICE  *Bridge,
 | 
						|
  IN PCI_TYPE00     *Pci,
 | 
						|
  IN UINT8          Bus,
 | 
						|
  IN UINT8          Device,
 | 
						|
  IN UINT8          Func
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_IO_DEVICE  *PciIoDevice;
 | 
						|
 | 
						|
  PciIoDevice = CreatePciIoDevice (
 | 
						|
                  Bridge,
 | 
						|
                  Pci,
 | 
						|
                  Bus,
 | 
						|
                  Device,
 | 
						|
                  Func
 | 
						|
                  );
 | 
						|
 | 
						|
  if (PciIoDevice == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (gFullEnumeration) {
 | 
						|
    PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize the bridge control register
 | 
						|
    //
 | 
						|
    PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // P2C only has one bar that is in 0x10
 | 
						|
  //
 | 
						|
  PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Read PciBar information from the bar register
 | 
						|
  //
 | 
						|
  GetBackPcCardBar (PciIoDevice);
 | 
						|
  PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED  |
 | 
						|
                         EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
 | 
						|
                         EFI_BRIDGE_IO32_DECODE_SUPPORTED;
 | 
						|
 | 
						|
  DEBUG_CODE (
 | 
						|
    DumpPciBars (PciIoDevice);
 | 
						|
    );
 | 
						|
 | 
						|
  return PciIoDevice;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create device path for pci device.
 | 
						|
 | 
						|
  @param ParentDevicePath  Parent bridge's path.
 | 
						|
  @param PciIoDevice       Pci device instance.
 | 
						|
 | 
						|
  @return Device path protocol instance for specific pci device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_DEVICE_PATH_PROTOCOL *
 | 
						|
CreatePciDevicePath (
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath,
 | 
						|
  IN  PCI_IO_DEVICE             *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_DEVICE_PATH  PciNode;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create PCI device path
 | 
						|
  //
 | 
						|
  PciNode.Header.Type    = HARDWARE_DEVICE_PATH;
 | 
						|
  PciNode.Header.SubType = HW_PCI_DP;
 | 
						|
  SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
 | 
						|
 | 
						|
  PciNode.Device          = PciIoDevice->DeviceNumber;
 | 
						|
  PciNode.Function        = PciIoDevice->FunctionNumber;
 | 
						|
  PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);
 | 
						|
 | 
						|
  return PciIoDevice->DevicePath;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the PCI IOV VF bar is existed or not.
 | 
						|
 | 
						|
  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
 | 
						|
  @param Offset            The offset.
 | 
						|
  @param BarLengthValue    The bar length value returned.
 | 
						|
  @param OriginalBarValue  The original bar value returned.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND    The bar doesn't exist.
 | 
						|
  @retval EFI_SUCCESS      The bar exist.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
VfBarExisted (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN UINTN          Offset,
 | 
						|
  OUT UINT32        *BarLengthValue,
 | 
						|
  OUT UINT32        *OriginalBarValue
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
  UINT32               OriginalValue;
 | 
						|
  UINT32               Value;
 | 
						|
  EFI_TPL              OldTpl;
 | 
						|
 | 
						|
  //
 | 
						|
  // Ensure it is called properly
 | 
						|
  //
 | 
						|
  ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
 | 
						|
  if (PciIoDevice->SrIovCapabilityOffset == 0) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  PciIo = &PciIoDevice->PciIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Preserve the original value
 | 
						|
  //
 | 
						|
 | 
						|
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
 | 
						|
 | 
						|
  //
 | 
						|
  // Raise TPL to high level to disable timer interrupt while the BAR is probed
 | 
						|
  //
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);
 | 
						|
 | 
						|
  //
 | 
						|
  // Write back the original value
 | 
						|
  //
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
 | 
						|
 | 
						|
  //
 | 
						|
  // Restore TPL to its original level
 | 
						|
  //
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (BarLengthValue != NULL) {
 | 
						|
    *BarLengthValue = Value;
 | 
						|
  }
 | 
						|
 | 
						|
  if (OriginalBarValue != NULL) {
 | 
						|
    *OriginalBarValue = OriginalValue;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Value == 0) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  } else {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the bar is existed or not.
 | 
						|
 | 
						|
  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
 | 
						|
  @param Offset            The offset.
 | 
						|
  @param BarLengthValue    The bar length value returned.
 | 
						|
  @param OriginalBarValue  The original bar value returned.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND    The bar doesn't exist.
 | 
						|
  @retval EFI_SUCCESS      The bar exist.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
BarExisted (
 | 
						|
  IN  PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN  UINTN          Offset,
 | 
						|
  OUT UINT32         *BarLengthValue,
 | 
						|
  OUT UINT32         *OriginalBarValue
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
  UINT32               OriginalValue;
 | 
						|
  UINT32               Value;
 | 
						|
  EFI_TPL              OldTpl;
 | 
						|
 | 
						|
  PciIo = &PciIoDevice->PciIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Preserve the original value
 | 
						|
  //
 | 
						|
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);
 | 
						|
 | 
						|
  //
 | 
						|
  // Raise TPL to high level to disable timer interrupt while the BAR is probed
 | 
						|
  //
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &Value);
 | 
						|
 | 
						|
  //
 | 
						|
  // Write back the original value
 | 
						|
  //
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);
 | 
						|
 | 
						|
  //
 | 
						|
  // Restore TPL to its original level
 | 
						|
  //
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (BarLengthValue != NULL) {
 | 
						|
    *BarLengthValue = Value;
 | 
						|
  }
 | 
						|
 | 
						|
  if (OriginalBarValue != NULL) {
 | 
						|
    *OriginalBarValue = OriginalValue;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Value == 0) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  } else {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Test whether the device can support given attributes.
 | 
						|
 | 
						|
  @param PciIoDevice      Pci device instance.
 | 
						|
  @param Command          Input command register value, and
 | 
						|
                          returned supported register value.
 | 
						|
  @param BridgeControl    Input bridge control value for PPB or P2C, and
 | 
						|
                          returned supported bridge control value.
 | 
						|
  @param OldCommand       Returned and stored old command register offset.
 | 
						|
  @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PciTestSupportedAttribute (
 | 
						|
  IN     PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN OUT UINT16         *Command,
 | 
						|
  IN OUT UINT16         *BridgeControl,
 | 
						|
  OUT UINT16            *OldCommand,
 | 
						|
  OUT UINT16            *OldBridgeControl
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_TPL  OldTpl;
 | 
						|
  UINT16   CommandValue;
 | 
						|
 | 
						|
  //
 | 
						|
  // Preserve the original value
 | 
						|
  //
 | 
						|
  PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
 | 
						|
 | 
						|
  //
 | 
						|
  // Raise TPL to high level to disable timer interrupt while the BAR is probed
 | 
						|
  //
 | 
						|
  OldTpl       = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 | 
						|
  CommandValue = *Command | *OldCommand;
 | 
						|
 | 
						|
  PCI_SET_COMMAND_REGISTER (PciIoDevice, CommandValue);
 | 
						|
  PCI_READ_COMMAND_REGISTER (PciIoDevice, &CommandValue);
 | 
						|
 | 
						|
  *Command = *Command & CommandValue;
 | 
						|
  //
 | 
						|
  // Write back the original value
 | 
						|
  //
 | 
						|
  PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
 | 
						|
 | 
						|
  //
 | 
						|
  // Restore TPL to its original level
 | 
						|
  //
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
 | 
						|
    //
 | 
						|
    // Preserve the original value
 | 
						|
    //
 | 
						|
    PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
 | 
						|
 | 
						|
    //
 | 
						|
    // Raise TPL to high level to disable timer interrupt while the BAR is probed
 | 
						|
    //
 | 
						|
    OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 | 
						|
 | 
						|
    PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
 | 
						|
    PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
 | 
						|
 | 
						|
    //
 | 
						|
    // Write back the original value
 | 
						|
    //
 | 
						|
    PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
 | 
						|
 | 
						|
    //
 | 
						|
    // Restore TPL to its original level
 | 
						|
    //
 | 
						|
    gBS->RestoreTPL (OldTpl);
 | 
						|
  } else {
 | 
						|
    *OldBridgeControl = 0;
 | 
						|
    *BridgeControl    = 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the supported or current attributes of a PCI device.
 | 
						|
 | 
						|
  @param PciIoDevice    Structure pointer for PCI device.
 | 
						|
  @param Command        Command register value.
 | 
						|
  @param BridgeControl  Bridge control value for PPB or P2C.
 | 
						|
  @param Option         Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PciSetDeviceAttribute (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN UINT16         Command,
 | 
						|
  IN UINT16         BridgeControl,
 | 
						|
  IN UINTN          Option
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64  Attributes;
 | 
						|
 | 
						|
  Attributes = 0;
 | 
						|
 | 
						|
  if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
 | 
						|
    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Option == EFI_SET_SUPPORTS) {
 | 
						|
    Attributes |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
 | 
						|
                           EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED        |
 | 
						|
                           EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE       |
 | 
						|
                           EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE      |
 | 
						|
                           EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM         |
 | 
						|
                           EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
 | 
						|
 | 
						|
    if (IS_PCI_LPC (&PciIoDevice->Pci)) {
 | 
						|
      Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
 | 
						|
      Attributes |= (mReserveIsaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO : \
 | 
						|
                     (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
 | 
						|
    }
 | 
						|
 | 
						|
    if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
 | 
						|
      //
 | 
						|
      // For bridge, it should support IDE attributes
 | 
						|
      //
 | 
						|
      Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
 | 
						|
      Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
 | 
						|
 | 
						|
      if (mReserveVgaAliases) {
 | 
						|
        Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \
 | 
						|
                                EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);
 | 
						|
      } else {
 | 
						|
        Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \
 | 
						|
                                EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      if (IS_PCI_IDE (&PciIoDevice->Pci)) {
 | 
						|
        Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
 | 
						|
        Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
 | 
						|
      }
 | 
						|
 | 
						|
      if (IS_PCI_VGA (&PciIoDevice->Pci)) {
 | 
						|
        Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
 | 
						|
        Attributes |= (mReserveVgaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO : \
 | 
						|
                       (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    PciIoDevice->Supports  = Attributes;
 | 
						|
    PciIoDevice->Supports &= ((PciIoDevice->Parent->Supports) | \
 | 
						|
                              EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
 | 
						|
                              EFI_PCI_IO_ATTRIBUTE_BUS_MASTER);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were
 | 
						|
    // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.
 | 
						|
    // When this attribute is set, the PCI option ROM described by the RomImage and RomSize
 | 
						|
    // fields is not from the the ROM BAR of the PCI controller.
 | 
						|
    //
 | 
						|
    if (!PciIoDevice->EmbeddedRom) {
 | 
						|
      Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;
 | 
						|
    }
 | 
						|
 | 
						|
    PciIoDevice->Attributes = Attributes;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Determine if the device can support Fast Back to Back attribute.
 | 
						|
 | 
						|
  @param PciIoDevice  Pci device instance.
 | 
						|
  @param StatusIndex  Status register value.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       This device support Fast Back to Back attribute.
 | 
						|
  @retval EFI_UNSUPPORTED   This device doesn't support Fast Back to Back attribute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetFastBackToBackSupport (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN UINT8          StatusIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  UINT32               StatusRegister;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read the status register
 | 
						|
  //
 | 
						|
  PciIo  = &PciIoDevice->PciIo;
 | 
						|
  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the Fast B2B bit
 | 
						|
  //
 | 
						|
  if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process the option ROM for all the children of the specified parent PCI device.
 | 
						|
  It can only be used after the first full Option ROM process.
 | 
						|
 | 
						|
  @param PciIoDevice Pci device instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
ProcessOptionRomLight (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_IO_DEVICE  *Temp;
 | 
						|
  LIST_ENTRY     *CurrentLink;
 | 
						|
 | 
						|
  //
 | 
						|
  // For RootBridge, PPB , P2C, go recursively to traverse all its children
 | 
						|
  //
 | 
						|
  CurrentLink = PciIoDevice->ChildList.ForwardLink;
 | 
						|
  while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
 | 
						|
    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
 | 
						|
 | 
						|
    if (!IsListEmpty (&Temp->ChildList)) {
 | 
						|
      ProcessOptionRomLight (Temp);
 | 
						|
    }
 | 
						|
 | 
						|
    Temp->AllOpRomProcessed = PciRomGetImageMapping (Temp);
 | 
						|
 | 
						|
    CurrentLink = CurrentLink->ForwardLink;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Determine the related attributes of all devices under a Root Bridge.
 | 
						|
 | 
						|
  @param PciIoDevice   PCI device instance.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DetermineDeviceAttribute (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16         Command;
 | 
						|
  UINT16         BridgeControl;
 | 
						|
  UINT16         OldCommand;
 | 
						|
  UINT16         OldBridgeControl;
 | 
						|
  BOOLEAN        FastB2BSupport;
 | 
						|
  PCI_IO_DEVICE  *Temp;
 | 
						|
  LIST_ENTRY     *CurrentLink;
 | 
						|
  EFI_STATUS     Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // For Root Bridge, just copy it by RootBridgeIo protocol
 | 
						|
  // so as to keep consistent with the actual attribute
 | 
						|
  //
 | 
						|
  if (PciIoDevice->Parent == NULL) {
 | 
						|
    Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
 | 
						|
                                             PciIoDevice->PciRootBridgeIo,
 | 
						|
                                             &PciIoDevice->Supports,
 | 
						|
                                             &PciIoDevice->Attributes
 | 
						|
                                             );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Assume the PCI Root Bridge supports DAC
 | 
						|
    //
 | 
						|
    PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
 | 
						|
                                      EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
 | 
						|
                                      EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Set the attributes to be checked for common PCI devices and PPB or P2C
 | 
						|
    // Since some devices only support part of them, it is better to set the
 | 
						|
    // attribute according to its command or bridge control register
 | 
						|
    //
 | 
						|
    Command = EFI_PCI_COMMAND_IO_SPACE     |
 | 
						|
              EFI_PCI_COMMAND_MEMORY_SPACE |
 | 
						|
              EFI_PCI_COMMAND_BUS_MASTER   |
 | 
						|
              EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
 | 
						|
 | 
						|
    BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
 | 
						|
 | 
						|
    //
 | 
						|
    // Test whether the device can support attributes above
 | 
						|
    //
 | 
						|
    PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
 | 
						|
 | 
						|
    //
 | 
						|
    // Set the supported attributes for specified PCI device
 | 
						|
    //
 | 
						|
    PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
 | 
						|
 | 
						|
    //
 | 
						|
    // Set the current attributes for specified PCI device
 | 
						|
    //
 | 
						|
    PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
 | 
						|
 | 
						|
    //
 | 
						|
    // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL
 | 
						|
    // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.
 | 
						|
    if (!PciIoDevice->IsPciExp) {
 | 
						|
      PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FastB2BSupport = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // P2C can not support FB2B on the secondary side
 | 
						|
  //
 | 
						|
  if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
 | 
						|
    FastB2BSupport = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // For RootBridge, PPB , P2C, go recursively to traverse all its children
 | 
						|
  //
 | 
						|
  CurrentLink = PciIoDevice->ChildList.ForwardLink;
 | 
						|
  while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
 | 
						|
    Temp   = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
 | 
						|
    Status = DetermineDeviceAttribute (Temp);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Detect Fast Back to Back support for the device under the bridge
 | 
						|
    //
 | 
						|
    Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
 | 
						|
    if (FastB2BSupport && EFI_ERROR (Status)) {
 | 
						|
      FastB2BSupport = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    CurrentLink = CurrentLink->ForwardLink;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Set or clear Fast Back to Back bit for the whole bridge
 | 
						|
  //
 | 
						|
  if (!IsListEmpty (&PciIoDevice->ChildList)) {
 | 
						|
    if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
 | 
						|
      Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
 | 
						|
 | 
						|
      if (EFI_ERROR (Status) || (!FastB2BSupport)) {
 | 
						|
        FastB2BSupport = FALSE;
 | 
						|
        PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
 | 
						|
      } else {
 | 
						|
        PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    CurrentLink = PciIoDevice->ChildList.ForwardLink;
 | 
						|
    while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
 | 
						|
      Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
 | 
						|
      if (FastB2BSupport) {
 | 
						|
        PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
 | 
						|
      } else {
 | 
						|
        PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
 | 
						|
      }
 | 
						|
 | 
						|
      CurrentLink = CurrentLink->ForwardLink;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // End for IsListEmpty
 | 
						|
  //
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is used to update the bar information for those incompatible PCI device.
 | 
						|
 | 
						|
  @param PciIoDevice      Input Pci device instance. Output Pci device instance with updated
 | 
						|
                          Bar information.
 | 
						|
  @param IgnoreOptionRom  Output If the option rom of incompatible device need to be ignored.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     Successfully updated bar information.
 | 
						|
  @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UpdatePciInfo (
 | 
						|
  IN OUT PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  OUT BOOLEAN           *IgnoreOptionRom
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  UINTN                              BarIndex;
 | 
						|
  BOOLEAN                            SetFlag;
 | 
						|
  VOID                               *Configuration;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Ptr;
 | 
						|
 | 
						|
  Configuration = NULL;
 | 
						|
  Status        = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (gIncompatiblePciDeviceSupport == NULL) {
 | 
						|
    //
 | 
						|
    // It can only be supported after the Incompatible PCI Device
 | 
						|
    // Support Protocol has been installed
 | 
						|
    //
 | 
						|
    Status = gBS->LocateProtocol (
 | 
						|
                    &gEfiIncompatiblePciDeviceSupportProtocolGuid,
 | 
						|
                    NULL,
 | 
						|
                    (VOID **)&gIncompatiblePciDeviceSupport
 | 
						|
                    );
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
    //
 | 
						|
    // Check whether the device belongs to incompatible devices from protocol or not
 | 
						|
    // If it is , then get its special requirement in the ACPI table
 | 
						|
    //
 | 
						|
    Status = gIncompatiblePciDeviceSupport->CheckDevice (
 | 
						|
                                              gIncompatiblePciDeviceSupport,
 | 
						|
                                              PciIoDevice->Pci.Hdr.VendorId,
 | 
						|
                                              PciIoDevice->Pci.Hdr.DeviceId,
 | 
						|
                                              PciIoDevice->Pci.Hdr.RevisionID,
 | 
						|
                                              PciIoDevice->Pci.Device.SubsystemVendorID,
 | 
						|
                                              PciIoDevice->Pci.Device.SubsystemID,
 | 
						|
                                              &Configuration
 | 
						|
                                              );
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status) || (Configuration == NULL)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update PCI device information from the ACPI table
 | 
						|
  //
 | 
						|
  Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
 | 
						|
 | 
						|
  while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
 | 
						|
    if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
 | 
						|
      //
 | 
						|
      // The format is not support
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // According to "Table 20. ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage"
 | 
						|
    // in PI Spec 1.7, Type-specific flags can be set to 0 when Address Translation
 | 
						|
    // Offset == 6 to skip device option ROM (do not probe option rom BAR).
 | 
						|
    //
 | 
						|
    if (((Ptr->AddrTranslationOffset == PCI_MAX_BAR) && (Ptr->SpecificFlag == 0))) {
 | 
						|
      *IgnoreOptionRom = TRUE;
 | 
						|
      Ptr++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
 | 
						|
      if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&
 | 
						|
          (Ptr->AddrTranslationOffset != MAX_UINT8) &&
 | 
						|
          (Ptr->AddrTranslationOffset != BarIndex)
 | 
						|
          )
 | 
						|
      {
 | 
						|
        //
 | 
						|
        // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).
 | 
						|
        // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.
 | 
						|
        // Comparing against MAX_UINT8 is to keep backward compatibility.
 | 
						|
        //
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      SetFlag = FALSE;
 | 
						|
      switch (Ptr->ResType) {
 | 
						|
        case ACPI_ADDRESS_SPACE_TYPE_MEM:
 | 
						|
 | 
						|
          //
 | 
						|
          // Make sure the bar is memory type
 | 
						|
          //
 | 
						|
          if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeMem)) {
 | 
						|
            SetFlag = TRUE;
 | 
						|
 | 
						|
            //
 | 
						|
            // Ignored if granularity is 0.
 | 
						|
            // Ignored if PCI BAR is I/O or 32-bit memory.
 | 
						|
            // If PCI BAR is 64-bit memory and granularity is 32, then
 | 
						|
            // the PCI BAR resource is allocated below 4GB.
 | 
						|
            // If PCI BAR is 64-bit memory and granularity is 64, then
 | 
						|
            // the PCI BAR resource is allocated above 4GB.
 | 
						|
            //
 | 
						|
            if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {
 | 
						|
              switch (Ptr->AddrSpaceGranularity) {
 | 
						|
                case 32:
 | 
						|
                  PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
 | 
						|
                case 64:
 | 
						|
                  PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
 | 
						|
                  break;
 | 
						|
                default:
 | 
						|
                  break;
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {
 | 
						|
              switch (Ptr->AddrSpaceGranularity) {
 | 
						|
                case 32:
 | 
						|
                  PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
 | 
						|
                case 64:
 | 
						|
                  PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
 | 
						|
                  break;
 | 
						|
                default:
 | 
						|
                  break;
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          break;
 | 
						|
 | 
						|
        case ACPI_ADDRESS_SPACE_TYPE_IO:
 | 
						|
 | 
						|
          //
 | 
						|
          // Make sure the bar is IO type
 | 
						|
          //
 | 
						|
          if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeIo)) {
 | 
						|
            SetFlag = TRUE;
 | 
						|
          }
 | 
						|
 | 
						|
          break;
 | 
						|
      }
 | 
						|
 | 
						|
      if (SetFlag) {
 | 
						|
        //
 | 
						|
        // Update the new alignment for the device
 | 
						|
        //
 | 
						|
        SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
 | 
						|
 | 
						|
        //
 | 
						|
        // Update the new length for the device
 | 
						|
        //
 | 
						|
        if (Ptr->AddrLen != 0) {
 | 
						|
          PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    Ptr++;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Configuration);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine will update the alignment with the new alignment.
 | 
						|
  Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep
 | 
						|
  backward compatibility.
 | 
						|
 | 
						|
  @param Alignment    Input Old alignment. Output updated alignment.
 | 
						|
  @param NewAlignment New alignment.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetNewAlign (
 | 
						|
  IN OUT UINT64  *Alignment,
 | 
						|
  IN     UINT64  NewAlignment
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64  OldAlignment;
 | 
						|
  UINTN   ShiftBit;
 | 
						|
 | 
						|
  //
 | 
						|
  // The new alignment is the same as the original,
 | 
						|
  // so skip it
 | 
						|
  //
 | 
						|
  if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the validity of the parameter
 | 
						|
  //
 | 
						|
  if ((NewAlignment != EVEN_ALIGN) &&
 | 
						|
      (NewAlignment != SQUAD_ALIGN) &&
 | 
						|
      (NewAlignment != DQUAD_ALIGN))
 | 
						|
  {
 | 
						|
    *Alignment = NewAlignment;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  OldAlignment = (*Alignment) + 1;
 | 
						|
  ShiftBit     = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the first non-zero hex value of the length
 | 
						|
  //
 | 
						|
  while ((OldAlignment & 0x0F) == 0x00) {
 | 
						|
    OldAlignment = RShiftU64 (OldAlignment, 4);
 | 
						|
    ShiftBit    += 4;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Adjust the alignment to even, quad or double quad boundary
 | 
						|
  //
 | 
						|
  if (NewAlignment == EVEN_ALIGN) {
 | 
						|
    if ((OldAlignment & 0x01) != 0) {
 | 
						|
      OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
 | 
						|
    }
 | 
						|
  } else if (NewAlignment == SQUAD_ALIGN) {
 | 
						|
    if ((OldAlignment & 0x03) != 0) {
 | 
						|
      OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
 | 
						|
    }
 | 
						|
  } else if (NewAlignment == DQUAD_ALIGN) {
 | 
						|
    if ((OldAlignment & 0x07) != 0) {
 | 
						|
      OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the old value
 | 
						|
  //
 | 
						|
  NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
 | 
						|
  *Alignment   = NewAlignment;
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parse PCI IOV VF bar information and fill them into PCI device instance.
 | 
						|
 | 
						|
  @param PciIoDevice  Pci device instance.
 | 
						|
  @param Offset       Bar offset.
 | 
						|
  @param BarIndex     Bar index.
 | 
						|
 | 
						|
  @return Next bar offset.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
PciIovParseVfBar (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN UINTN          Offset,
 | 
						|
  IN UINTN          BarIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32      Value;
 | 
						|
  UINT32      OriginalValue;
 | 
						|
  UINT32      Mask;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Ensure it is called properly
 | 
						|
  //
 | 
						|
  ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
 | 
						|
  if (PciIoDevice->SrIovCapabilityOffset == 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  OriginalValue = 0;
 | 
						|
  Value         = 0;
 | 
						|
 | 
						|
  Status = VfBarExisted (
 | 
						|
             PciIoDevice,
 | 
						|
             Offset,
 | 
						|
             &Value,
 | 
						|
             &OriginalValue
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].Length      = 0;
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].Alignment   = 0;
 | 
						|
 | 
						|
    //
 | 
						|
    // Scan all the BARs anyway
 | 
						|
    //
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;
 | 
						|
    return Offset + 4;
 | 
						|
  }
 | 
						|
 | 
						|
  PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;
 | 
						|
  if ((Value & 0x01) != 0) {
 | 
						|
    //
 | 
						|
    // Device I/Os. Impossible
 | 
						|
    //
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return Offset + 4;
 | 
						|
  } else {
 | 
						|
    Mask = 0xfffffff0;
 | 
						|
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;
 | 
						|
 | 
						|
    switch (Value & 0x07) {
 | 
						|
      //
 | 
						|
      // memory space; anywhere in 32 bit address space
 | 
						|
      //
 | 
						|
      case 0x00:
 | 
						|
        if ((Value & 0x08) != 0) {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;
 | 
						|
        } else {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;
 | 
						|
        }
 | 
						|
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Length    = (~(Value & Mask)) + 1;
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
 | 
						|
 | 
						|
        //
 | 
						|
        // Adjust Length
 | 
						|
        //
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
 | 
						|
        //
 | 
						|
        // Adjust Alignment
 | 
						|
        //
 | 
						|
        if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      //
 | 
						|
      // memory space; anywhere in 64 bit address space
 | 
						|
      //
 | 
						|
      case 0x04:
 | 
						|
        if ((Value & 0x08) != 0) {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;
 | 
						|
        } else {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
 | 
						|
        // is regarded as an extension for the first bar. As a result
 | 
						|
        // the sizing will be conducted on combined 64 bit value
 | 
						|
        // Here just store the masked first 32bit value for future size
 | 
						|
        // calculation
 | 
						|
        //
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Length    = Value & Mask;
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
 | 
						|
 | 
						|
        if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Increment the offset to point to next DWORD
 | 
						|
        //
 | 
						|
        Offset += 4;
 | 
						|
 | 
						|
        Status = VfBarExisted (
 | 
						|
                   PciIoDevice,
 | 
						|
                   Offset,
 | 
						|
                   &Value,
 | 
						|
                   &OriginalValue
 | 
						|
                   );
 | 
						|
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
 | 
						|
          return Offset + 4;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Fix the length to support some special 64 bit BAR
 | 
						|
        //
 | 
						|
        Value |= ((UINT32)-1 << HighBitSet32 (Value));
 | 
						|
 | 
						|
        //
 | 
						|
        // Calculate the size of 64bit bar
 | 
						|
        //
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);
 | 
						|
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Length    = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Length    = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
 | 
						|
 | 
						|
        //
 | 
						|
        // Adjust Length
 | 
						|
        //
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
 | 
						|
        //
 | 
						|
        // Adjust Alignment
 | 
						|
        //
 | 
						|
        if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      //
 | 
						|
      // reserved
 | 
						|
      //
 | 
						|
      default:
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].BarType   = PciBarTypeUnknown;
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Length    = (~(Value & Mask)) + 1;
 | 
						|
        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
 | 
						|
 | 
						|
        if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
 | 
						|
          PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the length again so as to keep compatible with some special bars
 | 
						|
  //
 | 
						|
  if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].BarType     = PciBarTypeUnknown;
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
 | 
						|
    PciIoDevice->VfPciBar[BarIndex].Alignment   = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Increment number of bar
 | 
						|
  //
 | 
						|
  return Offset + 4;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parse PCI bar information and fill them into PCI device instance.
 | 
						|
 | 
						|
  @param PciIoDevice  Pci device instance.
 | 
						|
  @param Offset       Bar offset.
 | 
						|
  @param BarIndex     Bar index.
 | 
						|
 | 
						|
  @return Next bar offset.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
PciParseBar (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice,
 | 
						|
  IN UINTN          Offset,
 | 
						|
  IN UINTN          BarIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32      Value;
 | 
						|
  UINT32      OriginalValue;
 | 
						|
  UINT32      Mask;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  OriginalValue = 0;
 | 
						|
  Value         = 0;
 | 
						|
 | 
						|
  Status = BarExisted (
 | 
						|
             PciIoDevice,
 | 
						|
             Offset,
 | 
						|
             &Value,
 | 
						|
             &OriginalValue
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
 | 
						|
    PciIoDevice->PciBar[BarIndex].Length      = 0;
 | 
						|
    PciIoDevice->PciBar[BarIndex].Alignment   = 0;
 | 
						|
 | 
						|
    //
 | 
						|
    // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
 | 
						|
    //
 | 
						|
    PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset;
 | 
						|
    return Offset + 4;
 | 
						|
  }
 | 
						|
 | 
						|
  PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;
 | 
						|
  PciIoDevice->PciBar[BarIndex].Offset       = (UINT8)Offset;
 | 
						|
  if ((Value & 0x01) != 0) {
 | 
						|
    //
 | 
						|
    // Device I/Os
 | 
						|
    //
 | 
						|
    Mask = 0xfffffffc;
 | 
						|
 | 
						|
    if ((Value & 0xFFFF0000) != 0) {
 | 
						|
      //
 | 
						|
      // It is a IO32 bar
 | 
						|
      //
 | 
						|
      PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo32;
 | 
						|
      PciIoDevice->PciBar[BarIndex].Length    = ((~(Value & Mask)) + 1);
 | 
						|
      PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // It is a IO16 bar
 | 
						|
      //
 | 
						|
      PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo16;
 | 
						|
      PciIoDevice->PciBar[BarIndex].Length    = 0x0000FFFF & ((~(Value & Mask)) + 1);
 | 
						|
      PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Workaround. Some platforms implement IO bar with 0 length
 | 
						|
    // Need to treat it as no-bar
 | 
						|
    //
 | 
						|
    if (PciIoDevice->PciBar[BarIndex].Length == 0) {
 | 
						|
      PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE)0;
 | 
						|
    }
 | 
						|
 | 
						|
    PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
 | 
						|
  } else {
 | 
						|
    Mask = 0xfffffff0;
 | 
						|
 | 
						|
    PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
 | 
						|
 | 
						|
    switch (Value & 0x07) {
 | 
						|
      //
 | 
						|
      // memory space; anywhere in 32 bit address space
 | 
						|
      //
 | 
						|
      case 0x00:
 | 
						|
        if ((Value & 0x08) != 0) {
 | 
						|
          PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
 | 
						|
        } else {
 | 
						|
          PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
 | 
						|
        }
 | 
						|
 | 
						|
        PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
 | 
						|
        if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
 | 
						|
          //
 | 
						|
          // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
 | 
						|
          //
 | 
						|
          PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
 | 
						|
        } else {
 | 
						|
          PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      //
 | 
						|
      // memory space; anywhere in 64 bit address space
 | 
						|
      //
 | 
						|
      case 0x04:
 | 
						|
        if ((Value & 0x08) != 0) {
 | 
						|
          PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
 | 
						|
        } else {
 | 
						|
          PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
 | 
						|
        // is regarded as an extension for the first bar. As a result
 | 
						|
        // the sizing will be conducted on combined 64 bit value
 | 
						|
        // Here just store the masked first 32bit value for future size
 | 
						|
        // calculation
 | 
						|
        //
 | 
						|
        PciIoDevice->PciBar[BarIndex].Length    = Value & Mask;
 | 
						|
        PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
 | 
						|
 | 
						|
        //
 | 
						|
        // Increment the offset to point to next DWORD
 | 
						|
        //
 | 
						|
        Offset += 4;
 | 
						|
 | 
						|
        Status = BarExisted (
 | 
						|
                   PciIoDevice,
 | 
						|
                   Offset,
 | 
						|
                   &Value,
 | 
						|
                   &OriginalValue
 | 
						|
                   );
 | 
						|
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          //
 | 
						|
          // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
 | 
						|
          //
 | 
						|
          if (PciIoDevice->PciBar[BarIndex].Length == 0) {
 | 
						|
            //
 | 
						|
            // some device implement MMIO bar with 0 length, need to treat it as no-bar
 | 
						|
            //
 | 
						|
            PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
 | 
						|
            return Offset + 4;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Fix the length to support some special 64 bit BAR
 | 
						|
        //
 | 
						|
        if (Value == 0) {
 | 
						|
          DEBUG ((DEBUG_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));
 | 
						|
          Value = (UINT32)-1;
 | 
						|
        } else {
 | 
						|
          Value |= ((UINT32)(-1) << HighBitSet32 (Value));
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Calculate the size of 64bit bar
 | 
						|
        //
 | 
						|
        PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);
 | 
						|
 | 
						|
        PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);
 | 
						|
        PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
 | 
						|
        if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
 | 
						|
          //
 | 
						|
          // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
 | 
						|
          //
 | 
						|
          PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
 | 
						|
        } else {
 | 
						|
          PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      //
 | 
						|
      // reserved
 | 
						|
      //
 | 
						|
      default:
 | 
						|
        PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
 | 
						|
        PciIoDevice->PciBar[BarIndex].Length  = (~(Value & Mask)) + 1;
 | 
						|
        if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
 | 
						|
          //
 | 
						|
          // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
 | 
						|
          //
 | 
						|
          PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
 | 
						|
        } else {
 | 
						|
          PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the length again so as to keep compatible with some special bars
 | 
						|
  //
 | 
						|
  if (PciIoDevice->PciBar[BarIndex].Length == 0) {
 | 
						|
    PciIoDevice->PciBar[BarIndex].BarType     = PciBarTypeUnknown;
 | 
						|
    PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
 | 
						|
    PciIoDevice->PciBar[BarIndex].Alignment   = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Increment number of bar
 | 
						|
  //
 | 
						|
  return Offset + 4;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is used to initialize the bar of a PCI device.
 | 
						|
 | 
						|
  @param PciIoDevice Pci device instance.
 | 
						|
 | 
						|
  @note It can be called typically when a device is going to be rejected.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitializePciDevice (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
  UINT8                Offset;
 | 
						|
 | 
						|
  PciIo = &(PciIoDevice->PciIo);
 | 
						|
 | 
						|
  //
 | 
						|
  // Put all the resource apertures
 | 
						|
  // Resource base is set to all ones so as to indicate its resource
 | 
						|
  // has not been allocated
 | 
						|
  //
 | 
						|
  for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
 | 
						|
    PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is used to initialize the bar of a PCI-PCI Bridge device.
 | 
						|
 | 
						|
  @param  PciIoDevice PCI-PCI bridge device instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitializePpb (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
 | 
						|
  PciIo = &(PciIoDevice->PciIo);
 | 
						|
 | 
						|
  //
 | 
						|
  // Put all the resource apertures including IO16
 | 
						|
  // Io32, pMem32, pMem64 to quiescent state
 | 
						|
  // Resource base all ones, Resource limit all zeros
 | 
						|
  //
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
 | 
						|
 | 
						|
  //
 | 
						|
  // Don't support use io32 as for now
 | 
						|
  //
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
 | 
						|
 | 
						|
  //
 | 
						|
  // Force Interrupt line to zero for cards that come up randomly
 | 
						|
  //
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is used to initialize the bar of a PCI Card Bridge device.
 | 
						|
 | 
						|
  @param PciIoDevice  PCI Card bridge device.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitializeP2C (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
 | 
						|
  PciIo = &(PciIoDevice->PciIo);
 | 
						|
 | 
						|
  //
 | 
						|
  // Put all the resource apertures including IO16
 | 
						|
  // Io32, pMem32, pMem64 to quiescent state(
 | 
						|
  // Resource base all ones, Resource limit all zeros
 | 
						|
  //
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
 | 
						|
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
 | 
						|
 | 
						|
  //
 | 
						|
  // Force Interrupt line to zero for cards that come up randomly
 | 
						|
  //
 | 
						|
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Authenticate the PCI device by using DeviceSecurityProtocol.
 | 
						|
 | 
						|
  @param PciIoDevice  PCI device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The device passes the authentication.
 | 
						|
  @return not EFI_SUCCESS The device failes the authentication or
 | 
						|
                          unexpected error happen during authentication.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AuthenticatePciDevice (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EDKII_DEVICE_IDENTIFIER  DeviceIdentifier;
 | 
						|
  EFI_STATUS               Status;
 | 
						|
 | 
						|
  if (mDeviceSecurityProtocol != NULL) {
 | 
						|
    //
 | 
						|
    // Prepare the parameter
 | 
						|
    //
 | 
						|
    DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;
 | 
						|
    CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid);
 | 
						|
    DeviceIdentifier.DeviceHandle = NULL;
 | 
						|
    Status                        = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                                           &DeviceIdentifier.DeviceHandle,
 | 
						|
                                           &gEfiDevicePathProtocolGuid,
 | 
						|
                                           PciIoDevice->DevicePath,
 | 
						|
                                           &gEdkiiDeviceIdentifierTypePciGuid,
 | 
						|
                                           &PciIoDevice->PciIo,
 | 
						|
                                           NULL
 | 
						|
                                           );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Do DeviceAuthentication
 | 
						|
    //
 | 
						|
    Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier);
 | 
						|
    //
 | 
						|
    // Always uninstall, because they are only for Authentication.
 | 
						|
    // No need to check return Status.
 | 
						|
    //
 | 
						|
    gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
           DeviceIdentifier.DeviceHandle,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           PciIoDevice->DevicePath,
 | 
						|
           &gEdkiiDeviceIdentifierTypePciGuid,
 | 
						|
           &PciIoDevice->PciIo,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Device Security Protocol is not found, just return success
 | 
						|
  //
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Checks if PCI device is Root Bridge.
 | 
						|
 | 
						|
  @param PciIoDevice       Instance of PCI device
 | 
						|
 | 
						|
  @retval TRUE             Device is Root Bridge
 | 
						|
  @retval FALSE            Device is not Root Bridge
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsRootBridge (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (PciIoDevice->Parent == NULL) {
 | 
						|
    return TRUE;
 | 
						|
  } else {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create and initialize general PCI I/O device instance for
 | 
						|
  PCI device/bridge device/hotplug bridge device.
 | 
						|
 | 
						|
  @param Bridge            Parent bridge instance.
 | 
						|
  @param Pci               Input Pci information block.
 | 
						|
  @param Bus               Device Bus NO.
 | 
						|
  @param Device            Device device NO.
 | 
						|
  @param Func              Device func NO.
 | 
						|
 | 
						|
  @return Instance of PCI device. NULL means no instance created.
 | 
						|
 | 
						|
**/
 | 
						|
PCI_IO_DEVICE *
 | 
						|
CreatePciIoDevice (
 | 
						|
  IN PCI_IO_DEVICE  *Bridge,
 | 
						|
  IN PCI_TYPE00     *Pci,
 | 
						|
  IN UINT8          Bus,
 | 
						|
  IN UINT8          Device,
 | 
						|
  IN UINT8          Func
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_IO_DEVICE        *PciIoDevice;
 | 
						|
  EFI_PCI_IO_PROTOCOL  *PciIo;
 | 
						|
  EFI_STATUS           Status;
 | 
						|
 | 
						|
  PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
 | 
						|
  if (PciIoDevice == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  PciIoDevice->Signature       = PCI_IO_DEVICE_SIGNATURE;
 | 
						|
  PciIoDevice->Handle          = NULL;
 | 
						|
  PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;
 | 
						|
  PciIoDevice->DevicePath      = NULL;
 | 
						|
  PciIoDevice->BusNumber       = Bus;
 | 
						|
  PciIoDevice->DeviceNumber    = Device;
 | 
						|
  PciIoDevice->FunctionNumber  = Func;
 | 
						|
  PciIoDevice->Decodes         = 0;
 | 
						|
 | 
						|
  if (gFullEnumeration) {
 | 
						|
    PciIoDevice->Allocated = FALSE;
 | 
						|
  } else {
 | 
						|
    PciIoDevice->Allocated = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  PciIoDevice->Registered        = FALSE;
 | 
						|
  PciIoDevice->Attributes        = 0;
 | 
						|
  PciIoDevice->Supports          = 0;
 | 
						|
  PciIoDevice->BusOverride       = FALSE;
 | 
						|
  PciIoDevice->AllOpRomProcessed = FALSE;
 | 
						|
 | 
						|
  PciIoDevice->IsPciExp = FALSE;
 | 
						|
 | 
						|
  CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the PCI I/O instance structure
 | 
						|
  //
 | 
						|
  InitializePciIoInstance (PciIoDevice);
 | 
						|
  InitializePciDriverOverrideInstance (PciIoDevice);
 | 
						|
  InitializePciLoadFile2 (PciIoDevice);
 | 
						|
  PciIo = &PciIoDevice->PciIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a device path for this PCI device and store it into its private data
 | 
						|
  //
 | 
						|
  CreatePciDevicePath (
 | 
						|
    Bridge->DevicePath,
 | 
						|
    PciIoDevice
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Detect if PCI Express Device
 | 
						|
  //
 | 
						|
  PciIoDevice->PciExpressCapabilityOffset = 0;
 | 
						|
  Status                                  = LocateCapabilityRegBlock (
 | 
						|
                                              PciIoDevice,
 | 
						|
                                              EFI_PCI_CAPABILITY_ID_PCIEXP,
 | 
						|
                                              &PciIoDevice->PciExpressCapabilityOffset,
 | 
						|
                                              NULL
 | 
						|
                                              );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    PciIoDevice->IsPciExp = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Now we can do the authentication check for the device.
 | 
						|
  //
 | 
						|
  Status = AuthenticatePciDevice (PciIoDevice);
 | 
						|
  //
 | 
						|
  // If authentication fails, skip this device.
 | 
						|
  //
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    if (PciIoDevice->DevicePath != NULL) {
 | 
						|
      FreePool (PciIoDevice->DevicePath);
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (PciIoDevice);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if device's parent is not Root Bridge
 | 
						|
  //
 | 
						|
  if (PcdGetBool (PcdAriSupport) && !IsRootBridge (Bridge)) {
 | 
						|
    //
 | 
						|
    // Check if the device is an ARI device.
 | 
						|
    //
 | 
						|
    Status = LocatePciExpressCapabilityRegBlock (
 | 
						|
               PciIoDevice,
 | 
						|
               EFI_PCIE_CAPABILITY_ID_ARI,
 | 
						|
               &PciIoDevice->AriCapabilityOffset,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // We need to enable ARI feature before calculate BusReservation,
 | 
						|
      // because FirstVFOffset and VFStride may change after that.
 | 
						|
      //
 | 
						|
      EFI_PCI_IO_PROTOCOL  *ParentPciIo;
 | 
						|
      UINT32               Data32;
 | 
						|
 | 
						|
      //
 | 
						|
      // Check if its parent supports ARI forwarding.
 | 
						|
      //
 | 
						|
      ParentPciIo = &Bridge->PciIo;
 | 
						|
      ParentPciIo->Pci.Read (
 | 
						|
                         ParentPciIo,
 | 
						|
                         EfiPciIoWidthUint32,
 | 
						|
                         Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,
 | 
						|
                         1,
 | 
						|
                         &Data32
 | 
						|
                         );
 | 
						|
      if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {
 | 
						|
        PciIoDevice->IsAriEnabled = TRUE;
 | 
						|
        //
 | 
						|
        // ARI forward support in bridge, so enable it.
 | 
						|
        //
 | 
						|
        ParentPciIo->Pci.Read (
 | 
						|
                           ParentPciIo,
 | 
						|
                           EfiPciIoWidthUint32,
 | 
						|
                           Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
 | 
						|
                           1,
 | 
						|
                           &Data32
 | 
						|
                           );
 | 
						|
        if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {
 | 
						|
          Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
 | 
						|
          ParentPciIo->Pci.Write (
 | 
						|
                             ParentPciIo,
 | 
						|
                             EfiPciIoWidthUint32,
 | 
						|
                             Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
 | 
						|
                             1,
 | 
						|
                             &Data32
 | 
						|
                             );
 | 
						|
          DEBUG ((
 | 
						|
            DEBUG_INFO,
 | 
						|
            " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
 | 
						|
            Bridge->BusNumber,
 | 
						|
            Bridge->DeviceNumber,
 | 
						|
            Bridge->FunctionNumber
 | 
						|
            ));
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      DEBUG ((DEBUG_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialization for SR-IOV
 | 
						|
  //
 | 
						|
 | 
						|
  if (PcdGetBool (PcdSrIovSupport)) {
 | 
						|
    Status = LocatePciExpressCapabilityRegBlock (
 | 
						|
               PciIoDevice,
 | 
						|
               EFI_PCIE_CAPABILITY_ID_SRIOV,
 | 
						|
               &PciIoDevice->SrIovCapabilityOffset,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      UINT32  SupportedPageSize;
 | 
						|
      UINT16  VFStride;
 | 
						|
      UINT16  FirstVFOffset;
 | 
						|
      UINT16  Data16;
 | 
						|
      UINT32  PFRid;
 | 
						|
      UINT32  LastVF;
 | 
						|
 | 
						|
      //
 | 
						|
      // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
 | 
						|
      //
 | 
						|
      if (PcdGetBool (PcdAriSupport) && (PciIoDevice->AriCapabilityOffset != 0)) {
 | 
						|
        PciIo->Pci.Read (
 | 
						|
                     PciIo,
 | 
						|
                     EfiPciIoWidthUint16,
 | 
						|
                     PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
 | 
						|
                     1,
 | 
						|
                     &Data16
 | 
						|
                     );
 | 
						|
        Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;
 | 
						|
        PciIo->Pci.Write (
 | 
						|
                     PciIo,
 | 
						|
                     EfiPciIoWidthUint16,
 | 
						|
                     PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
 | 
						|
                     1,
 | 
						|
                     &Data16
 | 
						|
                     );
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Calculate SystemPageSize
 | 
						|
      //
 | 
						|
 | 
						|
      PciIo->Pci.Read (
 | 
						|
                   PciIo,
 | 
						|
                   EfiPciIoWidthUint32,
 | 
						|
                   PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
 | 
						|
                   1,
 | 
						|
                   &SupportedPageSize
 | 
						|
                   );
 | 
						|
      PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);
 | 
						|
      ASSERT (PciIoDevice->SystemPageSize != 0);
 | 
						|
 | 
						|
      PciIo->Pci.Write (
 | 
						|
                   PciIo,
 | 
						|
                   EfiPciIoWidthUint32,
 | 
						|
                   PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
 | 
						|
                   1,
 | 
						|
                   &PciIoDevice->SystemPageSize
 | 
						|
                   );
 | 
						|
      //
 | 
						|
      // Adjust SystemPageSize for Alignment usage later
 | 
						|
      //
 | 
						|
      PciIoDevice->SystemPageSize <<= 12;
 | 
						|
 | 
						|
      //
 | 
						|
      // Calculate BusReservation for PCI IOV
 | 
						|
      //
 | 
						|
 | 
						|
      //
 | 
						|
      // Read First FirstVFOffset, InitialVFs, and VFStride
 | 
						|
      //
 | 
						|
      PciIo->Pci.Read (
 | 
						|
                   PciIo,
 | 
						|
                   EfiPciIoWidthUint16,
 | 
						|
                   PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
 | 
						|
                   1,
 | 
						|
                   &FirstVFOffset
 | 
						|
                   );
 | 
						|
      PciIo->Pci.Read (
 | 
						|
                   PciIo,
 | 
						|
                   EfiPciIoWidthUint16,
 | 
						|
                   PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
 | 
						|
                   1,
 | 
						|
                   &PciIoDevice->InitialVFs
 | 
						|
                   );
 | 
						|
      PciIo->Pci.Read (
 | 
						|
                   PciIo,
 | 
						|
                   EfiPciIoWidthUint16,
 | 
						|
                   PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
 | 
						|
                   1,
 | 
						|
                   &VFStride
 | 
						|
                   );
 | 
						|
      //
 | 
						|
      // Calculate LastVF
 | 
						|
      //
 | 
						|
      if (PciIoDevice->InitialVFs == 0) {
 | 
						|
        PciIoDevice->ReservedBusNum = 0;
 | 
						|
      } else {
 | 
						|
        PFRid  = EFI_PCI_RID (Bus, Device, Func);
 | 
						|
        LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
 | 
						|
 | 
						|
        //
 | 
						|
        // Calculate ReservedBusNum for this PF
 | 
						|
        //
 | 
						|
        PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus);
 | 
						|
      }
 | 
						|
 | 
						|
      DEBUG ((
 | 
						|
        DEBUG_INFO,
 | 
						|
        " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
 | 
						|
        SupportedPageSize,
 | 
						|
        PciIoDevice->SystemPageSize >> 12,
 | 
						|
        FirstVFOffset
 | 
						|
        ));
 | 
						|
      DEBUG ((
 | 
						|
        DEBUG_INFO,
 | 
						|
        "         InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
 | 
						|
        PciIoDevice->InitialVFs,
 | 
						|
        PciIoDevice->ReservedBusNum,
 | 
						|
        PciIoDevice->SrIovCapabilityOffset
 | 
						|
        ));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (PcdGetBool (PcdMrIovSupport)) {
 | 
						|
    Status = LocatePciExpressCapabilityRegBlock (
 | 
						|
               PciIoDevice,
 | 
						|
               EFI_PCIE_CAPABILITY_ID_MRIOV,
 | 
						|
               &PciIoDevice->MrIovCapabilityOffset,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((DEBUG_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  PciIoDevice->ResizableBarOffset = 0;
 | 
						|
  if (PcdGetBool (PcdPcieResizableBarSupport)) {
 | 
						|
    Status = LocatePciExpressCapabilityRegBlock (
 | 
						|
               PciIoDevice,
 | 
						|
               PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID,
 | 
						|
               &PciIoDevice->ResizableBarOffset,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL  ResizableBarControl;
 | 
						|
      UINT32                                                   Offset;
 | 
						|
      Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
 | 
						|
               + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY),
 | 
						|
      PciIo->Pci.Read (
 | 
						|
                   PciIo,
 | 
						|
                   EfiPciIoWidthUint8,
 | 
						|
                   Offset,
 | 
						|
                   sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL),
 | 
						|
                   &ResizableBarControl
 | 
						|
                   );
 | 
						|
      PciIoDevice->ResizableBarNumber = ResizableBarControl.Bits.ResizableBarNumber;
 | 
						|
      PciProgramResizableBar (PciIoDevice, PciResizableBarMax);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the reserved resource list
 | 
						|
  //
 | 
						|
  InitializeListHead (&PciIoDevice->ReservedResourceList);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the driver list
 | 
						|
  //
 | 
						|
  InitializeListHead (&PciIoDevice->OptionRomDriverList);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the child list
 | 
						|
  //
 | 
						|
  InitializeListHead (&PciIoDevice->ChildList);
 | 
						|
 | 
						|
  return PciIoDevice;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is used to enumerate entire pci bus system
 | 
						|
  in a given platform.
 | 
						|
 | 
						|
  It is only called on the second start on the same Root Bridge.
 | 
						|
 | 
						|
  @param  Controller     Parent bridge handler.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    PCI enumeration finished successfully.
 | 
						|
  @retval other          Some error occurred when enumerating the pci bus system.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PciEnumeratorLight (
 | 
						|
  IN EFI_HANDLE  Controller
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL    *PciRootBridgeIo;
 | 
						|
  PCI_IO_DEVICE                      *RootBridgeDev;
 | 
						|
  UINT16                             MinBus;
 | 
						|
  UINT16                             MaxBus;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Descriptors;
 | 
						|
 | 
						|
  MinBus      = 0;
 | 
						|
  MaxBus      = PCI_MAX_BUS;
 | 
						|
  Descriptors = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // If this root bridge has been already enumerated, then return successfully
 | 
						|
  //
 | 
						|
  if (GetRootBridgeByHandle (Controller) != NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Open pci root bridge io protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiPciRootBridgeIoProtocolGuid,
 | 
						|
                  (VOID **)&PciRootBridgeIo,
 | 
						|
                  gPciBusDriverBinding.DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)&Descriptors);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
 | 
						|
    //
 | 
						|
    // Create a device node for root bridge device with a NULL host bridge controller handle
 | 
						|
    //
 | 
						|
    RootBridgeDev = CreateRootBridge (Controller);
 | 
						|
 | 
						|
    if (RootBridgeDev == NULL) {
 | 
						|
      Descriptors++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Record the root bridge-io protocol
 | 
						|
    //
 | 
						|
    RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
 | 
						|
 | 
						|
    Status = PciPciDeviceInfoCollector (
 | 
						|
               RootBridgeDev,
 | 
						|
               (UINT8)MinBus
 | 
						|
               );
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Remove those PCI devices which are rejected when full enumeration
 | 
						|
      //
 | 
						|
      RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
 | 
						|
 | 
						|
      //
 | 
						|
      // Process option rom light
 | 
						|
      //
 | 
						|
      ProcessOptionRomLight (RootBridgeDev);
 | 
						|
 | 
						|
      //
 | 
						|
      // Determine attributes for all devices under this root bridge
 | 
						|
      //
 | 
						|
      DetermineDeviceAttribute (RootBridgeDev);
 | 
						|
 | 
						|
      //
 | 
						|
      // If successfully, insert the node into device pool
 | 
						|
      //
 | 
						|
      InsertRootBridge (RootBridgeDev);
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // If unsuccessfully, destroy the entire node
 | 
						|
      //
 | 
						|
      DestroyRootBridge (RootBridgeDev);
 | 
						|
    }
 | 
						|
 | 
						|
    Descriptors++;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get bus range from PCI resource descriptor list.
 | 
						|
 | 
						|
  @param Descriptors  A pointer to the address space descriptor.
 | 
						|
  @param MinBus       The min bus returned.
 | 
						|
  @param MaxBus       The max bus returned.
 | 
						|
  @param BusRange     The bus range returned.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    Successfully got bus range.
 | 
						|
  @retval EFI_NOT_FOUND  Can not find the specific bus.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PciGetBusRange (
 | 
						|
  IN     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  **Descriptors,
 | 
						|
  OUT    UINT16                             *MinBus,
 | 
						|
  OUT    UINT16                             *MaxBus,
 | 
						|
  OUT    UINT16                             *BusRange
 | 
						|
  )
 | 
						|
{
 | 
						|
  while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
 | 
						|
    if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
 | 
						|
      if (MinBus != NULL) {
 | 
						|
        *MinBus = (UINT16)(*Descriptors)->AddrRangeMin;
 | 
						|
      }
 | 
						|
 | 
						|
      if (MaxBus != NULL) {
 | 
						|
        *MaxBus = (UINT16)(*Descriptors)->AddrRangeMax;
 | 
						|
      }
 | 
						|
 | 
						|
      if (BusRange != NULL) {
 | 
						|
        *BusRange = (UINT16)(*Descriptors)->AddrLen;
 | 
						|
      }
 | 
						|
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    (*Descriptors)++;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine can be used to start the root bridge.
 | 
						|
 | 
						|
  @param RootBridgeDev     Pci device instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS      This device started.
 | 
						|
  @retval other            Failed to get PCI Root Bridge I/O protocol.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
StartManagingRootBridge (
 | 
						|
  IN PCI_IO_DEVICE  *RootBridgeDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE                       RootBridgeHandle;
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the root bridge handle
 | 
						|
  //
 | 
						|
  RootBridgeHandle = RootBridgeDev->Handle;
 | 
						|
  PciRootBridgeIo  = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the pci root bridge io protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  RootBridgeHandle,
 | 
						|
                  &gEfiPciRootBridgeIoProtocolGuid,
 | 
						|
                  (VOID **)&PciRootBridgeIo,
 | 
						|
                  gPciBusDriverBinding.DriverBindingHandle,
 | 
						|
                  RootBridgeHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Store the PciRootBridgeIo protocol into root bridge private data
 | 
						|
  //
 | 
						|
  RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine can be used to check whether a PCI device should be rejected when light enumeration.
 | 
						|
 | 
						|
  @param PciIoDevice  Pci device instance.
 | 
						|
 | 
						|
  @retval TRUE      This device should be rejected.
 | 
						|
  @retval FALSE     This device shouldn't be rejected.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsPciDeviceRejected (
 | 
						|
  IN PCI_IO_DEVICE  *PciIoDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      TestValue;
 | 
						|
  UINT32      OldValue;
 | 
						|
  UINT32      Mask;
 | 
						|
  UINT8       BarOffset;
 | 
						|
 | 
						|
  //
 | 
						|
  // PPB should be skip!
 | 
						|
  //
 | 
						|
  if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
 | 
						|
    //
 | 
						|
    // Only test base registers for P2C
 | 
						|
    //
 | 
						|
    for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
 | 
						|
      Mask   = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
 | 
						|
      Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      TestValue = TestValue & Mask;
 | 
						|
      if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
 | 
						|
        //
 | 
						|
        // The bar isn't programed, so it should be rejected
 | 
						|
        //
 | 
						|
        return TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
 | 
						|
    //
 | 
						|
    // Test PCI devices
 | 
						|
    //
 | 
						|
    Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((TestValue & 0x01) != 0) {
 | 
						|
      //
 | 
						|
      // IO Bar
 | 
						|
      //
 | 
						|
      Mask      = 0xFFFFFFFC;
 | 
						|
      TestValue = TestValue & Mask;
 | 
						|
      if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
 | 
						|
        return TRUE;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Mem Bar
 | 
						|
      //
 | 
						|
      Mask      = 0xFFFFFFF0;
 | 
						|
      TestValue = TestValue & Mask;
 | 
						|
 | 
						|
      if ((TestValue & 0x07) == 0x04) {
 | 
						|
        //
 | 
						|
        // Mem64 or PMem64
 | 
						|
        //
 | 
						|
        BarOffset += sizeof (UINT32);
 | 
						|
        if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
 | 
						|
          //
 | 
						|
          // Test its high 32-Bit BAR
 | 
						|
          //
 | 
						|
          Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
 | 
						|
          if (TestValue == OldValue) {
 | 
						|
            return TRUE;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Mem32 or PMem32
 | 
						|
        //
 | 
						|
        if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
 | 
						|
          return TRUE;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reset all bus number from specific bridge.
 | 
						|
 | 
						|
  @param Bridge           Parent specific bridge.
 | 
						|
  @param StartBusNumber   Start bus number.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
ResetAllPpbBusNumber (
 | 
						|
  IN PCI_IO_DEVICE  *Bridge,
 | 
						|
  IN UINT8          StartBusNumber
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  PCI_TYPE00                       Pci;
 | 
						|
  UINT8                            Device;
 | 
						|
  UINT32                           Register;
 | 
						|
  UINT8                            Func;
 | 
						|
  UINT64                           Address;
 | 
						|
  UINT8                            SecondaryBus;
 | 
						|
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo;
 | 
						|
 | 
						|
  PciRootBridgeIo = Bridge->PciRootBridgeIo;
 | 
						|
 | 
						|
  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
 | 
						|
    for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
 | 
						|
      //
 | 
						|
      // Check to see whether a pci device is present
 | 
						|
      //
 | 
						|
      Status = PciDevicePresent (
 | 
						|
                 PciRootBridgeIo,
 | 
						|
                 &Pci,
 | 
						|
                 StartBusNumber,
 | 
						|
                 Device,
 | 
						|
                 Func
 | 
						|
                 );
 | 
						|
 | 
						|
      if (EFI_ERROR (Status) && (Func == 0)) {
 | 
						|
        //
 | 
						|
        // go to next device if there is no Function 0
 | 
						|
        //
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
 | 
						|
        Register = 0;
 | 
						|
        Address  = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
 | 
						|
        Status   = PciRootBridgeIo->Pci.Read (
 | 
						|
                                          PciRootBridgeIo,
 | 
						|
                                          EfiPciWidthUint32,
 | 
						|
                                          Address,
 | 
						|
                                          1,
 | 
						|
                                          &Register
 | 
						|
                                          );
 | 
						|
        SecondaryBus = (UINT8)(Register >> 8);
 | 
						|
 | 
						|
        if (SecondaryBus != 0) {
 | 
						|
          ResetAllPpbBusNumber (Bridge, SecondaryBus);
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Reset register 18h, 19h, 1Ah on PCI Bridge
 | 
						|
        //
 | 
						|
        Register &= 0xFF000000;
 | 
						|
        Status    = PciRootBridgeIo->Pci.Write (
 | 
						|
                                           PciRootBridgeIo,
 | 
						|
                                           EfiPciWidthUint32,
 | 
						|
                                           Address,
 | 
						|
                                           1,
 | 
						|
                                           &Register
 | 
						|
                                           );
 | 
						|
      }
 | 
						|
 | 
						|
      if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {
 | 
						|
        //
 | 
						|
        // Skip sub functions, this is not a multi function device
 | 
						|
        //
 | 
						|
        Func = PCI_MAX_FUNC;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |