aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/cpu/microcode/amd.c78
1 files changed, 18 insertions, 60 deletions
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index 2a194e384207..5e1b57747c2f 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -45,14 +45,14 @@ static struct equiv_cpu_entry *equiv_cpu_table;
45 * save from the initrd/builtin before jettisoning its contents. @mc is the 45 * save from the initrd/builtin before jettisoning its contents. @mc is the
46 * microcode patch we found to match. 46 * microcode patch we found to match.
47 */ 47 */
48static struct cont_desc { 48struct cont_desc {
49 struct microcode_amd *mc; 49 struct microcode_amd *mc;
50 u32 cpuid_1_eax; 50 u32 cpuid_1_eax;
51 u32 psize; 51 u32 psize;
52 u16 eq_id; 52 u16 eq_id;
53 u8 *data; 53 u8 *data;
54 size_t size; 54 size_t size;
55} cont; 55};
56 56
57static u32 ucode_new_rev; 57static u32 ucode_new_rev;
58static u8 amd_ucode_patch[PATCH_MAX_SIZE]; 58static u8 amd_ucode_patch[PATCH_MAX_SIZE];
@@ -201,8 +201,7 @@ static int __apply_microcode_amd(struct microcode_amd *mc)
201 * Returns true if container found (sets @desc), false otherwise. 201 * Returns true if container found (sets @desc), false otherwise.
202 */ 202 */
203static bool 203static bool
204apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, 204apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch)
205 bool save_patch, struct cont_desc *ret_desc)
206{ 205{
207 struct cont_desc desc = { 0 }; 206 struct cont_desc desc = { 0 };
208 u8 (*patch)[PATCH_MAX_SIZE]; 207 u8 (*patch)[PATCH_MAX_SIZE];
@@ -240,9 +239,6 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size,
240 memcpy(patch, mc, min_t(u32, desc.psize, PATCH_MAX_SIZE)); 239 memcpy(patch, mc, min_t(u32, desc.psize, PATCH_MAX_SIZE));
241 } 240 }
242 241
243 if (ret_desc)
244 *ret_desc = desc;
245
246 return ret; 242 return ret;
247} 243}
248 244
@@ -292,79 +288,41 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax)
292 struct cpio_data cp = { }; 288 struct cpio_data cp = { };
293 289
294 __load_ucode_amd(cpuid_1_eax, &cp); 290 __load_ucode_amd(cpuid_1_eax, &cp);
295
296 if (!(cp.data && cp.size)) 291 if (!(cp.data && cp.size))
297 return; 292 return;
298 293
299 apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, true, NULL); 294 apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, true);
300} 295}
301 296
302void load_ucode_amd_ap(unsigned int cpuid_1_eax) 297void load_ucode_amd_ap(unsigned int cpuid_1_eax)
303{ 298{
304 struct equiv_cpu_entry *eq;
305 struct microcode_amd *mc; 299 struct microcode_amd *mc;
306 struct cont_desc *desc; 300 struct cpio_data cp;
307 u16 eq_id; 301 u32 *new_rev, rev, dummy;
308 302
309 if (IS_ENABLED(CONFIG_X86_32)) { 303 if (IS_ENABLED(CONFIG_X86_32)) {
310 mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch); 304 mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch);
311 desc = (struct cont_desc *)__pa_nodebug(&cont); 305 new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
312 } else { 306 } else {
313 mc = (struct microcode_amd *)amd_ucode_patch; 307 mc = (struct microcode_amd *)amd_ucode_patch;
314 desc = &cont; 308 new_rev = &ucode_new_rev;
315 } 309 }
316 310
317 /* First AP hasn't cached it yet, go through the blob. */ 311 native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
318 if (!desc->data) {
319 struct cpio_data cp = { };
320
321 if (desc->size == -1)
322 return;
323
324reget:
325 __load_ucode_amd(cpuid_1_eax, &cp);
326 if (!(cp.data && cp.size)) {
327 /*
328 * Mark it so that other APs do not scan again for no
329 * real reason and slow down boot needlessly.
330 */
331 desc->size = -1;
332 return;
333 }
334 312
335 if (!apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, false, desc)) { 313 /* Check whether we have saved a new patch already: */
336 desc->data = NULL; 314 if (*new_rev && rev < mc->hdr.patch_id) {
337 desc->size = -1; 315 if (!__apply_microcode_amd(mc)) {
316 *new_rev = mc->hdr.patch_id;
338 return; 317 return;
339 } 318 }
340 } 319 }
341 320
342 eq = (struct equiv_cpu_entry *)(desc->data + CONTAINER_HDR_SZ); 321 __load_ucode_amd(cpuid_1_eax, &cp);
343 322 if (!(cp.data && cp.size))
344 eq_id = find_equiv_id(eq, cpuid_1_eax);
345 if (!eq_id)
346 return; 323 return;
347 324
348 if (eq_id == desc->eq_id) { 325 apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, false);
349 u32 rev, dummy;
350
351 native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
352
353 mc = (struct microcode_amd *)amd_ucode_patch;
354
355 if (mc && rev < mc->hdr.patch_id) {
356 if (!__apply_microcode_amd(mc))
357 ucode_new_rev = mc->hdr.patch_id;
358 }
359
360 } else {
361
362 /*
363 * AP has a different equivalence ID than BSP, looks like
364 * mixed-steppings silicon so go through the ucode blob anew.
365 */
366 goto reget;
367 }
368} 326}
369 327
370static enum ucode_state 328static enum ucode_state