blob: 21d3e9bd8d3c6b7e3875654e188a17c1e0de005e [file] [log] [blame]
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * AMD CPU Core Leveling Function.
6 *
7 * Contains code to Level the number of core in a multi-socket system
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: CPU
12 * @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 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/*
49 *----------------------------------------------------------------------------
50 * MODULES USED
51 *
52 *----------------------------------------------------------------------------
53 */
54#include "AGESA.h"
55#include "AMD.h"
56#include "amdlib.h"
57#include "Topology.h"
58#include "cpuRegisters.h"
59#include "GeneralServices.h"
60#include "cpuServices.h"
61#include "cpuFamilyTranslation.h"
62#include "cpuFeatures.h"
63#include "cpuEarlyInit.h"
64#include "heapManager.h"
65#include "Filecode.h"
66CODE_GROUP (G1_PEICC)
67RDATA_GROUP (G1_PEICC)
68#define FILECODE PROC_CPU_FEATURE_CPUCORELEVELING_FILECODE
69/*----------------------------------------------------------------------------
70 * DEFINITIONS AND MACROS
71 *
72 *----------------------------------------------------------------------------
73 */
74
75
76/*----------------------------------------------------------------------------
77 * TYPEDEFS AND STRUCTURES
78 *
79 *----------------------------------------------------------------------------
80 */
81
82/*----------------------------------------------------------------------------------------
83 * E X P O R T E D F U N C T I O N S
84 *----------------------------------------------------------------------------------------
85 */
86extern CPU_FAMILY_SUPPORT_TABLE CoreLevelingFamilyServiceTable;
87
88/*----------------------------------------------------------------------------
89 * PROTOTYPES OF LOCAL FUNCTIONS
90 *
91 *----------------------------------------------------------------------------
92 */
93
94/*----------------------------------------------------------------------------------------
95 * P U B L I C F U N C T I O N S
96 *----------------------------------------------------------------------------------------
97 */
98
99/*---------------------------------------------------------------------------------------*/
100/**
101 * Should core leveling be enabled
102 *
103 * @param[in] PlatformConfig Contains the runtime modifiable feature input data.
104 * @param[in] StdHeader Config Handle for library, services.
105 *
106 * @retval TRUE core leveling is supported.
107 * @retval FALSE core leveling cannot be enabled.
108 *
109 */
110BOOLEAN
111STATIC
112IsCoreLevelingEnabled (
113 IN PLATFORM_CONFIGURATION *PlatformConfig,
114 IN AMD_CONFIG_PARAMS *StdHeader
115 )
116{
117 CORE_LEVELING_TYPE CoreLevelMode;
118
119 CoreLevelMode = (CORE_LEVELING_TYPE) PlatformConfig->CoreLevelingMode;
120 if (CoreLevelMode != CORE_LEVEL_NONE) {
121 return (TRUE);
122 } else {
123 return (FALSE);
124 }
125}
126
127/*---------------------------------------------------------------------------------------*/
128/**
129 * Performs core leveling for the system.
130 *
131 * This function implements the AMD_CPU_EARLY_PARAMS.CoreLevelingMode parameter.
132 * The possible modes are:
133 * -0 CORE_LEVEL_LOWEST Level to lowest common denominator
134 * -1 CORE_LEVEL_TWO Level to 2 cores
135 * -2 CORE_LEVEL_POWER_OF_TWO Level to 1,2,4 or 8
136 * -3 CORE_LEVEL_NONE Do no leveling
137 * -4 CORE_LEVEL_COMPUTE_UNIT Level cores to one core per compute unit
138 *
139 * @param[in] EntryPoint Timepoint designator.
140 * @param[in] PlatformConfig Contains the leveling mode parameter
141 * @param[in] StdHeader Config handle for library and services
142 *
143 * @return The most severe status of any family specific service.
144 *
145 */
146AGESA_STATUS
147CoreLevelingAtEarly (
148 IN UINT64 EntryPoint,
149 IN PLATFORM_CONFIGURATION *PlatformConfig,
150 IN AMD_CONFIG_PARAMS *StdHeader
151 )
152{
153 UINT32 CoreNumPerComputeUnit;
154 UINT32 MinNumOfComputeUnit;
155 UINT32 EnabledComputeUnit;
156 UINT32 Socket;
157 UINT32 Module;
158 UINT32 NumberOfSockets;
159 UINT32 NumberOfModules;
160 UINT32 MinCoreCountOnNode;
161 UINT32 MaxCoreCountOnNode;
162 UINT32 LowCore;
163 UINT32 HighCore;
164 UINT32 LeveledCores;
165 UINT32 RequestedCores;
166 UINT32 TotalEnabledCoresOnNode;
167 BOOLEAN RegUpdated;
168 AP_MAIL_INFO ApMailboxInfo;
169 CORE_LEVELING_TYPE CoreLevelMode;
170 CPU_CORE_LEVELING_FAMILY_SERVICES *FamilySpecificServices;
171 WARM_RESET_REQUEST Request;
172
173 MaxCoreCountOnNode = 0;
174 MinCoreCountOnNode = 0xFFFFFFFF;
175 LeveledCores = 0;
176 CoreNumPerComputeUnit = 1;
177 MinNumOfComputeUnit = 0xFF;
178
179 ASSERT (PlatformConfig->CoreLevelingMode < CoreLevelModeMax);
180
181 // Get OEM IO core level mode
182 CoreLevelMode = (CORE_LEVELING_TYPE) PlatformConfig->CoreLevelingMode;
183
184 // Get socket count
185 NumberOfSockets = GetPlatformNumberOfSockets ();
186 GetApMailbox (&ApMailboxInfo.Info, StdHeader);
187 NumberOfModules = ApMailboxInfo.Fields.ModuleType + 1;
188
189 // Collect cpu core info
190 for (Socket = 0; Socket < NumberOfSockets; Socket++) {
191 if (IsProcessorPresent (Socket, StdHeader)) {
192 for (Module = 0; Module < NumberOfModules; Module++) {
193 if (GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader)) {
194 // Get the highest and lowest core count in all nodes
195 TotalEnabledCoresOnNode = HighCore - LowCore + 1;
196 if (TotalEnabledCoresOnNode < MinCoreCountOnNode) {
197 MinCoreCountOnNode = TotalEnabledCoresOnNode;
198 }
199 if (TotalEnabledCoresOnNode > MaxCoreCountOnNode) {
200 MaxCoreCountOnNode = TotalEnabledCoresOnNode;
201 }
202 EnabledComputeUnit = TotalEnabledCoresOnNode;
203 switch (GetComputeUnitMapping (StdHeader)) {
204 case AllCoresMapping:
205 // All cores are in their own compute unit.
206 break;
207 case EvenCoresMapping:
208 // Cores are paired in compute units.
209 CoreNumPerComputeUnit = 2;
210 EnabledComputeUnit = (TotalEnabledCoresOnNode / 2);
211 break;
212 default:
213 ASSERT (FALSE);
214 }
215 // Get minimum of compute unit. This will either be the minimum number of cores (AllCoresMapping),
216 // or less (EvenCoresMapping).
217 if (EnabledComputeUnit < MinNumOfComputeUnit) {
218 MinNumOfComputeUnit = EnabledComputeUnit;
219 }
220 }
221 }
222 }
223 }
224
225 // Get LeveledCores
226 switch (CoreLevelMode) {
227 case CORE_LEVEL_LOWEST:
228 if (MinCoreCountOnNode == MaxCoreCountOnNode) {
229 return (AGESA_SUCCESS);
230 }
231 LeveledCores = (MinCoreCountOnNode / CoreNumPerComputeUnit) * CoreNumPerComputeUnit;
232 break;
233 case CORE_LEVEL_TWO:
234 LeveledCores = 2 / NumberOfModules;
235 if (LeveledCores != 0) {
236 LeveledCores = (LeveledCores <= MinCoreCountOnNode) ? LeveledCores : MinCoreCountOnNode;
237 } else {
238 return (AGESA_WARNING);
239 }
240 if ((LeveledCores * NumberOfModules) != 2) {
241 PutEventLog (
242 AGESA_WARNING,
243 CPU_WARNING_ADJUSTED_LEVELING_MODE,
244 2, (LeveledCores * NumberOfModules), 0, 0, StdHeader
245 );
246 }
247 break;
248 case CORE_LEVEL_POWER_OF_TWO:
249 // Level to power of 2 (1, 2, 4, 8...)
250 LeveledCores = 1;
251 while (MinCoreCountOnNode >= (LeveledCores * 2)) {
252 LeveledCores = LeveledCores * 2;
253 }
254 break;
255 case CORE_LEVEL_COMPUTE_UNIT:
256 // Level cores to one core per compute unit, with additional reduction to level
257 // all processors to match the processor with the minimum number of cores.
258 if (CoreNumPerComputeUnit == 1) {
259 // If there is one core per compute unit, this is the same as CORE_LEVEL_LOWEST.
260 if (MinCoreCountOnNode == MaxCoreCountOnNode) {
261 return (AGESA_SUCCESS);
262 }
263 LeveledCores = MinCoreCountOnNode;
264 } else {
265 // If there are more than one core per compute unit, level to the number of compute units.
266 LeveledCores = MinNumOfComputeUnit;
267 }
268 break;
269 case CORE_LEVEL_ONE:
270 LeveledCores = 1;
271 if (NumberOfModules > 1) {
272 PutEventLog (
273 AGESA_WARNING,
274 CPU_WARNING_ADJUSTED_LEVELING_MODE,
275 1, NumberOfModules, 0, 0, StdHeader
276 );
277 }
278 break;
279 case CORE_LEVEL_THREE:
280 case CORE_LEVEL_FOUR:
281 case CORE_LEVEL_FIVE:
282 case CORE_LEVEL_SIX:
283 case CORE_LEVEL_SEVEN:
284 case CORE_LEVEL_EIGHT:
285 case CORE_LEVEL_NINE:
286 case CORE_LEVEL_TEN:
287 case CORE_LEVEL_ELEVEN:
288 case CORE_LEVEL_TWELVE:
289 case CORE_LEVEL_THIRTEEN:
290 case CORE_LEVEL_FOURTEEN:
291 case CORE_LEVEL_FIFTEEN:
292 // MCM processors can not have an odd number of cores. For an odd CORE_LEVEL_N, MCM processors will be
293 // leveled as though CORE_LEVEL_N+1 was chosen.
294 // Processors with compute units disable all cores in an entire compute unit at a time, or on an MCM processor,
295 // two compute units at a time. For example, on an SCM processor with two cores per compute unit, the effective
296 // explicit levels are CORE_LEVEL_ONE, CORE_LEVEL_TWO, CORE_LEVEL_FOUR, CORE_LEVEL_SIX, and
297 // CORE_LEVEL_EIGHT. The same example for an MCM processor with two cores per compute unit has effective
298 // explicit levels of CORE_LEVEL_TWO, CORE_LEVEL_FOUR, CORE_LEVEL_EIGHT, and CORE_LEVEL_TWELVE.
299 RequestedCores = CoreLevelMode - CORE_LEVEL_THREE + 3;
300 LeveledCores = (RequestedCores + NumberOfModules - 1) / NumberOfModules;
301 LeveledCores = (LeveledCores / CoreNumPerComputeUnit) * CoreNumPerComputeUnit;
302 LeveledCores = (LeveledCores <= MinCoreCountOnNode) ? LeveledCores : MinCoreCountOnNode;
303 if (LeveledCores != 1) {
304 LeveledCores = (LeveledCores / CoreNumPerComputeUnit) * CoreNumPerComputeUnit;
305 }
306 if ((LeveledCores * NumberOfModules * CoreNumPerComputeUnit) != RequestedCores) {
307 PutEventLog (
308 AGESA_WARNING,
309 CPU_WARNING_ADJUSTED_LEVELING_MODE,
310 RequestedCores, (LeveledCores * NumberOfModules * CoreNumPerComputeUnit), 0, 0, StdHeader
311 );
312 }
313 break;
314 default:
315 ASSERT (FALSE);
316 }
317
318 // Set down core register
319 for (Socket = 0; Socket < NumberOfSockets; Socket++) {
320 if (IsProcessorPresent (Socket, StdHeader)) {
efdesign9884cbce22011-08-04 12:09:17 -0600321 GetFeatureServicesOfSocket (&CoreLevelingFamilyServiceTable, Socket, (const VOID **)&FamilySpecificServices, StdHeader);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000322 if (FamilySpecificServices != NULL) {
323 for (Module = 0; Module < NumberOfModules; Module++) {
324 RegUpdated = FamilySpecificServices->SetDownCoreRegister (FamilySpecificServices, &Socket, &Module, &LeveledCores, CoreLevelMode, StdHeader);
325 // If the down core register is updated, trigger a warm reset.
326 if (RegUpdated) {
327 GetWarmResetFlag (StdHeader, &Request);
328 Request.RequestBit = TRUE;
329 Request.StateBits = Request.PostStage - 1;
330 SetWarmResetFlag (StdHeader, &Request);
331 }
332 }
333 }
334 }
335 }
336
337 return (AGESA_SUCCESS);
338}
339
340
341CONST CPU_FEATURE_DESCRIPTOR ROMDATA CpuFeatureCoreLeveling =
342{
343 CoreLeveling,
344 (CPU_FEAT_AFTER_PM_INIT),
345 IsCoreLevelingEnabled,
346 CoreLevelingAtEarly
347};
348
349/*----------------------------------------------------------------------------------------
350 * L O C A L F U N C T I O N S
351 *----------------------------------------------------------------------------------------
352 */
353