diff options
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe')
9 files changed, 3571 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.c b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.c new file mode 100644 index 0000000..e660935 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.c @@ -0,0 +1,1414 @@ +/** @file + Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "Token.h" // <<< AMI_OVERRIDE +#include "PciHostBridge.h" +#include "PciRootBridge.h" +#include "PchAccess.h" // <<< AMI_OVERRIDE - EIP# 42483 - Support for Multi-Monitor >>> +#ifndef GUID_VARIABLE_DECLARATION // AMI_OVERRIDE ... EIP#42483: MemCeiling support <<>> +#define GUID_VARIABLE_DECLARATION(Variable, Guid) extern EFI_GUID Variable +#endif +#include <Protocol\NBMemInfo.h> // AMI_OVERRIDE ... EIP#42483: MemCeiling support <<>> +/// +/// Support 64 K IO space +/// Moving RES_IO_BASE due to new ACPI Base address 0x1800 +/// +#define RES_IO_BASE 0x2000 +#define RES_IO_LIMIT 0xFFFF + +/// +/// Support 4G address space +/// +#define RES_MEM_LIMIT_1 ((UINTN) MmPciAddress (0,0,0,0,0) - 1) + +/// +/// Hard code: Root Bridge Number within the host bridge +/// Root Bridge's attribute +/// Root Bridge's device path +/// Root Bridge's resource aperture +/// +static UINTN RootBridgeNumber[1] = { 1 }; +/// +/// Hard code EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM 0 to support prefetchable memory allocation +/// +#ifdef AMI_COMBINE_MEM_PMEM_FLAG +static UINT64 RootBridgeAttribute[1][1] = { EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM }; +#else // AMI_COMBINE_MEM_PMEM_FLAG +static UINT64 RootBridgeAttribute[1][1] = { 0 }; +#endif // AMI_COMBINE_MEM_PMEM_FLAG +static EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[1][1] = { + { + ACPI_DEVICE_PATH, + ACPI_DP, + (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), + (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8), + EISA_PNP_ID(0x0A03), + 0, + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + END_DEVICE_PATH_LENGTH, + 0 + } +}; + +static PCI_ROOT_BRIDGE_RESOURCE_APERTURE mResAperture[1][1] = { { 0, ((UINT8)((PCIEX_LENGTH >> 20) - 1)), 0, 0xffffffff, 0, 1 << 16 } }; // <<< AMI_OVERRIDE +static EFI_HANDLE mDriverImageHandle; +CHAR16 gMemoryCeilingVariable[] = L"MemCeil."; // AMI_OVERRIDE ... EIP#42483: MemCeiling support <<>> +EFI_GUID gEfiNbMrcS3DataGuid = EFI_NB_MRC_S3_DATA_GUID; // AMI_OVERRIDE ... EIP#42483: MemCeiling support <<>> + +// AMI_OVERRIDE ... Fixed GenericSio use 0x0 ~ 0xfff issue start. +// It will Override CoreAllocateIoSpace. +static EFI_ALLOCATE_IO_SPACE gAmiCoreAllocateIoSpace; + +EFI_STATUS +NbCspOverrideCoreAllocateIoSpace ( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_IO_TYPE GcdIoType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_GCD_IO_SPACE_DESCRIPTOR IoDescriptor; + + if (GcdIoType == EfiGcdIoTypeIo && *BaseAddress < RES_IO_BASE) + { + if(GcdAllocateType == EfiGcdAllocateAddress) + { + Status = gDS->GetIoSpaceDescriptor(*BaseAddress, &IoDescriptor); + if(!EFI_ERROR(Status)) + { + if(IoDescriptor.GcdIoType == EfiGcdIoTypeNonExistent) + { + Status = gDS->AddIoSpace ( + EfiGcdIoTypeIo, + *BaseAddress, + Length + ); +// ASSERT_EFI_ERROR (Status); + } + } + } + } + + return gAmiCoreAllocateIoSpace ( + GcdAllocateType, + GcdIoType, + Alignment, + Length, + BaseAddress, + ImageHandle, + DeviceHandle + ); +} +// AMI_OVERRIDE ... Fixed GenericSio use 0x0 ~ 0xfff issue end. + +//AMI_OVERRIDE START // AMI_OVERRIDE ... EIP#42483: MemCeiling support ...Start... +EFI_STATUS +HbCspAdjustMemoryMmioOverlap ( + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + UINTN NumberOfDescriptors; + PCI_RES_NODE res; + UINTN i; + EFI_PHYSICAL_ADDRESS Highest4GMem = 0; + EFI_PHYSICAL_ADDRESS LowestMMIO = 0xffffffff; + EFI_PHYSICAL_ADDRESS LowestAllocMMIO = 0xffffffff; + UINTN MemoryCeiling = 0; //Init to zero incase variable doesn't exist. + UINTN NewMemoryCeiling = 0xffffffff; + UINTN DataSize = sizeof(UINT32); + EFI_PHYSICAL_ADDRESS NeededBottomMmio; + UINT32 Attributes = 0; // [ EIP167027 ] + +//------------------------------------ + //Status = gRT->GetVariable ( // [ EIP167027 ] + // gMemoryCeilingVariable, + // &gEfiNbMrcS3DataGuid, + // NULL, + // &DataSize, + // &MemoryCeiling ); + Status = gRT->GetVariable ( + gMemoryCeilingVariable, + &gEfiNbMrcS3DataGuid, + &Attributes, + &DataSize, + &MemoryCeiling ); + + DEBUG((-1, "OEM trace - GetVariable MemCeil Status = %r\n", Status)); + + if (EFI_ERROR(Status)) + Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS; + + if (Status == EFI_NOT_FOUND) { + //Status = gRT->GetVariable ( // [ EIP167027 ] + // gMemoryCeilingVariable, + // &gEfiGlobalVariableGuid, + // NULL, + // &DataSize, + // &MemoryCeiling + // ); + Status = gRT->GetVariable ( + gMemoryCeilingVariable, + &gEfiGlobalVariableGuid, + &Attributes, + &DataSize, + &MemoryCeiling + ); + + if (!EFI_ERROR(Status)) { + //gRT->SetVariable ( // [ EIP167027 ] + // gMemoryCeilingVariable, + // &gEfiNbMrcS3DataGuid, + // EFI_VARIABLE_NON_VOLATILE + // + EFI_VARIABLE_BOOTSERVICE_ACCESS + // + EFI_VARIABLE_RUNTIME_ACCESS, + // DataSize, + // &MemoryCeiling + //); + gRT->SetVariable ( + gMemoryCeilingVariable, + &gEfiNbMrcS3DataGuid, + Attributes, + DataSize, + &MemoryCeiling + ); + } + else + Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS; + } + + //Memory sizing uses memory ceiling to set top of memory. + + Status = gDS->GetMemorySpaceMap(&NumberOfDescriptors, &MemorySpaceMap); + ASSERT_EFI_ERROR(Status); + + //Find the lowest MMIO and lowest allocated MMIO in GCD. + for(i = 0; i < NumberOfDescriptors; ++i) { + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descr = &MemorySpaceMap[i]; + EFI_PHYSICAL_ADDRESS Base = Descr->BaseAddress; + //Find highest system below 4GB memory. + //Treat any non MMIO as system memory. Not all system memory is reported as system memory, + //such as SMM. + if (Descr->GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo && Base < LowestMMIO) { + EFI_PHYSICAL_ADDRESS EndMem = Base + Descr->Length - 1; + if (EndMem > Highest4GMem && EndMem <= 0xffffffff) Highest4GMem = EndMem; + + //Find Lowest mmio above system memory. + } else if (Descr->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { + if (Base >= 0x100000) { + if (Base < LowestMMIO) LowestMMIO = Base; + //If ImageHandle, then MMIO is allocated. + if (Base < LowestAllocMMIO && Descr->ImageHandle) LowestAllocMMIO = Base; + } + } + } + + (gBS->FreePool)(MemorySpaceMap); + + if (Highest4GMem + 1 != LowestMMIO) { + DEBUG((-1, "PciHostCSHooks: System Memory and MMIO are not consequitive.\n Top of Below 4G Memory: %lX\n Bottom of MMIO: %x%x\n", + Highest4GMem, LowestMMIO )); + } + + //Find any MMIO that could not be allocated due to small of MMIO region. + NeededBottomMmio = LowestAllocMMIO; + for(i = 0; i < TypeMax; ++i) { + + res=RootBridgeInstance->ResAllocNode[i]; + if ((res.Type == TypeMem32 && (res.Status != ResNone) && (res.Status != ResAllocated)) || + (res.Type == TypePMem32 && (res.Status != ResNone) && (res.Status != ResAllocated))) { + //Determine new memory ceiling variable needed to allocate this memory. + NeededBottomMmio = NeededBottomMmio - res.Length; + NeededBottomMmio &= ~(res.Alignment); + if (NeededBottomMmio < NewMemoryCeiling) NewMemoryCeiling = (UINTN) NeededBottomMmio; + } + } + + if (NewMemoryCeiling < 0xffffffff) { //Check if a NewMemory Ceiling is needed. + + // Adjust the granularity + NewMemoryCeiling &= (~(TOP_LOW_MEM_GRANULARITY - 1)); + + if (MemoryCeiling == NewMemoryCeiling) return EFI_SUCCESS; //No change in system configuration. Nothing more to do. Just exit. + + // Change in system config, so MMIO requirement changed. Update MemCeil and do reset. + // Set memory ceiling variable. + //gRT->SetVariable( // [ EIP167027 ] + // gMemoryCeilingVariable, + // &gEfiNbMrcS3DataGuid, + // EFI_VARIABLE_NON_VOLATILE + // + EFI_VARIABLE_BOOTSERVICE_ACCESS + // + EFI_VARIABLE_RUNTIME_ACCESS, + // DataSize, + // &NewMemoryCeiling + //); + gRT->SetVariable( + gMemoryCeilingVariable, + &gEfiNbMrcS3DataGuid, + Attributes, + DataSize, + &NewMemoryCeiling + ); + + DEBUG((-1, "Adjusting maximum top of RAM.\n Resetting System.\n")); + +#if (NV_SIMULATION != 1) + //Reset only needed of type of physical memory overlaps with MMIO. + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); +#endif + + } + + return Status; +} +//AMI_OVERRIDE ... // AMI_OVERRIDE ... EIP#42483: MemCeiling support ...END... + +EFI_DRIVER_ENTRY_POINT (PciHostBridgeEntryPoint) +/// +/// Implementation +/// +/** + Entry point of this driver + + @param[in] ImageHandle - + @param[in] SystemTable - + + @retval EFI_SUCCESS - Driver Start OK + @retval EFI_DEVICE_ERROR - Fail to install PCI_ROOT_BRIDGE_IO protocol. +**/ +EFI_STATUS +EFIAPI +PciHostBridgeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN Loop1; + UINTN Loop2; + PCI_HOST_BRIDGE_INSTANCE *HostBridge; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PHYSICAL_ADDRESS PciBaseAddress; + EFI_PHYSICAL_ADDRESS RemapBase; + EFI_PHYSICAL_ADDRESS RemapLimit; + EFI_PHYSICAL_ADDRESS MeSegMask; + EFI_PHYSICAL_ADDRESS MeStolenSize; + BOOLEAN MeStolenEnable; + UINT32 Tolud; + UINT64 Length; + EFI_PHYSICAL_ADDRESS BaseAddress; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; +#ifndef AMI_OVERRIDE_FOR_REMAP_DISABLED + EFI_PHYSICAL_ADDRESS MeStolenBase; +#endif // AMI_OVERRIDE_FOR_REMAP_DISABLED + + INITIALIZE_SCRIPT (ImageHandle, SystemTable); + + mDriverImageHandle = ImageHandle; + + /// + /// This system has one Host Bridge (one Root Bridge in this Host Bridge) + /// + /// + /// Create Host Bridge Device Handle + /// + for (Loop1 = 0; Loop1 < HOST_BRIDGE_NUMBER; Loop1++) { + Status = (gBS->AllocatePool) (EfiBootServicesData, sizeof (PCI_HOST_BRIDGE_INSTANCE), (VOID **) &HostBridge); + ASSERT (!EFI_ERROR (Status)); + + HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE; + HostBridge->RootBridgeNumber = RootBridgeNumber[Loop1]; + HostBridge->ResourceSubmited = FALSE; + HostBridge->CanRestarted = TRUE; + + /// + /// InitializeListHead (&HostBridge->Head); + /// + 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; + HostBridge->HostBridgeHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &HostBridge->HostBridgeHandle, + &gEfiPciHostBridgeResourceAllocationProtocolGuid, + EFI_NATIVE_INTERFACE, + &HostBridge->ResAlloc + ); + if (EFI_ERROR (Status)) { + (gBS->FreePool) (HostBridge); + return EFI_DEVICE_ERROR; + } + /// + /// Create Root Bridge Device Handle in this Host Bridge + /// + InitializeListHead (&HostBridge->Head); + for (Loop2 = 0; Loop2 < HostBridge->RootBridgeNumber; Loop2++) { + Status = (gBS->AllocatePool) (EfiBootServicesData, sizeof (PCI_ROOT_BRIDGE_INSTANCE), (VOID **) &PrivateData); + ASSERT (!EFI_ERROR (Status)); + + PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE; + PrivateData->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &mEfiPciRootBridgeDevicePath[Loop1][Loop2]; + RootBridgeConstructor ( + &PrivateData->Io, + HostBridge->HostBridgeHandle, + RootBridgeAttribute[Loop1][Loop2], + &mResAperture[Loop1][Loop2] + ); + PrivateData->Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &PrivateData->Handle, + &gEfiDevicePathProtocolGuid, + PrivateData->DevicePath, + &gEfiPciRootBridgeIoProtocolGuid, + &PrivateData->Io, + NULL + ); + if (EFI_ERROR (Status)) { + (gBS->FreePool) (PrivateData); + return EFI_DEVICE_ERROR; + } + + InsertTailList (&HostBridge->Head, &PrivateData->Link); + } + } + /// + /// Allocate 60 KB of I/O space [0x1000..0xFFFF] + /// + Status = gDS->AddIoSpace ( + EfiGcdIoTypeIo, + RES_IO_BASE, + RES_IO_LIMIT - RES_IO_BASE + 1 + ); + ASSERT_EFI_ERROR (Status); + + // AMI_OVERRIDE ... Fixed GenericSio use 0x0 ~ 0xfff issue start. + // It will Override CoreAllocateIoSpace. + gAmiCoreAllocateIoSpace = gDS->AllocateIoSpace; + gDS->AllocateIoSpace = NbCspOverrideCoreAllocateIoSpace; + // AMI_OVERRIDE ... Fixed GenericSio use 0x0 ~ 0xfff issue end. + + /// + /// Allocate PCI memory space. + /// + /// + /// Read memory map registers + /// + RemapBase = McD0PciCfg64 (R_SA_REMAPBASE) & B_SA_REMAPBASE_REMAPBASE_MASK; + RemapLimit = McD0PciCfg64 (R_SA_REMAPLIMIT) & B_SA_REMAPLIMIT_REMAPLMT_MASK; + Tolud = McD0PciCfg32 (R_SA_TOLUD) & B_SA_TOLUD_TOLUD_MASK; + PciBaseAddress = Tolud; + MeSegMask = McD0PciCfg64 (R_SA_MESEG_MASK); + MeStolenEnable = (BOOLEAN) ((MeSegMask & B_SA_MESEG_MASK_ME_STLEN_EN_MASK) != 0); + + /// + /// First check if memory remap is used + /// + if ((RemapBase > RemapLimit) && (MeStolenEnable)) { + MeStolenSize = MeSegMask & B_SA_MESEG_MASK_MEMASK_MASK; + if (MeStolenSize != 0) { + MeStolenSize = 0x8000000000L - MeStolenSize; +#ifndef AMI_OVERRIDE_FOR_REMAP_DISABLED + // Remap is disabled -> if Me Stolen Base on PCI resume, PCI resume - MeStolenSize. + MeStolenBase = McD0PciCfg64 (R_SA_MESEG_BASE); + if(MeStolenBase < RES_MEM_LIMIT_1) { + // + // Remap is disabled -> PCI starts at TOLUD + ME Stolen size + // + PciBaseAddress += MeStolenSize; + } +#endif // AMI_OVERRIDE_FOR_REMAP_DISABLED + } + /// + /// Remap is disabled -> PCI starts at TOLUD + ME Stolen size + /// +#ifdef AMI_OVERRIDE_FOR_REMAP_DISABLED + PciBaseAddress += MeStolenSize; +#endif // AMI_OVERRIDE_FOR_REMAP_DISABLED + } + + Length = RES_MEM_LIMIT_1 - PciBaseAddress + 1; + + if (Length != 0) { + DEBUG ( + ( + EFI_D_INFO, " Allocating PCI space from 0x%X to 0x%X\n", (UINT32) PciBaseAddress, (UINT32) + (PciBaseAddress + Length - 1) + ) + ); + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + PciBaseAddress, + Length, + 0 + ); + ASSERT_EFI_ERROR (Status); + } + /// + /// Get CPU Family and Stepping ID + /// + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + + /// + /// WA for HSW A0. To exclude the ranges 20000000-201FFFFF (2MB) and 0x40004000-0x40004FFF (4KB). + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + if (McD0PciCfg32 (R_SA_DEVEN) & B_SA_DEVEN_D2EN_MASK) { + BaseAddress = 0x20000000; + Status = (gBS->AllocatePages) (AllocateAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (0x00200000), &BaseAddress); + + BaseAddress = 0x40004000; + Status = (gBS->AllocatePages) (AllocateAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (0x00001000), &BaseAddress); + } + } + + return EFI_SUCCESS; +} + +/** + Enter a certain phase of the PCI enumeration process + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance + @param[in] 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 *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + PCI_RESOURCE_TYPE Index; + LIST_ENTRY *List; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 AddrLen; + UINTN BitsOfAlignment; + UINT64 Alignment; + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + switch (Phase) { + case EfiPciHostBridgeBeginEnumeration: + if (HostBridgeInstance->CanRestarted) { + /// + /// Reset the Each Root Bridge + /// + List = HostBridgeInstance->Head.ForwardLink; + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + for (Index = TypeIo; Index < TypeMax; Index++) { + RootBridgeInstance->ResAllocNode[Index].Type = Index; + RootBridgeInstance->ResAllocNode[Index].Base = 0; + RootBridgeInstance->ResAllocNode[Index].Length = 0; + RootBridgeInstance->ResAllocNode[Index].Status = ResNone; + } + + List = List->ForwardLink; + } + + HostBridgeInstance->ResourceSubmited = FALSE; + HostBridgeInstance->CanRestarted = TRUE; + } else { + /// + /// Can not restart + /// + return EFI_NOT_READY; + } + break; + + case EfiPciHostBridgeBeginBusAllocation: + /// + /// No specific action is required here, can perform any chipset specific programing + /// + HostBridgeInstance->CanRestarted = FALSE; + return EFI_SUCCESS; + break; + + case EfiPciHostBridgeEndBusAllocation: + /// + /// No specific action is required here, can perform any chipset specific programing + /// + return EFI_SUCCESS; + break; + + case EfiPciHostBridgeBeginResourceAllocation: + /// + /// No specific action is required here, can perform any chipset specific programing + /// + return EFI_SUCCESS; + break; + + case EfiPciHostBridgeAllocateResources: + ReturnStatus = EFI_SUCCESS; + if (HostBridgeInstance->ResourceSubmited) { + /// + /// Take care of the resource dependencies between the root bridges + /// + List = HostBridgeInstance->Head.ForwardLink; + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + + Status = HbCspAdjustMemoryMmioOverlap(RootBridgeInstance); // <<< AMI_OVERRIDE - EIP# 42483 - Support for Multi-Monitor >>> + + for (Index = TypeIo; Index < TypeBus; Index++) { + if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) { + AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; + Alignment = RootBridgeInstance->ResAllocNode[Index].Alignment; + + /// + /// Get the number of '1' in Alignment. + /// + for (BitsOfAlignment = 0; Alignment != 0; BitsOfAlignment++) { + Alignment = RShiftU64 (Alignment, 1); + } + + switch (Index) { + case TypeIo: + /// + /// It is impossible for this chipset to align 0xFFFF for IO16 + /// So clear it + /// + if (BitsOfAlignment >= 16) { + BitsOfAlignment = 0; + } + +#ifndef AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + // Support MaxAddressSearchTopDown for Gcd Io + BaseAddress = 0xFFFF; +#endif // AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + + Status = gDS->AllocateIoSpace ( +#ifdef AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + EfiGcdAllocateAnySearchBottomUp, +#else // AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + EfiGcdAllocateMaxAddressSearchTopDown, +#endif // AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + EfiGcdIoTypeIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + mDriverImageHandle, + NULL + ); + if (!EFI_ERROR (Status)) { + RootBridgeInstance->ResAllocNode[Index].Base = (UINTN) BaseAddress; + RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated; + } else { + /// + /// Not able to allocate enough I/O memory - critical stop + /// + DEBUG ((EFI_D_ERROR, "Out of I/O space! AllocateIoSpace() returned %r\n", Status)); + DEBUG ((EFI_D_ERROR, "Size requested: 0x%lX bytes\n", AddrLen)); + ReturnStatus = Status; + } + break; + + case TypeMem32: + case TypePMem32: + /// + /// It is impossible for this chipset to align 0xFFFFFFFF for Mem32 + /// So clear it + /// + if (BitsOfAlignment >= 32) { + BitsOfAlignment = 0; + } + +#ifndef AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + // Support MMIO 4G to Tolud for EfiGcdAllocateMaxAddressSearchTopDown + BaseAddress = 0xFFFFFFFF; +#endif // AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + /// + /// Fall through to TypeMem64 / TypePMem64... + /// + case TypeMem64: + case TypePMem64: + Status = gDS->AllocateMemorySpace ( +#ifdef AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + EfiGcdAllocateAnySearchBottomUp, +#else // AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + EfiGcdAllocateMaxAddressSearchTopDown, +#endif // AMI_ORIGINAL_FOR_MMIO_4G_TOLUD + EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + mDriverImageHandle, + NULL + ); + if (!EFI_ERROR (Status)) { + /// + /// We were able to allocate the PCI memory + /// + RootBridgeInstance->ResAllocNode[Index].Base = (UINTN) BaseAddress; + RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated; + } else { + /// + /// Not able to allocate enough PCI memory - critical stop + /// + DEBUG ((EFI_D_ERROR, "Out of PCI memory! AllocateMemorySpace() returned %r\n", Status)); + DEBUG ((EFI_D_ERROR, "Size requested: 0x%lX bytes\n", AddrLen)); + ReturnStatus = Status; + } + break; + default: + break; + } + /// + /// end switch + /// + } + } + + List = List->ForwardLink; + } + + return ReturnStatus; + } else { + return EFI_NOT_READY; + } + break; + + case EfiPciHostBridgeSetResources: + break; + + case EfiPciHostBridgeFreeResources: + ReturnStatus = EFI_SUCCESS; + + List = HostBridgeInstance->Head.ForwardLink; + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + for (Index = TypeIo; Index < TypeBus; Index++) { + if (RootBridgeInstance->ResAllocNode[Index].Status == ResAllocated) { + AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; + BaseAddress = RootBridgeInstance->ResAllocNode[Index].Base; + switch (Index) { + case TypeIo: + Status = gDS->FreeIoSpace (BaseAddress, AddrLen); + break; + + case TypeMem32: + case TypePMem32: + case TypeMem64: + case TypePMem64: + Status = gDS->FreeMemorySpace (BaseAddress, AddrLen); + break; + + default: + Status = EFI_INVALID_PARAMETER; + + } + + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + /// + /// end switch + /// + RootBridgeInstance->ResAllocNode[Index].Type = Index; + RootBridgeInstance->ResAllocNode[Index].Base = 0; + RootBridgeInstance->ResAllocNode[Index].Length = 0; + RootBridgeInstance->ResAllocNode[Index].Status = ResNone; + } + } + + List = List->ForwardLink; + } + + HostBridgeInstance->ResourceSubmited = FALSE; + HostBridgeInstance->CanRestarted = TRUE; + return ReturnStatus; + break; + + case EfiPciHostBridgeEndResourceAllocation: + HostBridgeInstance->CanRestarted = FALSE; + break; + + default: + return EFI_INVALID_PARAMETER; + } + /// + /// end switch + /// + return EFI_SUCCESS; +} + +/** + Return the device handle of the next PCI root bridge that is associated with + this Host Bridge + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] 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 NoRootBridge; + LIST_ENTRY *List; + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + + NoRootBridge = TRUE; + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + List = HostBridgeInstance->Head.ForwardLink; + + while (List != &HostBridgeInstance->Head) { + NoRootBridge = FALSE; + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (*RootBridgeHandle == NULL) { + /// + /// Return the first Root Bridge Handle of the Host Bridge + /// + *RootBridgeHandle = RootBridgeInstance->Handle; + return EFI_SUCCESS; + } else { + if (*RootBridgeHandle == RootBridgeInstance->Handle) { + /// + /// Get next if have + /// + List = List->ForwardLink; + if (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + *RootBridgeHandle = RootBridgeInstance->Handle; + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + } + } + + List = List->ForwardLink; + } + /// + /// end while + /// + if (NoRootBridge) { + return EFI_NOT_FOUND; + } else { + return EFI_INVALID_PARAMETER; + } +} + +/** + Returns the attributes of a PCI Root Bridge. + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance. + @param[in] RootBridgeHandle - The device handle of the PCI Root Bridge + that the caller is interested in + @param[in] 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 *List; + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + + if (Attributes == NULL) { + return EFI_INVALID_PARAMETER; + } + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + List = HostBridgeInstance->Head.ForwardLink; + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (RootBridgeHandle == RootBridgeInstance->Handle) { + *Attributes = RootBridgeInstance->RootBridgeAttrib; + return EFI_SUCCESS; + } + + List = List->ForwardLink; + } + /// + /// RootBridgeHandle is not an EFI_HANDLE + /// that was returned on a previous call to GetNextRootBridge() + /// + 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[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance. + @param[in] RootBridgeHandle - The PCI Root Bridge to be set up. + @param[in] 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 *List; + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + VOID *Buffer; + UINT8 *Temp; + EFI_STATUS Status; + UINT64 BusStart; + UINT64 BusEnd; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + List = HostBridgeInstance->Head.ForwardLink; + + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (RootBridgeHandle == RootBridgeInstance->Handle) { + /// + /// Set up the Root Bridge for Bus Enumeration + /// + BusStart = RootBridgeInstance->BusBase; + BusEnd = RootBridgeInstance->BusLimit; + + /// + /// Program the Hardware(if needed) if error return EFI_DEVICE_ERROR + /// + Status = (gBS->AllocatePool) ( + EfiBootServicesData, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), &Buffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Temp = (UINT8 *) Buffer; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Len = 0x2B; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->GenFlag = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->SpecificFlag = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrSpaceGranularity = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMin = BusStart; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMax = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrTranslationOffset = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrLen = BusEnd - BusStart + 1; + + Temp = Temp + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc = ACPI_END_TAG_DESCRIPTOR; + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum = 0x0; + *Configuration = Buffer; + return EFI_SUCCESS; + } + + List = List->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + +/** + This function programs the PCI Root Bridge hardware so that + it decodes the specified PCI bus range + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge whose bus range is to be programmed + @param[in] 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 *List; + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + UINT8 *Ptr; + UINTN BusStart; + UINTN BusEnd; + UINTN BusLen; + + if (Configuration == NULL) { + return EFI_INVALID_PARAMETER; + } + + Ptr = Configuration; + + /// + /// Check the Configuration is valid + /// + if (*Ptr != ACPI_ADDRESS_SPACE_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) { + return EFI_INVALID_PARAMETER; + } + + Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + if (*Ptr != ACPI_END_TAG_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + List = HostBridgeInstance->Head.ForwardLink; + Ptr = Configuration; + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (RootBridgeHandle == RootBridgeInstance->Handle) { + BusStart = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrRangeMin; + BusLen = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrLen; + BusEnd = BusStart + BusLen - 1; + if (BusStart > BusEnd) { + return EFI_INVALID_PARAMETER; + } + + if ((BusStart < RootBridgeInstance->BusBase) || (BusEnd > RootBridgeInstance->BusLimit)) { + return EFI_INVALID_PARAMETER; + } + /// + /// Update the Bus Range + /// + RootBridgeInstance->ResAllocNode[TypeBus].Base = BusStart; + RootBridgeInstance->ResAllocNode[TypeBus].Length = BusLen; + RootBridgeInstance->ResAllocNode[TypeBus].Status = ResAllocated; + + /// + /// Program the Root Bridge Hardware + /// + return EFI_SUCCESS; + } + + List = List->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Submits the I/O and memory resource requirements for the specified PCI Root Bridge + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge whose I/O and memory resource requirements + are being submitted + @param[in] 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 *List; + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + UINT8 *Temp; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr; + UINT64 AddrLen; + UINT64 Alignment; + + /// + /// Check the input parameter: Configuration + /// + if (Configuration == NULL) { + return EFI_INVALID_PARAMETER; + } + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + List = HostBridgeInstance->Head.ForwardLink; + Temp = (UINT8 *) Configuration; + while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } + + if (*Temp != ACPI_END_TAG_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + Temp = (UINT8 *) Configuration; + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (RootBridgeHandle == RootBridgeInstance->Handle) { + while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + + /// + /// Check address range alignment + /// + if (ptr->AddrRangeMax >= (UINT64) 0xffffffff || + ptr->AddrRangeMax != (Power2MaxMemory (ptr->AddrRangeMax + 1) - 1) + ) { + return EFI_INVALID_PARAMETER; + } + + switch (ptr->ResType) { + case ACPI_ADDRESS_SPACE_TYPE_MEM: + /// + /// check the memory resource request is supported by PCI root bridge + /// + /// Hard code EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM 0 to support prefetchable memory allocation + /// + if (RootBridgeInstance->RootBridgeAttrib == 0 && ptr->SpecificFlag == 0x06) { + return EFI_INVALID_PARAMETER; + } + + AddrLen = (UINT64) ptr->AddrLen; + Alignment = (UINT64) ptr->AddrRangeMax; + if (ptr->AddrSpaceGranularity == 32) { + if ((ptr->SpecificFlag & 0x06) == 0x06) { + /// + /// Apply from GCD + /// + RootBridgeInstance->ResAllocNode[TypePMem32].Length = AddrLen; + RootBridgeInstance->ResAllocNode[TypePMem32].Alignment = Alignment; + RootBridgeInstance->ResAllocNode[TypePMem32].Status = ResRequested; + HostBridgeInstance->ResourceSubmited = TRUE; + + } else { + RootBridgeInstance->ResAllocNode[TypeMem32].Length = AddrLen; + RootBridgeInstance->ResAllocNode[TypeMem32].Alignment = Alignment; + RootBridgeInstance->ResAllocNode[TypeMem32].Status = ResRequested; + HostBridgeInstance->ResourceSubmited = TRUE; + } + } + + if (ptr->AddrSpaceGranularity == 64) { + if ((ptr->SpecificFlag & 0x06) == 0x06) { + RootBridgeInstance->ResAllocNode[TypePMem64].Length = AddrLen; + RootBridgeInstance->ResAllocNode[TypePMem64].Alignment = Alignment; + RootBridgeInstance->ResAllocNode[TypePMem64].Status = ResSubmitted; + HostBridgeInstance->ResourceSubmited = TRUE; + + } else { + RootBridgeInstance->ResAllocNode[TypeMem64].Length = AddrLen; + RootBridgeInstance->ResAllocNode[TypeMem64].Alignment = Alignment; + RootBridgeInstance->ResAllocNode[TypeMem64].Status = ResSubmitted; + HostBridgeInstance->ResourceSubmited = TRUE; + } + } + break; + + case ACPI_ADDRESS_SPACE_TYPE_IO: + AddrLen = (UINT64) ptr->AddrLen; + Alignment = (UINT64) ptr->AddrRangeMax; + RootBridgeInstance->ResAllocNode[TypeIo].Length = AddrLen; + RootBridgeInstance->ResAllocNode[TypeIo].Alignment = Alignment; + RootBridgeInstance->ResAllocNode[TypeIo].Status = ResRequested; + HostBridgeInstance->ResourceSubmited = TRUE; + break; + + default: + break; + } + + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } + + return EFI_SUCCESS; + } + + List = List->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + +/** + This function returns the proposed resource settings for the specified + PCI Root Bridge + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge handle + @param[in] 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 *List; + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + UINTN Index; + UINTN Number; + VOID *Buffer; + UINT8 *Temp; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr; + EFI_STATUS Status; + UINT64 ResStatus; + + Buffer = NULL; + Number = 0; + + /// + /// Get the Host Bridge Instance from the resource allocation protocol + /// + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + List = HostBridgeInstance->Head.ForwardLink; + + /// + /// Enumerate the root bridges in this host bridge + /// + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (RootBridgeHandle == RootBridgeInstance->Handle) { + for (Index = 0; Index < TypeBus; Index++) { + if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) { + Number++; + } + } + + if (Number > 0) { + Status = (gBS->AllocatePool) + ( + EfiBootServicesData, Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), &Buffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (Buffer, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Number + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + + Temp = Buffer; + for (Index = 0; Index < TypeBus; Index++) { + if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) { + ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + ResStatus = RootBridgeInstance->ResAllocNode[Index].Status; + switch (Index) { + case TypeIo: + /// + /// Io + /// + ptr->Desc = 0x8A; + ptr->Len = 0x2B; + ptr->ResType = 1; + ptr->GenFlag = 0; + ptr->SpecificFlag = 0; + ptr->AddrRangeMin = RootBridgeInstance->ResAllocNode[Index].Base; + ptr->AddrRangeMax = 0; + ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; + break; + + case TypeMem32: + /// + /// Memory 32 + /// + ptr->Desc = 0x8A; + ptr->Len = 0x2B; + ptr->ResType = 0; + ptr->GenFlag = 0; + ptr->SpecificFlag = 0; + ptr->AddrSpaceGranularity = 32; + ptr->AddrRangeMin = RootBridgeInstance->ResAllocNode[Index].Base; + ptr->AddrRangeMax = 0; + ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; + break; + + case TypePMem32: + /// + /// Prefetch memory 32 + /// + ptr->Desc = 0x8A; + ptr->Len = 0x2B; + ptr->ResType = 0; + ptr->GenFlag = 0; + ptr->SpecificFlag = 6; + ptr->AddrSpaceGranularity = 32; + ptr->AddrRangeMin = 0; + ptr->AddrRangeMax = 0; + ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; + break; + + case TypeMem64: + /// + /// Memory 64 + /// + ptr->Desc = 0x8A; + ptr->Len = 0x2B; + ptr->ResType = 0; + ptr->GenFlag = 0; + ptr->SpecificFlag = 0; + ptr->AddrSpaceGranularity = 64; + ptr->AddrRangeMin = 0; + ptr->AddrRangeMax = 0; + ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; + break; + + case TypePMem64: + /// + /// Prefetch memory 64 + /// + ptr->Desc = 0x8A; + ptr->Len = 0x2B; + ptr->ResType = 0; + ptr->GenFlag = 0; + ptr->SpecificFlag = 6; + ptr->AddrSpaceGranularity = 64; + ptr->AddrRangeMin = 0; + ptr->AddrRangeMax = 0; + ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; + break; + } + + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } + } + + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc = 0x79; + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum = 0x0; + *Configuration = Buffer; + } + + return EFI_SUCCESS; + } + + List = List->ForwardLink; + } + + 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[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge handle + @param[in] PciAddress - Address of the controller on the PCI bus + @param[in] 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 + ) +{ + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + LIST_ENTRY *List; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + List = HostBridgeInstance->Head.ForwardLink; + + /// + /// Enumerate the root bridges in this host bridge + /// + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (RootBridgeHandle == RootBridgeInstance->Handle) { + return EFI_SUCCESS; + } + + List = List->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Calculate max memory of power 2 + + @param[in] MemoryLength - Input memory length. + + @retval Returned Maximum length. +**/ +UINT64 +Power2MaxMemory ( + IN UINT64 MemoryLength + ) +{ + UINT64 Result; + + if (RShiftU64 (MemoryLength, 32)) { + Result = LShiftU64 ((UINT64) GetPowerOfTwo64 (RShiftU64 (MemoryLength, 32)), 32); + } else { + Result = (UINT64) GetPowerOfTwo64 (MemoryLength); + } + + return Result; +} diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.cif b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.cif new file mode 100644 index 0000000..55f38b5 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.cif @@ -0,0 +1,15 @@ +<component> + name = "PciHostBridge" + category = ModulePart + LocalRoot = "ReferenceCode\Chipset\SystemAgent\PciHostBridge\Dxe\" + RefName = "PciHostBridge" +[files] +"PciHostBridge.sdl" +"PciHostBridge.mak" +"PciHostBridge.c" +"PciHostBridge.h" +"PciHostBridge.dxs" +"PciRootBridgeIo.c" +"PciRootBridge.h" +"PciHostBridge.inf" +<endComponent> diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.dxs b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.dxs new file mode 100644 index 0000000..87cf509 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.dxs @@ -0,0 +1,43 @@ +/** @file + Dependency expression source file. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + + +// +// Common for R8 and R9 codebase +// +#include "AutoGen.h" +#include "DxeDepex.h" + +// +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase; +// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase. +// +#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB) +#include "EfiDepex.h" + +#include EFI_PROTOCOL_DEFINITION (CpuIo) +#include EFI_ARCH_PROTOCOL_DEFINITION (Metronome) +#endif + +DEPENDENCY_START + EFI_CPU_IO_PROTOCOL_GUID AND + EFI_METRONOME_ARCH_PROTOCOL_GUID +DEPENDENCY_END diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.h b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.h new file mode 100644 index 0000000..d94ff48 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.h @@ -0,0 +1,234 @@ +/** @file + The Header file of the Pci Host Bridge Driver + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#ifndef _PCI_HOST_BRIDGE_H_ +#define _PCI_HOST_BRIDGE_H_ + +#include "EdkIIGlueDxe.h" +#include "CpuRegs.h" +#include "CpuPlatformLib.h" + +#include EFI_PROTOCOL_DEFINITION (PciHostBridgeResourceAllocation) + +/// +/// Hard code the host bridge number in the platform. +/// In this chipset, there is only one host bridge. +/// +#define HOST_BRIDGE_NUMBER 1 + +#define PCI_HOST_BRIDGE_SIGNATURE EFI_SIGNATURE_32 ('e', 'h', 's', 't') +typedef struct { + UINTN Signature; + EFI_HANDLE HostBridgeHandle; + UINTN RootBridgeNumber; + LIST_ENTRY Head; + BOOLEAN ResourceSubmited; + BOOLEAN CanRestarted; + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc; +} PCI_HOST_BRIDGE_INSTANCE; + +#define INSTANCE_FROM_RESOURCE_ALLOCATION_THIS(a) CR (a, PCI_HOST_BRIDGE_INSTANCE, ResAlloc, PCI_HOST_BRIDGE_SIGNATURE) + +/// +/// HostBridge Resource Allocation interface +/// +/** + Enter a certain phase of the PCI enumeration process + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance + @param[in] 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 + ) +; + +/** + Return the device handle of the next PCI root bridge that is associated with + this Host Bridge + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] 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 + ) +; + +/** + Returns the attributes of a PCI Root Bridge. + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance. + @param[in] RootBridgeHandle - The device handle of the PCI Root Bridge + that the caller is interested in + @param[in] 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 + ) +; + +/** + This is the request from the PCI enumerator to set up + the specified PCI Root Bridge for bus enumeration process. + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance. + @param[in] RootBridgeHandle - The PCI Root Bridge to be set up. + @param[in] 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 + ) +; + +/** + This function programs the PCI Root Bridge hardware so that + it decodes the specified PCI bus range + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge whose bus range is to be programmed + @param[in] 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 + ) +; + +/** + Submits the I/O and memory resource requirements for the specified PCI Root Bridge + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge whose I/O and memory resource requirements + are being submitted + @param[in] 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 + ) +; + +/** + This function returns the proposed resource settings for the specified + PCI Root Bridge + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge handle + @param[in] 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 + ) +; + +/** + This function is called for all the PCI controllers that the PCI + bus driver finds. Can be used to Preprogram the controller. + + @param[in] This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle - The PCI Root Bridge handle + @param[in] PciAddress - Address of the controller on the PCI bus + @param[in] 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 struct _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 + ) +; + +/** + Calculate max memory of power 2 + + @param[in] MemoryLength - Input memory length. + + @retval Returned Maximum length. +**/ +UINT64 +Power2MaxMemory ( + IN UINT64 MemoryLength + ) +; + +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.inf b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.inf new file mode 100644 index 0000000..0c4561c --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.inf @@ -0,0 +1,86 @@ +## @file +# Component description file for PciHostBridge module +# {8D6756B9-E55E-4d6a-A3A5-5E4D72DDF772} +# 0x8d6756b9, 0xee5e, 0x4d6a, 0xa3, 0xa5, 0x5e, 0x4d, 0x72, 0xdd, 0xf7, 0x72 +# +#@copyright +# Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# This file contains a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +# + +[defines] +BASE_NAME = PciHostBridge +FILE_GUID = 8D6756B9-E55E-4d6a-A3A5-5E4D72DDF772 +COMPONENT_TYPE = BS_DRIVER + +[sources.common] + PciHostBridge.h + PciHostBridge.c + PciRootBridge.h + PciRootBridgeIo.c +# +# Edk II Glue Driver Entry Point +# + EdkIIGlueDxeDriverEntryPoint.c + +[includes.common] + $(EDK_SOURCE)/Foundation/Efi + $(EDK_SOURCE)/Foundation + $(EDK_SOURCE)/Foundation/Framework + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework/Include + $(EDK_SOURCE)/Foundation/Include/IndustryStandard + $(EFI_SOURCE) + $(EDK_SOURCE)/Foundation/Core/Dxe + $(EDK_SOURCE)/Foundation/Library/Dxe/Include + $(EFI_SOURCE)/$(PROJECT_SA_ROOT) + $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include + $(EDK_SOURCE)/Foundation/Cpu/Pentium/Include + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT) + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include/Library + +[libraries.common] + ArchProtocolLib + EdkFrameworkProtocolLib + EfiScriptLib + EdkIIGlueBaseLib + EdkIIGlueBaseIoLibIntrinsic + EdkIIGlueDxeDebugLibReportStatusCode + EdkIIGlueDxeReportStatusCodeLib + EdkIIGlueUefiBootServicesTableLib + EdkIIGlueUefiRuntimeServicesTableLib + EdkIIGlueDxeServicesTableLib + EdkIIGlueUefiLib + CPUIA32LIB + EdkIIGlueDxeMemoryAllocationLib + EdkProtocolLib + CpuPlatformLib + +[nmake.common] + IMAGE_ENTRY_POINT = _ModuleEntryPoint + DPX_SOURCE = PciHostBridge.dxs + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=PciHostBridgeEntryPoint \ + -D __EDKII_GLUE_BASE_LIB__ \ + -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + -D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \ + -D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + -D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_UEFI_LIB__\ + -D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \ + diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.mak b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.mak new file mode 100644 index 0000000..fe3614c --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.mak @@ -0,0 +1,67 @@ +#--------------------------------------------------------------------------- +# Create PCI Host Bridge DXE Component +#--------------------------------------------------------------------------- +EDK : PciHostBridge + +PciHostBridge : $(BUILD_DIR)\PciHostBridge.mak PciHostBridgeBin + +$(BUILD_DIR)\PciHostBridge.mak : $(PciHostBridge_DIR)\PciHostBridge.cif $(BUILD_RULES) + $(CIF2MAK) $(PciHostBridge_DIR)\PciHostBridge.cif $(CIF2MAK_DEFAULTS) + +PciHostBridge_INCLUDES=\ + $(EdkIIGlueLib_INCLUDES)\ + $(EDK_INCLUDES)\ + $(PROJECT_CPU_INCLUDES)\ + $(INTEL_MCH_INCLUDES)\ + $(INTEL_PCH_INCLUDES)\ + /IInclude + +PciHostBridge_DEFINES =$(MY_DEFINES)\ + /D "__EDKII_GLUE_MODULE_ENTRY_POINT__=PciHostBridgeEntryPoint" \ + /D __EDKII_GLUE_BASE_LIB__ \ + /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + /D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + /D __EDKII_GLUE_UEFI_LIB__\ + /D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \ + /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \ + +PciHostBridge_LIB_LINKS =\ + $(ArchProtocolLib)\ + $(EFISCRIPTLIB)\ + $(EDKFRAMEWORKPROTOCOLLIB)\ + $(EdkIIGlueBaseIoLibIntrinsic_LIB)\ + $(EdkIIGlueBaseLib_LIB)\ +!IF "$(x64_BUILD)"=="1" + $(EdkIIGlueBaseLibX64_LIB)\ +!ELSE + $(EdkIIGlueBaseLibIA32_LIB)\ +!ENDIF + $(EdkIIGlueDxeReportStatusCodeLib_LIB)\ + $(EdkIIGlueDxeServicesTableLib_LIB)\ + $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\ + $(EdkIIGlueUefiBootServicesTableLib_LIB)\ + $(EdkIIGlueUefiLib_LIB)\ + $(EdkIIGlueDxeMemoryAllocationLib_LIB)\ + $(EdkIIGlueUefiBootServicesTableLib_LIB)\ + $(EdkIIGlueUefiRuntimeServicesTableLib_LIB)\ + $(EdkIIGlueBasePciLibPciExpress_LIB)\ + $(EDKPROTOCOLLIB)\ + $(EFIDRIVERLIB)\ + $(CpuPlatformLib_LIB)\ + $(PchPlatformDxeLib_LIB) + +PciHostBridgeBin : $(PciHostBridge_LIB_LINKS) + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\PciHostBridge.mak all\ + GUID=8D6756B9-E55E-4d6a-A3A5-5E4D72DDF772 \ + ENTRY_POINT=_ModuleEntryPoint \ + "MY_DEFINES=$(PciHostBridge_DEFINES)"\ + "MY_INCLUDES=$(PciHostBridge_INCLUDES)"\ + TYPE=BS_DRIVER \ + EDKIIModule=DXEDRIVER\ + DEPEX1=$(PciHostBridge_DIR)\PciHostBridge.dxs\ + DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX\ + COMPRESS=1 diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.sdl b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.sdl new file mode 100644 index 0000000..9e2b5b3 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciHostBridge.sdl @@ -0,0 +1,41 @@ +TOKEN + Name = "PciHostBridge_SUPPORT" + Value = "1" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Master = Yes + Help = "Main switch to enable PciHostBridge support in Project" + Token = "AMI_ROOT_BRIDGE_SUPPORT" "=" "0" +End + +TOKEN + Name = "TOP_LOW_MEM_GRANULARITY" + Value = "0x10000000" + Help = "Adjust the MMIO granularity size 256MB." + TokenType = Integer + TargetH = Yes +End + +MODULE + Help = "Includes PciHostBridge.mak to Project" + File = "PciHostBridge.mak" +End + +PATH + Name = "PciHostBridge_DIR" +End + +ELINK + Name = "$(BUILD_DIR)\PciHostBridge.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +ELINK + Name = "/D AMI_COMBINE_MEM_PMEM_FLAG" + Parent = "GLOBAL_DEFINES" + InvokeOrder = AfterParent + Token = "COMBINE_MEM_PMEM" "=" "1" +End
\ No newline at end of file diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridge.h b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridge.h new file mode 100644 index 0000000..557755e --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridge.h @@ -0,0 +1,156 @@ +/** @file + The driver for the host to pci bridge (root bridge). + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_ + +#include "EdkIIGlueDxe.h" +#include "Acpi.h" +#include "EfiScriptLib.h" +#include "SaAccess.h" + +/// +/// Driver Consumed Protocol Prototypes +/// +#include EFI_ARCH_PROTOCOL_DEFINITION (Metronome) +#include EFI_PROTOCOL_CONSUMER (CpuIo) + +/// +/// Driver Produced Protocol Prototypes +/// +#include EFI_PROTOCOL_DEFINITION (DevicePath) +#include EFI_PROTOCOL_DEFINITION (PciRootBridgeIo) + +/// +/// Define resource status constant +/// +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFF +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFE +#define EFI_RESOURCE_SATISFIED 0x0000000000000000 + +/// +/// Driver Instance Data Prototypes +/// +typedef struct { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation; + UINTN NumberOfBytes; + UINTN NumberOfPages; + EFI_PHYSICAL_ADDRESS HostAddress; + EFI_PHYSICAL_ADDRESS MappedHostAddress; +} MAP_INFO; + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +typedef struct { + UINT64 BusBase; + UINT64 BusLimit; + UINT64 MemBase; + UINT64 MemLimit; + UINT64 IoBase; + UINT64 IoLimit; +} PCI_ROOT_BRIDGE_RESOURCE_APERTURE; + +typedef enum { + TypeIo = 0, + TypeMem32, + TypePMem32, + TypeMem64, + TypePMem64, + TypeBus, + TypeMax +} PCI_RESOURCE_TYPE; + +typedef enum { + ResNone = 0, + ResSubmitted, + ResRequested, + ResAllocated, + ResStatusMax +} RES_STATUS; + +typedef struct { + PCI_RESOURCE_TYPE Type; + UINT64 Base; + UINT64 Length; + UINT64 Alignment; + RES_STATUS Status; +} PCI_RES_NODE; + +#define PCI_ROOT_BRIDGE_SIGNATURE EFI_SIGNATURE_32 ('e', '2', 'p', 'b') + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + EFI_HANDLE Handle; + UINT64 RootBridgeAttrib; + UINT64 Attributes; + UINT64 Supports; + + /// + /// Specific for this memory controller: Bus, I/O, Mem + /// + PCI_RES_NODE ResAllocNode[6]; + + /// + /// Addressing for Memory and I/O and Bus arrange + /// + UINT64 BusBase; + UINT64 MemBase; + UINT64 IoBase; + UINT64 BusLimit; + UINT64 MemLimit; + UINT64 IoLimit; + EFI_LOCK PciLock; + UINTN PciAddress; + UINTN PciData; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; +} PCI_ROOT_BRIDGE_INSTANCE; + +/// +/// Driver Instance Data Macros +/// +#define DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, Io, PCI_ROOT_BRIDGE_SIGNATURE) + +#define DRIVER_INSTANCE_FROM_LIST_ENTRY(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_ROOT_BRIDGE_SIGNATURE) + +/** + Construct the Pci Root Bridge Io protocol + + @param[in] Protocol - Point to protocol instance + @param[in] HostBridgeHandle - Handle of host bridge + @param[in] Attri - Attribute of host bridge + @param[in] ResAperture - ResourceAperture for host bridge + + @retval EFI_SUCCESS - Success to initialize the Pci Root Bridge. +**/ +EFI_STATUS +RootBridgeConstructor ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN EFI_HANDLE HostBridgeHandle, + IN UINT64 Attri, + IN PCI_ROOT_BRIDGE_RESOURCE_APERTURE *ResAperture + ) +; + +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c new file mode 100644 index 0000000..a3a0447 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c @@ -0,0 +1,1515 @@ +/** @file + EFI Memory Controller PCI Root Bridge Io Protocol + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PciRootBridge.h" +#include "Pci22.h" + +typedef struct { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR SpaceDesp[TypeMax]; + EFI_ACPI_END_TAG_DESCRIPTOR EndDesp; +} RESOURCE_CONFIGURATION; + +RESOURCE_CONFIGURATION Configuration = { + { + { + 0x8A, + 0x2B, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 0, + 32, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 6, + 32, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 0, + 64, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 6, + 64, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + } + }, + { + 0x79, + 0 + } +}; + +/// +/// Protocol Member Function Prototypes +/// +EFI_STATUS +EFIAPI +RootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +RootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +RootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoCopyMem ( + IN struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +EFI_STATUS +EFIAPI +RootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +RootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +RootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +EFI_STATUS +EFIAPI +RootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +RootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +RootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +RootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +RootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +/// +/// Sub Function Prototypes +/// +typedef union { + UINT8 VOLATILE *buf; + UINT8 VOLATILE *ui8; + UINT16 VOLATILE *ui16; + UINT32 VOLATILE *ui32; + UINT64 VOLATILE *ui64; + UINTN VOLATILE ui; +} PTR; + +STATIC +EFI_STATUS +RootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +/// +/// Memory Controller Pci Root Bridge Io Module Variables +/// +EFI_METRONOME_ARCH_PROTOCOL *mMetronome; +EFI_CPU_IO_PROTOCOL *mCpuIo; + +/** + Construct the Pci Root Bridge Io protocol + + @param Protocol - Point to protocol instance + @param HostBridgeHandle - Handle of host bridge + @param Attri - Attribute of host bridge + @param ResAperture - ResourceAperture for host bridge + + @retval EFI_SUCCESS - Success to initialize the Pci Root Bridge. +**/ +EFI_STATUS +RootBridgeConstructor ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN EFI_HANDLE HostBridgeHandle, + IN UINT64 Attri, + IN PCI_ROOT_BRIDGE_RESOURCE_APERTURE *ResAperture + ) +{ + EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + PCI_RESOURCE_TYPE Index; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (Protocol); + + /// + /// The host to pci bridge, the host memory and io addresses are + /// direct mapped to pci addresses, so no need translate, set bases to 0. + /// + PrivateData->MemBase = ResAperture->MemBase; + PrivateData->IoBase = ResAperture->IoBase; + + /// + /// The host bridge only supports 32bit addressing for memory + /// and standard IA32 16bit io + /// + PrivateData->MemLimit = ResAperture->MemLimit; + PrivateData->IoLimit = ResAperture->IoLimit; + + /// + /// Bus Aperture for this Root Bridge (Possible Range) + /// + PrivateData->BusBase = ResAperture->BusBase; + PrivateData->BusLimit = ResAperture->BusLimit; + + /// + /// Specific for this chipset + /// + for (Index = TypeIo; Index < TypeMax; Index++) { + PrivateData->ResAllocNode[Index].Type = Index; + PrivateData->ResAllocNode[Index].Base = 0; + PrivateData->ResAllocNode[Index].Length = 0; + PrivateData->ResAllocNode[Index].Status = ResNone; + } + + EfiInitializeLock (&PrivateData->PciLock, EFI_TPL_HIGH_LEVEL); + PrivateData->PciAddress = 0xCF8; + PrivateData->PciData = 0xCFC; + PrivateData->RootBridgeAttrib = Attri; + PrivateData->Attributes = 0; + /// + /// Set both ISA_IO and ISA_IO_16 / VGA_IO and VGA_IO_16 to co-work + /// with EDK and EDK2 PCI bus driver. + /// + PrivateData->Supports = EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO | + EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | + EFI_PCI_ATTRIBUTE_ISA_IO | + EFI_PCI_ATTRIBUTE_ISA_IO_16 | + EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | + EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 | + EFI_PCI_ATTRIBUTE_VGA_MEMORY | + EFI_PCI_ATTRIBUTE_VGA_IO | + EFI_PCI_ATTRIBUTE_VGA_IO_16; + Protocol->ParentHandle = HostBridgeHandle; + Protocol->PollMem = RootBridgeIoPollMem; + Protocol->PollIo = RootBridgeIoPollIo; + Protocol->Mem.Read = RootBridgeIoMemRead; + Protocol->Mem.Write = RootBridgeIoMemWrite; + Protocol->Io.Read = RootBridgeIoIoRead; + Protocol->Io.Write = RootBridgeIoIoWrite; + Protocol->CopyMem = RootBridgeIoCopyMem; + Protocol->Pci.Read = RootBridgeIoPciRead; + Protocol->Pci.Write = RootBridgeIoPciWrite; + Protocol->Map = RootBridgeIoMap; + Protocol->Unmap = RootBridgeIoUnmap; + Protocol->AllocateBuffer = RootBridgeIoAllocateBuffer; + Protocol->FreeBuffer = RootBridgeIoFreeBuffer; + Protocol->Flush = RootBridgeIoFlush; + Protocol->GetAttributes = RootBridgeIoGetAttributes; + Protocol->SetAttributes = RootBridgeIoSetAttributes; + Protocol->Configuration = RootBridgeIoConfiguration; + Protocol->SegmentNumber = 0; + Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, (VOID **) &mCpuIo); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Polls an address in memory mapped I/O space until an exit condition is met, or + a timeout occurs. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] Address - The base address of the memory operations. The caller is + responsible for aligning Address if required. + @param[in] Mask - Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the memory address. + @param[in] Value - The comparison value used for the polling exit criteria. + @param[in] Delay - The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result - Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS - The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER - Width is invalid or Result is NULL.. + @retval EFI_TIMEOUT - Delay expired before a match occurred. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + /// + /// No matter what, always do a single poll. + /// + Status = This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } else { + /// + /// Determine the proper # of metronome ticks to wait for polling the + /// location. The nuber of ticks is Roundup (Delay / mMetronome->TickPeriod)+1 + /// The "+1" to account for the possibility of the first tick being short + /// because we started in the middle of a tick. + /// + NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, &Remainder); + if (Remainder != 0) { + NumberOfTicks += 1; + } + + NumberOfTicks += 1; + while (NumberOfTicks) { + mMetronome->WaitForTick (mMetronome, 1); + Status = This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + + return EFI_TIMEOUT; +} + +/** + Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the I/O operations. + @param[in] Address - The base address of the I/O operations. The caller is responsible + for aligning Address if required. + @param[in] Mask - Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the I/O address. + @param[in] Value - The comparison value used for the polling exit criteria. + @param[in] Delay - The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result - Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS - The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER - Width is invalid or Result is NULL. + @retval EFI_TIMEOUT - Delay expired before a match occurred. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + /// + /// No matter what, always do a single poll. + /// + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + Status = This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } else { + /// + /// Determine the proper # of metronome ticks to wait for polling the + /// location. The number of ticks is Roundup (Delay / mMetronome->TickPeriod)+1 + /// The "+1" to account for the possibility of the first tick being short + /// because we started in the middle of a tick. + /// + NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, &Remainder); + if (Remainder != 0) { + NumberOfTicks += 1; + } + + NumberOfTicks += 1; + while (NumberOfTicks) { + mMetronome->WaitForTick (mMetronome, 1); + Status = This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + + return EFI_TIMEOUT; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operation. + @param[in] Address - The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count - The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + +// AMI_OVERRIDE (EIP#106042+)>> + // Fix Fpt.efi not work, accessing Rom decode region could cause AEL bit + // be set, and, Pci Resource should not be inside rom decode region. + if ((Address >= 0xff000000) && (Address <= 0xffffffff)) { + return EFI_INVALID_PARAMETER; + } +// AMI_OVERRIDE << + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// Check memory access limit + /// + if (Address < PrivateData->MemBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 > PrivateData->MemLimit) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Mem.Read ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operation. + @param[in] Address - The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count - The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// Check memory access limit + /// + if (Address < PrivateData->MemBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 > PrivateData->MemLimit) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Mem.Write ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] UserAddress - The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count - The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[in, out] UserBuffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + + UINTN AlignMask; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// AlignMask = (1 << Width) - 1; + /// + AlignMask = (1 << (Width & 0x03)) - 1; + + /// + /// Check Io access limit + /// + if (Address < PrivateData->IoBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 >= PrivateData->IoLimit) { + return EFI_INVALID_PARAMETER; + } + + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Io.Read ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] UserAddress - The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count - The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[in, out] UserBuffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + UINTN AlignMask; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// AlignMask = (1 << Width) - 1; + /// + AlignMask = (1 << (Width & 0x03)) - 1; + + /// + /// Check Io access limit + /// + if (Address < PrivateData->IoBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 >= PrivateData->IoLimit) { + return EFI_INVALID_PARAMETER; + } + + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Io.Write ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI + root bridge memory space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance. + @param[in] Width - Signifies the width of the memory operations. + @param[in] DestAddress - The destination address of the memory operation. The caller is + responsible for aligning the DestAddress if required. + @param[in] SrcAddress - The source address of the memory operation. The caller is + responsible for aligning the SrcAddress if required. + @param[in] Count - The number of memory operations to perform. Bytes moved is + Width size * Count, starting at DestAddress and SrcAddress. + + @retval EFI_SUCCESS - The data was copied from one memory region to another memory region. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoCopyMem ( + IN struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ) +{ + EFI_STATUS Status; + BOOLEAN Direction; + UINTN Stride; + UINTN Index; + UINT64 Result; + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + if (DestAddress == SrcAddress) { + return EFI_SUCCESS; + } + + Stride = (UINTN) (LShiftU64 (1, Width)); + Direction = TRUE; + if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) { + Direction = FALSE; + SrcAddress = SrcAddress + (Count - 1) * Stride; + DestAddress = DestAddress + (Count - 1) * Stride; + } + + for (Index = 0; Index < Count; Index++) { + Status = RootBridgeIoMemRead ( + This, + Width, + SrcAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = RootBridgeIoMemWrite ( + This, + Width, + DestAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Direction) { + SrcAddress += Stride; + DestAddress += Stride; + } else { + SrcAddress -= Stride; + DestAddress -= Stride; + } + } + + return EFI_SUCCESS; +} + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] Address - The address within the PCI configuration space for the PCI controller. + @param[in] Count - The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + /// + /// Read Pci configuration space + /// + return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] Address - The address within the PCI configuration space for the PCI controller. + @param[in] Count - The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + /// + /// Write Pci configuration space + /// + return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +} + +/** + Provides the PCI controller-specific addresses required to access system memory from a + DMA bus master. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Operation - Indicates if the bus master is going to read or write to system memory. + @param[in] HostAddress - The system memory address to map to the PCI controller. + @param[in, out] NumberOfBytes - On input the number of bytes to map. On output the number of bytes that were mapped. + @param[out] DeviceAddress - The resulting map address for the bus master PCI controller to use + to access the system memory's HostAddress. + @param[out] Mapping - The value to pass to Unmap() when the bus master DMA operation is complete. + + @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes. + @retval EFI_INVALID_PARAMETER - Operation is invalid. + @retval EFI_INVALID_PARAMETER - HostAddress or NumberOfBytes or DeviceAddress or Mapping is NULL. + @retval EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common buffer. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + MAP_INFO *MapInfo; + + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) { + return EFI_INVALID_PARAMETER; + } + /// + /// Initialize the return values to their defaults + /// + *Mapping = NULL; + + /// + /// Make sure that Operation is valid + /// + if (Operation < 0 || Operation >= EfiPciOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + /// + /// Most PCAT like chipsets can not handle performing DMA above 4GB. + /// If any part of the DMA transfer being mapped is above 4GB, then + /// map the DMA transfer to a buffer below 4GB. + /// + PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; + if ((PhysicalAddress +*NumberOfBytes) > 0x100000000) { + /// + /// Common Buffer operations can not be remapped. If the common buffer + /// if above 4GB, then it is not possible to generate a mapping, so return + /// an error. + /// + if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) { + return EFI_UNSUPPORTED; + } + /// + /// Allocate a MAP_INFO structure to remember the mapping when Unmap() is + /// called later. + /// + Status = (gBS->AllocatePool) (EfiBootServicesData, sizeof (MAP_INFO), (VOID **) &MapInfo); + if (EFI_ERROR (Status)) { + *NumberOfBytes = 0; + return Status; + } + /// + /// Return a pointer to the MAP_INFO structure in Mapping + /// + *Mapping = MapInfo; + + /// + /// Initialize the MAP_INFO structure + /// + MapInfo->Operation = Operation; + MapInfo->NumberOfBytes = *NumberOfBytes; + MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes); + MapInfo->HostAddress = PhysicalAddress; + MapInfo->MappedHostAddress = 0x00000000ffffffff; + + /// + /// Allocate a buffer below 4GB to map the transfer to. + /// + Status = (gBS->AllocatePages) (AllocateMaxAddress, EfiBootServicesData, MapInfo->NumberOfPages, &MapInfo->MappedHostAddress); + if (EFI_ERROR (Status)) { + (gBS->FreePool) (MapInfo); + *NumberOfBytes = 0; + return Status; + } + /// + /// If this is a read operation from the Bus Master's point of view, + /// then copy the contents of the real buffer into the mapped buffer + /// so the Bus Master can read the contents of the real buffer. + /// + if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) { + CopyMem ( + (VOID *) (UINTN) MapInfo->MappedHostAddress, + (VOID *) (UINTN) MapInfo->HostAddress, + MapInfo->NumberOfBytes + ); + } + /// + /// The DeviceAddress is the address of the maped buffer below 4GB + /// + *DeviceAddress = MapInfo->MappedHostAddress; + } else { + /// + /// The transfer is below 4GB, so the DeviceAddress is simply the HostAddress + /// + *DeviceAddress = PhysicalAddress; + } + + return EFI_SUCCESS; +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Mapping - The mapping value returned from Map(). + + @retval EFI_SUCCESS - The range was unmapped. + @retval EFI_INVALID_PARAMETER - Mapping is not a value that was returned by Map(). +**/ +EFI_STATUS +EFIAPI +RootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ) +{ + MAP_INFO *MapInfo; + + /// + /// See if the Map() operation associated with this Unmap() required a mapping buffer. + /// If a mapping buffer was not required, then this function simply returns EFI_SUCCESS. + /// + if (Mapping != NULL) { + /// + /// Get the MAP_INFO structure from Mapping + /// + MapInfo = (MAP_INFO *) Mapping; + + /// + /// If this is a write operation from the Bus Master's point of view, + /// then copy the contents of the mapped buffer into the real buffer + /// so the processor can read the contents of the real buffer. + /// + if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) { + CopyMem ( + (VOID *) (UINTN) MapInfo->HostAddress, + (VOID *) (UINTN) MapInfo->MappedHostAddress, + MapInfo->NumberOfBytes + ); + } + /// + /// Free the mapped buffer and the MAP_INFO structure. + /// + (gBS->FreePages) (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); + (gBS->FreePool) (Mapping); + } + + return EFI_SUCCESS; +} + +/** + Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or + EfiPciOperationBusMasterCommonBuffer64 mapping. + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Type - This parameter is not used and must be ignored. + @param MemoryType - The type of memory to allocate, EfiBootServicesData or EfiRuntimeServicesData. + @param Pages - The number of pages to allocate. + @param HostAddress - A pointer to store the base system memory address of the allocated range. + @param Attributes - The requested bit mask of attributes for the allocated range. Only + the attributes EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_ATTRIBUTE_MEMORY_CACHED, + and EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this function. + + @retval EFI_SUCCESS - The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER - MemoryType is invalid or HostAddress is NULL. + @retval EFI_UNSUPPORTED - Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and DUAL_ADDRESS_CYCLE. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + + /// + /// Validate Attributes + /// + if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { + return EFI_UNSUPPORTED; + } + /// + /// Check for invalid inputs + /// + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + /// + /// The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + /// + if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) { + return EFI_INVALID_PARAMETER; + } + /// + /// Limit allocations to memory below 4GB + /// + PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (0xffffffff); + Status = (gBS->AllocatePages) (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress); + if (EFI_ERROR (Status)) { + return Status; + } + + *HostAddress = (VOID *) (UINTN) PhysicalAddress; + return EFI_SUCCESS; +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + The FreeBuffer() function frees memory that was allocated with AllocateBuffer(). + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pages - The number of pages to free. + @param HostAddress - The base system memory address of the allocated range. + + @retval EFI_SUCCESS - The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER - The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ) +{ + return (gBS->FreePages) ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages); +} + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @retval EFI_SUCCESS - The PCI posted write transactions were flushed from the PCI host + bridge to system memory. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ) +{ + /// + /// not supported yet + /// + return EFI_SUCCESS; +} + +/** + Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the + attributes that a PCI root bridge is currently using. + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Supported - A pointer to the mask of attributes that this PCI root bridge + supports setting with SetAttributes(). + @param Attributes - A pointer to the mask of attributes that this PCI root bridge is + currently using. + + @retval EFI_SUCCESS - If Supports is not NULL, then the attributes that the PCI root + bridge supports is returned in Supports. If Attributes is + not NULL, then the attributes that the PCI root bridge is currently + using is returned in Attributes. + @retval EFI_INVALID_PARAMETER - Both Supports and Attributes are NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + if (Attributes == NULL && Supported == NULL) { + return EFI_INVALID_PARAMETER; + } + /// + /// Set the return value for Supported and Attributes + /// + if (Supported) { + *Supported = PrivateData->Supports; + } + + if (Attributes) { + *Attributes = PrivateData->Attributes; + } + + return EFI_SUCCESS; +} + +/** + Sets attributes for a resource range on a PCI root bridge. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Attributes - The mask of attributes to set. If the attribute bit + MEMORY_WRITE_COMBINE, MEMORY_CACHED, or + MEMORY_DISABLE is set, then the resource range is specified by + ResourceBase and ResourceLength. If + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and + MEMORY_DISABLE are not set, then ResourceBase and + ResourceLength are ignored, and may be NULL. + @param[in, out] ResourceBase - A pointer to the base address of the resource range to be modified + by the attributes specified by Attributes. + @param[in, out] ResourceLength - A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS - The current configuration of this PCI root bridge was returned in Resources. + @retval EFI_UNSUPPORTED - The current configuration of this PCI root bridge could not be retrieved. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + if (Attributes) { + if ((Attributes & (~(PrivateData->Supports))) != 0) { + return EFI_UNSUPPORTED; + } + } + + if (Attributes == PrivateData->Attributes) { + return EFI_SUCCESS; + } + /// + /// It is just a trick for some attribute can only be enabled or disabled + /// otherwise it can impact on other devices + /// + PrivateData->Attributes = Attributes; + return EFI_SUCCESS; +} + +/** + Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0 + resource descriptors. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[out] Resources - A pointer to the ACPI 2.0 resource descriptors that describe the + current configuration of this PCI root bridge. The storage for the + ACPI 2.0 resource descriptors is allocated by this function. The + caller must treat the return buffer as read-only data, and the buffer + must not be freed by the caller. + + @retval EFI_SUCCESS - The current configuration of this PCI root bridge was returned in Resources. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN Index; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + for (Index = 0; Index < TypeMax; Index++) { + if (PrivateData->ResAllocNode[Index].Status == ResAllocated) { + Configuration.SpaceDesp[Index].AddrRangeMin = PrivateData->ResAllocNode[Index].Base; + Configuration.SpaceDesp[Index].AddrRangeMax = PrivateData->ResAllocNode[Index].Base + + PrivateData->ResAllocNode[Index].Length - + 1; + Configuration.SpaceDesp[Index].AddrLen = PrivateData->ResAllocNode[Index].Length; + } + } + + *Resources = &Configuration; + return EFI_SUCCESS; +} + +/** + Internal help function for read and write PCI configuration space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Write - Switch value for Read or Write. + @param[in] Width - Signifies the width of the memory operations. + @param[in] UserAddress - The address within the PCI configuration space for the PCI controller. + @param[in] Count - The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in, out] UserBuffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +STATIC +EFI_STATUS +RootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + UINT32 InStride; + UINT32 OutStride; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr; + UINT8 *PcieRegAddr; + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + OutStride = 0; + } + + PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &UserAddress; + PcieRegAddr = (UINT8 *) MmPciAddress ( + 0, /// No segment support + PciRbAddr->Bus, + PciRbAddr->Device, + PciRbAddr->Function, + 0 /// Register is added next + ); + + /// + /// Add the register offset to the address + /// + if (PciRbAddr->ExtendedRegister != 0) { + PcieRegAddr += PciRbAddr->ExtendedRegister; + } else { + PcieRegAddr += PciRbAddr->Register; + } + + while (Count) { + if (Write) { + This->Mem.Write (This, Width, (UINTN) PcieRegAddr, 1, UserBuffer); + } else { + This->Mem.Read (This, Width, (UINTN) PcieRegAddr, 1, UserBuffer); + } + + UserBuffer = ((UINT8 *) UserBuffer) + OutStride; + PcieRegAddr += InStride; + Count -= 1; + } + + return EFI_SUCCESS; +} |