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

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

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
Loading
Loading
Loading
Loading
+36 −26
Original line number Diff line number Diff line
@@ -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,38 +711,30 @@ 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));

	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);
	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;
}
+0 −10
Original line number Diff line number Diff line
@@ -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);
}