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