audk/PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.c

1202 lines
37 KiB
C
Raw Normal View History

/** @file
Pci Host Bridge driver:
Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation
Copyright (c) 2008 - 2009, Intel Corporation<BR> All rights
reserved. This program and the accompanying materials are
licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PciHostBridge.h"
//
// Support 64 K IO space
//
#define RES_IO_BASE 0x1000
#define RES_IO_LIMIT 0xFFFF
//
// Support 4G address space
//
#define RES_MEM_BASE_1 0xF8000000
#define RES_MEM_LIMIT_1 (0xFEC00000 - 1)
//
// Hard code: Root Bridge Number within the host bridge
// Root Bridge's attribute
// Root Bridge's device path
// Root Bridge's resource appeture
//
UINTN RootBridgeNumber[1] = { 1 };
UINT64 RootBridgeAttribute[1][1] = { EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM };
EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[1][1] = {
{
ACPI_DEVICE_PATH,
ACPI_DP,
(UINT8) (sizeof(ACPI_HID_DEVICE_PATH)),
(UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8),
EISA_PNP_ID(0x0A03),
0,
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
END_DEVICE_PATH_LENGTH,
0
}
};
PCI_ROOT_BRIDGE_RESOURCE_APPETURE mResAppeture[1][1] = {
{0, 0, 0, 0xffffffff, 0, 1 << 16}
};
EFI_HANDLE mDriverImageHandle;
PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = {
PCI_HOST_BRIDGE_SIGNATURE, // Signature
NULL, // HostBridgeHandle
0, // RootBridgeNumber
{NULL, NULL}, // Head
FALSE, // ResourceSubiteed
TRUE, // CanRestarted
{
NotifyPhase,
GetNextRootBridge,
GetAttributes,
StartBusEnumeration,
SetBusNumbers,
SubmitResources,
GetProposedResources,
PreprocessController
}
};
//
// Implementation
//
EFI_STATUS
EFIAPI
InitializePciHostBridge (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Entry point of this driver
Arguments:
ImageHandle -
SystemTable -
Returns:
--*/
{
EFI_STATUS Status;
UINTN Loop1;
UINTN Loop2;
PCI_HOST_BRIDGE_INSTANCE *HostBridge;
PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
IN EFI_PHYSICAL_ADDRESS BaseAddress;
IN UINT64 Length;
mDriverImageHandle = ImageHandle;
//
// Create Host Bridge Device Handle
//
for (Loop1 = 0; Loop1 < HOST_BRIDGE_NUMBER; Loop1++) {
HostBridge = AllocateCopyPool (sizeof(PCI_HOST_BRIDGE_INSTANCE), &mPciHostBridgeInstanceTemplate);
if (HostBridge == NULL) {
return EFI_OUT_OF_RESOURCES;
}
HostBridge->RootBridgeNumber = RootBridgeNumber[Loop1];
InitializeListHead (&HostBridge->Head);
Status = gBS->InstallMultipleProtocolInterfaces (
&HostBridge->HostBridgeHandle,
&gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,
NULL
);
if (EFI_ERROR (Status)) {
FreePool (HostBridge);
return EFI_DEVICE_ERROR;
}
//
// Create Root Bridge Device Handle in this Host Bridge
//
for (Loop2 = 0; Loop2 < HostBridge->RootBridgeNumber; Loop2++) {
PrivateData = AllocateZeroPool (sizeof(PCI_ROOT_BRIDGE_INSTANCE));
if (PrivateData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
PrivateData->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[Loop1][Loop2];
RootBridgeConstructor (
&PrivateData->Io,
HostBridge->HostBridgeHandle,
RootBridgeAttribute[Loop1][Loop2],
&mResAppeture[Loop1][Loop2]
);
Status = gBS->InstallMultipleProtocolInterfaces(
&PrivateData->Handle,
&gEfiDevicePathProtocolGuid, PrivateData->DevicePath,
&gEfiPciRootBridgeIoProtocolGuid, &PrivateData->Io,
NULL
);
if (EFI_ERROR (Status)) {
FreePool(PrivateData);
return EFI_DEVICE_ERROR;
}
InsertTailList (&HostBridge->Head, &PrivateData->Link);
}
}
Status = gDS->AddIoSpace (
EfiGcdIoTypeIo,
RES_IO_BASE,
RES_IO_LIMIT - RES_IO_BASE + 1
);
// PCI memory space from 3.75Gbytes->(4GBytes - BIOSFWH local APIC etc)
Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeMemoryMappedIo,
RES_MEM_BASE_1,
(RES_MEM_LIMIT_1 - RES_MEM_BASE_1 + 1),
0
);
BaseAddress = 0x80000000;
Length = RES_MEM_BASE_1 - BaseAddress;
Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeMemoryMappedIo,
BaseAddress,
Length,
0
);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
NotifyPhase(
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
)
/*++
Routine Description:
Enter a certain phase of the PCI enumeration process
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance
Phase -- The phase during enumeration
Returns:
--*/
{
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
PCI_RESOURCE_TYPE Index;
LIST_ENTRY *List;
EFI_PHYSICAL_ADDRESS BaseAddress;
UINT64 AddrLen;
UINTN BitsOfAlignment;
EFI_STATUS Status;
EFI_STATUS ReturnStatus;
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
switch (Phase) {
case EfiPciHostBridgeBeginEnumeration:
if (HostBridgeInstance->CanRestarted) {
//
// Reset the Each Root Bridge
//
List = HostBridgeInstance->Head.ForwardLink;
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
for (Index = TypeIo; Index < TypeMax; Index++) {
RootBridgeInstance->ResAllocNode[Index].Type = Index;
RootBridgeInstance->ResAllocNode[Index].Base = 0;
RootBridgeInstance->ResAllocNode[Index].Length = 0;
RootBridgeInstance->ResAllocNode[Index].Status = ResNone;
}
List = List->ForwardLink;
}
HostBridgeInstance->ResourceSubmited = FALSE;
HostBridgeInstance->CanRestarted = TRUE;
} else {
//
// Can not restart
//
return EFI_NOT_READY;
}
break;
case EfiPciHostBridgeBeginBusAllocation:
//
// No specific action is required here, can perform any chipset specific programing
//
HostBridgeInstance->CanRestarted = FALSE;
return EFI_SUCCESS;
break;
case EfiPciHostBridgeEndBusAllocation:
//
// No specific action is required here, can perform any chipset specific programing
//
//HostBridgeInstance->CanRestarted = FALSE;
return EFI_SUCCESS;
break;
case EfiPciHostBridgeBeginResourceAllocation:
//
// No specific action is required here, can perform any chipset specific programing
//
//HostBridgeInstance->CanRestarted = FALSE;
return EFI_SUCCESS;
break;
case EfiPciHostBridgeAllocateResources:
ReturnStatus = EFI_SUCCESS;
if (HostBridgeInstance->ResourceSubmited) {
//
// Take care of the resource dependencies between the root bridges
//
List = HostBridgeInstance->Head.ForwardLink;
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
for (Index = TypeIo; Index < TypeBus; Index++) {
if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) {
AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
//
// Get the number of '1' in Alignment.
//
BitsOfAlignment = HighBitSet64 (RootBridgeInstance->ResAllocNode[Index].Alignment) + 1;
switch (Index) {
case TypeIo:
//
// It is impossible for this chipset to align 0xFFFF for IO16
// So clear it
//
if (BitsOfAlignment >= 16) {
BitsOfAlignment = 0;
}
Status = gDS->AllocateIoSpace (
EfiGcdAllocateAnySearchBottomUp,
EfiGcdIoTypeIo,
BitsOfAlignment,
AddrLen,
&BaseAddress,
mDriverImageHandle,
NULL
);
if (!EFI_ERROR (Status)) {
RootBridgeInstance->ResAllocNode[Index].Base = (UINTN)BaseAddress;
RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated;
} else {
ReturnStatus = Status;
if (Status != EFI_OUT_OF_RESOURCES) {
RootBridgeInstance->ResAllocNode[Index].Length = 0;
}
}
break;
case TypeMem32:
//
// It is impossible for this chipset to align 0xFFFFFFFF for Mem32
// So clear it
//
if (BitsOfAlignment >= 32) {
BitsOfAlignment = 0;
}
Status = gDS->AllocateMemorySpace (
EfiGcdAllocateAnySearchBottomUp,
EfiGcdMemoryTypeMemoryMappedIo,
BitsOfAlignment,
AddrLen,
&BaseAddress,
mDriverImageHandle,
NULL
);
if (!EFI_ERROR (Status)) {
// We were able to allocate the PCI memory
RootBridgeInstance->ResAllocNode[Index].Base = (UINTN)BaseAddress;
RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated;
} else {
// Not able to allocate enough PCI memory
ReturnStatus = Status;
if (Status != EFI_OUT_OF_RESOURCES) {
RootBridgeInstance->ResAllocNode[Index].Length = 0;
}
ASSERT (FALSE);
}
break;
case TypePMem32:
case TypeMem64:
case TypePMem64:
ReturnStatus = EFI_ABORTED;
break;
default:
ASSERT (FALSE);
break;
}; //end switch
}
}
List = List->ForwardLink;
}
return ReturnStatus;
} else {
return EFI_NOT_READY;
}
break;
case EfiPciHostBridgeSetResources:
break;
case EfiPciHostBridgeFreeResources:
ReturnStatus = EFI_SUCCESS;
List = HostBridgeInstance->Head.ForwardLink;
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
for (Index = TypeIo; Index < TypeBus; Index++) {
if (RootBridgeInstance->ResAllocNode[Index].Status == ResAllocated) {
AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
BaseAddress = RootBridgeInstance->ResAllocNode[Index].Base;
switch (Index) {
case TypeIo:
Status = gDS->FreeIoSpace (BaseAddress, AddrLen);
if (EFI_ERROR (Status)) {
ReturnStatus = Status;
}
break;
case TypeMem32:
Status = gDS->FreeMemorySpace (BaseAddress, AddrLen);
if (EFI_ERROR (Status)) {
ReturnStatus = Status;
}
break;
case TypePMem32:
break;
case TypeMem64:
break;
case TypePMem64:
break;
default:
ASSERT (FALSE);
break;
}; //end switch
RootBridgeInstance->ResAllocNode[Index].Type = Index;
RootBridgeInstance->ResAllocNode[Index].Base = 0;
RootBridgeInstance->ResAllocNode[Index].Length = 0;
RootBridgeInstance->ResAllocNode[Index].Status = ResNone;
}
}
List = List->ForwardLink;
}
HostBridgeInstance->ResourceSubmited = FALSE;
HostBridgeInstance->CanRestarted = TRUE;
return ReturnStatus;
break;
case EfiPciHostBridgeEndResourceAllocation:
HostBridgeInstance->CanRestarted = FALSE;
break;
default:
return EFI_INVALID_PARAMETER;
}; // end switch
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GetNextRootBridge(
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN OUT EFI_HANDLE *RootBridgeHandle
)
/*++
Routine Description:
Return the device handle of the next PCI root bridge that is associated with
this Host Bridge
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
RootBridgeHandle -- Returns the device handle of the next PCI Root Bridge.
On input, it holds the RootBridgeHandle returned by the most
recent call to GetNextRootBridge().The handle for the first
PCI Root Bridge is returned if RootBridgeHandle is NULL on input
Returns:
--*/
{
BOOLEAN NoRootBridge;
LIST_ENTRY *List;
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
NoRootBridge = TRUE;
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
List = HostBridgeInstance->Head.ForwardLink;
while (List != &HostBridgeInstance->Head) {
NoRootBridge = FALSE;
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
if (*RootBridgeHandle == NULL) {
//
// Return the first Root Bridge Handle of the Host Bridge
//
*RootBridgeHandle = RootBridgeInstance->Handle;
return EFI_SUCCESS;
} else {
if (*RootBridgeHandle == RootBridgeInstance->Handle) {
//
// Get next if have
//
List = List->ForwardLink;
if (List!=&HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
*RootBridgeHandle = RootBridgeInstance->Handle;
return EFI_SUCCESS;
} else {
return EFI_NOT_FOUND;
}
}
}
List = List->ForwardLink;
} //end while
if (NoRootBridge) {
return EFI_NOT_FOUND;
} else {
return EFI_INVALID_PARAMETER;
}
}
EFI_STATUS
EFIAPI
GetAttributes(
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN EFI_HANDLE RootBridgeHandle,
OUT UINT64 *Attributes
)
/*++
Routine Description:
Returns the attributes of a PCI Root Bridge.
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
RootBridgeHandle -- The device handle of the PCI Root Bridge
that the caller is interested in
Attribute -- The pointer to attributes of the PCI Root Bridge
Returns:
--*/
{
LIST_ENTRY *List;
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
if (Attributes == NULL) {
return EFI_INVALID_PARAMETER;
}
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
List = HostBridgeInstance->Head.ForwardLink;
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
if (RootBridgeHandle == RootBridgeInstance->Handle) {
*Attributes = RootBridgeInstance->RootBridgeAttrib;
return EFI_SUCCESS;
}
List = List->ForwardLink;
}
//
// RootBridgeHandle is not an EFI_HANDLE
// that was returned on a previous call to GetNextRootBridge()
//
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
EFIAPI
StartBusEnumeration(
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN EFI_HANDLE RootBridgeHandle,
OUT VOID **Configuration
)
/*++
Routine Description:
This is the request from the PCI enumerator to set up
the specified PCI Root Bridge for bus enumeration process.
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
RootBridgeHandle -- The PCI Root Bridge to be set up
Configuration -- Pointer to the pointer to the PCI bus resource descriptor
Returns:
--*/
{
LIST_ENTRY *List;
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
VOID *Buffer;
UINT8 *Temp;
UINT64 BusStart;
UINT64 BusEnd;
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
List = HostBridgeInstance->Head.ForwardLink;
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
if (RootBridgeHandle == RootBridgeInstance->Handle) {
//
// Set up the Root Bridge for Bus Enumeration
//
BusStart = RootBridgeInstance->BusBase;
BusEnd = RootBridgeInstance->BusLimit;
//
// Program the Hardware(if needed) if error return EFI_DEVICE_ERROR
//
Buffer = AllocatePool (sizeof(EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof(EFI_ACPI_END_TAG_DESCRIPTOR));
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Temp = (UINT8 *)Buffer;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->Desc = 0x8A;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->Len = 0x2B;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->ResType = 2;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->GenFlag = 0;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->SpecificFlag = 0;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrSpaceGranularity = 0;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrRangeMin = BusStart;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrRangeMax = 0;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrTranslationOffset = 0;
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp)->AddrLen = BusEnd - BusStart + 1;
Temp = Temp + sizeof(EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
((EFI_ACPI_END_TAG_DESCRIPTOR *)Temp)->Desc = 0x79;
((EFI_ACPI_END_TAG_DESCRIPTOR *)Temp)->Checksum = 0x0;
*Configuration = Buffer;
return EFI_SUCCESS;
}
List = List->ForwardLink;
}
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
EFIAPI
SetBusNumbers(
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN EFI_HANDLE RootBridgeHandle,
IN VOID *Configuration
)
/*++
Routine Description:
This function programs the PCI Root Bridge hardware so that
it decodes the specified PCI bus range
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
RootBridgeHandle -- The PCI Root Bridge whose bus range is to be programmed
Configuration -- The pointer to the PCI bus resource descriptor
Returns:
--*/
{
LIST_ENTRY *List;
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
UINT8 *Ptr;
UINTN BusStart;
UINTN BusEnd;
UINTN BusLen;
if (Configuration == NULL) {
return EFI_INVALID_PARAMETER;
}
Ptr = Configuration;
//
// Check the Configuration is valid
//
if(*Ptr != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
return EFI_INVALID_PARAMETER;
}
if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->ResType != 2) {
return EFI_INVALID_PARAMETER;
}
Ptr += sizeof(EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
if (*Ptr != ACPI_END_TAG_DESCRIPTOR) {
return EFI_INVALID_PARAMETER;
}
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
List = HostBridgeInstance->Head.ForwardLink;
Ptr = Configuration;
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
if (RootBridgeHandle == RootBridgeInstance->Handle) {
BusStart = (UINTN)((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrRangeMin;
BusLen = (UINTN)((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrLen;
BusEnd = BusStart + BusLen - 1;
if (BusStart > BusEnd) {
return EFI_INVALID_PARAMETER;
}
if ((BusStart < RootBridgeInstance->BusBase) || (BusEnd > RootBridgeInstance->BusLimit)) {
return EFI_INVALID_PARAMETER;
}
//
// Update the Bus Range
//
RootBridgeInstance->ResAllocNode[TypeBus].Base = BusStart;
RootBridgeInstance->ResAllocNode[TypeBus].Length = BusLen;
RootBridgeInstance->ResAllocNode[TypeBus].Status = ResAllocated;
//
// Program the Root Bridge Hardware
//
return EFI_SUCCESS;
}
List = List->ForwardLink;
}
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
EFIAPI
SubmitResources(
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN EFI_HANDLE RootBridgeHandle,
IN VOID *Configuration
)
/*++
Routine Description:
Submits the I/O and memory resource requirements for the specified PCI Root Bridge
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
RootBridgeHandle -- The PCI Root Bridge whose I/O and memory resource requirements
are being submitted
Configuration -- The pointer to the PCI I/O and PCI memory resource descriptor
Returns:
--*/
{
LIST_ENTRY *List;
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
UINT8 *Temp;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr;
UINT64 AddrLen;
UINT64 Alignment;
//
// Check the input parameter: Configuration
//
if (Configuration == NULL) {
return EFI_INVALID_PARAMETER;
}
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
List = HostBridgeInstance->Head.ForwardLink;
Temp = (UINT8 *)Configuration;
while ( *Temp == 0x8A) {
Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) ;
}
if (*Temp != 0x79) {
return EFI_INVALID_PARAMETER;
}
Temp = (UINT8 *)Configuration;
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
if (RootBridgeHandle == RootBridgeInstance->Handle) {
while ( *Temp == 0x8A) {
ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp ;
//
// Check Address Length
//
if (ptr->AddrLen > 0xffffffff) {
return EFI_INVALID_PARAMETER;
}
//
// Check address range alignment
//
if (ptr->AddrRangeMax >= 0xffffffff || ptr->AddrRangeMax != (GetPowerOfTwo64 (ptr->AddrRangeMax + 1) - 1)) {
return EFI_INVALID_PARAMETER;
}
switch (ptr->ResType) {
case 0:
//
// Check invalid Address Sapce Granularity
//
if (ptr->AddrSpaceGranularity != 32) {
return EFI_INVALID_PARAMETER;
}
//
// check the memory resource request is supported by PCI root bridge
//
if (RootBridgeInstance->RootBridgeAttrib == EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM &&
ptr->SpecificFlag == 0x06) {
return EFI_INVALID_PARAMETER;
}
AddrLen = ptr->AddrLen;
Alignment = ptr->AddrRangeMax;
if (ptr->AddrSpaceGranularity == 32) {
if (ptr->SpecificFlag == 0x06) {
//
// Apply from GCD
//
RootBridgeInstance->ResAllocNode[TypePMem32].Status = ResSubmitted;
} else {
RootBridgeInstance->ResAllocNode[TypeMem32].Length = AddrLen;
RootBridgeInstance->ResAllocNode[TypeMem32].Alignment = Alignment;
RootBridgeInstance->ResAllocNode[TypeMem32].Status = ResRequested;
HostBridgeInstance->ResourceSubmited = TRUE;
}
}
if (ptr->AddrSpaceGranularity == 64) {
if (ptr->SpecificFlag == 0x06) {
RootBridgeInstance->ResAllocNode[TypePMem64].Status = ResSubmitted;
} else {
RootBridgeInstance->ResAllocNode[TypeMem64].Status = ResSubmitted;
}
}
break;
case 1:
AddrLen = (UINTN)ptr->AddrLen;
Alignment = (UINTN)ptr->AddrRangeMax;
RootBridgeInstance->ResAllocNode[TypeIo].Length = AddrLen;
RootBridgeInstance->ResAllocNode[TypeIo].Alignment = Alignment;
RootBridgeInstance->ResAllocNode[TypeIo].Status = ResRequested;
HostBridgeInstance->ResourceSubmited = TRUE;
break;
default:
break;
};
Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) ;
}
return EFI_SUCCESS;
}
List = List->ForwardLink;
}
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
EFIAPI
GetProposedResources(
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN EFI_HANDLE RootBridgeHandle,
OUT VOID **Configuration
)
/*++
Routine Description:
This function returns the proposed resource settings for the specified
PCI Root Bridge
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
RootBridgeHandle -- The PCI Root Bridge handle
Configuration -- The pointer to the pointer to the PCI I/O
and memory resource descriptor
Returns:
--*/
{
LIST_ENTRY *List;
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
UINTN Index;
UINTN Number;
VOID *Buffer;
UINT8 *Temp;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr;
UINT64 ResStatus;
Buffer = NULL;
Number = 0;
//
// Get the Host Bridge Instance from the resource allocation protocol
//
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
List = HostBridgeInstance->Head.ForwardLink;
//
// Enumerate the root bridges in this host bridge
//
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
if (RootBridgeHandle == RootBridgeInstance->Handle) {
for (Index = 0; Index < TypeBus; Index ++) {
if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) {
Number ++;
}
}
if (Number == 0) {
return EFI_INVALID_PARAMETER;
}
Buffer = AllocateZeroPool (Number * sizeof(EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof(EFI_ACPI_END_TAG_DESCRIPTOR));
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Temp = Buffer;
for (Index = 0; Index < TypeBus; Index ++) {
if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) {
ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp ;
ResStatus = RootBridgeInstance->ResAllocNode[Index].Status;
switch (Index) {
case TypeIo:
//
// Io
//
ptr->Desc = 0x8A;
ptr->Len = 0x2B;
ptr->ResType = 1;
ptr->GenFlag = 0;
ptr->SpecificFlag = 0;
ptr->AddrRangeMin = RootBridgeInstance->ResAllocNode[Index].Base;
ptr->AddrRangeMax = 0;
ptr->AddrTranslationOffset = \
(ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS;
ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
break;
case TypeMem32:
//
// Memory 32
//
ptr->Desc = 0x8A;
ptr->Len = 0x2B;
ptr->ResType = 0;
ptr->GenFlag = 0;
ptr->SpecificFlag = 0;
ptr->AddrSpaceGranularity = 32;
ptr->AddrRangeMin = RootBridgeInstance->ResAllocNode[Index].Base;
ptr->AddrRangeMax = 0;
ptr->AddrTranslationOffset = \
(ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS;
ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
break;
case TypePMem32:
//
// Prefetch memory 32
//
ptr->Desc = 0x8A;
ptr->Len = 0x2B;
ptr->ResType = 0;
ptr->GenFlag = 0;
ptr->SpecificFlag = 6;
ptr->AddrSpaceGranularity = 32;
ptr->AddrRangeMin = 0;
ptr->AddrRangeMax = 0;
ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
ptr->AddrLen = 0;
break;
case TypeMem64:
//
// Memory 64
//
ptr->Desc = 0x8A;
ptr->Len = 0x2B;
ptr->ResType = 0;
ptr->GenFlag = 0;
ptr->SpecificFlag = 0;
ptr->AddrSpaceGranularity = 64;
ptr->AddrRangeMin = 0;
ptr->AddrRangeMax = 0;
ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
ptr->AddrLen = 0;
break;
case TypePMem64:
//
// Prefetch memory 64
//
ptr->Desc = 0x8A;
ptr->Len = 0x2B;
ptr->ResType = 0;
ptr->GenFlag = 0;
ptr->SpecificFlag = 6;
ptr->AddrSpaceGranularity = 64;
ptr->AddrRangeMin = 0;
ptr->AddrRangeMax = 0;
ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
ptr->AddrLen = 0;
break;
};
Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
}
}
((EFI_ACPI_END_TAG_DESCRIPTOR *)Temp)->Desc = 0x79;
((EFI_ACPI_END_TAG_DESCRIPTOR *)Temp)->Checksum = 0x0;
*Configuration = Buffer;
return EFI_SUCCESS;
}
List = List->ForwardLink;
}
return EFI_INVALID_PARAMETER;
}
STATIC
VOID
UpdateRootBridgeAttributes (
IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge,
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress
)
{
EFI_STATUS Status;
PCI_TYPE01 PciConfigurationHeader;
UINT64 Attributes;
//
// Read the PCI Configuration Header for the device
//
Status = RootBridge->Io.Pci.Read (
&RootBridge->Io,
EfiPciWidthUint16,
EFI_PCI_ADDRESS(
PciAddress.Bus,
PciAddress.Device,
PciAddress.Function,
0
),
sizeof (PciConfigurationHeader) / sizeof (UINT16),
&PciConfigurationHeader
);
if (EFI_ERROR (Status)) {
return;
}
Attributes = RootBridge->Attributes;
//
// Look for devices with the VGA Palette Snoop enabled in the COMMAND register of the PCI Config Header
//
if (PciConfigurationHeader.Hdr.Command & 0x20) {
Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
}
//
// If the device is a PCI-PCI Bridge, then look at the Subordinate Bus Number
//
if (IS_PCI_BRIDGE(&PciConfigurationHeader)) {
//
// Look at the PPB Configuration for legacy decoding attributes
//
if (PciConfigurationHeader.Bridge.BridgeControl & 0x04) {
Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
}
if (PciConfigurationHeader.Bridge.BridgeControl & 0x08) {
Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
}
} else {
//
// See if the PCI device is an IDE controller
//
if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x01 &&
PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) {
if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x80) {
Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
}
if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x01) {
Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
}
if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x04) {
Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
}
}
//
// See if the PCI device is a legacy VGA controller
//
if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x00 &&
PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) {
Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
}
//
// See if the PCI device is a standard VGA controller
//
if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x03 &&
PciConfigurationHeader.Hdr.ClassCode[1] == 0x00 ) {
Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
}
}
RootBridge->Attributes = Attributes;
RootBridge->Supports = Attributes;
}
EFI_STATUS
EFIAPI
PreprocessController (
IN struct _EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
IN EFI_HANDLE RootBridgeHandle,
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
)
/*++
Routine Description:
This function is called for all the PCI controllers that the PCI
bus driver finds. Can be used to Preprogram the controller.
Arguments:
This -- The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
RootBridgeHandle -- The PCI Root Bridge handle
PciBusAddress -- Address of the controller on the PCI bus
Phase -- The Phase during resource allocation
Returns:
EFI_SUCCESS
--*/
{
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
LIST_ENTRY *List;
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
List = HostBridgeInstance->Head.ForwardLink;
//
// Enumerate the root bridges in this host bridge
//
while (List != &HostBridgeInstance->Head) {
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
if (RootBridgeHandle == RootBridgeInstance->Handle) {
UpdateRootBridgeAttributes (
RootBridgeInstance,
PciAddress
);
return EFI_SUCCESS;
}
List = List->ForwardLink;
}
return EFI_INVALID_PARAMETER;
}