/* $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: 38402 $ @e \$Date: 2010-09-24 02:11:44 +0800 (Fri, 24 Sep 2010) $ * */ /* ***************************************************************************** * * Copyright (c) 2011, Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Advanced Micro Devices, Inc. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * *************************************************************************** * */ /*---------------------------------------------------------------------------------------- * 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 "Filecode.h" CODE_GROUP (G1_PEICC) RDATA_GROUP (G1_PEICC) #define FILECODE PROC_CPU_TABLE_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 *---------------------------------------------------------------------------------------- */ VOID SetRegistersFromTablesAtEarly ( IN CPU_SPECIFIC_SERVICES *FamilyServices, IN AMD_CPU_EARLY_PARAMS *EarlyParams, IN AMD_CONFIG_PARAMS *StdHeader ); /*---------------------------------------------------------------------------------------- * E X P O R T E D F U N C T I O N S *---------------------------------------------------------------------------------------- */ extern BUILD_OPT_CFG UserOptions; /*---------------------------------------------------------------------------------------*/ /** * An iterator for all the Family and Model Register Tables. * * RegisterTableHandle should be set to NULL to begin iteration, the first time the method is * invoked. Register tables can be processed, until this method returns NULL. RegisterTableHandle * should simply be passed back to the method without modification or use by the caller. * The table selector allows the relevant tables for different cores to be iterated, if the family separates * tables. For example, MSRs can be in a table processed by all cores and PCI registers in a table processed by * primary cores. * * @param[in] FamilySpecificServices The current Family Specific Services. * @param[in] Selector Select whether to iterate over tables for either all cores, primary cores, bsp, .... * @param[in,out] RegisterTableHandle IN: The handle of the current register table, or NULL if Begin. * OUT: The handle of the next register table, if not End. * @param[out] NumberOfEntries The number of entries in the table returned, if not End. * @param[in] StdHeader Handle of Header for calling lib functions and services. * * @return The pointer to the next Register Table, or NULL if End. */ TABLE_ENTRY_FIELDS STATIC *GetNextRegisterTable ( IN CPU_SPECIFIC_SERVICES *FamilySpecificServices, IN TABLE_CORE_SELECTOR Selector, IN OUT REGISTER_TABLE ***RegisterTableHandle, OUT UINTN *NumberOfEntries, IN AMD_CONFIG_PARAMS *StdHeader ) { REGISTER_TABLE **NextTable; TABLE_ENTRY_FIELDS *Entries; ASSERT ((FamilySpecificServices != NULL) && (StdHeader != NULL)); ASSERT (Selector < TableCoreSelectorMax); NextTable = *RegisterTableHandle; if (NextTable == NULL) { // Begin NextTable = FamilySpecificServices->RegisterTableList; IDS_OPTION_HOOK (IDS_REG_TABLE, &NextTable, StdHeader); } else { NextTable++; } // skip if not selected while ((*NextTable != NULL) && (*NextTable)->Selector != Selector) { NextTable++; } if (*NextTable == NULL) { // End *RegisterTableHandle = NULL; Entries = NULL; } else { // Iterate next table *RegisterTableHandle = NextTable; *NumberOfEntries = (*NextTable)->NumberOfEntries; Entries = (TABLE_ENTRY_FIELDS *) (*NextTable)->Table; } return Entries; } /*---------------------------------------------------------------------------------------*/ /** * Compare counts to a pair of ranges. * * @param[in] FirstCount The actual count to be compared to the first range. * @param[in] SecondCount The actual count to be compared to the second range. * @param[in] Ranges The ranges which the counts are compared to. * * @retval TRUE Either one, or both, of the counts is in the range given. * @retval FALSE Neither count is in the range given. */ BOOLEAN IsEitherCountInRange ( IN UINTN FirstCount, IN UINTN SecondCount, IN COUNT_RANGE_FEATURE Ranges ) { // Errors: Entire Range value is zero, Min and Max reversed or not <=, ranges overlap (OK if first range is all), // the real counts are too big. ASSERT ((Ranges.Range0Min <= Ranges.Range0Max) && (Ranges.Range1Min <= Ranges.Range1Max) && (Ranges.Range0Max != 0) && (Ranges.Range1Max != 0) && ((Ranges.Range0Max == COUNT_RANGE_HIGH) || (Ranges.Range0Max < Ranges.Range1Min)) && ((FirstCount < COUNT_RANGE_HIGH) && (SecondCount < COUNT_RANGE_HIGH))); return (BOOLEAN) (((FirstCount <= Ranges.Range0Max) && (FirstCount >= Ranges.Range0Min)) || ((SecondCount <= Ranges.Range1Max) && (SecondCount >= Ranges.Range1Min))); } /*-------------------------------------------------------------------------------------*/ /** * Returns the performance profile features list of the currently running processor core. * * @param[out] Features The performance profile features supported by this platform * @param[in] PlatformConfig Config handle for platform specific information * @param[in] StdHeader Header for library and services * */ VOID GetPerformanceFeatures ( OUT PERFORMANCE_PROFILE_FEATS *Features, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { CPUID_DATA CpuidDataStruct; CPU_SPECIFIC_SERVICES *FamilySpecificServices; Features->PerformanceProfileValue = 0; // Reflect Probe Filter Configuration. Features->PerformanceProfileFeatures.ProbeFilter = 0; if (IsFeatureEnabled (HtAssist, PlatformConfig, StdHeader)) { Features->PerformanceProfileFeatures.ProbeFilter = 1; } // Reflect Display Refresh Requests use 32 bytes Configuration. Features->PerformanceProfileFeatures.RefreshRequest32Byte = 0; if (PlatformConfig->PlatformProfile.Use32ByteRefresh) { Features->PerformanceProfileFeatures.RefreshRequest32Byte = 1; } // Reflect Mct Isoc Read Priority set to variable Configuration. Features->PerformanceProfileFeatures.MctIsocVariable = 0; if (PlatformConfig->PlatformProfile.UseVariableMctIsocPriority) { Features->PerformanceProfileFeatures.MctIsocVariable = 1; } // Indicate if this boot is a warm reset. Features->PerformanceProfileFeatures.IsWarmReset = 0; if (IsWarmReset (StdHeader)) { Features->PerformanceProfileFeatures.IsWarmReset = 1; } // Get L3 Cache present as indicated by CPUID Features->PerformanceProfileFeatures.L3Cache = 0; Features->PerformanceProfileFeatures.NoL3Cache = 1; LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuidDataStruct, StdHeader); if (((CpuidDataStruct.EDX_Reg & 0xFFFC0000) >> 18) != 0) { Features->PerformanceProfileFeatures.L3Cache = 1; Features->PerformanceProfileFeatures.NoL3Cache = 0; } // Get VRM select high speed from build option. Features->PerformanceProfileFeatures.VrmHighSpeed = 0; if (PlatformConfig->VrmProperties[CoreVrm].HiSpeedEnable) { Features->PerformanceProfileFeatures.VrmHighSpeed = 1; } // Get some family, model specific performance type info. GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); ASSERT (FamilySpecificServices != NULL); // Is the Northbridge P-State feature enabled Features->PerformanceProfileFeatures.NbPstates = 0; if (FamilySpecificServices->IsNbPstateEnabled (FamilySpecificServices, PlatformConfig, StdHeader)) { Features->PerformanceProfileFeatures.NbPstates = 1; } } /*---------------------------------------------------------------------------------------*/ /** * Perform the MSR Register Entry. * * @TableEntryTypeMethod{::MsrRegister}. * * Read - Modify - Write the MSR, clearing masked bits, and setting the data bits. * * @param[in] Entry The MSR register entry to perform * @param[in] PlatformConfig Config handle for platform specific information * @param[in] StdHeader Config handle for library and services. * */ VOID SetRegisterForMsrEntry ( IN TABLE_ENTRY_DATA *Entry, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT64 MsrData; // Even for only single bit fields, use those in the mask. "Mask nothing" is a bug, even if just by policy. ASSERT (Entry->MsrEntry.Mask != 0); LibAmdMsrRead (Entry->MsrEntry.Address, &MsrData, StdHeader); MsrData = MsrData & (~(Entry->MsrEntry.Mask)); MsrData = MsrData | Entry->MsrEntry.Data; LibAmdMsrWrite (Entry->MsrEntry.Address, &MsrData, StdHeader); } /*---------------------------------------------------------------------------------------*/ /** * Perform the PCI Register Entry. * * @TableEntryTypeMethod{::PciRegister}. * * Make the current core's PCI address with the function and register for 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 SetRegisterForPciEntry ( IN TABLE_ENTRY_DATA *Entry, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 TempVar32_a; UINT32 MySocket; UINT32 MyModule; UINT32 Ignored; PCI_ADDR MyPciAddress; AGESA_STATUS IgnoredSts; 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. // Even for only single bit fields, use those in the mask. "Mask nothing" is a bug, even if just by policy. ASSERT ((Entry->InitialValues[4] == 0) && (Entry->InitialValues[3] == 0) && (Entry->PciEntry.Mask != 0)); LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader); PciEntry.PciEntry = Entry->PciEntry; IDS_OPTION_HOOK (IDS_SET_PCI_REGISTER_ENTRY, &PciEntry, StdHeader); IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredSts); GetPciAddress (StdHeader, MySocket, MyModule, &MyPciAddress, &IgnoredSts); MyPciAddress.Address.Function = PciEntry.PciEntry.Address.Address.Function; MyPciAddress.Address.Register = PciEntry.PciEntry.Address.Address.Register; LibAmdPciRead (AccessWidth32, MyPciAddress, &TempVar32_a, StdHeader); TempVar32_a = TempVar32_a & (~(PciEntry.PciEntry.Mask)); TempVar32_a = TempVar32_a | PciEntry.PciEntry.Data; LibAmdPciWrite (AccessWidth32, MyPciAddress, &TempVar32_a, StdHeader); } /*---------------------------------------------------------------------------------------*/ /** * Perform the Family Specific Workaround Register Entry. * * @TableEntryTypeMethod{::FamSpecificWorkaround}. * * Call the function, passing the data. * * See if you can use the other entries or make an entry that covers the fix. * After all, the purpose of having a table entry is to @b NOT have code which * isn't generic feature code, but is family/model code specific to one case. * * @param[in] Entry The Family Specific Workaround register entry to perform * @param[in] PlatformConfig Config handle for platform specific information * @param[in] StdHeader Config handle for library and services. * */ VOID SetRegisterForFamSpecificWorkaroundEntry ( IN TABLE_ENTRY_DATA *Entry, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { ASSERT (Entry->FamSpecificEntry.DoAction != NULL); Entry->FamSpecificEntry.DoAction (Entry->FamSpecificEntry.Data, StdHeader); } /*---------------------------------------------------------------------------------------*/ /** * 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)) == 0) && (Entry->HtPhyEntry.Address < HTPHY_REGISTER_MAX)); IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus); GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus); GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader); GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&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, (const CPU_SPECIFIC_SERVICES **)&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, (const CPU_SPECIFIC_SERVICES **)&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 ); } } } /*---------------------------------------------------------------------------------------*/ /** * 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, (const CPU_SPECIFIC_SERVICES **)&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 Performance Profile PCI Register Entry. * * @TableEntryTypeMethod{::ProfileFixup}. * * Check the entry's performance profile features to the platform's and do the * PCI register entry if they match. * * @param[in] Entry The Performance Profile register entry to perform * @param[in] PlatformConfig Config handle for platform specific information * @param[in] StdHeader Config handle for library and services. * */ VOID SetRegisterForPerformanceProfileEntry ( IN TABLE_ENTRY_DATA *Entry, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { PERFORMANCE_PROFILE_FEATS PlatformProfile; 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) && (Entry->InitialValues[4] == 0)); GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader); if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->FixupEntry.TypeFeats.PerformanceProfileValue)) { LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader); PciEntry.PciEntry = Entry->FixupEntry.PciEntry; SetRegisterForPciEntry (&PciEntry, PlatformConfig, 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, (const CPU_SPECIFIC_SERVICES **)&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, (const CPU_SPECIFIC_SERVICES **)&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 Core Counts Performance PCI Register Entry. * * @TableEntryTypeMethod{::CoreCountsPciRegister}. * * Check the performance profile. * Check the actual core count to the range pair given, and apply if matched. * * @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 SetRegisterForCoreCountsPerformanceEntry ( IN TABLE_ENTRY_DATA *Entry, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { PERFORMANCE_PROFILE_FEATS PlatformProfile; UINTN ActualCoreCount; 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->CoreCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0)); GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader); if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->CoreCountEntry.TypeFeats.PerformanceProfileValue)) { ActualCoreCount = GetActiveCoresInCurrentModule (StdHeader); // Check if the actual core count is in either range. if (IsEitherCountInRange (ActualCoreCount, ActualCoreCount, Entry->CoreCountEntry.CoreCounts.CoreRanges)) { LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader); PciEntry.PciEntry = Entry->CoreCountEntry.PciEntry; SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader); } } } /*---------------------------------------------------------------------------------------*/ /** * Perform the Processor Counts PCI Register Entry. * * @TableEntryTypeMethod{::ProcCountsPciRegister}. * * Check the performance profile. * Check the actual processor count (not node count!) to the range pair given, and apply if matched. * * @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 SetRegisterForProcessorCountsEntry ( IN TABLE_ENTRY_DATA *Entry, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { PERFORMANCE_PROFILE_FEATS PlatformProfile; UINTN ProcessorCount; 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->ProcCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0)); GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader); if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->ProcCountEntry.TypeFeats.PerformanceProfileValue)) { ProcessorCount = GetNumberOfProcessors (StdHeader); // Check if the actual processor count is in either range. if (IsEitherCountInRange (ProcessorCount, ProcessorCount, Entry->ProcCountEntry.ProcessorCounts.ProcessorCountRanges)) { LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader); PciEntry.PciEntry = Entry->ProcCountEntry.PciEntry; SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader); } } } /*---------------------------------------------------------------------------------------*/ /** * Perform the Compute Unit Counts PCI Register Entry. * * @TableEntryTypeMethod{::CompUnitCountsPciRegister}. * * Check the entry's performance profile features and the compute unit count * to the platform's and do the PCI register entry if they match. * * @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 SetRegisterForComputeUnitCountsEntry ( IN TABLE_ENTRY_DATA *Entry, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { PERFORMANCE_PROFILE_FEATS PlatformProfile; UINTN ComputeUnitCount; 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->CompUnitCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0)); GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader); if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->CompUnitCountEntry.TypeFeats.PerformanceProfileValue)) { ComputeUnitCount = GetNumberOfCompUnitsInCurrentModule (StdHeader); // Check if the actual compute unit count is in either range. if (IsEitherCountInRange (ComputeUnitCount, ComputeUnitCount, Entry->CompUnitCountEntry.ComputeUnitCounts.ComputeUnitRanges)) { LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader); PciEntry.PciEntry = Entry->ProcCountEntry.PciEntry; SetRegisterForPciEntry (&PciEntry, PlatformConfig, 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, (const CPU_SPECIFIC_SERVICES **)&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, (const CPU_SPECIFIC_SERVICES **)&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); } } } /* -----------------------------------------------------------------------------*/ /** * Returns the platform features list of the currently running processor core. * * @param[out] Features The Features supported by this platform * @param[in] PlatformConfig Config handle for platform specific information * @param[in] StdHeader Header for library and services * */ VOID GetPlatformFeatures ( OUT PLATFORM_FEATS *Features, IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { PCI_ADDR PciAddress; UINT32 CapabilityReg; UINT32 Link; CPU_SPECIFIC_SERVICES *FamilySpecificServices; UINT32 CoreCount; // Start with none. Features->PlatformValue = 0; switch (PlatformConfig->PlatformProfile.PlatformControlFlowMode) { case Nfcm: Features->PlatformFeatures.PlatformNfcm = 1; break; case UmaDr: Features->PlatformFeatures.PlatformUma = 1; break; case UmaIfcm: Features->PlatformFeatures.PlatformUmaIfcm = 1; break; case Ifcm: Features->PlatformFeatures.PlatformIfcm = 1; break; case Iommu: Features->PlatformFeatures.PlatformIommu = 1; break; default: ASSERT (FALSE); } // Check - Single Link? // This is based on the implemented links on the package regardless of their // connection status. All processors must match the BSP, so we only check it and // not the current node. We don't care exactly how many links there are, as soon // as we find more than one we are done. Link = 0; PciAddress.AddressValue = MAKE_SBDFO (0, 0, PCI_DEV_BASE, FUNC_0, 0); // Until either all capabilities are done or until the desired link is found, // keep looking for HT Host Capabilities. while (Link < 2) { LibAmdPciFindNextCap (&PciAddress, StdHeader); if (PciAddress.AddressValue != ILLEGAL_SBDFO) { LibAmdPciRead (AccessWidth32, PciAddress, &CapabilityReg, StdHeader); if ((CapabilityReg & 0xE00000FF) == 0x20000008) { Link++; } // A capability other than an HT capability, keep looking. } else { // end of capabilities break; } } if (Link < 2) { Features->PlatformFeatures.PlatformSingleLink = 1; } else { Features->PlatformFeatures.PlatformMultiLink = 1; } // Set the legacy core count bits. GetActiveCoresInCurrentSocket (&CoreCount, StdHeader); switch (CoreCount) { case 1: Features->PlatformFeatures.PlatformSingleCore = 1; break; case 2: Features->PlatformFeatures.PlatformDualCore = 1; break; default: Features->PlatformFeatures.PlatformMultiCore = 1; } // // Get some specific platform type info, VC...etc. // GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); ASSERT (FamilySpecificServices != NULL); FamilySpecificServices->GetPlatformTypeSpecificInfo (FamilySpecificServices, Features, StdHeader); } /*---------------------------------------------------------------------------------------*/ /** * Checks if a register table entry applies to the executing core. * * This function uses a combination of logical ID and platform features to * determine whether or not a register table entry applies to the executing core. * * @param[in] CoreCpuRevision The current core's logical ID * @param[in] EntryCpuRevision The entry's desired logical IDs * @param[in] PlatformFeatures The platform features * @param[in] EntryFeatures The entry's desired platform features * * @retval TRUE This entry should be applied * @retval FALSE This entry does not apply * */ BOOLEAN STATIC DoesEntryMatchPlatform ( IN CPU_LOGICAL_ID CoreCpuRevision, IN CPU_LOGICAL_ID EntryCpuRevision, IN PLATFORM_FEATS PlatformFeatures, IN PLATFORM_FEATS EntryFeatures ) { BOOLEAN Result; Result = FALSE; if (((CoreCpuRevision.Family & EntryCpuRevision.Family) != 0) && ((CoreCpuRevision.Revision & EntryCpuRevision.Revision) != 0)) { if (EntryFeatures.PlatformFeatures.AndPlatformFeats == 0) { // Match if ANY entry feats match a platform feat (an OR test) if ((EntryFeatures.PlatformValue & PlatformFeatures.PlatformValue) != 0) { Result = TRUE; } } else { // Match if ALL entry feats match a platform feat (an AND test) if ((EntryFeatures.PlatformValue & ~(AMD_PF_AND)) == (EntryFeatures.PlatformValue & PlatformFeatures.PlatformValue)) { Result = TRUE; } } } return Result; } /*---------------------------------------------------------------------------------------*/ /** * Checks register table entry type specific criteria to the platform. * * Entry Data Type implementer methods can use this generically to check their own * specific criteria. The method collects the actual platform characteristics and * provides them along with the table entry's criteria to this service. * * There are a couple considerations for any implementer method using this service. * The criteria value has to be representable as a UINT32. The MSB, Bit 31, has to * be used as a AND test request if set in the entry. (The platform value should never * have that bit set.) * * @param[in] PlatformTypeSpecificFeatures The platform features * @param[in] EntryTypeFeatures The entry's desired platform features * * @retval TRUE This entry should be applied * @retval FALSE This entry does not apply * */ BOOLEAN DoesEntryTypeSpecificInfoMatch ( IN UINT32 PlatformTypeSpecificFeatures, IN UINT32 EntryTypeFeatures ) { BOOLEAN Result; Result = FALSE; if ((EntryTypeFeatures & BIT31) == 0) { // Match if ANY entry feats match a platform feat (an OR test) if ((EntryTypeFeatures & PlatformTypeSpecificFeatures) != 0) { Result = TRUE; } } else { // Match if ALL entry feats match a platform feat (an AND test) if ((EntryTypeFeatures & ~(BIT31)) == (EntryTypeFeatures & PlatformTypeSpecificFeatures)) { Result = TRUE; } } return Result; } /*---------------------------------------------------------------------------------------*/ /** * Determine this core's Selector matches. * * @param[in] Selector Is the current core this selector type? * @param[in] StdHeader Config handle for library and services. * * @retval TRUE Yes, it is. * @retval FALSE No, it is not. */ BOOLEAN STATIC IsCoreSelector ( IN TABLE_CORE_SELECTOR Selector, IN AMD_CONFIG_PARAMS *StdHeader ) { BOOLEAN Result; AGESA_STATUS CalledStatus; Result = TRUE; ASSERT (Selector < TableCoreSelectorMax); if ((Selector == PrimaryCores) && !IsCurrentCorePrimary (StdHeader)) { Result = FALSE; } if ((Selector == CorePairPrimary) && !IsCorePairPrimary (FirstCoreIsComputeUnitPrimary, StdHeader)) { Result = FALSE; } if ((Selector == BscCore) && (!IsBsp (StdHeader, &CalledStatus))) { Result = FALSE; } return Result; } /*---------------------------------------------------------------------------------------*/ /** * Set the registers for this core based on entries in a list of Register Tables. * * Determine the platform features and this core's logical id. Get the specific table * entry type implementations for the logical model, which may be either generic (the ones * in this file) or specific. * * Scan the tables starting the with ones for all cores and progressively narrowing the selection * based on this core's role (ex. primary core). For a selected table, check for each entry * matching the current core and platform, and call the implementer method to perform the * register set operation if it matches. * * @param[in] PlatformConfig Config handle for platform specific information * @param[in] StdHeader Config handle for library and services. * */ VOID SetRegistersFromTables ( IN PLATFORM_CONFIGURATION *PlatformConfig, IN AMD_CONFIG_PARAMS *StdHeader ) { CPU_LOGICAL_ID CpuLogicalId; PLATFORM_FEATS PlatformFeatures; CPU_SPECIFIC_SERVICES *FamilySpecificServices; TABLE_ENTRY_FIELDS *Entries; TABLE_CORE_SELECTOR Selector; TABLE_ENTRY_TYPE EntryType; REGISTER_TABLE **TableHandle; UINTN NumberOfEntries; UINTN CurrentEntryCount; TABLE_ENTRY_TYPE_DESCRIPTOR *TypeImplementer; PF_DO_TABLE_ENTRY DoTableEntry[TableEntryTypeMax]; // Did you really mean to increase the size of ALL table entries??!! // While it is not necessarily a bug to increase the size of table entries: // - Is this warning a surprise? Please fix it. // - If expected, is this really a feature which is worth the increase? Then let other entries also use the space. ASSERT (sizeof (TABLE_ENTRY_DATA) == (MAX_ENTRY_TYPE_ITEMS32 * sizeof (UINT32))); PlatformFeatures.PlatformValue = 0; GetLogicalIdOfCurrentCore (&CpuLogicalId, StdHeader); GetPlatformFeatures (&PlatformFeatures, PlatformConfig, StdHeader); GetCpuServicesFromLogicalId (&CpuLogicalId, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); // Build a non-sparse table of implementer methods, so we don't have to keep searching. // It is a bug to not include a descriptor for a type that is in the table (but the // descriptor can point to a non-assert stub). // Also, it is not a bug to have no register table implementations, but it is a bug to have none and call this routine. for (EntryType = MsrRegister; EntryType < TableEntryTypeMax; EntryType++) { DoTableEntry[EntryType] = (PF_DO_TABLE_ENTRY)CommonAssert; } TypeImplementer = FamilySpecificServices->TableEntryTypeDescriptors; ASSERT (TypeImplementer != NULL); while (TypeImplementer->EntryType < TableEntryTypeMax) { DoTableEntry[TypeImplementer->EntryType] = TypeImplementer->DoTableEntry; TypeImplementer++; } for (Selector = AllCores; Selector < TableCoreSelectorMax; Selector++) { if (IsCoreSelector (Selector, StdHeader)) { // If the current core is the selected type of core, work the table list for tables for that type of core. TableHandle = NULL; Entries = GetNextRegisterTable (FamilySpecificServices, Selector, &TableHandle, &NumberOfEntries, StdHeader); while (Entries != NULL) { for (CurrentEntryCount = 0; CurrentEntryCount < NumberOfEntries; CurrentEntryCount++, Entries++) { if (DoesEntryMatchPlatform (CpuLogicalId, Entries->CpuRevision, PlatformFeatures, Entries->Features)) { // The entry matches this config, Do It! // Find the implementer for this entry type and pass the entry data to it. ASSERT (Entries->EntryType < TableEntryTypeMax); DoTableEntry[Entries->EntryType] (&Entries->Entry, PlatformConfig, StdHeader); } } Entries = GetNextRegisterTable (FamilySpecificServices, Selector, &TableHandle, &NumberOfEntries, StdHeader); } } else { // Once a selector does not match the current core, quit looking. break; } } } /*---------------------------------------------------------------------------------------*/ /** * Set the registers for this core based on entries in a list of Register Tables. * * This function acts as a wrapper for calling the SetRegistersFromTables * routine at AmdInitEarly. * * @param[in] FamilyServices The current Family Specific Services. * @param[in] EarlyParams Service parameters. * @param[in] StdHeader Config handle for library and services. * */ VOID SetRegistersFromTablesAtEarly ( IN CPU_SPECIFIC_SERVICES *FamilyServices, IN AMD_CPU_EARLY_PARAMS *EarlyParams, IN AMD_CONFIG_PARAMS *StdHeader ) { AGESA_TESTPOINT (TpProcCpuProcessRegisterTables, StdHeader); SetRegistersFromTables (&EarlyParams->PlatformConfig, StdHeader); }