| /* $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 (c) 2008 - 2012, 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 "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); |
| } |
| } |
| } |
| |