/** @file Pci Host Bridge driver for a simple IIO. There is only one PCI Root Bridge in the system. Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation. Copyright (c) 2013-2015 Intel Corporation. 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" #include <IntelQNCRegs.h> // // We can hardcode the following for a Simple IIO - // Root Bridge Count within the host bridge // Root Bridge's device path // Root Bridge's resource appeture // EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[ROOT_BRIDGE_COUNT] = { { { { 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 } } } }; EFI_HANDLE mDriverImageHandle; PCI_ROOT_BRIDGE_RESOURCE_APERTURE *mResAperture; // // Implementation // EFI_STATUS EFIAPI InitializePciHostBridge ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: Entry point of this driver. Arguments: ImageHandle - Image handle of this driver. SystemTable - Pointer to standard EFI system table. Returns: EFI_SUCCESS - Succeed. EFI_DEVICE_ERROR - Fail to install PCI_ROOT_BRIDGE_IO protocol. --*/ { EFI_STATUS Status; UINTN TotalRootBridgeFound; PCI_HOST_BRIDGE_INSTANCE *HostBridge; PCI_ROOT_BRIDGE_INSTANCE *PrivateData; UINT64 AllocAttributes; EFI_PHYSICAL_ADDRESS BaseAddress; PrivateData = NULL; mDriverImageHandle = ImageHandle; // // Most systems in the world including complex servers // have only one Host Bridge. Create Host Bridge Device Handle // Status = gBS->AllocatePool(EfiBootServicesData, sizeof(PCI_HOST_BRIDGE_INSTANCE), (VOID **) &HostBridge); ASSERT_EFI_ERROR (Status); ZeroMem (HostBridge, sizeof (PCI_HOST_BRIDGE_INSTANCE)); HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE; HostBridge->RootBridgeCount = 1; HostBridge->ResourceSubmited = FALSE; HostBridge->CanRestarted = TRUE; // // InitializeListHead (&HostBridge->Head); // HostBridge->ResAlloc.NotifyPhase = NotifyPhase; HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge; HostBridge->ResAlloc.GetAllocAttributes = GetAttributes; HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration; HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers; HostBridge->ResAlloc.SubmitResources = SubmitResources; HostBridge->ResAlloc.GetProposedResources = GetProposedResources; HostBridge->ResAlloc.PreprocessController = PreprocessController; Status = gBS->InstallProtocolInterface ( &HostBridge->HostBridgeHandle, &gEfiPciHostBridgeResourceAllocationProtocolGuid, EFI_NATIVE_INTERFACE, &HostBridge->ResAlloc ); if (EFI_ERROR (Status)) { gBS->FreePool (HostBridge); return EFI_DEVICE_ERROR; } Status = gBS->AllocatePool (EfiBootServicesData, HostBridge->RootBridgeCount * sizeof(PCI_ROOT_BRIDGE_RESOURCE_APERTURE), (VOID **) &mResAperture); ASSERT_EFI_ERROR (Status); ZeroMem (mResAperture, HostBridge->RootBridgeCount * sizeof(PCI_ROOT_BRIDGE_RESOURCE_APERTURE)); DEBUG ((EFI_D_INFO, "Address of resource Aperture: %x\n", mResAperture)); // // Create Root Bridge Device Handle in this Host Bridge // InitializeListHead (&HostBridge->Head); TotalRootBridgeFound = 0; Status = gBS->AllocatePool ( EfiBootServicesData,sizeof (PCI_ROOT_BRIDGE_INSTANCE), (VOID **) &PrivateData); ASSERT_EFI_ERROR (Status); ZeroMem (PrivateData, sizeof (PCI_ROOT_BRIDGE_INSTANCE)); PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE; PrivateData->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &mEfiPciRootBridgeDevicePath[TotalRootBridgeFound]; AllocAttributes = GetAllocAttributes (TotalRootBridgeFound); SimpleIioRootBridgeConstructor ( &PrivateData->Io, HostBridge->HostBridgeHandle, &(mResAperture[TotalRootBridgeFound]), AllocAttributes ); // // Update Root Bridge with UDS resource information // PrivateData->Aperture.BusBase = QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE; PrivateData->Aperture.BusLimit = QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT; PrivateData->Aperture.Mem32Base = PcdGet32 (PcdPciHostBridgeMemory32Base); PrivateData->Aperture.Mem32Limit = PcdGet32 (PcdPciHostBridgeMemory32Base) + (PcdGet32 (PcdPciHostBridgeMemory32Size) - 1); PrivateData->Aperture.IoBase = PcdGet16 (PcdPciHostBridgeIoBase); PrivateData->Aperture.IoLimit = PcdGet16 (PcdPciHostBridgeIoBase) + (PcdGet16 (PcdPciHostBridgeIoSize) - 1); DEBUG ((EFI_D_INFO, "PCI Host Bridge BusBase: %x\n", QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE)); DEBUG ((EFI_D_INFO, "PCI Host Bridge BusLimit: %x\n", QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT)); DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem32Base: %x\n", PcdGet32 (PcdPciHostBridgeMemory32Base))); DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem32Limit: %x\n", PcdGet32 (PcdPciHostBridgeMemory32Base) + (PcdGet32 (PcdPciHostBridgeMemory32Size) - 1))); DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem64Base: %lX\n", PcdGet64 (PcdPciHostBridgeMemory64Base))); DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem64Limit: %lX\n", PcdGet64 (PcdPciHostBridgeMemory64Base) + (PcdGet64 (PcdPciHostBridgeMemory64Size) - 1))); DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceIoBase: %x\n", PcdGet16 (PcdPciHostBridgeIoBase))); DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceIoLimit: %x\n", PcdGet16 (PcdPciHostBridgeIoBase) + (PcdGet16 (PcdPciHostBridgeIoSize) - 1))); PrivateData->Handle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &PrivateData->Handle, &gEfiDevicePathProtocolGuid, PrivateData->DevicePath, &gEfiPciRootBridgeIoProtocolGuid, &PrivateData->Io, NULL ); ASSERT_EFI_ERROR (Status); InsertTailList (&HostBridge->Head, &PrivateData->Link); TotalRootBridgeFound++; // This is a valid rootbridge so imcrement total root bridges found // // Add PCIE base into Runtime memory so that it can be reported in E820 table // Status = gDS->AddMemorySpace ( EfiGcdMemoryTypeMemoryMappedIo, PcdGet64 (PcdPciExpressBaseAddress), PcdGet64 (PcdPciExpressSize), EFI_MEMORY_RUNTIME | EFI_MEMORY_UC ); ASSERT_EFI_ERROR(Status); BaseAddress = PcdGet64 (PcdPciExpressBaseAddress); Status = gDS->AllocateMemorySpace ( EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo, 0, PcdGet64 (PcdPciExpressSize), &BaseAddress, ImageHandle, NULL ); ASSERT_EFI_ERROR(Status); Status = gDS->SetMemorySpaceAttributes ( PcdGet64 (PcdPciExpressBaseAddress), PcdGet64 (PcdPciExpressSize), EFI_MEMORY_RUNTIME ); ASSERT_EFI_ERROR (Status); if (PcdGet16 (PcdPciHostBridgeIoSize) > 0) { // // At present, we use up the first 4k for fixed ranges like // ICH GPIO, ACPI and ISA devices. The first 4k is not // tracked through GCD. It should be. // Status = gDS->AddIoSpace ( EfiGcdIoTypeIo, PcdGet16(PcdPciHostBridgeIoBase), PcdGet16(PcdPciHostBridgeIoSize) ); ASSERT_EFI_ERROR (Status); } if (PcdGet32(PcdPciHostBridgeMemory32Size) > 0) { // // Shouldn't the capabilities be UC? // Status = gDS->AddMemorySpace ( EfiGcdMemoryTypeMemoryMappedIo, PcdGet32(PcdPciHostBridgeMemory32Base), PcdGet32(PcdPciHostBridgeMemory32Size), 0 ); ASSERT_EFI_ERROR (Status); } return Status; } 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: EFI_SUCCESS - Succeed. EFI_INVALID_PARAMETER - Wrong phase parameter passed in. EFI_NOT_READY - Resources have not been submitted yet. --*/ { PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; PCI_RESOURCE_TYPE Index; EFI_LIST_ENTRY *List; EFI_PHYSICAL_ADDRESS BaseAddress; UINT64 AddrLen; UINTN BitsOfAlignment; UINT64 Alignment; EFI_STATUS Status; EFI_STATUS ReturnStatus; PCI_RESOURCE_TYPE Index1; PCI_RESOURCE_TYPE Index2; BOOLEAN ResNodeHandled[TypeMax]; UINT64 MaxAlignment; HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); switch (Phase) { case EfiPciHostBridgeBeginEnumeration: if (HostBridgeInstance->CanRestarted) { // // Reset 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; } // for List = List->ForwardLink; } // while HostBridgeInstance->ResourceSubmited = FALSE; HostBridgeInstance->CanRestarted = TRUE; } else { // // Can not restart // return EFI_NOT_READY; } // if break; case EfiPciHostBridgeEndEnumeration: return EFI_SUCCESS; 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) { List = HostBridgeInstance->Head.ForwardLink; while (List != &HostBridgeInstance->Head) { for (Index1 = TypeIo; Index1 < TypeBus; Index1++) { ResNodeHandled[Index1] = FALSE; } RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); DEBUG ((EFI_D_INFO, "Address of RootBridgeInstance: %x)\n", RootBridgeInstance)); DEBUG ((EFI_D_INFO, " Signature: %x\n", RootBridgeInstance->Signature)); DEBUG ((EFI_D_INFO, " Bus Number Assigned: %x\n", RootBridgeInstance->BusNumberAssigned)); DEBUG ((EFI_D_INFO, " Bus Scan Count: %x\n", RootBridgeInstance->BusScanCount)); for (Index1 = TypeIo; Index1 < TypeBus; Index1++) { if (RootBridgeInstance->ResAllocNode[Index1].Status == ResNone) { ResNodeHandled[Index1] = TRUE; } else { // // Allocate the resource node with max alignment at first // MaxAlignment = 0; Index = TypeMax; for (Index2 = TypeIo; Index2 < TypeBus; Index2++) { if (ResNodeHandled[Index2]) { continue; } if (MaxAlignment <= RootBridgeInstance->ResAllocNode[Index2].Alignment) { MaxAlignment = RootBridgeInstance->ResAllocNode[Index2].Alignment; Index = Index2; } } // for if (Index < TypeMax) { ResNodeHandled[Index] = TRUE; } else { ASSERT (FALSE); } Alignment = RootBridgeInstance->ResAllocNode[Index].Alignment; // // Get the number of '1' in Alignment. // for (BitsOfAlignment = 0; Alignment != 0; BitsOfAlignment++) { Alignment = RShiftU64 (Alignment, 1); } AddrLen = RootBridgeInstance->ResAllocNode[Index].Length; Alignment = RootBridgeInstance->ResAllocNode[Index].Alignment; DEBUG ((EFI_D_INFO, "\n\nResource Type to assign : %x\n", Index)); DEBUG ((EFI_D_INFO, " Length to allocate: %x\n", RootBridgeInstance->ResAllocNode[Index].Length)); DEBUG ((EFI_D_INFO, " Aligment: %x\n", Alignment)); switch (Index) { case TypeIo: if (RootBridgeInstance->Aperture.IoBase < RootBridgeInstance->Aperture.IoLimit) { // // It is impossible for 0xFFFF Alignment for IO16 // if (BitsOfAlignment >= 16) Alignment = 0; BaseAddress = RootBridgeInstance->Aperture.IoBase; // // Have to make sure Aligment is handled seeing we are doing direct address allocation // if ((BaseAddress & ~(Alignment)) != BaseAddress) BaseAddress = ((BaseAddress + Alignment) & ~(Alignment)); while((BaseAddress + AddrLen) <= RootBridgeInstance->Aperture.IoLimit + 1) { Status = gDS->AllocateIoSpace ( EfiGcdAllocateAddress, EfiGcdIoTypeIo, BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL ); if (!EFI_ERROR (Status)) { RootBridgeInstance->ResAllocNode[Index].Base = (UINT64) BaseAddress; RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated; goto TypeIoFound; } BaseAddress += (Alignment + 1); } // while } // if TypeIoFound: if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) { // // No Room at the Inn for this resources request // ReturnStatus = EFI_OUT_OF_RESOURCES; } // if break; case TypeMem32: if (RootBridgeInstance->Aperture.Mem32Base < RootBridgeInstance->Aperture.Mem32Limit) { BaseAddress = RootBridgeInstance->Aperture.Mem32Base; // // Have to make sure Aligment is handled seeing we are doing direct address allocation // if ((BaseAddress & ~(Alignment)) != BaseAddress) BaseAddress = ((BaseAddress + Alignment) & ~(Alignment)); while((BaseAddress + AddrLen) <= RootBridgeInstance->Aperture.Mem32Limit + 1) { Status = gDS->AllocateMemorySpace ( EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo, BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL); if (!EFI_ERROR (Status)) { RootBridgeInstance->ResAllocNode[Index].Base = (UINT64) BaseAddress; RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated; goto TypeMem32Found; } // if BaseAddress += (Alignment + 1); } // while } // if TypeMem32Found: if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) { // // No Room at the Inn for this resources request // ReturnStatus = EFI_OUT_OF_RESOURCES; } break; case TypePMem32: StartTypePMem32: if (RootBridgeInstance->Aperture.Mem32Base < RootBridgeInstance->Aperture.Mem32Limit) { BaseAddress = RootBridgeInstance->Aperture.Mem32Limit + 1; BaseAddress -= AddrLen; // // Have to make sure Aligment is handled seeing we are doing direct address allocation // if ((BaseAddress & ~(Alignment)) != BaseAddress) BaseAddress = ((BaseAddress) & ~(Alignment)); while(RootBridgeInstance->Aperture.Mem32Base <= BaseAddress) { DEBUG ((EFI_D_INFO, " Attempting %x allocation at 0x%lx .....", Index, BaseAddress)); Status = gDS->AllocateMemorySpace ( EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo, BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL); if (!EFI_ERROR (Status)) { RootBridgeInstance->ResAllocNode[Index].Base = (UINT64) BaseAddress; RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated; DEBUG ((EFI_D_INFO, "... Passed!!\n")); goto TypePMem32Found; } DEBUG ((EFI_D_INFO, "... Failed!!\n")); BaseAddress -= (Alignment + 1); } // while } // if TypePMem32Found: if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) { // // No Room at the Inn for this resources request // ReturnStatus = EFI_OUT_OF_RESOURCES; } break; case TypeMem64: case TypePMem64: if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) { // // If 64-bit resourcing is not available, then try as PMem32 // goto StartTypePMem32; } break; default: break; } // End switch (Index) DEBUG ((EFI_D_INFO, "Resource Type Assigned: %x\n", Index)); if (RootBridgeInstance->ResAllocNode[Index].Status == ResAllocated) { DEBUG ((EFI_D_INFO, " Base Address Assigned: %x\n", RootBridgeInstance->ResAllocNode[Index].Base)); DEBUG ((EFI_D_INFO, " Length Assigned: %x\n", RootBridgeInstance->ResAllocNode[Index].Length)); } else { DEBUG ((DEBUG_ERROR, " Resource Allocation failed! There was no room at the inn\n")); } } } List = List->ForwardLink; } if (ReturnStatus == EFI_OUT_OF_RESOURCES) { DEBUG ((DEBUG_ERROR, "Resource allocation Failed. Continue booting the system.\n")); } // // Set resource to zero for nodes where allocation fails // 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) { RootBridgeInstance->ResAllocNode[Index].Length = 0; } } List = List->ForwardLink; } return ReturnStatus; } else { return EFI_NOT_READY; } // // HostBridgeInstance->CanRestarted = FALSE; // break; case EfiPciHostBridgeSetResources: // // HostBridgeInstance->CanRestarted = FALSE; // break; case EfiPciHostBridgeFreeResources: // // HostBridgeInstance->CanRestarted = FALSE; // 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 = (EFI_PHYSICAL_ADDRESS) 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: Status = gDS->FreeMemorySpace (BaseAddress, AddrLen); if (EFI_ERROR (Status)) { ReturnStatus = Status; } break; default: break; } // end switch (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; return ReturnStatus; break; case EfiPciHostBridgeEndResourceAllocation: // // Resource enumeration is done. Perform any activities that // must wait until that time. // break; default: return EFI_INVALID_PARAMETER; } // End switch (Phase) 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: EFI_SUCCESS - Succeed. EFI_NOT_FOUND - Next PCI root bridge not found. EFI_INVALID_PARAMETER - Wrong parameter passed in. --*/ { BOOLEAN NoRootBridge; EFI_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. Attributes - The pointer to attributes of the PCI Root Bridge. Returns: EFI_SUCCESS - Succeed. EFI_INVALID_PARAMETER - Attributes parameter passed in is NULL or RootBridgeHandle is not an EFI_HANDLE that was returned on a previous call to GetNextRootBridge(). --*/ { EFI_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->RootBridgeAllocAttrib; 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: EFI_SUCCESS - Succeed. EFI_OUT_OF_RESOURCES - Not enough pool to be allocated. EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle. --*/ { EFI_LIST_ENTRY *List; PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; VOID *Buffer; UINT8 *Temp; EFI_STATUS Status; UINTN BusStart; UINTN BusEnd; UINT64 BusReserve; 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->Aperture.BusBase; BusEnd = RootBridgeInstance->Aperture.BusLimit; BusReserve = RootBridgeInstance->Aperture.BusReserve; // // Program the Hardware(if needed) if error return EFI_DEVICE_ERROR // Status = gBS->AllocatePool ( EfiBootServicesData, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), &Buffer ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } Temp = (UINT8 *) Buffer; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Len = 0x2B; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->GenFlag = 0; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->SpecificFlag = 0; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrSpaceGranularity = 0; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMin = BusStart; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMax = BusReserve; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrTranslationOffset = 0; ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrLen = BusEnd - BusStart + 1; Temp = Temp + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc = ACPI_END_TAG_DESCRIPTOR; ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum = 0x0; *Configuration = Buffer; return EFI_SUCCESS; } List = List->ForwardLink; } return EFI_INVALID_PARAMETER; } 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: EFI_SUCCESS - Succeed. EFI_INVALID_PARAMETER - Wrong parameters passed in. --*/ { EFI_LIST_ENTRY *List; PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; UINT8 *Ptr; UINTN BusStart; UINTN BusEnd; UINTN BusLen; if (Configuration == NULL) { return EFI_INVALID_PARAMETER; } Ptr = Configuration; // // Check the Configuration is valid // if (*Ptr != ACPI_ADDRESS_SPACE_DESCRIPTOR) { return EFI_INVALID_PARAMETER; } if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) { return EFI_INVALID_PARAMETER; } Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); if (*Ptr != ACPI_END_TAG_DESCRIPTOR) { return EFI_INVALID_PARAMETER; } HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); List = HostBridgeInstance->Head.ForwardLink; Ptr = Configuration; while (List != &HostBridgeInstance->Head) { RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); if (RootBridgeHandle == RootBridgeInstance->Handle) { BusStart = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrRangeMin; BusLen = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrLen; BusEnd = BusStart + BusLen - 1; if (BusStart > BusEnd) { return EFI_INVALID_PARAMETER; } if ((BusStart < RootBridgeInstance->Aperture.BusBase) || (BusEnd > RootBridgeInstance->Aperture.BusLimit)) { return EFI_INVALID_PARAMETER; } // // Update the Bus Range // RootBridgeInstance->ResAllocNode[TypeBus].Base = BusStart; RootBridgeInstance->ResAllocNode[TypeBus].Length = BusLen; RootBridgeInstance->ResAllocNode[TypeBus].Status = ResAllocated; RootBridgeInstance->BusScanCount++; if (RootBridgeInstance->BusScanCount > 0) { // // Only care about the 2nd PCI bus scanning // RootBridgeInstance->BusNumberAssigned = TRUE; } 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: EFI_SUCCESS - Succeed. EFI_INVALID_PARAMETER - Wrong parameters passed in. --*/ { EFI_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; UINT64 Value; // // 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 (List != &HostBridgeInstance->Head) { RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); if (RootBridgeHandle == RootBridgeInstance->Handle) { // // Check the resource descriptors. // If the Configuration includes one or more invalid resource descriptors, all the resource // descriptors are ignored and the function returns EFI_INVALID_PARAMETER. // while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; DEBUG ((EFI_D_INFO, " ptr->ResType:%x \n",ptr->ResType)); DEBUG ((EFI_D_INFO, " ptr->AddrLen:0x%lx AddrRangeMin:0x%lx AddrRangeMax:0x%lx\n\n",ptr->AddrLen,ptr->AddrRangeMin,ptr->AddrRangeMax)); switch (ptr->ResType) { case ACPI_ADDRESS_SPACE_TYPE_MEM: if (ptr->AddrSpaceGranularity != 32 && ptr->AddrSpaceGranularity != 64) { return EFI_INVALID_PARAMETER; } if (ptr->AddrSpaceGranularity == 32 && ptr->AddrLen > 0xffffffff) { return EFI_INVALID_PARAMETER; } // // If the PCI root bridge does not support separate windows for nonprefetchable and // prefetchable memory, then the PCI bus driver needs to include requests for // prefetchable memory in the nonprefetchable memory pool. // if ((RootBridgeInstance->RootBridgeAllocAttrib & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 && ((ptr->SpecificFlag & (BIT2 | BIT1)) != 0)) { return EFI_INVALID_PARAMETER; } case ACPI_ADDRESS_SPACE_TYPE_IO: // // Check aligment, it should be of the form 2^n-1 // Value = Power2MaxMemory (ptr->AddrRangeMax + 1); if (Value != (ptr->AddrRangeMax + 1)) { CpuDeadLoop(); return EFI_INVALID_PARAMETER; } break; case ACPI_ADDRESS_SPACE_TYPE_BUS: default: return EFI_INVALID_PARAMETER; } Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) ; } if (*Temp != ACPI_END_TAG_DESCRIPTOR) { return EFI_INVALID_PARAMETER; } Temp = (UINT8 *) Configuration; while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; switch (ptr->ResType) { case ACPI_ADDRESS_SPACE_TYPE_MEM: AddrLen = (UINT64) ptr->AddrLen; Alignment = (UINT64) 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].Length = AddrLen; RootBridgeInstance->ResAllocNode[TypeMem64].Alignment = Alignment; RootBridgeInstance->ResAllocNode[TypeMem64].Status = ResSubmitted; HostBridgeInstance->ResourceSubmited = TRUE; } } break; case ACPI_ADDRESS_SPACE_TYPE_IO: AddrLen = (UINT64) ptr->AddrLen; Alignment = (UINT64) ptr->AddrRangeMax; RootBridgeInstance->ResAllocNode[TypeIo].Length = AddrLen; RootBridgeInstance->ResAllocNode[TypeIo].Alignment = Alignment; RootBridgeInstance->ResAllocNode[TypeIo].Status = ResRequested; HostBridgeInstance->ResourceSubmited = TRUE; break; default: break; } Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); } return EFI_SUCCESS; } List = List->ForwardLink; } return EFI_INVALID_PARAMETER; } 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: EFI_SUCCESS - Succeed. EFI_OUT_OF_RESOURCES - Not enough pool to be allocated. EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle. --*/ { EFI_LIST_ENTRY *List; PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; UINTN Index; UINTN Number; VOID *Buffer; UINT8 *Temp; EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr; EFI_STATUS Status; UINT64 ResStatus; Buffer = NULL; Number = 0; // // Get the Host Bridge Instance from the resource allocation protocol // HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); List = HostBridgeInstance->Head.ForwardLink; // // Enumerate the root bridges in this host bridge // while (List != &HostBridgeInstance->Head) { RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List); if (RootBridgeHandle == RootBridgeInstance->Handle) { for (Index = 0; Index < TypeBus; Index++) { if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) { Number++; } } if (Number > 0) { Status = gBS->AllocatePool ( EfiBootServicesData, Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), &Buffer ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } ZeroMem (Buffer, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Number + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); } ASSERT (Buffer != NULL); 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 = 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 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; } 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 ) /*++ 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. PciAddress - Address of the controller on the PCI bus. Phase - The Phase during resource allocation. Returns: EFI_SUCCESS - Succeed. EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle. --*/ { BOOLEAN RootBridgeFound; EFI_LIST_ENTRY *List; PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; if (RootBridgeHandle == NULL) { return EFI_INVALID_PARAMETER; } RootBridgeFound = FALSE; 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) { RootBridgeFound = TRUE; break; } // // Get next if have // List = List->ForwardLink; } if (RootBridgeFound == FALSE) { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; } UINT64 Power2MaxMemory ( IN UINT64 MemoryLength ) /*++ Routine Description: Calculate maximum memory length that can be fit to a mtrr. Arguments: MemoryLength - Input memory length. Returns: Returned Maximum length. --*/ { UINT64 Result; if (RShiftU64 (MemoryLength, 32)) { Result = LShiftU64 ((UINT64) GetPowerOfTwo64 ((UINT32) RShiftU64 (MemoryLength, 32)), 32); } else { Result = (UINT64) GetPowerOfTwo64 ((UINT32) MemoryLength); } return Result; }