audk/UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLibAcpiBoardI...

230 lines
7.0 KiB
C

/** @file
PCI Segment Information Library that returns one segment whose
segment base address is retrieved from AcpiBoardInfo HOB.
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2024, Rivos Inc. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiDxe.h>
#include <Guid/AcpiBoardInfoGuid.h>
#include <Library/HobLib.h>
#include <Library/PciSegmentInfoLib.h>
#include <Library/DebugLib.h>
#include <UniversalPayload/PciRootBridges.h>
#include <Library/PciLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Library/BaseMemoryLib.h>
#include <Guid/PciSegmentInfoGuid.h>
static PCI_SEGMENT_INFO *mPciSegments;
static UINTN mCount;
/**
Find segment info from all root bridges
@param[in] PciRootBridgeInfo Pointer of Universal Payload PCI Root Bridge Info Hob
@param[in] UplSegmentInfo Pointer of Universal UPL Segment Info
@param[out] NumberOfRootBridges Number of root bridges detected
**/
VOID
RetrieveMultiSegmentInfoFromHob (
IN UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo,
IN UPL_PCI_SEGMENT_INFO_HOB *UplSegmentInfo,
OUT UINTN *NumberOfRootBridges
)
{
UINTN Size;
UINT8 Index;
if (PciRootBridgeInfo == NULL) {
mPciSegments = NULL;
return;
}
*NumberOfRootBridges = PciRootBridgeInfo->Count;
Size = PciRootBridgeInfo->Count * sizeof (PCI_SEGMENT_INFO);
mPciSegments = (PCI_SEGMENT_INFO *)AllocatePool (Size);
ASSERT (mPciSegments != NULL);
ZeroMem (mPciSegments, PciRootBridgeInfo->Count * sizeof (PCI_SEGMENT_INFO));
//
// Create all root bridges with PciRootBridgeInfoHob
//
for (Index = 0; Index < PciRootBridgeInfo->Count; Index++) {
if (UplSegmentInfo->SegmentInfo[Index].SegmentNumber == (UINT16)(PciRootBridgeInfo->RootBridge[Index].Segment)) {
mPciSegments[Index].BaseAddress = UplSegmentInfo->SegmentInfo[Index].BaseAddress;
}
mPciSegments[Index].SegmentNumber = (UINT16)(PciRootBridgeInfo->RootBridge[Index].Segment);
mPciSegments[Index].StartBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[Index].Bus.Base;
mPciSegments[Index].EndBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[Index].Bus.Limit;
}
return;
}
/**
Find segment info from all root bridges for legacy systems
@param[in] PciRootBridgeInfo Pointer of Universal Payload PCI Root Bridge Info Hob
@param[out] NumberOfRootBridges Number of root bridges detected
**/
VOID
RetrieveSegmentInfoFromHob (
OUT UINTN *NumberOfRootBridges
)
{
EFI_HOB_GUID_TYPE *GuidHob;
ACPI_BOARD_INFO *AcpiBoardInfo;
*NumberOfRootBridges = 1;
// old model relies on gUefiAcpiBoardInfoGuid and hardcoded values for single segment only.
// This is only for backward compatibility, new platforms should adopt new model even in single segment cases.
//
mPciSegments = (PCI_SEGMENT_INFO *)AllocatePool (sizeof (PCI_SEGMENT_INFO));
ASSERT (mPciSegments != NULL);
GuidHob = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);
ASSERT (GuidHob != NULL);
if (GuidHob != NULL) {
AcpiBoardInfo = (ACPI_BOARD_INFO *)GET_GUID_HOB_DATA (GuidHob);
mPciSegments->SegmentNumber = 0;
mPciSegments->BaseAddress = AcpiBoardInfo->PcieBaseAddress;
mPciSegments->StartBusNumber = 0;
mPciSegments->EndBusNumber = 0xFF;
}
}
/**
Return info for all root bridges
@return All the root bridge info instances in an array.
**/
UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *
Get_RBInfo (
VOID
)
{
UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo;
EFI_HOB_GUID_TYPE *GuidHob;
UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;
//
// Find Universal Payload PCI Root Bridge Info hob
//
GuidHob = GetFirstGuidHob (&gUniversalPayloadPciRootBridgeInfoGuid);
if ((GuidHob == NULL) || (sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob))) {
return NULL;
}
GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);
if (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob)) {
return NULL;
}
if ((GenericHeader->Revision != UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION) || (GenericHeader->Length < sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES))) {
return NULL;
}
//
// UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES structure is used when Revision equals to UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION
//
PciRootBridgeInfo = (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *)GET_GUID_HOB_DATA (GuidHob);
if (PciRootBridgeInfo->Count <= (GET_GUID_HOB_DATA_SIZE (GuidHob) - sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES)) / sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE)) {
return PciRootBridgeInfo;
}
return NULL;
}
/**
Return info for all root bridge segments
@return All the segment info instances in an array.
**/
UPL_PCI_SEGMENT_INFO_HOB *
Get_UPLSegInfo (
VOID
)
{
UPL_PCI_SEGMENT_INFO_HOB *UplSegmentInfo;
EFI_HOB_GUID_TYPE *GuidHob;
UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;
//
// Find Universal Payload Segment Info hob
//
GuidHob = GetFirstGuidHob (&gUplPciSegmentInfoHobGuid);
if ((GuidHob == NULL) || (sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob))) {
return NULL;
}
GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);
if (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob)) {
return NULL;
}
if ((GenericHeader->Revision != UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION) || (GenericHeader->Length < sizeof (UPL_PCI_SEGMENT_INFO_HOB))) {
return NULL;
}
//
// UPL_PCI_SEGMENT_INFO_HOB structure is used when Revision equals to UPL_PCI_SEGMENT_INFO_HOB_REVISION
//
UplSegmentInfo = (UPL_PCI_SEGMENT_INFO_HOB *)GET_GUID_HOB_DATA (GuidHob);
if (UplSegmentInfo->Count <= (GET_GUID_HOB_DATA_SIZE (GuidHob) - sizeof (UPL_PCI_SEGMENT_INFO_HOB)) / sizeof (UPL_SEGMENT_INFO)) {
return UplSegmentInfo;
}
return NULL;
}
/**
Return all the root bridge instances in an array.
@param Count Return the count of root bridge instances.
@return All the root bridge instances in an array.
The array should be passed into PciHostBridgeFreeRootBridges()
when it's not used.
**/
PCI_SEGMENT_INFO *
EFIAPI
GetPciSegmentInfo (
UINTN *Count
)
{
UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo;
UPL_PCI_SEGMENT_INFO_HOB *UplSegmentInfo;
if (mPciSegments != NULL) {
*Count = mCount;
return mPciSegments;
}
UplSegmentInfo = Get_UPLSegInfo ();
if (UplSegmentInfo == NULL) {
RetrieveSegmentInfoFromHob (Count);
} else {
PciRootBridgeInfo = Get_RBInfo ();
if (PciRootBridgeInfo == NULL) {
return 0;
}
RetrieveMultiSegmentInfoFromHob (PciRootBridgeInfo, UplSegmentInfo, Count);
}
mCount = *Count;
return mPciSegments;
}