mirror of https://github.com/acidanthera/audk.git
283 lines
9.6 KiB
C
283 lines
9.6 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 IndexForExistingSegments;
|
|
UINT8 NumberOfExistingSegments;
|
|
UINT8 IndexForRb;
|
|
PCI_SEGMENT_INFO *pPciSegments;
|
|
|
|
if (PciRootBridgeInfo == NULL) {
|
|
mPciSegments = NULL;
|
|
return;
|
|
}
|
|
|
|
IndexForExistingSegments = 0;
|
|
NumberOfExistingSegments = 0;
|
|
IndexForRb = 0;
|
|
Size = PciRootBridgeInfo->Count * sizeof (PCI_SEGMENT_INFO);
|
|
|
|
*NumberOfRootBridges = PciRootBridgeInfo->Count;
|
|
|
|
pPciSegments = (PCI_SEGMENT_INFO *)AllocatePool (Size);
|
|
if (pPciSegments == NULL) {
|
|
ASSERT (pPciSegments != NULL);
|
|
return;
|
|
}
|
|
|
|
ZeroMem (pPciSegments, PciRootBridgeInfo->Count * sizeof (PCI_SEGMENT_INFO));
|
|
|
|
//
|
|
// RBs may share the same Segment number, but mPciSegments should not have duplicate segment data.
|
|
// 1. if RB Segment is same with existing one, update StartBus and EndBus of existing one
|
|
// 2. if RB Segment is different from all existing ones, add it to the existing Segments data buffer.
|
|
// pPciSegments is local temporary data buffer that will be freed later (size depends on numbers of RB)
|
|
// mPciSegments is global data that will be updated with the pPciSegments for caller to utilize. (size depends on numbers of different PciSegments)
|
|
//
|
|
NumberOfExistingSegments = 1;
|
|
pPciSegments[0].BaseAddress = UplSegmentInfo->SegmentInfo[0].BaseAddress;
|
|
pPciSegments[0].SegmentNumber = (UINT16)(PciRootBridgeInfo->RootBridge[0].Segment);
|
|
pPciSegments[0].StartBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[0].Bus.Base;
|
|
pPciSegments[0].EndBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[0].Bus.Limit;
|
|
for (IndexForRb = 1; IndexForRb < PciRootBridgeInfo->Count; IndexForRb++) {
|
|
for (IndexForExistingSegments = 0; IndexForExistingSegments < NumberOfExistingSegments; IndexForExistingSegments++) {
|
|
if (pPciSegments[IndexForExistingSegments].SegmentNumber == PciRootBridgeInfo->RootBridge[IndexForRb].Segment) {
|
|
if (pPciSegments[IndexForExistingSegments].StartBusNumber > PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Base) {
|
|
pPciSegments[IndexForExistingSegments].StartBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Base;
|
|
}
|
|
|
|
if (pPciSegments[IndexForExistingSegments].EndBusNumber < PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Limit) {
|
|
pPciSegments[IndexForExistingSegments].EndBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Limit;
|
|
}
|
|
|
|
break; // breaking after a match found
|
|
}
|
|
}
|
|
|
|
if (IndexForExistingSegments >= NumberOfExistingSegments) {
|
|
//
|
|
// No match found, add it to segments data buffer
|
|
//
|
|
pPciSegments[NumberOfExistingSegments].BaseAddress = UplSegmentInfo->SegmentInfo[IndexForRb].BaseAddress;
|
|
pPciSegments[NumberOfExistingSegments].SegmentNumber = (UINT16)(PciRootBridgeInfo->RootBridge[IndexForRb].Segment);
|
|
pPciSegments[NumberOfExistingSegments].StartBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Base;
|
|
pPciSegments[NumberOfExistingSegments].EndBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Limit;
|
|
NumberOfExistingSegments++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prepare data for returning to caller
|
|
//
|
|
*NumberOfRootBridges = NumberOfExistingSegments;
|
|
Size = NumberOfExistingSegments * sizeof (PCI_SEGMENT_INFO);
|
|
mPciSegments = (PCI_SEGMENT_INFO *)AllocatePool (Size);
|
|
if (mPciSegments == NULL) {
|
|
ASSERT (FALSE);
|
|
return;
|
|
}
|
|
|
|
CopyMem (&mPciSegments[0], &pPciSegments[0], Size);
|
|
if (pPciSegments != NULL) {
|
|
FreePool (pPciSegments);
|
|
}
|
|
|
|
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;
|
|
}
|