AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / CPU / Table.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * AMD CPU Register Table Related Functions
6  *
7  * Set registers according to a set of register tables
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  CPU
12  * @e \$Revision: 59564 $   @e \$Date: 2011-09-26 12:33:51 -0600 (Mon, 26 Sep 2011) $
13  *
14  */
15 /*
16  ******************************************************************************
17  *
18  * Copyright (C) 2012 Advanced Micro Devices, Inc.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions are met:
23  *     * Redistributions of source code must retain the above copyright
24  *       notice, this list of conditions and the following disclaimer.
25  *     * Redistributions in binary form must reproduce the above copyright
26  *       notice, this list of conditions and the following disclaimer in the
27  *       documentation and/or other materials provided with the distribution.
28  *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
29  *       its contributors may be used to endorse or promote products derived
30  *       from this software without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35  * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  ******************************************************************************
44  */
45
46 /*----------------------------------------------------------------------------------------
47  *                            M O D U L E S    U S E D
48  *----------------------------------------------------------------------------------------
49  */
50 #include "AGESA.h"
51 #include "amdlib.h"
52 #include "Ids.h"
53 #include "Topology.h"
54 #include "OptionMultiSocket.h"
55 #include "cpuRegisters.h"
56 #include "cpuFamilyTranslation.h"
57 #include "Table.h"
58 #include "GeneralServices.h"
59 #include "cpuServices.h"
60 #include "cpuFeatures.h"
61 #include "CommonReturns.h"
62 #include "cpuL3Features.h"
63 #include "Filecode.h"
64 CODE_GROUP (G1_PEICC)
65 RDATA_GROUP (G2_PEI)
66
67 #define FILECODE PROC_CPU_TABLE_FILECODE
68
69 extern OPTION_MULTISOCKET_CONFIGURATION OptionMultiSocketConfiguration;
70
71 /*----------------------------------------------------------------------------------------
72  *                   D E F I N I T I O N S    A N D    M A C R O S
73  *----------------------------------------------------------------------------------------
74  */
75
76 /*----------------------------------------------------------------------------------------
77  *                  T Y P E D E F S     A N D     S T R U C T U R E S
78  *----------------------------------------------------------------------------------------
79  */
80
81 /*----------------------------------------------------------------------------------------
82  *           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
83  *----------------------------------------------------------------------------------------
84  */
85 VOID
86 SetRegistersFromTablesAtEarly (
87   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
88   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
89   IN       AMD_CONFIG_PARAMS      *StdHeader
90   );
91
92 /*----------------------------------------------------------------------------------------
93  *                          E X P O R T E D    F U N C T I O N S
94  *----------------------------------------------------------------------------------------
95  */
96 extern BUILD_OPT_CFG UserOptions;
97 extern CPU_FAMILY_SUPPORT_TABLE L3FeatureFamilyServiceTable;
98
99 /*---------------------------------------------------------------------------------------*/
100 /**
101  * An iterator for all the Family and Model Register Tables.
102  *
103  * RegisterTableHandle should be set to NULL to begin iteration, the first time the method is
104  * invoked.  Register tables can be processed, until this method returns NULL.  RegisterTableHandle
105  * should simply be passed back to the method without modification or use by the caller.
106  * The table selector allows the relevant tables for different cores to be iterated, if the family separates
107  * tables.  For example, MSRs can be in a table processed by all cores and PCI registers in a table processed by
108  * primary cores.
109  *
110  * @param[in]     FamilySpecificServices  The current Family Specific Services.
111  * @param[in]     Selector                Select whether to iterate over tables for either all cores, primary cores, bsp, ....
112  * @param[in,out] RegisterTableHandle     IN: The handle of the current register table, or NULL if Begin.
113  *                                        OUT: The handle of the next register table, if not End.
114  * @param[out]    NumberOfEntries         The number of entries in the table returned, if not End.
115  * @param[in]     StdHeader               Handle of Header for calling lib functions and services.
116  *
117  * @return        The pointer to the next Register Table, or NULL if End.
118  */
119 TABLE_ENTRY_FIELDS
120 STATIC
121 *GetNextRegisterTable (
122   IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
123   IN       TABLE_CORE_SELECTOR     Selector,
124   IN OUT   REGISTER_TABLE       ***RegisterTableHandle,
125      OUT   UINTN                  *NumberOfEntries,
126   IN       AMD_CONFIG_PARAMS      *StdHeader
127   )
128 {
129   REGISTER_TABLE **NextTable;
130   TABLE_ENTRY_FIELDS *Entries;
131
132   ASSERT ((FamilySpecificServices != NULL) && (StdHeader != NULL));
133   ASSERT (Selector < TableCoreSelectorMax);
134
135   NextTable = *RegisterTableHandle;
136   if (NextTable == NULL) {
137     // Begin
138     NextTable = FamilySpecificServices->RegisterTableList;
139     IDS_OPTION_HOOK (IDS_REG_TABLE, &NextTable, StdHeader);
140   } else {
141     NextTable++;
142   }
143   // skip if not selected
144   while ((*NextTable != NULL) && (*NextTable)->Selector != Selector) {
145     NextTable++;
146   }
147   if (*NextTable == NULL) {
148     // End
149     *RegisterTableHandle = NULL;
150     Entries = NULL;
151   } else {
152     // Iterate next table
153     *RegisterTableHandle = NextTable;
154     *NumberOfEntries = (*NextTable)->NumberOfEntries;
155     Entries = (TABLE_ENTRY_FIELDS *) (*NextTable)->Table;
156   }
157   return Entries;
158 }
159
160 /*---------------------------------------------------------------------------------------*/
161 /**
162  * Compare counts to a pair of ranges.
163  *
164  * @param[in]       FirstCount       The actual count to be compared to the first range.
165  * @param[in]       SecondCount      The actual count to be compared to the second range.
166  * @param[in]       Ranges           The ranges which the counts are compared to.
167  *
168  * @retval          TRUE             Either one, or both, of the counts is in the range given.
169  * @retval          FALSE            Neither count is in the range given.
170  */
171 BOOLEAN
172 IsEitherCountInRange (
173   IN       UINTN                FirstCount,
174   IN       UINTN                SecondCount,
175   IN       COUNT_RANGE_FEATURE  Ranges
176   )
177 {
178   // Errors: Entire Range value is zero, Min and Max reversed or not <=, ranges overlap (OK if first range is all),
179   // the real counts are too big.
180   ASSERT ((Ranges.Range0Min <= Ranges.Range0Max) &&
181           (Ranges.Range1Min <= Ranges.Range1Max) &&
182           (Ranges.Range0Max != 0) &&
183           (Ranges.Range1Max != 0) &&
184           ((Ranges.Range0Max == COUNT_RANGE_HIGH) || (Ranges.Range0Max < Ranges.Range1Min)) &&
185           ((FirstCount < COUNT_RANGE_HIGH) && (SecondCount < COUNT_RANGE_HIGH)));
186
187   return (BOOLEAN) (((FirstCount <= Ranges.Range0Max) && (FirstCount >= Ranges.Range0Min)) ||
188                    ((SecondCount <= Ranges.Range1Max) && (SecondCount >= Ranges.Range1Min)));
189 }
190
191 /*-------------------------------------------------------------------------------------*/
192 /**
193  * Returns the performance profile features list of the currently running processor core.
194  *
195  * @param[out]      Features          The performance profile features supported by this platform
196  * @param[in]       PlatformConfig    Config handle for platform specific information
197  * @param[in]       StdHeader         Header for library and services
198  *
199  */
200 VOID
201 GetPerformanceFeatures (
202      OUT   PERFORMANCE_PROFILE_FEATS    *Features,
203   IN       PLATFORM_CONFIGURATION       *PlatformConfig,
204   IN       AMD_CONFIG_PARAMS            *StdHeader
205   )
206 {
207   CPUID_DATA  CpuidDataStruct;
208   CPU_SPECIFIC_SERVICES  *FamilySpecificServices;
209   L3_FEATURE_FAMILY_SERVICES *FeatureFamilyServices;
210
211   Features->PerformanceProfileValue = 0;
212   // Reflect Probe Filter Configuration.
213   Features->PerformanceProfileFeatures.ProbeFilter = 0;
214   if (IsFeatureEnabled (L3Features, PlatformConfig, StdHeader)) {
215     GetFeatureServicesOfCurrentCore (&L3FeatureFamilyServiceTable, (CONST VOID **)&FeatureFamilyServices, StdHeader);
216     if ((FeatureFamilyServices != NULL) &&
217         (FeatureFamilyServices->IsHtAssistSupported (FeatureFamilyServices, PlatformConfig, StdHeader))) {
218       Features->PerformanceProfileFeatures.ProbeFilter = 1;
219     }
220   }
221
222   // Reflect Display Refresh Requests use 32 bytes Configuration.
223   Features->PerformanceProfileFeatures.RefreshRequest32Byte = 0;
224   if (PlatformConfig->PlatformProfile.Use32ByteRefresh) {
225     Features->PerformanceProfileFeatures.RefreshRequest32Byte = 1;
226   }
227   // Reflect Mct Isoc Read Priority set to variable Configuration.
228   Features->PerformanceProfileFeatures.MctIsocVariable = 0;
229   if (PlatformConfig->PlatformProfile.UseVariableMctIsocPriority) {
230     Features->PerformanceProfileFeatures.MctIsocVariable = 1;
231   }
232   // Indicate if this boot is a warm reset.
233   Features->PerformanceProfileFeatures.IsWarmReset = 0;
234   if (IsWarmReset (StdHeader)) {
235     Features->PerformanceProfileFeatures.IsWarmReset = 1;
236   }
237
238   // Get L3 Cache present as indicated by CPUID
239   Features->PerformanceProfileFeatures.L3Cache = 0;
240   Features->PerformanceProfileFeatures.NoL3Cache = 1;
241   LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuidDataStruct, StdHeader);
242   if (((CpuidDataStruct.EDX_Reg & 0xFFFC0000) >> 18) != 0) {
243     Features->PerformanceProfileFeatures.L3Cache = 1;
244     Features->PerformanceProfileFeatures.NoL3Cache = 0;
245   }
246
247   // Get VRM select high speed from build option.
248   Features->PerformanceProfileFeatures.VrmHighSpeed = 0;
249   if (PlatformConfig->VrmProperties[CoreVrm].HiSpeedEnable) {
250     Features->PerformanceProfileFeatures.VrmHighSpeed = 1;
251   }
252
253   // Get some family, model specific performance type info.
254   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
255   ASSERT (FamilySpecificServices != NULL);
256
257   // Is the Northbridge P-State feature enabled
258   Features->PerformanceProfileFeatures.NbPstates = 0;
259   if (FamilySpecificServices->IsNbPstateEnabled (FamilySpecificServices, PlatformConfig, StdHeader)) {
260     Features->PerformanceProfileFeatures.NbPstates = 1;
261   }
262 }
263
264 /*---------------------------------------------------------------------------------------*/
265 /**
266  * Perform the MSR Register Entry.
267  *
268  * @TableEntryTypeMethod{::MsrRegister}.
269  *
270  * Read - Modify - Write the MSR, clearing masked bits, and setting the data bits.
271  *
272  * @param[in]     Entry             The MSR register entry to perform
273  * @param[in]     PlatformConfig    Config handle for platform specific information
274  * @param[in]     StdHeader         Config handle for library and services.
275  *
276  */
277 VOID
278 SetRegisterForMsrEntry (
279   IN       TABLE_ENTRY_DATA       *Entry,
280   IN       PLATFORM_CONFIGURATION *PlatformConfig,
281   IN       AMD_CONFIG_PARAMS      *StdHeader
282   )
283 {
284   UINT64          MsrData;
285
286   // Even for only single bit fields, use those in the mask.  "Mask nothing" is a bug, even if just by policy.
287   ASSERT (Entry->MsrEntry.Mask != 0);
288
289   LibAmdMsrRead (Entry->MsrEntry.Address, &MsrData, StdHeader);
290   MsrData = MsrData & (~(Entry->MsrEntry.Mask));
291   MsrData = MsrData | Entry->MsrEntry.Data;
292   LibAmdMsrWrite (Entry->MsrEntry.Address, &MsrData, StdHeader);
293 }
294
295 /*---------------------------------------------------------------------------------------*/
296 /**
297  * Perform the PCI Register Entry.
298  *
299  * @TableEntryTypeMethod{::PciRegister}.
300  *
301  * Make the current core's PCI address with the function and register for the entry.
302  * Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
303  *
304  * @param[in]     Entry             The PCI register entry to perform
305  * @param[in]     PlatformConfig    Config handle for platform specific information
306  * @param[in]     StdHeader         Config handle for library and services.
307  *
308  */
309 VOID
310 SetRegisterForPciEntry (
311   IN       TABLE_ENTRY_DATA       *Entry,
312   IN       PLATFORM_CONFIGURATION *PlatformConfig,
313   IN       AMD_CONFIG_PARAMS      *StdHeader
314   )
315 {
316   UINT32          TempVar32_a;
317   UINT32          MySocket;
318   UINT32          MyModule;
319   UINT32          Ignored;
320   PCI_ADDR        MyPciAddress;
321   AGESA_STATUS    IgnoredSts;
322   TABLE_ENTRY_DATA  PciEntry;
323
324   // Errors:  Possible values in unused entry space, extra type features, value range checks.
325   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
326   // Even for only single bit fields, use those in the mask.  "Mask nothing" is a bug, even if just by policy.
327   ASSERT ((Entry->InitialValues[4] == 0) &&
328           (Entry->InitialValues[3] == 0) &&
329           (Entry->PciEntry.Mask != 0));
330
331   LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
332   PciEntry.PciEntry = Entry->PciEntry;
333
334   IDS_OPTION_HOOK (IDS_SET_PCI_REGISTER_ENTRY, &PciEntry, StdHeader);
335
336   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredSts);
337   GetPciAddress (StdHeader, MySocket, MyModule, &MyPciAddress, &IgnoredSts);
338   MyPciAddress.Address.Function = PciEntry.PciEntry.Address.Address.Function;
339   MyPciAddress.Address.Register = PciEntry.PciEntry.Address.Address.Register;
340   LibAmdPciRead (AccessWidth32, MyPciAddress, &TempVar32_a, StdHeader);
341   TempVar32_a = TempVar32_a & (~(PciEntry.PciEntry.Mask));
342   TempVar32_a = TempVar32_a | PciEntry.PciEntry.Data;
343   LibAmdPciWrite (AccessWidth32, MyPciAddress, &TempVar32_a, StdHeader);
344 }
345
346 /*---------------------------------------------------------------------------------------*/
347 /**
348  * Perform the Family Specific Workaround Register Entry.
349  *
350  * @TableEntryTypeMethod{::FamSpecificWorkaround}.
351  *
352  * Call the function, passing the data.
353  *
354  * See if you can use the other entries or make an entry that covers the fix.
355  * After all, the purpose of having a table entry is to @b NOT have code which
356  * isn't generic feature code, but is family/model code specific to one case.
357  *
358  * @param[in]     Entry             The Family Specific Workaround register entry to perform
359  * @param[in]     PlatformConfig    Config handle for platform specific information
360  * @param[in]     StdHeader         Config handle for library and services.
361  *
362  */
363 VOID
364 SetRegisterForFamSpecificWorkaroundEntry (
365   IN       TABLE_ENTRY_DATA       *Entry,
366   IN       PLATFORM_CONFIGURATION *PlatformConfig,
367   IN       AMD_CONFIG_PARAMS      *StdHeader
368   )
369 {
370   ASSERT (Entry->FamSpecificEntry.DoAction != NULL);
371
372   Entry->FamSpecificEntry.DoAction (Entry->FamSpecificEntry.Data, StdHeader);
373 }
374
375 /*---------------------------------------------------------------------------------------*/
376 /**
377  * Program HT Phy PCI registers using BKDG values.
378  *
379  * @TableEntryTypeMethod{::HtPhyRegister}.
380  *
381  *
382  * @param[in]       Entry               The type specific entry data to be implemented (that is written).
383  * @param[in]       PlatformConfig      Config handle for platform specific information
384  * @param[in]       StdHeader           Config params for library, services.
385  *
386  */
387 VOID
388 SetRegisterForHtPhyEntry (
389   IN       TABLE_ENTRY_DATA       *Entry,
390   IN       PLATFORM_CONFIGURATION *PlatformConfig,
391   IN       AMD_CONFIG_PARAMS      *StdHeader
392   )
393 {
394   UINT32                Link;
395   UINT32                MySocket;
396   UINT32                MyModule;
397   AGESA_STATUS          IgnoredStatus;
398   UINT32                Ignored;
399   CPU_LOGICAL_ID        CpuFamilyRevision;
400   PCI_ADDR              CapabilitySet;
401   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
402   BOOLEAN               MatchedSublink1;
403   HT_FREQUENCIES        Freq0;
404   HT_FREQUENCIES        Freq1;
405
406   // Errors:  Possible values in unused entry space, extra type features, value range checks.
407   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
408   ASSERT ((Entry->InitialValues[4] == 0) &&
409           ((Entry->HtPhyEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL | HTPHY_LINKTYPE_SL0_AND | HTPHY_LINKTYPE_SL1_AND)) == 0) &&
410           (Entry->HtPhyEntry.Address < HTPHY_REGISTER_MAX));
411
412   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
413   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
414   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
415   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
416   Link = 0;
417   while (FamilySpecificServices->NextLinkHasHtPhyFeats (
418            FamilySpecificServices,
419            &CapabilitySet,
420            &Link,
421            &Entry->HtPhyEntry.TypeFeats,
422            &MatchedSublink1,
423            &Freq0,
424            &Freq1,
425            StdHeader)) {
426     FamilySpecificServices->SetHtPhyRegister (FamilySpecificServices, &Entry->HtPhyEntry, CapabilitySet, Link, StdHeader);
427   }
428 }
429
430 /*---------------------------------------------------------------------------------------*/
431 /**
432  * Program a range of HT Phy PCI registers using BKDG values.
433  *
434  * @TableEntryTypeMethod{::HtPhyRangeRegister}.
435  *
436  *
437  * @param[in]       Entry               The type specific entry data to be implemented (that is written).
438  * @param[in]       PlatformConfig      Config handle for platform specific information
439  * @param[in]       StdHeader           Config params for library, services.
440  *
441  */
442 VOID
443 SetRegisterForHtPhyRangeEntry (
444   IN       TABLE_ENTRY_DATA       *Entry,
445   IN       PLATFORM_CONFIGURATION *PlatformConfig,
446   IN       AMD_CONFIG_PARAMS      *StdHeader
447   )
448 {
449   UINT32                Link;
450   UINT32                MySocket;
451   UINT32                MyModule;
452   AGESA_STATUS          IgnoredStatus;
453   UINT32                Ignored;
454   CPU_LOGICAL_ID        CpuFamilyRevision;
455   PCI_ADDR              CapabilitySet;
456   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
457   HT_PHY_TYPE_ENTRY_DATA CurrentHtPhyRegister;
458   BOOLEAN                MatchedSublink1;
459   HT_FREQUENCIES        Freq0;
460   HT_FREQUENCIES        Freq1;
461
462   // Errors:  Possible values in unused entry space, extra type features, value range checks.
463   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
464   ASSERT (((Entry->HtPhyRangeEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL)) == 0) &&
465           (Entry->HtPhyRangeEntry.LowAddress <= Entry->HtPhyRangeEntry.HighAddress) &&
466           (Entry->HtPhyRangeEntry.HighAddress < HTPHY_REGISTER_MAX) &&
467           (Entry->HtPhyRangeEntry.HighAddress != 0));
468
469   CurrentHtPhyRegister.Mask = Entry->HtPhyRangeEntry.Mask;
470   CurrentHtPhyRegister.Data = Entry->HtPhyRangeEntry.Data;
471   CurrentHtPhyRegister.TypeFeats = Entry->HtPhyRangeEntry.TypeFeats;
472
473   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
474   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
475   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
476   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
477   Link = 0;
478   while (FamilySpecificServices->NextLinkHasHtPhyFeats (
479            FamilySpecificServices,
480            &CapabilitySet,
481            &Link,
482            &Entry->HtPhyRangeEntry.TypeFeats,
483            &MatchedSublink1,
484            &Freq0,
485            &Freq1,
486            StdHeader)) {
487     for (CurrentHtPhyRegister.Address = Entry->HtPhyRangeEntry.LowAddress;
488          CurrentHtPhyRegister.Address <= Entry->HtPhyRangeEntry.HighAddress;
489          CurrentHtPhyRegister.Address++) {
490       FamilySpecificServices->SetHtPhyRegister (FamilySpecificServices, &CurrentHtPhyRegister, CapabilitySet, Link, StdHeader);
491     }
492   }
493 }
494
495 /*----------------------------------------------------------------------------------------*/
496 /**
497  * Is PackageLink an Internal Link?
498  *
499  * This is a test for the logical link match codes in the user interface, not a test for
500  * the actual northbridge links.
501  *
502  * @param[in]    PackageLink   The link
503  *
504  * @retval       TRUE          This is an internal link
505  * @retval       FALSE         This is not an internal link
506  */
507 BOOLEAN
508 STATIC
509 IsDeemphasisLinkInternal (
510   IN       UINT32  PackageLink
511   )
512 {
513   return (BOOLEAN) ((PackageLink <= HT_LIST_MATCH_INTERNAL_LINK_2) && (PackageLink >= HT_LIST_MATCH_INTERNAL_LINK_0));
514 }
515
516 /*----------------------------------------------------------------------------------------*/
517 /**
518  * Get the Package Link number, for the current node and real link number.
519  *
520  * Based on the link to package link mapping from BKDG, look up package link for
521  * the input link on the internal node number corresponding to the current core's node.
522  * For single module processors, the northbridge link and package link are the same.
523  *
524  * @param[in]   Link                      the link on the current node.
525  * @param[in]   FamilySpecificServices    CPU specific support interface.
526  * @param[in]   StdHeader                 Config params for library, services.
527  *
528  * @return      the Package Link, HT_LIST_TERMINAL Not connected in package, HT_LIST_MATCH_INTERNAL_LINK package internal link.
529  *
530  */
531 UINT32
532 STATIC
533 LookupPackageLink (
534   IN       UINT32                 Link,
535   IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
536   IN       AMD_CONFIG_PARAMS     *StdHeader
537   )
538 {
539   UINT32 PackageLinkMapItem;
540   UINT32 PackageLink;
541   AP_MAIL_INFO ApMailbox;
542
543   PackageLink = HT_LIST_TERMINAL;
544
545   GetApMailbox (&ApMailbox.Info, StdHeader);
546
547   if (ApMailbox.Fields.ModuleType != 0) {
548     ASSERT (FamilySpecificServices->PackageLinkMap != NULL);
549     // Use table to find this module's package link
550     PackageLinkMapItem = 0;
551     while ((*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].Link != HT_LIST_TERMINAL) {
552       if (((*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].Module == ApMailbox.Fields.Module) &&
553           ((*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].Link == Link)) {
554         PackageLink = (*FamilySpecificServices->PackageLinkMap)[PackageLinkMapItem].PackageLink;
555         break;
556       }
557       PackageLinkMapItem++;
558     }
559   } else {
560     PackageLink = Link;
561   }
562   return PackageLink;
563 }
564
565 /*---------------------------------------------------------------------------------------*/
566 /**
567  * Get the platform's specified deemphasis levels for the current link.
568  *
569  * Search the platform's list for a match to the current link and also matching frequency.
570  * If a match is found, use the specified deemphasis levels.
571  *
572  * @param[in]       Socket                    The current Socket.
573  * @param[in]       Link                      The link on that socket.
574  * @param[in]       Frequency                 The frequency the link is set to.
575  * @param[in]       PlatformConfig            Config handle for platform specific information
576  * @param[in]       FamilySpecificServices    CPU specific support interface.
577  * @param[in]       StdHeader                 Config params for library, services.
578  *
579  * @return          The Deemphasis values for the link.
580  */
581 UINT32
582 STATIC
583 GetLinkDeemphasis (
584   IN       UINT32                  Socket,
585   IN       UINT32                  Link,
586   IN       HT_FREQUENCIES          Frequency,
587   IN       PLATFORM_CONFIGURATION *PlatformConfig,
588   IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
589   IN       AMD_CONFIG_PARAMS      *StdHeader
590   )
591 {
592   UINT32 Result;
593   CPU_HT_DEEMPHASIS_LEVEL *Match;
594   UINT32 PackageLink;
595
596   PackageLink = LookupPackageLink (Link, FamilySpecificServices, StdHeader);
597   // All External and Internal links have deemphasis level none as the default.
598   // However, it is expected that the platform BIOS will provide deemphasis levels for the external links.
599   Result = ((DCV_LEVEL_NONE) | (DEEMPHASIS_LEVEL_NONE));
600
601   if (PlatformConfig->PlatformDeemphasisList != NULL) {
602     Match = PlatformConfig->PlatformDeemphasisList;
603     while (Match->Socket != HT_LIST_TERMINAL) {
604       if (((Match->Socket == Socket) || (Match->Socket == HT_LIST_MATCH_ANY)) &&
605           ((Match->Link == PackageLink) ||
606            ((Match->Link == HT_LIST_MATCH_ANY) && (!IsDeemphasisLinkInternal (PackageLink))) ||
607            ((Match->Link == HT_LIST_MATCH_INTERNAL_LINK) && (IsDeemphasisLinkInternal (PackageLink)))) &&
608           ((Match->LoFreq <= Frequency) && (Match->HighFreq >= Frequency))) {
609         // Found a match, get the deemphasis value.
610         ASSERT ((MaxPlatformDeemphasisLevel > Match->DcvDeemphasis) | (MaxPlatformDeemphasisLevel > Match->ReceiverDeemphasis));
611         Result = ((1 << Match->DcvDeemphasis) | (1 << Match->ReceiverDeemphasis));
612         break;
613       } else {
614         Match++;
615       }
616     }
617   }
618   return Result;
619 }
620
621 /*---------------------------------------------------------------------------------------*/
622 /**
623  * Program Deemphasis registers using BKDG values, for the platform specified levels.
624  *
625  * @TableEntryTypeMethod{::DeemphasisRegister}.
626  *
627  *
628  * @param[in]    Entry            The type specific entry data to be implemented (that is written).
629  * @param[in]    PlatformConfig   Config handle for platform specific information
630  * @param[in]    StdHeader        Config params for library, services.
631  *
632  */
633 VOID
634 SetRegisterForDeemphasisEntry (
635   IN       TABLE_ENTRY_DATA       *Entry,
636   IN       PLATFORM_CONFIGURATION *PlatformConfig,
637   IN       AMD_CONFIG_PARAMS      *StdHeader
638   )
639 {
640   UINT32                Link;
641   UINT32                MySocket;
642   UINT32                MyModule;
643   AGESA_STATUS          IgnoredStatus;
644   UINT32                Ignored;
645   CPU_LOGICAL_ID        CpuFamilyRevision;
646   PCI_ADDR              CapabilitySet;
647   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
648   BOOLEAN               MatchedSublink1;
649   HT_FREQUENCIES        Freq0;
650   HT_FREQUENCIES        Freq1;
651
652   // Errors:  Possible values in unused entry space, extra type features, value range checks.
653   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
654   ASSERT (((Entry->DeemphasisEntry.Levels.DeemphasisValues & ~(VALID_DEEMPHASIS_LEVELS)) == 0) &&
655           ((Entry->DeemphasisEntry.HtPhyEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL)) == 0) &&
656           (Entry->DeemphasisEntry.HtPhyEntry.Address < HTPHY_REGISTER_MAX));
657
658   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
659   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
660   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
661   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
662   Link = 0;
663   while (FamilySpecificServices->NextLinkHasHtPhyFeats (
664            FamilySpecificServices,
665            &CapabilitySet,
666            &Link,
667            &Entry->DeemphasisEntry.HtPhyEntry.TypeFeats,
668            &MatchedSublink1,
669            &Freq0,
670            &Freq1,
671            StdHeader)) {
672     if (DoesEntryTypeSpecificInfoMatch (
673           GetLinkDeemphasis (
674             MySocket,
675             (MatchedSublink1 ? (Link + 4) : Link),
676             (MatchedSublink1 ? Freq1 : Freq0),
677             PlatformConfig,
678             FamilySpecificServices,
679             StdHeader),
680           Entry->DeemphasisEntry.Levels.DeemphasisValues)) {
681       FamilySpecificServices->SetHtPhyRegister (
682         FamilySpecificServices,
683         &Entry->DeemphasisEntry.HtPhyEntry,
684         CapabilitySet,
685         Link,
686         StdHeader
687         );
688       IDS_HDT_CONSOLE (HT_TRACE, "Socket %d Module %d Sub-link %1d :\n  ----> running on HT3, %s Level is %s\n",
689         MySocket, MyModule,
690         ((Entry->DeemphasisEntry.HtPhyEntry.TypeFeats.HtPhyLinkValue & HTPHY_LINKTYPE_SL0_ALL) != 0) ? Link : (Link + 4),
691         ((Entry->DeemphasisEntry.Levels.DeemphasisValues & DCV_LEVELS_ALL) != 0) ? "DCV" : "Deemphasis",
692         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL_NONE) ? " 0 dB" :
693         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__3) ? " - 3 dB" :
694         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__6) ? " - 6 dB" :
695         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__6) ? " - 6 dB" :
696         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__8) ? " - 8 dB" :
697         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__11) ? " - 11 dB" :
698         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DEEMPHASIS_LEVEL__11_8) ? " - 11 dB postcursor with - 8 dB precursor" :
699         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL_NONE) ? " 0 dB" :
700         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__2) ? " - 2 dB" :
701         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__3) ? " - 3 dB" :
702         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__5) ? " - 5 dB" :
703         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__6) ? " - 6 dB" :
704         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__7) ? " - 7 dB" :
705         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__8) ? " - 8 dB" :
706         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__9) ? " - 9 dB" :
707         (Entry->DeemphasisEntry.Levels.DeemphasisValues == DCV_LEVEL__11) ? " - 11 dB" : "Undefined");
708     }
709   }
710 }
711
712 /*---------------------------------------------------------------------------------------*/
713 /**
714  * Program HT Phy PCI registers which have complex frequency dependencies.
715  *
716  * @TableEntryTypeMethod{::HtPhyFreqRegister}.
717  *
718  * After matching a link for HT Features, check if the HT frequency matches the given range.
719  * If it does, get the northbridge frequency limits for implemented NB P-states and check if
720  * each matches the given range - range 0 and range 1 for each NB frequency, respectively.
721  * If all matches, apply the entry.
722  *
723  * @param[in]       Entry               The type specific entry data to be implemented (that is written).
724  * @param[in]       PlatformConfig      Config handle for platform specific information
725  * @param[in]       StdHeader           Config params for library, services.
726  *
727  */
728 VOID
729 SetRegisterForHtPhyFreqEntry (
730   IN       TABLE_ENTRY_DATA       *Entry,
731   IN       PLATFORM_CONFIGURATION *PlatformConfig,
732   IN       AMD_CONFIG_PARAMS      *StdHeader
733   )
734 {
735   UINT32                Link;
736   UINT32                MySocket;
737   UINT32                MyModule;
738   AGESA_STATUS          IgnoredStatus;
739   UINT32                Ignored;
740   CPU_LOGICAL_ID        CpuFamilyRevision;
741   PCI_ADDR              CapabilitySet;
742   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
743   BOOLEAN               MatchedSublink1;
744   HT_FREQUENCIES        Freq0;
745   HT_FREQUENCIES        Freq1;
746   BOOLEAN               Temp1;
747   BOOLEAN               Temp2;
748   UINT32                NbFreq0;
749   UINT32                NbFreq1;
750   UINT32                NbDivisor0;
751   UINT32                NbDivisor1;
752
753   // Errors:  extra type features, value range checks.
754   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
755   ASSERT (((Entry->HtPhyFreqEntry.HtPhyEntry.TypeFeats.HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL)) == 0) &&
756           (Entry->HtPhyFreqEntry.HtPhyEntry.Address < HTPHY_REGISTER_MAX));
757
758   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
759   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
760   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
761   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
762   Link = 0;
763   while (FamilySpecificServices->NextLinkHasHtPhyFeats (
764            FamilySpecificServices,
765            &CapabilitySet,
766            &Link,
767            &Entry->HtPhyFreqEntry.HtPhyEntry.TypeFeats,
768            &MatchedSublink1,
769            &Freq0,
770            &Freq1,
771            StdHeader)) {
772     // Check the HT Frequency for match to the range.
773     if (IsEitherCountInRange (
774           (MatchedSublink1 ? Freq1 : Freq0),
775           (MatchedSublink1 ? Freq1 : Freq0),
776           Entry->HtPhyFreqEntry.HtFreqCounts.HtFreqCountRanges)) {
777       // Get the NB Frequency, convert to 100's of MHz, then convert to equivalent HT encoding.  This supports
778       // NB frequencies from 800 MHz to 2600 MHz, which is currently greater than any processor supports.
779       OptionMultiSocketConfiguration.GetSystemNbPstateSettings (
780         (UINT32) 0,
781         PlatformConfig,
782         &NbFreq0,
783         &NbDivisor0,
784         &Temp1,
785         &Temp2,
786         StdHeader);
787
788       if (OptionMultiSocketConfiguration.GetSystemNbPstateSettings (
789             (UINT32) 1,
790             PlatformConfig,
791             &NbFreq1,
792             &NbDivisor1,
793             &Temp1,
794             &Temp2,
795             StdHeader)) {
796         ASSERT (NbDivisor1 != 0);
797         NbFreq1 = (NbFreq1 / NbDivisor1);
798         NbFreq1 = (NbFreq1 / 100);
799         NbFreq1 = (NbFreq1 / 2) + 1;
800       } else {
801         NbFreq1 = 0;
802       }
803
804       ASSERT (NbDivisor0 != 0);
805       NbFreq0 = (NbFreq0 / NbDivisor0);
806       NbFreq0 = (NbFreq0 / 100);
807       NbFreq0 = (NbFreq0 / 2) + 1;
808       if (IsEitherCountInRange (NbFreq0, NbFreq1, Entry->HtPhyFreqEntry.NbFreqCounts.HtFreqCountRanges)) {
809         FamilySpecificServices->SetHtPhyRegister (
810           FamilySpecificServices,
811           &Entry->HtPhyFreqEntry.HtPhyEntry,
812           CapabilitySet,
813           Link,
814           StdHeader);
815       }
816     }
817   }
818 }
819
820 /*---------------------------------------------------------------------------------------*/
821 /**
822  * Perform the Performance Profile PCI Register Entry.
823  *
824  * @TableEntryTypeMethod{::ProfileFixup}.
825  *
826  * Check the entry's performance profile features to the platform's and do the
827  * PCI register entry if they match.
828  *
829  * @param[in]     Entry             The Performance Profile register entry to perform
830  * @param[in]     PlatformConfig    Config handle for platform specific information
831  * @param[in]     StdHeader         Config handle for library and services.
832  *
833  */
834 VOID
835 SetRegisterForPerformanceProfileEntry (
836   IN       TABLE_ENTRY_DATA      *Entry,
837   IN       PLATFORM_CONFIGURATION *PlatformConfig,
838   IN       AMD_CONFIG_PARAMS     *StdHeader
839   )
840 {
841   PERFORMANCE_PROFILE_FEATS PlatformProfile;
842   TABLE_ENTRY_DATA          PciEntry;
843
844   // Errors:  Possible values in unused entry space, extra type features, value range checks.
845   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
846   ASSERT (((Entry->TokenPciEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0) &&
847           (Entry->InitialValues[4] == 0));
848
849   GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
850   if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue,
851                                       Entry->FixupEntry.TypeFeats.PerformanceProfileValue)) {
852     LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
853     PciEntry.PciEntry = Entry->FixupEntry.PciEntry;
854     SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
855   }
856 }
857
858 /*---------------------------------------------------------------------------------------*/
859 /**
860  * Perform the HT Phy Performance Profile Register Entry.
861  *
862  * @TableEntryTypeMethod{::HtPhyProfileRegister}.
863  *
864  * @param[in]     Entry             The HT Phy register entry to perform
865  * @param[in]     PlatformConfig    Config handle for platform specific information
866  * @param[in]     StdHeader         Config handle for library and services.
867  *
868  */
869 VOID
870 SetRegisterForHtPhyProfileEntry (
871   IN       TABLE_ENTRY_DATA       *Entry,
872   IN       PLATFORM_CONFIGURATION *PlatformConfig,
873   IN       AMD_CONFIG_PARAMS      *StdHeader
874   )
875 {
876   PERFORMANCE_PROFILE_FEATS PlatformProfile;
877   TABLE_ENTRY_DATA          HtPhyEntry;
878
879   // Errors:  Possible values in unused entry space, extra type features, value range checks.
880   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
881   ASSERT (((Entry->HtPhyProfileEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0) &&
882           (Entry->InitialValues[5] == 0));
883
884   GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
885   if (DoesEntryTypeSpecificInfoMatch (
886         PlatformProfile.PerformanceProfileValue,
887         Entry->HtPhyProfileEntry.TypeFeats.PerformanceProfileValue)) {
888     LibAmdMemFill (&HtPhyEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
889     HtPhyEntry.HtPhyEntry = Entry->HtPhyProfileEntry.HtPhyEntry;
890     SetRegisterForHtPhyEntry (&HtPhyEntry, PlatformConfig, StdHeader);
891   }
892 }
893
894 /*---------------------------------------------------------------------------------------*/
895 /**
896  * Perform the HT Host PCI Register Entry.
897  *
898  * @TableEntryTypeMethod{::HtHostPciRegister}.
899  *
900  * Make the current core's PCI address with the function and register for the entry.
901  * For all HT links, check the link's feature set for a match to the entry.
902  * Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
903  *
904  * @param[in]     Entry             The PCI register entry to perform
905  * @param[in]     PlatformConfig    Config handle for platform specific information
906  * @param[in]     StdHeader         Config handle for library and services.
907  *
908  */
909 VOID
910 SetRegisterForHtHostEntry (
911   IN       TABLE_ENTRY_DATA       *Entry,
912   IN       PLATFORM_CONFIGURATION *PlatformConfig,
913   IN       AMD_CONFIG_PARAMS      *StdHeader
914   )
915 {
916   UINTN                 Link;
917   UINT32                MySocket;
918   UINT32                MyModule;
919   AGESA_STATUS          IgnoredStatus;
920   UINT32                Ignored;
921   CPU_LOGICAL_ID        CpuFamilyRevision;
922   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
923   PCI_ADDR              CapabilitySet;
924   PCI_ADDR              PciAddress;
925   HT_HOST_FEATS         HtHostFeats;
926   UINT32                RegisterData;
927
928   // Errors:  Possible values in unused entry space, extra type features, value range checks.
929   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
930   ASSERT ((Entry->InitialValues[4] == 0) &&
931           ((Entry->HtHostEntry.TypeFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0) &&
932           (Entry->HtHostEntry.Address.Address.Register < HT_LINK_HOST_CAP_MAX));
933
934   HtHostFeats.HtHostValue = 0;
935   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
936   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
937   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
938   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
939   Link = 0;
940   while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
941     if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtHostEntry.TypeFeats.HtHostValue)) {
942       // Do the HT Host PCI register update.
943       PciAddress = CapabilitySet;
944       PciAddress.Address.Register += Entry->HtHostEntry.Address.Address.Register;
945       LibAmdPciRead (AccessWidth32, PciAddress, &RegisterData, StdHeader);
946       RegisterData = RegisterData & (~(Entry->HtHostEntry.Mask));
947       RegisterData = RegisterData | Entry->HtHostEntry.Data;
948       LibAmdPciWrite (AccessWidth32, PciAddress, &RegisterData, StdHeader);
949     }
950   }
951 }
952
953 /*---------------------------------------------------------------------------------------*/
954 /**
955  * Perform the HT Host Performance PCI Register Entry.
956  *
957  * @TableEntryTypeMethod{::HtHostPerfPciRegister}.
958  *
959  * Make the current core's PCI address with the function and register for the entry.
960  * For all HT links, check the link's feature set for a match to the entry.
961  * Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
962  *
963  * @param[in]     Entry             The PCI register entry to perform
964  * @param[in]     PlatformConfig    Config handle for platform specific information
965  * @param[in]     StdHeader         Config handle for library and services.
966  *
967  */
968 VOID
969 SetRegisterForHtHostPerfEntry (
970   IN       TABLE_ENTRY_DATA       *Entry,
971   IN       PLATFORM_CONFIGURATION *PlatformConfig,
972   IN       AMD_CONFIG_PARAMS      *StdHeader
973   )
974 {
975   PERFORMANCE_PROFILE_FEATS PlatformProfile;
976   TABLE_ENTRY_DATA HtHostPciTypeEntryData;
977
978   // Errors:  Possible values in unused entry space, extra type features, value range checks.
979   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
980   ASSERT ((Entry->InitialValues[5] == 0) &&
981           ((Entry->HtHostEntry.TypeFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0) &&
982           (Entry->HtHostEntry.Address.Address.Register < HT_LINK_HOST_CAP_MAX));
983
984   // Check for any performance profile features.
985   GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
986   if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue,
987                                       Entry->HtHostPerfEntry.PerformanceFeats.PerformanceProfileValue)) {
988     // Perform HT Host entry process.
989     LibAmdMemFill (&HtHostPciTypeEntryData, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
990     HtHostPciTypeEntryData.HtHostEntry = Entry->HtHostPerfEntry.HtHostEntry;
991     SetRegisterForHtHostEntry (&HtHostPciTypeEntryData, PlatformConfig, StdHeader);
992   }
993 }
994
995 /*---------------------------------------------------------------------------------------*/
996 /**
997  * Set the HT Link Token Count registers.
998  *
999  * @TableEntryTypeMethod{::HtTokenPciRegister}.
1000  *
1001  * Make the current core's PCI address with the function and register for the entry.
1002  * Check the performance profile features.
1003  * For all HT links, check the link's feature set for a match to the entry.
1004  * Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
1005  *
1006  * @param[in]     Entry             The Link Token register entry to perform
1007  * @param[in]     PlatformConfig    Config handle for platform specific information
1008  * @param[in]     StdHeader         Config handle for library and services.
1009  *
1010  */
1011 VOID
1012 SetRegisterForHtLinkTokenEntry (
1013   IN       TABLE_ENTRY_DATA       *Entry,
1014   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1015   IN       AMD_CONFIG_PARAMS      *StdHeader
1016   )
1017 {
1018   UINTN                 Link;
1019   UINT32                MySocket;
1020   UINT32                MyModule;
1021   AGESA_STATUS          IgnoredStatus;
1022   UINT32                Ignored;
1023   CPU_LOGICAL_ID        CpuFamilyRevision;
1024   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
1025   PCI_ADDR              CapabilitySet;
1026   HT_HOST_FEATS         HtHostFeats;
1027   PERFORMANCE_PROFILE_FEATS PlatformProfile;
1028   UINTN                 ProcessorCount;
1029   UINTN                     SystemDegree;
1030   UINT32                RegisterData;
1031   PCI_ADDR              PciAddress;
1032
1033   // Errors:  Possible values in unused entry space, extra type features, value range checks.
1034   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
1035   ASSERT (((Entry->HtTokenEntry.LinkFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0) &&
1036           ((Entry->HtTokenEntry.PerformanceFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0) &&
1037           (Entry->HtTokenEntry.Mask != 0));
1038
1039   HtHostFeats.HtHostValue = 0;
1040   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
1041   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
1042   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
1043   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
1044
1045   // Check if the actual processor count and SystemDegree are in either range.
1046   ProcessorCount = GetNumberOfProcessors (StdHeader);
1047   SystemDegree = GetSystemDegree (StdHeader);
1048   if (IsEitherCountInRange (ProcessorCount, SystemDegree, Entry->HtTokenEntry.ConnectivityCount.ConnectivityCountRanges)) {
1049     // Check for any performance profile features.
1050     GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
1051     if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue,
1052                                         Entry->HtTokenEntry.PerformanceFeats.PerformanceProfileValue)) {
1053       // Check the link features.
1054       Link = 0;
1055       while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
1056         if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtTokenEntry.LinkFeats.HtHostValue)) {
1057           // Do the HT Host PCI register update. Token register are four registers, sublink 0 and 1 share fields.
1058           // If sublink 0 is unconnected, we should let sublink 1 match.  If the links are ganged, of course only sublink 0 matches.
1059           // If the links are unganged and both connected, the BKDG settings are for both coherent.
1060           PciAddress = CapabilitySet;
1061           PciAddress.Address.Register = Entry->HtTokenEntry.Address.Address.Register +
1062             ((Link > 3) ? (((UINT32)Link - 4) * 4) : ((UINT32)Link * 4));
1063           PciAddress.Address.Function = Entry->HtTokenEntry.Address.Address.Function;
1064           LibAmdPciRead (AccessWidth32, PciAddress, &RegisterData, StdHeader);
1065           RegisterData = RegisterData & (~(Entry->HtTokenEntry.Mask));
1066           RegisterData = RegisterData | Entry->HtTokenEntry.Data;
1067           LibAmdPciWrite (AccessWidth32, PciAddress, &RegisterData, StdHeader);
1068         }
1069       }
1070     }
1071   }
1072 }
1073
1074 /*---------------------------------------------------------------------------------------*/
1075 /**
1076  * Perform the Core Counts Performance PCI Register Entry.
1077  *
1078  * @TableEntryTypeMethod{::CoreCountsPciRegister}.
1079  *
1080  * Check the performance profile.
1081  * Check the actual core count to the range pair given, and apply if matched.
1082  *
1083  * @param[in]     Entry             The PCI register entry to perform
1084  * @param[in]     PlatformConfig    Config handle for platform specific information
1085  * @param[in]     StdHeader         Config handle for library and services.
1086  *
1087  */
1088 VOID
1089 SetRegisterForCoreCountsPerformanceEntry (
1090   IN       TABLE_ENTRY_DATA      *Entry,
1091   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1092   IN       AMD_CONFIG_PARAMS     *StdHeader
1093   )
1094 {
1095   PERFORMANCE_PROFILE_FEATS PlatformProfile;
1096   UINTN ActualCoreCount;
1097   TABLE_ENTRY_DATA          PciEntry;
1098
1099   // Errors:  Possible values in unused entry space, extra type features, value range checks.
1100   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
1101   ASSERT (((Entry->CoreCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
1102
1103   GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
1104   if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->CoreCountEntry.TypeFeats.PerformanceProfileValue)) {
1105     ActualCoreCount = GetActiveCoresInCurrentModule (StdHeader);
1106     // Check if the actual core count is in either range.
1107     if (IsEitherCountInRange (ActualCoreCount, ActualCoreCount, Entry->CoreCountEntry.CoreCounts.CoreRanges)) {
1108       LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
1109       PciEntry.PciEntry = Entry->CoreCountEntry.PciEntry;
1110       SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
1111     }
1112   }
1113 }
1114
1115 /*---------------------------------------------------------------------------------------*/
1116 /**
1117  * Perform the Processor Counts PCI Register Entry.
1118  *
1119  * @TableEntryTypeMethod{::ProcCountsPciRegister}.
1120  *
1121  * Check the performance profile.
1122  * Check the actual processor count (not node count!) to the range pair given, and apply if matched.
1123  *
1124  * @param[in]     Entry             The PCI register entry to perform
1125  * @param[in]     PlatformConfig    Config handle for platform specific information
1126  * @param[in]     StdHeader         Config handle for library and services.
1127  *
1128  */
1129 VOID
1130 SetRegisterForProcessorCountsEntry (
1131   IN       TABLE_ENTRY_DATA       *Entry,
1132   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1133   IN       AMD_CONFIG_PARAMS      *StdHeader
1134   )
1135 {
1136   PERFORMANCE_PROFILE_FEATS PlatformProfile;
1137   UINTN ProcessorCount;
1138   TABLE_ENTRY_DATA          PciEntry;
1139
1140   // Errors:  Possible values in unused entry space, extra type features, value range checks.
1141   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
1142   ASSERT (((Entry->ProcCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
1143
1144   GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
1145   if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->ProcCountEntry.TypeFeats.PerformanceProfileValue)) {
1146     ProcessorCount = GetNumberOfProcessors (StdHeader);
1147     // Check if the actual processor count is in either range.
1148     if (IsEitherCountInRange (ProcessorCount, ProcessorCount, Entry->ProcCountEntry.ProcessorCounts.ProcessorCountRanges)) {
1149       LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
1150       PciEntry.PciEntry = Entry->ProcCountEntry.PciEntry;
1151       SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
1152     }
1153   }
1154 }
1155
1156 /*---------------------------------------------------------------------------------------*/
1157 /**
1158  * Perform the Compute Unit Counts PCI Register Entry.
1159  *
1160  * @TableEntryTypeMethod{::CompUnitCountsPciRegister}.
1161  *
1162  * Check the entry's performance profile features and the compute unit count
1163  * to the platform's and do the PCI register entry if they match.
1164  *
1165  * @param[in]     Entry             The PCI register entry to perform
1166  * @param[in]     PlatformConfig    Config handle for platform specific information
1167  * @param[in]     StdHeader         Config handle for library and services.
1168  *
1169  */
1170 VOID
1171 SetRegisterForComputeUnitCountsEntry (
1172   IN       TABLE_ENTRY_DATA       *Entry,
1173   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1174   IN       AMD_CONFIG_PARAMS      *StdHeader
1175   )
1176 {
1177   PERFORMANCE_PROFILE_FEATS PlatformProfile;
1178   UINTN ComputeUnitCount;
1179   TABLE_ENTRY_DATA          PciEntry;
1180
1181   // Errors:  Possible values in unused entry space, extra type features, value range checks.
1182   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
1183   ASSERT (((Entry->CompUnitCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
1184
1185   GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
1186   if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->CompUnitCountEntry.TypeFeats.PerformanceProfileValue)) {
1187     ComputeUnitCount = GetNumberOfCompUnitsInCurrentModule (StdHeader);
1188     // Check if the actual compute unit count is in either range.
1189     if (IsEitherCountInRange (ComputeUnitCount, ComputeUnitCount, Entry->CompUnitCountEntry.ComputeUnitCounts.ComputeUnitRanges)) {
1190       LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
1191       PciEntry.PciEntry = Entry->CompUnitCountEntry.PciEntry;
1192       SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
1193     }
1194   }
1195 }
1196
1197 /*---------------------------------------------------------------------------------------*/
1198 /**
1199  * Perform the Compute Unit Counts MSR Register Entry.
1200  *
1201  * @TableEntryTypeMethod{::CompUnitCountsMsr}.
1202  *
1203  * Check the entry's compute unit count to the platform's and do the
1204  * MSR entry if they match.
1205  *
1206  * @param[in]     Entry             The PCI register entry to perform
1207  * @param[in]     PlatformConfig    Config handle for platform specific information
1208  * @param[in]     StdHeader         Config handle for library and services.
1209  *
1210  */
1211 VOID
1212 SetMsrForComputeUnitCountsEntry (
1213   IN       TABLE_ENTRY_DATA       *Entry,
1214   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1215   IN       AMD_CONFIG_PARAMS      *StdHeader
1216   )
1217 {
1218   UINTN ComputeUnitCount;
1219   TABLE_ENTRY_DATA          MsrEntry;
1220
1221   ComputeUnitCount = GetNumberOfCompUnitsInCurrentModule (StdHeader);
1222   // Check if the actual compute unit count is in either range.
1223   if (IsEitherCountInRange (ComputeUnitCount, ComputeUnitCount, Entry->CompUnitCountMsrEntry.ComputeUnitCounts.ComputeUnitRanges)) {
1224     LibAmdMemFill (&MsrEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
1225     MsrEntry.MsrEntry = Entry->CompUnitCountMsrEntry.MsrEntry;
1226     SetRegisterForMsrEntry (&MsrEntry, PlatformConfig, StdHeader);
1227   }
1228 }
1229
1230 /*---------------------------------------------------------------------------------------*/
1231 /**
1232  * Perform the Processor Token Counts PCI Register Entry.
1233  *
1234  * @TableEntryTypeMethod{::TokenPciRegister}.
1235  *
1236  * The table criteria then translate as:
1237  * - 2 Socket, half populated  ==   Degree 1
1238  * - 4 Socket, half populated   ==  Degree 2
1239  * - 2 Socket, fully populated  ==  Degree 3
1240  * - 4 Socket, fully populated  ==  Degree > 3.  (4 or 5 if 3P, 6 if 4P)
1241  *
1242  * @param[in]     Entry             The PCI register entry to perform
1243  * @param[in]     PlatformConfig    Config handle for platform specific information
1244  * @param[in]     StdHeader         Config handle for library and services.
1245  *
1246  */
1247 VOID
1248 SetRegisterForTokenPciEntry (
1249   IN       TABLE_ENTRY_DATA       *Entry,
1250   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1251   IN       AMD_CONFIG_PARAMS      *StdHeader
1252   )
1253 {
1254   PERFORMANCE_PROFILE_FEATS PlatformProfile;
1255   UINTN                     SystemDegree;
1256   UINT32                    ProcessorPackageType;
1257   TABLE_ENTRY_DATA          PciEntry;
1258
1259   // Errors:  Possible values in unused entry space, extra type features, value range checks.
1260   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
1261   ASSERT ((Entry->TokenPciEntry.PackageType.PackageTypeValue & ~(PACKAGE_TYPE_ALL)) == 0);
1262   ASSERT (((Entry->TokenPciEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
1263
1264   ProcessorPackageType = LibAmdGetPackageType (StdHeader);
1265   if (DoesEntryTypeSpecificInfoMatch (ProcessorPackageType, Entry->TokenPciEntry.PackageType.PackageTypeValue)) {
1266   GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
1267   if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->TokenPciEntry.TypeFeats.PerformanceProfileValue)) {
1268     SystemDegree = GetSystemDegree (StdHeader);
1269     // Check if the system degree is in the range.
1270     if (IsEitherCountInRange (SystemDegree, SystemDegree, Entry->TokenPciEntry.ConnectivityCount.ConnectivityCountRanges)) {
1271       LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
1272       PciEntry.PciEntry = Entry->TokenPciEntry.PciEntry;
1273       SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
1274     }
1275   }
1276   }
1277 }
1278
1279 /*---------------------------------------------------------------------------------------*/
1280 /**
1281  * Perform the HT Link Feature PCI Register Entry.
1282  *
1283  * @TableEntryTypeMethod{::HtFeatPciRegister}.
1284  *
1285  * Set a single field (that is, the register field is not in HT Host capability or a
1286  * set of per link registers) in PCI config, based on HT link features and package type.
1287  * This code is used for two cases: single link processors and multilink processors.
1288  * For single link cases, the link will be tested for a match to the HT Features for the link.
1289  * For multilink processors, the entry will match if @b any link is found which matches.
1290  * For example, a setting can be applied based on coherent HT3 by matching coherent AND HT3.
1291  *
1292  * Make the core's PCI address.  Check the package type (currently more important to the single link case),
1293  * and if matching, iterate through all links checking for an HT feature match until found or exhausted.
1294  * If a match was found, pass the PCI entry data to the implementer for writing for the current core.
1295  *
1296  * @param[in]     Entry             The PCI register entry to perform
1297  * @param[in]     PlatformConfig    Config handle for platform specific information
1298  * @param[in]     StdHeader         Config handle for library and services.
1299  *
1300  */
1301 VOID
1302 SetRegisterForHtFeaturePciEntry (
1303   IN       TABLE_ENTRY_DATA       *Entry,
1304   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1305   IN       AMD_CONFIG_PARAMS      *StdHeader
1306   )
1307 {
1308   UINTN                 Link;
1309   UINT32                MySocket;
1310   UINT32                MyModule;
1311   AGESA_STATUS          IgnoredStatus;
1312   UINT32                Ignored;
1313   CPU_LOGICAL_ID        CpuFamilyRevision;
1314   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
1315   PCI_ADDR              CapabilitySet;
1316   HT_HOST_FEATS         HtHostFeats;
1317   UINT32                ProcessorPackageType;
1318   BOOLEAN               IsMatch;
1319   TABLE_ENTRY_DATA      PciEntry;
1320
1321   // Errors:  Possible values in unused entry space, extra type features, value range checks.
1322   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
1323   ASSERT ((Entry->HtFeatPciEntry.PciEntry.Mask != 0) &&
1324           ((Entry->HtFeatPciEntry.LinkFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0));
1325
1326   HtHostFeats.HtHostValue = 0;
1327   LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
1328   PciEntry.PciEntry = Entry->HtFeatPciEntry.PciEntry;
1329   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
1330   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
1331   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
1332   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
1333
1334   ASSERT ((Entry->HtFeatPciEntry.PackageType.PackageTypeValue & ~(PACKAGE_TYPE_ALL)) == 0);
1335
1336   ProcessorPackageType = LibAmdGetPackageType (StdHeader);
1337   if (DoesEntryTypeSpecificInfoMatch (ProcessorPackageType, Entry->HtFeatPciEntry.PackageType.PackageTypeValue)) {
1338     IsMatch = FALSE;
1339     while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
1340       if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtFeatPciEntry.LinkFeats.HtHostValue)) {
1341         IsMatch = TRUE;
1342         break;
1343       }
1344     }
1345     if (IsMatch) {
1346       // Do the PCI register update.
1347       SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
1348     }
1349   }
1350 }
1351
1352 /*---------------------------------------------------------------------------------------*/
1353 /**
1354  * Perform the HT Link PCI Register Entry.
1355  *
1356  * @TableEntryTypeMethod{::HtLinkPciRegister}.
1357  *
1358  * Make the current core's PCI address with the function and register for the entry.
1359  * Registers are processed for match per link, assuming sequential PCI address per link.
1360  * Read - Modify - Write each matching link's PCI register, clearing masked bits, and setting the data bits.
1361  *
1362  * @param[in]     Entry             The PCI register entry to perform
1363  * @param[in]     PlatformConfig    Config handle for platform specific information
1364  * @param[in]     StdHeader         Config handle for library and services.
1365  *
1366  */
1367 VOID
1368 SetRegisterForHtLinkPciEntry (
1369   IN       TABLE_ENTRY_DATA       *Entry,
1370   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1371   IN       AMD_CONFIG_PARAMS      *StdHeader
1372   )
1373 {
1374   UINTN                 Link;
1375   UINT32                MySocket;
1376   UINT32                MyModule;
1377   AGESA_STATUS          IgnoredStatus;
1378   UINT32                Ignored;
1379   CPU_LOGICAL_ID        CpuFamilyRevision;
1380   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
1381   PCI_ADDR              CapabilitySet;
1382   HT_HOST_FEATS         HtHostFeats;
1383   TABLE_ENTRY_DATA      PciEntry;
1384
1385   // Errors:  Possible values in unused entry space, extra type features, value range checks.
1386   // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
1387   ASSERT ((Entry->HtLinkPciEntry.PciEntry.Mask != 0) &&
1388           ((Entry->HtLinkPciEntry.LinkFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0));
1389
1390   HtHostFeats.HtHostValue = 0;
1391   LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
1392   PciEntry.PciEntry = Entry->HtLinkPciEntry.PciEntry;
1393   IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
1394   GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
1395   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
1396   GetCpuServicesFromLogicalId (&CpuFamilyRevision, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
1397
1398   Link = 0;
1399   while (FamilySpecificServices->GetNextHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader)) {
1400     if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtLinkPciEntry.LinkFeats.HtHostValue)) {
1401       // Do the update to the link's non-Host PCI register, based on the entry address.
1402       PciEntry.PciEntry.Address = Entry->HtLinkPciEntry.PciEntry.Address;
1403       PciEntry.PciEntry.Address.Address.Register = PciEntry.PciEntry.Address.Address.Register + ((UINT32)Link * 4);
1404       SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
1405     }
1406   }
1407 }
1408
1409 /* -----------------------------------------------------------------------------*/
1410 /**
1411  * Returns the platform features list of the currently running processor core.
1412  *
1413  * @param[out]      Features          The Features supported by this platform
1414  * @param[in]       PlatformConfig    Config handle for platform specific information
1415  * @param[in]       StdHeader         Header for library and services
1416  *
1417  */
1418 VOID
1419 GetPlatformFeatures (
1420      OUT   PLATFORM_FEATS         *Features,
1421   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1422   IN       AMD_CONFIG_PARAMS      *StdHeader
1423   )
1424 {
1425   PCI_ADDR  PciAddress;
1426   UINT32    CapabilityReg;
1427   UINT32     Link;
1428   CPU_SPECIFIC_SERVICES  *FamilySpecificServices;
1429   UINT32     CoreCount;
1430
1431   // Start with none.
1432   Features->PlatformValue = 0;
1433
1434   switch (PlatformConfig->PlatformProfile.PlatformControlFlowMode) {
1435   case Nfcm:
1436     Features->PlatformFeatures.PlatformNfcm = 1;
1437     break;
1438   case UmaDr:
1439     Features->PlatformFeatures.PlatformUma = 1;
1440     break;
1441   case UmaIfcm:
1442     Features->PlatformFeatures.PlatformUmaIfcm = 1;
1443     break;
1444   case Ifcm:
1445     Features->PlatformFeatures.PlatformIfcm = 1;
1446     break;
1447   case Iommu:
1448     Features->PlatformFeatures.PlatformIommu = 1;
1449     break;
1450   default:
1451     ASSERT (FALSE);
1452   }
1453   // Check - Single Link?
1454   // This is based on the implemented links on the package regardless of their
1455   // connection status.  All processors must match the BSP, so we only check it and
1456   // not the current node.  We don't care exactly how many links there are, as soon
1457   // as we find more than one we are done.
1458   Link = 0;
1459   PciAddress.AddressValue = MAKE_SBDFO (0, 0, PCI_DEV_BASE, FUNC_0, 0);
1460   // Until either all capabilities are done or until the desired link is found,
1461   // keep looking for HT Host Capabilities.
1462   while (Link < 2) {
1463     LibAmdPciFindNextCap (&PciAddress, StdHeader);
1464     if (PciAddress.AddressValue != ILLEGAL_SBDFO) {
1465       LibAmdPciRead (AccessWidth32, PciAddress, &CapabilityReg, StdHeader);
1466       if ((CapabilityReg & 0xE00000FF) == 0x20000008) {
1467         Link++;
1468       }
1469       // A capability other than an HT capability, keep looking.
1470     } else {
1471       // end of capabilities
1472       break;
1473     }
1474   }
1475   if (Link < 2) {
1476     Features->PlatformFeatures.PlatformSingleLink = 1;
1477   } else {
1478     Features->PlatformFeatures.PlatformMultiLink = 1;
1479   }
1480
1481   // Set the legacy core count bits.
1482   GetActiveCoresInCurrentSocket (&CoreCount, StdHeader);
1483   switch (CoreCount) {
1484   case 1:
1485     Features->PlatformFeatures.PlatformSingleCore = 1;
1486     break;
1487   case 2:
1488     Features->PlatformFeatures.PlatformDualCore = 1;
1489     break;
1490   default:
1491     Features->PlatformFeatures.PlatformMultiCore = 1;
1492   }
1493
1494   //
1495   // Get some specific platform type info, VC...etc.
1496   //
1497   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
1498   ASSERT (FamilySpecificServices != NULL);
1499   FamilySpecificServices->GetPlatformTypeSpecificInfo (FamilySpecificServices, Features, StdHeader);
1500
1501 }
1502
1503 /*---------------------------------------------------------------------------------------*/
1504 /**
1505  * Checks if a register table entry applies to the executing core.
1506  *
1507  * This function uses a combination of logical ID and platform features to
1508  * determine whether or not a register table entry applies to the executing core.
1509  *
1510  * @param[in]     CoreCpuRevision         The current core's logical ID
1511  * @param[in]     EntryCpuRevision        The entry's desired logical IDs
1512  * @param[in]     PlatformFeatures        The platform features
1513  * @param[in]     EntryFeatures           The entry's desired platform features
1514  *
1515  * @retval        TRUE           This entry should be applied
1516  * @retval        FALSE          This entry does not apply
1517  *
1518  */
1519 BOOLEAN
1520 STATIC
1521 DoesEntryMatchPlatform (
1522   IN       CPU_LOGICAL_ID   CoreCpuRevision,
1523   IN       CPU_LOGICAL_ID   EntryCpuRevision,
1524   IN       PLATFORM_FEATS   PlatformFeatures,
1525   IN       PLATFORM_FEATS   EntryFeatures
1526   )
1527 {
1528   BOOLEAN Result;
1529
1530   Result = FALSE;
1531
1532   if (((CoreCpuRevision.Family & EntryCpuRevision.Family) != 0) &&
1533       ((CoreCpuRevision.Revision & EntryCpuRevision.Revision) != 0)) {
1534     if (EntryFeatures.PlatformFeatures.AndPlatformFeats == 0) {
1535       // Match if ANY entry feats match a platform feat (an OR test)
1536       if ((EntryFeatures.PlatformValue & PlatformFeatures.PlatformValue) != 0) {
1537         Result = TRUE;
1538       }
1539     } else {
1540       // Match if ALL entry feats match a platform feat (an AND test)
1541       if ((EntryFeatures.PlatformValue & ~(AMD_PF_AND)) ==
1542           (EntryFeatures.PlatformValue & PlatformFeatures.PlatformValue)) {
1543         Result = TRUE;
1544       }
1545     }
1546   }
1547
1548   return Result;
1549 }
1550
1551 /*---------------------------------------------------------------------------------------*/
1552 /**
1553  * Checks register table entry type specific criteria to the platform.
1554  *
1555  * Entry Data Type implementer methods can use this generically to check their own
1556  * specific criteria.  The method collects the actual platform characteristics and
1557  * provides them along with the table entry's criteria to this service.
1558  *
1559  * There are a couple considerations for any implementer method using this service.
1560  * The criteria value has to be representable as a UINT32.  The MSB, Bit 31, has to
1561  * be used as a AND test request if set in the entry.  (The platform value should never
1562  * have that bit set.)
1563  *
1564  * @param[in]     PlatformTypeSpecificFeatures        The platform features
1565  * @param[in]     EntryTypeFeatures                   The entry's desired platform features
1566  *
1567  * @retval        TRUE                                This entry should be applied
1568  * @retval        FALSE                               This entry does not apply
1569  *
1570  */
1571 BOOLEAN
1572 DoesEntryTypeSpecificInfoMatch (
1573   IN       UINT32   PlatformTypeSpecificFeatures,
1574   IN       UINT32   EntryTypeFeatures
1575   )
1576 {
1577   BOOLEAN Result;
1578
1579   Result = FALSE;
1580
1581   if ((EntryTypeFeatures & BIT31) == 0) {
1582     // Match if ANY entry feats match a platform feat (an OR test)
1583     if ((EntryTypeFeatures & PlatformTypeSpecificFeatures) != 0) {
1584       Result = TRUE;
1585     }
1586   } else {
1587     // Match if ALL entry feats match a platform feat (an AND test)
1588     if ((EntryTypeFeatures & ~(BIT31)) == (EntryTypeFeatures & PlatformTypeSpecificFeatures)) {
1589       Result = TRUE;
1590     }
1591   }
1592   return Result;
1593 }
1594
1595 /*---------------------------------------------------------------------------------------*/
1596 /**
1597  * Determine this core's Selector matches.
1598  *
1599  * @param[in]  Selector    Is the current core this selector type?
1600  * @param[in]  StdHeader   Config handle for library and services.
1601  *
1602  * @retval  TRUE           Yes, it is.
1603  * @retval  FALSE          No, it is not.
1604  */
1605 BOOLEAN
1606 STATIC
1607 IsCoreSelector (
1608   IN       TABLE_CORE_SELECTOR       Selector,
1609   IN       AMD_CONFIG_PARAMS        *StdHeader
1610   )
1611 {
1612   BOOLEAN Result;
1613   AGESA_STATUS  CalledStatus;
1614
1615   Result = TRUE;
1616   ASSERT (Selector < TableCoreSelectorMax);
1617
1618   if ((Selector == PrimaryCores) && !IsCurrentCorePrimary (StdHeader)) {
1619     Result = FALSE;
1620   }
1621   if ((Selector == CorePairPrimary) && !IsCorePairPrimary (FirstCoreIsComputeUnitPrimary, StdHeader)) {
1622     Result = FALSE;
1623   }
1624   if ((Selector == BscCore) && (!IsBsp (StdHeader, &CalledStatus))) {
1625     Result = FALSE;
1626   }
1627   return Result;
1628 }
1629
1630 /*---------------------------------------------------------------------------------------*/
1631 /**
1632  * Set the registers for this core based on entries in a list of Register Tables.
1633  *
1634  * Determine the platform features and this core's logical id.  Get the specific table
1635  * entry type implementations for the logical model, which may be either generic (the ones
1636  * in this file) or specific.
1637  *
1638  * Scan the tables starting the with ones for all cores and progressively narrowing the selection
1639  * based on this core's role (ex. primary core).  For a selected table, check for each entry
1640  * matching the current core and platform, and call the implementer method to perform the
1641  * register set operation if it matches.
1642  *
1643  * @param[in]  PlatformConfig    Config handle for platform specific information
1644  * @param[in]  StdHeader         Config handle for library and services.
1645  *
1646  */
1647 VOID
1648 SetRegistersFromTables (
1649   IN       PLATFORM_CONFIGURATION *PlatformConfig,
1650   IN       AMD_CONFIG_PARAMS      *StdHeader
1651   )
1652 {
1653   CPU_LOGICAL_ID         CpuLogicalId;
1654   PLATFORM_FEATS         PlatformFeatures;
1655   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
1656   TABLE_ENTRY_FIELDS    *Entries;
1657   TABLE_CORE_SELECTOR    Selector;
1658   TABLE_ENTRY_TYPE       EntryType;
1659   REGISTER_TABLE       **TableHandle;
1660   UINTN                  NumberOfEntries;
1661   UINTN                  CurrentEntryCount;
1662   TABLE_ENTRY_TYPE_DESCRIPTOR *TypeImplementer;
1663   PF_DO_TABLE_ENTRY       DoTableEntry[TableEntryTypeMax];
1664
1665   // Did you really mean to increase the size of ALL table entries??!!
1666   // While it is not necessarily a bug to increase the size of table entries:
1667   //   - Is this warning a surprise?  Please fix it.
1668   //   - If expected, is this really a feature which is worth the increase?  Then let other entries also use the space.
1669   ASSERT (sizeof (TABLE_ENTRY_DATA) == (MAX_ENTRY_TYPE_ITEMS32 * sizeof (UINT32)));
1670
1671   PlatformFeatures.PlatformValue = 0;
1672   GetLogicalIdOfCurrentCore (&CpuLogicalId, StdHeader);
1673   GetPlatformFeatures (&PlatformFeatures, PlatformConfig, StdHeader);
1674   GetCpuServicesFromLogicalId (&CpuLogicalId, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
1675
1676   // Build a non-sparse table of implementer methods, so we don't have to keep searching.
1677   // It is a bug to not include a descriptor for a type that is in the table (but the
1678   // descriptor can point to a non-assert stub).
1679   // Also, it is not a bug to have no register table implementations, but it is a bug to have none and call this routine.
1680   for (EntryType = MsrRegister; EntryType < TableEntryTypeMax; EntryType++) {
1681     DoTableEntry[EntryType] = (PF_DO_TABLE_ENTRY)CommonAssert;
1682   }
1683   TypeImplementer = FamilySpecificServices->TableEntryTypeDescriptors;
1684   ASSERT (TypeImplementer != NULL);
1685   while (TypeImplementer->EntryType < TableEntryTypeMax) {
1686     DoTableEntry[TypeImplementer->EntryType] = TypeImplementer->DoTableEntry;
1687     TypeImplementer++;
1688   }
1689
1690   for (Selector = AllCores; Selector < TableCoreSelectorMax; Selector++) {
1691     if (IsCoreSelector (Selector, StdHeader)) {
1692       // If the current core is the selected type of core, work the table list for tables for that type of core.
1693       TableHandle = NULL;
1694       Entries = GetNextRegisterTable (FamilySpecificServices, Selector, &TableHandle, &NumberOfEntries, StdHeader);
1695       while (Entries != NULL) {
1696         for (CurrentEntryCount = 0; CurrentEntryCount < NumberOfEntries; CurrentEntryCount++, Entries++) {
1697           if (DoesEntryMatchPlatform (CpuLogicalId, Entries->CpuRevision, PlatformFeatures, Entries->Features)) {
1698             // The entry matches this config, Do It!
1699             // Find the implementer for this entry type and pass the entry data to it.
1700             ASSERT (Entries->EntryType < TableEntryTypeMax);
1701             DoTableEntry[Entries->EntryType] (&Entries->Entry, PlatformConfig, StdHeader);
1702           }
1703         }
1704         Entries = GetNextRegisterTable (FamilySpecificServices, Selector, &TableHandle, &NumberOfEntries, StdHeader);
1705       }
1706     } else {
1707       // Once a selector does not match the current core, quit looking.
1708       break;
1709     }
1710   }
1711 }
1712
1713 /*---------------------------------------------------------------------------------------*/
1714 /**
1715  * Set the registers for this core based on entries in a list of Register Tables.
1716  *
1717  * This function acts as a wrapper for calling the SetRegistersFromTables
1718  * routine at AmdInitEarly.
1719  *
1720  *  @param[in]   FamilyServices      The current Family Specific Services.
1721  *  @param[in]   EarlyParams         Service parameters.
1722  *  @param[in]   StdHeader           Config handle for library and services.
1723  *
1724  */
1725 VOID
1726 SetRegistersFromTablesAtEarly (
1727   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
1728   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
1729   IN       AMD_CONFIG_PARAMS      *StdHeader
1730   )
1731 {
1732   AGESA_TESTPOINT (TpProcCpuProcessRegisterTables, StdHeader);
1733   SetRegistersFromTables (&EarlyParams->PlatformConfig, StdHeader);
1734 }