AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / CPU / cpuMicrocodePatch.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * AMD CPU Microcode Patch Related Functions
6  *
7  * Contains code to program a microcode into the CPU
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  CPU
12  * @e \$Revision: 56322 $   @e \$Date: 2011-07-11 16:51:42 -0600 (Mon, 11 Jul 2011) $
13  *
14  */
15 /*
16  ******************************************************************************
17  *
18  * Copyright (C) 2012 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  *                            M O D U L E S    U S E D
48  *---------------------------------------------------------------------------------------
49  */
50 #include "AGESA.h"
51 #include "amdlib.h"
52 #include "Ids.h"
53 #include "cpuRegisters.h"
54 #include "cpuFamilyTranslation.h"
55 #include "cpuEarlyInit.h"
56 #include "GeneralServices.h"
57 #include "cpuServices.h"
58 #include "Filecode.h"
59 CODE_GROUP (G1_PEICC)
60 RDATA_GROUP (G2_PEI)
61
62 #define FILECODE PROC_CPU_CPUMICROCODEPATCH_FILECODE
63 /*----------------------------------------------------------------------------------------
64  *                   D E F I N I T I O N S    A N D    M A C R O S
65  *----------------------------------------------------------------------------------------
66  */
67
68
69 /*----------------------------------------------------------------------------------------
70  *                  T Y P E D E F S     A N D     S T R U C T U R E S
71  *----------------------------------------------------------------------------------------
72  */
73 typedef union {
74   UINT64           RawData;
75   PATCH_LOADER_MSR BitFields;
76 } PATCH_LOADER;
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 BOOLEAN
83 LoadMicrocode (
84   IN       MICROCODE_PATCH    *MicrocodePatchPtr,
85   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
86   );
87
88 VOID
89 LoadMicrocodePatchAtEarly (
90   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
91   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
92   IN       AMD_CONFIG_PARAMS      *StdHeader
93   );
94
95 /*----------------------------------------------------------------------------------------
96  *                          E X P O R T E D    F U N C T I O N S
97  *----------------------------------------------------------------------------------------
98  */
99
100
101 /* -----------------------------------------------------------------------------*/
102 /**
103  *  Update microcode patch in current processor.
104  *
105  *  Then reads the patch id, and compare it to the expected, in the Microprocessor
106  *  patch block.
107  *
108  *  @param[in] StdHeader   - Config handle for library and services.
109  *
110  *  @retval    TRUE   - Patch Loaded Successfully.
111  *  @retval    FALSE  - Patch Did Not Get Loaded.
112  *
113  */
114 BOOLEAN
115 LoadMicrocodePatch (
116   IN OUT   AMD_CONFIG_PARAMS *StdHeader
117   )
118 {
119   UINT8    PatchNumber;
120   UINT8    TotalPatches;
121   UINT16   ProcessorEquivalentId;
122   BOOLEAN  Status;
123   MICROCODE_PATCH **MicrocodePatchPtr;
124   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
125
126   Status = FALSE;
127
128   if (IsCorePairPrimary (FirstCoreIsComputeUnitPrimary, StdHeader)) {
129     // Get the patch pointer
130     GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
131     FamilySpecificServices->GetMicroCodePatchesStruct (FamilySpecificServices, (const VOID **) &MicrocodePatchPtr, &TotalPatches, StdHeader);
132
133     IDS_OPTION_HOOK (IDS_UCODE, &TotalPatches, StdHeader);
134
135     // Get the processor microcode path equivalent ID
136     if (GetPatchEquivalentId (&ProcessorEquivalentId, StdHeader)) {
137       // parse the patch table to see if we have one for the current cpu
138       for (PatchNumber = 0; PatchNumber < TotalPatches; PatchNumber++) {
139         if (ValidateMicrocode (MicrocodePatchPtr[PatchNumber], ProcessorEquivalentId, StdHeader)) {
140           if (LoadMicrocode (MicrocodePatchPtr[PatchNumber], StdHeader)) {
141             Status = TRUE;
142           } else {
143             PutEventLog (AGESA_ERROR,
144                          CPU_ERROR_MICRO_CODE_PATCH_IS_NOT_LOADED,
145                          0, 0, 0, 0, StdHeader);
146           }
147           break; // Once we find a microcode patch that matches the processor, exit the for loop
148         }
149       }
150     }
151   }
152   return Status;
153 }
154
155 /*---------------------------------------------------------------------------------------
156  *                           L O C A L    F U N C T I O N S
157  *---------------------------------------------------------------------------------------
158  */
159
160 /* -----------------------------------------------------------------------------*/
161 /**
162  *
163  *  LoadMicrocode
164  *
165  *    Update microcode patch in current processor, then reads the
166  *    patch id, and compare it to the expected, in the Microprocessor
167  *    patch block.
168  *
169  *    @param[in]       MicrocodePatchPtr  - Pointer to Microcode Patch.
170  *    @param[in,out]   StdHeader          - Pointer to AMD_CONFIG_PARAMS struct.
171  *
172  *    @retval          TRUE  - Patch Loaded Successfully.
173  *    @retval          FALSE - Patch Did Not Get Loaded.
174  *
175  */
176 BOOLEAN
177 LoadMicrocode (
178   IN       MICROCODE_PATCH    *MicrocodePatchPtr,
179   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
180   )
181 {
182   UINT32       MicrocodeVersion;
183   PATCH_LOADER PatchLoaderMsr;
184
185   // Load microcode patch into CPU
186   PatchLoaderMsr.RawData = (UINT64) MicrocodePatchPtr;
187   PatchLoaderMsr.BitFields.SBZ = 0;
188   LibAmdMsrWrite (MSR_PATCH_LOADER, &PatchLoaderMsr.RawData, StdHeader);
189
190   // Do ucode patch Authentication
191   // Read microcode version back from CPU, determine if
192   // it is the same patch level as contained in the source
193   // microprocessor patch block passed in
194   GetMicrocodeVersion (&MicrocodeVersion, StdHeader);
195   if (MicrocodeVersion == MicrocodePatchPtr->PatchID) {
196     return (TRUE);
197   } else {
198     return (FALSE);
199   }
200 }
201
202
203 /* -----------------------------------------------------------------------------*/
204 /**
205  *
206  *  GetPatchEquivalentId
207  *
208  *    Return the equivalent ID for microcode patching
209  *
210  *    @param[in,out]   ProcessorEquivalentId   - Pointer to Processor Equivalent ID table.
211  *    @param[in,out]   StdHeader               - Pointer to AMD_CONFIG_PARAMS struct.
212  *
213  *    @retval          TRUE  - ID Found.
214  *    @retval          FALSE - ID Not Found.
215  *
216  */
217 BOOLEAN
218 GetPatchEquivalentId (
219   IN OUT   UINT16             *ProcessorEquivalentId,
220   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
221   )
222 {
223   UINT8        i;
224   UINT8        EquivalencyEntries;
225   UINT16       ProcessorRevisionId;
226   UINT16       *MicrocodeEquivalenceTable;
227   CPUID_DATA   CpuIdData;
228   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
229
230   //
231   // compute the processor revision ID
232   //
233   LibAmdCpuidRead (AMD_CPUID_FMF, &CpuIdData, StdHeader);
234   // high byte contains extended model and extended family
235   ProcessorRevisionId  = (UINT16) ((CpuIdData.EAX_Reg & (CPU_EMODEL | CPU_EFAMILY)) >> 8);
236   // low byte contains model and family
237   ProcessorRevisionId |= (CpuIdData.EAX_Reg & (CPU_STEPPING | CPU_MODEL));
238
239   //
240   // find the equivalent ID for microcode purpose using the equivalence table
241   //
242   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
243
244   FamilySpecificServices->GetMicrocodeEquivalenceTable (FamilySpecificServices,
245                                                         (CONST VOID **) &MicrocodeEquivalenceTable,
246                                                         &EquivalencyEntries,
247                                                         StdHeader);
248
249   // parse the equivalence table
250   for (i = 0; i < (EquivalencyEntries * 2); i += 2) {
251     // check for equivalence
252     if (ProcessorRevisionId == MicrocodeEquivalenceTable[i]) {
253       *ProcessorEquivalentId = MicrocodeEquivalenceTable[i + 1];
254       return (TRUE);
255     }
256   }
257   // end of table reach, this processor is not supported
258   *ProcessorEquivalentId = 0x0000;
259   return (FALSE);
260 }
261
262 /*---------------------------------------------------------------------------------------*/
263 /**
264  *
265  *  ValidateMicrocode
266  *
267  *    Determine if the microcode patch block, currently pointed to
268  *    is valid, and is appropriate for the current processor
269
270  *    @param[in]       MicrocodePatchPtr      - Pointer to Microcode Patch.
271  *    @param[in]       ProcessorEquivalentId  - Pointer to Processor Equivalent ID table.
272  *    @param[in,out]   StdHeader              - Pointer to AMD_CONFIG_PARAMS struct.
273  *
274  *    @retval          TRUE  - Patch Found.
275  *    @retval          FALSE - Patch Not Found.
276  *
277  */
278 BOOLEAN
279 ValidateMicrocode (
280   IN       MICROCODE_PATCH    *MicrocodePatchPtr,
281   IN       UINT16             ProcessorEquivalentId,
282   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
283   )
284 {
285   BOOLEAN   Chipset1Matched;
286   BOOLEAN   Chipset2Matched;
287   PCI_ADDR  PciAddress;
288   UINT32    PciDeviceVidDid;
289   UINT8     PciDeviceRevision;
290   UINT8     DevCount;
291   UINT8     FunCount;
292   UINT32    Chipset1DeviceID;
293   UINT32    Chipset2DeviceID;
294   UINT8     MulitFunction;
295
296   Chipset1Matched = FALSE;
297   Chipset2Matched = FALSE;
298   PciDeviceVidDid = 0;
299   PciDeviceRevision = 0;
300   Chipset1DeviceID = MicrocodePatchPtr->Chipset1DeviceID;
301   Chipset2DeviceID = MicrocodePatchPtr->Chipset2DeviceID;
302   MulitFunction = 0;
303
304   //
305   // parse the supplied microcode to see if it is compatible with the processor
306   //
307   if (MicrocodePatchPtr->ProcessorRevisionID !=  ProcessorEquivalentId) {
308     return (FALSE);
309   }
310
311   if (Chipset1DeviceID == 0) {
312     Chipset1Matched = TRUE;
313   }
314   if (Chipset2DeviceID == 0) {
315     Chipset2Matched = TRUE;
316   }
317
318   if ((!Chipset1Matched) || (!Chipset2Matched)) {
319     //
320     // Scan all PCI devices in Bus 0, try to find out matched case.
321     //
322     for (DevCount = 0; DevCount < 32; DevCount++) {
323       for (FunCount = 0; FunCount < 8; FunCount++) {
324         PciAddress.AddressValue = MAKE_SBDFO (0, 0, DevCount, FunCount, 0);
325         LibAmdPciRead (AccessWidth32, PciAddress, &PciDeviceVidDid, StdHeader);
326         if (PciDeviceVidDid == 0xFFFFFFFF) {
327           if (FunCount == 0) {
328             break;
329           } else {
330             continue;
331           }
332         }
333         PciAddress.Address.Register = 0x8;
334         LibAmdPciRead (AccessWidth8, PciAddress, &PciDeviceRevision, StdHeader);
335         if ((!Chipset1Matched) && (PciDeviceVidDid == Chipset1DeviceID)) {
336           if (PciDeviceRevision == MicrocodePatchPtr->Chipset1RevisionID) {
337             Chipset1Matched = TRUE;
338           }
339         }
340         if ((!Chipset2Matched) && (PciDeviceVidDid == Chipset2DeviceID)) {
341           if (PciDeviceRevision == MicrocodePatchPtr->Chipset2RevisionID) {
342             Chipset2Matched = TRUE;
343           }
344         }
345         if (Chipset1Matched && Chipset2Matched) {
346           break;
347         }
348         //
349         // Check multi-function. If it doesen't exist, we don't have to loop functions to 7.
350         //
351         if (FunCount == 0) {
352           MulitFunction = 0;
353           PciAddress.Address.Register = 0xE;
354           LibAmdPciRead (AccessWidth8, PciAddress, &MulitFunction, StdHeader);
355           if ((MulitFunction & 0x80) == 0) {
356             break;
357           }
358         }
359       } // end FunCount for loop.
360
361       if (Chipset1Matched && Chipset2Matched) {
362         break;
363       }
364     }  // end DevCount for loop.
365   }
366
367   return (Chipset1Matched && Chipset2Matched);
368 }
369
370
371 /*---------------------------------------------------------------------------------------*/
372 /**
373  *
374  *  GetMicrocodeVersion
375  *
376  *    Return the version of the currently loaded microcode patch, if any.
377  *    Read from the patch level MSR, return the value in eax. If no patch
378  *    has been loaded, 0 will be returned.
379  *
380  *    @param[out]      pMicrocodeVersion  - Pointer to Microcode Version.
381  *    @param[in,out]   StdHeader          - Pointer to AMD_CONFIG_PARAMS struct.
382  *
383  */
384 VOID
385 GetMicrocodeVersion (
386      OUT   UINT32             *pMicrocodeVersion,
387   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
388   )
389 {
390   UINT64  MsrData;
391
392   MsrData = 0;
393   LibAmdMsrRead (MSR_PATCH_LEVEL, &MsrData, StdHeader);
394
395   *pMicrocodeVersion = (UINT32) MsrData;
396 }
397
398
399 /*---------------------------------------------------------------------------------------*/
400 /**
401  * Update microcode patch in current processor.
402  *
403  * This function acts as a wrapper for calling the LoadMicrocodePatch
404  * routine at AmdInitEarly.
405  *
406  *  @param[in]   FamilyServices      The current Family Specific Services.
407  *  @param[in]   EarlyParams         Service parameters.
408  *  @param[in]   StdHeader           Config handle for library and services.
409  *
410  */
411 VOID
412 LoadMicrocodePatchAtEarly (
413   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
414   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
415   IN       AMD_CONFIG_PARAMS      *StdHeader
416   )
417 {
418   AGESA_TESTPOINT (TpProcCpuLoadUcode, StdHeader);
419   LoadMicrocodePatch (StdHeader);
420 }