Add constants for fast path resume copying
[coreboot.git] / src / vendorcode / amd / agesa / f14 / Proc / CPU / cpuPowerMgmtMultiSocket.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * AMD CPU Power Management Multisocket Functions.
6  *
7  * Contains code for doing power management for multisocket CPUs
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.
20  * 
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions are met:
23  *     * Redistributions of source code must retain the above copyright
24  *       notice, this list of conditions and the following disclaimer.
25  *     * Redistributions in binary form must reproduce the above copyright
26  *       notice, this list of conditions and the following disclaimer in the
27  *       documentation and/or other materials provided with the distribution.
28  *     * Neither the name of Advanced Micro Devices, Inc. nor the names of 
29  *       its contributors may be used to endorse or promote products derived 
30  *       from this software without specific prior written permission.
31  * 
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35  * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  * 
43  * ***************************************************************************
44  *
45  */
46
47 /*----------------------------------------------------------------------------------------
48  *                             M O D U L E S    U S E D
49  *----------------------------------------------------------------------------------------
50  */
51
52 #include "AGESA.h"
53 #include "amdlib.h"
54 #include "Ids.h"
55 #include "cpuRegisters.h"
56 #include "GeneralServices.h"
57 #include "cpuServices.h"
58 #include "cpuApicUtilities.h"
59 #include "cpuFamilyTranslation.h"
60 #include "cpuPowerMgmtSystemTables.h"
61 #include "cpuPowerMgmtMultiSocket.h"
62 #include "GeneralServices.h"
63 #include "Filecode.h"
64 CODE_GROUP (G1_PEICC)
65 RDATA_GROUP (G1_PEICC)
66
67 #define FILECODE PROC_CPU_CPUPOWERMGMTMULTISOCKET_FILECODE
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  */
82 VOID
83 STATIC
84 GetNextEvent (
85   IN OUT   VOID  *EventLogEntryPtr,
86   IN       AMD_CONFIG_PARAMS *StdHeader
87   );
88
89 AGESA_STATUS
90 GetEarlyPmErrorsMulti (
91   IN       AMD_CONFIG_PARAMS *StdHeader
92   );
93
94 /*----------------------------------------------------------------------------------------
95  *                          E X P O R T E D    F U N C T I O N S
96  *----------------------------------------------------------------------------------------
97  */
98
99 /*---------------------------------------------------------------------------------------*/
100 /**
101  * Multisocket BSC call to start all system core 0s to perform a standard AP_TASK.
102  *
103  * This function loops through all possible socket locations, starting core 0 of
104  * each populated socket to perform the passed in AP_TASK.  After starting all
105  * other core 0s, the BSC will perform the AP_TASK as well.  This must be run by
106  * the system BSC only.
107  *
108  * @param[in]  TaskPtr           Function descriptor
109  * @param[in]  StdHeader         Config handle for library and services
110  * @param[in]  ConfigParams      AMD entry point's CPU parameter structure
111  *
112  */
113 VOID
114 RunCodeOnAllSystemCore0sMulti (
115   IN       AP_TASK *TaskPtr,
116   IN       AMD_CONFIG_PARAMS *StdHeader,
117   IN       VOID *ConfigParams
118   )
119 {
120   UINT32 BscSocket;
121   UINT32 BscModule;
122   UINT32 BscCoreNum;
123   UINT8  Socket;
124   UINT32 NumberOfSockets;
125   AGESA_STATUS DummyStatus;
126
127   ASSERT (IsBsp (StdHeader, &DummyStatus));
128
129   NumberOfSockets = GetPlatformNumberOfSockets ();
130
131   IdentifyCore (StdHeader, &BscSocket, &BscModule, &BscCoreNum, &DummyStatus);
132
133   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
134     if (Socket != BscSocket) {
135       if (IsProcessorPresent (Socket, StdHeader)) {
136         ApUtilRunCodeOnSocketCore (Socket, 0, TaskPtr, StdHeader);
137       }
138     }
139   }
140   ApUtilTaskOnExecutingCore (TaskPtr, StdHeader, ConfigParams);
141 }
142
143
144 /*---------------------------------------------------------------------------------------*/
145 /**
146  * Multisocket BSC call to determine the maximum number of steps that any single
147  * processor needs to execute.
148  *
149  * This function loops through all possible socket locations, gathering the number
150  * of power management steps each populated socket requires, and returns the
151  * highest number.
152  *
153  * @param[out] NumSystemSteps    Maximum number of system steps required
154  * @param[in]  StdHeader         Config handle for library and services
155  *
156  */
157 VOID
158 GetNumberOfSystemPmStepsPtrMulti (
159      OUT   UINT8 *NumSystemSteps,
160   IN       AMD_CONFIG_PARAMS *StdHeader
161   )
162 {
163   UINT8  NumberOfSteps;
164   UINT32 NumberOfSockets;
165   UINT32 Socket;
166   SYS_PM_TBL_STEP *Ignored;
167   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
168
169   NumberOfSockets = GetPlatformNumberOfSockets ();
170   *NumSystemSteps = 0;
171
172   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
173     if (IsProcessorPresent (Socket, StdHeader)) {
174       GetCpuServicesOfSocket (Socket, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
175       FamilySpecificServices->GetSysPmTableStruct (FamilySpecificServices, (const VOID **)&Ignored, &NumberOfSteps, StdHeader);
176       if (NumberOfSteps > *NumSystemSteps) {
177         *NumSystemSteps = NumberOfSteps;
178       }
179     }
180   }
181 }
182
183
184 /*---------------------------------------------------------------------------------------*/
185 /**
186  * Multisocket call to determine the frequency that the northbridges must run.
187  *
188  * This function loops through all possible socket locations, comparing the
189  * maximum NB frequencies to determine the slowest.  This function also
190  * determines if all coherent NB frequencies are equivalent.
191  *
192  * @param[in]  NbPstate                    NB P-state number to check (0 = fastest)
193  * @param[in]  PlatformConfig              Platform profile/build option config structure.
194  * @param[out] SystemNbCofNumerator        NB frequency numerator for the system in MHz
195  * @param[out] SystemNbCofDenominator      NB frequency denominator for the system
196  * @param[out] SystemNbCofsMatch           Whether or not all NB frequencies are equivalent
197  * @param[out] NbPstateIsEnabledOnAllCPUs  Whether or not NbPstate is valid on all CPUs
198  * @param[in]  StdHeader                   Config handle for library and services
199  *
200  * @retval     TRUE                        At least one processor has NbPstate enabled.
201  * @retval     FALSE                       NbPstate is disabled on all CPUs
202  *
203  */
204 BOOLEAN
205 GetSystemNbCofMulti (
206   IN       UINT32 NbPstate,
207   IN       PLATFORM_CONFIGURATION *PlatformConfig,
208      OUT   UINT32 *SystemNbCofNumerator,
209      OUT   UINT32 *SystemNbCofDenominator,
210      OUT   BOOLEAN *SystemNbCofsMatch,
211      OUT   BOOLEAN *NbPstateIsEnabledOnAllCPUs,
212   IN       AMD_CONFIG_PARAMS *StdHeader
213   )
214 {
215   UINT32   Socket;
216   UINT8    Module;
217   UINT32   CurrentNbCof;
218   UINT32   CurrentDivisor;
219   UINT32   CurrentFreq;
220   UINT32   LowFrequency;
221   UINT32   Ignored32;
222   BOOLEAN  FirstCofNotFound;
223   BOOLEAN  NbPstateDisabled;
224   BOOLEAN  IsNbPstateEnabledOnAny;
225   PCI_ADDR PciAddress;
226   AGESA_STATUS Ignored;
227   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
228
229   // Find the slowest NB COF in the system & whether or not all are equivalent
230   LowFrequency = 0xFFFFFFFF;
231   *SystemNbCofsMatch = TRUE;
232   *NbPstateIsEnabledOnAllCPUs = FALSE;
233   IsNbPstateEnabledOnAny = FALSE;
234   FirstCofNotFound = TRUE;
235   NbPstateDisabled = FALSE;
236   for (Socket = 0; Socket < GetPlatformNumberOfSockets (); Socket++) {
237     if (IsProcessorPresent (Socket, StdHeader)) {
238       GetCpuServicesOfSocket (Socket, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
239       for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
240         if (GetPciAddress (StdHeader, Socket, Module, &PciAddress, &Ignored)) {
241           break;
242         }
243       }
244       if (FamilySpecificServices->GetNbPstateInfo (FamilySpecificServices,
245                                                    PlatformConfig,
246                                                    &PciAddress,
247                                                    NbPstate,
248                                                    &CurrentNbCof,
249                                                    &CurrentDivisor,
250                                                    &Ignored32,
251                                                    StdHeader)) {
252         ASSERT (CurrentDivisor != 0);
253         CurrentFreq = (CurrentNbCof / CurrentDivisor);
254         if (FirstCofNotFound) {
255           *SystemNbCofNumerator = CurrentNbCof;
256           *SystemNbCofDenominator = CurrentDivisor;
257           LowFrequency = CurrentFreq;
258           IsNbPstateEnabledOnAny = TRUE;
259           if (!NbPstateDisabled) {
260             *NbPstateIsEnabledOnAllCPUs = TRUE;
261           }
262           FirstCofNotFound = FALSE;
263         } else {
264           if (CurrentFreq != LowFrequency) {
265             *SystemNbCofsMatch = FALSE;
266             if (CurrentFreq < LowFrequency) {
267               LowFrequency = CurrentFreq;
268               *SystemNbCofNumerator = CurrentNbCof;
269               *SystemNbCofDenominator = CurrentDivisor;
270             }
271           }
272         }
273       } else {
274         NbPstateDisabled = TRUE;
275         *NbPstateIsEnabledOnAllCPUs = FALSE;
276       }
277     }
278   }
279   return IsNbPstateEnabledOnAny;
280 }
281
282
283 /*---------------------------------------------------------------------------------------*/
284 /**
285  * Multisocket call to determine if the BIOS is responsible for updating the
286  * northbridge operating frequency and voltage.
287  *
288  * This function loops through all possible socket locations, checking whether
289  * any populated sockets require NB COF VID programming.
290  *
291  * @param[in]  StdHeader         Config handle for library and services
292  *
293  * @retval     TRUE    BIOS needs to set up NB frequency and voltage
294  * @retval     FALSE   BIOS does not need to set up NB frequency and voltage
295  *
296  */
297 BOOLEAN
298 GetSystemNbCofVidUpdateMulti (
299   IN       AMD_CONFIG_PARAMS *StdHeader
300   )
301 {
302   UINT8    Module;
303   UINT32   Socket;
304   UINT32   NumberOfSockets;
305   BOOLEAN  IgnoredBool;
306   BOOLEAN  AtLeast1RequiresUpdate;
307   PCI_ADDR PciAddress;
308   AGESA_STATUS Ignored;
309   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
310
311   NumberOfSockets = GetPlatformNumberOfSockets ();
312
313   AtLeast1RequiresUpdate = FALSE;
314   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
315     if (IsProcessorPresent (Socket, StdHeader)) {
316       GetCpuServicesOfSocket (Socket, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
317       for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
318         if (GetPciAddress (StdHeader, (UINT8) Socket, Module, &PciAddress, &Ignored)) {
319           break;
320         }
321       }
322       if (FamilySpecificServices->IsNbCofInitNeeded (FamilySpecificServices, &PciAddress, &IgnoredBool, StdHeader)) {
323         AtLeast1RequiresUpdate = TRUE;
324         break;
325       }
326     }
327   }
328   return AtLeast1RequiresUpdate;
329 }
330
331
332 /*---------------------------------------------------------------------------------------*/
333 /**
334  * Multisocket call to determine the most severe AGESA_STATUS return value after
335  * processing the power management initialization tables.
336  *
337  * This function loops through all possible socket locations, collecting any
338  * power management initialization errors that may have occurred.  These errors
339  * are transferred from the core 0s of the socket in which the errors occurred
340  * to the BSC's heap.  The BSC's heap is then searched for the most severe error
341  * that occurred, and returns it.  This function must be called by the BSC only.
342  *
343  * @param[in]  StdHeader         Config handle for library and services
344  *
345  * @return     The most severe error code from power management init
346  *
347  */
348 AGESA_STATUS
349 GetEarlyPmErrorsMulti (
350   IN       AMD_CONFIG_PARAMS *StdHeader
351   )
352 {
353   UINT16 i;
354   UINT32 BscSocket;
355   UINT32 BscModule;
356   UINT32 BscCoreNum;
357   UINT32 Socket;
358   UINT32 NumberOfSockets;
359   AP_TASK      TaskPtr;
360   AGESA_EVENT  EventLogEntry;
361   AGESA_STATUS ReturnCode;
362   AGESA_STATUS DummyStatus;
363
364   ASSERT (IsBsp (StdHeader, &ReturnCode));
365
366   ReturnCode = AGESA_SUCCESS;
367   EventLogEntry.EventClass = AGESA_SUCCESS;
368   EventLogEntry.EventInfo = 0;
369   EventLogEntry.DataParam1 = 0;
370   EventLogEntry.DataParam2 = 0;
371   EventLogEntry.DataParam3 = 0;
372   EventLogEntry.DataParam4 = 0;
373
374   NumberOfSockets = GetPlatformNumberOfSockets ();
375   IdentifyCore (StdHeader, &BscSocket, &BscModule, &BscCoreNum, &DummyStatus);
376
377   TaskPtr.FuncAddress.PfApTaskI = GetNextEvent;
378   TaskPtr.DataTransfer.DataSizeInDwords = SIZE_IN_DWORDS (AGESA_EVENT);
379   TaskPtr.DataTransfer.DataPtr = &EventLogEntry;
380   TaskPtr.DataTransfer.DataTransferFlags = 0;
381   TaskPtr.ExeFlags = WAIT_FOR_CORE | RETURN_PARAMS;
382   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
383     if (Socket != BscSocket) {
384       if (IsProcessorPresent (Socket, StdHeader)) {
385         do {
386           ApUtilRunCodeOnSocketCore ((UINT8)Socket, (UINT8) 0, &TaskPtr, StdHeader);
387           if ((EventLogEntry.EventInfo & CPU_EVENT_PM_EVENT_MASK) == CPU_EVENT_PM_EVENT_CLASS) {
388             PutEventLog (
389               EventLogEntry.EventClass,
390               EventLogEntry.EventInfo,
391               EventLogEntry.DataParam1,
392               EventLogEntry.DataParam2,
393               EventLogEntry.DataParam3,
394               EventLogEntry.DataParam4,
395               StdHeader
396               );
397           }
398         } while (EventLogEntry.EventInfo != 0);
399       }
400     }
401   }
402
403   for (i = 0; PeekEventLog (&EventLogEntry, i, StdHeader); i++) {
404     if ((EventLogEntry.EventInfo & CPU_EVENT_PM_EVENT_MASK) == CPU_EVENT_PM_EVENT_CLASS) {
405       if (EventLogEntry.EventClass > ReturnCode) {
406         ReturnCode = EventLogEntry.EventClass;
407       }
408     }
409   }
410   return (ReturnCode);
411 }
412
413 /*---------------------------------------------------------------------------------------
414  *                           L O C A L    F U N C T I O N S
415  *---------------------------------------------------------------------------------------
416  */
417
418 /*---------------------------------------------------------------------------------------*/
419 /**
420  * AP task to return the next event log entry to the BSC.
421  *
422  * This function calls to the event log manager to retrieve the next error out
423  * of the heap.
424  *
425  * @param[out] EventLogEntryPtr  The AP's next event log entry
426  * @param[in]  StdHeader         Config handle for library and services
427  *
428  */
429 VOID
430 STATIC
431 GetNextEvent (
432   IN OUT   VOID  *EventLogEntryPtr,
433   IN       AMD_CONFIG_PARAMS *StdHeader
434   )
435 {
436   GetEventLog ((AGESA_EVENT *) EventLogEntryPtr, StdHeader);
437 }