diff options
author | Dmitry Adamushko <dmitry.adamushko@gmail.com> | 2008-08-19 18:22:26 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-20 06:18:57 -0400 |
commit | d45de40934897c6ee5b05141f7895bbb28512395 (patch) | |
tree | 1b4c4a011071d188a08d0f5bce8caf6b2b0a93c2 | |
parent | 8343ef2437c599d30568e6b5a257a40bf2f4902b (diff) |
x86-microcode: generic interface refactoring
This is the 1st patch in the series. Here the aim was to avoid any
significant changes, logically-wise.
So it's mainly about generic interface refactoring: e.g. make
microcode_{intel,amd}.c more about arch-specific details and less
about policies like make-sure-we-run-on-a-target-cpu
(no more set_cpus_allowed_ptr() here) and generic synchronization (no
more microcode_mutex here).
All in all, more line have been deleted than added.
4 files changed, 145 insertions(+), 198 deletions(-)
Signed-off-by: Dmitry Adamushko <dmitry.adamushko@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/microcode.c | 155 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_amd.c | 77 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_intel.c | 91 | ||||
-rw-r--r-- | include/asm-x86/microcode.h | 20 |
4 files changed, 145 insertions, 198 deletions
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c index ad136ad99cb3..b2f84ce5eed3 100644 --- a/arch/x86/kernel/microcode.c +++ b/arch/x86/kernel/microcode.c | |||
@@ -71,7 +71,7 @@ | |||
71 | * Thanks to Stuart Swales for pointing out this bug. | 71 | * Thanks to Stuart Swales for pointing out this bug. |
72 | */ | 72 | */ |
73 | 73 | ||
74 | /*#define DEBUG pr_debug */ | 74 | /* #define DEBUG pr_debug */ |
75 | #include <linux/capability.h> | 75 | #include <linux/capability.h> |
76 | #include <linux/kernel.h> | 76 | #include <linux/kernel.h> |
77 | #include <linux/init.h> | 77 | #include <linux/init.h> |
@@ -104,8 +104,7 @@ MODULE_LICENSE("GPL"); | |||
104 | struct microcode_ops *microcode_ops; | 104 | struct microcode_ops *microcode_ops; |
105 | 105 | ||
106 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | 106 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ |
107 | DEFINE_MUTEX(microcode_mutex); | 107 | static DEFINE_MUTEX(microcode_mutex); |
108 | EXPORT_SYMBOL_GPL(microcode_mutex); | ||
109 | 108 | ||
110 | struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | 109 | struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; |
111 | EXPORT_SYMBOL_GPL(ucode_cpu_info); | 110 | EXPORT_SYMBOL_GPL(ucode_cpu_info); |
@@ -234,22 +233,6 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); | |||
234 | struct platform_device *microcode_pdev; | 233 | struct platform_device *microcode_pdev; |
235 | EXPORT_SYMBOL_GPL(microcode_pdev); | 234 | EXPORT_SYMBOL_GPL(microcode_pdev); |
236 | 235 | ||
237 | static void microcode_init_cpu(int cpu, int resume) | ||
238 | { | ||
239 | cpumask_t old; | ||
240 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
241 | |||
242 | old = current->cpus_allowed; | ||
243 | |||
244 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
245 | mutex_lock(µcode_mutex); | ||
246 | microcode_ops->collect_cpu_info(cpu); | ||
247 | if (uci->valid && system_state == SYSTEM_RUNNING && !resume) | ||
248 | microcode_ops->cpu_request_microcode(cpu); | ||
249 | mutex_unlock(µcode_mutex); | ||
250 | set_cpus_allowed_ptr(current, &old); | ||
251 | } | ||
252 | |||
253 | static ssize_t reload_store(struct sys_device *dev, | 236 | static ssize_t reload_store(struct sys_device *dev, |
254 | struct sysdev_attribute *attr, | 237 | struct sysdev_attribute *attr, |
255 | const char *buf, size_t sz) | 238 | const char *buf, size_t sz) |
@@ -266,14 +249,15 @@ static ssize_t reload_store(struct sys_device *dev, | |||
266 | cpumask_t old = current->cpus_allowed; | 249 | cpumask_t old = current->cpus_allowed; |
267 | 250 | ||
268 | get_online_cpus(); | 251 | get_online_cpus(); |
269 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | 252 | if (cpu_online(cpu)) { |
270 | 253 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | |
271 | mutex_lock(µcode_mutex); | 254 | mutex_lock(µcode_mutex); |
272 | if (uci->valid) | 255 | if (uci->valid) |
273 | err = microcode_ops->cpu_request_microcode(cpu); | 256 | err = microcode_ops->cpu_request_microcode(cpu); |
274 | mutex_unlock(µcode_mutex); | 257 | mutex_unlock(µcode_mutex); |
258 | set_cpus_allowed_ptr(current, &old); | ||
259 | } | ||
275 | put_online_cpus(); | 260 | put_online_cpus(); |
276 | set_cpus_allowed_ptr(current, &old); | ||
277 | } | 261 | } |
278 | if (err) | 262 | if (err) |
279 | return err; | 263 | return err; |
@@ -285,7 +269,7 @@ static ssize_t version_show(struct sys_device *dev, | |||
285 | { | 269 | { |
286 | struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | 270 | struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; |
287 | 271 | ||
288 | return sprintf(buf, "0x%x\n", uci->rev); | 272 | return sprintf(buf, "0x%x\n", uci->cpu_sig.rev); |
289 | } | 273 | } |
290 | 274 | ||
291 | static ssize_t pf_show(struct sys_device *dev, | 275 | static ssize_t pf_show(struct sys_device *dev, |
@@ -293,7 +277,7 @@ static ssize_t pf_show(struct sys_device *dev, | |||
293 | { | 277 | { |
294 | struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | 278 | struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; |
295 | 279 | ||
296 | return sprintf(buf, "0x%x\n", uci->pf); | 280 | return sprintf(buf, "0x%x\n", uci->cpu_sig.pf); |
297 | } | 281 | } |
298 | 282 | ||
299 | static SYSDEV_ATTR(reload, 0200, NULL, reload_store); | 283 | static SYSDEV_ATTR(reload, 0200, NULL, reload_store); |
@@ -312,7 +296,85 @@ static struct attribute_group mc_attr_group = { | |||
312 | .name = "microcode", | 296 | .name = "microcode", |
313 | }; | 297 | }; |
314 | 298 | ||
315 | static int __mc_sysdev_add(struct sys_device *sys_dev, int resume) | 299 | static void microcode_fini_cpu(int cpu) |
300 | { | ||
301 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
302 | |||
303 | mutex_lock(µcode_mutex); | ||
304 | microcode_ops->microcode_fini_cpu(cpu); | ||
305 | uci->valid = 0; | ||
306 | mutex_unlock(µcode_mutex); | ||
307 | } | ||
308 | |||
309 | static void collect_cpu_info(int cpu) | ||
310 | { | ||
311 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
312 | |||
313 | memset(uci, 0, sizeof(*uci)); | ||
314 | if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig)) | ||
315 | uci->valid = 1; | ||
316 | } | ||
317 | |||
318 | static void microcode_resume_cpu(int cpu) | ||
319 | { | ||
320 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
321 | struct cpu_signature nsig; | ||
322 | |||
323 | pr_debug("microcode: CPU%d resumed\n", cpu); | ||
324 | |||
325 | if (!uci->mc.valid_mc) | ||
326 | return; | ||
327 | |||
328 | /* | ||
329 | * Let's verify that the 'cached' ucode does belong | ||
330 | * to this cpu (a bit of paranoia): | ||
331 | */ | ||
332 | if (microcode_ops->collect_cpu_info(cpu, &nsig)) { | ||
333 | microcode_fini_cpu(cpu); | ||
334 | return; | ||
335 | } | ||
336 | |||
337 | if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) { | ||
338 | microcode_fini_cpu(cpu); | ||
339 | /* Should we look for a new ucode here? */ | ||
340 | return; | ||
341 | } | ||
342 | |||
343 | microcode_ops->apply_microcode(cpu); | ||
344 | } | ||
345 | |||
346 | void microcode_update_cpu(int cpu) | ||
347 | { | ||
348 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
349 | |||
350 | /* We should bind the task to the CPU */ | ||
351 | BUG_ON(raw_smp_processor_id() != cpu); | ||
352 | |||
353 | mutex_lock(µcode_mutex); | ||
354 | /* | ||
355 | * Check if the system resume is in progress (uci->valid != NULL), | ||
356 | * otherwise just request a firmware: | ||
357 | */ | ||
358 | if (uci->valid) { | ||
359 | microcode_resume_cpu(cpu); | ||
360 | } else { | ||
361 | collect_cpu_info(cpu); | ||
362 | if (uci->valid && system_state == SYSTEM_RUNNING) | ||
363 | microcode_ops->cpu_request_microcode(cpu); | ||
364 | } | ||
365 | mutex_unlock(µcode_mutex); | ||
366 | } | ||
367 | |||
368 | static void microcode_init_cpu(int cpu) | ||
369 | { | ||
370 | cpumask_t old = current->cpus_allowed; | ||
371 | |||
372 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
373 | microcode_update_cpu(cpu); | ||
374 | set_cpus_allowed_ptr(current, &old); | ||
375 | } | ||
376 | |||
377 | static int mc_sysdev_add(struct sys_device *sys_dev) | ||
316 | { | 378 | { |
317 | int err, cpu = sys_dev->id; | 379 | int err, cpu = sys_dev->id; |
318 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 380 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
@@ -327,16 +389,10 @@ static int __mc_sysdev_add(struct sys_device *sys_dev, int resume) | |||
327 | if (err) | 389 | if (err) |
328 | return err; | 390 | return err; |
329 | 391 | ||
330 | microcode_init_cpu(cpu, resume); | 392 | microcode_init_cpu(cpu); |
331 | |||
332 | return 0; | 393 | return 0; |
333 | } | 394 | } |
334 | 395 | ||
335 | static int mc_sysdev_add(struct sys_device *sys_dev) | ||
336 | { | ||
337 | return __mc_sysdev_add(sys_dev, 0); | ||
338 | } | ||
339 | |||
340 | static int mc_sysdev_remove(struct sys_device *sys_dev) | 396 | static int mc_sysdev_remove(struct sys_device *sys_dev) |
341 | { | 397 | { |
342 | int cpu = sys_dev->id; | 398 | int cpu = sys_dev->id; |
@@ -345,7 +401,7 @@ static int mc_sysdev_remove(struct sys_device *sys_dev) | |||
345 | return 0; | 401 | return 0; |
346 | 402 | ||
347 | pr_debug("microcode: CPU%d removed\n", cpu); | 403 | pr_debug("microcode: CPU%d removed\n", cpu); |
348 | microcode_ops->microcode_fini_cpu(cpu); | 404 | microcode_fini_cpu(cpu); |
349 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | 405 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); |
350 | return 0; | 406 | return 0; |
351 | } | 407 | } |
@@ -376,33 +432,26 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
376 | 432 | ||
377 | sys_dev = get_cpu_sysdev(cpu); | 433 | sys_dev = get_cpu_sysdev(cpu); |
378 | switch (action) { | 434 | switch (action) { |
379 | case CPU_UP_CANCELED_FROZEN: | ||
380 | /* The CPU refused to come up during a system resume */ | ||
381 | microcode_ops->microcode_fini_cpu(cpu); | ||
382 | break; | ||
383 | case CPU_ONLINE: | 435 | case CPU_ONLINE: |
384 | case CPU_DOWN_FAILED: | ||
385 | mc_sysdev_add(sys_dev); | ||
386 | break; | ||
387 | case CPU_ONLINE_FROZEN: | 436 | case CPU_ONLINE_FROZEN: |
388 | /* System-wide resume is in progress, try to apply microcode */ | 437 | microcode_init_cpu(cpu); |
389 | if (microcode_ops->apply_microcode_check_cpu(cpu)) { | 438 | case CPU_DOWN_FAILED: |
390 | /* The application of microcode failed */ | ||
391 | microcode_ops->microcode_fini_cpu(cpu); | ||
392 | __mc_sysdev_add(sys_dev, 1); | ||
393 | break; | ||
394 | } | ||
395 | case CPU_DOWN_FAILED_FROZEN: | 439 | case CPU_DOWN_FAILED_FROZEN: |
440 | pr_debug("microcode: CPU%d added\n", cpu); | ||
396 | if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group)) | 441 | if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group)) |
397 | printk(KERN_ERR "microcode: Failed to create the sysfs " | 442 | printk(KERN_ERR "microcode: Failed to create the sysfs " |
398 | "group for CPU%d\n", cpu); | 443 | "group for CPU%d\n", cpu); |
399 | break; | 444 | break; |
400 | case CPU_DOWN_PREPARE: | 445 | case CPU_DOWN_PREPARE: |
401 | mc_sysdev_remove(sys_dev); | ||
402 | break; | ||
403 | case CPU_DOWN_PREPARE_FROZEN: | 446 | case CPU_DOWN_PREPARE_FROZEN: |
404 | /* Suspend is in progress, only remove the interface */ | 447 | /* Suspend is in progress, only remove the interface */ |
405 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | 448 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); |
449 | pr_debug("microcode: CPU%d removed\n", cpu); | ||
450 | break; | ||
451 | case CPU_DEAD: | ||
452 | case CPU_UP_CANCELED_FROZEN: | ||
453 | /* The CPU refused to come up during a system resume */ | ||
454 | microcode_fini_cpu(cpu); | ||
406 | break; | 455 | break; |
407 | } | 456 | } |
408 | return NOTIFY_OK; | 457 | return NOTIFY_OK; |
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index a6e76ccf8158..4006e5e3adf0 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c | |||
@@ -59,38 +59,28 @@ MODULE_LICENSE("GPL v2"); | |||
59 | /* serialize access to the physical write */ | 59 | /* serialize access to the physical write */ |
60 | static DEFINE_SPINLOCK(microcode_update_lock); | 60 | static DEFINE_SPINLOCK(microcode_update_lock); |
61 | 61 | ||
62 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | ||
63 | extern struct mutex (microcode_mutex); | ||
64 | |||
65 | struct equiv_cpu_entry *equiv_cpu_table; | 62 | struct equiv_cpu_entry *equiv_cpu_table; |
66 | 63 | ||
67 | extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | 64 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) |
68 | |||
69 | static void collect_cpu_info_amd(int cpu) | ||
70 | { | 65 | { |
71 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 66 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
72 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
73 | 67 | ||
74 | /* We should bind the task to the CPU */ | 68 | memset(csig, 0, sizeof(*csig)); |
75 | BUG_ON(raw_smp_processor_id() != cpu); | ||
76 | uci->rev = 0; | ||
77 | uci->pf = 0; | ||
78 | uci->mc.mc_amd = NULL; | ||
79 | uci->valid = 1; | ||
80 | 69 | ||
81 | if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) { | 70 | if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) { |
82 | printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n", | 71 | printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n", |
83 | cpu); | 72 | cpu); |
84 | uci->valid = 0; | 73 | return -1; |
85 | return; | ||
86 | } | 74 | } |
87 | 75 | ||
88 | asm volatile("movl %1, %%ecx; rdmsr" | 76 | asm volatile("movl %1, %%ecx; rdmsr" |
89 | : "=a" (uci->rev) | 77 | : "=a" (csig->rev) |
90 | : "i" (0x0000008B) : "ecx"); | 78 | : "i" (0x0000008B) : "ecx"); |
91 | 79 | ||
92 | printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n", | 80 | printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n", |
93 | uci->rev); | 81 | csig->rev); |
82 | |||
83 | return 0; | ||
94 | } | 84 | } |
95 | 85 | ||
96 | static int get_matching_microcode_amd(void *mc, int cpu) | 86 | static int get_matching_microcode_amd(void *mc, int cpu) |
@@ -119,7 +109,7 @@ static int get_matching_microcode_amd(void *mc, int cpu) | |||
119 | if (equiv_cpu_table == NULL) { | 109 | if (equiv_cpu_table == NULL) { |
120 | printk(KERN_INFO "microcode: CPU%d microcode update with " | 110 | printk(KERN_INFO "microcode: CPU%d microcode update with " |
121 | "version 0x%x (current=0x%x)\n", | 111 | "version 0x%x (current=0x%x)\n", |
122 | cpu, mc_header->patch_id, uci->rev); | 112 | cpu, mc_header->patch_id, uci->cpu_sig.rev); |
123 | goto out; | 113 | goto out; |
124 | } | 114 | } |
125 | 115 | ||
@@ -185,12 +175,12 @@ static int get_matching_microcode_amd(void *mc, int cpu) | |||
185 | pci_dev_put(sb_pci_dev); | 175 | pci_dev_put(sb_pci_dev); |
186 | } | 176 | } |
187 | 177 | ||
188 | if (mc_header->patch_id <= uci->rev) | 178 | if (mc_header->patch_id <= uci->cpu_sig.rev) |
189 | return 0; | 179 | return 0; |
190 | 180 | ||
191 | printk(KERN_INFO "microcode: CPU%d found a matching microcode " | 181 | printk(KERN_INFO "microcode: CPU%d found a matching microcode " |
192 | "update with version 0x%x (current=0x%x)\n", | 182 | "update with version 0x%x (current=0x%x)\n", |
193 | cpu, mc_header->patch_id, uci->rev); | 183 | cpu, mc_header->patch_id, uci->cpu_sig.rev); |
194 | 184 | ||
195 | out: | 185 | out: |
196 | new_mc = vmalloc(UCODE_MAX_SIZE); | 186 | new_mc = vmalloc(UCODE_MAX_SIZE); |
@@ -250,9 +240,9 @@ static void apply_microcode_amd(int cpu) | |||
250 | 240 | ||
251 | printk(KERN_INFO "microcode: CPU%d updated from revision " | 241 | printk(KERN_INFO "microcode: CPU%d updated from revision " |
252 | "0x%x to 0x%x \n", | 242 | "0x%x to 0x%x \n", |
253 | cpu_num, uci->rev, uci->mc.mc_amd->hdr.patch_id); | 243 | cpu_num, uci->cpu_sig.rev, uci->mc.mc_amd->hdr.patch_id); |
254 | 244 | ||
255 | uci->rev = rev; | 245 | uci->cpu_sig.rev = rev; |
256 | } | 246 | } |
257 | 247 | ||
258 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE | 248 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE |
@@ -437,61 +427,18 @@ static int cpu_request_microcode_amd(int cpu) | |||
437 | return error; | 427 | return error; |
438 | } | 428 | } |
439 | 429 | ||
440 | static int apply_microcode_check_cpu_amd(int cpu) | ||
441 | { | ||
442 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
443 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
444 | unsigned int rev; | ||
445 | cpumask_t old; | ||
446 | int err = 0; | ||
447 | |||
448 | /* Check if the microcode is available */ | ||
449 | if (!uci->mc.mc_amd) | ||
450 | return 0; | ||
451 | |||
452 | old = current->cpus_allowed; | ||
453 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
454 | |||
455 | /* Check if the microcode we have in memory matches the CPU */ | ||
456 | if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 16) | ||
457 | err = -EINVAL; | ||
458 | |||
459 | if (!err) { | ||
460 | asm volatile("movl %1, %%ecx; rdmsr" | ||
461 | : "=a" (rev) | ||
462 | : "i" (0x0000008B) : "ecx"); | ||
463 | |||
464 | if (uci->rev != rev) | ||
465 | err = -EINVAL; | ||
466 | } | ||
467 | |||
468 | if (!err) | ||
469 | apply_microcode_amd(cpu); | ||
470 | else | ||
471 | printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:" | ||
472 | " rev=0x%x\n", | ||
473 | cpu, uci->rev); | ||
474 | |||
475 | set_cpus_allowed(current, old); | ||
476 | return err; | ||
477 | } | ||
478 | |||
479 | static void microcode_fini_cpu_amd(int cpu) | 430 | static void microcode_fini_cpu_amd(int cpu) |
480 | { | 431 | { |
481 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 432 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
482 | 433 | ||
483 | mutex_lock(µcode_mutex); | ||
484 | uci->valid = 0; | ||
485 | vfree(uci->mc.mc_amd); | 434 | vfree(uci->mc.mc_amd); |
486 | uci->mc.mc_amd = NULL; | 435 | uci->mc.mc_amd = NULL; |
487 | mutex_unlock(µcode_mutex); | ||
488 | } | 436 | } |
489 | 437 | ||
490 | static struct microcode_ops microcode_amd_ops = { | 438 | static struct microcode_ops microcode_amd_ops = { |
491 | .get_next_ucode = get_next_ucode_amd, | 439 | .get_next_ucode = get_next_ucode_amd, |
492 | .get_matching_microcode = get_matching_microcode_amd, | 440 | .get_matching_microcode = get_matching_microcode_amd, |
493 | .microcode_sanity_check = NULL, | 441 | .microcode_sanity_check = NULL, |
494 | .apply_microcode_check_cpu = apply_microcode_check_cpu_amd, | ||
495 | .cpu_request_microcode = cpu_request_microcode_amd, | 442 | .cpu_request_microcode = cpu_request_microcode_amd, |
496 | .collect_cpu_info = collect_cpu_info_amd, | 443 | .collect_cpu_info = collect_cpu_info_amd, |
497 | .apply_microcode = apply_microcode_amd, | 444 | .apply_microcode = apply_microcode_amd, |
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c index 6dd8907ff22e..c9b53202ba3d 100644 --- a/arch/x86/kernel/microcode_intel.c +++ b/arch/x86/kernel/microcode_intel.c | |||
@@ -122,46 +122,37 @@ MODULE_LICENSE("GPL"); | |||
122 | /* serialize access to the physical write to MSR 0x79 */ | 122 | /* serialize access to the physical write to MSR 0x79 */ |
123 | static DEFINE_SPINLOCK(microcode_update_lock); | 123 | static DEFINE_SPINLOCK(microcode_update_lock); |
124 | 124 | ||
125 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | 125 | static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) |
126 | extern struct mutex microcode_mutex; | ||
127 | |||
128 | extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | ||
129 | |||
130 | static void collect_cpu_info(int cpu_num) | ||
131 | { | 126 | { |
132 | struct cpuinfo_x86 *c = &cpu_data(cpu_num); | 127 | struct cpuinfo_x86 *c = &cpu_data(cpu_num); |
133 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
134 | unsigned int val[2]; | 128 | unsigned int val[2]; |
135 | 129 | ||
136 | /* We should bind the task to the CPU */ | 130 | memset(csig, 0, sizeof(*csig)); |
137 | BUG_ON(raw_smp_processor_id() != cpu_num); | ||
138 | uci->pf = uci->rev = 0; | ||
139 | uci->mc.mc_intel = NULL; | ||
140 | uci->valid = 1; | ||
141 | 131 | ||
142 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | 132 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || |
143 | cpu_has(c, X86_FEATURE_IA64)) { | 133 | cpu_has(c, X86_FEATURE_IA64)) { |
144 | printk(KERN_ERR "microcode: CPU%d not a capable Intel " | 134 | printk(KERN_ERR "microcode: CPU%d not a capable Intel " |
145 | "processor\n", cpu_num); | 135 | "processor\n", cpu_num); |
146 | uci->valid = 0; | 136 | return -1; |
147 | return; | ||
148 | } | 137 | } |
149 | 138 | ||
150 | uci->sig = cpuid_eax(0x00000001); | 139 | csig->sig = cpuid_eax(0x00000001); |
151 | 140 | ||
152 | if ((c->x86_model >= 5) || (c->x86 > 6)) { | 141 | if ((c->x86_model >= 5) || (c->x86 > 6)) { |
153 | /* get processor flags from MSR 0x17 */ | 142 | /* get processor flags from MSR 0x17 */ |
154 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | 143 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); |
155 | uci->pf = 1 << ((val[1] >> 18) & 7); | 144 | csig->pf = 1 << ((val[1] >> 18) & 7); |
156 | } | 145 | } |
157 | 146 | ||
158 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | 147 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); |
159 | /* see notes above for revision 1.07. Apparent chip bug */ | 148 | /* see notes above for revision 1.07. Apparent chip bug */ |
160 | sync_core(); | 149 | sync_core(); |
161 | /* get the current revision from MSR 0x8B */ | 150 | /* get the current revision from MSR 0x8B */ |
162 | rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev); | 151 | rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev); |
163 | pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n", | 152 | pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n", |
164 | uci->sig, uci->pf, uci->rev); | 153 | csig->sig, csig->pf, csig->rev); |
154 | |||
155 | return 0; | ||
165 | } | 156 | } |
166 | 157 | ||
167 | static inline int microcode_update_match(int cpu_num, | 158 | static inline int microcode_update_match(int cpu_num, |
@@ -169,8 +160,8 @@ static inline int microcode_update_match(int cpu_num, | |||
169 | { | 160 | { |
170 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | 161 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; |
171 | 162 | ||
172 | if (!sigmatch(sig, uci->sig, pf, uci->pf) | 163 | if (!sigmatch(sig, uci->cpu_sig.sig, pf, uci->cpu_sig.pf) |
173 | || mc_header->rev <= uci->rev) | 164 | || mc_header->rev <= uci->cpu_sig.rev) |
174 | return 0; | 165 | return 0; |
175 | return 1; | 166 | return 1; |
176 | } | 167 | } |
@@ -289,7 +280,7 @@ static int get_matching_microcode(void *mc, int cpu) | |||
289 | find: | 280 | find: |
290 | pr_debug("microcode: CPU%d found a matching microcode update with" | 281 | pr_debug("microcode: CPU%d found a matching microcode update with" |
291 | " version 0x%x (current=0x%x)\n", | 282 | " version 0x%x (current=0x%x)\n", |
292 | cpu, mc_header->rev, uci->rev); | 283 | cpu, mc_header->rev, uci->cpu_sig.rev); |
293 | new_mc = vmalloc(total_size); | 284 | new_mc = vmalloc(total_size); |
294 | if (!new_mc) { | 285 | if (!new_mc) { |
295 | printk(KERN_ERR "microcode: error! Can not allocate memory\n"); | 286 | printk(KERN_ERR "microcode: error! Can not allocate memory\n"); |
@@ -335,16 +326,16 @@ static void apply_microcode(int cpu) | |||
335 | spin_unlock_irqrestore(µcode_update_lock, flags); | 326 | spin_unlock_irqrestore(µcode_update_lock, flags); |
336 | if (val[1] != uci->mc.mc_intel->hdr.rev) { | 327 | if (val[1] != uci->mc.mc_intel->hdr.rev) { |
337 | printk(KERN_ERR "microcode: CPU%d update from revision " | 328 | printk(KERN_ERR "microcode: CPU%d update from revision " |
338 | "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]); | 329 | "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]); |
339 | return; | 330 | return; |
340 | } | 331 | } |
341 | printk(KERN_INFO "microcode: CPU%d updated from revision " | 332 | printk(KERN_INFO "microcode: CPU%d updated from revision " |
342 | "0x%x to 0x%x, date = %04x-%02x-%02x \n", | 333 | "0x%x to 0x%x, date = %04x-%02x-%02x \n", |
343 | cpu_num, uci->rev, val[1], | 334 | cpu_num, uci->cpu_sig.rev, val[1], |
344 | uci->mc.mc_intel->hdr.date & 0xffff, | 335 | uci->mc.mc_intel->hdr.date & 0xffff, |
345 | uci->mc.mc_intel->hdr.date >> 24, | 336 | uci->mc.mc_intel->hdr.date >> 24, |
346 | (uci->mc.mc_intel->hdr.date >> 16) & 0xff); | 337 | (uci->mc.mc_intel->hdr.date >> 16) & 0xff); |
347 | uci->rev = val[1]; | 338 | uci->cpu_sig.rev = val[1]; |
348 | } | 339 | } |
349 | 340 | ||
350 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE | 341 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE |
@@ -459,70 +450,18 @@ static int cpu_request_microcode(int cpu) | |||
459 | return error; | 450 | return error; |
460 | } | 451 | } |
461 | 452 | ||
462 | static int apply_microcode_check_cpu(int cpu) | ||
463 | { | ||
464 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
465 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
466 | cpumask_t old; | ||
467 | unsigned int val[2]; | ||
468 | int err = 0; | ||
469 | |||
470 | /* Check if the microcode is available */ | ||
471 | if (!uci->mc.mc_intel) | ||
472 | return 0; | ||
473 | |||
474 | old = current->cpus_allowed; | ||
475 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
476 | |||
477 | /* Check if the microcode we have in memory matches the CPU */ | ||
478 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | ||
479 | cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001)) | ||
480 | err = -EINVAL; | ||
481 | |||
482 | if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) { | ||
483 | /* get processor flags from MSR 0x17 */ | ||
484 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | ||
485 | if (uci->pf != (1 << ((val[1] >> 18) & 7))) | ||
486 | err = -EINVAL; | ||
487 | } | ||
488 | |||
489 | if (!err) { | ||
490 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
491 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
492 | sync_core(); | ||
493 | /* get the current revision from MSR 0x8B */ | ||
494 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); | ||
495 | if (uci->rev != val[1]) | ||
496 | err = -EINVAL; | ||
497 | } | ||
498 | |||
499 | if (!err) | ||
500 | apply_microcode(cpu); | ||
501 | else | ||
502 | printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:" | ||
503 | " sig=0x%x, pf=0x%x, rev=0x%x\n", | ||
504 | cpu, uci->sig, uci->pf, uci->rev); | ||
505 | |||
506 | set_cpus_allowed_ptr(current, &old); | ||
507 | return err; | ||
508 | } | ||
509 | |||
510 | static void microcode_fini_cpu(int cpu) | 453 | static void microcode_fini_cpu(int cpu) |
511 | { | 454 | { |
512 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 455 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
513 | 456 | ||
514 | mutex_lock(µcode_mutex); | ||
515 | uci->valid = 0; | ||
516 | vfree(uci->mc.mc_intel); | 457 | vfree(uci->mc.mc_intel); |
517 | uci->mc.mc_intel = NULL; | 458 | uci->mc.mc_intel = NULL; |
518 | mutex_unlock(µcode_mutex); | ||
519 | } | 459 | } |
520 | 460 | ||
521 | static struct microcode_ops microcode_intel_ops = { | 461 | static struct microcode_ops microcode_intel_ops = { |
522 | .get_next_ucode = get_next_ucode, | 462 | .get_next_ucode = get_next_ucode, |
523 | .get_matching_microcode = get_matching_microcode, | 463 | .get_matching_microcode = get_matching_microcode, |
524 | .microcode_sanity_check = microcode_sanity_check, | 464 | .microcode_sanity_check = microcode_sanity_check, |
525 | .apply_microcode_check_cpu = apply_microcode_check_cpu, | ||
526 | .cpu_request_microcode = cpu_request_microcode, | 465 | .cpu_request_microcode = cpu_request_microcode, |
527 | .collect_cpu_info = collect_cpu_info, | 466 | .collect_cpu_info = collect_cpu_info, |
528 | .apply_microcode = apply_microcode, | 467 | .apply_microcode = apply_microcode, |
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h index 18b2aeec2adf..7ceff48fa657 100644 --- a/include/asm-x86/microcode.h +++ b/include/asm-x86/microcode.h | |||
@@ -1,14 +1,18 @@ | |||
1 | #ifndef ASM_X86__MICROCODE_H | ||
2 | #define ASM_X86__MICROCODE_H | ||
3 | |||
1 | extern int microcode_init(void *opaque, struct module *module); | 4 | extern int microcode_init(void *opaque, struct module *module); |
2 | extern void microcode_exit(void); | 5 | extern void microcode_exit(void); |
3 | 6 | ||
7 | struct cpu_signature; | ||
8 | |||
4 | struct microcode_ops { | 9 | struct microcode_ops { |
5 | long (*get_next_ucode)(void **mc, long offset); | 10 | long (*get_next_ucode)(void **mc, long offset); |
6 | long (*microcode_get_next_ucode)(void **mc, long offset); | 11 | long (*microcode_get_next_ucode)(void **mc, long offset); |
7 | int (*get_matching_microcode)(void *mc, int cpu); | 12 | int (*get_matching_microcode)(void *mc, int cpu); |
8 | int (*apply_microcode_check_cpu)(int cpu); | ||
9 | int (*microcode_sanity_check)(void *mc); | 13 | int (*microcode_sanity_check)(void *mc); |
10 | int (*cpu_request_microcode)(int cpu); | 14 | int (*cpu_request_microcode)(int cpu); |
11 | void (*collect_cpu_info)(int cpu_num); | 15 | int (*collect_cpu_info)(int cpu_num, struct cpu_signature *csig); |
12 | void (*apply_microcode)(int cpu); | 16 | void (*apply_microcode)(int cpu); |
13 | void (*microcode_fini_cpu)(int cpu); | 17 | void (*microcode_fini_cpu)(int cpu); |
14 | void (*clear_patch)(void *data); | 18 | void (*clear_patch)(void *data); |
@@ -75,13 +79,21 @@ struct microcode_amd { | |||
75 | unsigned int mpb[0]; | 79 | unsigned int mpb[0]; |
76 | }; | 80 | }; |
77 | 81 | ||
78 | struct ucode_cpu_info { | 82 | struct cpu_signature { |
79 | int valid; | ||
80 | unsigned int sig; | 83 | unsigned int sig; |
81 | unsigned int pf; | 84 | unsigned int pf; |
82 | unsigned int rev; | 85 | unsigned int rev; |
86 | }; | ||
87 | |||
88 | struct ucode_cpu_info { | ||
89 | struct cpu_signature cpu_sig; | ||
90 | int valid; | ||
83 | union { | 91 | union { |
84 | struct microcode_intel *mc_intel; | 92 | struct microcode_intel *mc_intel; |
85 | struct microcode_amd *mc_amd; | 93 | struct microcode_amd *mc_amd; |
94 | void *valid_mc; | ||
86 | } mc; | 95 | } mc; |
87 | }; | 96 | }; |
97 | extern struct ucode_cpu_info ucode_cpu_info[]; | ||
98 | |||
99 | #endif /* ASM_X86__MICROCODE_H */ | ||