blob: f2dc00bd9a13ebd4f506c2716d25f385a53ee8da [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* AMD CPU Register Table Related Functions
*
* Set registers according to a set of register tables
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: CPU
* @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
*
*/
/*
******************************************************************************
*
* Copyright 2008 - 2012 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
*
* AMD is granting you permission to use this software (the Materials)
* pursuant to the terms and conditions of your Software License Agreement
* with AMD. This header does *NOT* give you permission to use the Materials
* or any rights under AMD's intellectual property. Your use of any portion
* of these Materials shall constitute your acceptance of those terms and
* conditions. If you do not agree to the terms and conditions of the Software
* License Agreement, please do not use any portion of these Materials.
*
* CONFIDENTIALITY: The Materials and all other information, identified as
* confidential and provided to you by AMD shall be kept confidential in
* accordance with the terms and conditions of the Software License Agreement.
*
* LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION
* PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE,
* OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE.
* IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER
* (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS
* INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE,
* GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER
* RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE
* EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES,
* THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
*
* AMD does not assume any responsibility for any errors which may appear in
* the Materials or any other related information provided to you by AMD, or
* result from use of the Materials or any related information.
*
* You agree that you will not reverse engineer or decompile the Materials.
*
* NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any
* further information, software, technical information, know-how, or show-how
* available to you. Additionally, AMD retains the right to modify the
* Materials at any time, without notice, and is not obligated to provide such
* modified Materials to you.
*
* U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with
* "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is
* subject to the restrictions as set forth in FAR 52.227-14 and
* DFAR252.227-7013, et seq., or its successor. Use of the Materials by the
* Government constitutes acknowledgement of AMD's proprietary rights in them.
*
* EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any
* direct product thereof will be exported directly or indirectly, into any
* country prohibited by the United States Export Administration Act and the
* regulations thereunder, without the required authorization from the U.S.
* government nor will be used for any purpose prohibited by the same.
******************************************************************************
*/
/*----------------------------------------------------------------------------------------
* M O D U L E S U S E D
*----------------------------------------------------------------------------------------
*/
#include "AGESA.h"
#include "amdlib.h"
#include "Ids.h"
#include "Topology.h"
#include "OptionMultiSocket.h"
#include "cpuRegisters.h"
#include "cpuFamilyTranslation.h"
#include "Table.h"
#include "GeneralServices.h"
#include "cpuServices.h"
#include "cpuFeatures.h"
#include "CommonReturns.h"
#include "cpuL3Features.h"
#include "Filecode.h"
CODE_GROUP (G1_PEICC)
RDATA_GROUP (G1_PEICC)
#define FILECODE PROC_CPU_TABLEHT_FILECODE
extern OPTION_MULTISOCKET_CONFIGURATION OptionMultiSocketConfiguration;
/*----------------------------------------------------------------------------------------
* D E F I N I T I O N S A N D M A C R O S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* T Y P E D E F S A N D S T R U C T U R E S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* P R O T O T Y P E S O F L O C A L F U N C T I O N S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* E X P O R T E D F U N C T I O N S
*----------------------------------------------------------------------------------------
*/
extern BUILD_OPT_CFG UserOptions;
/*---------------------------------------------------------------------------------------*/
/**
* Program HT Phy PCI registers using BKDG values.
*
* @TableEntryTypeMethod{::HtPhyRegister}.
*
*
* @param[in] Entry The type specific entry data to be implemented (that is written).
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config params for library, services.
*
*/
VOID
SetRegisterForHtPhyEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
PCI_ADDR CapabilitySet;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
BOOLEAN MatchedSublink1;
HT_FREQUENCIES Freq0;
HT_FREQUENCIES Freq1;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT ((Entry->InitialValues[4] == 0) &&
((Entry->HtPhyEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL | HTPHY_LINKTYPE_SL0_AND | HTPHY_LINKTYPE_SL1_AND)) == 0) &&
(Entry->HtPhyEntry.Address < HTPHY_REGISTER_MAX));
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
Link = 0;
while (FamilySpecificServices->NextLinkHasHtPhyFeats (
FamilySpecificServices,
&CapabilitySet,
&Link,
&Entry->HtPhyEntry.TypeFeats,
&MatchedSublink1,
&Freq0,
&Freq1,
StdHeader)) {
FamilySpecificServices->SetHtPhyRegister (FamilySpecificServices, &Entry->HtPhyEntry, CapabilitySet, Link, StdHeader);
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Program a range of HT Phy PCI registers using BKDG values.
*
* @TableEntryTypeMethod{::HtPhyRangeRegister}.
*
*
* @param[in] Entry The type specific entry data to be implemented (that is written).
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config params for library, services.
*
*/
VOID
SetRegisterForHtPhyRangeEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
PCI_ADDR CapabilitySet;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
HT_PHY_TYPE_ENTRY_DATA CurrentHtPhyRegister;
BOOLEAN MatchedSublink1;
HT_FREQUENCIES Freq0;
HT_FREQUENCIES Freq1;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT (((Entry->HtPhyRangeEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL)) == 0) &&
(Entry->HtPhyRangeEntry.LowAddress <= Entry->HtPhyRangeEntry.HighAddress) &&
(Entry->HtPhyRangeEntry.HighAddress < HTPHY_REGISTER_MAX) &&
(Entry->HtPhyRangeEntry.HighAddress != 0));
CurrentHtPhyRegister.Mask = Entry->HtPhyRangeEntry.Mask;
CurrentHtPhyRegister.Data = Entry->HtPhyRangeEntry.Data;
CurrentHtPhyRegister.TypeFeats = Entry->HtPhyRangeEntry.TypeFeats;
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
Link = 0;
while (FamilySpecificServices->NextLinkHasHtPhyFeats (
FamilySpecificServices,
&CapabilitySet,
&Link,
&Entry->HtPhyRangeEntry.TypeFeats,
&MatchedSublink1,
&Freq0,
&Freq1,
StdHeader)) {
for (CurrentHtPhyRegister.Address = Entry->HtPhyRangeEntry.LowAddress;
CurrentHtPhyRegister.Address <= Entry->HtPhyRangeEntry.HighAddress;
CurrentHtPhyRegister.Address++) {
FamilySpecificServices->SetHtPhyRegister (FamilySpecificServices, &CurrentHtPhyRegister, CapabilitySet, Link, StdHeader);
}
}
}
/*----------------------------------------------------------------------------------------*/
/**
* Is PackageLink an Internal Link?
*
* This is a test for the logical link match codes in the user interface, not a test for
* the actual northbridge links.
*
* @param[in] PackageLink The link
*
* @retval TRUE This is an internal link
* @retval FALSE This is not an internal link
*/
BOOLEAN
STATIC
IsDeemphasisLinkInternal (
IN UINT32 PackageLink
)
{
return (BOOLEAN) ((PackageLink <= HT_LIST_MATCH_INTERNAL_LINK_2) && (PackageLink >= HT_LIST_MATCH_INTERNAL_LINK_0));
}
/*----------------------------------------------------------------------------------------*/
/**
* Get the Package Link number, for the current node and real link number.
*
* Based on the link to package link mapping from BKDG, look up package link for
* the input link on the internal node number corresponding to the current core's node.
* For single module processors, the northbridge link and package link are the same.
*
* @param[in] Link the link on the current node.
* @param[in] FamilySpecificServices CPU specific support interface.
* @param[in] StdHeader Config params for library, services.
*
* @return the Package Link, HT_LIST_TERMINAL Not connected in package, HT_LIST_MATCH_INTERNAL_LINK package internal link.
*
*/
UINT32
STATIC
LookupPackageLink (
IN UINT32 Link,
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 PackageLinkMapItem;
UINT32 PackageLink;
AP_MAIL_INFO ApMailbox;
PackageLink = HT_LIST_TERMINAL;
GetApMailbox (&ApMailbox.Info, StdHeader);
if (ApMailbox.Fields.ModuleType != 0) {
ASSERT (FamilySpecificServices->PackageLinkMap != NULL);
// Use table to find this module's package link
PackageLinkMapItem = 0;
while ((*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].Link != HT_LIST_TERMINAL) {
if (((*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].Module == ApMailbox.Fields.Module) &&
((*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].Link == Link)) {
PackageLink = (*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].PackageLink;
break;
}
PackageLinkMapItem++;
}
} else {
PackageLink = Link;
}
return PackageLink;
}
/*---------------------------------------------------------------------------------------*/
/**
* Get the platform's specified deemphasis levels for the current link.
*
* Search the platform's list for a match to the current link and also matching frequency.
* If a match is found, use the specified deemphasis levels.
*
* @param[in] Socket The current Socket.
* @param[in] Link The link on that socket.
* @param[in] Frequency The frequency the link is set to.
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] FamilySpecificServices CPU specific support interface.
* @param[in] StdHeader Config params for library, services.
*
* @return The Deemphasis values for the link.
*/
UINT32
STATIC
GetLinkDeemphasis (
IN UINT32 Socket,
IN UINT32 Link,
IN HT_FREQUENCIES Frequency,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 Result;
CPU_HT_DEEMPHASIS_LEVEL *Match;
UINT32 PackageLink;
PackageLink = LookupPackageLink (Link, FamilySpecificServices, StdHeader);
// All External and Internal links have deemphasis level none as the default.
// However, it is expected that the platform BIOS will provide deemphasis levels for the external links.
Result = ((DCV_LEVEL_NONE) | (DEEMPHASIS_LEVEL_NONE));
if (PlatformConfig->PlatformDeemphasisList != NULL) {
Match = PlatformConfig->PlatformDeemphasisList;
while (Match->Socket != HT_LIST_TERMINAL) {
if (((Match->Socket == Socket) || (Match->Socket == HT_LIST_MATCH_ANY)) &&
((Match->Link == PackageLink) ||
((Match->Link == HT_LIST_MATCH_ANY) && (!IsDeemphasisLinkInternal (PackageLink))) ||
((Match->Link == HT_LIST_MATCH_INTERNAL_LINK) && (IsDeemphasisLinkInternal (PackageLink)))) &&
((Match->LoFreq <= Frequency) && (Match->HighFreq >= Frequency))) {
// Found a match, get the deemphasis value.
ASSERT ((MaxPlatformDeemphasisLevel > Match->DcvDeemphasis) | (MaxPlatformDeemphasisLevel > Match->ReceiverDeemphasis));
Result = ((1 << Match->DcvDeemphasis) | (1 << Match->ReceiverDeemphasis));
break;
} else {
Match++;
}
}
}
return Result;
}
/*---------------------------------------------------------------------------------------*/
/**
* Program Deemphasis registers using BKDG values, for the platform specified levels.
*
* @TableEntryTypeMethod{::DeemphasisRegister}.
*
*
* @param[in] Entry The type specific entry data to be implemented (that is written).
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config params for library, services.
*
*/
VOID
SetRegisterForDeemphasisEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
PCI_ADDR CapabilitySet;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
BOOLEAN MatchedSublink1;
HT_FREQUENCIES Freq0;
HT_FREQUENCIES Freq1;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT (((Entry->DeemphasisEntry.Levels.DeemphasisValues & ~(VALID_DEEMPHASIS_LEVELS)) == 0) &&
((Entry->DeemphasisEntry.HtPhyEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL)) == 0) &&
(Entry->DeemphasisEntry.HtPhyEntry.Address < HTPHY_REGISTER_MAX));
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
Link = 0;
while (FamilySpecificServices->NextLinkHasHtPhyFeats (
FamilySpecificServices,
&CapabilitySet,
&Link,
&Entry->DeemphasisEntry.HtPhyEntry.TypeFeats,
&MatchedSublink1,
&Freq0,
&Freq1,
StdHeader)) {
if (DoesEntryTypeSpecificInfoMatch (
GetLinkDeemphasis (
MySocket,
(MatchedSublink1 ? (Link + 4) : Link),
(MatchedSublink1 ? Freq1 : Freq0),
PlatformConfig,
FamilySpecificServices,
StdHeader),
Entry->DeemphasisEntry.Levels.DeemphasisValues)) {
FamilySpecificServices->SetHtPhyRegister (
FamilySpecificServices,
&Entry->DeemphasisEntry.HtPhyEntry,
CapabilitySet,
Link,
StdHeader
);
IDS_HDT_CONSOLE (HT_TRACE, "Socket %d Module %d Sub-link %1d :\n ----> running on HT3, %s Level is %s\n",
MySocket, MyModule,
((Entry->DeemphasisEntry.HtPhyEntry.TypeFeats.HtPhyLinkValue & HTPHY_LINKTYPE_SL0_ALL) != 0) ? Link : (Link + 4),
((Entry->DeemphasisEntry.Levels.DeemphasisValues & DCV_LEVELS_ALL) != 0) ? "DCV" : "Deemphasis",
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL_NONE) ? " 0 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__3) ? " - 3 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__6) ? " - 6 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__6) ? " - 6 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__8) ? " - 8 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__11) ? " - 11 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__11_8) ? " - 11 dB postcursor with - 8 dB precursor" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL_NONE) ? " 0 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__2) ? " - 2 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__3) ? " - 3 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__5) ? " - 5 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__6) ? " - 6 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__7) ? " - 7 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__8) ? " - 8 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__9) ? " - 9 dB" :
(Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__11) ? " - 11 dB" : "Undefined");
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Program HT Phy PCI registers which have complex frequency dependencies.
*
* @TableEntryTypeMethod{::HtPhyFreqRegister}.
*
* After matching a link for HT Features, check if the HT frequency matches the given range.
* If it does, get the northbridge frequency limits for implemented NB P-states and check if
* each matches the given range - range 0 and range 1 for each NB frequency, respectively.
* If all matches, apply the entry.
*
* @param[in] Entry The type specific entry data to be implemented (that is written).
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config params for library, services.
*
*/
VOID
SetRegisterForHtPhyFreqEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
PCI_ADDR CapabilitySet;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
BOOLEAN MatchedSublink1;
HT_FREQUENCIES Freq0;
HT_FREQUENCIES Freq1;
BOOLEAN Temp1;
BOOLEAN Temp2;
UINT32 NbFreq0;
UINT32 NbFreq1;
UINT32 NbDivisor0;
UINT32 NbDivisor1;
// Errors: extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT (((Entry->HtPhyFreqEntry.HtPhyEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL)) == 0) &&
(Entry->HtPhyFreqEntry.HtPhyEntry.Address < HTPHY_REGISTER_MAX));
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
Link = 0;
while (FamilySpecificServices->NextLinkHasHtPhyFeats (
FamilySpecificServices,
&CapabilitySet,
&Link,
&Entry->HtPhyFreqEntry.HtPhyEntry.TypeFeats,
&MatchedSublink1,
&Freq0,
&Freq1,
StdHeader)) {
// Check the HT Frequency for match to the range.
if (IsEitherCountInRange (
(MatchedSublink1 ? Freq1 : Freq0),
(MatchedSublink1 ? Freq1 : Freq0),
Entry->HtPhyFreqEntry.HtFreqCounts.HtFreqCountRanges)) {
// Get the NB Frequency, convert to 100's of MHz, then convert to equivalent HT encoding. This supports
// NB frequencies from 800 MHz to 2600 MHz, which is currently greater than any processor supports.
OptionMultiSocketConfiguration.GetSystemNbPstateSettings (
(UINT32) 0,
PlatformConfig,
&NbFreq0,
&NbDivisor0,
&Temp1,
&Temp2,
StdHeader);
if (OptionMultiSocketConfiguration.GetSystemNbPstateSettings (
(UINT32) 1,
PlatformConfig,
&NbFreq1,
&NbDivisor1,
&Temp1,
&Temp2,
StdHeader)) {
ASSERT (NbDivisor1 != 0);
NbFreq1 = (NbFreq1 / NbDivisor1);
NbFreq1 = (NbFreq1 / 100);
NbFreq1 = (NbFreq1 / 2) + 1;
} else {
NbFreq1 = 0;
}
ASSERT (NbDivisor0 != 0);
NbFreq0 = (NbFreq0 / NbDivisor0);
NbFreq0 = (NbFreq0 / 100);
NbFreq0 = (NbFreq0 / 2) + 1;
if (IsEitherCountInRange (NbFreq0, NbFreq1, Entry->HtPhyFreqEntry.NbFreqCounts.HtFreqCountRanges)) {
FamilySpecificServices->SetHtPhyRegister (
FamilySpecificServices,
&Entry->HtPhyFreqEntry.HtPhyEntry,
CapabilitySet,
Link,
StdHeader);
}
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Perform the HT Phy Performance Profile Register Entry.
*
* @TableEntryTypeMethod{::HtPhyProfileRegister}.
*
* @param[in] Entry The HT Phy register entry to perform
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config handle for library and services.
*
*/
VOID
SetRegisterForHtPhyProfileEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
PERFORMANCE_PROFILE_FEATS PlatformProfile;
TABLE_ENTRY_DATA HtPhyEntry;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT (((Entry->HtPhyProfileEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0) &&
(Entry->InitialValues[5] == 0));
GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
if (DoesEntryTypeSpecificInfoMatch (
PlatformProfile.PerformanceProfileValue,
Entry->HtPhyProfileEntry.TypeFeats.PerformanceProfileValue)) {
LibAmdMemFill (&HtPhyEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
HtPhyEntry.HtPhyEntry = Entry->HtPhyProfileEntry.HtPhyEntry;
SetRegisterForHtPhyEntry (&HtPhyEntry, PlatformConfig, StdHeader);
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Perform the HT Host PCI Register Entry.
*
* @TableEntryTypeMethod{::HtHostPciRegister}.
*
* Make the current core's PCI address with the function and register for the entry.
* For all HT links, check the link's feature set for a match to the entry.
* Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
*
* @param[in] Entry The PCI register entry to perform
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config handle for library and services.
*
*/
VOID
SetRegisterForHtHostEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINTN Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
PCI_ADDR CapabilitySet;
PCI_ADDR PciAddress;
HT_HOST_FEATS HtHostFeats;
UINT32 RegisterData;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT ((Entry->InitialValues[4] == 0) &&
((Entry->HtHostEntry.TypeFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0) &&
(Entry->HtHostEntry.Address.Address.Register < HT_LINK_HOST_CAP_MAX));
HtHostFeats.HtHostValue = 0;
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
Link = 0;
while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtHostEntry.TypeFeats.HtHostValue)) {
// Do the HT Host PCI register update.
PciAddress = CapabilitySet;
PciAddress.Address.Register += Entry->HtHostEntry.Address.Address.Register;
LibAmdPciRead (AccessWidth32, PciAddress, &RegisterData, StdHeader);
RegisterData = RegisterData & (~(Entry->HtHostEntry.Mask));
RegisterData = RegisterData | Entry->HtHostEntry.Data;
LibAmdPciWrite (AccessWidth32, PciAddress, &RegisterData, StdHeader);
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Perform the HT Host Performance PCI Register Entry.
*
* @TableEntryTypeMethod{::HtHostPerfPciRegister}.
*
* Make the current core's PCI address with the function and register for the entry.
* For all HT links, check the link's feature set for a match to the entry.
* Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
*
* @param[in] Entry The PCI register entry to perform
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config handle for library and services.
*
*/
VOID
SetRegisterForHtHostPerfEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
PERFORMANCE_PROFILE_FEATS PlatformProfile;
TABLE_ENTRY_DATA HtHostPciTypeEntryData;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT ((Entry->InitialValues[5] == 0) &&
((Entry->HtHostEntry.TypeFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0) &&
(Entry->HtHostEntry.Address.Address.Register < HT_LINK_HOST_CAP_MAX));
// Check for any performance profile features.
GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue,
Entry->HtHostPerfEntry.PerformanceFeats.PerformanceProfileValue)) {
// Perform HT Host entry process.
LibAmdMemFill (&HtHostPciTypeEntryData, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
HtHostPciTypeEntryData.HtHostEntry = Entry->HtHostPerfEntry.HtHostEntry;
SetRegisterForHtHostEntry (&HtHostPciTypeEntryData, PlatformConfig, StdHeader);
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Set the HT Link Token Count registers.
*
* @TableEntryTypeMethod{::HtTokenPciRegister}.
*
* Make the current core's PCI address with the function and register for the entry.
* Check the performance profile features.
* For all HT links, check the link's feature set for a match to the entry.
* Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
*
* @param[in] Entry The Link Token register entry to perform
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config handle for library and services.
*
*/
VOID
SetRegisterForHtLinkTokenEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINTN Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
PCI_ADDR CapabilitySet;
HT_HOST_FEATS HtHostFeats;
PERFORMANCE_PROFILE_FEATS PlatformProfile;
UINTN ProcessorCount;
UINTN SystemDegree;
UINT32 RegisterData;
PCI_ADDR PciAddress;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT (((Entry->HtTokenEntry.LinkFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0) &&
((Entry->HtTokenEntry.PerformanceFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0) &&
(Entry->HtTokenEntry.Mask != 0));
HtHostFeats.HtHostValue = 0;
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
// Check if the actual processor count and SystemDegree are in either range.
ProcessorCount = GetNumberOfProcessors (StdHeader);
SystemDegree = GetSystemDegree (StdHeader);
if (IsEitherCountInRange (ProcessorCount, SystemDegree, Entry->HtTokenEntry.ConnectivityCount.ConnectivityCountRanges)) {
// Check for any performance profile features.
GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue,
Entry->HtTokenEntry.PerformanceFeats.PerformanceProfileValue)) {
// Check the link features.
Link = 0;
while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtTokenEntry.LinkFeats.HtHostValue)) {
// Do the HT Host PCI register update. Token register are four registers, sublink 0 and 1 share fields.
// If sublink 0 is unconnected, we should let sublink 1 match. If the links are ganged, of course only sublink 0 matches.
// If the links are unganged and both connected, the BKDG settings are for both coherent.
PciAddress = CapabilitySet;
PciAddress.Address.Register = Entry->HtTokenEntry.Address.Address.Register +
((Link > 3) ? (((UINT32)Link - 4) * 4) : ((UINT32)Link * 4));
PciAddress.Address.Function = Entry->HtTokenEntry.Address.Address.Function;
LibAmdPciRead (AccessWidth32, PciAddress, &RegisterData, StdHeader);
RegisterData = RegisterData & (~(Entry->HtTokenEntry.Mask));
RegisterData = RegisterData | Entry->HtTokenEntry.Data;
LibAmdPciWrite (AccessWidth32, PciAddress, &RegisterData, StdHeader);
}
}
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Perform the Processor Token Counts PCI Register Entry.
*
* @TableEntryTypeMethod{::TokenPciRegister}.
*
* The table criteria then translate as:
* - 2 Socket, half populated == Degree 1
* - 4 Socket, half populated == Degree 2
* - 2 Socket, fully populated == Degree 3
* - 4 Socket, fully populated == Degree > 3. (4 or 5 if 3P, 6 if 4P)
*
* @param[in] Entry The PCI register entry to perform
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config handle for library and services.
*
*/
VOID
SetRegisterForTokenPciEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
PERFORMANCE_PROFILE_FEATS PlatformProfile;
UINTN SystemDegree;
TABLE_ENTRY_DATA PciEntry;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT (((Entry->TokenPciEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->TokenPciEntry.TypeFeats.PerformanceProfileValue)) {
SystemDegree = GetSystemDegree (StdHeader);
// Check if the system degree is in the range.
if (IsEitherCountInRange (SystemDegree, SystemDegree, Entry->TokenPciEntry.ConnectivityCount.ConnectivityCountRanges)) {
LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
PciEntry.PciEntry = Entry->TokenPciEntry.PciEntry;
SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Perform the HT Link Feature PCI Register Entry.
*
* @TableEntryTypeMethod{::HtFeatPciRegister}.
*
* Set a single field (that is, the register field is not in HT Host capability or a
* set of per link registers) in PCI config, based on HT link features and package type.
* This code is used for two cases: single link processors and multilink processors.
* For single link cases, the link will be tested for a match to the HT Features for the link.
* For multilink processors, the entry will match if @b any link is found which matches.
* For example, a setting can be applied based on coherent HT3 by matching coherent AND HT3.
*
* Make the core's PCI address. Check the package type (currently more important to the single link case),
* and if matching, iterate through all links checking for an HT feature match until found or exhausted.
* If a match was found, pass the PCI entry data to the implementer for writing for the current core.
*
* @param[in] Entry The PCI register entry to perform
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config handle for library and services.
*
*/
VOID
SetRegisterForHtFeaturePciEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINTN Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
PCI_ADDR CapabilitySet;
HT_HOST_FEATS HtHostFeats;
UINT32 ProcessorPackageType;
BOOLEAN IsMatch;
TABLE_ENTRY_DATA PciEntry;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT ((Entry->HtFeatPciEntry.PciEntry.Mask != 0) &&
((Entry->HtFeatPciEntry.LinkFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0));
HtHostFeats.HtHostValue = 0;
LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
PciEntry.PciEntry = Entry->HtFeatPciEntry.PciEntry;
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
ASSERT ((Entry->HtFeatPciEntry.PackageType.PackageTypeValue & ~(PACKAGE_TYPE_ALL)) == 0);
ProcessorPackageType = LibAmdGetPackageType (StdHeader);
if (DoesEntryTypeSpecificInfoMatch (ProcessorPackageType, Entry->HtFeatPciEntry.PackageType.PackageTypeValue)) {
IsMatch = FALSE;
while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtFeatPciEntry.LinkFeats.HtHostValue)) {
IsMatch = TRUE;
break;
}
}
if (IsMatch) {
// Do the PCI register update.
SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Perform the HT Link PCI Register Entry.
*
* @TableEntryTypeMethod{::HtLinkPciRegister}.
*
* Make the current core's PCI address with the function and register for the entry.
* Registers are processed for match per link, assuming sequential PCI address per link.
* Read - Modify - Write each matching link's PCI register, clearing masked bits, and setting the data bits.
*
* @param[in] Entry The PCI register entry to perform
* @param[in] PlatformConfig Config handle for platform specific information
* @param[in] StdHeader Config handle for library and services.
*
*/
VOID
SetRegisterForHtLinkPciEntry (
IN TABLE_ENTRY_DATA *Entry,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINTN Link;
UINT32 MySocket;
UINT32 MyModule;
AGESA_STATUS IgnoredStatus;
UINT32 Ignored;
CPU_LOGICAL_ID CpuFamilyRevision;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
PCI_ADDR CapabilitySet;
HT_HOST_FEATS HtHostFeats;
TABLE_ENTRY_DATA PciEntry;
// Errors: Possible values in unused entry space, extra type features, value range checks.
// Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
ASSERT ((Entry->HtLinkPciEntry.PciEntry.Mask != 0) &&
((Entry->HtLinkPciEntry.LinkFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0));
HtHostFeats.HtHostValue = 0;
LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
PciEntry.PciEntry = Entry->HtLinkPciEntry.PciEntry;
IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);
Link = 0;
while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtLinkPciEntry.LinkFeats.HtHostValue)) {
// Do the update to the link's non-Host PCI register, based on the entry address.
PciEntry.PciEntry.Address = Entry->HtLinkPciEntry.PciEntry.Address;
PciEntry.PciEntry.Address.Address.Register = PciEntry.PciEntry.Address.Address.Register + ((UINT32)Link * 4);
SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
}
}
}