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)
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 ucode_cpu_info *uci = ucode_cpu_info + cpu;
......@@ -575,8 +575,9 @@ static int apply_microcode_on_cpu(int cpu)
unsigned int val[2];
int err = 0;
/* Check if the microcode is available */
if (!uci->mc)
return -EINVAL;
return 0;
old = current->cpus_allowed;
set_cpus_allowed(current, cpumask_of_cpu(cpu));
......@@ -614,7 +615,7 @@ static int apply_microcode_on_cpu(int cpu)
return err;
}
static void microcode_init_cpu(int cpu)
static void microcode_init_cpu(int cpu, int resume)
{
cpumask_t old;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
......@@ -624,8 +625,7 @@ static void microcode_init_cpu(int cpu)
set_cpus_allowed(current, cpumask_of_cpu(cpu));
mutex_lock(&microcode_mutex);
collect_cpu_info(cpu);
if (uci->valid && system_state == SYSTEM_RUNNING &&
!suspend_cpu_hotplug)
if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex);
set_cpus_allowed(current, old);
......@@ -702,7 +702,7 @@ static struct attribute_group mc_attr_group = {
.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;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
......@@ -711,39 +711,31 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
return 0;
pr_debug("Microcode:CPU %d added\n", cpu);
/* If suspend_cpu_hotplug is set, the system is resuming and we should
* 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));
memset(uci, 0, sizeof(*uci));
err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
if (err)
return err;
if (!uci->valid)
microcode_init_cpu(cpu);
microcode_init_cpu(cpu, resume);
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)
{
int cpu = sys_dev->id;
if (!cpu_online(cpu))
return 0;
pr_debug("Microcode:CPU %d removed\n", cpu);
/* If suspend_cpu_hotplug is set, the system is suspending and we should
* keep the microcode in memory for the resume.
*/
if (!suspend_cpu_hotplug)
microcode_fini_cpu(cpu);
microcode_fini_cpu(cpu);
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
return 0;
}
......@@ -774,16 +766,34 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
sys_dev = get_cpu_sysdev(cpu);
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_FROZEN:
case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
mc_sysdev_add(sys_dev);
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_FROZEN:
mc_sysdev_remove(sys_dev);
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;
}
......
......@@ -262,12 +262,6 @@ int __cpuinit cpu_up(unsigned int cpu)
}
#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;
int disable_nonboot_cpus(void)
......@@ -275,7 +269,6 @@ int disable_nonboot_cpus(void)
int cpu, first_cpu, error = 0;
mutex_lock(&cpu_add_remove_lock);
suspend_cpu_hotplug = 1;
first_cpu = first_cpu(cpu_online_map);
/* 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
......@@ -302,7 +295,6 @@ int disable_nonboot_cpus(void)
} else {
printk(KERN_ERR "Non-boot CPUs are not disabled\n");
}
suspend_cpu_hotplug = 0;
mutex_unlock(&cpu_add_remove_lock);
return error;
}
......@@ -317,7 +309,6 @@ void enable_nonboot_cpus(void)
if (cpus_empty(frozen_cpus))
goto out;
suspend_cpu_hotplug = 1;
printk("Enabling non-boot CPUs ...\n");
for_each_cpu_mask(cpu, frozen_cpus) {
error = _cpu_up(cpu, 1);
......@@ -328,7 +319,6 @@ void enable_nonboot_cpus(void)
printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
}
cpus_clear(frozen_cpus);
suspend_cpu_hotplug = 0;
out:
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