blob: 2bef0633fcc586a244b251c77412df5ac4d1eb34 [file] [log] [blame]
zbao7d94cf92012-07-02 14:19:14 +08001/* $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: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
13 *
14 */
15/*
16 ******************************************************************************
17 *
Siyuan Wang641f00c2013-06-08 11:50:55 +080018 * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc.
19 * All rights reserved.
zbao7d94cf92012-07-02 14:19:14 +080020 *
Siyuan Wang641f00c2013-06-08 11:50:55 +080021 * 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.
zbao7d94cf92012-07-02 14:19:14 +080031 *
Siyuan Wang641f00c2013-06-08 11:50:55 +080032 * 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.
zbao7d94cf92012-07-02 14:19:14 +080042 ******************************************************************************
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 "Filecode.h"
63CODE_GROUP (G1_PEICC)
64RDATA_GROUP (G1_PEICC)
65
66#define FILECODE PROC_CPU_TABLE_FILECODE
67
68/*----------------------------------------------------------------------------------------
69 * D E F I N I T I O N S A N D M A C R O S
70 *----------------------------------------------------------------------------------------
71 */
72
73/*----------------------------------------------------------------------------------------
74 * T Y P E D E F S A N D S T R U C T U R E S
75 *----------------------------------------------------------------------------------------
76 */
77
78/*----------------------------------------------------------------------------------------
79 * 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
80 *----------------------------------------------------------------------------------------
81 */
82VOID
83SetRegistersFromTablesAtEarly (
84 IN CPU_SPECIFIC_SERVICES *FamilyServices,
85 IN AMD_CPU_EARLY_PARAMS *EarlyParams,
86 IN AMD_CONFIG_PARAMS *StdHeader
87 );
88
89/*----------------------------------------------------------------------------------------
90 * E X P O R T E D F U N C T I O N S
91 *----------------------------------------------------------------------------------------
92 */
93extern BUILD_OPT_CFG UserOptions;
94extern CPU_FAMILY_SUPPORT_TABLE L3FeatureFamilyServiceTable;
95
96/*---------------------------------------------------------------------------------------*/
97/**
98 * An iterator for all the Family and Model Register Tables.
99 *
100 * RegisterTableHandle should be set to NULL to begin iteration, the first time the method is
101 * invoked. Register tables can be processed, until this method returns NULL. RegisterTableHandle
102 * should simply be passed back to the method without modification or use by the caller.
103 * The table selector allows the relevant tables for different cores to be iterated, if the family separates
104 * tables. For example, MSRs can be in a table processed by all cores and PCI registers in a table processed by
105 * primary cores.
106 *
107 * @param[in] FamilySpecificServices The current Family Specific Services.
108 * @param[in] Selector Select whether to iterate over tables for either all cores, primary cores, bsp, ....
109 * @param[in,out] RegisterTableHandle IN: The handle of the current register table, or NULL if Begin.
110 * OUT: The handle of the next register table, if not End.
111 * @param[out] NumberOfEntries The number of entries in the table returned, if not End.
112 * @param[in] StdHeader Handle of Header for calling lib functions and services.
113 *
114 * @return The pointer to the next Register Table, or NULL if End.
115 */
116TABLE_ENTRY_FIELDS
117STATIC
118*GetNextRegisterTable (
119 IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
120 IN TABLE_CORE_SELECTOR Selector,
Arthur Heymans8d3640d2022-05-16 12:27:36 +0200121 CONST IN OUT REGISTER_TABLE ***RegisterTableHandle,
zbao7d94cf92012-07-02 14:19:14 +0800122 OUT UINTN *NumberOfEntries,
123 IN AMD_CONFIG_PARAMS *StdHeader
124 )
125{
Arthur Heymans8d3640d2022-05-16 12:27:36 +0200126 CONST REGISTER_TABLE **NextTable;
zbao7d94cf92012-07-02 14:19:14 +0800127 TABLE_ENTRY_FIELDS *Entries;
128
129 ASSERT ((FamilySpecificServices != NULL) && (StdHeader != NULL));
130 ASSERT (Selector < TableCoreSelectorMax);
131
132 NextTable = *RegisterTableHandle;
133 if (NextTable == NULL) {
134 // Begin
135 NextTable = FamilySpecificServices->RegisterTableList;
136 IDS_OPTION_HOOK (IDS_TRAP_TABLE, &NextTable, StdHeader);
137 } else {
138 NextTable++;
139 }
140 // skip if not selected
141 while ((*NextTable != NULL) && (*NextTable)->Selector != Selector) {
142 NextTable++;
143 }
144 if (*NextTable == NULL) {
145 // End
146 *RegisterTableHandle = NULL;
147 Entries = NULL;
148 } else {
149 // Iterate next table
150 *RegisterTableHandle = NextTable;
151 *NumberOfEntries = (*NextTable)->NumberOfEntries;
152 Entries = (TABLE_ENTRY_FIELDS *) (*NextTable)->Table;
153 }
154 return Entries;
155}
156
157/*---------------------------------------------------------------------------------------*/
158/**
159 * Compare counts to a pair of ranges.
160 *
161 * @param[in] FirstCount The actual count to be compared to the first range.
162 * @param[in] SecondCount The actual count to be compared to the second range.
163 * @param[in] Ranges The ranges which the counts are compared to.
164 *
165 * @retval TRUE Either one, or both, of the counts is in the range given.
166 * @retval FALSE Neither count is in the range given.
167 */
168BOOLEAN
169IsEitherCountInRange (
170 IN UINTN FirstCount,
171 IN UINTN SecondCount,
172 IN COUNT_RANGE_FEATURE Ranges
173 )
174{
175 // Errors: Entire Range value is zero, Min and Max reversed or not <=, ranges overlap (OK if first range is all),
176 // the real counts are too big.
177 ASSERT ((Ranges.Range0Min <= Ranges.Range0Max) &&
178 (Ranges.Range1Min <= Ranges.Range1Max) &&
179 (Ranges.Range0Max != 0) &&
180 (Ranges.Range1Max != 0) &&
181 ((Ranges.Range0Max == COUNT_RANGE_HIGH) || (Ranges.Range0Max < Ranges.Range1Min)) &&
182 ((FirstCount < COUNT_RANGE_HIGH) && (SecondCount < COUNT_RANGE_HIGH)));
183
184 return (BOOLEAN) (((FirstCount <= Ranges.Range0Max) && (FirstCount >= Ranges.Range0Min)) ||
185 ((SecondCount <= Ranges.Range1Max) && (SecondCount >= Ranges.Range1Min)));
186}
187
188/*-------------------------------------------------------------------------------------*/
189/**
190 * Returns the performance profile features list of the currently running processor core.
191 *
192 * @param[out] Features The performance profile features supported by this platform
193 * @param[in] PlatformConfig Config handle for platform specific information
194 * @param[in] StdHeader Header for library and services
195 *
196 */
197VOID
198GetPerformanceFeatures (
199 OUT PERFORMANCE_PROFILE_FEATS *Features,
200 IN PLATFORM_CONFIGURATION *PlatformConfig,
201 IN AMD_CONFIG_PARAMS *StdHeader
202 )
203{
204 CPUID_DATA CpuidDataStruct;
205 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
206 L3_FEATURE_FAMILY_SERVICES *FeatureFamilyServices;
207
208 Features->PerformanceProfileValue = 0;
209 // Reflect Probe Filter Configuration.
210 Features->PerformanceProfileFeatures.ProbeFilter = 0;
211 if (IsFeatureEnabled (L3Features, PlatformConfig, StdHeader)) {
212 GetFeatureServicesOfCurrentCore (&L3FeatureFamilyServiceTable, (CONST VOID **)&FeatureFamilyServices, StdHeader);
213 if ((FeatureFamilyServices != NULL) &&
214 (FeatureFamilyServices->IsHtAssistSupported (FeatureFamilyServices, PlatformConfig, StdHeader))) {
215 Features->PerformanceProfileFeatures.ProbeFilter = 1;
216 }
217 }
218
219 // Reflect Display Refresh Requests use 32 bytes Configuration.
220 Features->PerformanceProfileFeatures.RefreshRequest32Byte = 0;
221 if (PlatformConfig->PlatformProfile.Use32ByteRefresh) {
222 Features->PerformanceProfileFeatures.RefreshRequest32Byte = 1;
223 }
224 // Reflect Mct Isoc Read Priority set to variable Configuration.
225 Features->PerformanceProfileFeatures.MctIsocVariable = 0;
226 if (PlatformConfig->PlatformProfile.UseVariableMctIsocPriority) {
227 Features->PerformanceProfileFeatures.MctIsocVariable = 1;
228 }
229 // Indicate if this boot is a warm reset.
230 Features->PerformanceProfileFeatures.IsWarmReset = 0;
231 if (IsWarmReset (StdHeader)) {
232 Features->PerformanceProfileFeatures.IsWarmReset = 1;
233 }
234
235 // Get L3 Cache present as indicated by CPUID
236 Features->PerformanceProfileFeatures.L3Cache = 0;
237 Features->PerformanceProfileFeatures.NoL3Cache = 1;
238 LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuidDataStruct, StdHeader);
239 if (((CpuidDataStruct.EDX_Reg & 0xFFFC0000) >> 18) != 0) {
240 Features->PerformanceProfileFeatures.L3Cache = 1;
241 Features->PerformanceProfileFeatures.NoL3Cache = 0;
242 }
243
244 // Get VRM select high speed from build option.
245 Features->PerformanceProfileFeatures.VrmHighSpeed = 0;
246 if (PlatformConfig->VrmProperties[CoreVrm].HiSpeedEnable) {
247 Features->PerformanceProfileFeatures.VrmHighSpeed = 1;
248 }
249
250 // Get some family, model specific performance type info.
251 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
252 ASSERT (FamilySpecificServices != NULL);
253
254 // Is the Northbridge P-State feature enabled
255 Features->PerformanceProfileFeatures.NbPstates = 0;
256 if (FamilySpecificServices->IsNbPstateEnabled (FamilySpecificServices, PlatformConfig, StdHeader)) {
257 Features->PerformanceProfileFeatures.NbPstates = 1;
258 }
259}
260
261/*---------------------------------------------------------------------------------------*/
262/**
263 * Perform the MSR Register Entry.
264 *
265 * @TableEntryTypeMethod{::MsrRegister}.
266 *
267 * Read - Modify - Write the MSR, clearing masked bits, and setting the data bits.
268 *
269 * @param[in] Entry The MSR register entry to perform
270 * @param[in] PlatformConfig Config handle for platform specific information
271 * @param[in] StdHeader Config handle for library and services.
272 *
273 */
274VOID
275SetRegisterForMsrEntry (
276 IN TABLE_ENTRY_DATA *Entry,
277 IN PLATFORM_CONFIGURATION *PlatformConfig,
278 IN AMD_CONFIG_PARAMS *StdHeader
279 )
280{
281 UINT64 MsrData;
282
283 // Even for only single bit fields, use those in the mask. "Mask nothing" is a bug, even if just by policy.
284 ASSERT (Entry->MsrEntry.Mask != 0);
285
286 LibAmdMsrRead (Entry->MsrEntry.Address, &MsrData, StdHeader);
287 MsrData = MsrData & (~(Entry->MsrEntry.Mask));
288 MsrData = MsrData | Entry->MsrEntry.Data;
289 LibAmdMsrWrite (Entry->MsrEntry.Address, &MsrData, StdHeader);
290}
291
292/*---------------------------------------------------------------------------------------*/
293/**
294 * Perform the PCI Register Entry.
295 *
296 * @TableEntryTypeMethod{::PciRegister}.
297 *
298 * Make the current core's PCI address with the function and register for the entry.
299 * Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
300 *
301 * @param[in] Entry The PCI register entry to perform
302 * @param[in] PlatformConfig Config handle for platform specific information
303 * @param[in] StdHeader Config handle for library and services.
304 *
305 */
306VOID
307SetRegisterForPciEntry (
308 IN TABLE_ENTRY_DATA *Entry,
309 IN PLATFORM_CONFIGURATION *PlatformConfig,
310 IN AMD_CONFIG_PARAMS *StdHeader
311 )
312{
313 UINT32 TempVar32_a;
314 UINT32 MySocket;
315 UINT32 MyModule;
316 UINT32 Ignored;
317 PCI_ADDR MyPciAddress;
318 AGESA_STATUS IgnoredSts;
319 TABLE_ENTRY_DATA PciEntry;
320
321 // Errors: Possible values in unused entry space, extra type features, value range checks.
322 // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
323 // Even for only single bit fields, use those in the mask. "Mask nothing" is a bug, even if just by policy.
324 ASSERT ((Entry->InitialValues[4] == 0) &&
325 (Entry->InitialValues[3] == 0) &&
326 (Entry->PciEntry.Mask != 0));
327
328 LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
329 PciEntry.PciEntry = Entry->PciEntry;
330
331 IDS_OPTION_HOOK (IDS_SET_PCI_REGISTER_ENTRY, &PciEntry, StdHeader);
332
333 IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredSts);
334 GetPciAddress (StdHeader, MySocket, MyModule, &MyPciAddress, &IgnoredSts);
335 MyPciAddress.Address.Function = PciEntry.PciEntry.Address.Address.Function;
336 MyPciAddress.Address.Register = PciEntry.PciEntry.Address.Address.Register;
337 LibAmdPciRead (AccessWidth32, MyPciAddress, &TempVar32_a, StdHeader);
338 TempVar32_a = TempVar32_a & (~(PciEntry.PciEntry.Mask));
339 TempVar32_a = TempVar32_a | PciEntry.PciEntry.Data;
340 LibAmdPciWrite (AccessWidth32, MyPciAddress, &TempVar32_a, StdHeader);
341}
342
343/*---------------------------------------------------------------------------------------*/
344/**
345 * Perform the Family Specific Workaround Register Entry.
346 *
347 * @TableEntryTypeMethod{::FamSpecificWorkaround}.
348 *
349 * Call the function, passing the data.
350 *
351 * See if you can use the other entries or make an entry that covers the fix.
352 * After all, the purpose of having a table entry is to @b NOT have code which
353 * isn't generic feature code, but is family/model code specific to one case.
354 *
355 * @param[in] Entry The Family Specific Workaround register entry to perform
356 * @param[in] PlatformConfig Config handle for platform specific information
357 * @param[in] StdHeader Config handle for library and services.
358 *
359 */
360VOID
361SetRegisterForFamSpecificWorkaroundEntry (
362 IN TABLE_ENTRY_DATA *Entry,
363 IN PLATFORM_CONFIGURATION *PlatformConfig,
364 IN AMD_CONFIG_PARAMS *StdHeader
365 )
366{
367 ASSERT (Entry->FamSpecificEntry.DoAction != NULL);
368
369 Entry->FamSpecificEntry.DoAction (Entry->FamSpecificEntry.Data, StdHeader);
370}
371
372/*---------------------------------------------------------------------------------------*/
373/**
374 * Perform the Performance Profile PCI Register Entry.
375 *
376 * @TableEntryTypeMethod{::ProfileFixup}.
377 *
378 * Check the entry's performance profile features to the platform's and do the
379 * PCI register entry if they match.
380 *
381 * @param[in] Entry The Performance Profile register entry to perform
382 * @param[in] PlatformConfig Config handle for platform specific information
383 * @param[in] StdHeader Config handle for library and services.
384 *
385 */
386VOID
387SetRegisterForPerformanceProfileEntry (
388 IN TABLE_ENTRY_DATA *Entry,
389 IN PLATFORM_CONFIGURATION *PlatformConfig,
390 IN AMD_CONFIG_PARAMS *StdHeader
391 )
392{
393 PERFORMANCE_PROFILE_FEATS PlatformProfile;
394 TABLE_ENTRY_DATA PciEntry;
395
396 // Errors: Possible values in unused entry space, extra type features, value range checks.
397 // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
398 ASSERT (((Entry->TokenPciEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0) &&
399 (Entry->InitialValues[4] == 0));
400
401 GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
402 if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue,
403 Entry->FixupEntry.TypeFeats.PerformanceProfileValue)) {
404 LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
405 PciEntry.PciEntry = Entry->FixupEntry.PciEntry;
406 SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
407 }
408}
409
410
411/*---------------------------------------------------------------------------------------*/
412/**
413 * Perform the Core Counts Performance PCI Register Entry.
414 *
415 * @TableEntryTypeMethod{::CoreCountsPciRegister}.
416 *
417 * Check the performance profile.
418 * Check the actual core count to the range pair given, and apply if matched.
419 *
420 * @param[in] Entry The PCI register entry to perform
421 * @param[in] PlatformConfig Config handle for platform specific information
422 * @param[in] StdHeader Config handle for library and services.
423 *
424 */
425VOID
426SetRegisterForCoreCountsPerformanceEntry (
427 IN TABLE_ENTRY_DATA *Entry,
428 IN PLATFORM_CONFIGURATION *PlatformConfig,
429 IN AMD_CONFIG_PARAMS *StdHeader
430 )
431{
432 PERFORMANCE_PROFILE_FEATS PlatformProfile;
433 UINTN ActualCoreCount;
434 TABLE_ENTRY_DATA PciEntry;
435
436 // Errors: Possible values in unused entry space, extra type features, value range checks.
437 // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
438 ASSERT (((Entry->CoreCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
439
440 GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
441 if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->CoreCountEntry.TypeFeats.PerformanceProfileValue)) {
442 ActualCoreCount = GetActiveCoresInCurrentModule (StdHeader);
443 // Check if the actual core count is in either range.
444 if (IsEitherCountInRange (ActualCoreCount, ActualCoreCount, Entry->CoreCountEntry.CoreCounts.CoreRanges)) {
445 LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
446 PciEntry.PciEntry = Entry->CoreCountEntry.PciEntry;
447 SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
448 }
449 }
450}
451
452/*---------------------------------------------------------------------------------------*/
453/**
454 * Perform the Processor Counts PCI Register Entry.
455 *
456 * @TableEntryTypeMethod{::ProcCountsPciRegister}.
457 *
458 * Check the performance profile.
459 * Check the actual processor count (not node count!) to the range pair given, and apply if matched.
460 *
461 * @param[in] Entry The PCI register entry to perform
462 * @param[in] PlatformConfig Config handle for platform specific information
463 * @param[in] StdHeader Config handle for library and services.
464 *
465 */
466VOID
467SetRegisterForProcessorCountsEntry (
468 IN TABLE_ENTRY_DATA *Entry,
469 IN PLATFORM_CONFIGURATION *PlatformConfig,
470 IN AMD_CONFIG_PARAMS *StdHeader
471 )
472{
473 PERFORMANCE_PROFILE_FEATS PlatformProfile;
474 UINTN ProcessorCount;
475 TABLE_ENTRY_DATA PciEntry;
476
477 // Errors: Possible values in unused entry space, extra type features, value range checks.
478 // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
479 ASSERT (((Entry->ProcCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
480
481 GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
482 if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->ProcCountEntry.TypeFeats.PerformanceProfileValue)) {
483 ProcessorCount = GetNumberOfProcessors (StdHeader);
484 // Check if the actual processor count is in either range.
485 if (IsEitherCountInRange (ProcessorCount, ProcessorCount, Entry->ProcCountEntry.ProcessorCounts.ProcessorCountRanges)) {
486 LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
487 PciEntry.PciEntry = Entry->ProcCountEntry.PciEntry;
488 SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
489 }
490 }
491}
492
493/*---------------------------------------------------------------------------------------*/
494/**
495 * Perform the Compute Unit Counts PCI Register Entry.
496 *
497 * @TableEntryTypeMethod{::CompUnitCountsPciRegister}.
498 *
499 * Check the entry's performance profile features and the compute unit count
500 * to the platform's and do the PCI register entry if they match.
501 *
502 * @param[in] Entry The PCI register entry to perform
503 * @param[in] PlatformConfig Config handle for platform specific information
504 * @param[in] StdHeader Config handle for library and services.
505 *
506 */
507VOID
508SetRegisterForComputeUnitCountsEntry (
509 IN TABLE_ENTRY_DATA *Entry,
510 IN PLATFORM_CONFIGURATION *PlatformConfig,
511 IN AMD_CONFIG_PARAMS *StdHeader
512 )
513{
514 PERFORMANCE_PROFILE_FEATS PlatformProfile;
515 UINTN ComputeUnitCount;
516 TABLE_ENTRY_DATA PciEntry;
517
518 // Errors: Possible values in unused entry space, extra type features, value range checks.
519 // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
520 ASSERT (((Entry->CompUnitCountEntry.TypeFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0));
521
522 GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
523 if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue, Entry->CompUnitCountEntry.TypeFeats.PerformanceProfileValue)) {
524 ComputeUnitCount = GetNumberOfCompUnitsInCurrentModule (StdHeader);
525 // Check if the actual compute unit count is in either range.
526 if (IsEitherCountInRange (ComputeUnitCount, ComputeUnitCount, Entry->CompUnitCountEntry.ComputeUnitCounts.ComputeUnitRanges)) {
527 LibAmdMemFill (&PciEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
528 PciEntry.PciEntry = Entry->CompUnitCountEntry.PciEntry;
529 SetRegisterForPciEntry (&PciEntry, PlatformConfig, StdHeader);
530 }
531 }
532}
533
534/*---------------------------------------------------------------------------------------*/
535/**
536 * Perform the Compute Unit Counts MSR Register Entry.
537 *
538 * @TableEntryTypeMethod{::CompUnitCountsMsr}.
539 *
540 * Check the entry's compute unit count to the platform's and do the
541 * MSR entry if they match.
542 *
543 * @param[in] Entry The PCI register entry to perform
544 * @param[in] PlatformConfig Config handle for platform specific information
545 * @param[in] StdHeader Config handle for library and services.
546 *
547 */
548VOID
549SetMsrForComputeUnitCountsEntry (
550 IN TABLE_ENTRY_DATA *Entry,
551 IN PLATFORM_CONFIGURATION *PlatformConfig,
552 IN AMD_CONFIG_PARAMS *StdHeader
553 )
554{
555 UINTN ComputeUnitCount;
556 TABLE_ENTRY_DATA MsrEntry;
557
558 ComputeUnitCount = GetNumberOfCompUnitsInCurrentModule (StdHeader);
559 // Check if the actual compute unit count is in either range.
560 if (IsEitherCountInRange (ComputeUnitCount, ComputeUnitCount, Entry->CompUnitCountMsrEntry.ComputeUnitCounts.ComputeUnitRanges)) {
561 LibAmdMemFill (&MsrEntry, 0, sizeof (TABLE_ENTRY_DATA), StdHeader);
562 MsrEntry.MsrEntry = Entry->CompUnitCountMsrEntry.MsrEntry;
563 SetRegisterForMsrEntry (&MsrEntry, PlatformConfig, StdHeader);
564 }
565}
566
567/* -----------------------------------------------------------------------------*/
568/**
569 * Returns the platform features list of the currently running processor core.
570 *
571 * @param[out] Features The Features supported by this platform
572 * @param[in] PlatformConfig Config handle for platform specific information
573 * @param[in] StdHeader Header for library and services
574 *
575 */
576VOID
577GetPlatformFeatures (
578 OUT PLATFORM_FEATS *Features,
579 IN PLATFORM_CONFIGURATION *PlatformConfig,
580 IN AMD_CONFIG_PARAMS *StdHeader
581 )
582{
583 PCI_ADDR PciAddress;
584 UINT32 CapabilityReg;
585 UINT32 Link;
586 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
587 UINT32 CoreCount;
588
589 // Start with none.
590 Features->PlatformValue = 0;
591
592 switch (PlatformConfig->PlatformProfile.PlatformControlFlowMode) {
593 case Nfcm:
594 Features->PlatformFeatures.PlatformNfcm = 1;
595 break;
596 case UmaDr:
597 Features->PlatformFeatures.PlatformUma = 1;
598 break;
599 case UmaIfcm:
600 Features->PlatformFeatures.PlatformUmaIfcm = 1;
601 break;
602 case Ifcm:
603 Features->PlatformFeatures.PlatformIfcm = 1;
604 break;
605 case Iommu:
606 Features->PlatformFeatures.PlatformIommu = 1;
607 break;
608 default:
609 ASSERT (FALSE);
610 }
611 // Check - Single Link?
612 // This is based on the implemented links on the package regardless of their
613 // connection status. All processors must match the BSP, so we only check it and
614 // not the current node. We don't care exactly how many links there are, as soon
615 // as we find more than one we are done.
616 Link = 0;
617 PciAddress.AddressValue = MAKE_SBDFO (0, 0, PCI_DEV_BASE, FUNC_0, 0);
618 // Until either all capabilities are done or until the desired link is found,
619 // keep looking for HT Host Capabilities.
620 while (Link < 2) {
621 LibAmdPciFindNextCap (&PciAddress, StdHeader);
622 if (PciAddress.AddressValue != ILLEGAL_SBDFO) {
623 LibAmdPciRead (AccessWidth32, PciAddress, &CapabilityReg, StdHeader);
624 if ((CapabilityReg & 0xE00000FF) == 0x20000008) {
625 Link++;
626 }
627 // A capability other than an HT capability, keep looking.
628 } else {
629 // end of capabilities
630 break;
631 }
632 }
633 if (Link < 2) {
634 Features->PlatformFeatures.PlatformSingleLink = 1;
635 } else {
636 Features->PlatformFeatures.PlatformMultiLink = 1;
637 }
638
639 // Set the legacy core count bits.
640 GetActiveCoresInCurrentSocket (&CoreCount, StdHeader);
641 switch (CoreCount) {
642 case 1:
643 Features->PlatformFeatures.PlatformSingleCore = 1;
644 break;
645 case 2:
646 Features->PlatformFeatures.PlatformDualCore = 1;
647 break;
648 default:
649 Features->PlatformFeatures.PlatformMultiCore = 1;
650 }
651
652 //
653 // Get some specific platform type info, VC...etc.
654 //
655 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
656 ASSERT (FamilySpecificServices != NULL);
657 FamilySpecificServices->GetPlatformTypeSpecificInfo (FamilySpecificServices, Features, StdHeader);
658
659}
660
661/*---------------------------------------------------------------------------------------*/
662/**
663 * Checks if a register table entry applies to the executing core.
664 *
665 * This function uses a combination of logical ID and platform features to
666 * determine whether or not a register table entry applies to the executing core.
667 *
668 * @param[in] CoreCpuRevision The current core's logical ID
669 * @param[in] EntryCpuRevision The entry's desired logical IDs
670 * @param[in] PlatformFeatures The platform features
671 * @param[in] EntryFeatures The entry's desired platform features
672 *
673 * @retval TRUE This entry should be applied
674 * @retval FALSE This entry does not apply
675 *
676 */
677BOOLEAN
678STATIC
679DoesEntryMatchPlatform (
680 IN CPU_LOGICAL_ID CoreCpuRevision,
681 IN CPU_LOGICAL_ID EntryCpuRevision,
682 IN PLATFORM_FEATS PlatformFeatures,
683 IN PLATFORM_FEATS EntryFeatures
684 )
685{
686 BOOLEAN Result;
687
688 Result = FALSE;
689
690 if (((CoreCpuRevision.Family & EntryCpuRevision.Family) != 0) &&
691 ((CoreCpuRevision.Revision & EntryCpuRevision.Revision) != 0)) {
692 if (EntryFeatures.PlatformFeatures.AndPlatformFeats == 0) {
693 // Match if ANY entry feats match a platform feat (an OR test)
694 if ((EntryFeatures.PlatformValue & PlatformFeatures.PlatformValue) != 0) {
695 Result = TRUE;
696 }
697 } else {
698 // Match if ALL entry feats match a platform feat (an AND test)
699 if ((EntryFeatures.PlatformValue & ~(AMD_PF_AND)) ==
700 (EntryFeatures.PlatformValue & PlatformFeatures.PlatformValue)) {
701 Result = TRUE;
702 }
703 }
704 }
705
706 return Result;
707}
708
709/*---------------------------------------------------------------------------------------*/
710/**
711 * Checks register table entry type specific criteria to the platform.
712 *
713 * Entry Data Type implementer methods can use this generically to check their own
714 * specific criteria. The method collects the actual platform characteristics and
715 * provides them along with the table entry's criteria to this service.
716 *
717 * There are a couple considerations for any implementer method using this service.
718 * The criteria value has to be representable as a UINT32. The MSB, Bit 31, has to
719 * be used as a AND test request if set in the entry. (The platform value should never
720 * have that bit set.)
721 *
722 * @param[in] PlatformTypeSpecificFeatures The platform features
723 * @param[in] EntryTypeFeatures The entry's desired platform features
724 *
725 * @retval TRUE This entry should be applied
726 * @retval FALSE This entry does not apply
727 *
728 */
729BOOLEAN
730DoesEntryTypeSpecificInfoMatch (
731 IN UINT32 PlatformTypeSpecificFeatures,
732 IN UINT32 EntryTypeFeatures
733 )
734{
735 BOOLEAN Result;
736
737 Result = FALSE;
738
739 if ((EntryTypeFeatures & BIT31) == 0) {
740 // Match if ANY entry feats match a platform feat (an OR test)
741 if ((EntryTypeFeatures & PlatformTypeSpecificFeatures) != 0) {
742 Result = TRUE;
743 }
744 } else {
745 // Match if ALL entry feats match a platform feat (an AND test)
746 if ((EntryTypeFeatures & ~(BIT31)) == (EntryTypeFeatures & PlatformTypeSpecificFeatures)) {
747 Result = TRUE;
748 }
749 }
750 return Result;
751}
752
753/*---------------------------------------------------------------------------------------*/
754/**
755 * Determine this core's Selector matches.
756 *
757 * @param[in] Selector Is the current core this selector type?
758 * @param[in] StdHeader Config handle for library and services.
759 *
760 * @retval TRUE Yes, it is.
761 * @retval FALSE No, it is not.
762 */
763BOOLEAN
764STATIC
765IsCoreSelector (
766 IN TABLE_CORE_SELECTOR Selector,
767 IN AMD_CONFIG_PARAMS *StdHeader
768 )
769{
770 BOOLEAN Result;
771 AGESA_STATUS CalledStatus;
772
773 Result = TRUE;
774 ASSERT (Selector < TableCoreSelectorMax);
775
776 if ((Selector == PrimaryCores) && !IsCurrentCorePrimary (StdHeader)) {
777 Result = FALSE;
778 }
779 if ((Selector == CorePairPrimary) && !IsCorePairPrimary (FirstCoreIsComputeUnitPrimary, StdHeader)) {
780 Result = FALSE;
781 }
782 if ((Selector == BscCore) && (!IsBsp (StdHeader, &CalledStatus))) {
783 Result = FALSE;
784 }
785 return Result;
786}
787
788/*---------------------------------------------------------------------------------------*/
789/**
790 * Set the registers for this core based on entries in a list of Register Tables.
791 *
792 * Determine the platform features and this core's logical id. Get the specific table
793 * entry type implementations for the logical model, which may be either generic (the ones
794 * in this file) or specific.
795 *
796 * Scan the tables starting the with ones for all cores and progressively narrowing the selection
797 * based on this core's role (ex. primary core). For a selected table, check for each entry
798 * matching the current core and platform, and call the implementer method to perform the
799 * register set operation if it matches.
800 *
801 * @param[in] PlatformConfig Config handle for platform specific information
802 * @param[in] StdHeader Config handle for library and services.
803 *
804 */
805VOID
806SetRegistersFromTables (
807 IN PLATFORM_CONFIGURATION *PlatformConfig,
808 IN AMD_CONFIG_PARAMS *StdHeader
809 )
810{
811 CPU_LOGICAL_ID CpuLogicalId;
812 PLATFORM_FEATS PlatformFeatures;
813 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
814 TABLE_ENTRY_FIELDS *Entries;
815 TABLE_CORE_SELECTOR Selector;
816 TABLE_ENTRY_TYPE EntryType;
Arthur Heymans8d3640d2022-05-16 12:27:36 +0200817 CONST REGISTER_TABLE **TableHandle;
zbao7d94cf92012-07-02 14:19:14 +0800818 UINTN NumberOfEntries;
819 UINTN CurrentEntryCount;
820 TABLE_ENTRY_TYPE_DESCRIPTOR *TypeImplementer;
821 PF_DO_TABLE_ENTRY DoTableEntry[TableEntryTypeMax];
822
823 // Did you really mean to increase the size of ALL table entries??!!
824 // While it is not necessarily a bug to increase the size of table entries:
825 // - Is this warning a surprise? Please fix it.
826 // - If expected, is this really a feature which is worth the increase? Then let other entries also use the space.
827 ASSERT (sizeof (TABLE_ENTRY_DATA) == (MAX_ENTRY_TYPE_ITEMS32 * sizeof (UINT32)));
828
829 PlatformFeatures.PlatformValue = 0;
830 GetLogicalIdOfCurrentCore (&CpuLogicalId, StdHeader);
831 GetPlatformFeatures (&PlatformFeatures, PlatformConfig, StdHeader);
832 GetCpuServicesFromLogicalId (&CpuLogicalId, (CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
833
834 // Build a non-sparse table of implementer methods, so we don't have to keep searching.
835 // It is a bug to not include a descriptor for a type that is in the table (but the
836 // descriptor can point to a non-assert stub).
837 // Also, it is not a bug to have no register table implementations, but it is a bug to have none and call this routine.
838 for (EntryType = MsrRegister; EntryType < TableEntryTypeMax; EntryType++) {
839 DoTableEntry[EntryType] = (PF_DO_TABLE_ENTRY)CommonAssert;
840 }
841 TypeImplementer = FamilySpecificServices->TableEntryTypeDescriptors;
842 ASSERT (TypeImplementer != NULL);
843 while (TypeImplementer->EntryType < TableEntryTypeMax) {
844 DoTableEntry[TypeImplementer->EntryType] = TypeImplementer->DoTableEntry;
845 TypeImplementer++;
846 }
847
848 for (Selector = AllCores; Selector < TableCoreSelectorMax; Selector++) {
849 if (IsCoreSelector (Selector, StdHeader)) {
850 // If the current core is the selected type of core, work the table list for tables for that type of core.
851 TableHandle = NULL;
852 Entries = GetNextRegisterTable (FamilySpecificServices, Selector, &TableHandle, &NumberOfEntries, StdHeader);
853 while (Entries != NULL) {
854 for (CurrentEntryCount = 0; CurrentEntryCount < NumberOfEntries; CurrentEntryCount++, Entries++) {
855 if (DoesEntryMatchPlatform (CpuLogicalId, Entries->CpuRevision, PlatformFeatures, Entries->Features)) {
856 // The entry matches this config, Do It!
857 // Find the implementer for this entry type and pass the entry data to it.
858 ASSERT (Entries->EntryType < TableEntryTypeMax);
859 DoTableEntry[Entries->EntryType] (&Entries->Entry, PlatformConfig, StdHeader);
860 }
861 }
862 Entries = GetNextRegisterTable (FamilySpecificServices, Selector, &TableHandle, &NumberOfEntries, StdHeader);
863 }
864 } else {
865 // Once a selector does not match the current core, quit looking.
866 break;
867 }
868 }
869}
870
871/*---------------------------------------------------------------------------------------*/
872/**
873 * Set the registers for this core based on entries in a list of Register Tables.
874 *
875 * This function acts as a wrapper for calling the SetRegistersFromTables
876 * routine at AmdInitEarly.
877 *
878 * @param[in] FamilyServices The current Family Specific Services.
879 * @param[in] EarlyParams Service parameters.
880 * @param[in] StdHeader Config handle for library and services.
881 *
882 */
883VOID
884SetRegistersFromTablesAtEarly (
885 IN CPU_SPECIFIC_SERVICES *FamilyServices,
886 IN AMD_CPU_EARLY_PARAMS *EarlyParams,
887 IN AMD_CONFIG_PARAMS *StdHeader
888 )
889{
890 AGESA_TESTPOINT (TpProcCpuProcessRegisterTables, StdHeader);
891 SetRegistersFromTables (&EarlyParams->PlatformConfig, StdHeader);
892}