Skip to content

Commit

Permalink
Merge tag 'pm-4.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/rafael/linux-pm

Pull power management fixes from Rafael Wysocki:
 "These fix a cpufreq core issue with the initialization of the cpufreq
  sysfs interface and a cpuidle powernv driver initialization issue.

  Specifics:

   - symbolic links from CPU directories to the corresponding cpufreq
     policy directories in sysfs are not created during initialization
     in some cases which confuses user space, so prevent that from
     happening (Rafael Wysocki).

   - the powernv cpuidle driver fails to pass a correct cpumaks to the
     cpuidle core in some cases which causes subsequent failures to
     occur, so fix it (Vaidyanathan Srinivasan)"

* tag 'pm-4.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  cpuidle: powernv: Pass correct drv->cpumask for registration
  cpufreq: Fix creation of symbolic links to policy directories
  • Loading branch information
torvalds committed Apr 1, 2017
2 parents 1300dc6 + 46e1d5e commit 0d2ceec
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 17 deletions.
38 changes: 21 additions & 17 deletions drivers/cpufreq/cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -918,11 +918,19 @@ static struct kobj_type ktype_cpufreq = {
.release = cpufreq_sysfs_release,
};

static int add_cpu_dev_symlink(struct cpufreq_policy *policy,
struct device *dev)
static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu)
{
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__);
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,
Expand Down Expand Up @@ -1180,10 +1188,10 @@ static int cpufreq_online(unsigned int cpu)
policy->user_policy.min = policy->min;
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;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
add_cpu_dev_symlink(policy, j);
}
} else {
policy->min = policy->user_policy.min;
policy->max = policy->user_policy.max;
Expand Down Expand Up @@ -1275,13 +1283,15 @@ static int cpufreq_online(unsigned int cpu)

if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);

for_each_cpu(j, policy->real_cpus)
remove_cpu_dev_symlink(policy, get_cpu_device(j));

out_free_policy:
cpufreq_policy_free(policy);
return ret;
}

static int cpufreq_offline(unsigned int cpu);

/**
* cpufreq_add_dev - the cpufreq interface for a CPU device.
* @dev: CPU device.
Expand All @@ -1303,16 +1313,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)

/* Create sysfs link on CPU registration */
policy = per_cpu(cpufreq_cpu_data, cpu);
if (!policy || cpumask_test_and_set_cpu(cpu, policy->real_cpus))
return 0;
if (policy)
add_cpu_dev_symlink(policy, cpu);

ret = add_cpu_dev_symlink(policy, dev);
if (ret) {
cpumask_clear_cpu(cpu, policy->real_cpus);
cpufreq_offline(cpu);
}

return ret;
return 0;
}

static int cpufreq_offline(unsigned int cpu)
Expand Down
18 changes: 18 additions & 0 deletions drivers/cpuidle/cpuidle-powernv.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,24 @@ static int powernv_cpuidle_driver_init(void)
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;
}

Expand Down

0 comments on commit 0d2ceec

Please sign in to comment.