Commit 455c017a authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

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: default avatarRafael J. Wysocki <rjw@sisk.pl>
Cc: Gautham R Shenoy <ego@in.ibm.com>
Cc: Pavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8bb78442
...@@ -567,7 +567,7 @@ static int cpu_request_microcode(int cpu) ...@@ -567,7 +567,7 @@ static int cpu_request_microcode(int cpu)
return error; return error;
} }
static int apply_microcode_on_cpu(int cpu) static int apply_microcode_check_cpu(int cpu)
{ {
struct cpuinfo_x86 *c = cpu_data + cpu; struct cpuinfo_x86 *c = cpu_data + cpu;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
...@@ -575,8 +575,9 @@ static int apply_microcode_on_cpu(int cpu) ...@@ -575,8 +575,9 @@ static int apply_microcode_on_cpu(int cpu)
unsigned int val[2]; unsigned int val[2];
int err = 0; int err = 0;
/* Check if the microcode is available */
if (!uci->mc) if (!uci->mc)
return -EINVAL; return 0;
old = current->cpus_allowed; old = current->cpus_allowed;
set_cpus_allowed(current, cpumask_of_cpu(cpu)); set_cpus_allowed(current, cpumask_of_cpu(cpu));
...@@ -614,7 +615,7 @@ static int apply_microcode_on_cpu(int cpu) ...@@ -614,7 +615,7 @@ static int apply_microcode_on_cpu(int cpu)
return err; return err;
} }
static void microcode_init_cpu(int cpu) static void microcode_init_cpu(int cpu, int resume)
{ {
cpumask_t old; cpumask_t old;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
...@@ -624,8 +625,7 @@ static void microcode_init_cpu(int cpu) ...@@ -624,8 +625,7 @@ static void microcode_init_cpu(int cpu)
set_cpus_allowed(current, cpumask_of_cpu(cpu)); set_cpus_allowed(current, cpumask_of_cpu(cpu));
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
collect_cpu_info(cpu); collect_cpu_info(cpu);
if (uci->valid && system_state == SYSTEM_RUNNING && if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
!suspend_cpu_hotplug)
cpu_request_microcode(cpu); cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex); mutex_unlock(&microcode_mutex);
set_cpus_allowed(current, old); set_cpus_allowed(current, old);
...@@ -702,7 +702,7 @@ static struct attribute_group mc_attr_group = { ...@@ -702,7 +702,7 @@ static struct attribute_group mc_attr_group = {
.name = "microcode", .name = "microcode",
}; };
static int mc_sysdev_add(struct sys_device *sys_dev) static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
{ {
int err, cpu = sys_dev->id; int err, cpu = sys_dev->id;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
...@@ -711,39 +711,31 @@ static int mc_sysdev_add(struct sys_device *sys_dev) ...@@ -711,39 +711,31 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
return 0; return 0;
pr_debug("Microcode:CPU %d added\n", cpu); pr_debug("Microcode:CPU %d added\n", cpu);
/* If suspend_cpu_hotplug is set, the system is resuming and we should memset(uci, 0, sizeof(*uci));
* use the data from before the suspend.
*/
if (suspend_cpu_hotplug) {
err = apply_microcode_on_cpu(cpu);
if (err)
microcode_fini_cpu(cpu);
}
if (!uci->valid)
memset(uci, 0, sizeof(*uci));
err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
if (err) if (err)
return err; return err;
if (!uci->valid) microcode_init_cpu(cpu, resume);
microcode_init_cpu(cpu);
return 0; return 0;
} }
static int mc_sysdev_add(struct sys_device *sys_dev)
{
return __mc_sysdev_add(sys_dev, 0);
}
static int mc_sysdev_remove(struct sys_device *sys_dev) static int mc_sysdev_remove(struct sys_device *sys_dev)
{ {
int cpu = sys_dev->id; int cpu = sys_dev->id;
if (!cpu_online(cpu)) if (!cpu_online(cpu))
return 0; return 0;
pr_debug("Microcode:CPU %d removed\n", cpu); pr_debug("Microcode:CPU %d removed\n", cpu);
/* If suspend_cpu_hotplug is set, the system is suspending and we should microcode_fini_cpu(cpu);
* keep the microcode in memory for the resume.
*/
if (!suspend_cpu_hotplug)
microcode_fini_cpu(cpu);
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
return 0; return 0;
} }
...@@ -774,16 +766,34 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) ...@@ -774,16 +766,34 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
sys_dev = get_cpu_sysdev(cpu); sys_dev = get_cpu_sysdev(cpu);
switch (action) { switch (action) {
case CPU_UP_CANCELED_FROZEN:
/* The CPU refused to come up during a system resume */
microcode_fini_cpu(cpu);
break;
case CPU_ONLINE: case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
case CPU_DOWN_FAILED: case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
mc_sysdev_add(sys_dev); mc_sysdev_add(sys_dev);
break; break;
case CPU_ONLINE_FROZEN:
/* System-wide resume is in progress, try to apply microcode */
if (apply_microcode_check_cpu(cpu)) {
/* The application of microcode failed */
microcode_fini_cpu(cpu);
__mc_sysdev_add(sys_dev, 1);
break;
}
case CPU_DOWN_FAILED_FROZEN:
if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
printk(KERN_ERR "Microcode: Failed to create the sysfs "
"group for CPU%d\n", cpu);
break;
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
mc_sysdev_remove(sys_dev); mc_sysdev_remove(sys_dev);
break; break;
case CPU_DOWN_PREPARE_FROZEN:
/* Suspend is in progress, only remove the interface */
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
break;
} }
return NOTIFY_OK; return NOTIFY_OK;
} }
......
...@@ -262,12 +262,6 @@ int __cpuinit cpu_up(unsigned int cpu) ...@@ -262,12 +262,6 @@ int __cpuinit cpu_up(unsigned int cpu)
} }
#ifdef CONFIG_SUSPEND_SMP #ifdef CONFIG_SUSPEND_SMP
/* Needed to prevent the microcode driver from requesting firmware in its CPU
* hotplug notifier during the suspend/resume.
*/
int suspend_cpu_hotplug;
EXPORT_SYMBOL(suspend_cpu_hotplug);
static cpumask_t frozen_cpus; static cpumask_t frozen_cpus;
int disable_nonboot_cpus(void) int disable_nonboot_cpus(void)
...@@ -275,7 +269,6 @@ int disable_nonboot_cpus(void) ...@@ -275,7 +269,6 @@ int disable_nonboot_cpus(void)
int cpu, first_cpu, error = 0; int cpu, first_cpu, error = 0;
mutex_lock(&cpu_add_remove_lock); mutex_lock(&cpu_add_remove_lock);
suspend_cpu_hotplug = 1;
first_cpu = first_cpu(cpu_online_map); first_cpu = first_cpu(cpu_online_map);
/* We take down all of the non-boot CPUs in one shot to avoid races /* We take down all of the non-boot CPUs in one shot to avoid races
* with the userspace trying to use the CPU hotplug at the same time * with the userspace trying to use the CPU hotplug at the same time
...@@ -302,7 +295,6 @@ int disable_nonboot_cpus(void) ...@@ -302,7 +295,6 @@ int disable_nonboot_cpus(void)
} else { } else {
printk(KERN_ERR "Non-boot CPUs are not disabled\n"); printk(KERN_ERR "Non-boot CPUs are not disabled\n");
} }
suspend_cpu_hotplug = 0;
mutex_unlock(&cpu_add_remove_lock); mutex_unlock(&cpu_add_remove_lock);
return error; return error;
} }
...@@ -317,7 +309,6 @@ void enable_nonboot_cpus(void) ...@@ -317,7 +309,6 @@ void enable_nonboot_cpus(void)
if (cpus_empty(frozen_cpus)) if (cpus_empty(frozen_cpus))
goto out; goto out;
suspend_cpu_hotplug = 1;
printk("Enabling non-boot CPUs ...\n"); printk("Enabling non-boot CPUs ...\n");
for_each_cpu_mask(cpu, frozen_cpus) { for_each_cpu_mask(cpu, frozen_cpus) {
error = _cpu_up(cpu, 1); error = _cpu_up(cpu, 1);
...@@ -328,7 +319,6 @@ void enable_nonboot_cpus(void) ...@@ -328,7 +319,6 @@ void enable_nonboot_cpus(void)
printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error); printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
} }
cpus_clear(frozen_cpus); cpus_clear(frozen_cpus);
suspend_cpu_hotplug = 0;
out: out:
mutex_unlock(&cpu_add_remove_lock); mutex_unlock(&cpu_add_remove_lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment