mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-03 21:17:23 +01:00 
			
		
		
		
	https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			1597 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1597 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
 | 
						|
 | 
						|
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "PciHostBridge.h"
 | 
						|
#include "PciRootBridge.h"
 | 
						|
#include "PciHostResource.h"
 | 
						|
 | 
						|
EFI_CPU_IO2_PROTOCOL        *mCpuIo;
 | 
						|
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
 | 
						|
  L"Mem", L"I/O", L"Bus"
 | 
						|
};
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {
 | 
						|
  L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"
 | 
						|
};
 | 
						|
 | 
						|
EDKII_IOMMU_PROTOCOL        *mIoMmu;
 | 
						|
EFI_EVENT                   mIoMmuEvent;
 | 
						|
VOID                        *mIoMmuRegistration;
 | 
						|
 | 
						|
/**
 | 
						|
  This routine gets translation offset from a root bridge instance by resource type.
 | 
						|
 | 
						|
  @param RootBridge The Root Bridge Instance for the resources.
 | 
						|
  @param ResourceType The Resource Type of the translation offset.
 | 
						|
 | 
						|
  @retval The Translation Offset of the specified resource.
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
GetTranslationByResourceType (
 | 
						|
  IN  PCI_ROOT_BRIDGE_INSTANCE     *RootBridge,
 | 
						|
  IN  PCI_RESOURCE_TYPE            ResourceType
 | 
						|
  )
 | 
						|
{
 | 
						|
  switch (ResourceType) {
 | 
						|
    case TypeIo:
 | 
						|
      return RootBridge->Io.Translation;
 | 
						|
    case TypeMem32:
 | 
						|
      return RootBridge->Mem.Translation;
 | 
						|
    case TypePMem32:
 | 
						|
      return RootBridge->PMem.Translation;
 | 
						|
    case TypeMem64:
 | 
						|
      return RootBridge->MemAbove4G.Translation;
 | 
						|
    case TypePMem64:
 | 
						|
      return RootBridge->PMemAbove4G.Translation;
 | 
						|
    case TypeBus:
 | 
						|
      return RootBridge->Bus.Translation;
 | 
						|
    default:
 | 
						|
      ASSERT (FALSE);
 | 
						|
      return 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Ensure the compatibility of an IO space descriptor with the IO aperture.
 | 
						|
 | 
						|
  The IO space descriptor can come from the GCD IO space map, or it can
 | 
						|
  represent a gap between two neighboring IO space descriptors. In the latter
 | 
						|
  case, the GcdIoType field is expected to be EfiGcdIoTypeNonExistent.
 | 
						|
 | 
						|
  If the IO space descriptor already has type EfiGcdIoTypeIo, then no action is
 | 
						|
  taken -- it is by definition compatible with the aperture.
 | 
						|
 | 
						|
  Otherwise, the intersection of the IO space descriptor is calculated with the
 | 
						|
  aperture. If the intersection is the empty set (no overlap), no action is
 | 
						|
  taken; the IO space descriptor is compatible with the aperture.
 | 
						|
 | 
						|
  Otherwise, the type of the descriptor is investigated again. If the type is
 | 
						|
  EfiGcdIoTypeNonExistent (representing a gap, or a genuine descriptor with
 | 
						|
  such a type), then an attempt is made to add the intersection as IO space to
 | 
						|
  the GCD IO space map. This ensures continuity for the aperture, and the
 | 
						|
  descriptor is deemed compatible with the aperture.
 | 
						|
 | 
						|
  Otherwise, the IO space descriptor is incompatible with the IO aperture.
 | 
						|
 | 
						|
  @param[in] Base        Base address of the aperture.
 | 
						|
  @param[in] Length      Length of the aperture.
 | 
						|
  @param[in] Descriptor  The descriptor to ensure compatibility with the
 | 
						|
                         aperture for.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The descriptor is compatible. The GCD IO space
 | 
						|
                                 map may have been updated, for continuity
 | 
						|
                                 within the aperture.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The descriptor is incompatible.
 | 
						|
  @return                        Error codes from gDS->AddIoSpace().
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IntersectIoDescriptor (
 | 
						|
  IN  UINT64                            Base,
 | 
						|
  IN  UINT64                            Length,
 | 
						|
  IN  CONST EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64                                IntersectionBase;
 | 
						|
  UINT64                                IntersectionEnd;
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
 | 
						|
  if (Descriptor->GcdIoType == EfiGcdIoTypeIo) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  IntersectionBase = MAX (Base, Descriptor->BaseAddress);
 | 
						|
  IntersectionEnd = MIN (Base + Length,
 | 
						|
                      Descriptor->BaseAddress + Descriptor->Length);
 | 
						|
  if (IntersectionBase >= IntersectionEnd) {
 | 
						|
    //
 | 
						|
    // The descriptor and the aperture don't overlap.
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Descriptor->GcdIoType == EfiGcdIoTypeNonExistent) {
 | 
						|
    Status = gDS->AddIoSpace (EfiGcdIoTypeIo, IntersectionBase,
 | 
						|
                    IntersectionEnd - IntersectionBase);
 | 
						|
 | 
						|
    DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE,
 | 
						|
      "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__,
 | 
						|
      IntersectionBase, IntersectionEnd, Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u conflicts with "
 | 
						|
    "aperture [%Lx, %Lx)\n", gEfiCallerBaseName, __FUNCTION__,
 | 
						|
    Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length,
 | 
						|
    (UINT32)Descriptor->GcdIoType, Base, Base + Length));
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Add IO space to GCD.
 | 
						|
  The routine checks the GCD database and only adds those which are
 | 
						|
  not added in the specified range to GCD.
 | 
						|
 | 
						|
  @param Base   Base address of the IO space.
 | 
						|
  @param Length Length of the IO space.
 | 
						|
 | 
						|
  @retval EFI_SUCCES The IO space was added successfully.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AddIoSpace (
 | 
						|
  IN  UINT64                        Base,
 | 
						|
  IN  UINT64                        Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  UINTN                             Index;
 | 
						|
  UINTN                             NumberOfDescriptors;
 | 
						|
  EFI_GCD_IO_SPACE_DESCRIPTOR       *IoSpaceMap;
 | 
						|
 | 
						|
  Status = gDS->GetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "%a: %a: GetIoSpaceMap(): %r\n",
 | 
						|
      gEfiCallerBaseName, __FUNCTION__, Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < NumberOfDescriptors; Index++) {
 | 
						|
    Status = IntersectIoDescriptor (Base, Length, &IoSpaceMap[Index]);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto FreeIoSpaceMap;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE (
 | 
						|
    //
 | 
						|
    // Make sure there are adjacent descriptors covering [Base, Base + Length).
 | 
						|
    // It is possible that they have not been merged; merging can be prevented
 | 
						|
    // by allocation.
 | 
						|
    //
 | 
						|
    UINT64                      CheckBase;
 | 
						|
    EFI_STATUS                  CheckStatus;
 | 
						|
    EFI_GCD_IO_SPACE_DESCRIPTOR Descriptor;
 | 
						|
 | 
						|
    for (CheckBase = Base;
 | 
						|
         CheckBase < Base + Length;
 | 
						|
         CheckBase = Descriptor.BaseAddress + Descriptor.Length) {
 | 
						|
      CheckStatus = gDS->GetIoSpaceDescriptor (CheckBase, &Descriptor);
 | 
						|
      ASSERT_EFI_ERROR (CheckStatus);
 | 
						|
      ASSERT (Descriptor.GcdIoType == EfiGcdIoTypeIo);
 | 
						|
    }
 | 
						|
    );
 | 
						|
 | 
						|
FreeIoSpaceMap:
 | 
						|
  FreePool (IoSpaceMap);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Ensure the compatibility of a memory space descriptor with the MMIO aperture.
 | 
						|
 | 
						|
  The memory space descriptor can come from the GCD memory space map, or it can
 | 
						|
  represent a gap between two neighboring memory space descriptors. In the
 | 
						|
  latter case, the GcdMemoryType field is expected to be
 | 
						|
  EfiGcdMemoryTypeNonExistent.
 | 
						|
 | 
						|
  If the memory space descriptor already has type
 | 
						|
  EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
 | 
						|
  required capabilities, then no action is taken -- it is by definition
 | 
						|
  compatible with the aperture.
 | 
						|
 | 
						|
  Otherwise, the intersection of the memory space descriptor is calculated with
 | 
						|
  the aperture. If the intersection is the empty set (no overlap), no action is
 | 
						|
  taken; the memory space descriptor is compatible with the aperture.
 | 
						|
 | 
						|
  Otherwise, the type of the descriptor is investigated again. If the type is
 | 
						|
  EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
 | 
						|
  such a type), then an attempt is made to add the intersection as MMIO space
 | 
						|
  to the GCD memory space map, with the specified capabilities. This ensures
 | 
						|
  continuity for the aperture, and the descriptor is deemed compatible with the
 | 
						|
  aperture.
 | 
						|
 | 
						|
  Otherwise, the memory space descriptor is incompatible with the MMIO
 | 
						|
  aperture.
 | 
						|
 | 
						|
  @param[in] Base         Base address of the aperture.
 | 
						|
  @param[in] Length       Length of the aperture.
 | 
						|
  @param[in] Capabilities Capabilities required by the aperture.
 | 
						|
  @param[in] Descriptor   The descriptor to ensure compatibility with the
 | 
						|
                          aperture for.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The descriptor is compatible. The GCD memory
 | 
						|
                                 space map may have been updated, for
 | 
						|
                                 continuity within the aperture.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The descriptor is incompatible.
 | 
						|
  @return                        Error codes from gDS->AddMemorySpace().
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IntersectMemoryDescriptor (
 | 
						|
  IN  UINT64                                Base,
 | 
						|
  IN  UINT64                                Length,
 | 
						|
  IN  UINT64                                Capabilities,
 | 
						|
  IN  CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64                                    IntersectionBase;
 | 
						|
  UINT64                                    IntersectionEnd;
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
 | 
						|
  if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo &&
 | 
						|
      (Descriptor->Capabilities & Capabilities) == Capabilities) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  IntersectionBase = MAX (Base, Descriptor->BaseAddress);
 | 
						|
  IntersectionEnd = MIN (Base + Length,
 | 
						|
                      Descriptor->BaseAddress + Descriptor->Length);
 | 
						|
  if (IntersectionBase >= IntersectionEnd) {
 | 
						|
    //
 | 
						|
    // The descriptor and the aperture don't overlap.
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
 | 
						|
    Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
 | 
						|
                    IntersectionBase, IntersectionEnd - IntersectionBase,
 | 
						|
                    Capabilities);
 | 
						|
 | 
						|
    DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE,
 | 
						|
      "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__,
 | 
						|
      IntersectionBase, IntersectionEnd, Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
 | 
						|
    "with aperture [%Lx, %Lx) cap %Lx\n", gEfiCallerBaseName, __FUNCTION__,
 | 
						|
    Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length,
 | 
						|
    (UINT32)Descriptor->GcdMemoryType, Descriptor->Capabilities,
 | 
						|
    Base, Base + Length, Capabilities));
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Add MMIO space to GCD.
 | 
						|
  The routine checks the GCD database and only adds those which are
 | 
						|
  not added in the specified range to GCD.
 | 
						|
 | 
						|
  @param Base         Base address of the MMIO space.
 | 
						|
  @param Length       Length of the MMIO space.
 | 
						|
  @param Capabilities Capabilities of the MMIO space.
 | 
						|
 | 
						|
  @retval EFI_SUCCES The MMIO space was added successfully.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AddMemoryMappedIoSpace (
 | 
						|
  IN  UINT64                            Base,
 | 
						|
  IN  UINT64                            Length,
 | 
						|
  IN  UINT64                            Capabilities
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  UINTN                                 Index;
 | 
						|
  UINTN                                 NumberOfDescriptors;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR       *MemorySpaceMap;
 | 
						|
 | 
						|
  Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "%a: %a: GetMemorySpaceMap(): %r\n",
 | 
						|
      gEfiCallerBaseName, __FUNCTION__, Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < NumberOfDescriptors; Index++) {
 | 
						|
    Status = IntersectMemoryDescriptor (Base, Length, Capabilities,
 | 
						|
               &MemorySpaceMap[Index]);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto FreeMemorySpaceMap;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE (
 | 
						|
    //
 | 
						|
    // Make sure there are adjacent descriptors covering [Base, Base + Length).
 | 
						|
    // It is possible that they have not been merged; merging can be prevented
 | 
						|
    // by allocation and different capabilities.
 | 
						|
    //
 | 
						|
    UINT64                          CheckBase;
 | 
						|
    EFI_STATUS                      CheckStatus;
 | 
						|
    EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
 | 
						|
 | 
						|
    for (CheckBase = Base;
 | 
						|
         CheckBase < Base + Length;
 | 
						|
         CheckBase = Descriptor.BaseAddress + Descriptor.Length) {
 | 
						|
      CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);
 | 
						|
      ASSERT_EFI_ERROR (CheckStatus);
 | 
						|
      ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);
 | 
						|
      ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);
 | 
						|
    }
 | 
						|
    );
 | 
						|
 | 
						|
FreeMemorySpaceMap:
 | 
						|
  FreePool (MemorySpaceMap);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Event notification that is fired when IOMMU protocol is installed.
 | 
						|
 | 
						|
  @param  Event                 The Event that is being processed.
 | 
						|
  @param  Context               Event Context.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
IoMmuProtocolCallback (
 | 
						|
  IN  EFI_EVENT       Event,
 | 
						|
  IN  VOID            *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS   Status;
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);
 | 
						|
  if (!EFI_ERROR(Status)) {
 | 
						|
    gBS->CloseEvent (mIoMmuEvent);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Entry point of this driver.
 | 
						|
 | 
						|
  @param ImageHandle  Image handle of this driver.
 | 
						|
  @param SystemTable  Pointer to standard EFI system table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       Succeed.
 | 
						|
  @retval EFI_DEVICE_ERROR  Fail to install PCI_ROOT_BRIDGE_IO protocol.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializePciHostBridge (
 | 
						|
  IN EFI_HANDLE         ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE   *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE    *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE    *RootBridge;
 | 
						|
  PCI_ROOT_BRIDGE             *RootBridges;
 | 
						|
  UINTN                       RootBridgeCount;
 | 
						|
  UINTN                       Index;
 | 
						|
  PCI_ROOT_BRIDGE_APERTURE    *MemApertures[4];
 | 
						|
  UINTN                       MemApertureIndex;
 | 
						|
  BOOLEAN                     ResourceAssigned;
 | 
						|
  LIST_ENTRY                  *Link;
 | 
						|
  UINT64                      HostAddress;
 | 
						|
 | 
						|
  RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
 | 
						|
  if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Most systems in the world including complex servers have only one Host Bridge.
 | 
						|
  //
 | 
						|
  HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
 | 
						|
  ASSERT (HostBridge != NULL);
 | 
						|
 | 
						|
  HostBridge->Signature        = PCI_HOST_BRIDGE_SIGNATURE;
 | 
						|
  HostBridge->CanRestarted     = TRUE;
 | 
						|
  InitializeListHead (&HostBridge->RootBridges);
 | 
						|
  ResourceAssigned             = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create Root Bridge Device Handle in this Host Bridge
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < RootBridgeCount; Index++) {
 | 
						|
    //
 | 
						|
    // Create Root Bridge Handle Instance
 | 
						|
    //
 | 
						|
    RootBridge = CreateRootBridge (&RootBridges[Index]);
 | 
						|
    ASSERT (RootBridge != NULL);
 | 
						|
    if (RootBridge == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Make sure all root bridges share the same ResourceAssigned value.
 | 
						|
    //
 | 
						|
    if (Index == 0) {
 | 
						|
      ResourceAssigned = RootBridges[Index].ResourceAssigned;
 | 
						|
    } else {
 | 
						|
      ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);
 | 
						|
    }
 | 
						|
 | 
						|
    if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {
 | 
						|
      //
 | 
						|
      // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
 | 
						|
      // For GCD resource manipulation, we need to use host address.
 | 
						|
      //
 | 
						|
      HostAddress = TO_HOST_ADDRESS (RootBridges[Index].Io.Base,
 | 
						|
        RootBridges[Index].Io.Translation);
 | 
						|
 | 
						|
      Status = AddIoSpace (
 | 
						|
                 HostAddress,
 | 
						|
                 RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1
 | 
						|
                 );
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
      if (ResourceAssigned) {
 | 
						|
        Status = gDS->AllocateIoSpace (
 | 
						|
                        EfiGcdAllocateAddress,
 | 
						|
                        EfiGcdIoTypeIo,
 | 
						|
                        0,
 | 
						|
                        RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,
 | 
						|
                        &HostAddress,
 | 
						|
                        gImageHandle,
 | 
						|
                        NULL
 | 
						|
                        );
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Add all the Mem/PMem aperture to GCD
 | 
						|
    // Mem/PMem shouldn't overlap with each other
 | 
						|
    // Root bridge which needs to combine MEM and PMEM should only report
 | 
						|
    // the MEM aperture in Mem
 | 
						|
    //
 | 
						|
    MemApertures[0] = &RootBridges[Index].Mem;
 | 
						|
    MemApertures[1] = &RootBridges[Index].MemAbove4G;
 | 
						|
    MemApertures[2] = &RootBridges[Index].PMem;
 | 
						|
    MemApertures[3] = &RootBridges[Index].PMemAbove4G;
 | 
						|
 | 
						|
    for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {
 | 
						|
      if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {
 | 
						|
        //
 | 
						|
        // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
 | 
						|
        // For GCD resource manipulation, we need to use host address.
 | 
						|
        //
 | 
						|
        HostAddress = TO_HOST_ADDRESS (MemApertures[MemApertureIndex]->Base,
 | 
						|
          MemApertures[MemApertureIndex]->Translation);
 | 
						|
        Status = AddMemoryMappedIoSpace (
 | 
						|
                   HostAddress,
 | 
						|
                   MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
 | 
						|
                   EFI_MEMORY_UC
 | 
						|
                   );
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
        Status = gDS->SetMemorySpaceAttributes (
 | 
						|
                        HostAddress,
 | 
						|
                        MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
 | 
						|
                        EFI_MEMORY_UC
 | 
						|
                        );
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));
 | 
						|
        }
 | 
						|
        if (ResourceAssigned) {
 | 
						|
          Status = gDS->AllocateMemorySpace (
 | 
						|
                          EfiGcdAllocateAddress,
 | 
						|
                          EfiGcdMemoryTypeMemoryMappedIo,
 | 
						|
                          0,
 | 
						|
                          MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
 | 
						|
                          &HostAddress,
 | 
						|
                          gImageHandle,
 | 
						|
                          NULL
 | 
						|
                          );
 | 
						|
          ASSERT_EFI_ERROR (Status);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Insert Root Bridge Handle Instance
 | 
						|
    //
 | 
						|
    InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // When resources were assigned, it's not needed to expose
 | 
						|
  // PciHostBridgeResourceAllocation protocol.
 | 
						|
  //
 | 
						|
  if (!ResourceAssigned) {
 | 
						|
    HostBridge->ResAlloc.NotifyPhase = NotifyPhase;
 | 
						|
    HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;
 | 
						|
    HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;
 | 
						|
    HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;
 | 
						|
    HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;
 | 
						|
    HostBridge->ResAlloc.SubmitResources = SubmitResources;
 | 
						|
    HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
 | 
						|
    HostBridge->ResAlloc.PreprocessController = PreprocessController;
 | 
						|
 | 
						|
    Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                    &HostBridge->Handle,
 | 
						|
                    &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
       ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
       ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;
 | 
						|
 | 
						|
    Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                    &RootBridge->Handle,
 | 
						|
                    &gEfiDevicePathProtocolGuid, RootBridge->DevicePath,
 | 
						|
                    &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->RootBridgeIo,
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
  PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    mIoMmuEvent = EfiCreateProtocolNotifyEvent (
 | 
						|
                    &gEdkiiIoMmuProtocolGuid,
 | 
						|
                    TPL_CALLBACK,
 | 
						|
                    IoMmuProtocolCallback,
 | 
						|
                    NULL,
 | 
						|
                    &mIoMmuRegistration
 | 
						|
                    );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().
 | 
						|
 | 
						|
  @param HostBridge The Host Bridge Instance where the resource adjustment happens.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
ResourceConflict (
 | 
						|
  IN  PCI_HOST_BRIDGE_INSTANCE *HostBridge
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
 | 
						|
  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE          *RootBridge;
 | 
						|
  LIST_ENTRY                        *Link;
 | 
						|
  UINTN                             RootBridgeCount;
 | 
						|
  PCI_RESOURCE_TYPE                 Index;
 | 
						|
  PCI_RES_NODE                      *ResAllocNode;
 | 
						|
 | 
						|
  RootBridgeCount = 0;
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
       ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
       ) {
 | 
						|
    RootBridgeCount++;
 | 
						|
  }
 | 
						|
 | 
						|
  Resources = AllocatePool (
 | 
						|
                RootBridgeCount * (TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)) +
 | 
						|
                sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
 | 
						|
                );
 | 
						|
  ASSERT (Resources != NULL);
 | 
						|
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges), Descriptor = Resources
 | 
						|
       ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
       ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    for (Index = TypeIo; Index < TypeMax; Index++) {
 | 
						|
      ResAllocNode = &RootBridge->ResAllocNode[Index];
 | 
						|
 | 
						|
      Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
 | 
						|
      Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
 | 
						|
      Descriptor->AddrRangeMin = ResAllocNode->Base;
 | 
						|
      Descriptor->AddrRangeMax = ResAllocNode->Alignment;
 | 
						|
      Descriptor->AddrLen      = ResAllocNode->Length;
 | 
						|
      Descriptor->SpecificFlag = 0;
 | 
						|
      switch (ResAllocNode->Type) {
 | 
						|
 | 
						|
      case TypeIo:
 | 
						|
        Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
 | 
						|
        break;
 | 
						|
 | 
						|
      case TypePMem32:
 | 
						|
        Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
 | 
						|
      case TypeMem32:
 | 
						|
        Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
 | 
						|
        Descriptor->AddrSpaceGranularity = 32;
 | 
						|
        break;
 | 
						|
 | 
						|
      case TypePMem64:
 | 
						|
        Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
 | 
						|
      case TypeMem64:
 | 
						|
        Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
 | 
						|
        Descriptor->AddrSpaceGranularity = 64;
 | 
						|
        break;
 | 
						|
 | 
						|
      case TypeBus:
 | 
						|
        Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      Descriptor++;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Terminate the root bridge resources.
 | 
						|
    //
 | 
						|
    End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
 | 
						|
    End->Desc = ACPI_END_TAG_DESCRIPTOR;
 | 
						|
    End->Checksum = 0x0;
 | 
						|
 | 
						|
    Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (End + 1);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Terminate the host bridge resources.
 | 
						|
  //
 | 
						|
  End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
 | 
						|
  End->Desc = ACPI_END_TAG_DESCRIPTOR;
 | 
						|
  End->Checksum = 0x0;
 | 
						|
 | 
						|
  DEBUG ((DEBUG_ERROR, "Call PciHostBridgeResourceConflict().\n"));
 | 
						|
  PciHostBridgeResourceConflict (HostBridge->Handle, Resources);
 | 
						|
  FreePool (Resources);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocate Length of MMIO or IO resource with alignment BitsOfAlignment
 | 
						|
  from GCD range [BaseAddress, Limit).
 | 
						|
 | 
						|
  @param Mmio            TRUE for MMIO and FALSE for IO.
 | 
						|
  @param Length          Length of the resource to allocate.
 | 
						|
  @param BitsOfAlignment Alignment of the resource to allocate.
 | 
						|
  @param BaseAddress     The starting address the allocation is from.
 | 
						|
  @param Limit           The ending address the allocation is to.
 | 
						|
 | 
						|
  @retval  The base address of the allocated resource or MAX_UINT64 if allocation
 | 
						|
           fails.
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
AllocateResource (
 | 
						|
  BOOLEAN Mmio,
 | 
						|
  UINT64  Length,
 | 
						|
  UINTN   BitsOfAlignment,
 | 
						|
  UINT64  BaseAddress,
 | 
						|
  UINT64  Limit
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  if (BaseAddress < Limit) {
 | 
						|
    //
 | 
						|
    // Have to make sure Aligment is handled since we are doing direct address allocation
 | 
						|
    // Strictly speaking, alignment requirement should be applied to device
 | 
						|
    // address instead of host address which is used in GCD manipulation below,
 | 
						|
    // but as we restrict the alignment of Translation to be larger than any BAR
 | 
						|
    // alignment in the root bridge, we can simplify the situation and consider
 | 
						|
    // the same alignment requirement is also applied to host address.
 | 
						|
    //
 | 
						|
    BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));
 | 
						|
 | 
						|
    while (BaseAddress + Length <= Limit + 1) {
 | 
						|
      if (Mmio) {
 | 
						|
        Status = gDS->AllocateMemorySpace (
 | 
						|
                        EfiGcdAllocateAddress,
 | 
						|
                        EfiGcdMemoryTypeMemoryMappedIo,
 | 
						|
                        BitsOfAlignment,
 | 
						|
                        Length,
 | 
						|
                        &BaseAddress,
 | 
						|
                        gImageHandle,
 | 
						|
                        NULL
 | 
						|
                        );
 | 
						|
      } else {
 | 
						|
        Status = gDS->AllocateIoSpace (
 | 
						|
                        EfiGcdAllocateAddress,
 | 
						|
                        EfiGcdIoTypeIo,
 | 
						|
                        BitsOfAlignment,
 | 
						|
                        Length,
 | 
						|
                        &BaseAddress,
 | 
						|
                        gImageHandle,
 | 
						|
                        NULL
 | 
						|
                        );
 | 
						|
      }
 | 
						|
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        return BaseAddress;
 | 
						|
      }
 | 
						|
      BaseAddress += LShiftU64 (1, BitsOfAlignment);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return MAX_UINT64;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Enter a certain phase of the PCI enumeration process.
 | 
						|
 | 
						|
  @param This   The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
 | 
						|
  @param Phase  The phase during enumeration.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Wrong phase parameter passed in.
 | 
						|
  @retval EFI_NOT_READY          Resources have not been submitted yet.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
NotifyPhase (
 | 
						|
  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
 | 
						|
  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE    Phase
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE              *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE              *RootBridge;
 | 
						|
  LIST_ENTRY                            *Link;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  BaseAddress;
 | 
						|
  UINTN                                 BitsOfAlignment;
 | 
						|
  UINT64                                Alignment;
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  EFI_STATUS                            ReturnStatus;
 | 
						|
  PCI_RESOURCE_TYPE                     Index;
 | 
						|
  PCI_RESOURCE_TYPE                     Index1;
 | 
						|
  PCI_RESOURCE_TYPE                     Index2;
 | 
						|
  BOOLEAN                               ResNodeHandled[TypeMax];
 | 
						|
  UINT64                                MaxAlignment;
 | 
						|
  UINT64                                Translation;
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
 | 
						|
  switch (Phase) {
 | 
						|
  case EfiPciHostBridgeBeginEnumeration:
 | 
						|
    if (!HostBridge->CanRestarted) {
 | 
						|
      return EFI_NOT_READY;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Reset Root Bridge
 | 
						|
    //
 | 
						|
    for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
          ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
          ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
          ) {
 | 
						|
      RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
      for (Index = TypeIo; Index < TypeMax; Index++) {
 | 
						|
        RootBridge->ResAllocNode[Index].Type   = Index;
 | 
						|
        RootBridge->ResAllocNode[Index].Base   = 0;
 | 
						|
        RootBridge->ResAllocNode[Index].Length = 0;
 | 
						|
        RootBridge->ResAllocNode[Index].Status = ResNone;
 | 
						|
 | 
						|
        RootBridge->ResourceSubmitted = FALSE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    HostBridge->CanRestarted = TRUE;
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciHostBridgeBeginBusAllocation:
 | 
						|
    //
 | 
						|
    // No specific action is required here, can perform any chipset specific programing
 | 
						|
    //
 | 
						|
    HostBridge->CanRestarted = FALSE;
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciHostBridgeEndBusAllocation:
 | 
						|
    //
 | 
						|
    // No specific action is required here, can perform any chipset specific programing
 | 
						|
    //
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciHostBridgeBeginResourceAllocation:
 | 
						|
    //
 | 
						|
    // No specific action is required here, can perform any chipset specific programing
 | 
						|
    //
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciHostBridgeAllocateResources:
 | 
						|
    ReturnStatus = EFI_SUCCESS;
 | 
						|
 | 
						|
    //
 | 
						|
    // Make sure the resource for all root bridges has been submitted.
 | 
						|
    //
 | 
						|
    for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
         ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
         ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
         ) {
 | 
						|
      RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
      if (!RootBridge->ResourceSubmitted) {
 | 
						|
        return EFI_NOT_READY;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG ((EFI_D_INFO, "PciHostBridge: NotifyPhase (AllocateResources)\n"));
 | 
						|
    for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
         ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
         ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
         ) {
 | 
						|
      for (Index = TypeIo; Index < TypeBus; Index++) {
 | 
						|
        ResNodeHandled[Index] = FALSE;
 | 
						|
      }
 | 
						|
 | 
						|
      RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
      DEBUG ((EFI_D_INFO, " RootBridge: %s\n", RootBridge->DevicePathStr));
 | 
						|
 | 
						|
      for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {
 | 
						|
        if (RootBridge->ResAllocNode[Index1].Status == ResNone) {
 | 
						|
          ResNodeHandled[Index1] = TRUE;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Allocate the resource node with max alignment at first
 | 
						|
          //
 | 
						|
          MaxAlignment = 0;
 | 
						|
          Index = TypeMax;
 | 
						|
          for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {
 | 
						|
            if (ResNodeHandled[Index2]) {
 | 
						|
              continue;
 | 
						|
            }
 | 
						|
            if (MaxAlignment <= RootBridge->ResAllocNode[Index2].Alignment) {
 | 
						|
              MaxAlignment = RootBridge->ResAllocNode[Index2].Alignment;
 | 
						|
              Index = Index2;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          ASSERT (Index < TypeMax);
 | 
						|
          ResNodeHandled[Index] = TRUE;
 | 
						|
          Alignment = RootBridge->ResAllocNode[Index].Alignment;
 | 
						|
          BitsOfAlignment = LowBitSet64 (Alignment + 1);
 | 
						|
          BaseAddress = MAX_UINT64;
 | 
						|
 | 
						|
          //
 | 
						|
          // RESTRICTION: To simplify the situation, we require the alignment of
 | 
						|
          // Translation must be larger than any BAR alignment in the same root
 | 
						|
          // bridge, so that resource allocation alignment can be applied to
 | 
						|
          // both device address and host address.
 | 
						|
          //
 | 
						|
          Translation = GetTranslationByResourceType (RootBridge, Index);
 | 
						|
          if ((Translation & Alignment) != 0) {
 | 
						|
            DEBUG ((DEBUG_ERROR, "[%a:%d] Translation %lx is not aligned to %lx!\n",
 | 
						|
              __FUNCTION__, __LINE__, Translation, Alignment
 | 
						|
              ));
 | 
						|
            ASSERT ((Translation & Alignment) == 0);
 | 
						|
            //
 | 
						|
            // This may be caused by too large alignment or too small
 | 
						|
            // Translation; pick the 1st possibility and return out of resource,
 | 
						|
            // which can also go thru the same process for out of resource
 | 
						|
            // outside the loop.
 | 
						|
            //
 | 
						|
            ReturnStatus = EFI_OUT_OF_RESOURCES;
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          switch (Index) {
 | 
						|
          case TypeIo:
 | 
						|
            //
 | 
						|
            // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
 | 
						|
            // For AllocateResource is manipulating GCD resource, we need to use
 | 
						|
            // host address here.
 | 
						|
            //
 | 
						|
            BaseAddress = AllocateResource (
 | 
						|
                            FALSE,
 | 
						|
                            RootBridge->ResAllocNode[Index].Length,
 | 
						|
                            MIN (15, BitsOfAlignment),
 | 
						|
                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),
 | 
						|
                              RootBridge->Io.Translation),
 | 
						|
                            TO_HOST_ADDRESS (RootBridge->Io.Limit,
 | 
						|
                              RootBridge->Io.Translation)
 | 
						|
                            );
 | 
						|
            break;
 | 
						|
 | 
						|
          case TypeMem64:
 | 
						|
            BaseAddress = AllocateResource (
 | 
						|
                            TRUE,
 | 
						|
                            RootBridge->ResAllocNode[Index].Length,
 | 
						|
                            MIN (63, BitsOfAlignment),
 | 
						|
                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),
 | 
						|
                              RootBridge->MemAbove4G.Translation),
 | 
						|
                            TO_HOST_ADDRESS (RootBridge->MemAbove4G.Limit,
 | 
						|
                              RootBridge->MemAbove4G.Translation)
 | 
						|
                            );
 | 
						|
            if (BaseAddress != MAX_UINT64) {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
            //
 | 
						|
            // If memory above 4GB is not available, try memory below 4GB
 | 
						|
            //
 | 
						|
 | 
						|
          case TypeMem32:
 | 
						|
            BaseAddress = AllocateResource (
 | 
						|
                            TRUE,
 | 
						|
                            RootBridge->ResAllocNode[Index].Length,
 | 
						|
                            MIN (31, BitsOfAlignment),
 | 
						|
                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),
 | 
						|
                              RootBridge->Mem.Translation),
 | 
						|
                            TO_HOST_ADDRESS (RootBridge->Mem.Limit,
 | 
						|
                              RootBridge->Mem.Translation)
 | 
						|
                            );
 | 
						|
            break;
 | 
						|
 | 
						|
          case TypePMem64:
 | 
						|
            BaseAddress = AllocateResource (
 | 
						|
                            TRUE,
 | 
						|
                            RootBridge->ResAllocNode[Index].Length,
 | 
						|
                            MIN (63, BitsOfAlignment),
 | 
						|
                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),
 | 
						|
                              RootBridge->PMemAbove4G.Translation),
 | 
						|
                            TO_HOST_ADDRESS (RootBridge->PMemAbove4G.Limit,
 | 
						|
                              RootBridge->PMemAbove4G.Translation)
 | 
						|
                            );
 | 
						|
            if (BaseAddress != MAX_UINT64) {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
            //
 | 
						|
            // If memory above 4GB is not available, try memory below 4GB
 | 
						|
            //
 | 
						|
          case TypePMem32:
 | 
						|
            BaseAddress = AllocateResource (
 | 
						|
                            TRUE,
 | 
						|
                            RootBridge->ResAllocNode[Index].Length,
 | 
						|
                            MIN (31, BitsOfAlignment),
 | 
						|
                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),
 | 
						|
                              RootBridge->PMem.Translation),
 | 
						|
                            TO_HOST_ADDRESS (RootBridge->PMem.Limit,
 | 
						|
                              RootBridge->PMem.Translation)
 | 
						|
                            );
 | 
						|
            break;
 | 
						|
 | 
						|
          default:
 | 
						|
            ASSERT (FALSE);
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          DEBUG ((DEBUG_INFO, "  %s: Base/Length/Alignment = %lx/%lx/%lx - ",
 | 
						|
                  mPciResourceTypeStr[Index], BaseAddress, RootBridge->ResAllocNode[Index].Length, Alignment));
 | 
						|
          if (BaseAddress != MAX_UINT64) {
 | 
						|
            RootBridge->ResAllocNode[Index].Base = BaseAddress;
 | 
						|
            RootBridge->ResAllocNode[Index].Status = ResAllocated;
 | 
						|
            DEBUG ((DEBUG_INFO, "Success\n"));
 | 
						|
          } else {
 | 
						|
            ReturnStatus = EFI_OUT_OF_RESOURCES;
 | 
						|
            DEBUG ((DEBUG_ERROR, "Out Of Resource!\n"));
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (ReturnStatus == EFI_OUT_OF_RESOURCES) {
 | 
						|
      ResourceConflict (HostBridge);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Set resource to zero for nodes where allocation fails
 | 
						|
    //
 | 
						|
    for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
          ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
          ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
          ) {
 | 
						|
      RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
      for (Index = TypeIo; Index < TypeBus; Index++) {
 | 
						|
        if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
 | 
						|
          RootBridge->ResAllocNode[Index].Length = 0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return ReturnStatus;
 | 
						|
 | 
						|
  case EfiPciHostBridgeSetResources:
 | 
						|
    //
 | 
						|
    // HostBridgeInstance->CanRestarted = FALSE;
 | 
						|
    //
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciHostBridgeFreeResources:
 | 
						|
    //
 | 
						|
    // HostBridgeInstance->CanRestarted = FALSE;
 | 
						|
    //
 | 
						|
    ReturnStatus = EFI_SUCCESS;
 | 
						|
    for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
         ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
         ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
         ) {
 | 
						|
      RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
      for (Index = TypeIo; Index < TypeBus; Index++) {
 | 
						|
        if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {
 | 
						|
          switch (Index) {
 | 
						|
          case TypeIo:
 | 
						|
            Status = gDS->FreeIoSpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
 | 
						|
            if (EFI_ERROR (Status)) {
 | 
						|
              ReturnStatus = Status;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
          case TypeMem32:
 | 
						|
          case TypePMem32:
 | 
						|
          case TypeMem64:
 | 
						|
          case TypePMem64:
 | 
						|
            Status = gDS->FreeMemorySpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
 | 
						|
            if (EFI_ERROR (Status)) {
 | 
						|
              ReturnStatus = Status;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
          default:
 | 
						|
            ASSERT (FALSE);
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          RootBridge->ResAllocNode[Index].Type = Index;
 | 
						|
          RootBridge->ResAllocNode[Index].Base = 0;
 | 
						|
          RootBridge->ResAllocNode[Index].Length = 0;
 | 
						|
          RootBridge->ResAllocNode[Index].Status = ResNone;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      RootBridge->ResourceSubmitted = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    HostBridge->CanRestarted = TRUE;
 | 
						|
    return ReturnStatus;
 | 
						|
 | 
						|
  case EfiPciHostBridgeEndResourceAllocation:
 | 
						|
    //
 | 
						|
    // The resource allocation phase is completed.  No specific action is required
 | 
						|
    // here. This notification can be used to perform any chipset specific programming.
 | 
						|
    //
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciHostBridgeEndEnumeration:
 | 
						|
    //
 | 
						|
    // The Host Bridge Enumeration is completed. No specific action is required here.
 | 
						|
    // This notification can be used to perform any chipset specific programming.
 | 
						|
    //
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Return the device handle of the next PCI root bridge that is associated with
 | 
						|
  this Host Bridge.
 | 
						|
 | 
						|
  @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
 | 
						|
  @param RootBridgeHandle  Returns the device handle of the next PCI Root Bridge.
 | 
						|
                           On input, it holds the RootBridgeHandle returned by the most
 | 
						|
                           recent call to GetNextRootBridge().The handle for the first
 | 
						|
                           PCI Root Bridge is returned if RootBridgeHandle is NULL on input.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_NOT_FOUND          Next PCI root bridge not found.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Wrong parameter passed in.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
GetNextRootBridge (
 | 
						|
  IN     EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
 | 
						|
  IN OUT EFI_HANDLE                                       *RootBridgeHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN                   ReturnNext;
 | 
						|
  LIST_ENTRY                *Link;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
 | 
						|
 | 
						|
  if (RootBridgeHandle == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
  ReturnNext = (BOOLEAN) (*RootBridgeHandle == NULL);
 | 
						|
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
      ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
      ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
      ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    if (ReturnNext) {
 | 
						|
      *RootBridgeHandle = RootBridge->Handle;
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    ReturnNext = (BOOLEAN) (*RootBridgeHandle == RootBridge->Handle);
 | 
						|
  }
 | 
						|
 | 
						|
  if (ReturnNext) {
 | 
						|
    ASSERT (IsNull (&HostBridge->RootBridges, Link));
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  } else {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Returns the attributes of a PCI Root Bridge.
 | 
						|
 | 
						|
  @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
 | 
						|
  @param RootBridgeHandle  The device handle of the PCI Root Bridge
 | 
						|
                           that the caller is interested in.
 | 
						|
  @param Attributes        The pointer to attributes of the PCI Root Bridge.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Attributes parameter passed in is NULL or
 | 
						|
                                 RootBridgeHandle is not an EFI_HANDLE
 | 
						|
                                 that was returned on a previous call to
 | 
						|
                                 GetNextRootBridge().
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
GetAttributes (
 | 
						|
  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
 | 
						|
  IN  EFI_HANDLE                                       RootBridgeHandle,
 | 
						|
  OUT UINT64                                           *Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY                *Link;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
 | 
						|
 | 
						|
  if (Attributes == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
      ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
      ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
      ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    if (RootBridgeHandle == RootBridge->Handle) {
 | 
						|
      *Attributes = RootBridge->AllocationAttributes;
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This is the request from the PCI enumerator to set up
 | 
						|
  the specified PCI Root Bridge for bus enumeration process.
 | 
						|
 | 
						|
  @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
 | 
						|
  @param RootBridgeHandle  The PCI Root Bridge to be set up.
 | 
						|
  @param Configuration     Pointer to the pointer to the PCI bus resource descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Not enough pool to be allocated.
 | 
						|
  @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid handle.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
StartBusEnumeration (
 | 
						|
  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
 | 
						|
  IN  EFI_HANDLE                                       RootBridgeHandle,
 | 
						|
  OUT VOID                                             **Configuration
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY                *Link;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
 | 
						|
  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
 | 
						|
 | 
						|
  if (Configuration == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
       ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
       ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    if (RootBridgeHandle == RootBridge->Handle) {
 | 
						|
      *Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
 | 
						|
      if (*Configuration == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) *Configuration;
 | 
						|
      Descriptor->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
 | 
						|
      Descriptor->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
 | 
						|
      Descriptor->ResType               = ACPI_ADDRESS_SPACE_TYPE_BUS;
 | 
						|
      Descriptor->GenFlag               = 0;
 | 
						|
      Descriptor->SpecificFlag          = 0;
 | 
						|
      Descriptor->AddrSpaceGranularity  = 0;
 | 
						|
      Descriptor->AddrRangeMin          = RootBridge->Bus.Base;
 | 
						|
      Descriptor->AddrRangeMax          = 0;
 | 
						|
      Descriptor->AddrTranslationOffset = 0;
 | 
						|
      Descriptor->AddrLen               = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1;
 | 
						|
 | 
						|
      End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
 | 
						|
      End->Desc = ACPI_END_TAG_DESCRIPTOR;
 | 
						|
      End->Checksum = 0x0;
 | 
						|
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This function programs the PCI Root Bridge hardware so that
 | 
						|
  it decodes the specified PCI bus range.
 | 
						|
 | 
						|
  @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
 | 
						|
  @param RootBridgeHandle  The PCI Root Bridge whose bus range is to be programmed.
 | 
						|
  @param Configuration     The pointer to the PCI bus resource descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Wrong parameters passed in.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SetBusNumbers (
 | 
						|
  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
 | 
						|
  IN EFI_HANDLE                                       RootBridgeHandle,
 | 
						|
  IN VOID                                             *Configuration
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY                *Link;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
 | 
						|
  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
 | 
						|
 | 
						|
  if (Configuration == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
 | 
						|
  End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the Configuration is valid
 | 
						|
  //
 | 
						|
  if ((Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) ||
 | 
						|
      (Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) ||
 | 
						|
      (End->Desc != ACPI_END_TAG_DESCRIPTOR)
 | 
						|
     ) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
       ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
       ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    if (RootBridgeHandle == RootBridge->Handle) {
 | 
						|
 | 
						|
      if (Descriptor->AddrLen == 0) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      if ((Descriptor->AddrRangeMin < RootBridge->Bus.Base) ||
 | 
						|
          (Descriptor->AddrRangeMin + Descriptor->AddrLen - 1 > RootBridge->Bus.Limit)
 | 
						|
         ) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Update the Bus Range
 | 
						|
      //
 | 
						|
      RootBridge->ResAllocNode[TypeBus].Base    = Descriptor->AddrRangeMin;
 | 
						|
      RootBridge->ResAllocNode[TypeBus].Length  = Descriptor->AddrLen;
 | 
						|
      RootBridge->ResAllocNode[TypeBus].Status  = ResAllocated;
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
 | 
						|
 | 
						|
  @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
 | 
						|
  @param RootBridgeHandle  The PCI Root Bridge whose I/O and memory resource requirements.
 | 
						|
                           are being submitted.
 | 
						|
  @param Configuration     The pointer to the PCI I/O and PCI memory resource descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Wrong parameters passed in.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SubmitResources (
 | 
						|
  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
 | 
						|
  IN EFI_HANDLE                                       RootBridgeHandle,
 | 
						|
  IN VOID                                             *Configuration
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY                        *Link;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE          *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE          *RootBridge;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
 | 
						|
  PCI_RESOURCE_TYPE                 Type;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the input parameter: Configuration
 | 
						|
  //
 | 
						|
  if (Configuration == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
       ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
       ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    if (RootBridgeHandle == RootBridge->Handle) {
 | 
						|
      DEBUG ((EFI_D_INFO, "PciHostBridge: SubmitResources for %s\n", RootBridge->DevicePathStr));
 | 
						|
      //
 | 
						|
      // Check the resource descriptors.
 | 
						|
      // If the Configuration includes one or more invalid resource descriptors, all the resource
 | 
						|
      // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.
 | 
						|
      //
 | 
						|
      for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
 | 
						|
        if (Descriptor->ResType > ACPI_ADDRESS_SPACE_TYPE_BUS) {
 | 
						|
          return EFI_INVALID_PARAMETER;
 | 
						|
        }
 | 
						|
 | 
						|
        DEBUG ((EFI_D_INFO, " %s: Granularity/SpecificFlag = %ld / %02x%s\n",
 | 
						|
                mAcpiAddressSpaceTypeStr[Descriptor->ResType], Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
 | 
						|
                (Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0 ? L" (Prefetchable)" : L""
 | 
						|
                ));
 | 
						|
        DEBUG ((EFI_D_INFO, "      Length/Alignment = 0x%lx / 0x%lx\n", Descriptor->AddrLen, Descriptor->AddrRangeMax));
 | 
						|
        switch (Descriptor->ResType) {
 | 
						|
        case ACPI_ADDRESS_SPACE_TYPE_MEM:
 | 
						|
          if (Descriptor->AddrSpaceGranularity != 32 && Descriptor->AddrSpaceGranularity != 64) {
 | 
						|
            return EFI_INVALID_PARAMETER;
 | 
						|
          }
 | 
						|
          if (Descriptor->AddrSpaceGranularity == 32 && Descriptor->AddrLen >= SIZE_4GB) {
 | 
						|
            return EFI_INVALID_PARAMETER;
 | 
						|
          }
 | 
						|
          //
 | 
						|
          // If the PCI root bridge does not support separate windows for nonprefetchable and
 | 
						|
          // prefetchable memory, then the PCI bus driver needs to include requests for
 | 
						|
          // prefetchable memory in the nonprefetchable memory pool.
 | 
						|
          //
 | 
						|
          if (((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) &&
 | 
						|
              ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0)
 | 
						|
             ) {
 | 
						|
            return EFI_INVALID_PARAMETER;
 | 
						|
          }
 | 
						|
        case ACPI_ADDRESS_SPACE_TYPE_IO:
 | 
						|
          //
 | 
						|
          // Check aligment, it should be of the form 2^n-1
 | 
						|
          //
 | 
						|
          if (GetPowerOfTwo64 (Descriptor->AddrRangeMax + 1) != (Descriptor->AddrRangeMax + 1)) {
 | 
						|
            return EFI_INVALID_PARAMETER;
 | 
						|
          }
 | 
						|
          break;
 | 
						|
        default:
 | 
						|
          ASSERT (FALSE);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
 | 
						|
        if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
 | 
						|
          if (Descriptor->AddrSpaceGranularity == 32) {
 | 
						|
            if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
 | 
						|
              Type = TypePMem32;
 | 
						|
            } else {
 | 
						|
              Type = TypeMem32;
 | 
						|
            }
 | 
						|
          } else {
 | 
						|
            ASSERT (Descriptor->AddrSpaceGranularity == 64);
 | 
						|
            if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
 | 
						|
              Type = TypePMem64;
 | 
						|
            } else {
 | 
						|
              Type = TypeMem64;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          ASSERT (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO);
 | 
						|
          Type = TypeIo;
 | 
						|
        }
 | 
						|
        RootBridge->ResAllocNode[Type].Length    = Descriptor->AddrLen;
 | 
						|
        RootBridge->ResAllocNode[Type].Alignment = Descriptor->AddrRangeMax;
 | 
						|
        RootBridge->ResAllocNode[Type].Status    = ResSubmitted;
 | 
						|
      }
 | 
						|
      RootBridge->ResourceSubmitted = TRUE;
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This function returns the proposed resource settings for the specified
 | 
						|
  PCI Root Bridge.
 | 
						|
 | 
						|
  @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
 | 
						|
  @param RootBridgeHandle  The PCI Root Bridge handle.
 | 
						|
  @param Configuration     The pointer to the pointer to the PCI I/O
 | 
						|
                           and memory resource descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Not enough pool to be allocated.
 | 
						|
  @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid handle.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
GetProposedResources (
 | 
						|
  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
 | 
						|
  IN  EFI_HANDLE                                       RootBridgeHandle,
 | 
						|
  OUT VOID                                             **Configuration
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY                        *Link;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE          *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE          *RootBridge;
 | 
						|
  UINTN                             Index;
 | 
						|
  UINTN                             Number;
 | 
						|
  VOID                              *Buffer;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
 | 
						|
  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
 | 
						|
  UINT64                            ResStatus;
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
      ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
      ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
      ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    if (RootBridgeHandle == RootBridge->Handle) {
 | 
						|
      for (Index = 0, Number = 0; Index < TypeBus; Index++) {
 | 
						|
        if (RootBridge->ResAllocNode[Index].Status != ResNone) {
 | 
						|
          Number++;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
 | 
						|
      if (Buffer == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Buffer;
 | 
						|
      for (Index = 0; Index < TypeBus; Index++) {
 | 
						|
        ResStatus = RootBridge->ResAllocNode[Index].Status;
 | 
						|
        if (ResStatus != ResNone) {
 | 
						|
          Descriptor->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
 | 
						|
          Descriptor->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;
 | 
						|
          Descriptor->GenFlag               = 0;
 | 
						|
          //
 | 
						|
          // AddrRangeMin in Resource Descriptor here should be device address
 | 
						|
          // instead of host address, or else PCI bus driver cannot set correct
 | 
						|
          // address into PCI BAR registers.
 | 
						|
          // Base in ResAllocNode is a host address, so conversion is needed.
 | 
						|
          //
 | 
						|
          Descriptor->AddrRangeMin          = TO_DEVICE_ADDRESS (RootBridge->ResAllocNode[Index].Base,
 | 
						|
            GetTranslationByResourceType (RootBridge, Index));
 | 
						|
          Descriptor->AddrRangeMax          = 0;
 | 
						|
          Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;
 | 
						|
          Descriptor->AddrLen               = RootBridge->ResAllocNode[Index].Length;
 | 
						|
 | 
						|
          switch (Index) {
 | 
						|
 | 
						|
          case TypeIo:
 | 
						|
            Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_IO;
 | 
						|
            break;
 | 
						|
 | 
						|
          case TypePMem32:
 | 
						|
            Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
 | 
						|
          case TypeMem32:
 | 
						|
            Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
 | 
						|
            Descriptor->AddrSpaceGranularity = 32;
 | 
						|
            break;
 | 
						|
 | 
						|
          case TypePMem64:
 | 
						|
            Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
 | 
						|
          case TypeMem64:
 | 
						|
            Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
 | 
						|
            Descriptor->AddrSpaceGranularity = 64;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          Descriptor++;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
 | 
						|
      End->Desc      = ACPI_END_TAG_DESCRIPTOR;
 | 
						|
      End->Checksum  = 0;
 | 
						|
 | 
						|
      *Configuration = Buffer;
 | 
						|
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This function is called for all the PCI controllers that the PCI
 | 
						|
  bus driver finds. Can be used to Preprogram the controller.
 | 
						|
 | 
						|
  @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
 | 
						|
  @param RootBridgeHandle  The PCI Root Bridge handle.
 | 
						|
  @param PciAddress        Address of the controller on the PCI bus.
 | 
						|
  @param Phase             The Phase during resource allocation.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Succeed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid handle.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PreprocessController (
 | 
						|
  IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL          *This,
 | 
						|
  IN  EFI_HANDLE                                                RootBridgeHandle,
 | 
						|
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS               PciAddress,
 | 
						|
  IN  EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE              Phase
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY                *Link;
 | 
						|
  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
 | 
						|
  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
 | 
						|
 | 
						|
  if ((UINT32) Phase > EfiPciBeforeResourceCollection) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
 | 
						|
  for (Link = GetFirstNode (&HostBridge->RootBridges)
 | 
						|
       ; !IsNull (&HostBridge->RootBridges, Link)
 | 
						|
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
 | 
						|
       ) {
 | 
						|
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
 | 
						|
    if (RootBridgeHandle == RootBridge->Handle) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 |