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