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