/*++ | |
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. | |
Module Name: | |
PciEnumerator.c | |
Abstract: | |
PCI Bus Driver | |
Revision History | |
--*/ | |
#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 = 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; | |
} | |
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; | |
REPORT_STATUS_CODE_LIBRARY_RESOURCE_ALLOC_FAILURE_ERROR_DATA 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 = 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; | |
} | |
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; | |
} |