Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+61 −45
Original line number Diff line number Diff line
@@ -108,29 +108,40 @@ struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
EXPORT_SYMBOL_GPL(ucode_cpu_info);

#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)
{
	cpumask_t old;
	int error = 0;
	int cpu;

	old = current->cpus_allowed;
	struct update_for_cpu ufc = { .buf = buf, .size = size };

	for_each_online_cpu(cpu) {
		struct ucode_cpu_info *uci = ucode_cpu_info + cpu;

		if (!uci->valid)
			continue;

		set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
		error = microcode_ops->request_microcode_user(cpu, buf, size);
		error = work_on_cpu(cpu, update_for_cpu, &ufc);
		if (error < 0)
			goto out;
		if (!error)
			microcode_ops->apply_microcode(cpu);
			break;
	}
out:
	set_cpus_allowed_ptr(current, &old);
	return error;
}

@@ -205,11 +216,26 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
/* fake device for request_firmware */
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,
			    struct sysdev_attribute *attr,
			    const char *buf, size_t sz)
{
	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
	char *end;
	unsigned long val = simple_strtoul(buf, &end, 0);
	int err = 0;
@@ -218,21 +244,9 @@ static ssize_t reload_store(struct sys_device *dev,
	if (end == buf)
		return -EINVAL;
	if (val == 1) {
		cpumask_t old = current->cpus_allowed;

		get_online_cpus();
		if (cpu_online(cpu)) {
			set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
			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);
		}
		if (cpu_online(cpu))
			err = work_on_cpu(cpu, reload_for_cpu, NULL);
		put_online_cpus();
	}
	if (err)
@@ -328,9 +342,9 @@ static int microcode_resume_cpu(int cpu)
	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;

	/*
@@ -338,30 +352,27 @@ static void microcode_update_cpu(int cpu)
	 * otherwise just request a firmware:
	 */
	if (uci->valid) {
		err = microcode_resume_cpu(cpu);
		err = microcode_resume_cpu(smp_processor_id());
	} else {	
		collect_cpu_info(cpu);
		collect_cpu_info(smp_processor_id());
		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);
	}
	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;

	set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
	/* We should bind the task to the CPU */
	BUG_ON(raw_smp_processor_id() != cpu);

	int err;
	mutex_lock(&microcode_mutex);
	microcode_update_cpu(cpu);
	err = work_on_cpu(cpu, microcode_update_cpu, NULL);
	mutex_unlock(&microcode_mutex);

	set_cpus_allowed_ptr(current, &old);
	return err;
}

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)
		return err;

	microcode_init_cpu(cpu);
	return 0;
	err = microcode_init_cpu(cpu);
	if (err)
		sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);

	return err;
}

static int mc_sysdev_remove(struct sys_device *sys_dev)
@@ -404,7 +418,7 @@ static int mc_sysdev_resume(struct sys_device *dev)
		return 0;

	/* only CPU 0 will apply ucode here */
	microcode_update_cpu(0);
	microcode_update_cpu(NULL);
	return 0;
}

@@ -424,7 +438,9 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
	switch (action) {
	case CPU_ONLINE:
	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_FROZEN:
		pr_debug("microcode: CPU%d added\n", cpu);