/** @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; }