aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/microcode.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/microcode.c')
-rw-r--r--arch/i386/kernel/microcode.c71
1 files changed, 67 insertions, 4 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index b8f16633a6ec..cbe7ec8dbb9f 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -567,6 +567,53 @@ static int cpu_request_microcode(int cpu)
567 return error; 567 return error;
568} 568}
569 569
570static int apply_microcode_on_cpu(int cpu)
571{
572 struct cpuinfo_x86 *c = cpu_data + cpu;
573 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
574 cpumask_t old;
575 unsigned int val[2];
576 int err = 0;
577
578 if (!uci->mc)
579 return -EINVAL;
580
581 old = current->cpus_allowed;
582 set_cpus_allowed(current, cpumask_of_cpu(cpu));
583
584 /* Check if the microcode we have in memory matches the CPU */
585 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
586 cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
587 err = -EINVAL;
588
589 if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
590 /* get processor flags from MSR 0x17 */
591 rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
592 if (uci->pf != (1 << ((val[1] >> 18) & 7)))
593 err = -EINVAL;
594 }
595
596 if (!err) {
597 wrmsr(MSR_IA32_UCODE_REV, 0, 0);
598 /* see notes above for revision 1.07. Apparent chip bug */
599 sync_core();
600 /* get the current revision from MSR 0x8B */
601 rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
602 if (uci->rev != val[1])
603 err = -EINVAL;
604 }
605
606 if (!err)
607 apply_microcode(cpu);
608 else
609 printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
610 " sig=0x%x, pf=0x%x, rev=0x%x\n",
611 cpu, uci->sig, uci->pf, uci->rev);
612
613 set_cpus_allowed(current, old);
614 return err;
615}
616
570static void microcode_init_cpu(int cpu) 617static void microcode_init_cpu(int cpu)
571{ 618{
572 cpumask_t old; 619 cpumask_t old;
@@ -577,7 +624,8 @@ static void microcode_init_cpu(int cpu)
577 set_cpus_allowed(current, cpumask_of_cpu(cpu)); 624 set_cpus_allowed(current, cpumask_of_cpu(cpu));
578 mutex_lock(&microcode_mutex); 625 mutex_lock(&microcode_mutex);
579 collect_cpu_info(cpu); 626 collect_cpu_info(cpu);
580 if (uci->valid && system_state == SYSTEM_RUNNING) 627 if (uci->valid && system_state == SYSTEM_RUNNING &&
628 !suspend_cpu_hotplug)
581 cpu_request_microcode(cpu); 629 cpu_request_microcode(cpu);
582 mutex_unlock(&microcode_mutex); 630 mutex_unlock(&microcode_mutex);
583 set_cpus_allowed(current, old); 631 set_cpus_allowed(current, old);
@@ -663,13 +711,24 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
663 return 0; 711 return 0;
664 712
665 pr_debug("Microcode:CPU %d added\n", cpu); 713 pr_debug("Microcode:CPU %d added\n", cpu);
666 memset(uci, 0, sizeof(*uci)); 714 /* If suspend_cpu_hotplug is set, the system is resuming and we should
715 * use the data from before the suspend.
716 */
717 if (suspend_cpu_hotplug) {
718 err = apply_microcode_on_cpu(cpu);
719 if (err)
720 microcode_fini_cpu(cpu);
721 }
722 if (!uci->valid)
723 memset(uci, 0, sizeof(*uci));
667 724
668 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); 725 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
669 if (err) 726 if (err)
670 return err; 727 return err;
671 728
672 microcode_init_cpu(cpu); 729 if (!uci->valid)
730 microcode_init_cpu(cpu);
731
673 return 0; 732 return 0;
674} 733}
675 734
@@ -680,7 +739,11 @@ static int mc_sysdev_remove(struct sys_device *sys_dev)
680 if (!cpu_online(cpu)) 739 if (!cpu_online(cpu))
681 return 0; 740 return 0;
682 pr_debug("Microcode:CPU %d removed\n", cpu); 741 pr_debug("Microcode:CPU %d removed\n", cpu);
683 microcode_fini_cpu(cpu); 742 /* If suspend_cpu_hotplug is set, the system is suspending and we should
743 * keep the microcode in memory for the resume.
744 */
745 if (!suspend_cpu_hotplug)
746 microcode_fini_cpu(cpu);
684 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); 747 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
685 return 0; 748 return 0;
686} 749}