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

Commit a82fab29 authored by Srivatsa S. Bhat's avatar Srivatsa S. Bhat Committed by Rafael J. Wysocki
Browse files

cpufreq: Introduce a flag ('frozen') to separate full vs temporary init/teardown



During suspend/resume we would like to do a light-weight init/teardown of
CPUs in the cpufreq subsystem and preserve certain things such as sysfs files
etc across suspend/resume transitions. Add a flag called 'frozen' to help
distinguish the full init/teardown sequence from the light-weight one.

Signed-off-by: default avatarSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent f9ba680d
Loading
Loading
Loading
Loading
+49 −27
Original line number Diff line number Diff line
@@ -903,7 +903,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)

#ifdef CONFIG_HOTPLUG_CPU
static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
				  struct device *dev)
				  struct device *dev, bool frozen)
{
	struct cpufreq_policy *policy;
	int ret = 0, has_target = !!cpufreq_driver->target;
@@ -931,13 +931,18 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
		__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
	}

	ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
	if (ret) {
	/* Don't touch sysfs links during light-weight init */
	if (frozen) {
		/* Drop the extra refcount that we took above */
		cpufreq_cpu_put(policy);
		return ret;
		return 0;
	}

	return 0;
	ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
	if (ret)
		cpufreq_cpu_put(policy);

	return ret;
}
#endif

@@ -972,16 +977,8 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
	kfree(policy);
}

/**
 * cpufreq_add_dev - add a CPU device
 *
 * Adds the cpufreq interface for a CPU device.
 *
 * The Oracle says: try running cpufreq registration/unregistration concurrently
 * with with cpu hotplugging and all hell will break loose. Tried to clean this
 * mess up, but more thorough testing is needed. - Mathieu
 */
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
			     bool frozen)
{
	unsigned int j, cpu = dev->id;
	int ret = -ENOMEM;
@@ -1013,7 +1010,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
		struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
		if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
			read_unlock_irqrestore(&cpufreq_driver_lock, flags);
			return cpufreq_add_policy_cpu(cpu, sibling, dev);
			return cpufreq_add_policy_cpu(cpu, sibling, dev,
						      frozen);
		}
	}
	read_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -1079,9 +1077,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
	}
	write_unlock_irqrestore(&cpufreq_driver_lock, flags);

	if (!frozen) {
		ret = cpufreq_add_dev_interface(cpu, policy, dev);
		if (ret)
			goto err_out_unregister;
	}

	cpufreq_init_policy(policy);

@@ -1112,6 +1112,20 @@ module_out:
	return ret;
}

/**
 * cpufreq_add_dev - add a CPU device
 *
 * Adds the cpufreq interface for a CPU device.
 *
 * The Oracle says: try running cpufreq registration/unregistration concurrently
 * with with cpu hotplugging and all hell will break loose. Tried to clean this
 * mess up, but more thorough testing is needed. - Mathieu
 */
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
	return __cpufreq_add_dev(dev, sif, false);
}

static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
{
	int j;
@@ -1130,7 +1144,7 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
}

static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
					   unsigned int old_cpu)
					   unsigned int old_cpu, bool frozen)
{
	struct device *cpu_dev;
	unsigned long flags;
@@ -1138,6 +1152,11 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,

	/* first sibling now owns the new sysfs dir */
	cpu_dev = get_cpu_device(cpumask_first(data->cpus));

	/* Don't touch sysfs files during light-weight tear-down */
	if (frozen)
		return cpu_dev->id;

	sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
	ret = kobject_move(&data->kobj, &cpu_dev->kobj);
	if (ret) {
@@ -1169,7 +1188,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
 * This routine frees the rwsem before returning.
 */
static int __cpufreq_remove_dev(struct device *dev,
		struct subsys_interface *sif)
				struct subsys_interface *sif, bool frozen)
{
	unsigned int cpu = dev->id, cpus;
	int new_cpu;
@@ -1208,19 +1227,22 @@ static int __cpufreq_remove_dev(struct device *dev,
		cpumask_clear_cpu(cpu, data->cpus);
	unlock_policy_rwsem_write(cpu);

	if (cpu != data->cpu) {
	if (cpu != data->cpu && !frozen) {
		sysfs_remove_link(&dev->kobj, "cpufreq");
	} else if (cpus > 1) {

		new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu);
		new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu, frozen);
		if (new_cpu >= 0) {
			WARN_ON(lock_policy_rwsem_write(cpu));
			update_policy_cpu(data, new_cpu);
			unlock_policy_rwsem_write(cpu);

			if (!frozen) {
				pr_debug("%s: policy Kobject moved to cpu: %d "
					 "from: %d\n",__func__, new_cpu, cpu);
			}
		}
	}

	/* If cpu is last user of policy, free policy */
	if (cpus == 1) {
@@ -1266,7 +1288,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
	if (cpu_is_offline(cpu))
		return 0;

	retval = __cpufreq_remove_dev(dev, sif);
	retval = __cpufreq_remove_dev(dev, sif, false);
	return retval;
}

@@ -1992,7 +2014,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
			break;
		case CPU_DOWN_PREPARE:
		case CPU_DOWN_PREPARE_FROZEN:
			__cpufreq_remove_dev(dev, NULL);
			__cpufreq_remove_dev(dev, NULL, false);
			break;
		case CPU_DOWN_FAILED:
		case CPU_DOWN_FAILED_FROZEN: