| /**@file | |
| Copyright (c) 2006, 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 "pcibus.h" | |
| #include "PciEnumerator.h" | |
| #include "PciResourceSupport.h" | |
| #include "PciOptionRomSupport.h" | |
| EFI_STATUS | |
| PciEnumerator ( | |
| IN EFI_HANDLE Controller | |
| ) | |
| /*++ | |
| Routine Description: | |
| This routine is used to enumerate entire pci bus system | |
| in a given platform | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Controller - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| EFI_HANDLE HostBridgeHandle; | |
| EFI_STATUS Status; | |
| EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc; | |
| EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
| // | |
| // If PCI bus has already done the full enumeration, never do it again | |
| // | |
| if (!gFullEnumeration) { | |
| return PciEnumeratorLight (Controller); | |
| } | |
| // | |
| // If this host bridge has been already enumerated, then return successfully | |
| // | |
| if (RootBridgeExisted (Controller)) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Get the rootbridge Io protocol to find the host bridge handle | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciRootBridgeIoProtocolGuid, | |
| (VOID **) &PciRootBridgeIo, | |
| gPciBusDriverBinding.DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Get the host bridge handle | |
| // | |
| HostBridgeHandle = PciRootBridgeIo->ParentHandle; | |
| // | |
| // 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 | |
| // | |
| NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration); | |
| // | |
| // 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; | |
| } | |
| // | |
| // 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; | |
| } | |
| gFullEnumeration = FALSE; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PciRootBridgeEnumerator ( | |
| IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, | |
| IN PCI_IO_DEVICE *RootBridgeDev | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: PciResAlloc - add argument and description to function comment | |
| // TODO: RootBridgeDev - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| EFI_STATUS Status; | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *pConfiguration; | |
| UINT8 SubBusNumber; | |
| UINT8 StartBusNumber; | |
| UINT8 PaddedBusRange; | |
| EFI_HANDLE RootBridgeHandle; | |
| 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_PC_BUS_ENUM, | |
| RootBridgeDev->DevicePath | |
| ); | |
| // | |
| // Get the Bus information | |
| // | |
| Status = PciResAlloc->StartBusEnumeration ( | |
| PciResAlloc, | |
| RootBridgeHandle, | |
| (VOID **) &pConfiguration | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Get the bus number to start with | |
| // | |
| StartBusNumber = (UINT8) (pConfiguration->AddrRangeMin); | |
| // | |
| // Initialize the subordinate bus number | |
| // | |
| SubBusNumber = StartBusNumber; | |
| // | |
| // Assign bus number | |
| // | |
| Status = PciScanBus ( | |
| RootBridgeDev, | |
| (UINT8) (pConfiguration->AddrRangeMin), | |
| &SubBusNumber, | |
| &PaddedBusRange | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Assign max bus number scanned | |
| // | |
| pConfiguration->AddrLen = SubBusNumber - StartBusNumber + 1 + PaddedBusRange; | |
| // | |
| // Set bus number | |
| // | |
| Status = PciResAlloc->SetBusNumbers ( | |
| PciResAlloc, | |
| RootBridgeHandle, | |
| pConfiguration | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| ProcessOptionRom ( | |
| IN PCI_IO_DEVICE *Bridge, | |
| IN UINT64 RomBase, | |
| IN UINT64 MaxLength | |
| ) | |
| /*++ | |
| Routine Description: | |
| This routine is used to process option rom on a certain root bridge | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Bridge - add argument and description to function comment | |
| // TODO: RomBase - add argument and description to function comment | |
| // TODO: MaxLength - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| LIST_ENTRY *CurrentLink; | |
| PCI_IO_DEVICE *Temp; | |
| EFI_STATUS Status; | |
| // | |
| // Go through bridges to reach all devices | |
| // | |
| CurrentLink = Bridge->ChildList.ForwardLink; | |
| while (CurrentLink && CurrentLink != &Bridge->ChildList) { | |
| Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
| if (!IsListEmpty (&Temp->ChildList)) { | |
| // | |
| // Go further to process the option rom under this bridge | |
| // | |
| Status = ProcessOptionRom (Temp, RomBase, MaxLength); | |
| } | |
| if (Temp->RomSize != 0 && Temp->RomSize <= MaxLength) { | |
| // | |
| // Load and process the option rom | |
| // | |
| Status = LoadOpRomImage (Temp, RomBase); | |
| if (Status == EFI_SUCCESS) { | |
| Status = ProcessOpRomImage (Temp); | |
| } | |
| } | |
| CurrentLink = CurrentLink->ForwardLink; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PciAssignBusNumber ( | |
| IN PCI_IO_DEVICE *Bridge, | |
| IN UINT8 StartBusNumber, | |
| OUT UINT8 *SubBusNumber | |
| ) | |
| /*++ | |
| Routine Description: | |
| This routine is used to assign bus number to the given PCI bus system | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Bridge - add argument and description to function comment | |
| // TODO: StartBusNumber - add argument and description to function comment | |
| // TODO: SubBusNumber - add argument and description to function comment | |
| // TODO: EFI_DEVICE_ERROR - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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) && | |
| (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) { | |
| // | |
| // Reserved one bus for cardbus bridge | |
| // | |
| SecondBus = ++(*SubBusNumber); | |
| Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber); | |
| Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18); | |
| Status = PciRootBridgeIoWrite ( | |
| PciRootBridgeIo, | |
| &Pci, | |
| EfiPciWidthUint16, | |
| Address, | |
| 1, | |
| &Register | |
| ); | |
| // | |
| // Initialize SubBusNumber to SecondBus | |
| // | |
| Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); | |
| Status = PciRootBridgeIoWrite ( | |
| PciRootBridgeIo, | |
| &Pci, | |
| EfiPciWidthUint8, | |
| Address, | |
| 1, | |
| SubBusNumber | |
| ); | |
| // | |
| // If it is PPB, resursively search down this bridge | |
| // | |
| if (IS_PCI_BRIDGE (&Pci)) { | |
| Register8 = 0xFF; | |
| Status = PciRootBridgeIoWrite ( | |
| PciRootBridgeIo, | |
| &Pci, | |
| 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 = PciRootBridgeIoWrite ( | |
| PciRootBridgeIo, | |
| &Pci, | |
| 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; | |
| } | |
| EFI_STATUS | |
| DetermineRootBridgeAttributes ( | |
| IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, | |
| IN PCI_IO_DEVICE *RootBridgeDev | |
| ) | |
| /*++ | |
| Routine Description: | |
| This routine is used to determine the root bridge attribute by interfacing | |
| the host bridge resource allocation protocol. | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: PciResAlloc - add argument and description to function comment | |
| // TODO: RootBridgeDev - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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) { | |
| RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED; | |
| } | |
| if (Attributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) { | |
| 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; | |
| } | |
| UINT64 | |
| GetMaxOptionRomSize ( | |
| IN PCI_IO_DEVICE *Bridge | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get Max Option Rom size on this bridge | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Bridge - add argument and description to function comment | |
| { | |
| LIST_ENTRY *CurrentLink; | |
| PCI_IO_DEVICE *Temp; | |
| UINT64 MaxOptionRomSize; | |
| UINT64 TempOptionRomSize; | |
| MaxOptionRomSize = 0; | |
| // | |
| // Go through bridges to reach all devices | |
| // | |
| CurrentLink = Bridge->ChildList.ForwardLink; | |
| while (CurrentLink && 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; | |
| } | |
| EFI_STATUS | |
| PciHostBridgeDeviceAttribute ( | |
| IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc | |
| ) | |
| /*++ | |
| Routine Description: | |
| Process attributes of devices on this host bridge | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: PciResAlloc - add argument and description to function comment | |
| // TODO: EFI_NOT_FOUND - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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; | |
| } | |
| EFI_STATUS | |
| GetResourceAllocationStatus ( | |
| VOID *AcpiConfig, | |
| OUT UINT64 *IoResStatus, | |
| OUT UINT64 *Mem32ResStatus, | |
| OUT UINT64 *PMem32ResStatus, | |
| OUT UINT64 *Mem64ResStatus, | |
| OUT UINT64 *PMem64ResStatus | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get resource allocation status from the ACPI pointer | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: AcpiConfig - add argument and description to function comment | |
| // TODO: IoResStatus - add argument and description to function comment | |
| // TODO: Mem32ResStatus - add argument and description to function comment | |
| // TODO: PMem32ResStatus - add argument and description to function comment | |
| // TODO: Mem64ResStatus - add argument and description to function comment | |
| // TODO: PMem64ResStatus - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| UINT8 *Temp; | |
| UINT64 ResStatus; | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr; | |
| Temp = (UINT8 *) AcpiConfig; | |
| while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { | |
| ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; | |
| ResStatus = ptr->AddrTranslationOffset; | |
| switch (ptr->ResType) { | |
| case 0: | |
| if (ptr->AddrSpaceGranularity == 32) { | |
| if (ptr->SpecificFlag == 0x06) { | |
| // | |
| // Pmem32 | |
| // | |
| *PMem32ResStatus = ResStatus; | |
| } else { | |
| // | |
| // Mem32 | |
| // | |
| *Mem32ResStatus = ResStatus; | |
| } | |
| } | |
| if (ptr->AddrSpaceGranularity == 64) { | |
| if (ptr->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); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| RejectPciDevice ( | |
| IN PCI_IO_DEVICE *PciDevice | |
| ) | |
| /*++ | |
| Routine Description: | |
| Remove a PCI device from device pool and mark its bar | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: PciDevice - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| // TODO: EFI_ABORTED - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| // TODO: EFI_ABORTED - add return value to function comment | |
| { | |
| 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 ) { | |
| gBS->FreePool (PciDevice->ResourcePaddingDescriptors); | |
| PciDevice->ResourcePaddingDescriptors = NULL; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Skip RB and PPB | |
| // | |
| if (IS_PCI_BRIDGE (&PciDevice->Pci) || (!PciDevice->Parent)) { | |
| return EFI_ABORTED; | |
| } | |
| if (IS_CARDBUS_BRIDGE (&PciDevice->Pci)) { | |
| // | |
| // Get the root bridge device | |
| // | |
| Bridge = PciDevice; | |
| while (Bridge->Parent) { | |
| Bridge = Bridge->Parent; | |
| } | |
| RemoveAllPciDeviceOnBridge (Bridge->Handle, PciDevice); | |
| // | |
| // Mark its bar | |
| // | |
| InitializeP2C (PciDevice); | |
| } | |
| // | |
| // Remove the device | |
| // | |
| Bridge = PciDevice->Parent; | |
| CurrentLink = Bridge->ChildList.ForwardLink; | |
| while (CurrentLink && CurrentLink != &Bridge->ChildList) { | |
| Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
| if (Temp == PciDevice) { | |
| InitializePciDevice (Temp); | |
| RemoveEntryList (CurrentLink); | |
| FreePciDevice (Temp); | |
| return EFI_SUCCESS; | |
| } | |
| CurrentLink = CurrentLink->ForwardLink; | |
| } | |
| return EFI_ABORTED; | |
| } | |
| BOOLEAN | |
| IsRejectiveDevice ( | |
| IN PCI_RESOURCE_NODE *PciResNode | |
| ) | |
| /*++ | |
| Routine Description: | |
| Determine whethter a PCI device can be rejected | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: PciResNode - add argument and description to function comment | |
| { | |
| PCI_IO_DEVICE *Temp; | |
| Temp = PciResNode->PciDev; | |
| // | |
| // Ensure the device is present | |
| // | |
| if (!Temp) { | |
| return FALSE; | |
| } | |
| // | |
| // PPB and RB should go ahead | |
| // | |
| if (IS_PCI_BRIDGE (&Temp->Pci) || (!Temp->Parent)) { | |
| return TRUE; | |
| } | |
| // | |
| // Skip device on Bus0 | |
| // | |
| if ((Temp->Parent) && (Temp->BusNumber == 0)) { | |
| return FALSE; | |
| } | |
| // | |
| // Skip VGA | |
| // | |
| if (IS_PCI_VGA (&Temp->Pci)) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| PCI_RESOURCE_NODE * | |
| GetLargerConsumerDevice ( | |
| IN PCI_RESOURCE_NODE *PciResNode1, | |
| IN PCI_RESOURCE_NODE *PciResNode2 | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get the larger resource consumer | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: PciResNode1 - add argument and description to function comment | |
| // TODO: PciResNode2 - add argument and description to function comment | |
| { | |
| if (!PciResNode2) { | |
| return PciResNode1; | |
| } | |
| if ((IS_PCI_BRIDGE(&(PciResNode2->PciDev->Pci)) || !(PciResNode2->PciDev->Parent)) \ | |
| && (PciResNode2->ResourceUsage != PciResUsagePadding) ) | |
| { | |
| return PciResNode1; | |
| } | |
| if (!PciResNode1) { | |
| return PciResNode2; | |
| } | |
| if ((PciResNode1->Length) > (PciResNode2->Length)) { | |
| return PciResNode1; | |
| } | |
| return PciResNode2; | |
| } | |
| PCI_RESOURCE_NODE * | |
| GetMaxResourceConsumerDevice ( | |
| IN PCI_RESOURCE_NODE *ResPool | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get the max resource consumer in the host resource pool | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: ResPool - add argument and description to function comment | |
| { | |
| PCI_RESOURCE_NODE *Temp; | |
| LIST_ENTRY *CurrentLink; | |
| PCI_RESOURCE_NODE *PciResNode; | |
| PCI_RESOURCE_NODE *PPBResNode; | |
| PciResNode = NULL; | |
| CurrentLink = ResPool->ChildList.ForwardLink; | |
| while (CurrentLink && 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)) \ | |
| && (Temp->ResourceUsage != PciResUsagePadding)) | |
| { | |
| PPBResNode = GetMaxResourceConsumerDevice (Temp); | |
| PciResNode = GetLargerConsumerDevice (PciResNode, PPBResNode); | |
| } else { | |
| PciResNode = GetLargerConsumerDevice (PciResNode, Temp); | |
| } | |
| CurrentLink = CurrentLink->ForwardLink; | |
| } | |
| return PciResNode; | |
| } | |
| 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 | |
| ) | |
| /*++ | |
| Routine Description: | |
| Adjust host bridge allocation so as to reduce resource requirement | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: IoPool - add argument and description to function comment | |
| // TODO: Mem32Pool - add argument and description to function comment | |
| // TODO: PMem32Pool - add argument and description to function comment | |
| // TODO: Mem64Pool - add argument and description to function comment | |
| // TODO: PMem64Pool - add argument and description to function comment | |
| // TODO: IoResStatus - add argument and description to function comment | |
| // TODO: Mem32ResStatus - add argument and description to function comment | |
| // TODO: PMem32ResStatus - add argument and description to function comment | |
| // TODO: Mem64ResStatus - add argument and description to function comment | |
| // TODO: PMem64ResStatus - add argument and description to function comment | |
| // TODO: EFI_ABORTED - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| // TODO: EFI_ABORTED - add return value to function comment | |
| { | |
| 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_NONEXISTENT) { | |
| // | |
| // Hostbridge hasn't this resource type | |
| // | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Hostbridge hasn't enough resource | |
| // | |
| PciResNode = GetMaxResourceConsumerDevice (ResPool[ResType]); | |
| if (!PciResNode) { | |
| continue; | |
| } | |
| // | |
| // Check if the device has been removed before | |
| // | |
| for (DevIndex = 0; DevIndex < RemovedPciDevNum; DevIndex++) { | |
| if (PciResNode->PciDev == RemovedPciDev[DevIndex]) { | |
| continue; | |
| } | |
| } | |
| // | |
| // Remove the device if it isn't in the array | |
| // | |
| Status = RejectPciDevice (PciResNode->PciDev); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code | |
| // | |
| // | |
| // Have no way to get ReqRes, AllocRes & Bar here | |
| // | |
| ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData)); | |
| AllocFailExtendedData.DevicePathSize = 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; | |
| } | |
| } | |
| 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 **pConfig | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Bridge - add argument and description to function comment | |
| // TODO: IoNode - add argument and description to function comment | |
| // TODO: Mem32Node - add argument and description to function comment | |
| // TODO: PMem32Node - add argument and description to function comment | |
| // TODO: Mem64Node - add argument and description to function comment | |
| // TODO: PMem64Node - add argument and description to function comment | |
| // TODO: pConfig - add argument and description to function comment | |
| // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment | |
| // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| UINT8 NumConfig; | |
| UINT8 Aperture; | |
| UINT8 *Configuration; | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; | |
| EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd; | |
| NumConfig = 0; | |
| Aperture = 0; | |
| *pConfig = 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 = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); | |
| if (Configuration == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| ZeroMem ( | |
| Configuration, | |
| sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) | |
| ); | |
| Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; | |
| // | |
| // Deal with io aperture | |
| // | |
| if (Aperture & 0x01) { | |
| Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); | |
| } | |
| // | |
| // Deal with mem32 aperture | |
| // | |
| if (Aperture & 0x02) { | |
| Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); | |
| } | |
| // | |
| // Deal with Pmem32 aperture | |
| // | |
| if (Aperture & 0x04) { | |
| Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); | |
| } | |
| // | |
| // Deal with mem64 aperture | |
| // | |
| if (Aperture & 0x08) { | |
| Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); | |
| } | |
| // | |
| // Deal with Pmem64 aperture | |
| // | |
| if (Aperture & 0x10) { | |
| Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (Configuration + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); | |
| } | |
| // | |
| // put the checksum | |
| // | |
| PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) ((UINT8 *) Ptr); | |
| PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; | |
| PtrEnd->Checksum = 0; | |
| } else { | |
| // | |
| // If there is no resource request | |
| // | |
| Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); | |
| if (Configuration == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| ZeroMem (Configuration, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); | |
| Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (Configuration); | |
| Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Configuration + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); | |
| PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; | |
| PtrEnd->Checksum = 0; | |
| } | |
| *pConfig = Configuration; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| GetResourceBase ( | |
| IN VOID *pConfig, | |
| OUT UINT64 *IoBase, | |
| OUT UINT64 *Mem32Base, | |
| OUT UINT64 *PMem32Base, | |
| OUT UINT64 *Mem64Base, | |
| OUT UINT64 *PMem64Base | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: pConfig - add argument and description to function comment | |
| // TODO: IoBase - add argument and description to function comment | |
| // TODO: Mem32Base - add argument and description to function comment | |
| // TODO: PMem32Base - add argument and description to function comment | |
| // TODO: Mem64Base - add argument and description to function comment | |
| // TODO: PMem64Base - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| UINT8 *Temp; | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; | |
| UINT64 ResStatus; | |
| *IoBase = 0xFFFFFFFFFFFFFFFFULL; | |
| *Mem32Base = 0xFFFFFFFFFFFFFFFFULL; | |
| *PMem32Base = 0xFFFFFFFFFFFFFFFFULL; | |
| *Mem64Base = 0xFFFFFFFFFFFFFFFFULL; | |
| *PMem64Base = 0xFFFFFFFFFFFFFFFFULL; | |
| Temp = (UINT8 *) pConfig; | |
| 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) { | |
| *PMem32Base = Ptr->AddrRangeMin; | |
| } else { | |
| *Mem32Base = Ptr->AddrRangeMin; | |
| } | |
| } | |
| if (Ptr->AddrSpaceGranularity == 64) { | |
| if (Ptr->SpecificFlag & 0x06) { | |
| *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); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PciBridgeEnumerator ( | |
| IN PCI_IO_DEVICE *BridgeDev | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: BridgeDev - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| UINT8 SubBusNumber; | |
| UINT8 StartBusNumber; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| EFI_STATUS Status; | |
| SubBusNumber = 0; | |
| StartBusNumber = 0; | |
| PciIo = &(BridgeDev->PciIo); | |
| Status = PciIoRead (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; | |
| } | |
| EFI_STATUS | |
| PciBridgeResourceAllocator ( | |
| IN PCI_IO_DEVICE *Bridge | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Bridge - add argument and description to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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, | |
| 0xFFF, | |
| 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 | |
| // | |
| Status = CreateResourceMap ( | |
| Bridge, | |
| IoBridge, | |
| Mem32Bridge, | |
| PMem32Bridge, | |
| Mem64Bridge, | |
| PMem64Bridge | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| 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; | |
| } | |
| EFI_STATUS | |
| GetResourceBaseFromBridge ( | |
| IN PCI_IO_DEVICE *Bridge, | |
| OUT UINT64 *IoBase, | |
| OUT UINT64 *Mem32Base, | |
| OUT UINT64 *PMem32Base, | |
| OUT UINT64 *Mem64Base, | |
| OUT UINT64 *PMem64Base | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Bridge - add argument and description to function comment | |
| // TODO: IoBase - add argument and description to function comment | |
| // TODO: Mem32Base - add argument and description to function comment | |
| // TODO: PMem32Base - add argument and description to function comment | |
| // TODO: Mem64Base - add argument and description to function comment | |
| // TODO: PMem64Base - add argument and description to function comment | |
| // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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) { | |
| *IoBase = Bridge->PciBar[PPB_IO_RANGE].BaseAddress; | |
| } | |
| if (Bridge->PciBar[PPB_MEM32_RANGE].Length) { | |
| *Mem32Base = Bridge->PciBar[PPB_MEM32_RANGE].BaseAddress; | |
| } | |
| if (Bridge->PciBar[PPB_PMEM32_RANGE].Length) { | |
| *PMem32Base = Bridge->PciBar[PPB_PMEM32_RANGE].BaseAddress; | |
| } | |
| if (Bridge->PciBar[PPB_PMEM64_RANGE].Length) { | |
| *PMem64Base = Bridge->PciBar[PPB_PMEM64_RANGE].BaseAddress; | |
| } else { | |
| *PMem64Base = gAllOne; | |
| } | |
| } | |
| if (IS_CARDBUS_BRIDGE (&Bridge->Pci)) { | |
| if (Bridge->PciBar[P2C_IO_1].Length) { | |
| *IoBase = Bridge->PciBar[P2C_IO_1].BaseAddress; | |
| } else { | |
| if (Bridge->PciBar[P2C_IO_2].Length) { | |
| *IoBase = Bridge->PciBar[P2C_IO_2].BaseAddress; | |
| } | |
| } | |
| if (Bridge->PciBar[P2C_MEM_1].Length) { | |
| 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) { | |
| 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; | |
| } | |
| EFI_STATUS | |
| NotifyPhase ( | |
| IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, | |
| EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: PciResAlloc - add argument and description to function comment | |
| // TODO: Phase - add argument and description to function comment | |
| // TODO: EFI_NOT_FOUND - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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::PhaseNotify() if the protocol is present. | |
| // | |
| gPciPlatformProtocol->PhaseNotify ( | |
| gPciPlatformProtocol, | |
| HostBridgeHandle, | |
| Phase, | |
| ChipsetEntry | |
| ); | |
| } | |
| Status = PciResAlloc->NotifyPhase ( | |
| PciResAlloc, | |
| Phase | |
| ); | |
| if (gPciPlatformProtocol != NULL) { | |
| // | |
| // Call PlatformPci::PhaseNotify() if the protocol is present. | |
| // | |
| gPciPlatformProtocol->PhaseNotify ( | |
| gPciPlatformProtocol, | |
| HostBridgeHandle, | |
| Phase, | |
| ChipsetExit | |
| ); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| 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 | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: Bridge - add argument and description to function comment | |
| // TODO: Bus - add argument and description to function comment | |
| // TODO: Device - add argument and description to function comment | |
| // TODO: Func - add argument and description to function comment | |
| // TODO: Phase - add argument and description to function comment | |
| // TODO: EFI_UNSUPPORTED - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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) { | |
| 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 | |
| ); | |
| } | |
| 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 | |
| ); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| 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 | |
| ) | |
| /*++ | |
| Routine Description: | |
| Hot plug request notify. | |
| Arguments: | |
| This - A pointer to the hot plug request protocol. | |
| Operation - The operation. | |
| Controller - A pointer to the controller. | |
| RemainningDevicePath - A pointer to the device path. | |
| NumberOfChildren - A the number of child handle in the ChildHandleBuffer. | |
| ChildHandleBuffer - A pointer to the array contain the child handle. | |
| Returns: | |
| Status code. | |
| --*/ | |
| // TODO: RemainingDevicePath - add argument and description to function comment | |
| // TODO: EFI_NOT_FOUND - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| PCI_IO_DEVICE *Bridge; | |
| PCI_IO_DEVICE *Temp; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINTN Index; | |
| EFI_HANDLE RootBridgeHandle; | |
| EFI_STATUS Status; | |
| 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) { | |
| Temp = Temp->Parent; | |
| } | |
| RootBridgeHandle = Temp->Handle; | |
| if (Operation == EfiPciHotPlugRequestAdd) { | |
| 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 EFI_SUCCESS; | |
| } | |
| if (Operation == EfiPciHotplugRequestRemove) { | |
| if (*NumberOfChildren == 0) { | |
| // | |
| // Remove all devices on the bridge | |
| // | |
| Status = RemoveAllPciDeviceOnBridge (RootBridgeHandle, Bridge); | |
| return Status; | |
| } | |
| 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; | |
| } | |
| BOOLEAN | |
| SearchHostBridgeHandle ( | |
| IN EFI_HANDLE RootBridgeHandle | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: RootBridgeHandle - add argument and description to function comment | |
| { | |
| 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; | |
| } | |
| EFI_STATUS | |
| AddHostBridgeEnumerator ( | |
| IN EFI_HANDLE HostBridgeHandle | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| // TODO: HostBridgeHandle - add argument and description to function comment | |
| // TODO: EFI_ABORTED - add return value to function comment | |
| // TODO: EFI_ABORTED - add return value to function comment | |
| // TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| UINTN Index; | |
| if (!HostBridgeHandle) { | |
| 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; | |
| } |