__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout MdeModulePkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
		
			
				
	
	
		
			1737 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1737 lines
		
	
	
		
			59 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) ? DEBUG_ERROR : DEBUG_VERBOSE,
 | |
|       "%a: %a: add [%Lx, %Lx): %r\n",
 | |
|       gEfiCallerBaseName,
 | |
|       __func__,
 | |
|       IntersectionBase,
 | |
|       IntersectionEnd,
 | |
|       Status
 | |
|       ));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_ERROR,
 | |
|     "%a: %a: desc [%Lx, %Lx) type %u conflicts with "
 | |
|     "aperture [%Lx, %Lx)\n",
 | |
|     gEfiCallerBaseName,
 | |
|     __func__,
 | |
|     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 ((
 | |
|       DEBUG_ERROR,
 | |
|       "%a: %a: GetIoSpaceMap(): %r\n",
 | |
|       gEfiCallerBaseName,
 | |
|       __func__,
 | |
|       Status
 | |
|       ));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NumberOfDescriptors; Index++) {
 | |
|     Status = IntersectIoDescriptor (Base, Length, &IoSpaceMap[Index]);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto FreeIoSpaceMap;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DEBUG_CODE_BEGIN ();
 | |
|   //
 | |
|   // 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);
 | |
|   }
 | |
| 
 | |
|   DEBUG_CODE_END ();
 | |
| 
 | |
| 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) ? DEBUG_ERROR : DEBUG_VERBOSE,
 | |
|       "%a: %a: add [%Lx, %Lx): %r\n",
 | |
|       gEfiCallerBaseName,
 | |
|       __func__,
 | |
|       IntersectionBase,
 | |
|       IntersectionEnd,
 | |
|       Status
 | |
|       ));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_ERROR,
 | |
|     "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
 | |
|     "with aperture [%Lx, %Lx) cap %Lx\n",
 | |
|     gEfiCallerBaseName,
 | |
|     __func__,
 | |
|     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 ((
 | |
|       DEBUG_ERROR,
 | |
|       "%a: %a: GetMemorySpaceMap(): %r\n",
 | |
|       gEfiCallerBaseName,
 | |
|       __func__,
 | |
|       Status
 | |
|       ));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NumberOfDescriptors; Index++) {
 | |
|     Status = IntersectMemoryDescriptor (
 | |
|                Base,
 | |
|                Length,
 | |
|                Capabilities,
 | |
|                &MemorySpaceMap[Index]
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto FreeMemorySpaceMap;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DEBUG_CODE_BEGIN ();
 | |
|   //
 | |
|   // 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);
 | |
|   }
 | |
| 
 | |
|   DEBUG_CODE_END ();
 | |
| 
 | |
| 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 ((DEBUG_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 ((DEBUG_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",
 | |
|                 __func__,
 | |
|                 DEBUG_LINE_NUMBER,
 | |
|                 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 ((DEBUG_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 ((
 | |
|           DEBUG_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 ((DEBUG_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;
 | |
| }
 |