aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/microcode.c62
-rw-r--r--kernel/cpu.c10
2 files changed, 36 insertions, 36 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 7d934e493e74..83f825f2e2d7 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -567,7 +567,7 @@ 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) 570static int apply_microcode_check_cpu(int cpu)
571{ 571{
572 struct cpuinfo_x86 *c = cpu_data + cpu; 572 struct cpuinfo_x86 *c = cpu_data + cpu;
573 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 573 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -575,8 +575,9 @@ static int apply_microcode_on_cpu(int cpu)
575 unsigned int val[2]; 575 unsigned int val[2];
576 int err = 0; 576 int err = 0;
577 577
578 /* Check if the microcode is available */
578 if (!uci->mc) 579 if (!uci->mc)
579 return -EINVAL; 580 return 0;
580 581
581 old = current->cpus_allowed; 582 old = current->cpus_allowed;
582 set_cpus_allowed(current, cpumask_of_cpu(cpu)); 583 set_cpus_allowed(current, cpumask_of_cpu(cpu));
@@ -614,7 +615,7 @@ static int apply_microcode_on_cpu(int cpu)
614 return err; 615 return err;
615} 616}
616 617
617static void microcode_init_cpu(int cpu) 618static void microcode_init_cpu(int cpu, int resume)
618{ 619{
619 cpumask_t old; 620 cpumask_t old;
620 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 621 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -624,8 +625,7 @@ static void microcode_init_cpu(int cpu)
624 set_cpus_allowed(current, cpumask_of_cpu(cpu)); 625 set_cpus_allowed(current, cpumask_of_cpu(cpu));
625 mutex_lock(&microcode_mutex); 626 mutex_lock(&microcode_mutex);
626 collect_cpu_info(cpu); 627 collect_cpu_info(cpu);
627 if (uci->valid && system_state == SYSTEM_RUNNING && 628 if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
628 !suspend_cpu_hotplug)
629 cpu_request_microcode(cpu); 629 cpu_request_microcode(cpu);
630 mutex_unlock(&microcode_mutex); 630 mutex_unlock(&microcode_mutex);
631 set_cpus_allowed(current, old); 631 set_cpus_allowed(current, old);
@@ -702,7 +702,7 @@ static struct attribute_group mc_attr_group = {
702 .name = "microcode", 702 .name = "microcode",
703}; 703};
704 704
705static int mc_sysdev_add(struct sys_device *sys_dev) 705static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
706{ 706{
707 int err, cpu = sys_dev->id; 707 int err, cpu = sys_dev->id;
708 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 708 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -711,39 +711,31 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
711 return 0; 711 return 0;
712 712
713 pr_debug("Microcode:CPU %d added\n", cpu); 713 pr_debug("Microcode:CPU %d added\n", cpu);
714 /* If suspend_cpu_hotplug is set, the system is resuming and we should 714 memset(uci, 0, sizeof(*uci));
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));
724 715
725 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); 716 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
726 if (err) 717 if (err)
727 return err; 718 return err;
728 719
729 if (!uci->valid) 720 microcode_init_cpu(cpu, resume);
730 microcode_init_cpu(cpu);
731 721
732 return 0; 722 return 0;
733} 723}
734 724
725static int mc_sysdev_add(struct sys_device *sys_dev)
726{
727 return __mc_sysdev_add(sys_dev, 0);
728}
729
735static int mc_sysdev_remove(struct sys_device *sys_dev) 730static int mc_sysdev_remove(struct sys_device *sys_dev)
736{ 731{
737 int cpu = sys_dev->id; 732 int cpu = sys_dev->id;
738 733
739 if (!cpu_online(cpu)) 734 if (!cpu_online(cpu))
740 return 0; 735 return 0;
736
741 pr_debug("Microcode:CPU %d removed\n", cpu); 737 pr_debug("Microcode:CPU %d removed\n", cpu);
742 /* If suspend_cpu_hotplug is set, the system is suspending and we should 738 microcode_fini_cpu(cpu);
743 * keep the microcode in memory for the resume.
744 */
745 if (!suspend_cpu_hotplug)
746 microcode_fini_cpu(cpu);
747 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); 739 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
748 return 0; 740 return 0;
749} 741}
@@ -774,16 +766,34 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
774 766
775 sys_dev = get_cpu_sysdev(cpu); 767 sys_dev = get_cpu_sysdev(cpu);
776 switch (action) { 768 switch (action) {
769 case CPU_UP_CANCELED_FROZEN:
770 /* The CPU refused to come up during a system resume */
771 microcode_fini_cpu(cpu);
772 break;
777 case CPU_ONLINE: 773 case CPU_ONLINE:
778 case CPU_ONLINE_FROZEN:
779 case CPU_DOWN_FAILED: 774 case CPU_DOWN_FAILED:
780 case CPU_DOWN_FAILED_FROZEN:
781 mc_sysdev_add(sys_dev); 775 mc_sysdev_add(sys_dev);
782 break; 776 break;
777 case CPU_ONLINE_FROZEN:
778 /* System-wide resume is in progress, try to apply microcode */
779 if (apply_microcode_check_cpu(cpu)) {
780 /* The application of microcode failed */
781 microcode_fini_cpu(cpu);
782 __mc_sysdev_add(sys_dev, 1);
783 break;
784 }
785 case CPU_DOWN_FAILED_FROZEN:
786 if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
787 printk(KERN_ERR "Microcode: Failed to create the sysfs "
788 "group for CPU%d\n", cpu);
789 break;
783 case CPU_DOWN_PREPARE: 790 case CPU_DOWN_PREPARE:
784 case CPU_DOWN_PREPARE_FROZEN:
785 mc_sysdev_remove(sys_dev); 791 mc_sysdev_remove(sys_dev);
786 break; 792 break;
793 case CPU_DOWN_PREPARE_FROZEN:
794 /* Suspend is in progress, only remove the interface */
795 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
796 break;
787 } 797 }
788 return NOTIFY_OK; 798 return NOTIFY_OK;
789} 799}
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 369d2892687d..208cf3497c10 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -262,12 +262,6 @@ int __cpuinit cpu_up(unsigned int cpu)
262} 262}
263 263
264#ifdef CONFIG_SUSPEND_SMP 264#ifdef CONFIG_SUSPEND_SMP
265/* Needed to prevent the microcode driver from requesting firmware in its CPU
266 * hotplug notifier during the suspend/resume.
267 */
268int suspend_cpu_hotplug;
269EXPORT_SYMBOL(suspend_cpu_hotplug);
270
271static cpumask_t frozen_cpus; 265static cpumask_t frozen_cpus;
272 266
273int disable_nonboot_cpus(void) 267int disable_nonboot_cpus(void)
@@ -275,7 +269,6 @@ int disable_nonboot_cpus(void)
275 int cpu, first_cpu, error = 0; 269 int cpu, first_cpu, error = 0;
276 270
277 mutex_lock(&cpu_add_remove_lock); 271 mutex_lock(&cpu_add_remove_lock);
278 suspend_cpu_hotplug = 1;
279 first_cpu = first_cpu(cpu_online_map); 272 first_cpu = first_cpu(cpu_online_map);
280 /* We take down all of the non-boot CPUs in one shot to avoid races 273 /* We take down all of the non-boot CPUs in one shot to avoid races
281 * with the userspace trying to use the CPU hotplug at the same time 274 * with the userspace trying to use the CPU hotplug at the same time
@@ -302,7 +295,6 @@ int disable_nonboot_cpus(void)
302 } else { 295 } else {
303 printk(KERN_ERR "Non-boot CPUs are not disabled\n"); 296 printk(KERN_ERR "Non-boot CPUs are not disabled\n");
304 } 297 }
305 suspend_cpu_hotplug = 0;
306 mutex_unlock(&cpu_add_remove_lock); 298 mutex_unlock(&cpu_add_remove_lock);
307 return error; 299 return error;
308} 300}
@@ -317,7 +309,6 @@ void enable_nonboot_cpus(void)
317 if (cpus_empty(frozen_cpus)) 309 if (cpus_empty(frozen_cpus))
318 goto out; 310 goto out;
319 311
320 suspend_cpu_hotplug = 1;
321 printk("Enabling non-boot CPUs ...\n"); 312 printk("Enabling non-boot CPUs ...\n");
322 for_each_cpu_mask(cpu, frozen_cpus) { 313 for_each_cpu_mask(cpu, frozen_cpus) {
323 error = _cpu_up(cpu, 1); 314 error = _cpu_up(cpu, 1);
@@ -328,7 +319,6 @@ void enable_nonboot_cpus(void)
328 printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error); 319 printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
329 } 320 }
330 cpus_clear(frozen_cpus); 321 cpus_clear(frozen_cpus);
331 suspend_cpu_hotplug = 0;
332out: 322out:
333 mutex_unlock(&cpu_add_remove_lock); 323 mutex_unlock(&cpu_add_remove_lock);
334} 324}