503 lines
16 KiB
C
503 lines
16 KiB
C
/** @file
|
|
Program silicon SVID and SSID.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2019 - 2021 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
|
|
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
|
|
the terms of your license agreement with Intel or your vendor. This file may
|
|
be modified by the user, subject to additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/ConfigBlockLib.h>
|
|
#include <Library/PcieHelperLib.h>
|
|
#include <Library/PeiSiSsidLib.h>
|
|
#include <Ppi/SiPolicy.h>
|
|
#include <PcieRegs.h>
|
|
#include <TcssDataHob.h>
|
|
#include <Library/HobLib.h>
|
|
|
|
STATIC SVID_SID_SKIP_TABLE mPcieSsidTable[] = {{0, 1, 0},
|
|
{0, 1, 1},
|
|
{0, 26, 0},
|
|
{0, 26, 1},
|
|
{0, 26, 2},
|
|
{0, 26, 3},
|
|
{0, 27, 0},
|
|
{0, 27, 1},
|
|
{0, 27, 2},
|
|
{0, 27, 3},
|
|
{0, 27, 4},
|
|
{0, 27, 5},
|
|
{0, 27, 6},
|
|
{0, 27, 7},
|
|
{0, 28, 0},
|
|
{0, 28, 1},
|
|
{0, 28, 2},
|
|
{0, 28, 3},
|
|
{0, 28, 4},
|
|
{0, 28, 5},
|
|
{0, 28, 6},
|
|
{0, 28, 7},
|
|
{0, 29, 0},
|
|
{0, 29, 1},
|
|
{0, 29, 2},
|
|
{0, 29, 3},
|
|
{0, 29, 4},
|
|
{0, 29, 5},
|
|
{0, 29, 6},
|
|
{0, 29, 7},
|
|
};
|
|
|
|
/**
|
|
Get SVID offset for PCI DEV FUNC.
|
|
|
|
@param[in] PciCfgBase Pci base address
|
|
|
|
@retval SVID offset
|
|
**/
|
|
STATIC
|
|
UINT16
|
|
GetSvidOffset (
|
|
UINT64 PciCfgBase
|
|
)
|
|
{
|
|
UINT8 HeaderType;
|
|
UINT8 CapList;
|
|
|
|
HeaderType = PciSegmentRead8 (PciCfgBase + PCI_HEADER_TYPE_OFFSET);
|
|
|
|
if ((HeaderType & HEADER_TYPE_CARDBUS_BRIDGE) != 0) {
|
|
return R_PCI_CARDBUS_BRIDGE_SVID;
|
|
} else if ((HeaderType & HEADER_TYPE_PCI_TO_PCI_BRIDGE) != 0) {
|
|
//
|
|
// If header type is PCI-to-PCI bridge, but device has SUBSYSTEM_VENDOR capability, it means it
|
|
// has SSID/SVID regs on offset SVCAP + 0x04.
|
|
// If capability does not exist, return 0 to skip programming that device.
|
|
//
|
|
CapList = PcieBaseFindCapId (PciCfgBase, PCI_CAP_ID_SUBSYSTEM_VENDOR);
|
|
if (CapList != 0) {
|
|
return CapList + R_PCIE_SUBSYSTEM_VENDOR_ID_OFFSET;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return PCI_SVID_OFFSET;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Override default SVID and SSID
|
|
|
|
@param[in] PciDevNum Pci device number
|
|
@param[in] PciFuncNum Pci function number
|
|
@param[in] SsidTablePtr Ssid policy table
|
|
@param[in] NumberOfSsidTableEntry Side of Ssid policy table
|
|
@param[in,out] Svid Svid value
|
|
@param[in,out] Ssid Ssid value
|
|
**/
|
|
STATIC
|
|
VOID
|
|
OverrideSvidSsidValue (
|
|
UINT32 PciDevNum,
|
|
UINT32 PciFuncNum,
|
|
SVID_SID_INIT_ENTRY *SsidTablePtr,
|
|
UINT16 NumberOfSsidTableEntry,
|
|
UINT16 *Svid,
|
|
UINT16 *Ssid
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
if (SsidTablePtr != NULL) {
|
|
for (Index = 0; Index < NumberOfSsidTableEntry; Index++) {
|
|
if ((SsidTablePtr[Index].Address.Bits.Device == PciDevNum) &&
|
|
(SsidTablePtr[Index].Address.Bits.Function == PciFuncNum))
|
|
{
|
|
*Svid = SsidTablePtr[Index].SvidSidValue.SubSystemVendorId;
|
|
*Ssid = SsidTablePtr[Index].SvidSidValue.SubSystemId;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Skip specific PCI devices program SSID before the device ready
|
|
|
|
@param[in] SsidSkipTablePtr SSID policy skip table
|
|
@param[in] NumberOfSsidSkipTableEntry Side of SSID policy skip table
|
|
@param[in] PciDevNum PCI device number
|
|
@param[in] PciFuncNum PCI function number
|
|
|
|
@retval TRUE skip program the SSID
|
|
@retval FALSE doesn't skip program the SSID
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
SkipSsidFunc (
|
|
IN SVID_SID_SKIP_TABLE *SsidSkipTablePtr,
|
|
IN UINT16 NumberOfSsidSkipTableEntry,
|
|
IN UINT32 PciDevNum,
|
|
IN UINT32 PciFuncNum
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
if (SsidSkipTablePtr != NULL) {
|
|
for (Index = 0; Index < NumberOfSsidSkipTableEntry; Index++) {
|
|
if ((PciDevNum == SsidSkipTablePtr[Index].SkipDevice) &&
|
|
(PciFuncNum == SsidSkipTablePtr[Index].SkipFunction)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Program devices Subsystem Vendor Identifier (SVID) and Subsystem Identifier (SID).
|
|
|
|
@param[in] SiPolicy The SI Policy PPI instance
|
|
@param[in] SiSsidOverrideFunc Silicon SSID override function
|
|
**/
|
|
VOID
|
|
SiProgramSsid (
|
|
IN SI_POLICY_PPI *SiPolicy,
|
|
IN SI_SSID_OVERRIDE_FUNC SiSsidOverrideFunc
|
|
)
|
|
{
|
|
UINT16 NumberOfSsidTableEntry;
|
|
SVID_SID_INIT_ENTRY *SsidTablePtr;
|
|
EFI_STATUS Status;
|
|
SI_CONFIG *SiConfig;
|
|
UINT16 CommonSvid;
|
|
UINT16 CommonSsid;
|
|
UINT16 DataSvid;
|
|
UINT16 DataSsid;
|
|
UINT32 PciDevNum;
|
|
UINT32 PciFuncNum;
|
|
UINT64 PciCfgBase;
|
|
UINT16 SvidOffset;
|
|
BOOLEAN IsMultiFunc;
|
|
UINT16 NumberOfTcssSsidTable;
|
|
SVID_SID_SKIP_TABLE *SsidSkipTablePtr;
|
|
TCSS_DATA_SSID_HOB *TcssSsidHob;
|
|
UINT16 NumberOfPcieSsidTable;
|
|
SVID_SID_SKIP_TABLE *PcieSsidSkipTablePtr;
|
|
|
|
CommonSvid = DEFAULT_SSVID;
|
|
CommonSsid = DEFAULT_SSDID;
|
|
SsidTablePtr = NULL;
|
|
NumberOfSsidTableEntry = 0;
|
|
SsidSkipTablePtr = NULL;
|
|
NumberOfTcssSsidTable = 0;
|
|
|
|
if (SiPolicy != NULL) {
|
|
Status = GetConfigBlock ((VOID *) SiPolicy, &gSiConfigGuid, (VOID *) &SiConfig);
|
|
if (!EFI_ERROR (Status) && (SiConfig != NULL)) {
|
|
if (SiConfig->SkipSsidProgramming) {
|
|
//
|
|
// Skip all SSID programming
|
|
//
|
|
return;
|
|
}
|
|
if (SiConfig->CustomizedSvid != 0) {
|
|
CommonSvid = SiConfig->CustomizedSvid;
|
|
}
|
|
if (SiConfig->CustomizedSsid != 0) {
|
|
CommonSsid = SiConfig->CustomizedSsid;
|
|
}
|
|
//
|
|
// Use SiPolicy Table and table counts
|
|
//
|
|
SsidTablePtr = (SVID_SID_INIT_ENTRY*) SiConfig->SsidTablePtr;
|
|
NumberOfSsidTableEntry = SiConfig->NumberOfSsidTableEntry;
|
|
ASSERT (NumberOfSsidTableEntry < SI_MAX_DEVICE_COUNT);
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Get Tcss SSID data Hob
|
|
///
|
|
TcssSsidHob = NULL;
|
|
TcssSsidHob = (TCSS_DATA_SSID_HOB *) GetFirstGuidHob (&gTcssSsidHobGuid);
|
|
if (TcssSsidHob != NULL) {
|
|
SsidSkipTablePtr = (SVID_SID_SKIP_TABLE*) TcssSsidHob->TcssSsidTable;
|
|
NumberOfTcssSsidTable = TcssSsidHob->NumberOfTcssSsidTable;
|
|
ASSERT (NumberOfTcssSsidTable < SI_MAX_DEVICE_COUNT);
|
|
}
|
|
|
|
PcieSsidSkipTablePtr = mPcieSsidTable;
|
|
NumberOfPcieSsidTable = sizeof (mPcieSsidTable) / sizeof (mPcieSsidTable[0]);
|
|
//
|
|
// Silicon code will scan all devices in BUS 0 and program SSID.
|
|
//
|
|
for (PciDevNum = 0; PciDevNum <= PCI_MAX_DEVICE; PciDevNum++) {
|
|
IsMultiFunc = FALSE;
|
|
for (PciFuncNum = 0; PciFuncNum <= PCI_MAX_FUNC; PciFuncNum++) {
|
|
//
|
|
// Skip high function if not multple function controller
|
|
//
|
|
if ((PciFuncNum > 0) && !IsMultiFunc) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get SVID offset
|
|
//
|
|
PciCfgBase = PCI_SEGMENT_LIB_ADDRESS (0, 0, PciDevNum, PciFuncNum, 0);
|
|
SvidOffset = GetSvidOffset (PciCfgBase);
|
|
|
|
//
|
|
// Skip if the device is not present or does not have SVID register
|
|
//
|
|
if (PciSegmentRead32 (PciCfgBase + PCI_VENDOR_ID_OFFSET) == 0xFFFFFFFF || SvidOffset == 0) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check if it's multiple function controller
|
|
//
|
|
if (PciFuncNum == 0) {
|
|
IsMultiFunc = (PciSegmentRead8 (PciCfgBase + PCI_HEADER_TYPE_OFFSET) & HEADER_TYPE_MULTI_FUNCTION) != 0;
|
|
}
|
|
|
|
if (SkipSsidFunc (SsidSkipTablePtr, NumberOfTcssSsidTable, PciDevNum, PciFuncNum) == TRUE) {
|
|
continue;
|
|
}
|
|
|
|
if (SkipSsidFunc (PcieSsidSkipTablePtr, NumberOfPcieSsidTable, PciDevNum, PciFuncNum) == TRUE) {
|
|
continue;
|
|
}
|
|
//
|
|
// Get SVID SSID value
|
|
//
|
|
DataSvid = CommonSvid;
|
|
DataSsid = CommonSsid;
|
|
|
|
if ((SiSsidOverrideFunc == NULL) ||
|
|
!SiSsidOverrideFunc (PciDevNum, PciFuncNum, &DataSvid, &DataSsid))
|
|
{
|
|
OverrideSvidSsidValue (PciDevNum, PciFuncNum, SsidTablePtr, NumberOfSsidTableEntry, &DataSvid, &DataSsid);
|
|
}
|
|
|
|
//
|
|
// Register programming
|
|
//
|
|
PciSegmentWrite32 (PciCfgBase + SvidOffset, (DataSsid << 16) | DataSvid);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Program TCSS Subsystem Vendor Identifier (SVID) and Subsystem Identifier (SID).
|
|
|
|
@param[in] SiPolicy The SI Policy PPI instance
|
|
@param[in] TcssSsidTablePtr Tcss SSID policy table
|
|
@param[in] NumberOfTcssTable The number of SSID Items
|
|
**/
|
|
VOID
|
|
SiTcssProgramSsid (
|
|
IN SI_POLICY_PPI *SiPolicy,
|
|
IN SVID_SID_SKIP_TABLE *TcssSsidTablePtr,
|
|
IN UINT16 NumberOfTcssTable
|
|
)
|
|
{
|
|
UINT16 NumberOfSsidTableEntry;
|
|
SVID_SID_INIT_ENTRY *SsidTablePtr;
|
|
EFI_STATUS Status;
|
|
SI_CONFIG *SiConfig;
|
|
UINT16 CommonSvid;
|
|
UINT16 CommonSsid;
|
|
UINT16 DataSvid;
|
|
UINT16 DataSsid;
|
|
UINT32 PciDevNum;
|
|
UINT32 PciFuncNum;
|
|
UINT64 PciCfgBase;
|
|
UINT16 SvidOffset;
|
|
UINT8 Index;
|
|
|
|
CommonSvid = DEFAULT_SSVID;
|
|
CommonSsid = DEFAULT_SSDID;
|
|
SsidTablePtr = NULL;
|
|
NumberOfSsidTableEntry = 0;
|
|
|
|
if ((TcssSsidTablePtr == NULL) || (NumberOfTcssTable == 0)) {
|
|
return;
|
|
}
|
|
|
|
if (SiPolicy != NULL) {
|
|
Status = GetConfigBlock ((VOID *) SiPolicy, &gSiConfigGuid, (VOID *) &SiConfig);
|
|
if (!EFI_ERROR (Status) && (SiConfig != NULL)) {
|
|
if (SiConfig->SkipSsidProgramming) {
|
|
//
|
|
// Skip all SSID programming
|
|
//
|
|
return;
|
|
}
|
|
if (SiConfig->CustomizedSvid != 0) {
|
|
CommonSvid = SiConfig->CustomizedSvid;
|
|
}
|
|
if (SiConfig->CustomizedSsid != 0) {
|
|
CommonSsid = SiConfig->CustomizedSsid;
|
|
}
|
|
//
|
|
// Use SiPolicy Table and table counts
|
|
//
|
|
SsidTablePtr = (SVID_SID_INIT_ENTRY*) SiConfig->SsidTablePtr;
|
|
NumberOfSsidTableEntry = SiConfig->NumberOfSsidTableEntry;
|
|
ASSERT (NumberOfSsidTableEntry < SI_MAX_DEVICE_COUNT);
|
|
}
|
|
}
|
|
|
|
for (Index = 0; Index < NumberOfTcssTable; Index++) {
|
|
PciDevNum = TcssSsidTablePtr[Index].SkipDevice;
|
|
PciFuncNum = TcssSsidTablePtr[Index].SkipFunction;
|
|
|
|
//
|
|
// Skip if the device is not present
|
|
//
|
|
PciCfgBase = PCI_SEGMENT_LIB_ADDRESS (0, 0, PciDevNum, PciFuncNum, 0);
|
|
if (PciSegmentRead32 (PciCfgBase + PCI_VENDOR_ID_OFFSET) == 0xFFFFFFFF) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get SVID offset
|
|
//
|
|
SvidOffset = GetSvidOffset (PciCfgBase);
|
|
|
|
//
|
|
// Get SVID SSID value
|
|
//
|
|
DataSvid = CommonSvid;
|
|
DataSsid = CommonSsid;
|
|
|
|
OverrideSvidSsidValue (PciDevNum, PciFuncNum, SsidTablePtr, NumberOfSsidTableEntry, &DataSvid, &DataSsid);
|
|
|
|
//
|
|
// Register programming
|
|
//
|
|
PciSegmentWrite32 (PciCfgBase + SvidOffset, (DataSsid << 16) | DataSvid);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Program Pcie Subsystem Vendor Identifier (SVID) and Subsystem Identifier (SID).
|
|
|
|
@param[in] SiPolicy The SI Policy PPI instance
|
|
**/
|
|
VOID
|
|
SiPcieProgramSsid (
|
|
IN SI_POLICY_PPI *SiPolicy
|
|
)
|
|
{
|
|
UINT16 NumberOfSsidTableEntry;
|
|
SVID_SID_INIT_ENTRY *SsidTablePtr;
|
|
EFI_STATUS Status;
|
|
SI_CONFIG *SiConfig;
|
|
UINT16 CommonSvid;
|
|
UINT16 CommonSsid;
|
|
UINT16 DataSvid;
|
|
UINT16 DataSsid;
|
|
UINT32 PciDevNum;
|
|
UINT32 PciFuncNum;
|
|
UINT64 PciCfgBase;
|
|
UINT16 SvidOffset;
|
|
UINT8 Index;
|
|
SVID_SID_SKIP_TABLE *PcieSsidTablePtr;
|
|
UINT16 NumberOfPcieTable;
|
|
|
|
CommonSvid = DEFAULT_SSVID;
|
|
CommonSsid = DEFAULT_SSDID;
|
|
SsidTablePtr = NULL;
|
|
NumberOfSsidTableEntry = 0;
|
|
|
|
PcieSsidTablePtr = mPcieSsidTable;
|
|
NumberOfPcieTable = sizeof (mPcieSsidTable) / sizeof (mPcieSsidTable[0]);
|
|
|
|
if ((PcieSsidTablePtr == NULL) || (NumberOfPcieTable == 0)) {
|
|
return;
|
|
}
|
|
|
|
if (SiPolicy != NULL) {
|
|
Status = GetConfigBlock ((VOID *) SiPolicy, &gSiConfigGuid, (VOID *) &SiConfig);
|
|
if (!EFI_ERROR (Status) && (SiConfig != NULL)) {
|
|
if (SiConfig->SkipSsidProgramming) {
|
|
//
|
|
// Skip all SSID programming
|
|
//
|
|
return;
|
|
}
|
|
if (SiConfig->CustomizedSvid != 0) {
|
|
CommonSvid = SiConfig->CustomizedSvid;
|
|
}
|
|
if (SiConfig->CustomizedSsid != 0) {
|
|
CommonSsid = SiConfig->CustomizedSsid;
|
|
}
|
|
//
|
|
// Use SiPolicy Table and table counts
|
|
//
|
|
SsidTablePtr = (SVID_SID_INIT_ENTRY*) SiConfig->SsidTablePtr;
|
|
NumberOfSsidTableEntry = SiConfig->NumberOfSsidTableEntry;
|
|
ASSERT (NumberOfSsidTableEntry < SI_MAX_DEVICE_COUNT);
|
|
}
|
|
}
|
|
|
|
for (Index = 0; Index < NumberOfPcieTable; Index++) {
|
|
PciDevNum = PcieSsidTablePtr[Index].SkipDevice;
|
|
PciFuncNum = PcieSsidTablePtr[Index].SkipFunction;
|
|
|
|
//
|
|
// Skip if the device is not present
|
|
//
|
|
PciCfgBase = PCI_SEGMENT_LIB_ADDRESS (0, 0, PciDevNum, PciFuncNum, 0);
|
|
if (PciSegmentRead32 (PciCfgBase + PCI_VENDOR_ID_OFFSET) == 0xFFFFFFFF) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get SVID offset
|
|
//
|
|
SvidOffset = GetSvidOffset (PciCfgBase);
|
|
|
|
//
|
|
// Get SVID SSID value
|
|
//
|
|
DataSvid = CommonSvid;
|
|
DataSsid = CommonSsid;
|
|
|
|
OverrideSvidSsidValue (PciDevNum, PciFuncNum, SsidTablePtr, NumberOfSsidTableEntry, &DataSvid, &DataSsid);
|
|
|
|
//
|
|
// Register programming
|
|
//
|
|
PciSegmentWrite32 (PciCfgBase + SvidOffset, (DataSsid << 16) | DataSvid);
|
|
}
|
|
} |