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>
This commit is contained in:
Родитель
8bb7844286
Коммит
455c017ae3
|
@ -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(µcode_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(µcode_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;
|
||||
}
|
||||
|
|
10
kernel/cpu.c
10
kernel/cpu.c
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче