mirror of https://github.com/acidanthera/audk.git
1404 lines
50 KiB
C
1404 lines
50 KiB
C
/** @file
|
|
Pci Host Bridge driver for a simple IIO. There is only one PCI Root Bridge in the system.
|
|
Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
|
|
|
|
Copyright (c) 2013-2015 Intel Corporation.
|
|
|
|
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"
|
|
#include <IntelQNCRegs.h>
|
|
|
|
//
|
|
// We can hardcode the following for a Simple IIO -
|
|
// Root Bridge Count within the host bridge
|
|
// Root Bridge's device path
|
|
// Root Bridge's resource appeture
|
|
//
|
|
EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[ROOT_BRIDGE_COUNT] = {
|
|
{
|
|
{
|
|
{
|
|
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
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
EFI_HANDLE mDriverImageHandle;
|
|
PCI_ROOT_BRIDGE_RESOURCE_APERTURE *mResAperture;
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InitializePciHostBridge (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Entry point of this driver.
|
|
|
|
Arguments:
|
|
|
|
ImageHandle - Image handle of this driver.
|
|
SystemTable - Pointer to standard EFI system table.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_DEVICE_ERROR - Fail to install PCI_ROOT_BRIDGE_IO protocol.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN TotalRootBridgeFound;
|
|
PCI_HOST_BRIDGE_INSTANCE *HostBridge;
|
|
PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
|
|
UINT64 AllocAttributes;
|
|
EFI_PHYSICAL_ADDRESS BaseAddress;
|
|
|
|
PrivateData = NULL;
|
|
|
|
mDriverImageHandle = ImageHandle;
|
|
|
|
//
|
|
// Most systems in the world including complex servers
|
|
// have only one Host Bridge. Create Host Bridge Device Handle
|
|
//
|
|
Status = gBS->AllocatePool(EfiBootServicesData, sizeof(PCI_HOST_BRIDGE_INSTANCE), (VOID **) &HostBridge);
|
|
ASSERT_EFI_ERROR (Status);
|
|
ZeroMem (HostBridge, sizeof (PCI_HOST_BRIDGE_INSTANCE));
|
|
|
|
HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE;
|
|
HostBridge->RootBridgeCount = 1;
|
|
HostBridge->ResourceSubmited = FALSE;
|
|
HostBridge->CanRestarted = TRUE;
|
|
//
|
|
// InitializeListHead (&HostBridge->Head);
|
|
//
|
|
HostBridge->ResAlloc.NotifyPhase = NotifyPhase;
|
|
HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;
|
|
HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;
|
|
HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;
|
|
HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;
|
|
HostBridge->ResAlloc.SubmitResources = SubmitResources;
|
|
HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
|
|
HostBridge->ResAlloc.PreprocessController = PreprocessController;
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&HostBridge->HostBridgeHandle,
|
|
&gEfiPciHostBridgeResourceAllocationProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&HostBridge->ResAlloc
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (HostBridge);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = gBS->AllocatePool (EfiBootServicesData,
|
|
HostBridge->RootBridgeCount * sizeof(PCI_ROOT_BRIDGE_RESOURCE_APERTURE),
|
|
(VOID **) &mResAperture);
|
|
ASSERT_EFI_ERROR (Status);
|
|
ZeroMem (mResAperture, HostBridge->RootBridgeCount * sizeof(PCI_ROOT_BRIDGE_RESOURCE_APERTURE));
|
|
|
|
DEBUG ((EFI_D_INFO, "Address of resource Aperture: %x\n", mResAperture));
|
|
|
|
//
|
|
// Create Root Bridge Device Handle in this Host Bridge
|
|
//
|
|
InitializeListHead (&HostBridge->Head);
|
|
|
|
TotalRootBridgeFound = 0;
|
|
|
|
Status = gBS->AllocatePool ( EfiBootServicesData,sizeof (PCI_ROOT_BRIDGE_INSTANCE), (VOID **) &PrivateData);
|
|
ASSERT_EFI_ERROR (Status);
|
|
ZeroMem (PrivateData, sizeof (PCI_ROOT_BRIDGE_INSTANCE));
|
|
|
|
PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
|
|
PrivateData->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &mEfiPciRootBridgeDevicePath[TotalRootBridgeFound];
|
|
AllocAttributes = GetAllocAttributes (TotalRootBridgeFound);
|
|
|
|
SimpleIioRootBridgeConstructor (
|
|
&PrivateData->Io,
|
|
HostBridge->HostBridgeHandle,
|
|
&(mResAperture[TotalRootBridgeFound]),
|
|
AllocAttributes
|
|
);
|
|
//
|
|
// Update Root Bridge with UDS resource information
|
|
//
|
|
PrivateData->Aperture.BusBase = QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE;
|
|
PrivateData->Aperture.BusLimit = QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT;
|
|
PrivateData->Aperture.Mem32Base = PcdGet32 (PcdPciHostBridgeMemory32Base);
|
|
PrivateData->Aperture.Mem32Limit = PcdGet32 (PcdPciHostBridgeMemory32Base) + (PcdGet32 (PcdPciHostBridgeMemory32Size) - 1);
|
|
PrivateData->Aperture.IoBase = PcdGet16 (PcdPciHostBridgeIoBase);
|
|
PrivateData->Aperture.IoLimit = PcdGet16 (PcdPciHostBridgeIoBase) + (PcdGet16 (PcdPciHostBridgeIoSize) - 1);
|
|
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge BusBase: %x\n", QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE));
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge BusLimit: %x\n", QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT));
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem32Base: %x\n", PcdGet32 (PcdPciHostBridgeMemory32Base)));
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem32Limit: %x\n", PcdGet32 (PcdPciHostBridgeMemory32Base) + (PcdGet32 (PcdPciHostBridgeMemory32Size) - 1)));
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem64Base: %lX\n", PcdGet64 (PcdPciHostBridgeMemory64Base)));
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceMem64Limit: %lX\n", PcdGet64 (PcdPciHostBridgeMemory64Base) + (PcdGet64 (PcdPciHostBridgeMemory64Size) - 1)));
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceIoBase: %x\n", PcdGet16 (PcdPciHostBridgeIoBase)));
|
|
DEBUG ((EFI_D_INFO, "PCI Host Bridge PciResourceIoLimit: %x\n", PcdGet16 (PcdPciHostBridgeIoBase) + (PcdGet16 (PcdPciHostBridgeIoSize) - 1)));
|
|
|
|
PrivateData->Handle = NULL;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&PrivateData->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
PrivateData->DevicePath,
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
&PrivateData->Io,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
InsertTailList (&HostBridge->Head, &PrivateData->Link);
|
|
TotalRootBridgeFound++; // This is a valid rootbridge so imcrement total root bridges found
|
|
|
|
//
|
|
// Add PCIE base into Runtime memory so that it can be reported in E820 table
|
|
//
|
|
Status = gDS->AddMemorySpace (
|
|
EfiGcdMemoryTypeMemoryMappedIo,
|
|
PcdGet64 (PcdPciExpressBaseAddress),
|
|
PcdGet64 (PcdPciExpressSize),
|
|
EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
|
|
);
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
BaseAddress = PcdGet64 (PcdPciExpressBaseAddress);
|
|
|
|
Status = gDS->AllocateMemorySpace (
|
|
EfiGcdAllocateAddress,
|
|
EfiGcdMemoryTypeMemoryMappedIo,
|
|
0,
|
|
PcdGet64 (PcdPciExpressSize),
|
|
&BaseAddress,
|
|
ImageHandle,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
Status = gDS->SetMemorySpaceAttributes (
|
|
PcdGet64 (PcdPciExpressBaseAddress),
|
|
PcdGet64 (PcdPciExpressSize),
|
|
EFI_MEMORY_RUNTIME
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (PcdGet16 (PcdPciHostBridgeIoSize) > 0) {
|
|
//
|
|
// At present, we use up the first 4k for fixed ranges like
|
|
// ICH GPIO, ACPI and ISA devices. The first 4k is not
|
|
// tracked through GCD. It should be.
|
|
//
|
|
Status = gDS->AddIoSpace (
|
|
EfiGcdIoTypeIo,
|
|
PcdGet16(PcdPciHostBridgeIoBase),
|
|
PcdGet16(PcdPciHostBridgeIoSize)
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
if (PcdGet32(PcdPciHostBridgeMemory32Size) > 0) {
|
|
//
|
|
// Shouldn't the capabilities be UC?
|
|
//
|
|
Status = gDS->AddMemorySpace (
|
|
EfiGcdMemoryTypeMemoryMappedIo,
|
|
PcdGet32(PcdPciHostBridgeMemory32Base),
|
|
PcdGet32(PcdPciHostBridgeMemory32Size),
|
|
0
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
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:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_INVALID_PARAMETER - Wrong phase parameter passed in.
|
|
EFI_NOT_READY - Resources have not been submitted yet.
|
|
|
|
--*/
|
|
{
|
|
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
|
|
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
|
|
PCI_RESOURCE_TYPE Index;
|
|
EFI_LIST_ENTRY *List;
|
|
EFI_PHYSICAL_ADDRESS BaseAddress;
|
|
UINT64 AddrLen;
|
|
UINTN BitsOfAlignment;
|
|
UINT64 Alignment;
|
|
EFI_STATUS Status;
|
|
EFI_STATUS ReturnStatus;
|
|
PCI_RESOURCE_TYPE Index1;
|
|
PCI_RESOURCE_TYPE Index2;
|
|
BOOLEAN ResNodeHandled[TypeMax];
|
|
UINT64 MaxAlignment;
|
|
|
|
HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
|
|
|
|
switch (Phase) {
|
|
case EfiPciHostBridgeBeginEnumeration:
|
|
if (HostBridgeInstance->CanRestarted) {
|
|
//
|
|
// Reset 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;
|
|
} // for
|
|
|
|
List = List->ForwardLink;
|
|
} // while
|
|
|
|
HostBridgeInstance->ResourceSubmited = FALSE;
|
|
HostBridgeInstance->CanRestarted = TRUE;
|
|
} else {
|
|
//
|
|
// Can not restart
|
|
//
|
|
return EFI_NOT_READY;
|
|
} // if
|
|
break;
|
|
|
|
case EfiPciHostBridgeEndEnumeration:
|
|
return EFI_SUCCESS;
|
|
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) {
|
|
List = HostBridgeInstance->Head.ForwardLink;
|
|
while (List != &HostBridgeInstance->Head) {
|
|
for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {
|
|
ResNodeHandled[Index1] = FALSE;
|
|
}
|
|
|
|
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
|
|
DEBUG ((EFI_D_INFO, "Address of RootBridgeInstance: %x)\n", RootBridgeInstance));
|
|
DEBUG ((EFI_D_INFO, " Signature: %x\n", RootBridgeInstance->Signature));
|
|
DEBUG ((EFI_D_INFO, " Bus Number Assigned: %x\n", RootBridgeInstance->BusNumberAssigned));
|
|
DEBUG ((EFI_D_INFO, " Bus Scan Count: %x\n", RootBridgeInstance->BusScanCount));
|
|
|
|
for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {
|
|
if (RootBridgeInstance->ResAllocNode[Index1].Status == ResNone) {
|
|
ResNodeHandled[Index1] = TRUE;
|
|
} else {
|
|
//
|
|
// Allocate the resource node with max alignment at first
|
|
//
|
|
MaxAlignment = 0;
|
|
Index = TypeMax;
|
|
for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {
|
|
if (ResNodeHandled[Index2]) {
|
|
continue;
|
|
}
|
|
if (MaxAlignment <= RootBridgeInstance->ResAllocNode[Index2].Alignment) {
|
|
MaxAlignment = RootBridgeInstance->ResAllocNode[Index2].Alignment;
|
|
Index = Index2;
|
|
}
|
|
} // for
|
|
|
|
if (Index < TypeMax) {
|
|
ResNodeHandled[Index] = TRUE;
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
Alignment = RootBridgeInstance->ResAllocNode[Index].Alignment;
|
|
|
|
//
|
|
// Get the number of '1' in Alignment.
|
|
//
|
|
for (BitsOfAlignment = 0; Alignment != 0; BitsOfAlignment++) {
|
|
Alignment = RShiftU64 (Alignment, 1);
|
|
}
|
|
|
|
AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
|
|
Alignment = RootBridgeInstance->ResAllocNode[Index].Alignment;
|
|
|
|
DEBUG ((EFI_D_INFO, "\n\nResource Type to assign : %x\n", Index));
|
|
DEBUG ((EFI_D_INFO, " Length to allocate: %x\n", RootBridgeInstance->ResAllocNode[Index].Length));
|
|
DEBUG ((EFI_D_INFO, " Aligment: %x\n", Alignment));
|
|
|
|
switch (Index) {
|
|
case TypeIo:
|
|
if (RootBridgeInstance->Aperture.IoBase < RootBridgeInstance->Aperture.IoLimit) {
|
|
//
|
|
// It is impossible for 0xFFFF Alignment for IO16
|
|
//
|
|
if (BitsOfAlignment >= 16)
|
|
Alignment = 0;
|
|
|
|
BaseAddress = RootBridgeInstance->Aperture.IoBase;
|
|
|
|
//
|
|
// Have to make sure Aligment is handled seeing we are doing direct address allocation
|
|
//
|
|
if ((BaseAddress & ~(Alignment)) != BaseAddress)
|
|
BaseAddress = ((BaseAddress + Alignment) & ~(Alignment));
|
|
|
|
while((BaseAddress + AddrLen) <= RootBridgeInstance->Aperture.IoLimit + 1) {
|
|
|
|
Status = gDS->AllocateIoSpace ( EfiGcdAllocateAddress, EfiGcdIoTypeIo, BitsOfAlignment,
|
|
AddrLen, &BaseAddress, mDriverImageHandle, NULL );
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
RootBridgeInstance->ResAllocNode[Index].Base = (UINT64) BaseAddress;
|
|
RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated;
|
|
goto TypeIoFound;
|
|
}
|
|
|
|
BaseAddress += (Alignment + 1);
|
|
} // while
|
|
|
|
} // if
|
|
|
|
TypeIoFound:
|
|
if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) {
|
|
//
|
|
// No Room at the Inn for this resources request
|
|
//
|
|
ReturnStatus = EFI_OUT_OF_RESOURCES;
|
|
} // if
|
|
|
|
break;
|
|
|
|
case TypeMem32:
|
|
if (RootBridgeInstance->Aperture.Mem32Base < RootBridgeInstance->Aperture.Mem32Limit) {
|
|
|
|
BaseAddress = RootBridgeInstance->Aperture.Mem32Base;
|
|
//
|
|
// Have to make sure Aligment is handled seeing we are doing direct address allocation
|
|
//
|
|
if ((BaseAddress & ~(Alignment)) != BaseAddress)
|
|
BaseAddress = ((BaseAddress + Alignment) & ~(Alignment));
|
|
|
|
while((BaseAddress + AddrLen) <= RootBridgeInstance->Aperture.Mem32Limit + 1) {
|
|
|
|
Status = gDS->AllocateMemorySpace ( EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo,
|
|
BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
RootBridgeInstance->ResAllocNode[Index].Base = (UINT64) BaseAddress;
|
|
RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated;
|
|
goto TypeMem32Found;
|
|
} // if
|
|
|
|
BaseAddress += (Alignment + 1);
|
|
} // while
|
|
} // if
|
|
|
|
TypeMem32Found:
|
|
if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) {
|
|
//
|
|
// No Room at the Inn for this resources request
|
|
//
|
|
ReturnStatus = EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
break;
|
|
|
|
case TypePMem32:
|
|
StartTypePMem32:
|
|
if (RootBridgeInstance->Aperture.Mem32Base < RootBridgeInstance->Aperture.Mem32Limit) {
|
|
|
|
BaseAddress = RootBridgeInstance->Aperture.Mem32Limit + 1;
|
|
BaseAddress -= AddrLen;
|
|
|
|
//
|
|
// Have to make sure Aligment is handled seeing we are doing direct address allocation
|
|
//
|
|
if ((BaseAddress & ~(Alignment)) != BaseAddress)
|
|
BaseAddress = ((BaseAddress) & ~(Alignment));
|
|
|
|
while(RootBridgeInstance->Aperture.Mem32Base <= BaseAddress) {
|
|
|
|
DEBUG ((EFI_D_INFO, " Attempting %x allocation at 0x%lx .....", Index, BaseAddress));
|
|
Status = gDS->AllocateMemorySpace ( EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo,
|
|
BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
RootBridgeInstance->ResAllocNode[Index].Base = (UINT64) BaseAddress;
|
|
RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated;
|
|
DEBUG ((EFI_D_INFO, "... Passed!!\n"));
|
|
goto TypePMem32Found;
|
|
}
|
|
DEBUG ((EFI_D_INFO, "... Failed!!\n"));
|
|
BaseAddress -= (Alignment + 1);
|
|
} // while
|
|
} // if
|
|
|
|
TypePMem32Found:
|
|
if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) {
|
|
//
|
|
// No Room at the Inn for this resources request
|
|
//
|
|
ReturnStatus = EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
break;
|
|
|
|
case TypeMem64:
|
|
case TypePMem64:
|
|
if (RootBridgeInstance->ResAllocNode[Index].Status != ResAllocated) {
|
|
//
|
|
// If 64-bit resourcing is not available, then try as PMem32
|
|
//
|
|
goto StartTypePMem32;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} // End switch (Index)
|
|
|
|
DEBUG ((EFI_D_INFO, "Resource Type Assigned: %x\n", Index));
|
|
if (RootBridgeInstance->ResAllocNode[Index].Status == ResAllocated) {
|
|
DEBUG ((EFI_D_INFO, " Base Address Assigned: %x\n", RootBridgeInstance->ResAllocNode[Index].Base));
|
|
DEBUG ((EFI_D_INFO, " Length Assigned: %x\n", RootBridgeInstance->ResAllocNode[Index].Length));
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, " Resource Allocation failed! There was no room at the inn\n"));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
List = List->ForwardLink;
|
|
}
|
|
|
|
if (ReturnStatus == EFI_OUT_OF_RESOURCES) {
|
|
DEBUG ((DEBUG_ERROR, "Resource allocation Failed. Continue booting the system.\n"));
|
|
}
|
|
|
|
//
|
|
// Set resource to zero for nodes where allocation fails
|
|
//
|
|
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) {
|
|
RootBridgeInstance->ResAllocNode[Index].Length = 0;
|
|
}
|
|
}
|
|
List = List->ForwardLink;
|
|
}
|
|
return ReturnStatus;
|
|
} else {
|
|
return EFI_NOT_READY;
|
|
}
|
|
//
|
|
// HostBridgeInstance->CanRestarted = FALSE;
|
|
//
|
|
break;
|
|
|
|
case EfiPciHostBridgeSetResources:
|
|
//
|
|
// HostBridgeInstance->CanRestarted = FALSE;
|
|
//
|
|
break;
|
|
|
|
case EfiPciHostBridgeFreeResources:
|
|
//
|
|
// HostBridgeInstance->CanRestarted = FALSE;
|
|
//
|
|
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 = (EFI_PHYSICAL_ADDRESS) 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:
|
|
Status = gDS->FreeMemorySpace (BaseAddress, AddrLen);
|
|
if (EFI_ERROR (Status)) {
|
|
ReturnStatus = Status;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} // end switch (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;
|
|
return ReturnStatus;
|
|
break;
|
|
|
|
case EfiPciHostBridgeEndResourceAllocation:
|
|
//
|
|
// Resource enumeration is done. Perform any activities that
|
|
// must wait until that time.
|
|
//
|
|
break;
|
|
|
|
default:
|
|
return EFI_INVALID_PARAMETER;
|
|
} // End switch (Phase)
|
|
|
|
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:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_NOT_FOUND - Next PCI root bridge not found.
|
|
EFI_INVALID_PARAMETER - Wrong parameter passed in.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN NoRootBridge;
|
|
EFI_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.
|
|
Attributes - The pointer to attributes of the PCI Root Bridge.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_INVALID_PARAMETER - Attributes parameter passed in is NULL or
|
|
RootBridgeHandle is not an EFI_HANDLE
|
|
that was returned on a previous call to
|
|
GetNextRootBridge().
|
|
|
|
--*/
|
|
{
|
|
EFI_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->RootBridgeAllocAttrib;
|
|
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:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_OUT_OF_RESOURCES - Not enough pool to be allocated.
|
|
EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
|
|
|
|
--*/
|
|
{
|
|
EFI_LIST_ENTRY *List;
|
|
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
|
|
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
|
|
VOID *Buffer;
|
|
UINT8 *Temp;
|
|
EFI_STATUS Status;
|
|
UINTN BusStart;
|
|
UINTN BusEnd;
|
|
UINT64 BusReserve;
|
|
|
|
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->Aperture.BusBase;
|
|
BusEnd = RootBridgeInstance->Aperture.BusLimit;
|
|
BusReserve = RootBridgeInstance->Aperture.BusReserve;
|
|
//
|
|
// Program the Hardware(if needed) if error return EFI_DEVICE_ERROR
|
|
//
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
|
|
&Buffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Temp = (UINT8 *) Buffer;
|
|
|
|
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
|
|
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Len = 0x2B;
|
|
((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
|
|
((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 = BusReserve;
|
|
((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 = ACPI_END_TAG_DESCRIPTOR;
|
|
((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:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_INVALID_PARAMETER - Wrong parameters passed in.
|
|
|
|
--*/
|
|
{
|
|
EFI_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 != ACPI_ADDRESS_SPACE_TYPE_BUS) {
|
|
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->Aperture.BusBase) || (BusEnd > RootBridgeInstance->Aperture.BusLimit)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Update the Bus Range
|
|
//
|
|
RootBridgeInstance->ResAllocNode[TypeBus].Base = BusStart;
|
|
RootBridgeInstance->ResAllocNode[TypeBus].Length = BusLen;
|
|
RootBridgeInstance->ResAllocNode[TypeBus].Status = ResAllocated;
|
|
RootBridgeInstance->BusScanCount++;
|
|
if (RootBridgeInstance->BusScanCount > 0) {
|
|
//
|
|
// Only care about the 2nd PCI bus scanning
|
|
//
|
|
RootBridgeInstance->BusNumberAssigned = TRUE;
|
|
}
|
|
|
|
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:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_INVALID_PARAMETER - Wrong parameters passed in.
|
|
|
|
--*/
|
|
{
|
|
EFI_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;
|
|
UINT64 Value;
|
|
|
|
//
|
|
// 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 (List != &HostBridgeInstance->Head) {
|
|
RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
|
|
if (RootBridgeHandle == RootBridgeInstance->Handle) {
|
|
//
|
|
// Check the resource descriptors.
|
|
// If the Configuration includes one or more invalid resource descriptors, all the resource
|
|
// descriptors are ignored and the function returns EFI_INVALID_PARAMETER.
|
|
//
|
|
while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
|
|
ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
|
|
DEBUG ((EFI_D_INFO, " ptr->ResType:%x \n",ptr->ResType));
|
|
DEBUG ((EFI_D_INFO, " ptr->AddrLen:0x%lx AddrRangeMin:0x%lx AddrRangeMax:0x%lx\n\n",ptr->AddrLen,ptr->AddrRangeMin,ptr->AddrRangeMax));
|
|
|
|
switch (ptr->ResType) {
|
|
case ACPI_ADDRESS_SPACE_TYPE_MEM:
|
|
if (ptr->AddrSpaceGranularity != 32 && ptr->AddrSpaceGranularity != 64) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (ptr->AddrSpaceGranularity == 32 && ptr->AddrLen > 0xffffffff) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// If the PCI root bridge does not support separate windows for nonprefetchable and
|
|
// prefetchable memory, then the PCI bus driver needs to include requests for
|
|
// prefetchable memory in the nonprefetchable memory pool.
|
|
//
|
|
if ((RootBridgeInstance->RootBridgeAllocAttrib & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 &&
|
|
((ptr->SpecificFlag & (BIT2 | BIT1)) != 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
case ACPI_ADDRESS_SPACE_TYPE_IO:
|
|
//
|
|
// Check aligment, it should be of the form 2^n-1
|
|
//
|
|
Value = Power2MaxMemory (ptr->AddrRangeMax + 1);
|
|
if (Value != (ptr->AddrRangeMax + 1)) {
|
|
CpuDeadLoop();
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
case ACPI_ADDRESS_SPACE_TYPE_BUS:
|
|
default:
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) ;
|
|
}
|
|
if (*Temp != ACPI_END_TAG_DESCRIPTOR) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Temp = (UINT8 *) Configuration;
|
|
while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
|
|
ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
|
|
|
|
switch (ptr->ResType) {
|
|
case ACPI_ADDRESS_SPACE_TYPE_MEM:
|
|
AddrLen = (UINT64) ptr->AddrLen;
|
|
Alignment = (UINT64) 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].Length = AddrLen;
|
|
RootBridgeInstance->ResAllocNode[TypeMem64].Alignment = Alignment;
|
|
RootBridgeInstance->ResAllocNode[TypeMem64].Status = ResSubmitted;
|
|
HostBridgeInstance->ResourceSubmited = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ACPI_ADDRESS_SPACE_TYPE_IO:
|
|
AddrLen = (UINT64) ptr->AddrLen;
|
|
Alignment = (UINT64) 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:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_OUT_OF_RESOURCES - Not enough pool to be allocated.
|
|
EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
|
|
|
|
--*/
|
|
{
|
|
EFI_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;
|
|
EFI_STATUS Status;
|
|
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) {
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
|
|
&Buffer
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ZeroMem (Buffer, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Number + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
|
|
}
|
|
|
|
ASSERT (Buffer != NULL);
|
|
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 = 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 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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PreprocessController (
|
|
IN 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.
|
|
PciAddress - Address of the controller on the PCI bus.
|
|
Phase - The Phase during resource allocation.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Succeed.
|
|
EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN RootBridgeFound;
|
|
EFI_LIST_ENTRY *List;
|
|
PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
|
|
PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
|
|
|
|
if (RootBridgeHandle == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
RootBridgeFound = FALSE;
|
|
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) {
|
|
RootBridgeFound = TRUE;
|
|
break;
|
|
}
|
|
//
|
|
// Get next if have
|
|
//
|
|
List = List->ForwardLink;
|
|
}
|
|
|
|
if (RootBridgeFound == FALSE) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
UINT64
|
|
Power2MaxMemory (
|
|
IN UINT64 MemoryLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calculate maximum memory length that can be fit to a mtrr.
|
|
|
|
Arguments:
|
|
|
|
MemoryLength - Input memory length.
|
|
|
|
Returns:
|
|
|
|
Returned Maximum length.
|
|
|
|
--*/
|
|
{
|
|
UINT64 Result;
|
|
|
|
if (RShiftU64 (MemoryLength, 32)) {
|
|
Result = LShiftU64 ((UINT64) GetPowerOfTwo64 ((UINT32) RShiftU64 (MemoryLength, 32)), 32);
|
|
} else {
|
|
Result = (UINT64) GetPowerOfTwo64 ((UINT32) MemoryLength);
|
|
}
|
|
|
|
return Result;
|
|
}
|