From d06da8dd6ddb71c0121de90bcdb0074332e7d2f1 Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Fri, 23 Dec 2016 10:59:38 +0800 Subject: BroxtonSiPkg: Add PciHostBridge Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../NorthCluster/PciHostBridge/Dxe/PciHostBridge.c | 1152 +++++++++++++++ .../NorthCluster/PciHostBridge/Dxe/PciHostBridge.h | 231 +++ .../PciHostBridge/Dxe/PciHostBridge.inf | 61 + .../NorthCluster/PciHostBridge/Dxe/PciRootBridge.h | 155 ++ .../PciHostBridge/Dxe/PciRootBridgeIo.c | 1563 ++++++++++++++++++++ 5 files changed, 3162 insertions(+) create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.inf create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridge.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridgeIo.c (limited to 'Silicon') diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.c b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.c new file mode 100644 index 0000000000..834cace036 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.c @@ -0,0 +1,1152 @@ +/** @file + Pci Host Bridge driver: + Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation. + + Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PciRootBridge.h" +#include "PciHostBridge.h" +#include "SaAccess.h" +#include "PlatformBaseAddresses.h" +#include +#include +#include + +// +// Support 64 K IO space +// +#define RES_IO_BASE 0x1000 +#define RES_IO_LIMIT 0xFFFF +// +// Support 4G address space +// +#define RES_MEM_BASE_1 0x80000000 +#define RES_MEM_LIMIT_1 (ACPI_MMIO_BASE_ADDRESS - 1) + +// +// Hard code: Root Bridge Number within the host bridge +// Root Bridge's attribute +// Root Bridge's device path +// Root Bridge's resource appeture +// +static UINTN RootBridgeNumber[1] = { 1 }; + +static UINT64 RootBridgeAttribute[1][1] = { EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM }; + +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_APPETURE mResAppeture[1][1] = { { 0, 255, 0, 0xffffffff, 0, 1 << 16 } }; + +static EFI_HANDLE mDriverImageHandle; + +// +// Implementation +// +/** + Entry point of PCI Host Bridge driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable A pointer to the EFI system table. + + @retval EFI_DEVICE_ERROR Start Failed. + @retval EFI_SUCCESS Driver Start OK. + @retval EFI_BUFFER_TOO_SMALL Fail to allocate required resource. + +**/ +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 dBMBOUND = 0; + UINT64 Length; + UINT32 buffer32; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR PciMemorySpaceDescriptor; + UINT64 BaseAddress; + UINT64 Attributes; + + 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++) { + HostBridge = AllocatePool (sizeof (PCI_HOST_BRIDGE_INSTANCE)); + if (HostBridge == NULL) { + ASSERT (FALSE); + return EFI_BUFFER_TOO_SMALL; + } + + HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE; + HostBridge->RootBridgeNumber = RootBridgeNumber[Loop1]; + HostBridge->ResourceSubmited = FALSE; + HostBridge->CanRestarted = TRUE; + + 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)) { + 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++) { + PrivateData = AllocatePool (sizeof (PCI_ROOT_BRIDGE_INSTANCE)); + if (PrivateData == NULL) { + ASSERT (FALSE); + return EFI_BUFFER_TOO_SMALL; + } + PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE; + + PrivateData->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &mEfiPciRootBridgeDevicePath[Loop1][Loop2]; + RootBridgeConstructor ( + &PrivateData->Io, + HostBridge->HostBridgeHandle, + RootBridgeAttribute[Loop1][Loop2], + &mResAppeture[Loop1][Loop2] + ); + + PrivateData->Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &PrivateData->Handle, + &gEfiDevicePathProtocolGuid, + PrivateData->DevicePath, + &gEfiPciRootBridgeIoProtocolGuid, + &PrivateData->Io, + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (PrivateData); + return EFI_DEVICE_ERROR; + } + InsertTailList (&HostBridge->Head, &PrivateData->Link); + } + } + + Status = gDS->AddIoSpace ( + EfiGcdIoTypeIo, + RES_IO_BASE, + RES_IO_LIMIT - RES_IO_BASE + 1 + ); + + buffer32 = (MmioRead32 ((UINTN) PcdGet64 (PcdPciExpressBaseAddress) + 0xBC) & 0xFFF00000); + dBMBOUND = (EFI_PHYSICAL_ADDRESS) (buffer32); + Length = RES_MEM_LIMIT_1 - dBMBOUND + 1; + if (Length) { + DEBUG ((EFI_D_INFO, "Allocating PCI space from 0x%X to 0x%X\n", (UINT32) dBMBOUND, (UINT32) (dBMBOUND + Length - 1))); + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + dBMBOUND, + Length, + 0 + ); + + DEBUG ((EFI_D_INFO, " Allocating ACPI MMIO space from 0x%X to 0x%X\n", ACPI_MMIO_BASE_ADDRESS, ACPI_MMIO_BASE_ADDRESS + ACPI_MMIO_SIZE - 1)); + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + ACPI_MMIO_BASE_ADDRESS, + ACPI_MMIO_SIZE, + 0 + ); + } + + // + // Reserve 0xE0000000 ~ 0xE4000000 as Pcie MMIO range + // + DEBUG ((EFI_D_INFO, "Allocating PCIe MMIO space from 0x%X to 0x%X\n", PCIE_MMIO_BASE_ADDRESS, PCIE_MMIO_BASE_ADDRESS + PCIE_MMIO_SIZE - 1)); + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + PCIE_MMIO_BASE_ADDRESS, + PCIE_MMIO_SIZE, + 0 + ); + + BaseAddress = (EFI_PHYSICAL_ADDRESS) PCIE_MMIO_BASE_ADDRESS; + Length = PCIE_MMIO_SIZE; + Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &PciMemorySpaceDescriptor); + ASSERT_EFI_ERROR (Status); + + Attributes = PciMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME; + + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + Length, + Attributes + ); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "Successfully changed memory attribute for PCIe\n")); + + 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 EfiPciHostBridgeEndEnumeration: + 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); + 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; + } + Status = gDS->AllocateIoSpace ( + EfiGcdAllocateAnySearchBottomUp, + EfiGcdIoTypeIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + mDriverImageHandle, + NULL + ); + if (!EFI_ERROR (Status)) { + RootBridgeInstance->ResAllocNode[Index].Base = (UINTN) BaseAddress; + RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated; + } else { + ReturnStatus = Status; + if (Status != EFI_OUT_OF_RESOURCES) { + RootBridgeInstance->ResAllocNode[Index].Length = 0; + } + } + break; + + case TypeMem32: + // + // It is impossible for this chipset to align 0xFFFFFFFF for Mem32 + // So clear it + // + if (BitsOfAlignment >= 32) { + BitsOfAlignment = 0; + } + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateAnySearchBottomUp, + 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 + // + ReturnStatus = Status; + + if (Status != EFI_OUT_OF_RESOURCES) { + RootBridgeInstance->ResAllocNode[Index].Length = 0; + } + // + // Reset + // + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + + } + break; + + case TypePMem32: + case TypeMem64: + case TypePMem64: + ReturnStatus = EFI_ABORTED; + break; + default: + break; + + } // end switch + } // end if + } //end while + + List = List->ForwardLink; + } //end if + + 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); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + break; + + case TypeMem32: + Status = gDS->FreeMemorySpace (BaseAddress, AddrLen); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + break; + + case TypePMem32: + break; + + case TypeMem64: + break; + + case TypePMem64: + break; + default: + break; + } //end switch + RootBridgeInstance->ResAllocNode[Index].Type = Index; + RootBridgeInstance->ResAllocNode[Index].Base = 0; + RootBridgeInstance->ResAllocNode[Index].Length = 0; + RootBridgeInstance->ResAllocNode[Index].Status = ResNone; + } //end if + } //end for + + 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,out] 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[out] 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[out] 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; + 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 + // + Buffer = AllocatePool ( + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) + ); + if (!Buffer) { + return EFI_OUT_OF_RESOURCES; + } + + Temp = (UINT8 *) Buffer; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Desc = 0x8A; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Len = 0x2B; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->ResType = 2; + ((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 = 0x79; + ((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 != 2) { + 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 == 0x8A) { + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } + + if (*Temp != 0x79) { + return EFI_INVALID_PARAMETER; + } + + Temp = (UINT8 *) Configuration; + while (List != &HostBridgeInstance->Head) { + RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); + if (RootBridgeHandle == RootBridgeInstance->Handle) { + while (*Temp == 0x8A) { + ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + + // + // Check Address Length + // + if (ptr->AddrLen > 0xffffffff) { + return EFI_INVALID_PARAMETER; + } + // + // Check address range alignment + // + if (ptr->AddrRangeMax >= 0xffffffff || ptr->AddrRangeMax != (Power2MaxMemory (ptr->AddrRangeMax + 1) - 1)) { + return EFI_INVALID_PARAMETER; + } + + switch (ptr->ResType) { + case 0: + // + // Check invalid Address Sapce Granularity + // + if (ptr->AddrSpaceGranularity != 32) { + return EFI_INVALID_PARAMETER; + } + // + // check the memory resource request is supported by PCI root bridge + // + if (RootBridgeInstance->RootBridgeAttrib == EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM && ptr->SpecificFlag == 0x06) { + return EFI_INVALID_PARAMETER; + } + + AddrLen = ptr->AddrLen; + Alignment = ptr->AddrRangeMax; + if (ptr->AddrSpaceGranularity == 32) { + if (ptr->SpecificFlag == 0x06) { + // + // Apply from GCD + // + RootBridgeInstance->ResAllocNode[TypePMem32].Status = ResSubmitted; + } 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) { + RootBridgeInstance->ResAllocNode[TypePMem64].Status = ResSubmitted; + } else { + RootBridgeInstance->ResAllocNode[TypeMem64].Status = ResSubmitted; + } + } + break; + + case 1: + AddrLen = (UINTN) ptr->AddrLen; + Alignment = (UINTN) ptr->AddrRangeMax; + RootBridgeInstance->ResAllocNode[TypeIo].Length = AddrLen; + RootBridgeInstance->ResAllocNode[TypeIo].Alignment = Alignment; + RootBridgeInstance->ResAllocNode[TypeIo].Status = ResRequested; + HostBridgeInstance->ResourceSubmited = TRUE; + break; + + default: + break; + } //end switch + + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } //end while + + return EFI_SUCCESS; + } //end if + + List = List->ForwardLink; + } //end while + + 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[out] 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; + 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) { + Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (!Buffer) { + return EFI_OUT_OF_RESOURCES; + } + } else { + return EFI_NOT_FOUND; + } + + 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 = EFI_RESOURCE_NONEXISTENT; + ptr->AddrLen = 0; + 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 = EFI_RESOURCE_NONEXISTENT; + ptr->AddrLen = 0; + 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 = EFI_RESOURCE_NONEXISTENT; + ptr->AddrLen = 0; + break; + } //end switch + + 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/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.h b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.h new file mode 100644 index 0000000000..bace944d4e --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.h @@ -0,0 +1,231 @@ +/** @file + The Header file of the Pci Host Bridge Driver. + + Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PCI_HOST_BRIDGE_H_ +#define _PCI_HOST_BRIDGE_H_ + +// +// Disable the warning since LIST_ENTRY was defined in EDKII +// and EFI_LIST_ENTRY was defined in PCI_HOST_BRIDGE_INSTANCE +// +#ifndef __GNUC__ +#pragma warning(disable: 4133) +#endif + +// +// 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 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,out] 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[out] 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[out] 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[out] 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/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.inf new file mode 100644 index 0000000000..de77fd1552 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciHostBridge.inf @@ -0,0 +1,61 @@ +## @file +# PciHostBridge module. +# +# Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PciHostBridge + FILE_GUID = D34E68E9-B9BF-4924-8A06-0EA2672204DD + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = PciHostBridgeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PciHostBridge.h + PciHostBridge.c + PciRootBridge.h + PciRootBridgeIo.c + +[Packages] + MdePkg/MdePkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DebugLib + S3BootScriptLib + DxeServicesTableLib + IoLib + SideBandLib + SteppingLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## SOMETIMES_CONSUMES + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid ## PRODUCES + gEfiPciHostBridgeResourceAllocationProtocolGuid ## PRODUCES + gEfiMetronomeArchProtocolGuid ## CONSUMES + gEfiCpuIo2ProtocolGuid ## CONSUMES + +[Depex] + gEfiCpuIo2ProtocolGuid AND + gEfiMetronomeArchProtocolGuid diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridge.h b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridge.h new file mode 100644 index 0000000000..81c143e6d1 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridge.h @@ -0,0 +1,155 @@ +/** @file + The driver for the host to pci bridge (root bridge). + + Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_ + +#include +#include +#include +#include "SaAccess.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Define resource status constant +// +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFF +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFE + + +// +// 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_APPETURE; + +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 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_APPETURE *ResAppeture + ); + +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridgeIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridgeIo.c new file mode 100644 index 0000000000..e5e2e8605f --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/NorthCluster/PciHostBridge/Dxe/PciRootBridgeIo.c @@ -0,0 +1,1563 @@ +/** @file + EFI Memory Controller PCI Root Bridge Io Protocol. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PciRootBridge.h" +#include + +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_IO2_PROTOCOL *mCpuIo; + +/** + 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_APPETURE *ResAppeture + ) +{ + 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 = ResAppeture->MemBase; + PrivateData->IoBase = ResAppeture->IoBase; + + // + // The host bridge only supports 32bit addressing for memory + // and standard IA32 16bit io + // + PrivateData->MemLimit = ResAppeture->MemLimit; + PrivateData->IoLimit = ResAppeture->IoLimit; + + // + // Bus Aperture for this Root Bridge (Possible Range) + // + PrivateData->BusBase = ResAppeture->BusBase; + PrivateData->BusLimit = ResAppeture->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, TPL_HIGH_LEVEL); + PrivateData->PciAddress = 0xCF8; + PrivateData->PciData = 0xCFC; + PrivateData->RootBridgeAttrib = Attri; + PrivateData->Attributes = 0; + + PrivateData->Supports = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | + EFI_PCI_ATTRIBUTE_ISA_IO | + EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | + EFI_PCI_ATTRIBUTE_VGA_MEMORY | + EFI_PCI_ATTRIBUTE_VGA_IO; + + 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 (&gEfiCpuIo2ProtocolGuid, 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; + UINTN 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. + // + // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome + // protocol definition is updated. + // + NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, (UINT32 *) &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; + UINTN 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, (UINT32 *) &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; + } + + 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_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. + // + MapInfo = AllocatePool (sizeof (MAP_INFO)); + if (!MapInfo) { + *NumberOfBytes = 0; + return EFI_OUT_OF_RESOURCES; + } + // + // 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. + // + MapInfo->MappedHostAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocatePages (MapInfo->NumberOfPages); + if (!(MapInfo->MappedHostAddress)) { + FreePool (MapInfo); + *NumberOfBytes = 0; + return EFI_OUT_OF_RESOURCES; + } + // + // 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. + // +#ifndef __GNUC__ +#pragma warning (disable: 4305) +#endif + FreePages ((VOID *) (UINTN) MapInfo->MappedHostAddress, MapInfo->NumberOfPages); +#ifndef __GNUC__ +#pragma warning (default: 4305) +#endif + FreePool (Mapping); + } + + return EFI_SUCCESS; +} + + +/** + Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or + EfiPciOperationBusMasterCommonBuffer64 mapping. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Type This parameter is not used and must be ignored. + @param[in] MemoryType The type of memory to allocate, EfiBootServicesData or EfiRuntimeServicesData. + @param[in] Pages The number of pages to allocate. + @param[out] HostAddress A pointer to store the base system memory address of the allocated range. + @param[in] 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_PHYSICAL_ADDRESS PhysicalAddress; + EFI_STATUS Status; + + // + // 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[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Pages The number of pages to free. + @param[out] 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 + ) +{ + FreePages ((VOID *) HostAddress, Pages); + return EFI_SUCCESS; +} + + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param[in] 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[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[out] Supported A pointer to the mask of attributes that this PCI root bridge + supports setting with SetAttributes(). + @param[out] 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 >= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) EfiCpuIoWidthFifoUint8 && Width <= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) EfiCpuIoWidthFillUint8 && Width <= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_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; +} + -- cgit v1.2.3