diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2007-05-09 05:35:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-09 15:30:56 -0400 |
commit | 455c017ae3934797653549704c286e7bcc3a9397 (patch) | |
tree | 7b5b67916b064e3ce7868082e0915f37b437aeb8 /arch/i386 | |
parent | 8bb7844286fb8c9fce6f65d8288aeb09d03a5e0d (diff) |
microcode: use suspend-related CPU hotplug notifications
Make the microcode driver use the suspend-related CPU hotplug notifications
to handle the CPU hotplug events occuring during system-wide suspend and
resume transitions. Remove the global variable suspend_cpu_hotplug
previously used for this purpose.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Gautham R Shenoy <ego@in.ibm.com>
Cc: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/microcode.c | 62 |
1 files changed, 36 insertions, 26 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 | ||
570 | static int apply_microcode_on_cpu(int cpu) | 570 | static 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 | ||
617 | static void microcode_init_cpu(int cpu) | 618 | static 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(µcode_mutex); | 626 | mutex_lock(µcode_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(µcode_mutex); | 630 | mutex_unlock(µcode_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 | ||
705 | static int mc_sysdev_add(struct sys_device *sys_dev) | 705 | static 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 | ||
725 | static int mc_sysdev_add(struct sys_device *sys_dev) | ||
726 | { | ||
727 | return __mc_sysdev_add(sys_dev, 0); | ||
728 | } | ||
729 | |||
735 | static int mc_sysdev_remove(struct sys_device *sys_dev) | 730 | static 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 | } |