summaryrefslogtreecommitdiff
path: root/drivers/thermal/cpu_cooling.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-09-24 20:14:26 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-24 20:14:26 -0700
commitced255c0c5fb9ab52c9465982f23b1c14005ef8b (patch)
treedfe7c308312ca57a612fc687a31d3a6a6e6ea3f0 /drivers/thermal/cpu_cooling.c
parent4401555a98601a3de7cc876ceeac1d5d09f617e6 (diff)
parent97584d1838b7e2545c3b10aacef3327fcaa9531b (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management fixes from Zhang Rui: - Power allocator governor changes to allow binding on thermal zones with missing power estimates information. From Javi Merino. - Add compile test flags on thermal drivers that allow it without producing compilation errors. From Eduardo Valentin. - Fixes around memory allocation on cpu_cooling. From Javi Merino. - Fix on db8500 cpufreq code to allow autoload. From Luis de Bethencourt. - Maintainer entries for cpu cooling device * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: thermal: power_allocator: exit early if there are no cooling devices thermal: power_allocator: don't require tzp to be present for the thermal zone thermal: power_allocator: relax the requirement of two passive trip points thermal: power_allocator: relax the requirement of a sustainable_power in tzp thermal: Add a function to get the minimum power thermal: cpu_cooling: free power table on error or when unregistering thermal: cpu_cooling: don't call kcalloc() under rcu_read_lock thermal: db8500_cpufreq_cooling: Fix module autoload for OF platform driver thermal: cpu_cooling: Add MAINTAINERS entry thermal: ti-soc: Kconfig fix to avoid menu showing wrongly thermal: ti-soc: allow compile test thermal: qcom_spmi: allow compile test thermal: exynos: allow compile test thermal: armada: allow compile test thermal: dove: allow compile test thermal: kirkwood: allow compile test thermal: rockchip: allow compile test thermal: spear: allow compile test thermal: hisi: allow compile test thermal: Fix thermal_zone_of_sensor_register to match documentation
Diffstat (limited to 'drivers/thermal/cpu_cooling.c')
-rw-r--r--drivers/thermal/cpu_cooling.c52
1 files changed, 31 insertions, 21 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 620dcd405ff6..42c6f71bdcc1 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -262,7 +262,9 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
* efficiently. Power is stored in mW, frequency in KHz. The
* resulting table is in ascending order.
*
- * Return: 0 on success, -E* on error.
+ * Return: 0 on success, -EINVAL if there are no OPPs for any CPUs,
+ * -ENOMEM if we run out of memory or -EAGAIN if an OPP was
+ * added/enabled while the function was executing.
*/
static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
u32 capacitance)
@@ -273,8 +275,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
int num_opps = 0, cpu, i, ret = 0;
unsigned long freq;
- rcu_read_lock();
-
for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {
dev = get_cpu_device(cpu);
if (!dev) {
@@ -284,24 +284,20 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
}
num_opps = dev_pm_opp_get_opp_count(dev);
- if (num_opps > 0) {
+ if (num_opps > 0)
break;
- } else if (num_opps < 0) {
- ret = num_opps;
- goto unlock;
- }
+ else if (num_opps < 0)
+ return num_opps;
}
- if (num_opps == 0) {
- ret = -EINVAL;
- goto unlock;
- }
+ if (num_opps == 0)
+ return -EINVAL;
power_table = kcalloc(num_opps, sizeof(*power_table), GFP_KERNEL);
- if (!power_table) {
- ret = -ENOMEM;
- goto unlock;
- }
+ if (!power_table)
+ return -ENOMEM;
+
+ rcu_read_lock();
for (freq = 0, i = 0;
opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
@@ -309,6 +305,12 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
u32 freq_mhz, voltage_mv;
u64 power;
+ if (i >= num_opps) {
+ rcu_read_unlock();
+ ret = -EAGAIN;
+ goto free_power_table;
+ }
+
freq_mhz = freq / 1000000;
voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
@@ -326,17 +328,22 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
power_table[i].power = power;
}
- if (i == 0) {
+ rcu_read_unlock();
+
+ if (i != num_opps) {
ret = PTR_ERR(opp);
- goto unlock;
+ goto free_power_table;
}
cpufreq_device->cpu_dev = dev;
cpufreq_device->dyn_power_table = power_table;
cpufreq_device->dyn_power_table_entries = i;
-unlock:
- rcu_read_unlock();
+ return 0;
+
+free_power_table:
+ kfree(power_table);
+
return ret;
}
@@ -847,7 +854,7 @@ __cpufreq_cooling_register(struct device_node *np,
ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
if (ret) {
cool_dev = ERR_PTR(ret);
- goto free_table;
+ goto free_power_table;
}
snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
@@ -889,6 +896,8 @@ __cpufreq_cooling_register(struct device_node *np,
remove_idr:
release_idr(&cpufreq_idr, cpufreq_dev->id);
+free_power_table:
+ kfree(cpufreq_dev->dyn_power_table);
free_table:
kfree(cpufreq_dev->freq_table);
free_time_in_idle_timestamp:
@@ -1039,6 +1048,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
release_idr(&cpufreq_idr, cpufreq_dev->id);
+ kfree(cpufreq_dev->dyn_power_table);
kfree(cpufreq_dev->time_in_idle_timestamp);
kfree(cpufreq_dev->time_in_idle);
kfree(cpufreq_dev->freq_table);