Commit 46e1d5e9 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'pm-cpufreq-fixes' and 'pm-cpuidle-fixes'

* pm-cpufreq-fixes:
  cpufreq: Fix creation of symbolic links to policy directories

* pm-cpuidle-fixes:
  cpuidle: powernv: Pass correct drv->cpumask for registration
...@@ -918,11 +918,19 @@ static struct kobj_type ktype_cpufreq = { ...@@ -918,11 +918,19 @@ static struct kobj_type ktype_cpufreq = {
.release = cpufreq_sysfs_release, .release = cpufreq_sysfs_release,
}; };
static int add_cpu_dev_symlink(struct cpufreq_policy *policy, static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu)
struct device *dev)
{ {
struct device *dev = get_cpu_device(cpu);
if (!dev)
return;
if (cpumask_test_and_set_cpu(cpu, policy->real_cpus))
return;
dev_dbg(dev, "%s: Adding symlink\n", __func__); dev_dbg(dev, "%s: Adding symlink\n", __func__);
return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); if (sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"))
dev_err(dev, "cpufreq symlink creation failed\n");
} }
static void remove_cpu_dev_symlink(struct cpufreq_policy *policy, static void remove_cpu_dev_symlink(struct cpufreq_policy *policy,
...@@ -1180,10 +1188,10 @@ static int cpufreq_online(unsigned int cpu) ...@@ -1180,10 +1188,10 @@ static int cpufreq_online(unsigned int cpu)
policy->user_policy.min = policy->min; policy->user_policy.min = policy->min;
policy->user_policy.max = policy->max; policy->user_policy.max = policy->max;
write_lock_irqsave(&cpufreq_driver_lock, flags); for_each_cpu(j, policy->related_cpus) {
for_each_cpu(j, policy->related_cpus)
per_cpu(cpufreq_cpu_data, j) = policy; per_cpu(cpufreq_cpu_data, j) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); add_cpu_dev_symlink(policy, j);
}
} else { } else {
policy->min = policy->user_policy.min; policy->min = policy->user_policy.min;
policy->max = policy->user_policy.max; policy->max = policy->user_policy.max;
...@@ -1275,13 +1283,15 @@ static int cpufreq_online(unsigned int cpu) ...@@ -1275,13 +1283,15 @@ static int cpufreq_online(unsigned int cpu)
if (cpufreq_driver->exit) if (cpufreq_driver->exit)
cpufreq_driver->exit(policy); cpufreq_driver->exit(policy);
for_each_cpu(j, policy->real_cpus)
remove_cpu_dev_symlink(policy, get_cpu_device(j));
out_free_policy: out_free_policy:
cpufreq_policy_free(policy); cpufreq_policy_free(policy);
return ret; return ret;
} }
static int cpufreq_offline(unsigned int cpu);
/** /**
* cpufreq_add_dev - the cpufreq interface for a CPU device. * cpufreq_add_dev - the cpufreq interface for a CPU device.
* @dev: CPU device. * @dev: CPU device.
...@@ -1303,16 +1313,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) ...@@ -1303,16 +1313,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
/* Create sysfs link on CPU registration */ /* Create sysfs link on CPU registration */
policy = per_cpu(cpufreq_cpu_data, cpu); policy = per_cpu(cpufreq_cpu_data, cpu);
if (!policy || cpumask_test_and_set_cpu(cpu, policy->real_cpus)) if (policy)
return 0; add_cpu_dev_symlink(policy, cpu);
ret = add_cpu_dev_symlink(policy, dev); return 0;
if (ret) {
cpumask_clear_cpu(cpu, policy->real_cpus);
cpufreq_offline(cpu);
}
return ret;
} }
static int cpufreq_offline(unsigned int cpu) static int cpufreq_offline(unsigned int cpu)
......
...@@ -175,6 +175,24 @@ static int powernv_cpuidle_driver_init(void) ...@@ -175,6 +175,24 @@ static int powernv_cpuidle_driver_init(void)
drv->state_count += 1; drv->state_count += 1;
} }
/*
* On the PowerNV platform cpu_present may be less than cpu_possible in
* cases when firmware detects the CPU, but it is not available to the
* OS. If CONFIG_HOTPLUG_CPU=n, then such CPUs are not hotplugable at
* run time and hence cpu_devices are not created for those CPUs by the
* generic topology_init().
*
* drv->cpumask defaults to cpu_possible_mask in
* __cpuidle_driver_init(). This breaks cpuidle on PowerNV where
* cpu_devices are not created for CPUs in cpu_possible_mask that
* cannot be hot-added later at run time.
*
* Trying cpuidle_register_device() on a CPU without a cpu_device is
* incorrect, so pass a correct CPU mask to the generic cpuidle driver.
*/
drv->cpumask = (struct cpumask *)cpu_present_mask;
return 0; return 0;
} }
......
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