From 21b404d11e1e9f2577aad5105a784bbac6cdde55 Mon Sep 17 00:00:00 2001 From: jljusten Date: Wed, 27 May 2009 21:09:52 +0000 Subject: [PATCH] Add a simple PCI host bridge driver. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8396 6f19259b-4bc3-4df7-8a09-765794883524 --- .../PciHostBridgeDxe/PciHostBridge.c | 1201 +++++++++++++++ .../PciHostBridgeDxe/PciHostBridge.h | 251 ++++ .../PciHostBridgeDxe/PciHostBridgeDxe.inf | 55 + .../PciHostBridgeDxe/PciRootBridgeIo.c | 1330 +++++++++++++++++ 4 files changed, 2837 insertions(+) create mode 100755 PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.c create mode 100755 PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.h create mode 100755 PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf create mode 100755 PcAtChipsetPkg/PciHostBridgeDxe/PciRootBridgeIo.c diff --git a/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.c b/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.c new file mode 100755 index 0000000000..c879057846 --- /dev/null +++ b/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.c @@ -0,0 +1,1201 @@ +/** @file + Pci Host Bridge driver: + Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation + + Copyright (c) 2008 - 2009, 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 "PciHostBridge.h" + +// +// Support 64 K IO space +// +#define RES_IO_BASE 0x1000 +#define RES_IO_LIMIT 0xFFFF +// +// Support 4G address space +// +#define RES_MEM_BASE_1 0xF8000000 +#define RES_MEM_LIMIT_1 (0xFEC00000 - 1) + +// +// Hard code: Root Bridge Number within the host bridge +// Root Bridge's attribute +// Root Bridge's device path +// Root Bridge's resource appeture +// +UINTN RootBridgeNumber[1] = { 1 }; + +UINT64 RootBridgeAttribute[1][1] = { EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM }; + +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 + } +}; + +PCI_ROOT_BRIDGE_RESOURCE_APPETURE mResAppeture[1][1] = { + {0, 0, 0, 0xffffffff, 0, 1 << 16} +}; + +EFI_HANDLE mDriverImageHandle; + +PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = { + PCI_HOST_BRIDGE_SIGNATURE, // Signature + NULL, // HostBridgeHandle + 0, // RootBridgeNumber + {NULL, NULL}, // Head + FALSE, // ResourceSubiteed + TRUE, // CanRestarted + { + NotifyPhase, + GetNextRootBridge, + GetAttributes, + StartBusEnumeration, + SetBusNumbers, + SubmitResources, + GetProposedResources, + PreprocessController + } +}; + +// +// Implementation +// +EFI_STATUS +EFIAPI +InitializePciHostBridge ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Entry point of this driver + +Arguments: + + ImageHandle - + + SystemTable - + +Returns: + +--*/ +{ + EFI_STATUS Status; + UINTN Loop1; + UINTN Loop2; + PCI_HOST_BRIDGE_INSTANCE *HostBridge; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + IN EFI_PHYSICAL_ADDRESS BaseAddress; + IN UINT64 Length; + + mDriverImageHandle = ImageHandle; + + // + // Create Host Bridge Device Handle + // + for (Loop1 = 0; Loop1 < HOST_BRIDGE_NUMBER; Loop1++) { + HostBridge = AllocateCopyPool (sizeof(PCI_HOST_BRIDGE_INSTANCE), &mPciHostBridgeInstanceTemplate); + if (HostBridge == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + HostBridge->RootBridgeNumber = RootBridgeNumber[Loop1]; + InitializeListHead (&HostBridge->Head); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &HostBridge->HostBridgeHandle, + &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc, + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (HostBridge); + return EFI_DEVICE_ERROR; + } + + // + // Create Root Bridge Device Handle in this Host Bridge + // + + for (Loop2 = 0; Loop2 < HostBridge->RootBridgeNumber; Loop2++) { + PrivateData = AllocateZeroPool (sizeof(PCI_ROOT_BRIDGE_INSTANCE)); + if (PrivateData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + 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] + ); + + 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 + ); + + // PCI memory space from 3.75Gbytes->(4GBytes - BIOSFWH local APIC etc) + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + RES_MEM_BASE_1, + (RES_MEM_LIMIT_1 - RES_MEM_BASE_1 + 1), + 0 + ); + + BaseAddress = 0x80000000; + Length = RES_MEM_BASE_1 - BaseAddress; + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + BaseAddress, + Length, + 0 + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +NotifyPhase( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ) +/*++ + +Routine Description: + Enter a certain phase of the PCI enumeration process + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance + Phase -- The phase during enumeration + +Returns: + +--*/ +{ + 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; + 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 + // + //HostBridgeInstance->CanRestarted = FALSE; + return EFI_SUCCESS; + break; + + case EfiPciHostBridgeBeginResourceAllocation: + // + // No specific action is required here, can perform any chipset specific programing + // + //HostBridgeInstance->CanRestarted = FALSE; + 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; + + // + // Get the number of '1' in Alignment. + // + BitsOfAlignment = HighBitSet64 (RootBridgeInstance->ResAllocNode[Index].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; + } + ASSERT (FALSE); + } + break; + + case TypePMem32: + case TypeMem64: + case TypePMem64: + ReturnStatus = EFI_ABORTED; + break; + default: + ASSERT (FALSE); + 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); + 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: + ASSERT (FALSE); + break; + + }; //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; +} + +EFI_STATUS +EFIAPI +GetNextRootBridge( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN OUT EFI_HANDLE *RootBridgeHandle + ) +/*++ + +Routine Description: + Return the device handle of the next PCI root bridge that is associated with + this Host Bridge + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + 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 + +Returns: + +--*/ +{ + 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; + } +} + +EFI_STATUS +EFIAPI +GetAttributes( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT UINT64 *Attributes + ) +/*++ + +Routine Description: + Returns the attributes of a PCI Root Bridge. + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + RootBridgeHandle -- The device handle of the PCI Root Bridge + that the caller is interested in + Attribute -- The pointer to attributes of the PCI Root Bridge + +Returns: + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +StartBusEnumeration( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ) +/*++ + +Routine Description: + This is the request from the PCI enumerator to set up + the specified PCI Root Bridge for bus enumeration process. + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + RootBridgeHandle -- The PCI Root Bridge to be set up + Configuration -- Pointer to the pointer to the PCI bus resource descriptor + +Returns: + +--*/ +{ + 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 == NULL) { + 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; +} + +EFI_STATUS +EFIAPI +SetBusNumbers( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ) +/*++ + +Routine Description: + This function programs the PCI Root Bridge hardware so that + it decodes the specified PCI bus range + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + RootBridgeHandle -- The PCI Root Bridge whose bus range is to be programmed + Configuration -- The pointer to the PCI bus resource descriptor + +Returns: + +--*/ +{ + 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; +} + + +EFI_STATUS +EFIAPI +SubmitResources( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ) +/*++ + +Routine Description: + Submits the I/O and memory resource requirements for the specified PCI Root Bridge + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + RootBridgeHandle -- The PCI Root Bridge whose I/O and memory resource requirements + are being submitted + Configuration -- The pointer to the PCI I/O and PCI memory resource descriptor +Returns: + +--*/ +{ + 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 != (GetPowerOfTwo64 (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; + }; + + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) ; + } + + return EFI_SUCCESS; + } + + List = List->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +GetProposedResources( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ) +/*++ + +Routine Description: + This function returns the proposed resource settings for the specified + PCI Root Bridge + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + RootBridgeHandle -- The PCI Root Bridge handle + Configuration -- The pointer to the pointer to the PCI I/O + and memory resource descriptor + +Returns: + +--*/ +{ + 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) { + return EFI_INVALID_PARAMETER; + } + + Buffer = AllocateZeroPool (Number * sizeof(EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof(EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + 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; + }; + + 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; +} + +STATIC +VOID +UpdateRootBridgeAttributes ( + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress + ) +{ + EFI_STATUS Status; + PCI_TYPE01 PciConfigurationHeader; + UINT64 Attributes; + + // + // Read the PCI Configuration Header for the device + // + Status = RootBridge->Io.Pci.Read ( + &RootBridge->Io, + EfiPciWidthUint16, + EFI_PCI_ADDRESS( + PciAddress.Bus, + PciAddress.Device, + PciAddress.Function, + 0 + ), + sizeof (PciConfigurationHeader) / sizeof (UINT16), + &PciConfigurationHeader + ); + if (EFI_ERROR (Status)) { + return; + } + + Attributes = RootBridge->Attributes; + + // + // Look for devices with the VGA Palette Snoop enabled in the COMMAND register of the PCI Config Header + // + if (PciConfigurationHeader.Hdr.Command & 0x20) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + } + + // + // If the device is a PCI-PCI Bridge, then look at the Subordinate Bus Number + // + if (IS_PCI_BRIDGE(&PciConfigurationHeader)) { + // + // Look at the PPB Configuration for legacy decoding attributes + // + if (PciConfigurationHeader.Bridge.BridgeControl & 0x04) { + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; + Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; + } + if (PciConfigurationHeader.Bridge.BridgeControl & 0x08) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + } + } else { + // + // See if the PCI device is an IDE controller + // + if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x01 && + PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) { + if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x80) { + Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; + Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; + } + if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x01) { + Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; + } + if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x04) { + Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; + } + } + + // + // See if the PCI device is a legacy VGA controller + // + if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x00 && + PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + } + + // + // See if the PCI device is a standard VGA controller + // + if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x03 && + PciConfigurationHeader.Hdr.ClassCode[1] == 0x00 ) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + } + } + + RootBridge->Attributes = Attributes; + RootBridge->Supports = Attributes; +} + +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 + ) +/*++ + +Routine Description: + This function is called for all the PCI controllers that the PCI + bus driver finds. Can be used to Preprogram the controller. + +Arguments: + This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + RootBridgeHandle -- The PCI Root Bridge handle + PciBusAddress -- Address of the controller on the PCI bus + Phase -- The Phase during resource allocation + +Returns: + EFI_SUCCESS +--*/ +{ + 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) { + UpdateRootBridgeAttributes ( + RootBridgeInstance, + PciAddress + ); + return EFI_SUCCESS; + } + List = List->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} diff --git a/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.h b/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.h new file mode 100755 index 0000000000..7cb6a6503f --- /dev/null +++ b/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.h @@ -0,0 +1,251 @@ +/** @file + The Header file of the Pci Host Bridge Driver + + Copyright (c) 2008 - 2009, 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_ + +#include + +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +// +// 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) + +// +// Driver Entry Point +// +EFI_STATUS +EFIAPI +EfiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// HostBridge Resource Allocation interface +// +EFI_STATUS +EFIAPI +NotifyPhase( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ); + +EFI_STATUS +EFIAPI +GetNextRootBridge( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN OUT EFI_HANDLE *RootBridgeHandle + ); + +EFI_STATUS +EFIAPI +GetAttributes( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +StartBusEnumeration( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ); + +EFI_STATUS +EFIAPI +SetBusNumbers( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ); + +EFI_STATUS +EFIAPI +SubmitResources( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ); + +EFI_STATUS +EFIAPI +GetProposedResources( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ); + +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 + ); + + +// +// Define resource status constant +// +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFFULL +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL + + +// +// 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) + + +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/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf b/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf new file mode 100755 index 0000000000..f36cf9b02a --- /dev/null +++ b/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf @@ -0,0 +1,55 @@ +#/** @file +# +# Component description file a sinngle segment PCI Host Bridge driver. +# +# Copyright (c) 2008 - 2009, 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 = 2383608E-C6D0-4e3e-858D-45DFAC3543D5 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x0002000A + + ENTRY_POINT = InitializePciHostBridge + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DxeServicesTableLib + UefiLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + DebugLib + DevicePathLib + +[Sources] + PciHostBridge.c + PciRootBridgeIo.c + PciHostBridge.h + +[Protocols] + gEfiPciHostBridgeResourceAllocationProtocolGuid + gEfiPciRootBridgeIoProtocolGuid + gEfiCpuIoProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiDevicePathProtocolGuid + +[depex] + gEfiCpuIoProtocolGuid AND gEfiMetronomeArchProtocolGuid diff --git a/PcAtChipsetPkg/PciHostBridgeDxe/PciRootBridgeIo.c b/PcAtChipsetPkg/PciHostBridgeDxe/PciRootBridgeIo.c new file mode 100755 index 0000000000..11eadb40f7 --- /dev/null +++ b/PcAtChipsetPkg/PciHostBridgeDxe/PciRootBridgeIo.c @@ -0,0 +1,1330 @@ +/** @file + PCI Root Bridge Io Protocol implementation + + Copyright (c) 2008 - 2009, 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 "PciHostBridge.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 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 +// +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; + +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 + ) +/*++ + +Routine Description: + + Construct the Pci Root Bridge Io protocol + +Arguments: + + Protocol - protocol to initialize + +Returns: + + None + +--*/ +{ + 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 Appeture 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 = 0; + + 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 (&gEfiCpuIoProtocolGuid, NULL, (VOID **)&mCpuIo); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **)&mMetronome); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +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 + ) +/*++ + +Routine Description: + Memory Poll + +Arguments: + +Returns: + +--*/ +{ + 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. + // + // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome + // protocol definition is updated. + // + 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; +} + +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 + ) +/*++ + +Routine Description: + Io Poll + +Arguments: + +Returns: + +--*/ +{ + 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; +} + +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 + ) +/*++ + +Routine Description: + Memory read + +Arguments: + +Returns: + +--*/ +{ + 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 = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03); + + if (Address + (((UINTN)1 << Width) * Count) - 1 > PrivateData->MemLimit) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, OldCount, 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 + ) +/*++ + +Routine Description: + Memory write + +Arguments: + +Returns: + +--*/ +{ + 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 = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03); + + if (Address + (((UINTN)1 << Width) * Count) - 1 > PrivateData->MemLimit) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, OldCount, Buffer); +} + +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 + ) +/*++ + +Routine Description: + Io read + +Arguments: + +Returns: + +--*/ +{ + + + 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 = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03); + + if (Address + (((UINTN)1 << Width) * 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); + +} + +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 + ) +/*++ + +Routine Description: + Io write + +Arguments: + +Returns: + +--*/ +{ + 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 = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)(Width & 0x03); + + if (Address + (((UINTN)1 << Width) * 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); + +} + +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 + ) +/*++ + +Routine Description: + Memory copy + +Arguments: + +Returns: + +--*/ +{ + 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)(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; +} + +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 + ) +/*++ + +Routine Description: + Pci read + +Arguments: + +Returns: + +--*/ +{ + + 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); +} + +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 + ) +/*++ + +Routine Description: + Pci write + +Arguments: + +Returns: + +--*/ +{ + + 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); +} + +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) > 0x100000000ULL) { + + // + // 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; +} + +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; +} + +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; +} + +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); +} + +EFI_STATUS +EFIAPI +RootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + // + // not supported yet + // + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +RootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +RootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + 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; + } + } + + // + // This is a generic driver for a PC-AT class system. It does not have any + // chipset specific knowlegde, so none of the attributes can be set or + // cleared. Any attempt to set attribute that are already set will succeed, + // and any attempt to set an attribute that is not supported will fail. + // + if (Attributes & (~PrivateData->Attributes)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +RootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + 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 function +// +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 + ) +{ + PCI_CONFIG_ACCESS_CF8 Pci; + PCI_CONFIG_ACCESS_CF8 PciAligned; + UINT32 InStride; + UINT32 OutStride; + UINTN PciData; + UINTN PciDataStride; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + OutStride = 0; + } + + CopyMem (&PciAddress, &UserAddress, sizeof(UINT64)); + + if (PciAddress.ExtendedRegister > 0xFF) { + return EFI_UNSUPPORTED; + } + + if (PciAddress.ExtendedRegister != 0) { + Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF; + } else { + Pci.Bits.Reg = PciAddress.Register; + } + + Pci.Bits.Func = PciAddress.Function; + Pci.Bits.Dev = PciAddress.Device; + Pci.Bits.Bus = PciAddress.Bus; + Pci.Bits.Reserved = 0; + Pci.Bits.Enable = 1; + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // To read a byte of PCI config space you load 0xcf8 and + // read 0xcfc, 0xcfd, 0xcfe, 0xcff + // + PciDataStride = Pci.Bits.Reg & 0x03; + + while (Count) { + CopyMem (&PciAligned, &Pci, sizeof (PciAligned)); + PciAligned.Bits.Reg &= 0xfc; + PciData = (UINTN)PrivateData->PciData + PciDataStride; + EfiAcquireLock(&PrivateData->PciLock); + This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned); + if (Write) { + This->Io.Write (This, Width, PciData, 1, UserBuffer); + } else { + This->Io.Read (This, Width, PciData, 1, UserBuffer); + } + EfiReleaseLock(&PrivateData->PciLock); + UserBuffer = ((UINT8 *)UserBuffer) + OutStride; + PciDataStride = (PciDataStride + InStride) % 4; + Pci.Bits.Reg += InStride; + Count -= 1; + } + + return EFI_SUCCESS; +} -- 2.39.2