diff options
-rw-r--r-- | arch/x86/Kconfig | 20 | ||||
-rw-r--r-- | arch/x86/include/asm/microcode.h | 10 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_amd.c | 357 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_core.c | 67 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_intel.c | 3 |
5 files changed, 273 insertions, 184 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6cd6f24e1223..943667050dae 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -986,25 +986,25 @@ config X86_REBOOTFIXUPS | |||
986 | Say N otherwise. | 986 | Say N otherwise. |
987 | 987 | ||
988 | config MICROCODE | 988 | config MICROCODE |
989 | tristate "/dev/cpu/microcode - microcode support" | 989 | tristate "CPU microcode loading support" |
990 | select FW_LOADER | 990 | select FW_LOADER |
991 | ---help--- | 991 | ---help--- |
992 | |||
992 | If you say Y here, you will be able to update the microcode on | 993 | If you say Y here, you will be able to update the microcode on |
993 | certain Intel and AMD processors. The Intel support is for the | 994 | certain Intel and AMD processors. The Intel support is for the |
994 | IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, | 995 | IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, |
995 | Pentium 4, Xeon etc. The AMD support is for family 0x10 and | 996 | Xeon etc. The AMD support is for families 0x10 and later. You will |
996 | 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra. | 997 | obviously need the actual microcode binary data itself which is not |
997 | You will obviously need the actual microcode binary data itself | 998 | shipped with the Linux kernel. |
998 | which is not shipped with the Linux kernel. | ||
999 | 999 | ||
1000 | This option selects the general module only, you need to select | 1000 | This option selects the general module only, you need to select |
1001 | at least one vendor specific module as well. | 1001 | at least one vendor specific module as well. |
1002 | 1002 | ||
1003 | To compile this driver as a module, choose M here: the | 1003 | To compile this driver as a module, choose M here: the module |
1004 | module will be called microcode. | 1004 | will be called microcode. |
1005 | 1005 | ||
1006 | config MICROCODE_INTEL | 1006 | config MICROCODE_INTEL |
1007 | bool "Intel microcode patch loading support" | 1007 | bool "Intel microcode loading support" |
1008 | depends on MICROCODE | 1008 | depends on MICROCODE |
1009 | default MICROCODE | 1009 | default MICROCODE |
1010 | select FW_LOADER | 1010 | select FW_LOADER |
@@ -1017,7 +1017,7 @@ config MICROCODE_INTEL | |||
1017 | <http://www.urbanmyth.org/microcode/>. | 1017 | <http://www.urbanmyth.org/microcode/>. |
1018 | 1018 | ||
1019 | config MICROCODE_AMD | 1019 | config MICROCODE_AMD |
1020 | bool "AMD microcode patch loading support" | 1020 | bool "AMD microcode loading support" |
1021 | depends on MICROCODE | 1021 | depends on MICROCODE |
1022 | select FW_LOADER | 1022 | select FW_LOADER |
1023 | ---help--- | 1023 | ---help--- |
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 4ebe157bf73d..43d921b4752c 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h | |||
@@ -15,8 +15,8 @@ struct microcode_ops { | |||
15 | enum ucode_state (*request_microcode_user) (int cpu, | 15 | enum ucode_state (*request_microcode_user) (int cpu, |
16 | const void __user *buf, size_t size); | 16 | const void __user *buf, size_t size); |
17 | 17 | ||
18 | enum ucode_state (*request_microcode_fw) (int cpu, | 18 | enum ucode_state (*request_microcode_fw) (int cpu, struct device *, |
19 | struct device *device); | 19 | bool refresh_fw); |
20 | 20 | ||
21 | void (*microcode_fini_cpu) (int cpu); | 21 | void (*microcode_fini_cpu) (int cpu); |
22 | 22 | ||
@@ -49,12 +49,6 @@ static inline struct microcode_ops * __init init_intel_microcode(void) | |||
49 | #ifdef CONFIG_MICROCODE_AMD | 49 | #ifdef CONFIG_MICROCODE_AMD |
50 | extern struct microcode_ops * __init init_amd_microcode(void); | 50 | extern struct microcode_ops * __init init_amd_microcode(void); |
51 | extern void __exit exit_amd_microcode(void); | 51 | extern void __exit exit_amd_microcode(void); |
52 | |||
53 | static inline void get_ucode_data(void *to, const u8 *from, size_t n) | ||
54 | { | ||
55 | memcpy(to, from, n); | ||
56 | } | ||
57 | |||
58 | #else | 52 | #else |
59 | static inline struct microcode_ops * __init init_amd_microcode(void) | 53 | static inline struct microcode_ops * __init init_amd_microcode(void) |
60 | { | 54 | { |
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 82746f942cd8..7720ff5a9ee2 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c | |||
@@ -75,20 +75,113 @@ struct microcode_amd { | |||
75 | 75 | ||
76 | static struct equiv_cpu_entry *equiv_cpu_table; | 76 | static struct equiv_cpu_entry *equiv_cpu_table; |
77 | 77 | ||
78 | /* page-sized ucode patch buffer */ | 78 | struct ucode_patch { |
79 | void *patch; | 79 | struct list_head plist; |
80 | void *data; | ||
81 | u32 patch_id; | ||
82 | u16 equiv_cpu; | ||
83 | }; | ||
84 | |||
85 | static LIST_HEAD(pcache); | ||
86 | |||
87 | static u16 find_equiv_id(unsigned int cpu) | ||
88 | { | ||
89 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
90 | int i = 0; | ||
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 | } | ||
103 | |||
104 | static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu) | ||
105 | { | ||
106 | int i = 0; | ||
107 | |||
108 | BUG_ON(!equiv_cpu_table); | ||
109 | |||
110 | while (equiv_cpu_table[i].equiv_cpu != 0) { | ||
111 | if (equiv_cpu == equiv_cpu_table[i].equiv_cpu) | ||
112 | return equiv_cpu_table[i].installed_cpu; | ||
113 | i++; | ||
114 | } | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * a small, trivial cache of per-family ucode patches | ||
120 | */ | ||
121 | static struct ucode_patch *cache_find_patch(u16 equiv_cpu) | ||
122 | { | ||
123 | struct ucode_patch *p; | ||
124 | |||
125 | list_for_each_entry(p, &pcache, plist) | ||
126 | if (p->equiv_cpu == equiv_cpu) | ||
127 | return p; | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | static void update_cache(struct ucode_patch *new_patch) | ||
132 | { | ||
133 | struct ucode_patch *p; | ||
134 | |||
135 | list_for_each_entry(p, &pcache, plist) { | ||
136 | if (p->equiv_cpu == new_patch->equiv_cpu) { | ||
137 | if (p->patch_id >= new_patch->patch_id) | ||
138 | /* we already have the latest patch */ | ||
139 | return; | ||
140 | |||
141 | list_replace(&p->plist, &new_patch->plist); | ||
142 | kfree(p->data); | ||
143 | kfree(p); | ||
144 | return; | ||
145 | } | ||
146 | } | ||
147 | /* no patch found, add it */ | ||
148 | list_add_tail(&new_patch->plist, &pcache); | ||
149 | } | ||
150 | |||
151 | static void free_cache(void) | ||
152 | { | ||
153 | struct ucode_patch *p, *tmp; | ||
154 | |||
155 | list_for_each_entry_safe(p, tmp, &pcache, plist) { | ||
156 | __list_del(p->plist.prev, p->plist.next); | ||
157 | kfree(p->data); | ||
158 | kfree(p); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | static struct ucode_patch *find_patch(unsigned int cpu) | ||
163 | { | ||
164 | u16 equiv_id; | ||
165 | |||
166 | equiv_id = find_equiv_id(cpu); | ||
167 | if (!equiv_id) | ||
168 | return NULL; | ||
169 | |||
170 | return cache_find_patch(equiv_id); | ||
171 | } | ||
80 | 172 | ||
81 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) | 173 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) |
82 | { | 174 | { |
83 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 175 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
84 | 176 | ||
177 | csig->sig = cpuid_eax(0x00000001); | ||
85 | csig->rev = c->microcode; | 178 | csig->rev = c->microcode; |
86 | pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); | 179 | pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); |
87 | 180 | ||
88 | return 0; | 181 | return 0; |
89 | } | 182 | } |
90 | 183 | ||
91 | static unsigned int verify_ucode_size(int cpu, u32 patch_size, | 184 | static unsigned int verify_patch_size(int cpu, u32 patch_size, |
92 | unsigned int size) | 185 | unsigned int size) |
93 | { | 186 | { |
94 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 187 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
@@ -118,95 +211,37 @@ static unsigned int verify_ucode_size(int cpu, u32 patch_size, | |||
118 | return patch_size; | 211 | return patch_size; |
119 | } | 212 | } |
120 | 213 | ||
121 | static u16 find_equiv_id(void) | 214 | static int apply_microcode_amd(int cpu) |
122 | { | 215 | { |
123 | unsigned int current_cpu_id, i = 0; | 216 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
124 | 217 | struct microcode_amd *mc_amd; | |
125 | BUG_ON(equiv_cpu_table == NULL); | 218 | struct ucode_cpu_info *uci; |
126 | 219 | struct ucode_patch *p; | |
127 | current_cpu_id = cpuid_eax(0x00000001); | 220 | u32 rev, dummy; |
128 | |||
129 | while (equiv_cpu_table[i].installed_cpu != 0) { | ||
130 | if (current_cpu_id == equiv_cpu_table[i].installed_cpu) | ||
131 | return equiv_cpu_table[i].equiv_cpu; | ||
132 | |||
133 | i++; | ||
134 | } | ||
135 | return 0; | ||
136 | } | ||
137 | 221 | ||
138 | /* | 222 | BUG_ON(raw_smp_processor_id() != cpu); |
139 | * we signal a good patch is found by returning its size > 0 | ||
140 | */ | ||
141 | static int get_matching_microcode(int cpu, const u8 *ucode_ptr, | ||
142 | unsigned int leftover_size, int rev, | ||
143 | unsigned int *current_size) | ||
144 | { | ||
145 | struct microcode_header_amd *mc_hdr; | ||
146 | unsigned int actual_size, patch_size; | ||
147 | u16 equiv_cpu_id; | ||
148 | 223 | ||
149 | /* size of the current patch we're staring at */ | 224 | uci = ucode_cpu_info + cpu; |
150 | patch_size = *(u32 *)(ucode_ptr + 4); | ||
151 | *current_size = patch_size + SECTION_HDR_SIZE; | ||
152 | 225 | ||
153 | equiv_cpu_id = find_equiv_id(); | 226 | p = find_patch(cpu); |
154 | if (!equiv_cpu_id) | 227 | if (!p) |
155 | return 0; | 228 | return 0; |
156 | 229 | ||
157 | /* | 230 | mc_amd = p->data; |
158 | * let's look at the patch header itself now | 231 | uci->mc = p->data; |
159 | */ | ||
160 | mc_hdr = (struct microcode_header_amd *)(ucode_ptr + SECTION_HDR_SIZE); | ||
161 | 232 | ||
162 | if (mc_hdr->processor_rev_id != equiv_cpu_id) | 233 | rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); |
163 | return 0; | ||
164 | 234 | ||
165 | /* ucode might be chipset specific -- currently we don't support this */ | 235 | /* need to apply patch? */ |
166 | if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) { | 236 | if (rev >= mc_amd->hdr.patch_id) { |
167 | pr_err("CPU%d: chipset specific code not yet supported\n", | 237 | c->microcode = rev; |
168 | cpu); | ||
169 | return 0; | 238 | return 0; |
170 | } | 239 | } |
171 | 240 | ||
172 | if (mc_hdr->patch_id <= rev) | ||
173 | return 0; | ||
174 | |||
175 | /* | ||
176 | * now that the header looks sane, verify its size | ||
177 | */ | ||
178 | actual_size = verify_ucode_size(cpu, patch_size, leftover_size); | ||
179 | if (!actual_size) | ||
180 | return 0; | ||
181 | |||
182 | /* clear the patch buffer */ | ||
183 | memset(patch, 0, PAGE_SIZE); | ||
184 | |||
185 | /* all looks ok, get the binary patch */ | ||
186 | get_ucode_data(patch, ucode_ptr + SECTION_HDR_SIZE, actual_size); | ||
187 | |||
188 | return actual_size; | ||
189 | } | ||
190 | |||
191 | static int apply_microcode_amd(int cpu) | ||
192 | { | ||
193 | u32 rev, dummy; | ||
194 | int cpu_num = raw_smp_processor_id(); | ||
195 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
196 | struct microcode_amd *mc_amd = uci->mc; | ||
197 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
198 | |||
199 | /* We should bind the task to the CPU */ | ||
200 | BUG_ON(cpu_num != cpu); | ||
201 | |||
202 | if (mc_amd == NULL) | ||
203 | return 0; | ||
204 | |||
205 | wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); | 241 | wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); |
206 | /* get patch id after patching */ | ||
207 | rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); | ||
208 | 242 | ||
209 | /* check current patch id and patch's id for match */ | 243 | /* verify patch application was successful */ |
244 | rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); | ||
210 | if (rev != mc_amd->hdr.patch_id) { | 245 | if (rev != mc_amd->hdr.patch_id) { |
211 | pr_err("CPU%d: update failed for patch_level=0x%08x\n", | 246 | pr_err("CPU%d: update failed for patch_level=0x%08x\n", |
212 | cpu, mc_amd->hdr.patch_id); | 247 | cpu, mc_amd->hdr.patch_id); |
@@ -238,7 +273,7 @@ static int install_equiv_cpu_table(const u8 *buf) | |||
238 | return -ENOMEM; | 273 | return -ENOMEM; |
239 | } | 274 | } |
240 | 275 | ||
241 | get_ucode_data(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size); | 276 | memcpy(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size); |
242 | 277 | ||
243 | /* add header length */ | 278 | /* add header length */ |
244 | return size + CONTAINER_HDR_SZ; | 279 | return size + CONTAINER_HDR_SZ; |
@@ -250,61 +285,113 @@ static void free_equiv_cpu_table(void) | |||
250 | equiv_cpu_table = NULL; | 285 | equiv_cpu_table = NULL; |
251 | } | 286 | } |
252 | 287 | ||
253 | static enum ucode_state | 288 | static void cleanup(void) |
254 | generic_load_microcode(int cpu, const u8 *data, size_t size) | ||
255 | { | 289 | { |
256 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 290 | free_equiv_cpu_table(); |
257 | struct microcode_header_amd *mc_hdr = NULL; | 291 | free_cache(); |
258 | unsigned int mc_size, leftover, current_size = 0; | 292 | } |
293 | |||
294 | /* | ||
295 | * We return the current size even if some of the checks failed so that | ||
296 | * we can skip over the next patch. If we return a negative value, we | ||
297 | * signal a grave error like a memory allocation has failed and the | ||
298 | * driver cannot continue functioning normally. In such cases, we tear | ||
299 | * down everything we've used up so far and exit. | ||
300 | */ | ||
301 | static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover) | ||
302 | { | ||
303 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
304 | struct microcode_header_amd *mc_hdr; | ||
305 | struct ucode_patch *patch; | ||
306 | unsigned int patch_size, crnt_size, ret; | ||
307 | u32 proc_fam; | ||
308 | u16 proc_id; | ||
309 | |||
310 | patch_size = *(u32 *)(fw + 4); | ||
311 | crnt_size = patch_size + SECTION_HDR_SIZE; | ||
312 | mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE); | ||
313 | proc_id = mc_hdr->processor_rev_id; | ||
314 | |||
315 | proc_fam = find_cpu_family_by_equiv_cpu(proc_id); | ||
316 | if (!proc_fam) { | ||
317 | pr_err("No patch family for equiv ID: 0x%04x\n", proc_id); | ||
318 | return crnt_size; | ||
319 | } | ||
320 | |||
321 | /* check if patch is for the current family */ | ||
322 | proc_fam = ((proc_fam >> 8) & 0xf) + ((proc_fam >> 20) & 0xff); | ||
323 | if (proc_fam != c->x86) | ||
324 | return crnt_size; | ||
325 | |||
326 | if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) { | ||
327 | pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", | ||
328 | mc_hdr->patch_id); | ||
329 | return crnt_size; | ||
330 | } | ||
331 | |||
332 | ret = verify_patch_size(cpu, patch_size, leftover); | ||
333 | if (!ret) { | ||
334 | pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id); | ||
335 | return crnt_size; | ||
336 | } | ||
337 | |||
338 | patch = kzalloc(sizeof(*patch), GFP_KERNEL); | ||
339 | if (!patch) { | ||
340 | pr_err("Patch allocation failure.\n"); | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | |||
344 | patch->data = kzalloc(patch_size, GFP_KERNEL); | ||
345 | if (!patch->data) { | ||
346 | pr_err("Patch data allocation failure.\n"); | ||
347 | kfree(patch); | ||
348 | return -EINVAL; | ||
349 | } | ||
350 | |||
351 | /* All looks ok, copy patch... */ | ||
352 | memcpy(patch->data, fw + SECTION_HDR_SIZE, patch_size); | ||
353 | INIT_LIST_HEAD(&patch->plist); | ||
354 | patch->patch_id = mc_hdr->patch_id; | ||
355 | patch->equiv_cpu = proc_id; | ||
356 | |||
357 | /* ... and add to cache. */ | ||
358 | update_cache(patch); | ||
359 | |||
360 | return crnt_size; | ||
361 | } | ||
362 | |||
363 | static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size) | ||
364 | { | ||
365 | enum ucode_state ret = UCODE_ERROR; | ||
366 | unsigned int leftover; | ||
367 | u8 *fw = (u8 *)data; | ||
368 | int crnt_size = 0; | ||
259 | int offset; | 369 | int offset; |
260 | const u8 *ucode_ptr = data; | ||
261 | void *new_mc = NULL; | ||
262 | unsigned int new_rev = uci->cpu_sig.rev; | ||
263 | enum ucode_state state = UCODE_ERROR; | ||
264 | 370 | ||
265 | offset = install_equiv_cpu_table(ucode_ptr); | 371 | offset = install_equiv_cpu_table(data); |
266 | if (offset < 0) { | 372 | if (offset < 0) { |
267 | pr_err("failed to create equivalent cpu table\n"); | 373 | pr_err("failed to create equivalent cpu table\n"); |
268 | goto out; | 374 | return ret; |
269 | } | 375 | } |
270 | ucode_ptr += offset; | 376 | fw += offset; |
271 | leftover = size - offset; | 377 | leftover = size - offset; |
272 | 378 | ||
273 | if (*(u32 *)ucode_ptr != UCODE_UCODE_TYPE) { | 379 | if (*(u32 *)fw != UCODE_UCODE_TYPE) { |
274 | pr_err("invalid type field in container file section header\n"); | 380 | pr_err("invalid type field in container file section header\n"); |
275 | goto free_table; | 381 | free_equiv_cpu_table(); |
382 | return ret; | ||
276 | } | 383 | } |
277 | 384 | ||
278 | while (leftover) { | 385 | while (leftover) { |
279 | mc_size = get_matching_microcode(cpu, ucode_ptr, leftover, | 386 | crnt_size = verify_and_add_patch(cpu, fw, leftover); |
280 | new_rev, ¤t_size); | 387 | if (crnt_size < 0) |
281 | if (mc_size) { | 388 | return ret; |
282 | mc_hdr = patch; | ||
283 | new_mc = patch; | ||
284 | new_rev = mc_hdr->patch_id; | ||
285 | goto out_ok; | ||
286 | } | ||
287 | |||
288 | ucode_ptr += current_size; | ||
289 | leftover -= current_size; | ||
290 | } | ||
291 | 389 | ||
292 | if (!new_mc) { | 390 | fw += crnt_size; |
293 | state = UCODE_NFOUND; | 391 | leftover -= crnt_size; |
294 | goto free_table; | ||
295 | } | 392 | } |
296 | 393 | ||
297 | out_ok: | 394 | return UCODE_OK; |
298 | uci->mc = new_mc; | ||
299 | state = UCODE_OK; | ||
300 | pr_debug("CPU%d update ucode (0x%08x -> 0x%08x)\n", | ||
301 | cpu, uci->cpu_sig.rev, new_rev); | ||
302 | |||
303 | free_table: | ||
304 | free_equiv_cpu_table(); | ||
305 | |||
306 | out: | ||
307 | return state; | ||
308 | } | 395 | } |
309 | 396 | ||
310 | /* | 397 | /* |
@@ -315,7 +402,7 @@ out: | |||
315 | * | 402 | * |
316 | * This legacy file is always smaller than 2K in size. | 403 | * This legacy file is always smaller than 2K in size. |
317 | * | 404 | * |
318 | * Starting at family 15h they are in family specific firmware files: | 405 | * Beginning with family 15h, they are in family-specific firmware files: |
319 | * | 406 | * |
320 | * amd-ucode/microcode_amd_fam15h.bin | 407 | * amd-ucode/microcode_amd_fam15h.bin |
321 | * amd-ucode/microcode_amd_fam16h.bin | 408 | * amd-ucode/microcode_amd_fam16h.bin |
@@ -323,12 +410,17 @@ out: | |||
323 | * | 410 | * |
324 | * These might be larger than 2K. | 411 | * These might be larger than 2K. |
325 | */ | 412 | */ |
326 | static enum ucode_state request_microcode_amd(int cpu, struct device *device) | 413 | static enum ucode_state request_microcode_amd(int cpu, struct device *device, |
414 | bool refresh_fw) | ||
327 | { | 415 | { |
328 | char fw_name[36] = "amd-ucode/microcode_amd.bin"; | 416 | char fw_name[36] = "amd-ucode/microcode_amd.bin"; |
329 | const struct firmware *fw; | ||
330 | enum ucode_state ret = UCODE_NFOUND; | ||
331 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 417 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
418 | enum ucode_state ret = UCODE_NFOUND; | ||
419 | const struct firmware *fw; | ||
420 | |||
421 | /* reload ucode container only on the boot cpu */ | ||
422 | if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index) | ||
423 | return UCODE_OK; | ||
332 | 424 | ||
333 | if (c->x86 >= 0x15) | 425 | if (c->x86 >= 0x15) |
334 | snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); | 426 | snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); |
@@ -344,12 +436,17 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device) | |||
344 | goto fw_release; | 436 | goto fw_release; |
345 | } | 437 | } |
346 | 438 | ||
347 | ret = generic_load_microcode(cpu, fw->data, fw->size); | 439 | /* free old equiv table */ |
440 | free_equiv_cpu_table(); | ||
441 | |||
442 | ret = load_microcode_amd(cpu, fw->data, fw->size); | ||
443 | if (ret != UCODE_OK) | ||
444 | cleanup(); | ||
348 | 445 | ||
349 | fw_release: | 446 | fw_release: |
350 | release_firmware(fw); | 447 | release_firmware(fw); |
351 | 448 | ||
352 | out: | 449 | out: |
353 | return ret; | 450 | return ret; |
354 | } | 451 | } |
355 | 452 | ||
@@ -383,14 +480,10 @@ struct microcode_ops * __init init_amd_microcode(void) | |||
383 | return NULL; | 480 | return NULL; |
384 | } | 481 | } |
385 | 482 | ||
386 | patch = (void *)get_zeroed_page(GFP_KERNEL); | ||
387 | if (!patch) | ||
388 | return NULL; | ||
389 | |||
390 | return µcode_amd_ops; | 483 | return µcode_amd_ops; |
391 | } | 484 | } |
392 | 485 | ||
393 | void __exit exit_amd_microcode(void) | 486 | void __exit exit_amd_microcode(void) |
394 | { | 487 | { |
395 | free_page((unsigned long)patch); | 488 | cleanup(); |
396 | } | 489 | } |
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index 9e5bcf1e2376..3a04b224d0c0 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
@@ -279,19 +279,18 @@ static struct platform_device *microcode_pdev; | |||
279 | static int reload_for_cpu(int cpu) | 279 | static int reload_for_cpu(int cpu) |
280 | { | 280 | { |
281 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 281 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
282 | enum ucode_state ustate; | ||
282 | int err = 0; | 283 | int err = 0; |
283 | 284 | ||
284 | if (uci->valid) { | 285 | if (!uci->valid) |
285 | enum ucode_state ustate; | 286 | return err; |
286 | |||
287 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); | ||
288 | if (ustate == UCODE_OK) | ||
289 | apply_microcode_on_target(cpu); | ||
290 | else | ||
291 | if (ustate == UCODE_ERROR) | ||
292 | err = -EINVAL; | ||
293 | } | ||
294 | 287 | ||
288 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); | ||
289 | if (ustate == UCODE_OK) | ||
290 | apply_microcode_on_target(cpu); | ||
291 | else | ||
292 | if (ustate == UCODE_ERROR) | ||
293 | err = -EINVAL; | ||
295 | return err; | 294 | return err; |
296 | } | 295 | } |
297 | 296 | ||
@@ -373,18 +372,15 @@ static void microcode_fini_cpu(int cpu) | |||
373 | 372 | ||
374 | static enum ucode_state microcode_resume_cpu(int cpu) | 373 | static enum ucode_state microcode_resume_cpu(int cpu) |
375 | { | 374 | { |
376 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
377 | |||
378 | if (!uci->mc) | ||
379 | return UCODE_NFOUND; | ||
380 | |||
381 | pr_debug("CPU%d updated upon resume\n", cpu); | 375 | pr_debug("CPU%d updated upon resume\n", cpu); |
382 | apply_microcode_on_target(cpu); | 376 | |
377 | if (apply_microcode_on_target(cpu)) | ||
378 | return UCODE_ERROR; | ||
383 | 379 | ||
384 | return UCODE_OK; | 380 | return UCODE_OK; |
385 | } | 381 | } |
386 | 382 | ||
387 | static enum ucode_state microcode_init_cpu(int cpu) | 383 | static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw) |
388 | { | 384 | { |
389 | enum ucode_state ustate; | 385 | enum ucode_state ustate; |
390 | 386 | ||
@@ -395,7 +391,8 @@ static enum ucode_state microcode_init_cpu(int cpu) | |||
395 | if (system_state != SYSTEM_RUNNING) | 391 | if (system_state != SYSTEM_RUNNING) |
396 | return UCODE_NFOUND; | 392 | return UCODE_NFOUND; |
397 | 393 | ||
398 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); | 394 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, |
395 | refresh_fw); | ||
399 | 396 | ||
400 | if (ustate == UCODE_OK) { | 397 | if (ustate == UCODE_OK) { |
401 | pr_debug("CPU%d updated upon init\n", cpu); | 398 | pr_debug("CPU%d updated upon init\n", cpu); |
@@ -408,14 +405,11 @@ static enum ucode_state microcode_init_cpu(int cpu) | |||
408 | static enum ucode_state microcode_update_cpu(int cpu) | 405 | static enum ucode_state microcode_update_cpu(int cpu) |
409 | { | 406 | { |
410 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 407 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
411 | enum ucode_state ustate; | ||
412 | 408 | ||
413 | if (uci->valid) | 409 | if (uci->valid) |
414 | ustate = microcode_resume_cpu(cpu); | 410 | return microcode_resume_cpu(cpu); |
415 | else | ||
416 | ustate = microcode_init_cpu(cpu); | ||
417 | 411 | ||
418 | return ustate; | 412 | return microcode_init_cpu(cpu, false); |
419 | } | 413 | } |
420 | 414 | ||
421 | static int mc_device_add(struct device *dev, struct subsys_interface *sif) | 415 | static int mc_device_add(struct device *dev, struct subsys_interface *sif) |
@@ -431,7 +425,7 @@ static int mc_device_add(struct device *dev, struct subsys_interface *sif) | |||
431 | if (err) | 425 | if (err) |
432 | return err; | 426 | return err; |
433 | 427 | ||
434 | if (microcode_init_cpu(cpu) == UCODE_ERROR) | 428 | if (microcode_init_cpu(cpu, true) == UCODE_ERROR) |
435 | return -EINVAL; | 429 | return -EINVAL; |
436 | 430 | ||
437 | return err; | 431 | return err; |
@@ -480,34 +474,41 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
480 | struct device *dev; | 474 | struct device *dev; |
481 | 475 | ||
482 | dev = get_cpu_device(cpu); | 476 | dev = get_cpu_device(cpu); |
483 | switch (action) { | 477 | |
478 | switch (action & ~CPU_TASKS_FROZEN) { | ||
484 | case CPU_ONLINE: | 479 | case CPU_ONLINE: |
485 | case CPU_ONLINE_FROZEN: | ||
486 | microcode_update_cpu(cpu); | 480 | microcode_update_cpu(cpu); |
487 | case CPU_DOWN_FAILED: | ||
488 | case CPU_DOWN_FAILED_FROZEN: | ||
489 | pr_debug("CPU%d added\n", cpu); | 481 | pr_debug("CPU%d added\n", cpu); |
482 | /* | ||
483 | * "break" is missing on purpose here because we want to fall | ||
484 | * through in order to create the sysfs group. | ||
485 | */ | ||
486 | |||
487 | case CPU_DOWN_FAILED: | ||
490 | if (sysfs_create_group(&dev->kobj, &mc_attr_group)) | 488 | if (sysfs_create_group(&dev->kobj, &mc_attr_group)) |
491 | pr_err("Failed to create group for CPU%d\n", cpu); | 489 | pr_err("Failed to create group for CPU%d\n", cpu); |
492 | break; | 490 | break; |
491 | |||
493 | case CPU_DOWN_PREPARE: | 492 | case CPU_DOWN_PREPARE: |
494 | case CPU_DOWN_PREPARE_FROZEN: | ||
495 | /* Suspend is in progress, only remove the interface */ | 493 | /* Suspend is in progress, only remove the interface */ |
496 | sysfs_remove_group(&dev->kobj, &mc_attr_group); | 494 | sysfs_remove_group(&dev->kobj, &mc_attr_group); |
497 | pr_debug("CPU%d removed\n", cpu); | 495 | pr_debug("CPU%d removed\n", cpu); |
498 | break; | 496 | break; |
499 | 497 | ||
500 | /* | 498 | /* |
499 | * case CPU_DEAD: | ||
500 | * | ||
501 | * When a CPU goes offline, don't free up or invalidate the copy of | 501 | * When a CPU goes offline, don't free up or invalidate the copy of |
502 | * the microcode in kernel memory, so that we can reuse it when the | 502 | * the microcode in kernel memory, so that we can reuse it when the |
503 | * CPU comes back online without unnecessarily requesting the userspace | 503 | * CPU comes back online without unnecessarily requesting the userspace |
504 | * for it again. | 504 | * for it again. |
505 | */ | 505 | */ |
506 | case CPU_UP_CANCELED_FROZEN: | ||
507 | /* The CPU refused to come up during a system resume */ | ||
508 | microcode_fini_cpu(cpu); | ||
509 | break; | ||
510 | } | 506 | } |
507 | |||
508 | /* The CPU refused to come up during a system resume */ | ||
509 | if (action == CPU_UP_CANCELED_FROZEN) | ||
510 | microcode_fini_cpu(cpu); | ||
511 | |||
511 | return NOTIFY_OK; | 512 | return NOTIFY_OK; |
512 | } | 513 | } |
513 | 514 | ||
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c index 0327e2b3c408..3544aed39338 100644 --- a/arch/x86/kernel/microcode_intel.c +++ b/arch/x86/kernel/microcode_intel.c | |||
@@ -405,7 +405,8 @@ static int get_ucode_fw(void *to, const void *from, size_t n) | |||
405 | return 0; | 405 | return 0; |
406 | } | 406 | } |
407 | 407 | ||
408 | static enum ucode_state request_microcode_fw(int cpu, struct device *device) | 408 | static enum ucode_state request_microcode_fw(int cpu, struct device *device, |
409 | bool refresh_fw) | ||
409 | { | 410 | { |
410 | char name[30]; | 411 | char name[30]; |
411 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 412 | struct cpuinfo_x86 *c = &cpu_data(cpu); |