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