diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c | 2210 |
1 files changed, 2210 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c new file mode 100644 index 00000000..4e1c328b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c @@ -0,0 +1,2210 @@ +/** @file + PCI eunmeration implementation on entire PCI bus system for PCI Bus module. + +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PciBus.h" + +/** + This routine is used to enumerate entire pci bus system + in a given platform. + + @param Controller Parent controller handle. + @param HostBridgeHandle Host bridge handle. + + @retval EFI_SUCCESS PCI enumeration finished successfully. + @retval other Some error occurred when enumerating the pci bus system. + +**/ +EFI_STATUS +PciEnumerator ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE HostBridgeHandle + ) +{ + EFI_STATUS Status; + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc; + + // + // Get the pci host bridge resource allocation protocol + // + Status = gBS->OpenProtocol ( + HostBridgeHandle, + &gEfiPciHostBridgeResourceAllocationProtocolGuid, + (VOID **) &PciResAlloc, + gPciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Notify the pci bus enumeration is about to begin + // + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Start the bus allocation phase + // + Status = PciHostBridgeEnumerator (PciResAlloc); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Submit the resource request + // + Status = PciHostBridgeResourceAllocator (PciResAlloc); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Notify the pci bus enumeration is about to complete + // + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndEnumeration); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Process P2C + // + Status = PciHostBridgeP2CProcess (PciResAlloc); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Process attributes for devices on this host bridge + // + Status = PciHostBridgeDeviceAttribute (PciResAlloc); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Enumerate PCI root bridge. + + @param PciResAlloc Pointer to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL. + @param RootBridgeDev Instance of root bridge device. + + @retval EFI_SUCCESS Successfully enumerated root bridge. + @retval other Failed to enumerate root bridge. + +**/ +EFI_STATUS +PciRootBridgeEnumerator ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + IN PCI_IO_DEVICE *RootBridgeDev + ) +{ + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration1; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration2; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration3; + UINT8 SubBusNumber; + UINT8 StartBusNumber; + UINT8 PaddedBusRange; + EFI_HANDLE RootBridgeHandle; + UINT8 Desc; + UINT64 AddrLen; + UINT64 AddrRangeMin; + + SubBusNumber = 0; + StartBusNumber = 0; + PaddedBusRange = 0; + + // + // Get the root bridge handle + // + RootBridgeHandle = RootBridgeDev->Handle; + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_PCI | EFI_IOB_PCI_BUS_ENUM, + RootBridgeDev->DevicePath + ); + + // + // Get the Bus information + // + Status = PciResAlloc->StartBusEnumeration ( + PciResAlloc, + RootBridgeHandle, + (VOID **) &Configuration + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Configuration == NULL || Configuration->Desc == ACPI_END_TAG_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + RootBridgeDev->BusNumberRanges = Configuration; + + // + // Sort the descriptors in ascending order + // + for (Configuration1 = Configuration; Configuration1->Desc != ACPI_END_TAG_DESCRIPTOR; Configuration1++) { + Configuration2 = Configuration1; + for (Configuration3 = Configuration1 + 1; Configuration3->Desc != ACPI_END_TAG_DESCRIPTOR; Configuration3++) { + if (Configuration2->AddrRangeMin > Configuration3->AddrRangeMin) { + Configuration2 = Configuration3; + } + } + // + // All other fields other than AddrRangeMin and AddrLen are ignored in a descriptor, + // so only need to swap these two fields. + // + if (Configuration2 != Configuration1) { + AddrRangeMin = Configuration1->AddrRangeMin; + Configuration1->AddrRangeMin = Configuration2->AddrRangeMin; + Configuration2->AddrRangeMin = AddrRangeMin; + + AddrLen = Configuration1->AddrLen; + Configuration1->AddrLen = Configuration2->AddrLen; + Configuration2->AddrLen = AddrLen; + } + } + + // + // Get the bus number to start with + // + StartBusNumber = (UINT8) (Configuration->AddrRangeMin); + + // + // Initialize the subordinate bus number + // + SubBusNumber = StartBusNumber; + + // + // Reset all assigned PCI bus number + // + ResetAllPpbBusNumber ( + RootBridgeDev, + StartBusNumber + ); + + // + // Assign bus number + // + Status = PciScanBus ( + RootBridgeDev, + StartBusNumber, + &SubBusNumber, + &PaddedBusRange + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + + // + // Assign max bus number scanned + // + + Status = PciAllocateBusNumber (RootBridgeDev, SubBusNumber, PaddedBusRange, &SubBusNumber); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find the bus range which contains the higest bus number, then returns the number of buses + // that should be decoded. + // + while (Configuration->AddrRangeMin + Configuration->AddrLen - 1 < SubBusNumber) { + Configuration++; + } + AddrLen = Configuration->AddrLen; + Configuration->AddrLen = SubBusNumber - Configuration->AddrRangeMin + 1; + + // + // Save the Desc field of the next descriptor. Mark the next descriptor as an END descriptor. + // + Configuration++; + Desc = Configuration->Desc; + Configuration->Desc = ACPI_END_TAG_DESCRIPTOR; + + // + // Set bus number + // + Status = PciResAlloc->SetBusNumbers ( + PciResAlloc, + RootBridgeHandle, + RootBridgeDev->BusNumberRanges + ); + + // + // Restore changed fields + // + Configuration->Desc = Desc; + (Configuration - 1)->AddrLen = AddrLen; + + return Status; +} + +/** + This routine is used to process all PCI devices' Option Rom + on a certain root bridge. + + @param Bridge Given parent's root bridge. + @param RomBase Base address of ROM driver loaded from. + @param MaxLength Maximum rom size. + +**/ +VOID +ProcessOptionRom ( + IN PCI_IO_DEVICE *Bridge, + IN UINT64 RomBase, + IN UINT64 MaxLength + ) +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + // + // Go through bridges to reach all devices + // + CurrentLink = Bridge->ChildList.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (!IsListEmpty (&Temp->ChildList)) { + + // + // Go further to process the option rom under this bridge + // + ProcessOptionRom (Temp, RomBase, MaxLength); + } + + if (Temp->RomSize != 0 && Temp->RomSize <= MaxLength) { + + // + // Load and process the option rom + // + LoadOpRomImage (Temp, RomBase); + } + + CurrentLink = CurrentLink->ForwardLink; + } +} + +/** + This routine is used to assign bus number to the given PCI bus system + + @param Bridge Parent root bridge instance. + @param StartBusNumber Number of beginning. + @param SubBusNumber The number of sub bus. + + @retval EFI_SUCCESS Successfully assigned bus number. + @retval EFI_DEVICE_ERROR Failed to assign bus number. + +**/ +EFI_STATUS +PciAssignBusNumber ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber + ) +{ + EFI_STATUS Status; + PCI_TYPE00 Pci; + UINT8 Device; + UINT8 Func; + UINT64 Address; + UINTN SecondBus; + UINT16 Register; + UINT8 Register8; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + + SecondBus = 0; + Register = 0; + + *SubBusNumber = StartBusNumber; + + // + // First check to see whether the parent is ppb + // + for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { + for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { + + // + // Check to see whether a pci device is present + // + Status = PciDevicePresent ( + PciRootBridgeIo, + &Pci, + StartBusNumber, + Device, + Func + ); + + if (EFI_ERROR (Status) && Func == 0) { + // + // go to next device if there is no Function 0 + // + break; + } + + if (!EFI_ERROR (Status) && + (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) { + + // + // Reserved one bus for cardbus bridge + // + Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1, SubBusNumber); + if (EFI_ERROR (Status)) { + return Status; + } + SecondBus = *SubBusNumber; + + Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber); + + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18); + + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + EfiPciWidthUint16, + Address, + 1, + &Register + ); + + // + // Initialize SubBusNumber to SecondBus + // + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + EfiPciWidthUint8, + Address, + 1, + SubBusNumber + ); + // + // If it is PPB, resursively search down this bridge + // + if (IS_PCI_BRIDGE (&Pci)) { + + Register8 = 0xFF; + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + EfiPciWidthUint8, + Address, + 1, + &Register8 + ); + + Status = PciAssignBusNumber ( + Bridge, + (UINT8) (SecondBus), + SubBusNumber + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + // + // Set the current maximum bus number under the PPB + // + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + EfiPciWidthUint8, + Address, + 1, + SubBusNumber + ); + + } + + if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { + + // + // Skip sub functions, this is not a multi function device + // + Func = PCI_MAX_FUNC; + } + } + } + + return EFI_SUCCESS; +} + +/** + This routine is used to determine the root bridge attribute by interfacing + the host bridge resource allocation protocol. + + @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + @param RootBridgeDev Root bridge instance + + @retval EFI_SUCCESS Successfully got root bridge's attribute. + @retval other Failed to get attribute. + +**/ +EFI_STATUS +DetermineRootBridgeAttributes ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + IN PCI_IO_DEVICE *RootBridgeDev + ) +{ + UINT64 Attributes; + EFI_STATUS Status; + EFI_HANDLE RootBridgeHandle; + + Attributes = 0; + RootBridgeHandle = RootBridgeDev->Handle; + + // + // Get root bridge attribute by calling into pci host bridge resource allocation protocol + // + Status = PciResAlloc->GetAllocAttributes ( + PciResAlloc, + RootBridgeHandle, + &Attributes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Here is the point where PCI bus driver calls HOST bridge allocation protocol + // Currently we hardcoded for ea815 + // + if ((Attributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) { + RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED; + } + + if ((Attributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0) { + RootBridgeDev->Decodes |= EFI_BRIDGE_MEM64_DECODE_SUPPORTED; + RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED; + } + + RootBridgeDev->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED; + RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED; + RootBridgeDev->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED; + + return EFI_SUCCESS; +} + +/** + Get Max Option Rom size on specified bridge. + + @param Bridge Given bridge device instance. + + @return Max size of option rom needed. + +**/ +UINT32 +GetMaxOptionRomSize ( + IN PCI_IO_DEVICE *Bridge + ) +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + UINT32 MaxOptionRomSize; + UINT32 TempOptionRomSize; + + MaxOptionRomSize = 0; + + // + // Go through bridges to reach all devices + // + CurrentLink = Bridge->ChildList.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (!IsListEmpty (&Temp->ChildList)) { + + // + // Get max option rom size under this bridge + // + TempOptionRomSize = GetMaxOptionRomSize (Temp); + + // + // Compare with the option rom size of the bridge + // Get the larger one + // + if (Temp->RomSize > TempOptionRomSize) { + TempOptionRomSize = Temp->RomSize; + } + + } else { + + // + // For devices get the rom size directly + // + TempOptionRomSize = Temp->RomSize; + } + + // + // Get the largest rom size on this bridge + // + if (TempOptionRomSize > MaxOptionRomSize) { + MaxOptionRomSize = TempOptionRomSize; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return MaxOptionRomSize; +} + +/** + Process attributes of devices on this host bridge + + @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL. + + @retval EFI_SUCCESS Successfully process attribute. + @retval EFI_NOT_FOUND Can not find the specific root bridge device. + @retval other Failed to determine the root bridge device's attribute. + +**/ +EFI_STATUS +PciHostBridgeDeviceAttribute ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +{ + EFI_HANDLE RootBridgeHandle; + PCI_IO_DEVICE *RootBridgeDev; + EFI_STATUS Status; + + RootBridgeHandle = NULL; + + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + + // + // Get RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + // + // Set the attributes for devcies behind the Root Bridge + // + Status = DetermineDeviceAttribute (RootBridgeDev); + if (EFI_ERROR (Status)) { + return Status; + } + + } + + return EFI_SUCCESS; +} + +/** + Get resource allocation status from the ACPI resource descriptor. + + @param AcpiConfig Point to Acpi configuration table. + @param IoResStatus Return the status of I/O resource. + @param Mem32ResStatus Return the status of 32-bit Memory resource. + @param PMem32ResStatus Return the status of 32-bit Prefetchable Memory resource. + @param Mem64ResStatus Return the status of 64-bit Memory resource. + @param PMem64ResStatus Return the status of 64-bit Prefetchable Memory resource. + +**/ +VOID +GetResourceAllocationStatus ( + VOID *AcpiConfig, + OUT UINT64 *IoResStatus, + OUT UINT64 *Mem32ResStatus, + OUT UINT64 *PMem32ResStatus, + OUT UINT64 *Mem64ResStatus, + OUT UINT64 *PMem64ResStatus + ) +{ + UINT8 *Temp; + UINT64 ResStatus; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ACPIAddressDesc; + + Temp = (UINT8 *) AcpiConfig; + + while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + + ACPIAddressDesc = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + ResStatus = ACPIAddressDesc->AddrTranslationOffset; + + switch (ACPIAddressDesc->ResType) { + case 0: + if (ACPIAddressDesc->AddrSpaceGranularity == 32) { + if (ACPIAddressDesc->SpecificFlag == 0x06) { + // + // Pmem32 + // + *PMem32ResStatus = ResStatus; + } else { + // + // Mem32 + // + *Mem32ResStatus = ResStatus; + } + } + + if (ACPIAddressDesc->AddrSpaceGranularity == 64) { + if (ACPIAddressDesc->SpecificFlag == 0x06) { + // + // PMem64 + // + *PMem64ResStatus = ResStatus; + } else { + // + // Mem64 + // + *Mem64ResStatus = ResStatus; + } + } + + break; + + case 1: + // + // Io + // + *IoResStatus = ResStatus; + break; + + default: + break; + } + + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } +} + +/** + Remove a PCI device from device pool and mark its bar. + + @param PciDevice Instance of Pci device. + + @retval EFI_SUCCESS Successfully remove the PCI device. + @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge. + +**/ +EFI_STATUS +RejectPciDevice ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + PCI_IO_DEVICE *Bridge; + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + + // + // Remove the padding resource from a bridge + // + if ( IS_PCI_BRIDGE(&PciDevice->Pci) && + PciDevice->ResourcePaddingDescriptors != NULL ) { + FreePool (PciDevice->ResourcePaddingDescriptors); + PciDevice->ResourcePaddingDescriptors = NULL; + return EFI_SUCCESS; + } + + // + // Skip RB and PPB + // + if (IS_PCI_BRIDGE (&PciDevice->Pci) || (PciDevice->Parent == NULL)) { + return EFI_ABORTED; + } + + if (IS_CARDBUS_BRIDGE (&PciDevice->Pci)) { + // + // Get the root bridge device + // + Bridge = PciDevice; + while (Bridge->Parent != NULL) { + Bridge = Bridge->Parent; + } + + RemoveAllPciDeviceOnBridge (Bridge->Handle, PciDevice); + + // + // Mark its bar + // + InitializeP2C (PciDevice); + } + + // + // Remove the device + // + Bridge = PciDevice->Parent; + CurrentLink = Bridge->ChildList.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (Temp == PciDevice) { + InitializePciDevice (Temp); + RemoveEntryList (CurrentLink); + return EFI_SUCCESS; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_ABORTED; +} + +/** + Determine whethter a PCI device can be rejected. + + @param PciResNode Pointer to Pci resource node instance. + + @retval TRUE The PCI device can be rejected. + @retval TRUE The PCI device cannot be rejected. + +**/ +BOOLEAN +IsRejectiveDevice ( + IN PCI_RESOURCE_NODE *PciResNode + ) +{ + PCI_IO_DEVICE *Temp; + + Temp = PciResNode->PciDev; + + // + // Ensure the device is present + // + if (Temp == NULL) { + return FALSE; + } + + // + // PPB and RB should go ahead + // + if (IS_PCI_BRIDGE (&Temp->Pci) || (Temp->Parent == NULL)) { + return TRUE; + } + + // + // Skip device on Bus0 + // + if ((Temp->Parent != NULL) && (Temp->BusNumber == 0)) { + return FALSE; + } + + // + // Skip VGA + // + if (IS_PCI_VGA (&Temp->Pci)) { + return FALSE; + } + + return TRUE; +} + +/** + Compare two resource nodes and get the larger resource consumer. + + @param PciResNode1 resource node 1 want to be compared + @param PciResNode2 resource node 2 want to be compared + + @return Larger resource node. + +**/ +PCI_RESOURCE_NODE * +GetLargerConsumerDevice ( + IN PCI_RESOURCE_NODE *PciResNode1, + IN PCI_RESOURCE_NODE *PciResNode2 + ) +{ + if (PciResNode2 == NULL) { + return PciResNode1; + } + + if ((IS_PCI_BRIDGE(&(PciResNode2->PciDev->Pci)) || (PciResNode2->PciDev->Parent == NULL)) \ + && (PciResNode2->ResourceUsage != PciResUsagePadding) ) + { + return PciResNode1; + } + + if (PciResNode1 == NULL) { + return PciResNode2; + } + + if ((PciResNode1->Length) > (PciResNode2->Length)) { + return PciResNode1; + } + + return PciResNode2; +} + + +/** + Get the max resource consumer in the host resource pool. + + @param ResPool Pointer to resource pool node. + + @return The max resource consumer in the host resource pool. + +**/ +PCI_RESOURCE_NODE * +GetMaxResourceConsumerDevice ( + IN PCI_RESOURCE_NODE *ResPool + ) +{ + PCI_RESOURCE_NODE *Temp; + LIST_ENTRY *CurrentLink; + PCI_RESOURCE_NODE *PciResNode; + PCI_RESOURCE_NODE *PPBResNode; + + PciResNode = NULL; + + CurrentLink = ResPool->ChildList.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &ResPool->ChildList) { + + Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (!IsRejectiveDevice (Temp)) { + CurrentLink = CurrentLink->ForwardLink; + continue; + } + + if ((IS_PCI_BRIDGE (&(Temp->PciDev->Pci)) || (Temp->PciDev->Parent == NULL)) \ + && (Temp->ResourceUsage != PciResUsagePadding)) + { + PPBResNode = GetMaxResourceConsumerDevice (Temp); + PciResNode = GetLargerConsumerDevice (PciResNode, PPBResNode); + } else { + PciResNode = GetLargerConsumerDevice (PciResNode, Temp); + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return PciResNode; +} + +/** + Adjust host bridge allocation so as to reduce resource requirement + + @param IoPool Pointer to instance of I/O resource Node. + @param Mem32Pool Pointer to instance of 32-bit memory resource Node. + @param PMem32Pool Pointer to instance of 32-bit Prefetchable memory resource node. + @param Mem64Pool Pointer to instance of 64-bit memory resource node. + @param PMem64Pool Pointer to instance of 64-bit Prefetchable memory resource node. + @param IoResStatus Status of I/O resource Node. + @param Mem32ResStatus Status of 32-bit memory resource Node. + @param PMem32ResStatus Status of 32-bit Prefetchable memory resource node. + @param Mem64ResStatus Status of 64-bit memory resource node. + @param PMem64ResStatus Status of 64-bit Prefetchable memory resource node. + + @retval EFI_SUCCESS Successfully adjusted resource on host bridge. + @retval EFI_ABORTED Host bridge hasn't this resource type or no resource be adjusted. + +**/ +EFI_STATUS +PciHostBridgeAdjustAllocation ( + IN PCI_RESOURCE_NODE *IoPool, + IN PCI_RESOURCE_NODE *Mem32Pool, + IN PCI_RESOURCE_NODE *PMem32Pool, + IN PCI_RESOURCE_NODE *Mem64Pool, + IN PCI_RESOURCE_NODE *PMem64Pool, + IN UINT64 IoResStatus, + IN UINT64 Mem32ResStatus, + IN UINT64 PMem32ResStatus, + IN UINT64 Mem64ResStatus, + IN UINT64 PMem64ResStatus + ) +{ + BOOLEAN AllocationAjusted; + PCI_RESOURCE_NODE *PciResNode; + PCI_RESOURCE_NODE *ResPool[5]; + PCI_IO_DEVICE *RemovedPciDev[5]; + UINT64 ResStatus[5]; + UINTN RemovedPciDevNum; + UINTN DevIndex; + UINTN ResType; + EFI_STATUS Status; + EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData; + + PciResNode = NULL; + ZeroMem (RemovedPciDev, 5 * sizeof (PCI_IO_DEVICE *)); + RemovedPciDevNum = 0; + + ResPool[0] = IoPool; + ResPool[1] = Mem32Pool; + ResPool[2] = PMem32Pool; + ResPool[3] = Mem64Pool; + ResPool[4] = PMem64Pool; + + ResStatus[0] = IoResStatus; + ResStatus[1] = Mem32ResStatus; + ResStatus[2] = PMem32ResStatus; + ResStatus[3] = Mem64ResStatus; + ResStatus[4] = PMem64ResStatus; + + AllocationAjusted = FALSE; + + for (ResType = 0; ResType < 5; ResType++) { + + if (ResStatus[ResType] == EFI_RESOURCE_SATISFIED) { + continue; + } + + if (ResStatus[ResType] == EFI_RESOURCE_NOT_SATISFIED) { + // + // Host bridge hasn't this resource type + // + return EFI_ABORTED; + } + + // + // Hostbridge hasn't enough resource + // + PciResNode = GetMaxResourceConsumerDevice (ResPool[ResType]); + if (PciResNode == NULL) { + continue; + } + + // + // Check if the device has been removed before + // + for (DevIndex = 0; DevIndex < RemovedPciDevNum; DevIndex++) { + if (PciResNode->PciDev == RemovedPciDev[DevIndex]) { + break; + } + } + + if (DevIndex != RemovedPciDevNum) { + continue; + } + + // + // Remove the device if it isn't in the array + // + Status = RejectPciDevice (PciResNode->PciDev); + if (Status == EFI_SUCCESS) { + DEBUG (( + EFI_D_ERROR, + "PciBus: [%02x|%02x|%02x] was rejected due to resource confliction.\n", + PciResNode->PciDev->BusNumber, PciResNode->PciDev->DeviceNumber, PciResNode->PciDev->FunctionNumber + )); + + // + // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code + // + // + // Have no way to get ReqRes, AllocRes & Bar here + // + ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData)); + AllocFailExtendedData.DevicePathSize = (UINT16) sizeof (EFI_DEVICE_PATH_PROTOCOL); + AllocFailExtendedData.DevicePath = (UINT8 *) PciResNode->PciDev->DevicePath; + AllocFailExtendedData.Bar = PciResNode->Bar; + + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT, + (VOID *) &AllocFailExtendedData, + sizeof (AllocFailExtendedData) + ); + + // + // Add it to the array and indicate at least a device has been rejected + // + RemovedPciDev[RemovedPciDevNum++] = PciResNode->PciDev; + AllocationAjusted = TRUE; + } + } + // + // End for + // + + if (AllocationAjusted) { + return EFI_SUCCESS; + } else { + return EFI_ABORTED; + } +} + +/** + Summary requests for all resource type, and construct ACPI resource + requestor instance. + + @param Bridge detecting bridge + @param IoNode Pointer to instance of I/O resource Node + @param Mem32Node Pointer to instance of 32-bit memory resource Node + @param PMem32Node Pointer to instance of 32-bit Pmemory resource node + @param Mem64Node Pointer to instance of 64-bit memory resource node + @param PMem64Node Pointer to instance of 64-bit Pmemory resource node + @param Config Output buffer holding new constructed APCI resource requestor + + @retval EFI_SUCCESS Successfully constructed ACPI resource. + @retval EFI_OUT_OF_RESOURCES No memory available. + +**/ +EFI_STATUS +ConstructAcpiResourceRequestor ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_RESOURCE_NODE *IoNode, + IN PCI_RESOURCE_NODE *Mem32Node, + IN PCI_RESOURCE_NODE *PMem32Node, + IN PCI_RESOURCE_NODE *Mem64Node, + IN PCI_RESOURCE_NODE *PMem64Node, + OUT VOID **Config + ) +{ + UINT8 NumConfig; + UINT8 Aperture; + UINT8 *Configuration; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; + EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd; + + NumConfig = 0; + Aperture = 0; + + *Config = NULL; + + // + // if there is io request, add to the io aperture + // + if (ResourceRequestExisted (IoNode)) { + NumConfig++; + Aperture |= 0x01; + } + + // + // if there is mem32 request, add to the mem32 aperture + // + if (ResourceRequestExisted (Mem32Node)) { + NumConfig++; + Aperture |= 0x02; + } + + // + // if there is pmem32 request, add to the pmem32 aperture + // + if (ResourceRequestExisted (PMem32Node)) { + NumConfig++; + Aperture |= 0x04; + } + + // + // if there is mem64 request, add to the mem64 aperture + // + if (ResourceRequestExisted (Mem64Node)) { + NumConfig++; + Aperture |= 0x08; + } + + // + // if there is pmem64 request, add to the pmem64 aperture + // + if (ResourceRequestExisted (PMem64Node)) { + NumConfig++; + Aperture |= 0x10; + } + + if (NumConfig != 0) { + + // + // If there is at least one type of resource request, + // allocate a acpi resource node + // + Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; + + // + // Deal with io aperture + // + if ((Aperture & 0x01) != 0) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3); + // + // Io + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; + // + // non ISA range + // + Ptr->SpecificFlag = 1; + Ptr->AddrLen = IoNode->Length; + Ptr->AddrRangeMax = IoNode->Alignment; + + Ptr++; + } + // + // Deal with mem32 aperture + // + if ((Aperture & 0x02) != 0) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3); + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // Nonprefechable + // + Ptr->SpecificFlag = 0; + // + // 32 bit + // + Ptr->AddrSpaceGranularity = 32; + Ptr->AddrLen = Mem32Node->Length; + Ptr->AddrRangeMax = Mem32Node->Alignment; + + Ptr++; + } + + // + // Deal with Pmem32 aperture + // + if ((Aperture & 0x04) != 0) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3); + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // prefechable + // + Ptr->SpecificFlag = 0x6; + // + // 32 bit + // + Ptr->AddrSpaceGranularity = 32; + Ptr->AddrLen = PMem32Node->Length; + Ptr->AddrRangeMax = PMem32Node->Alignment; + + Ptr++; + } + // + // Deal with mem64 aperture + // + if ((Aperture & 0x08) != 0) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3); + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // nonprefechable + // + Ptr->SpecificFlag = 0; + // + // 64 bit + // + Ptr->AddrSpaceGranularity = 64; + Ptr->AddrLen = Mem64Node->Length; + Ptr->AddrRangeMax = Mem64Node->Alignment; + + Ptr++; + } + // + // Deal with Pmem64 aperture + // + if ((Aperture & 0x10) != 0) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3); + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // prefechable + // + Ptr->SpecificFlag = 0x06; + // + // 64 bit + // + Ptr->AddrSpaceGranularity = 64; + Ptr->AddrLen = PMem64Node->Length; + Ptr->AddrRangeMax = PMem64Node->Alignment; + + Ptr++; + } + + // + // put the checksum + // + PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr; + + PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + PtrEnd->Checksum = 0; + + } else { + + // + // If there is no resource request + // + Configuration = AllocateZeroPool (sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Configuration); + PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + PtrEnd->Checksum = 0; + } + + *Config = Configuration; + + return EFI_SUCCESS; +} + +/** + Get resource base from an acpi configuration descriptor. + + @param Config An acpi configuration descriptor. + @param IoBase Output of I/O resource base address. + @param Mem32Base Output of 32-bit memory base address. + @param PMem32Base Output of 32-bit prefetchable memory base address. + @param Mem64Base Output of 64-bit memory base address. + @param PMem64Base Output of 64-bit prefetchable memory base address. + +**/ +VOID +GetResourceBase ( + IN VOID *Config, + OUT UINT64 *IoBase, + OUT UINT64 *Mem32Base, + OUT UINT64 *PMem32Base, + OUT UINT64 *Mem64Base, + OUT UINT64 *PMem64Base + ) +{ + UINT8 *Temp; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; + UINT64 ResStatus; + + ASSERT (Config != NULL); + + *IoBase = 0xFFFFFFFFFFFFFFFFULL; + *Mem32Base = 0xFFFFFFFFFFFFFFFFULL; + *PMem32Base = 0xFFFFFFFFFFFFFFFFULL; + *Mem64Base = 0xFFFFFFFFFFFFFFFFULL; + *PMem64Base = 0xFFFFFFFFFFFFFFFFULL; + + Temp = (UINT8 *) Config; + + while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + + Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + ResStatus = Ptr->AddrTranslationOffset; + + if (ResStatus == EFI_RESOURCE_SATISFIED) { + + switch (Ptr->ResType) { + + // + // Memory type aperture + // + case 0: + + // + // Check to see the granularity + // + if (Ptr->AddrSpaceGranularity == 32) { + if ((Ptr->SpecificFlag & 0x06) != 0) { + *PMem32Base = Ptr->AddrRangeMin; + } else { + *Mem32Base = Ptr->AddrRangeMin; + } + } + + if (Ptr->AddrSpaceGranularity == 64) { + if ((Ptr->SpecificFlag & 0x06) != 0) { + *PMem64Base = Ptr->AddrRangeMin; + } else { + *Mem64Base = Ptr->AddrRangeMin; + } + } + break; + + case 1: + + // + // Io type aperture + // + *IoBase = Ptr->AddrRangeMin; + break; + + default: + break; + + } + // + // End switch + // + } + // + // End for + // + Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } +} + +/** + Enumerate pci bridge, allocate resource and determine attribute + for devices on this bridge. + + @param BridgeDev Pointer to instance of bridge device. + + @retval EFI_SUCCESS Successfully enumerated PCI bridge. + @retval other Failed to enumerate. + +**/ +EFI_STATUS +PciBridgeEnumerator ( + IN PCI_IO_DEVICE *BridgeDev + ) +{ + UINT8 SubBusNumber; + UINT8 StartBusNumber; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; + + SubBusNumber = 0; + StartBusNumber = 0; + PciIo = &(BridgeDev->PciIo); + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x19, 1, &StartBusNumber); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciAssignBusNumber ( + BridgeDev, + StartBusNumber, + &SubBusNumber + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciPciDeviceInfoCollector (BridgeDev, StartBusNumber); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciBridgeResourceAllocator (BridgeDev); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = DetermineDeviceAttribute (BridgeDev); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; + +} + +/** + Allocate all kinds of resource for PCI bridge. + + @param Bridge Pointer to bridge instance. + + @retval EFI_SUCCESS Successfully allocated resource for PCI bridge. + @retval other Failed to allocate resource for bridge. + +**/ +EFI_STATUS +PciBridgeResourceAllocator ( + IN PCI_IO_DEVICE *Bridge + ) +{ + PCI_RESOURCE_NODE *IoBridge; + PCI_RESOURCE_NODE *Mem32Bridge; + PCI_RESOURCE_NODE *PMem32Bridge; + PCI_RESOURCE_NODE *Mem64Bridge; + PCI_RESOURCE_NODE *PMem64Bridge; + UINT64 IoBase; + UINT64 Mem32Base; + UINT64 PMem32Base; + UINT64 Mem64Base; + UINT64 PMem64Base; + EFI_STATUS Status; + + IoBridge = CreateResourceNode ( + Bridge, + 0, + Bridge->BridgeIoAlignment, + 0, + PciBarTypeIo16, + PciResUsageTypical + ); + + Mem32Bridge = CreateResourceNode ( + Bridge, + 0, + 0xFFFFF, + 0, + PciBarTypeMem32, + PciResUsageTypical + ); + + PMem32Bridge = CreateResourceNode ( + Bridge, + 0, + 0xFFFFF, + 0, + PciBarTypePMem32, + PciResUsageTypical + ); + + Mem64Bridge = CreateResourceNode ( + Bridge, + 0, + 0xFFFFF, + 0, + PciBarTypeMem64, + PciResUsageTypical + ); + + PMem64Bridge = CreateResourceNode ( + Bridge, + 0, + 0xFFFFF, + 0, + PciBarTypePMem64, + PciResUsageTypical + ); + + // + // Create resourcemap by going through all the devices subject to this root bridge + // + CreateResourceMap ( + Bridge, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge + ); + + Status = GetResourceBaseFromBridge ( + Bridge, + &IoBase, + &Mem32Base, + &PMem32Base, + &Mem64Base, + &PMem64Base + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Program IO resources + // + ProgramResource ( + IoBase, + IoBridge + ); + + // + // Program Mem32 resources + // + ProgramResource ( + Mem32Base, + Mem32Bridge + ); + + // + // Program PMem32 resources + // + ProgramResource ( + PMem32Base, + PMem32Bridge + ); + + // + // Program Mem64 resources + // + ProgramResource ( + Mem64Base, + Mem64Bridge + ); + + // + // Program PMem64 resources + // + ProgramResource ( + PMem64Base, + PMem64Bridge + ); + + DestroyResourceTree (IoBridge); + DestroyResourceTree (Mem32Bridge); + DestroyResourceTree (PMem32Bridge); + DestroyResourceTree (PMem64Bridge); + DestroyResourceTree (Mem64Bridge); + + gBS->FreePool (IoBridge); + gBS->FreePool (Mem32Bridge); + gBS->FreePool (PMem32Bridge); + gBS->FreePool (PMem64Bridge); + gBS->FreePool (Mem64Bridge); + + return EFI_SUCCESS; +} + +/** + Get resource base address for a pci bridge device. + + @param Bridge Given Pci driver instance. + @param IoBase Output for base address of I/O type resource. + @param Mem32Base Output for base address of 32-bit memory type resource. + @param PMem32Base Ooutput for base address of 32-bit Pmemory type resource. + @param Mem64Base Output for base address of 64-bit memory type resource. + @param PMem64Base Output for base address of 64-bit Pmemory type resource. + + @retval EFI_SUCCESS Successfully got resource base address. + @retval EFI_OUT_OF_RESOURCES PCI bridge is not available. + +**/ +EFI_STATUS +GetResourceBaseFromBridge ( + IN PCI_IO_DEVICE *Bridge, + OUT UINT64 *IoBase, + OUT UINT64 *Mem32Base, + OUT UINT64 *PMem32Base, + OUT UINT64 *Mem64Base, + OUT UINT64 *PMem64Base + ) +{ + if (!Bridge->Allocated) { + return EFI_OUT_OF_RESOURCES; + } + + *IoBase = gAllOne; + *Mem32Base = gAllOne; + *PMem32Base = gAllOne; + *Mem64Base = gAllOne; + *PMem64Base = gAllOne; + + if (IS_PCI_BRIDGE (&Bridge->Pci)) { + + if (Bridge->PciBar[PPB_IO_RANGE].Length > 0) { + *IoBase = Bridge->PciBar[PPB_IO_RANGE].BaseAddress; + } + + if (Bridge->PciBar[PPB_MEM32_RANGE].Length > 0) { + *Mem32Base = Bridge->PciBar[PPB_MEM32_RANGE].BaseAddress; + } + + if (Bridge->PciBar[PPB_PMEM32_RANGE].Length > 0) { + *PMem32Base = Bridge->PciBar[PPB_PMEM32_RANGE].BaseAddress; + } + + if (Bridge->PciBar[PPB_PMEM64_RANGE].Length > 0) { + *PMem64Base = Bridge->PciBar[PPB_PMEM64_RANGE].BaseAddress; + } else { + *PMem64Base = gAllOne; + } + + } + + if (IS_CARDBUS_BRIDGE (&Bridge->Pci)) { + if (Bridge->PciBar[P2C_IO_1].Length > 0) { + *IoBase = Bridge->PciBar[P2C_IO_1].BaseAddress; + } else { + if (Bridge->PciBar[P2C_IO_2].Length > 0) { + *IoBase = Bridge->PciBar[P2C_IO_2].BaseAddress; + } + } + + if (Bridge->PciBar[P2C_MEM_1].Length > 0) { + if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypePMem32) { + *PMem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress; + } + + if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypeMem32) { + *Mem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress; + } + } + + if (Bridge->PciBar[P2C_MEM_2].Length > 0) { + if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypePMem32) { + *PMem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress; + } + + if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypeMem32) { + *Mem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress; + } + } + } + + return EFI_SUCCESS; +} + +/** + These are the notifications from the PCI bus driver that it is about to enter a certain + phase of the PCI enumeration process. + + This member function can be used to notify the host bridge driver to perform specific actions, + including any chipset-specific initialization, so that the chipset is ready to enter the next phase. + Eight notification points are defined at this time. See belows: + EfiPciHostBridgeBeginEnumeration Resets the host bridge PCI apertures and internal data + structures. The PCI enumerator should issue this notification + before starting a fresh enumeration process. Enumeration cannot + be restarted after sending any other notification such as + EfiPciHostBridgeBeginBusAllocation. + EfiPciHostBridgeBeginBusAllocation The bus allocation phase is about to begin. No specific action is + required here. This notification can be used to perform any + chipset-specific programming. + EfiPciHostBridgeEndBusAllocation The bus allocation and bus programming phase is complete. No + specific action is required here. This notification can be used to + perform any chipset-specific programming. + EfiPciHostBridgeBeginResourceAllocation + The resource allocation phase is about to begin. No specific + action is required here. This notification can be used to perform + any chipset-specific programming. + EfiPciHostBridgeAllocateResources Allocates resources per previously submitted requests for all the PCI + root bridges. These resource settings are returned on the next call to + GetProposedResources(). Before calling NotifyPhase() with a Phase of + EfiPciHostBridgeAllocateResource, the PCI bus enumerator is responsible + for gathering I/O and memory requests for + all the PCI root bridges and submitting these requests using + SubmitResources(). This function pads the resource amount + to suit the root bridge hardware, takes care of dependencies between + the PCI root bridges, and calls the Global Coherency Domain (GCD) + with the allocation request. In the case of padding, the allocated range + could be bigger than what was requested. + EfiPciHostBridgeSetResources Programs the host bridge hardware to decode previously allocated + resources (proposed resources) for all the PCI root bridges. After the + hardware is programmed, reassigning resources will not be supported. + The bus settings are not affected. + EfiPciHostBridgeFreeResources Deallocates resources that were previously allocated for all the PCI + root bridges and resets the I/O and memory apertures to their initial + state. The bus settings are not affected. If the request to allocate + resources fails, the PCI enumerator can use this notification to + deallocate previous resources, adjust the requests, and retry + allocation. + EfiPciHostBridgeEndResourceAllocation The resource allocation phase is completed. No specific action is + required here. This notification can be used to perform any chipsetspecific + programming. + + @param[in] PciResAlloc The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + @param[in] Phase The phase during enumeration + + @retval EFI_NOT_READY This phase cannot be entered at this time. For example, this error + is valid for a Phase of EfiPciHostBridgeAllocateResources if + SubmitResources() has not been called for one or more + PCI root bridges before this call + @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. This error is valid + for a Phase of EfiPciHostBridgeSetResources. + @retval EFI_INVALID_PARAMETER Invalid phase parameter + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + This error is valid for a Phase of EfiPciHostBridgeAllocateResources if the + previously submitted resource requests cannot be fulfilled or + were only partially fulfilled. + @retval EFI_SUCCESS The notification was accepted without any errors. + +**/ +EFI_STATUS +NotifyPhase ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ) +{ + EFI_HANDLE HostBridgeHandle; + EFI_HANDLE RootBridgeHandle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_STATUS Status; + + HostBridgeHandle = NULL; + RootBridgeHandle = NULL; + if (gPciPlatformProtocol != NULL) { + // + // Get Host Bridge Handle. + // + PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle); + + // + // Get the rootbridge Io protocol to find the host bridge handle + // + Status = gBS->HandleProtocol ( + RootBridgeHandle, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo + ); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + HostBridgeHandle = PciRootBridgeIo->ParentHandle; + + // + // Call PlatformPci::PlatformNotify() if the protocol is present. + // + gPciPlatformProtocol->PlatformNotify ( + gPciPlatformProtocol, + HostBridgeHandle, + Phase, + ChipsetEntry + ); + } else if (gPciOverrideProtocol != NULL){ + // + // Get Host Bridge Handle. + // + PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle); + + // + // Get the rootbridge Io protocol to find the host bridge handle + // + Status = gBS->HandleProtocol ( + RootBridgeHandle, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo + ); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + HostBridgeHandle = PciRootBridgeIo->ParentHandle; + + // + // Call PlatformPci::PhaseNotify() if the protocol is present. + // + gPciOverrideProtocol->PlatformNotify ( + gPciOverrideProtocol, + HostBridgeHandle, + Phase, + ChipsetEntry + ); + } + + Status = PciResAlloc->NotifyPhase ( + PciResAlloc, + Phase + ); + + if (gPciPlatformProtocol != NULL) { + // + // Call PlatformPci::PlatformNotify() if the protocol is present. + // + gPciPlatformProtocol->PlatformNotify ( + gPciPlatformProtocol, + HostBridgeHandle, + Phase, + ChipsetExit + ); + + } else if (gPciOverrideProtocol != NULL) { + // + // Call PlatformPci::PhaseNotify() if the protocol is present. + // + gPciOverrideProtocol->PlatformNotify ( + gPciOverrideProtocol, + HostBridgeHandle, + Phase, + ChipsetExit + ); + } + + return Status; +} + +/** + Provides the hooks from the PCI bus driver to every PCI controller (device/function) at various + stages of the PCI enumeration process that allow the host bridge driver to preinitialize individual + PCI controllers before enumeration. + + This function is called during the PCI enumeration process. No specific action is expected from this + member function. It allows the host bridge driver to preinitialize individual PCI controllers before + enumeration. + + @param Bridge Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance. + @param Bus The bus number of the pci device. + @param Device The device number of the pci device. + @param Func The function number of the pci device. + @param Phase The phase of the PCI device enumeration. + + @retval EFI_SUCCESS The requested parameters were returned. + @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle. + @retval EFI_INVALID_PARAMETER Phase is not a valid phase that is defined in + EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE. + @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. The PCI enumerator should + not enumerate this device, including its child devices if it is a PCI-to-PCI + bridge. + +**/ +EFI_STATUS +PreprocessController ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Func, + IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase + ) +{ + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS RootBridgePciAddress; + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc; + EFI_HANDLE RootBridgeHandle; + EFI_HANDLE HostBridgeHandle; + EFI_STATUS Status; + + // + // Get the host bridge handle + // + HostBridgeHandle = Bridge->PciRootBridgeIo->ParentHandle; + + // + // Get the pci host bridge resource allocation protocol + // + Status = gBS->OpenProtocol ( + HostBridgeHandle, + &gEfiPciHostBridgeResourceAllocationProtocolGuid, + (VOID **) &PciResAlloc, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Get Root Brige Handle + // + while (Bridge->Parent != NULL) { + Bridge = Bridge->Parent; + } + + RootBridgeHandle = Bridge->Handle; + + RootBridgePciAddress.Register = 0; + RootBridgePciAddress.Function = Func; + RootBridgePciAddress.Device = Device; + RootBridgePciAddress.Bus = Bus; + RootBridgePciAddress.ExtendedRegister = 0; + + if (gPciPlatformProtocol != NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + gPciPlatformProtocol->PlatformPrepController ( + gPciPlatformProtocol, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ChipsetEntry + ); + } else if (gPciOverrideProtocol != NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + gPciOverrideProtocol->PlatformPrepController ( + gPciOverrideProtocol, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ChipsetEntry + ); + } + + Status = PciResAlloc->PreprocessController ( + PciResAlloc, + RootBridgeHandle, + RootBridgePciAddress, + Phase + ); + + if (gPciPlatformProtocol != NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + gPciPlatformProtocol->PlatformPrepController ( + gPciPlatformProtocol, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ChipsetExit + ); + } else if (gPciOverrideProtocol != NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + gPciOverrideProtocol->PlatformPrepController ( + gPciOverrideProtocol, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ChipsetExit + ); + } + + return EFI_SUCCESS; +} + +/** + This function allows the PCI bus driver to be notified to act as requested when a hot-plug event has + happened on the hot-plug controller. Currently, the operations include add operation and remove operation.. + + @param This A pointer to the hot plug request protocol. + @param Operation The operation the PCI bus driver is requested to make. + @param Controller The handle of the hot-plug controller. + @param RemainingDevicePath The remaining device path for the PCI-like hot-plug device. + @param NumberOfChildren The number of child handles. + For a add operation, it is an output parameter. + For a remove operation, it's an input parameter. + @param ChildHandleBuffer The buffer which contains the child handles. + + @retval EFI_INVALID_PARAMETER Operation is not a legal value. + Controller is NULL or not a valid handle. + NumberOfChildren is NULL. + ChildHandleBuffer is NULL while Operation is add. + @retval EFI_OUT_OF_RESOURCES There are no enough resources to start the devices. + @retval EFI_NOT_FOUND Can not find bridge according to controller handle. + @retval EFI_SUCCESS The handles for the specified device have been created or destroyed + as requested, and for an add operation, the new handles are + returned in ChildHandleBuffer. +**/ +EFI_STATUS +EFIAPI +PciHotPlugRequestNotify ( + IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL * This, + IN EFI_PCI_HOTPLUG_OPERATION Operation, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL, + IN OUT UINT8 *NumberOfChildren, + IN OUT EFI_HANDLE * ChildHandleBuffer + ) +{ + PCI_IO_DEVICE *Bridge; + PCI_IO_DEVICE *Temp; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN Index; + EFI_HANDLE RootBridgeHandle; + EFI_STATUS Status; + + // + // Check input parameter validity + // + if ((Controller == NULL) || (NumberOfChildren == NULL)){ + return EFI_INVALID_PARAMETER; + } + + if ((Operation != EfiPciHotPlugRequestAdd) && (Operation != EfiPciHotplugRequestRemove)) { + return EFI_INVALID_PARAMETER; + } + + if (Operation == EfiPciHotPlugRequestAdd){ + if (ChildHandleBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + } else if ((Operation == EfiPciHotplugRequestRemove) && (*NumberOfChildren != 0)) { + if (ChildHandleBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + gPciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Bridge = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); + + // + // Get root bridge handle + // + Temp = Bridge; + while (Temp->Parent != NULL) { + Temp = Temp->Parent; + } + + RootBridgeHandle = Temp->Handle; + + if (Operation == EfiPciHotPlugRequestAdd) { + // + // Report Status Code to indicate hot plug happens + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_PCI | EFI_IOB_PC_HOTPLUG), + Temp->DevicePath + ); + + if (NumberOfChildren != NULL) { + *NumberOfChildren = 0; + } + + if (IsListEmpty (&Bridge->ChildList)) { + + Status = PciBridgeEnumerator (Bridge); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + Status = StartPciDevicesOnBridge ( + RootBridgeHandle, + Bridge, + RemainingDevicePath, + NumberOfChildren, + ChildHandleBuffer + ); + + return Status; + } + + if (Operation == EfiPciHotplugRequestRemove) { + + if (*NumberOfChildren == 0) { + // + // Remove all devices on the bridge + // + RemoveAllPciDeviceOnBridge (RootBridgeHandle, Bridge); + return EFI_SUCCESS; + + } + + for (Index = 0; Index < *NumberOfChildren; Index++) { + // + // De register all the pci device + // + Status = DeRegisterPciDevice (RootBridgeHandle, ChildHandleBuffer[Index]); + + if (EFI_ERROR (Status)) { + return Status; + } + + } + // + // End for + // + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} + +/** + Search hostbridge according to given handle + + @param RootBridgeHandle Host bridge handle. + + @retval TRUE Found host bridge handle. + @retval FALSE Not found hot bridge handle. + +**/ +BOOLEAN +SearchHostBridgeHandle ( + IN EFI_HANDLE RootBridgeHandle + ) +{ + EFI_HANDLE HostBridgeHandle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + UINTN Index; + EFI_STATUS Status; + + // + // Get the rootbridge Io protocol to find the host bridge handle + // + Status = gBS->OpenProtocol ( + RootBridgeHandle, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo, + gPciBusDriverBinding.DriverBindingHandle, + RootBridgeHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + HostBridgeHandle = PciRootBridgeIo->ParentHandle; + for (Index = 0; Index < gPciHostBridgeNumber; Index++) { + if (HostBridgeHandle == gPciHostBrigeHandles[Index]) { + return TRUE; + } + } + + return FALSE; +} + +/** + Add host bridge handle to global variable for enumerating. + + @param HostBridgeHandle Host bridge handle. + + @retval EFI_SUCCESS Successfully added host bridge. + @retval EFI_ABORTED Host bridge is NULL, or given host bridge + has been in host bridge list. + +**/ +EFI_STATUS +AddHostBridgeEnumerator ( + IN EFI_HANDLE HostBridgeHandle + ) +{ + UINTN Index; + + if (HostBridgeHandle == NULL) { + return EFI_ABORTED; + } + + for (Index = 0; Index < gPciHostBridgeNumber; Index++) { + if (HostBridgeHandle == gPciHostBrigeHandles[Index]) { + return EFI_ABORTED; + } + } + + if (Index < PCI_MAX_HOST_BRIDGE_NUM) { + gPciHostBrigeHandles[Index] = HostBridgeHandle; + gPciHostBridgeNumber++; + } + + return EFI_SUCCESS; +} + |