/** @file
This file contains PSF routines for RC usage
Copyright (c) 2021, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "PsfLibInternal.h"
#include
/**
Get PSF SideBand Port ID from PSF ID (1 - PSF1, 2 - PSF2, ...)
@param[in] PsfId PSF ID (1 - PSF1, 2 - PSF2, ...)
@retval PSF SideBand Port ID
**/
PCH_SBI_PID
PsfSbPortId (
UINT32 PsfId
)
{
UINT32 PsfTableIndex;
PSF_SEGMENT *PsfTable;
UINT32 PsfTableSize;
PsfSegments (&PsfTable, &PsfTableSize);
for (PsfTableIndex = 0; PsfTableIndex < PsfTableSize; PsfTableIndex++) {
if (PsfTable[PsfTableIndex].Id == PsfId) {
return PsfTable[PsfTableIndex].SbPid;
}
}
ASSERT (FALSE);
return 0;
}
/**
Get PCH Root PSF ID. This is the PSF segment to which OPDMI/DMI is connected.
@retval PsfId Root PSF ID
**/
UINT32
PsfRootId (
VOID
)
{
PSF_SEGMENT *PsfTable;
UINT32 PsfTableSize;
PsfSegments (&PsfTable, &PsfTableSize);
return PsfTable[0].Id;
}
/**
Add EOI Target in a given PSF
@param[in] PsfId PSF ID (1 - PSF1, 2 - PSF2, ...)
@param[in] TargetId EOI Target ID
**/
STATIC
VOID
PsfAddEoiTarget (
UINT32 PsfId,
PSF_PORT_DEST_ID TargetId
)
{
UINT16 EoiTargetBase;
UINT16 EoiControlBase;
UINT8 NumOfEnabledTargets;
UINT8 MaximalNumberOfTargets;
PCH_SBI_PID PsfSbiPortId;
UINT32 Data32;
UINT8 TargetIndex;
MaximalNumberOfTargets = PsfEoiRegData (PsfId, &EoiTargetBase, &EoiControlBase);
PsfSbiPortId = PsfSbPortId (PsfId);
//
// Get number of enabled agents from PSF_x_PSF_MC_CONTROL_MCAST0_RS0_EOI register
//
Data32 = PchPcrRead32 (PsfSbiPortId, EoiControlBase);
NumOfEnabledTargets = (UINT8) (Data32 >> N_PCH_PSFX_PCR_MC_CONTROL_MCASTX_NUMMC);
//
// Check if target was not already enabled
// Targets from a different PSF segment are aggregated into single destination on
// current PSF segment.
//
for (TargetIndex = 0; TargetIndex < NumOfEnabledTargets; TargetIndex++) {
Data32 = PchPcrRead32 (PsfSbiPortId, EoiTargetBase + TargetIndex * 4);
//
// If target already added don't add it again
//
if (Data32 == TargetId.RegVal) {
ASSERT (FALSE);
return;
}
//
// If target is from different PSF segment than currently being analyzed
// it is enough that its PsfID is matching
//
if ((Data32 & B_PCH_PSFX_PCR_TARGET_PSFID) >> N_PCH_PSFX_PCR_TARGET_PSFID == TargetId.Fields.PsfId) {
return;
}
}
//
// Check if next one can be added
//
if (NumOfEnabledTargets >= MaximalNumberOfTargets) {
ASSERT (FALSE);
return;
}
//
// Add next target
// Configure Multicast Destination ID register with target device on PSF.
// Configuration must be done in next available PSF_MC_AGENT_MCAST0_RS0_TGT_EOI register
// so that other targets are not overridden. is known from the number of multicast agents
// in Multicast Control Register. Value programmed is based on
// PsfID, PortGroupID, PortID and ChannelID of the target
//
PchPcrWrite32 (PsfSbiPortId, EoiTargetBase + NumOfEnabledTargets * 4, TargetId.RegVal);
//
// Enable new target
// Configure PSF_x_PSF_MC_CONTROL_MCAST0_RS0_EOI, increase NumMc and set MultCEn
//
NumOfEnabledTargets++;
Data32 = (NumOfEnabledTargets << N_PCH_PSFX_PCR_MC_CONTROL_MCASTX_NUMMC) | B_PCH_PSFX_PCR_MC_CONTROL_MCASTX_MULTCEN;
PchPcrWrite32 (PsfSbiPortId, EoiControlBase, Data32);
}
/**
Enable EOI Target
@param[in] TargetId Target ID
**/
STATIC
VOID
PsfEnableEoiTarget (
PSF_PORT_DEST_ID TargetId
)
{
UINT32 RootLevelPsf;
RootLevelPsf = PsfRootId ();
//
// Enable EOI target in root PSF
//
PsfAddEoiTarget (RootLevelPsf, TargetId);
//
// Enable EOI target on other PSF segment if target
// is not located on root PSF
//
if (TargetId.Fields.PsfId != RootLevelPsf) {
PsfAddEoiTarget (TargetId.Fields.PsfId, TargetId);
}
}
/**
This function enables EOI message forwarding in PSF for PCIe ports
for cases where IOAPIC is present behind this root port.
@param[in] RpIndex Root port index (0 based)
@retval Status
**/
EFI_STATUS
PsfConfigurEoiForPciePort (
IN UINT32 RpIndex
)
{
ASSERT (RpIndex < GetPchMaxPciePortNum ());
//
// If there is an IOAPIC discovered behind root port program PSF Multicast registers
// accordingly to CNL PCH BWG PSF EOI Multicast Configuration
// Since there is a device behind RootPort to which EOI needs to be forwarded
// enable multicast (MULTCEN) and increase the number of multicast agents (NUMMC)
// in Multicast Control Register.
//
PsfEnableEoiTarget (PsfPcieDestinationId (RpIndex));
return EFI_SUCCESS;
}