aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/microcode_amd.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/microcode_amd.c')
-rw-r--r--arch/x86/kernel/microcode_amd.c133
1 files changed, 64 insertions, 69 deletions
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index efdec7cd8e01..47ebb1dbfbcb 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -31,48 +31,12 @@
31#include <asm/microcode.h> 31#include <asm/microcode.h>
32#include <asm/processor.h> 32#include <asm/processor.h>
33#include <asm/msr.h> 33#include <asm/msr.h>
34#include <asm/microcode_amd.h>
34 35
35MODULE_DESCRIPTION("AMD Microcode Update Driver"); 36MODULE_DESCRIPTION("AMD Microcode Update Driver");
36MODULE_AUTHOR("Peter Oruba"); 37MODULE_AUTHOR("Peter Oruba");
37MODULE_LICENSE("GPL v2"); 38MODULE_LICENSE("GPL v2");
38 39
39#define UCODE_MAGIC 0x00414d44
40#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
41#define UCODE_UCODE_TYPE 0x00000001
42
43struct equiv_cpu_entry {
44 u32 installed_cpu;
45 u32 fixed_errata_mask;
46 u32 fixed_errata_compare;
47 u16 equiv_cpu;
48 u16 res;
49} __attribute__((packed));
50
51struct microcode_header_amd {
52 u32 data_code;
53 u32 patch_id;
54 u16 mc_patch_data_id;
55 u8 mc_patch_data_len;
56 u8 init_flag;
57 u32 mc_patch_data_checksum;
58 u32 nb_dev_id;
59 u32 sb_dev_id;
60 u16 processor_rev_id;
61 u8 nb_rev_id;
62 u8 sb_rev_id;
63 u8 bios_api_rev;
64 u8 reserved1[3];
65 u32 match_reg[8];
66} __attribute__((packed));
67
68struct microcode_amd {
69 struct microcode_header_amd hdr;
70 unsigned int mpb[0];
71};
72
73#define SECTION_HDR_SIZE 8
74#define CONTAINER_HDR_SZ 12
75
76static struct equiv_cpu_entry *equiv_cpu_table; 40static struct equiv_cpu_entry *equiv_cpu_table;
77 41
78struct ucode_patch { 42struct ucode_patch {
@@ -84,21 +48,10 @@ struct ucode_patch {
84 48
85static LIST_HEAD(pcache); 49static LIST_HEAD(pcache);
86 50
87static u16 find_equiv_id(unsigned int cpu) 51static u16 __find_equiv_id(unsigned int cpu)
88{ 52{
89 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 53 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
90 int i = 0; 54 return find_equiv_id(equiv_cpu_table, uci->cpu_sig.sig);
91
92 if (!equiv_cpu_table)
93 return 0;
94
95 while (equiv_cpu_table[i].installed_cpu != 0) {
96 if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu)
97 return equiv_cpu_table[i].equiv_cpu;
98
99 i++;
100 }
101 return 0;
102} 55}
103 56
104static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu) 57static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu)
@@ -163,7 +116,7 @@ static struct ucode_patch *find_patch(unsigned int cpu)
163{ 116{
164 u16 equiv_id; 117 u16 equiv_id;
165 118
166 equiv_id = find_equiv_id(cpu); 119 equiv_id = __find_equiv_id(cpu);
167 if (!equiv_id) 120 if (!equiv_id)
168 return NULL; 121 return NULL;
169 122
@@ -173,9 +126,20 @@ static struct ucode_patch *find_patch(unsigned int cpu)
173static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) 126static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
174{ 127{
175 struct cpuinfo_x86 *c = &cpu_data(cpu); 128 struct cpuinfo_x86 *c = &cpu_data(cpu);
129 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
130 struct ucode_patch *p;
176 131
177 csig->sig = cpuid_eax(0x00000001); 132 csig->sig = cpuid_eax(0x00000001);
178 csig->rev = c->microcode; 133 csig->rev = c->microcode;
134
135 /*
136 * a patch could have been loaded early, set uci->mc so that
137 * mc_bp_resume() can call apply_microcode()
138 */
139 p = find_patch(cpu);
140 if (p && (p->patch_id == csig->rev))
141 uci->mc = p->data;
142
179 pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); 143 pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
180 144
181 return 0; 145 return 0;
@@ -215,7 +179,21 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size,
215 return patch_size; 179 return patch_size;
216} 180}
217 181
218static int apply_microcode_amd(int cpu) 182int __apply_microcode_amd(struct microcode_amd *mc_amd)
183{
184 u32 rev, dummy;
185
186 wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
187
188 /* verify patch application was successful */
189 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
190 if (rev != mc_amd->hdr.patch_id)
191 return -1;
192
193 return 0;
194}
195
196int apply_microcode_amd(int cpu)
219{ 197{
220 struct cpuinfo_x86 *c = &cpu_data(cpu); 198 struct cpuinfo_x86 *c = &cpu_data(cpu);
221 struct microcode_amd *mc_amd; 199 struct microcode_amd *mc_amd;
@@ -242,19 +220,15 @@ static int apply_microcode_amd(int cpu)
242 return 0; 220 return 0;
243 } 221 }
244 222
245 wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); 223 if (__apply_microcode_amd(mc_amd))
246
247 /* verify patch application was successful */
248 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
249 if (rev != mc_amd->hdr.patch_id) {
250 pr_err("CPU%d: update failed for patch_level=0x%08x\n", 224 pr_err("CPU%d: update failed for patch_level=0x%08x\n",
251 cpu, mc_amd->hdr.patch_id); 225 cpu, mc_amd->hdr.patch_id);
252 return -1; 226 else
253 } 227 pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
228 mc_amd->hdr.patch_id);
254 229
255 pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev); 230 uci->cpu_sig.rev = mc_amd->hdr.patch_id;
256 uci->cpu_sig.rev = rev; 231 c->microcode = mc_amd->hdr.patch_id;
257 c->microcode = rev;
258 232
259 return 0; 233 return 0;
260} 234}
@@ -364,7 +338,7 @@ static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
364 return crnt_size; 338 return crnt_size;
365} 339}
366 340
367static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size) 341static enum ucode_state __load_microcode_amd(int cpu, const u8 *data, size_t size)
368{ 342{
369 enum ucode_state ret = UCODE_ERROR; 343 enum ucode_state ret = UCODE_ERROR;
370 unsigned int leftover; 344 unsigned int leftover;
@@ -398,6 +372,32 @@ static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
398 return UCODE_OK; 372 return UCODE_OK;
399} 373}
400 374
375enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
376{
377 enum ucode_state ret;
378
379 /* free old equiv table */
380 free_equiv_cpu_table();
381
382 ret = __load_microcode_amd(cpu, data, size);
383
384 if (ret != UCODE_OK)
385 cleanup();
386
387#if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32)
388 /* save BSP's matching patch for early load */
389 if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
390 struct ucode_patch *p = find_patch(cpu);
391 if (p) {
392 memset(amd_bsp_mpb, 0, MPB_MAX_SIZE);
393 memcpy(amd_bsp_mpb, p->data, min_t(u32, ksize(p->data),
394 MPB_MAX_SIZE));
395 }
396 }
397#endif
398 return ret;
399}
400
401/* 401/*
402 * AMD microcode firmware naming convention, up to family 15h they are in 402 * AMD microcode firmware naming convention, up to family 15h they are in
403 * the legacy file: 403 * the legacy file:
@@ -440,12 +440,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
440 goto fw_release; 440 goto fw_release;
441 } 441 }
442 442
443 /* free old equiv table */
444 free_equiv_cpu_table();
445
446 ret = load_microcode_amd(cpu, fw->data, fw->size); 443 ret = load_microcode_amd(cpu, fw->data, fw->size);
447 if (ret != UCODE_OK)
448 cleanup();
449 444
450 fw_release: 445 fw_release:
451 release_firmware(fw); 446 release_firmware(fw);