Commit af5c820a authored by Rusty Russell's avatar Rusty Russell Committed by Ingo Molnar

x86: cpumask: use work_on_cpu in arch/x86/kernel/microcode_core.c

Impact: don't play with current's cpumask

Straightforward indirection through work_on_cpu().  One change is
that the error code from microcode_update_cpu() is now actually
plumbed back to microcode_init_cpu(), so now we printk if it fails
on cpu hotplug.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Dmitry Adamushko <dmitry.adamushko@gmail.com>
Cc: Peter Oruba <peter.oruba@amd.com>
LKML-Reference: <200903111632.37279.rusty@rustcorp.com.au>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 30e1e6d1
...@@ -108,29 +108,40 @@ struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; ...@@ -108,29 +108,40 @@ struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
EXPORT_SYMBOL_GPL(ucode_cpu_info); EXPORT_SYMBOL_GPL(ucode_cpu_info);
#ifdef CONFIG_MICROCODE_OLD_INTERFACE #ifdef CONFIG_MICROCODE_OLD_INTERFACE
struct update_for_cpu {
const void __user *buf;
size_t size;
};
static long update_for_cpu(void *_ufc)
{
struct update_for_cpu *ufc = _ufc;
int error;
error = microcode_ops->request_microcode_user(smp_processor_id(),
ufc->buf, ufc->size);
if (error < 0)
return error;
if (!error)
microcode_ops->apply_microcode(smp_processor_id());
return error;
}
static int do_microcode_update(const void __user *buf, size_t size) static int do_microcode_update(const void __user *buf, size_t size)
{ {
cpumask_t old;
int error = 0; int error = 0;
int cpu; int cpu;
struct update_for_cpu ufc = { .buf = buf, .size = size };
old = current->cpus_allowed;
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
if (!uci->valid) if (!uci->valid)
continue; continue;
error = work_on_cpu(cpu, update_for_cpu, &ufc);
set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
error = microcode_ops->request_microcode_user(cpu, buf, size);
if (error < 0) if (error < 0)
goto out; break;
if (!error)
microcode_ops->apply_microcode(cpu);
} }
out:
set_cpus_allowed_ptr(current, &old);
return error; return error;
} }
...@@ -205,11 +216,26 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); ...@@ -205,11 +216,26 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
/* fake device for request_firmware */ /* fake device for request_firmware */
static struct platform_device *microcode_pdev; static struct platform_device *microcode_pdev;
static long reload_for_cpu(void *unused)
{
struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id();
int err = 0;
mutex_lock(&microcode_mutex);
if (uci->valid) {
err = microcode_ops->request_microcode_fw(smp_processor_id(),
&microcode_pdev->dev);
if (!err)
microcode_ops->apply_microcode(smp_processor_id());
}
mutex_unlock(&microcode_mutex);
return err;
}
static ssize_t reload_store(struct sys_device *dev, static ssize_t reload_store(struct sys_device *dev,
struct sysdev_attribute *attr, struct sysdev_attribute *attr,
const char *buf, size_t sz) const char *buf, size_t sz)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
char *end; char *end;
unsigned long val = simple_strtoul(buf, &end, 0); unsigned long val = simple_strtoul(buf, &end, 0);
int err = 0; int err = 0;
...@@ -218,21 +244,9 @@ static ssize_t reload_store(struct sys_device *dev, ...@@ -218,21 +244,9 @@ static ssize_t reload_store(struct sys_device *dev,
if (end == buf) if (end == buf)
return -EINVAL; return -EINVAL;
if (val == 1) { if (val == 1) {
cpumask_t old = current->cpus_allowed;
get_online_cpus(); get_online_cpus();
if (cpu_online(cpu)) { if (cpu_online(cpu))
set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); err = work_on_cpu(cpu, reload_for_cpu, NULL);
mutex_lock(&microcode_mutex);
if (uci->valid) {
err = microcode_ops->request_microcode_fw(cpu,
&microcode_pdev->dev);
if (!err)
microcode_ops->apply_microcode(cpu);
}
mutex_unlock(&microcode_mutex);
set_cpus_allowed_ptr(current, &old);
}
put_online_cpus(); put_online_cpus();
} }
if (err) if (err)
...@@ -328,9 +342,9 @@ static int microcode_resume_cpu(int cpu) ...@@ -328,9 +342,9 @@ static int microcode_resume_cpu(int cpu)
return 0; return 0;
} }
static void microcode_update_cpu(int cpu) static long microcode_update_cpu(void *unused)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id();
int err = 0; int err = 0;
/* /*
...@@ -338,30 +352,27 @@ static void microcode_update_cpu(int cpu) ...@@ -338,30 +352,27 @@ static void microcode_update_cpu(int cpu)
* otherwise just request a firmware: * otherwise just request a firmware:
*/ */
if (uci->valid) { if (uci->valid) {
err = microcode_resume_cpu(cpu); err = microcode_resume_cpu(smp_processor_id());
} else { } else {
collect_cpu_info(cpu); collect_cpu_info(smp_processor_id());
if (uci->valid && system_state == SYSTEM_RUNNING) if (uci->valid && system_state == SYSTEM_RUNNING)
err = microcode_ops->request_microcode_fw(cpu, err = microcode_ops->request_microcode_fw(
smp_processor_id(),
&microcode_pdev->dev); &microcode_pdev->dev);
} }
if (!err) if (!err)
microcode_ops->apply_microcode(cpu); microcode_ops->apply_microcode(smp_processor_id());
return err;
} }
static void microcode_init_cpu(int cpu) static int microcode_init_cpu(int cpu)
{ {
cpumask_t old = current->cpus_allowed; int err;
set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
/* We should bind the task to the CPU */
BUG_ON(raw_smp_processor_id() != cpu);
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
microcode_update_cpu(cpu); err = work_on_cpu(cpu, microcode_update_cpu, NULL);
mutex_unlock(&microcode_mutex); mutex_unlock(&microcode_mutex);
set_cpus_allowed_ptr(current, &old); return err;
} }
static int mc_sysdev_add(struct sys_device *sys_dev) static int mc_sysdev_add(struct sys_device *sys_dev)
...@@ -379,8 +390,11 @@ static int mc_sysdev_add(struct sys_device *sys_dev) ...@@ -379,8 +390,11 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
if (err) if (err)
return err; return err;
microcode_init_cpu(cpu); err = microcode_init_cpu(cpu);
return 0; if (err)
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
return err;
} }
static int mc_sysdev_remove(struct sys_device *sys_dev) static int mc_sysdev_remove(struct sys_device *sys_dev)
...@@ -404,7 +418,7 @@ static int mc_sysdev_resume(struct sys_device *dev) ...@@ -404,7 +418,7 @@ static int mc_sysdev_resume(struct sys_device *dev)
return 0; return 0;
/* only CPU 0 will apply ucode here */ /* only CPU 0 will apply ucode here */
microcode_update_cpu(0); microcode_update_cpu(NULL);
return 0; return 0;
} }
...@@ -424,7 +438,9 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) ...@@ -424,7 +438,9 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
switch (action) { switch (action) {
case CPU_ONLINE: case CPU_ONLINE:
case CPU_ONLINE_FROZEN: case CPU_ONLINE_FROZEN:
microcode_init_cpu(cpu); if (microcode_init_cpu(cpu))
printk(KERN_ERR "microcode: failed to init CPU%d\n",
cpu);
case CPU_DOWN_FAILED: case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN: case CPU_DOWN_FAILED_FROZEN:
pr_debug("microcode: CPU%d added\n", cpu); pr_debug("microcode: CPU%d added\n", cpu);
......
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