Commit 5d72ed35 authored by Zhang Rui's avatar Zhang Rui

Merge branches 'thermal-core', 'thermal-intel' and 'thermal-soc' into next

...@@ -540,7 +540,7 @@ static void bL_cpufreq_ready(struct cpufreq_policy *policy) ...@@ -540,7 +540,7 @@ static void bL_cpufreq_ready(struct cpufreq_policy *policy)
&power_coefficient); &power_coefficient);
cdev[cur_cluster] = of_cpufreq_power_cooling_register(np, cdev[cur_cluster] = of_cpufreq_power_cooling_register(np,
policy->related_cpus, power_coefficient, NULL); policy, power_coefficient, NULL);
if (IS_ERR(cdev[cur_cluster])) { if (IS_ERR(cdev[cur_cluster])) {
dev_err(cpu_dev, dev_err(cpu_dev,
"running cpufreq without cooling device: %ld\n", "running cpufreq without cooling device: %ld\n",
......
...@@ -326,7 +326,7 @@ static void cpufreq_ready(struct cpufreq_policy *policy) ...@@ -326,7 +326,7 @@ static void cpufreq_ready(struct cpufreq_policy *policy)
&power_coefficient); &power_coefficient);
priv->cdev = of_cpufreq_power_cooling_register(np, priv->cdev = of_cpufreq_power_cooling_register(np,
policy->related_cpus, power_coefficient, NULL); policy, power_coefficient, NULL);
if (IS_ERR(priv->cdev)) { if (IS_ERR(priv->cdev)) {
dev_err(priv->cpu_dev, dev_err(priv->cpu_dev,
"running cpufreq without cooling device: %ld\n", "running cpufreq without cooling device: %ld\n",
......
...@@ -170,11 +170,10 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) ...@@ -170,11 +170,10 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
unsigned int i = 0, count = 0, ret = -ENOMEM; unsigned int i = 0, count = 0, ret = -ENOMEM;
struct cpufreq_stats *stats; struct cpufreq_stats *stats;
unsigned int alloc_size; unsigned int alloc_size;
struct cpufreq_frequency_table *pos, *table; struct cpufreq_frequency_table *pos;
/* We need cpufreq table for creating stats table */ count = cpufreq_table_count_valid_entries(policy);
table = policy->freq_table; if (!count)
if (unlikely(!table))
return; return;
/* stats already initialized */ /* stats already initialized */
...@@ -185,10 +184,6 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) ...@@ -185,10 +184,6 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
if (!stats) if (!stats)
return; return;
/* Find total allocation size */
cpufreq_for_each_valid_entry(pos, table)
count++;
alloc_size = count * sizeof(int) + count * sizeof(u64); alloc_size = count * sizeof(int) + count * sizeof(u64);
alloc_size += count * count * sizeof(int); alloc_size += count * count * sizeof(int);
...@@ -205,7 +200,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) ...@@ -205,7 +200,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
stats->max_state = count; stats->max_state = count;
/* Find valid-unique entries */ /* Find valid-unique entries */
cpufreq_for_each_valid_entry(pos, table) cpufreq_for_each_valid_entry(pos, policy->freq_table)
if (freq_table_get_index(stats, pos->frequency) == -1) if (freq_table_get_index(stats, pos->frequency) == -1)
stats->freq_table[i++] = pos->frequency; stats->freq_table[i++] = pos->frequency;
......
...@@ -43,7 +43,7 @@ static int dbx500_cpufreq_exit(struct cpufreq_policy *policy) ...@@ -43,7 +43,7 @@ static int dbx500_cpufreq_exit(struct cpufreq_policy *policy)
static void dbx500_cpufreq_ready(struct cpufreq_policy *policy) static void dbx500_cpufreq_ready(struct cpufreq_policy *policy)
{ {
cdev = cpufreq_cooling_register(policy->cpus); cdev = cpufreq_cooling_register(policy);
if (IS_ERR(cdev)) if (IS_ERR(cdev))
pr_err("Failed to register cooling device %ld\n", PTR_ERR(cdev)); pr_err("Failed to register cooling device %ld\n", PTR_ERR(cdev));
else else
......
...@@ -320,9 +320,7 @@ static void mtk_cpufreq_ready(struct cpufreq_policy *policy) ...@@ -320,9 +320,7 @@ static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
of_property_read_u32(np, DYNAMIC_POWER, &capacitance); of_property_read_u32(np, DYNAMIC_POWER, &capacitance);
info->cdev = of_cpufreq_power_cooling_register(np, info->cdev = of_cpufreq_power_cooling_register(np,
policy->related_cpus, policy, capacitance, NULL);
capacitance,
NULL);
if (IS_ERR(info->cdev)) { if (IS_ERR(info->cdev)) {
dev_err(info->cpu_dev, dev_err(info->cpu_dev,
......
...@@ -278,8 +278,7 @@ static void qoriq_cpufreq_ready(struct cpufreq_policy *policy) ...@@ -278,8 +278,7 @@ static void qoriq_cpufreq_ready(struct cpufreq_policy *policy)
struct device_node *np = of_get_cpu_node(policy->cpu, NULL); struct device_node *np = of_get_cpu_node(policy->cpu, NULL);
if (of_find_property(np, "#cooling-cells", NULL)) { if (of_find_property(np, "#cooling-cells", NULL)) {
cpud->cdev = of_cpufreq_cooling_register(np, cpud->cdev = of_cpufreq_cooling_register(np, policy);
policy->related_cpus);
if (IS_ERR(cpud->cdev) && PTR_ERR(cpud->cdev) != -ENOSYS) { if (IS_ERR(cpud->cdev) && PTR_ERR(cpud->cdev) != -ENOSYS) {
pr_err("cpu%d is not running as cooling device: %ld\n", pr_err("cpu%d is not running as cooling device: %ld\n",
......
...@@ -245,7 +245,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) ...@@ -245,7 +245,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
*/ */
err = tz->ops->get_trip_temp(tz, 0, &trip_temp); err = tz->ops->get_trip_temp(tz, 0, &trip_temp);
if (err < 0) { if (err < 0) {
err = PTR_ERR(tz);
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Not able to read trip_temp: %d\n", "Not able to read trip_temp: %d\n",
err); err);
......
...@@ -49,40 +49,45 @@ ...@@ -49,40 +49,45 @@
*/ */
/** /**
* struct power_table - frequency to power conversion * struct freq_table - frequency table along with power entries
* @frequency: frequency in KHz * @frequency: frequency in KHz
* @power: power in mW * @power: power in mW
* *
* This structure is built when the cooling device registers and helps * This structure is built when the cooling device registers and helps
* in translating frequency to power and viceversa. * in translating frequency to power and vice versa.
*/ */
struct power_table { struct freq_table {
u32 frequency; u32 frequency;
u32 power; u32 power;
}; };
/**
* struct time_in_idle - Idle time stats
* @time: previous reading of the absolute time that this cpu was idle
* @timestamp: wall time of the last invocation of get_cpu_idle_time_us()
*/
struct time_in_idle {
u64 time;
u64 timestamp;
};
/** /**
* struct cpufreq_cooling_device - data for cooling device with cpufreq * struct cpufreq_cooling_device - data for cooling device with cpufreq
* @id: unique integer value corresponding to each cpufreq_cooling_device * @id: unique integer value corresponding to each cpufreq_cooling_device
* registered. * registered.
* @cool_dev: thermal_cooling_device pointer to keep track of the * @last_load: load measured by the latest call to cpufreq_get_requested_power()
* registered cooling device.
* @cpufreq_state: integer value representing the current state of cpufreq * @cpufreq_state: integer value representing the current state of cpufreq
* cooling devices. * cooling devices.
* @clipped_freq: integer value representing the absolute value of the clipped * @clipped_freq: integer value representing the absolute value of the clipped
* frequency. * frequency.
* @max_level: maximum cooling level. One less than total number of valid * @max_level: maximum cooling level. One less than total number of valid
* cpufreq frequencies. * cpufreq frequencies.
* @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. * @freq_table: Freq table in descending order of frequencies
* @cdev: thermal_cooling_device pointer to keep track of the
* registered cooling device.
* @policy: cpufreq policy.
* @node: list_head to link all cpufreq_cooling_device together. * @node: list_head to link all cpufreq_cooling_device together.
* @last_load: load measured by the latest call to cpufreq_get_requested_power() * @idle_time: idle time stats
* @time_in_idle: previous reading of the absolute time that this cpu was idle
* @time_in_idle_timestamp: wall time of the last invocation of
* get_cpu_idle_time_us()
* @dyn_power_table: array of struct power_table for frequency to power
* conversion, sorted in ascending order.
* @dyn_power_table_entries: number of entries in the @dyn_power_table array
* @cpu_dev: the first cpu_device from @allowed_cpus that has OPPs registered
* @plat_get_static_power: callback to calculate the static power * @plat_get_static_power: callback to calculate the static power
* *
* This structure is required for keeping information of each registered * This structure is required for keeping information of each registered
...@@ -90,80 +95,44 @@ struct power_table { ...@@ -90,80 +95,44 @@ struct power_table {
*/ */
struct cpufreq_cooling_device { struct cpufreq_cooling_device {
int id; int id;
struct thermal_cooling_device *cool_dev; u32 last_load;
unsigned int cpufreq_state; unsigned int cpufreq_state;
unsigned int clipped_freq; unsigned int clipped_freq;
unsigned int max_level; unsigned int max_level;
unsigned int *freq_table; /* In descending order */ struct freq_table *freq_table; /* In descending order */
struct cpumask allowed_cpus; struct thermal_cooling_device *cdev;
struct cpufreq_policy *policy;
struct list_head node; struct list_head node;
u32 last_load; struct time_in_idle *idle_time;
u64 *time_in_idle;
u64 *time_in_idle_timestamp;
struct power_table *dyn_power_table;
int dyn_power_table_entries;
struct device *cpu_dev;
get_static_t plat_get_static_power; get_static_t plat_get_static_power;
}; };
static DEFINE_IDA(cpufreq_ida);
static DEFINE_IDA(cpufreq_ida);
static DEFINE_MUTEX(cooling_list_lock); static DEFINE_MUTEX(cooling_list_lock);
static LIST_HEAD(cpufreq_dev_list); static LIST_HEAD(cpufreq_cdev_list);
/* Below code defines functions to be used for cpufreq as cooling device */ /* Below code defines functions to be used for cpufreq as cooling device */
/** /**
* get_level: Find the level for a particular frequency * get_level: Find the level for a particular frequency
* @cpufreq_dev: cpufreq_dev for which the property is required * @cpufreq_cdev: cpufreq_cdev for which the property is required
* @freq: Frequency * @freq: Frequency
* *
* Return: level on success, THERMAL_CSTATE_INVALID on error. * Return: level corresponding to the frequency.
*/ */
static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev, static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
unsigned int freq) unsigned int freq)
{ {
struct freq_table *freq_table = cpufreq_cdev->freq_table;
unsigned long level; unsigned long level;
for (level = 0; level <= cpufreq_dev->max_level; level++) { for (level = 1; level <= cpufreq_cdev->max_level; level++)
if (freq == cpufreq_dev->freq_table[level]) if (freq > freq_table[level].frequency)
return level;
if (freq > cpufreq_dev->freq_table[level])
break; break;
}
return THERMAL_CSTATE_INVALID; return level - 1;
} }
/**
* cpufreq_cooling_get_level - for a given cpu, return the cooling level.
* @cpu: cpu for which the level is required
* @freq: the frequency of interest
*
* This function will match the cooling level corresponding to the
* requested @freq and return it.
*
* Return: The matched cooling level on success or THERMAL_CSTATE_INVALID
* otherwise.
*/
unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
{
struct cpufreq_cooling_device *cpufreq_dev;
mutex_lock(&cooling_list_lock);
list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) {
mutex_unlock(&cooling_list_lock);
return get_level(cpufreq_dev, freq);
}
}
mutex_unlock(&cooling_list_lock);
pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu);
return THERMAL_CSTATE_INVALID;
}
EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
/** /**
* cpufreq_thermal_notifier - notifier callback for cpufreq policy change. * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
* @nb: struct notifier_block * with callback info. * @nb: struct notifier_block * with callback info.
...@@ -181,14 +150,18 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, ...@@ -181,14 +150,18 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
{ {
struct cpufreq_policy *policy = data; struct cpufreq_policy *policy = data;
unsigned long clipped_freq; unsigned long clipped_freq;
struct cpufreq_cooling_device *cpufreq_dev; struct cpufreq_cooling_device *cpufreq_cdev;
if (event != CPUFREQ_ADJUST) if (event != CPUFREQ_ADJUST)
return NOTIFY_DONE; return NOTIFY_DONE;
mutex_lock(&cooling_list_lock); mutex_lock(&cooling_list_lock);
list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { list_for_each_entry(cpufreq_cdev, &cpufreq_cdev_list, node) {
if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus)) /*
* A new copy of the policy is sent to the notifier and can't
* compare that directly.
*/
if (policy->cpu != cpufreq_cdev->policy->cpu)
continue; continue;
/* /*
...@@ -202,7 +175,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, ...@@ -202,7 +175,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
* But, if clipped_freq is greater than policy->max, we don't * But, if clipped_freq is greater than policy->max, we don't
* need to do anything. * need to do anything.
*/ */
clipped_freq = cpufreq_dev->clipped_freq; clipped_freq = cpufreq_cdev->clipped_freq;
if (policy->max > clipped_freq) if (policy->max > clipped_freq)
cpufreq_verify_within_limits(policy, 0, clipped_freq); cpufreq_verify_within_limits(policy, 0, clipped_freq);
...@@ -214,63 +187,63 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, ...@@ -214,63 +187,63 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
} }
/** /**
* build_dyn_power_table() - create a dynamic power to frequency table * update_freq_table() - Update the freq table with power numbers
* @cpufreq_device: the cpufreq cooling device in which to store the table * @cpufreq_cdev: the cpufreq cooling device in which to update the table
* @capacitance: dynamic power coefficient for these cpus * @capacitance: dynamic power coefficient for these cpus
* *
* Build a dynamic power to frequency table for this cpu and store it * Update the freq table with power numbers. This table will be used in
* in @cpufreq_device. This table will be used in cpu_power_to_freq() and * cpu_power_to_freq() and cpu_freq_to_power() to convert between power and
* cpu_freq_to_power() to convert between power and frequency * frequency efficiently. Power is stored in mW, frequency in KHz. The
* efficiently. Power is stored in mW, frequency in KHz. The * resulting table is in descending order.
* resulting table is in ascending order.
* *
* Return: 0 on success, -EINVAL if there are no OPPs for any CPUs, * 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 * or -ENOMEM if we run out of memory.
* added/enabled while the function was executing.
*/ */
static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev,
u32 capacitance) u32 capacitance)
{ {
struct power_table *power_table; struct freq_table *freq_table = cpufreq_cdev->freq_table;
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
struct device *dev = NULL; struct device *dev = NULL;
int num_opps = 0, cpu, i, ret = 0; int num_opps = 0, cpu = cpufreq_cdev->policy->cpu, i;
unsigned long freq;
for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {
dev = get_cpu_device(cpu); dev = get_cpu_device(cpu);
if (!dev) { if (unlikely(!dev)) {
dev_warn(&cpufreq_device->cool_dev->device, dev_warn(&cpufreq_cdev->cdev->device,
"No cpu device for cpu %d\n", cpu); "No cpu device for cpu %d\n", cpu);
continue; return -ENODEV;
} }
num_opps = dev_pm_opp_get_opp_count(dev); num_opps = dev_pm_opp_get_opp_count(dev);
if (num_opps > 0) if (num_opps < 0)
break;
else if (num_opps < 0)
return num_opps; return num_opps;
}
if (num_opps == 0) /*
* The cpufreq table is also built from the OPP table and so the count
* should match.
*/
if (num_opps != cpufreq_cdev->max_level + 1) {
dev_warn(dev, "Number of OPPs not matching with max_levels\n");
return -EINVAL; return -EINVAL;
}
power_table = kcalloc(num_opps, sizeof(*power_table), GFP_KERNEL); for (i = 0; i <= cpufreq_cdev->max_level; i++) {
if (!power_table) unsigned long freq = freq_table[i].frequency * 1000;
return -ENOMEM; u32 freq_mhz = freq_table[i].frequency / 1000;
for (freq = 0, i = 0;
opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
freq++, i++) {
u32 freq_mhz, voltage_mv;
u64 power; u64 power;
u32 voltage_mv;
if (i >= num_opps) { /*
ret = -EAGAIN; * Find ceil frequency as 'freq' may be slightly lower than OPP
goto free_power_table; * freq due to truncation while converting to kHz.
*/
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
if (IS_ERR(opp)) {
dev_err(dev, "failed to get opp for %lu frequency\n",
freq);
return -EINVAL;
} }
freq_mhz = freq / 1000000;
voltage_mv = dev_pm_opp_get_voltage(opp) / 1000; voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
dev_pm_opp_put(opp); dev_pm_opp_put(opp);
...@@ -281,89 +254,73 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, ...@@ -281,89 +254,73 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv; power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv;
do_div(power, 1000000000); do_div(power, 1000000000);
/* frequency is stored in power_table in KHz */
power_table[i].frequency = freq / 1000;
/* power is stored in mW */ /* power is stored in mW */
power_table[i].power = power; freq_table[i].power = power;
} }
if (i != num_opps) {
ret = PTR_ERR(opp);
goto free_power_table;
}
cpufreq_device->cpu_dev = dev;
cpufreq_device->dyn_power_table = power_table;
cpufreq_device->dyn_power_table_entries = i;
return 0; return 0;
free_power_table:
kfree(power_table);
return ret;
} }
static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_device, static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
u32 freq) u32 freq)
{ {
int i; int i;
struct power_table *pt = cpufreq_device->dyn_power_table; struct freq_table *freq_table = cpufreq_cdev->freq_table;
for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++) for (i = 1; i <= cpufreq_cdev->max_level; i++)
if (freq < pt[i].frequency) if (freq > freq_table[i].frequency)
break; break;
return pt[i - 1].power; return freq_table[i - 1].power;
} }
static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device, static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
u32 power) u32 power)
{ {
int i; int i;
struct power_table *pt = cpufreq_device->dyn_power_table; struct freq_table *freq_table = cpufreq_cdev->freq_table;
for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++) for (i = 1; i <= cpufreq_cdev->max_level; i++)
if (power < pt[i].power) if (power > freq_table[i].power)
break; break;
return pt[i - 1].frequency; return freq_table[i - 1].frequency;
} }
/** /**
* get_load() - get load for a cpu since last updated * get_load() - get load for a cpu since last updated
* @cpufreq_device: &struct cpufreq_cooling_device for this cpu * @cpufreq_cdev: &struct cpufreq_cooling_device for this cpu
* @cpu: cpu number * @cpu: cpu number
* @cpu_idx: index of the cpu in cpufreq_device->allowed_cpus * @cpu_idx: index of the cpu in time_in_idle*
* *
* Return: The average load of cpu @cpu in percentage since this * Return: The average load of cpu @cpu in percentage since this
* function was last called. * function was last called.
*/ */
static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu, static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
int cpu_idx) int cpu_idx)
{ {
u32 load; u32 load;
u64 now, now_idle, delta_time, delta_idle; u64 now, now_idle, delta_time, delta_idle;
struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu_idx];
now_idle = get_cpu_idle_time(cpu, &now, 0); now_idle = get_cpu_idle_time(cpu, &now, 0);
delta_idle = now_idle - cpufreq_device->time_in_idle[cpu_idx]; delta_idle = now_idle - idle_time->time;
delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu_idx]; delta_time = now - idle_time->timestamp;
if (delta_time <= delta_idle) if (delta_time <= delta_idle)
load = 0; load = 0;
else else
load = div64_u64(100 * (delta_time - delta_idle), delta_time); load = div64_u64(100 * (delta_time - delta_idle), delta_time);
cpufreq_device->time_in_idle[cpu_idx] = now_idle; idle_time->time = now_idle;
cpufreq_device->time_in_idle_timestamp[cpu_idx] = now; idle_time->timestamp = now;
return load; return load;
} }
/** /**
* get_static_power() - calculate the static power consumed by the cpus * get_static_power() - calculate the static power consumed by the cpus
* @cpufreq_device: struct &cpufreq_cooling_device for this cpu cdev * @cpufreq_cdev: struct &cpufreq_cooling_device for this cpu cdev
* @tz: thermal zone device in which we're operating * @tz: thermal zone device in which we're operating
* @freq: frequency in KHz * @freq: frequency in KHz
* @power: pointer in which to store the calculated static power * @power: pointer in which to store the calculated static power
...@@ -376,26 +333,28 @@ static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu, ...@@ -376,26 +333,28 @@ static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu,
* *
* Return: 0 on success, -E* on failure. * Return: 0 on success, -E* on failure.
*/ */
static int get_static_power(struct cpufreq_cooling_device *cpufreq_device, static int get_static_power(struct cpufreq_cooling_device *cpufreq_cdev,
struct thermal_zone_device *tz, unsigned long freq, struct thermal_zone_device *tz, unsigned long freq,
u32 *power) u32 *power)
{ {
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
unsigned long voltage; unsigned long voltage;
struct cpumask *cpumask = &cpufreq_device->allowed_cpus; struct cpufreq_policy *policy = cpufreq_cdev->policy;
struct cpumask *cpumask = policy->related_cpus;
unsigned long freq_hz = freq * 1000; unsigned long freq_hz = freq * 1000;
struct device *dev;
if (!cpufreq_device->plat_get_static_power || if (!cpufreq_cdev->plat_get_static_power) {
!cpufreq_device->cpu_dev) {
*power = 0; *power = 0;
return 0; return 0;
} }
opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz, dev = get_cpu_device(policy->cpu);
true); WARN_ON(!dev);
opp = dev_pm_opp_find_freq_exact(dev, freq_hz, true);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
dev_warn_ratelimited(cpufreq_device->cpu_dev, dev_warn_ratelimited(dev, "Failed to find OPP for frequency %lu: %ld\n",
"Failed to find OPP for frequency %lu: %ld\n",
freq_hz, PTR_ERR(opp)); freq_hz, PTR_ERR(opp));
return -EINVAL; return -EINVAL;
} }
...@@ -404,31 +363,30 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device, ...@@ -404,31 +363,30 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
dev_pm_opp_put(opp); dev_pm_opp_put(opp);
if (voltage == 0) { if (voltage == 0) {
dev_err_ratelimited(cpufreq_device->cpu_dev, dev_err_ratelimited(dev, "Failed to get voltage for frequency %lu\n",
"Failed to get voltage for frequency %lu\n",
freq_hz); freq_hz);
return -EINVAL; return -EINVAL;
} }
return cpufreq_device->plat_get_static_power(cpumask, tz->passive_delay, return cpufreq_cdev->plat_get_static_power(cpumask, tz->passive_delay,
voltage, power); voltage, power);
} }
/** /**
* get_dynamic_power() - calculate the dynamic power * get_dynamic_power() - calculate the dynamic power
* @cpufreq_device: &cpufreq_cooling_device for this cdev * @cpufreq_cdev: &cpufreq_cooling_device for this cdev
* @freq: current frequency * @freq: current frequency
* *
* Return: the dynamic power consumed by the cpus described by * Return: the dynamic power consumed by the cpus described by
* @cpufreq_device. * @cpufreq_cdev.
*/ */
static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device, static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_cdev,
unsigned long freq) unsigned long freq)
{ {
u32 raw_cpu_power; u32 raw_cpu_power;
raw_cpu_power = cpu_freq_to_power(cpufreq_device, freq); raw_cpu_power = cpu_freq_to_power(cpufreq_cdev, freq);
return (raw_cpu_power * cpufreq_device->last_load) / 100; return (raw_cpu_power * cpufreq_cdev->last_load) / 100;
} }
/* cpufreq cooling device callback functions are defined below */ /* cpufreq cooling device callback functions are defined below */
...@@ -446,9 +404,9 @@ static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device, ...@@ -446,9 +404,9 @@ static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device,
static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state) unsigned long *state)
{ {
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
*state = cpufreq_device->max_level; *state = cpufreq_cdev->max_level;
return 0; return 0;
} }
...@@ -465,9 +423,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, ...@@ -465,9 +423,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state) unsigned long *state)
{ {
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
*state = cpufreq_device->cpufreq_state; *state = cpufreq_cdev->cpufreq_state;
return 0; return 0;
} }
...@@ -485,23 +443,22 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, ...@@ -485,23 +443,22 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state) unsigned long state)
{ {
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
unsigned int clip_freq; unsigned int clip_freq;
/* Request state should be less than max_level */ /* Request state should be less than max_level */
if (WARN_ON(state > cpufreq_device->max_level)) if (WARN_ON(state > cpufreq_cdev->max_level))
return -EINVAL; return -EINVAL;
/* Check if the old cooling action is same as new cooling action */ /* Check if the old cooling action is same as new cooling action */
if (cpufreq_device->cpufreq_state == state) if (cpufreq_cdev->cpufreq_state == state)
return 0; return 0;
clip_freq = cpufreq_device->freq_table[state]; clip_freq = cpufreq_cdev->freq_table[state].frequency;
cpufreq_device->cpufreq_state = state; cpufreq_cdev->cpufreq_state = state;
cpufreq_device->clipped_freq = clip_freq; cpufreq_cdev->clipped_freq = clip_freq;
cpufreq_update_policy(cpu); cpufreq_update_policy(cpufreq_cdev->policy->cpu);
return 0; return 0;
} }
...@@ -536,33 +493,23 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, ...@@ -536,33 +493,23 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
unsigned long freq; unsigned long freq;
int i = 0, cpu, ret; int i = 0, cpu, ret;
u32 static_power, dynamic_power, total_load = 0; u32 static_power, dynamic_power, total_load = 0;
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
struct cpufreq_policy *policy = cpufreq_cdev->policy;
u32 *load_cpu = NULL; u32 *load_cpu = NULL;
cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask); freq = cpufreq_quick_get(policy->cpu);
/*
* All the CPUs are offline, thus the requested power by
* the cdev is 0
*/
if (cpu >= nr_cpu_ids) {
*power = 0;
return 0;
}
freq = cpufreq_quick_get(cpu);
if (trace_thermal_power_cpu_get_power_enabled()) { if (trace_thermal_power_cpu_get_power_enabled()) {
u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus); u32 ncpus = cpumask_weight(policy->related_cpus);
load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL); load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL);
} }
for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { for_each_cpu(cpu, policy->related_cpus) {
u32 load; u32 load;
if (cpu_online(cpu)) if (cpu_online(cpu))
load = get_load(cpufreq_device, cpu, i); load = get_load(cpufreq_cdev, cpu, i);
else else
load = 0; load = 0;
...@@ -573,19 +520,19 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, ...@@ -573,19 +520,19 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
i++; i++;
} }
cpufreq_device->last_load = total_load; cpufreq_cdev->last_load = total_load;
dynamic_power = get_dynamic_power(cpufreq_device, freq); dynamic_power = get_dynamic_power(cpufreq_cdev, freq);
ret = get_static_power(cpufreq_device, tz, freq, &static_power); ret = get_static_power(cpufreq_cdev, tz, freq, &static_power);
if (ret) { if (ret) {
kfree(load_cpu); kfree(load_cpu);
return ret; return ret;
} }
if (load_cpu) { if (load_cpu) {
trace_thermal_power_cpu_get_power( trace_thermal_power_cpu_get_power(policy->related_cpus, freq,
&cpufreq_device->allowed_cpus, load_cpu, i, dynamic_power,
freq, load_cpu, i, dynamic_power, static_power); static_power);
kfree(load_cpu); kfree(load_cpu);
} }
...@@ -614,38 +561,23 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev, ...@@ -614,38 +561,23 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
unsigned long state, u32 *power) unsigned long state, u32 *power)
{ {
unsigned int freq, num_cpus; unsigned int freq, num_cpus;
cpumask_var_t cpumask;
u32 static_power, dynamic_power; u32 static_power, dynamic_power;
int ret; int ret;
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
if (!alloc_cpumask_var(&cpumask, GFP_KERNEL)) /* Request state should be less than max_level */
return -ENOMEM; if (WARN_ON(state > cpufreq_cdev->max_level))
return -EINVAL;
cpumask_and(cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
num_cpus = cpumask_weight(cpumask);
/* None of our cpus are online, so no power */
if (num_cpus == 0) {
*power = 0;
ret = 0;
goto out;
}
freq = cpufreq_device->freq_table[state]; num_cpus = cpumask_weight(cpufreq_cdev->policy->cpus);
if (!freq) {
ret = -EINVAL;
goto out;
}
dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus; freq = cpufreq_cdev->freq_table[state].frequency;
ret = get_static_power(cpufreq_device, tz, freq, &static_power); dynamic_power = cpu_freq_to_power(cpufreq_cdev, freq) * num_cpus;
ret = get_static_power(cpufreq_cdev, tz, freq, &static_power);
if (ret) if (ret)
goto out; return ret;
*power = static_power + dynamic_power; *power = static_power + dynamic_power;
out:
free_cpumask_var(cpumask);
return ret; return ret;
} }
...@@ -673,39 +605,27 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev, ...@@ -673,39 +605,27 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev,
struct thermal_zone_device *tz, u32 power, struct thermal_zone_device *tz, u32 power,
unsigned long *state) unsigned long *state)
{ {
unsigned int cpu, cur_freq, target_freq; unsigned int cur_freq, target_freq;
int ret; int ret;
s32 dyn_power; s32 dyn_power;
u32 last_load, normalised_power, static_power; u32 last_load, normalised_power, static_power;
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
struct cpufreq_policy *policy = cpufreq_cdev->policy;
cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask);
/* None of our cpus are online */
if (cpu >= nr_cpu_ids)
return -ENODEV;
cur_freq = cpufreq_quick_get(cpu); cur_freq = cpufreq_quick_get(policy->cpu);
ret = get_static_power(cpufreq_device, tz, cur_freq, &static_power); ret = get_static_power(cpufreq_cdev, tz, cur_freq, &static_power);
if (ret) if (ret)
return ret; return ret;
dyn_power = power - static_power; dyn_power = power - static_power;
dyn_power = dyn_power > 0 ? dyn_power : 0; dyn_power = dyn_power > 0 ? dyn_power : 0;
last_load = cpufreq_device->last_load ?: 1; last_load = cpufreq_cdev->last_load ?: 1;
normalised_power = (dyn_power * 100) / last_load; normalised_power = (dyn_power * 100) / last_load;
target_freq = cpu_power_to_freq(cpufreq_device, normalised_power); target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power);
*state = cpufreq_cooling_get_level(cpu, target_freq);
if (*state == THERMAL_CSTATE_INVALID) {
dev_err_ratelimited(&cdev->device,
"Failed to convert %dKHz for cpu %d into a cdev state\n",
target_freq, cpu);
return -EINVAL;
}
trace_thermal_power_cpu_limit(&cpufreq_device->allowed_cpus, *state = get_level(cpufreq_cdev, target_freq);
target_freq, *state, power); trace_thermal_power_cpu_limit(policy->related_cpus, target_freq, *state,
power);
return 0; return 0;
} }
...@@ -748,7 +668,7 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table, ...@@ -748,7 +668,7 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
/** /**
* __cpufreq_cooling_register - helper function to create cpufreq cooling device * __cpufreq_cooling_register - helper function to create cpufreq cooling device
* @np: a valid struct device_node to the cooling device device tree node * @np: a valid struct device_node to the cooling device device tree node
* @clip_cpus: cpumask of cpus where the frequency constraints will happen. * @policy: cpufreq policy
* Normally this should be same as cpufreq policy->related_cpus. * Normally this should be same as cpufreq policy->related_cpus.
* @capacitance: dynamic power coefficient for these cpus * @capacitance: dynamic power coefficient for these cpus
* @plat_static_func: function to calculate the static power consumed by these * @plat_static_func: function to calculate the static power consumed by these
...@@ -764,102 +684,68 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table, ...@@ -764,102 +684,68 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
*/ */
static struct thermal_cooling_device * static struct thermal_cooling_device *
__cpufreq_cooling_register(struct device_node *np, __cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, u32 capacitance, struct cpufreq_policy *policy, u32 capacitance,
get_static_t plat_static_func) get_static_t plat_static_func)
{ {
struct cpufreq_policy *policy; struct thermal_cooling_device *cdev;
struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_cdev;
struct cpufreq_cooling_device *cpufreq_dev;
char dev_name[THERMAL_NAME_LENGTH]; char dev_name[THERMAL_NAME_LENGTH];
struct cpufreq_frequency_table *pos, *table;
cpumask_var_t temp_mask;
unsigned int freq, i, num_cpus; unsigned int freq, i, num_cpus;
int ret; int ret;
struct thermal_cooling_device_ops *cooling_ops; struct thermal_cooling_device_ops *cooling_ops;
bool first; bool first;
if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL)) if (IS_ERR_OR_NULL(policy)) {
return ERR_PTR(-ENOMEM); pr_err("%s: cpufreq policy isn't valid: %p", __func__, policy);
return ERR_PTR(-EINVAL);
cpumask_and(temp_mask, clip_cpus, cpu_online_mask);
policy = cpufreq_cpu_get(cpumask_first(temp_mask));
if (!policy) {
pr_debug("%s: CPUFreq policy not found\n", __func__);
cool_dev = ERR_PTR(-EPROBE_DEFER);
goto free_cpumask;
} }
table = policy->freq_table; i = cpufreq_table_count_valid_entries(policy);
if (!table) { if (!i) {
pr_debug("%s: CPUFreq table not found\n", __func__); pr_debug("%s: CPUFreq table not found or has no valid entries\n",
cool_dev = ERR_PTR(-ENODEV); __func__);
goto put_policy; return ERR_PTR(-ENODEV);
} }
cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); cpufreq_cdev = kzalloc(sizeof(*cpufreq_cdev), GFP_KERNEL);
if (!cpufreq_dev) { if (!cpufreq_cdev)
cool_dev = ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
goto put_policy;
}
num_cpus = cpumask_weight(clip_cpus); cpufreq_cdev->policy = policy;
cpufreq_dev->time_in_idle = kcalloc(num_cpus, num_cpus = cpumask_weight(policy->related_cpus);
sizeof(*cpufreq_dev->time_in_idle), cpufreq_cdev->idle_time = kcalloc(num_cpus,
sizeof(*cpufreq_cdev->idle_time),
GFP_KERNEL); GFP_KERNEL);
if (!cpufreq_dev->time_in_idle) { if (!cpufreq_cdev->idle_time) {
cool_dev = ERR_PTR(-ENOMEM); cdev = ERR_PTR(-ENOMEM);
goto free_cdev; goto free_cdev;
} }
cpufreq_dev->time_in_idle_timestamp =
kcalloc(num_cpus, sizeof(*cpufreq_dev->time_in_idle_timestamp),
GFP_KERNEL);
if (!cpufreq_dev->time_in_idle_timestamp) {
cool_dev = ERR_PTR(-ENOMEM);
goto free_time_in_idle;
}
/* Find max levels */
cpufreq_for_each_valid_entry(pos, table)
cpufreq_dev->max_level++;
cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) *
cpufreq_dev->max_level, GFP_KERNEL);
if (!cpufreq_dev->freq_table) {
cool_dev = ERR_PTR(-ENOMEM);
goto free_time_in_idle_timestamp;
}
/* max_level is an index, not a counter */ /* max_level is an index, not a counter */
cpufreq_dev->max_level--; cpufreq_cdev->max_level = i - 1;
cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
if (capacitance) {
cpufreq_dev->plat_get_static_power = plat_static_func;
ret = build_dyn_power_table(cpufreq_dev, capacitance);
if (ret) {
cool_dev = ERR_PTR(ret);
goto free_table;
}
cooling_ops = &cpufreq_power_cooling_ops; cpufreq_cdev->freq_table = kmalloc_array(i,
} else { sizeof(*cpufreq_cdev->freq_table),
cooling_ops = &cpufreq_cooling_ops; GFP_KERNEL);
if (!cpufreq_cdev->freq_table) {
cdev = ERR_PTR(-ENOMEM);
goto free_idle_time;
} }
ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL); ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
cool_dev = ERR_PTR(ret); cdev = ERR_PTR(ret);
goto free_power_table; goto free_table;
} }
cpufreq_dev->id = ret; cpufreq_cdev->id = ret;
snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
cpufreq_cdev->id);
/* Fill freq-table in descending order of frequencies */ /* Fill freq-table in descending order of frequencies */
for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { for (i = 0, freq = -1; i <= cpufreq_cdev->max_level; i++) {
freq = find_next_max(table, freq); freq = find_next_max(policy->freq_table, freq);
cpufreq_dev->freq_table[i] = freq; cpufreq_cdev->freq_table[i].frequency = freq;
/* Warn for duplicate entries */ /* Warn for duplicate entries */
if (!freq) if (!freq)
...@@ -868,51 +754,54 @@ __cpufreq_cooling_register(struct device_node *np, ...@@ -868,51 +754,54 @@ __cpufreq_cooling_register(struct device_node *np,
pr_debug("%s: freq:%u KHz\n", __func__, freq); pr_debug("%s: freq:%u KHz\n", __func__, freq);
} }
snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", if (capacitance) {
cpufreq_dev->id); cpufreq_cdev->plat_get_static_power = plat_static_func;
ret = update_freq_table(cpufreq_cdev, capacitance);
if (ret) {
cdev = ERR_PTR(ret);
goto remove_ida;
}
cooling_ops = &cpufreq_power_cooling_ops;
} else {
cooling_ops = &cpufreq_cooling_ops;
}
cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev,
cooling_ops); cooling_ops);
if (IS_ERR(cool_dev)) if (IS_ERR(cdev))
goto remove_ida; goto remove_ida;
cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0]; cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency;
cpufreq_dev->cool_dev = cool_dev; cpufreq_cdev->cdev = cdev;
mutex_lock(&cooling_list_lock); mutex_lock(&cooling_list_lock);
/* Register the notifier for first cpufreq cooling device */ /* Register the notifier for first cpufreq cooling device */
first = list_empty(&cpufreq_dev_list); first = list_empty(&cpufreq_cdev_list);
list_add(&cpufreq_dev->node, &cpufreq_dev_list); list_add(&cpufreq_cdev->node, &cpufreq_cdev_list);
mutex_unlock(&cooling_list_lock); mutex_unlock(&cooling_list_lock);
if (first) if (first)
cpufreq_register_notifier(&thermal_cpufreq_notifier_block, cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
goto put_policy; return cdev;
remove_ida: remove_ida:
ida_simple_remove(&cpufreq_ida, cpufreq_dev->id); ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
free_power_table:
kfree(cpufreq_dev->dyn_power_table);
free_table: free_table:
kfree(cpufreq_dev->freq_table); kfree(cpufreq_cdev->freq_table);
free_time_in_idle_timestamp: free_idle_time:
kfree(cpufreq_dev->time_in_idle_timestamp); kfree(cpufreq_cdev->idle_time);
free_time_in_idle:
kfree(cpufreq_dev->time_in_idle);
free_cdev: free_cdev:
kfree(cpufreq_dev); kfree(cpufreq_cdev);
put_policy: return cdev;
cpufreq_cpu_put(policy);
free_cpumask:
free_cpumask_var(temp_mask);
return cool_dev;
} }
/** /**
* cpufreq_cooling_register - function to create cpufreq cooling device. * cpufreq_cooling_register - function to create cpufreq cooling device.
* @clip_cpus: cpumask of cpus where the frequency constraints will happen. * @policy: cpufreq policy
* *
* This interface function registers the cpufreq cooling device with the name * This interface function registers the cpufreq cooling device with the name
* "thermal-cpufreq-%x". This api can support multiple instances of cpufreq * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
...@@ -922,16 +811,16 @@ __cpufreq_cooling_register(struct device_node *np, ...@@ -922,16 +811,16 @@ __cpufreq_cooling_register(struct device_node *np,
* on failure, it returns a corresponding ERR_PTR(). * on failure, it returns a corresponding ERR_PTR().
*/ */
struct thermal_cooling_device * struct thermal_cooling_device *
cpufreq_cooling_register(const struct cpumask *clip_cpus) cpufreq_cooling_register(struct cpufreq_policy *policy)
{ {
return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL); return __cpufreq_cooling_register(NULL, policy, 0, NULL);
} }
EXPORT_SYMBOL_GPL(cpufreq_cooling_register); EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
/** /**
* of_cpufreq_cooling_register - function to create cpufreq cooling device. * of_cpufreq_cooling_register - function to create cpufreq cooling device.
* @np: a valid struct device_node to the cooling device device tree node * @np: a valid struct device_node to the cooling device device tree node
* @clip_cpus: cpumask of cpus where the frequency constraints will happen. * @policy: cpufreq policy
* *
* This interface function registers the cpufreq cooling device with the name * This interface function registers the cpufreq cooling device with the name
* "thermal-cpufreq-%x". This api can support multiple instances of cpufreq * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
...@@ -943,18 +832,18 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_register); ...@@ -943,18 +832,18 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
*/ */
struct thermal_cooling_device * struct thermal_cooling_device *
of_cpufreq_cooling_register(struct device_node *np, of_cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus) struct cpufreq_policy *policy)
{ {
if (!np) if (!np)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
return __cpufreq_cooling_register(np, clip_cpus, 0, NULL); return __cpufreq_cooling_register(np, policy, 0, NULL);
} }
EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
/** /**
* cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions * cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
* @clip_cpus: cpumask of cpus where the frequency constraints will happen * @policy: cpufreq policy
* @capacitance: dynamic power coefficient for these cpus * @capacitance: dynamic power coefficient for these cpus
* @plat_static_func: function to calculate the static power consumed by these * @plat_static_func: function to calculate the static power consumed by these
* cpus (optional) * cpus (optional)
...@@ -974,10 +863,10 @@ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); ...@@ -974,10 +863,10 @@ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
* on failure, it returns a corresponding ERR_PTR(). * on failure, it returns a corresponding ERR_PTR().
*/ */
struct thermal_cooling_device * struct thermal_cooling_device *
cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance, cpufreq_power_cooling_register(struct cpufreq_policy *policy, u32 capacitance,
get_static_t plat_static_func) get_static_t plat_static_func)
{ {
return __cpufreq_cooling_register(NULL, clip_cpus, capacitance, return __cpufreq_cooling_register(NULL, policy, capacitance,
plat_static_func); plat_static_func);
} }
EXPORT_SYMBOL(cpufreq_power_cooling_register); EXPORT_SYMBOL(cpufreq_power_cooling_register);
...@@ -985,7 +874,7 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register); ...@@ -985,7 +874,7 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register);
/** /**
* of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
* @np: a valid struct device_node to the cooling device device tree node * @np: a valid struct device_node to the cooling device device tree node
* @clip_cpus: cpumask of cpus where the frequency constraints will happen * @policy: cpufreq policy
* @capacitance: dynamic power coefficient for these cpus * @capacitance: dynamic power coefficient for these cpus
* @plat_static_func: function to calculate the static power consumed by these * @plat_static_func: function to calculate the static power consumed by these
* cpus (optional) * cpus (optional)
...@@ -1007,14 +896,14 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register); ...@@ -1007,14 +896,14 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register);
*/ */
struct thermal_cooling_device * struct thermal_cooling_device *
of_cpufreq_power_cooling_register(struct device_node *np, of_cpufreq_power_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, struct cpufreq_policy *policy,
u32 capacitance, u32 capacitance,
get_static_t plat_static_func) get_static_t plat_static_func)
{ {
if (!np) if (!np)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
return __cpufreq_cooling_register(np, clip_cpus, capacitance, return __cpufreq_cooling_register(np, policy, capacitance,
plat_static_func); plat_static_func);
} }
EXPORT_SYMBOL(of_cpufreq_power_cooling_register); EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
...@@ -1027,30 +916,28 @@ EXPORT_SYMBOL(of_cpufreq_power_cooling_register); ...@@ -1027,30 +916,28 @@ EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
*/ */
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
{ {
struct cpufreq_cooling_device *cpufreq_dev; struct cpufreq_cooling_device *cpufreq_cdev;
bool last; bool last;
if (!cdev) if (!cdev)
return; return;
cpufreq_dev = cdev->devdata; cpufreq_cdev = cdev->devdata;
mutex_lock(&cooling_list_lock); mutex_lock(&cooling_list_lock);
list_del(&cpufreq_dev->node); list_del(&cpufreq_cdev->node);
/* Unregister the notifier for the last cpufreq cooling device */ /* Unregister the notifier for the last cpufreq cooling device */
last = list_empty(&cpufreq_dev_list); last = list_empty(&cpufreq_cdev_list);
mutex_unlock(&cooling_list_lock); mutex_unlock(&cooling_list_lock);
if (last) if (last)
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
thermal_cooling_device_unregister(cpufreq_dev->cool_dev); thermal_cooling_device_unregister(cpufreq_cdev->cdev);
ida_simple_remove(&cpufreq_ida, cpufreq_dev->id); ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
kfree(cpufreq_dev->dyn_power_table); kfree(cpufreq_cdev->idle_time);
kfree(cpufreq_dev->time_in_idle_timestamp); kfree(cpufreq_cdev->freq_table);
kfree(cpufreq_dev->time_in_idle); kfree(cpufreq_cdev);
kfree(cpufreq_dev->freq_table);
kfree(cpufreq_dev);
} }
EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);
...@@ -397,8 +397,11 @@ static int hisi_thermal_suspend(struct device *dev) ...@@ -397,8 +397,11 @@ static int hisi_thermal_suspend(struct device *dev)
static int hisi_thermal_resume(struct device *dev) static int hisi_thermal_resume(struct device *dev)
{ {
struct hisi_thermal_data *data = dev_get_drvdata(dev); struct hisi_thermal_data *data = dev_get_drvdata(dev);
int ret;
clk_prepare_enable(data->clk); ret = clk_prepare_enable(data->clk);
if (ret)
return ret;
data->irq_enabled = true; data->irq_enabled = true;
hisi_thermal_enable_bind_irq_sensor(data); hisi_thermal_enable_bind_irq_sensor(data);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/cpu_cooling.h> #include <linux/cpu_cooling.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
...@@ -88,6 +89,7 @@ static struct thermal_soc_data thermal_imx6sx_data = { ...@@ -88,6 +89,7 @@ static struct thermal_soc_data thermal_imx6sx_data = {
}; };
struct imx_thermal_data { struct imx_thermal_data {
struct cpufreq_policy *policy;
struct thermal_zone_device *tz; struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
enum thermal_device_mode mode; enum thermal_device_mode mode;
...@@ -525,13 +527,18 @@ static int imx_thermal_probe(struct platform_device *pdev) ...@@ -525,13 +527,18 @@ static int imx_thermal_probe(struct platform_device *pdev)
regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
data->cdev = cpufreq_cooling_register(cpu_present_mask); data->policy = cpufreq_cpu_get(0);
if (!data->policy) {
pr_debug("%s: CPUFreq policy not found\n", __func__);
return -EPROBE_DEFER;
}
data->cdev = cpufreq_cooling_register(data->policy);
if (IS_ERR(data->cdev)) { if (IS_ERR(data->cdev)) {
ret = PTR_ERR(data->cdev); ret = PTR_ERR(data->cdev);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to register cpufreq cooling device: %d\n", "failed to register cpufreq cooling device: %d\n", ret);
ret); cpufreq_cpu_put(data->policy);
return ret; return ret;
} }
...@@ -542,6 +549,7 @@ static int imx_thermal_probe(struct platform_device *pdev) ...@@ -542,6 +549,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to get thermal clk: %d\n", ret); "failed to get thermal clk: %d\n", ret);
cpufreq_cooling_unregister(data->cdev); cpufreq_cooling_unregister(data->cdev);
cpufreq_cpu_put(data->policy);
return ret; return ret;
} }
...@@ -556,6 +564,7 @@ static int imx_thermal_probe(struct platform_device *pdev) ...@@ -556,6 +564,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret); dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
cpufreq_cooling_unregister(data->cdev); cpufreq_cooling_unregister(data->cdev);
cpufreq_cpu_put(data->policy);
return ret; return ret;
} }
...@@ -571,6 +580,7 @@ static int imx_thermal_probe(struct platform_device *pdev) ...@@ -571,6 +580,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
"failed to register thermal zone device %d\n", ret); "failed to register thermal zone device %d\n", ret);
clk_disable_unprepare(data->thermal_clk); clk_disable_unprepare(data->thermal_clk);
cpufreq_cooling_unregister(data->cdev); cpufreq_cooling_unregister(data->cdev);
cpufreq_cpu_put(data->policy);
return ret; return ret;
} }
...@@ -599,6 +609,7 @@ static int imx_thermal_probe(struct platform_device *pdev) ...@@ -599,6 +609,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
clk_disable_unprepare(data->thermal_clk); clk_disable_unprepare(data->thermal_clk);
thermal_zone_device_unregister(data->tz); thermal_zone_device_unregister(data->tz);
cpufreq_cooling_unregister(data->cdev); cpufreq_cooling_unregister(data->cdev);
cpufreq_cpu_put(data->policy);
return ret; return ret;
} }
...@@ -620,6 +631,7 @@ static int imx_thermal_remove(struct platform_device *pdev) ...@@ -620,6 +631,7 @@ static int imx_thermal_remove(struct platform_device *pdev)
thermal_zone_device_unregister(data->tz); thermal_zone_device_unregister(data->tz);
cpufreq_cooling_unregister(data->cdev); cpufreq_cooling_unregister(data->cdev);
cpufreq_cpu_put(data->policy);
return 0; return 0;
} }
...@@ -648,8 +660,11 @@ static int imx_thermal_resume(struct device *dev) ...@@ -648,8 +660,11 @@ static int imx_thermal_resume(struct device *dev)
{ {
struct imx_thermal_data *data = dev_get_drvdata(dev); struct imx_thermal_data *data = dev_get_drvdata(dev);
struct regmap *map = data->tempmon; struct regmap *map = data->tempmon;
int ret;
clk_prepare_enable(data->thermal_clk); ret = clk_prepare_enable(data->thermal_clk);
if (ret)
return ret;
/* Enabled thermal sensor after resume */ /* Enabled thermal sensor after resume */
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
......
...@@ -62,8 +62,8 @@ static int acpi_thermal_rel_release(struct inode *inode, struct file *file) ...@@ -62,8 +62,8 @@ static int acpi_thermal_rel_release(struct inode *inode, struct file *file)
* acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling * acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling
* *
* @handle: ACPI handle of the device contains _TRT * @handle: ACPI handle of the device contains _TRT
* @art_count: the number of valid entries resulted from parsing _TRT * @trt_count: the number of valid entries resulted from parsing _TRT
* @artp: pointer to pointer of array of art entries in parsing result * @trtp: pointer to pointer of array of _TRT entries in parsing result
* @create_dev: whether to create platform devices for target and source * @create_dev: whether to create platform devices for target and source
* *
*/ */
...@@ -208,7 +208,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, ...@@ -208,7 +208,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
if (art->target) { if (art->target) {
result = acpi_bus_get_device(art->target, &adev); result = acpi_bus_get_device(art->target, &adev);
if (result) if (result)
pr_warn("Failed to get source ACPI device\n"); pr_warn("Failed to get target ACPI device\n");
} }
} }
......
...@@ -237,9 +237,17 @@ static int int3403_add(struct platform_device *pdev) ...@@ -237,9 +237,17 @@ static int int3403_add(struct platform_device *pdev)
status = acpi_evaluate_integer(priv->adev->handle, "PTYP", status = acpi_evaluate_integer(priv->adev->handle, "PTYP",
NULL, &priv->type); NULL, &priv->type);
if (ACPI_FAILURE(status)) {
unsigned long long tmp;
status = acpi_evaluate_integer(priv->adev->handle, "_TMP",
NULL, &tmp);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
result = -EINVAL; result = -EINVAL;
goto err; goto err;
} else {
priv->type = INT3403_TYPE_SENSOR;
}
} }
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/cpufreq.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/cpu_cooling.h> #include <linux/cpu_cooling.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
/* common data structures */ /* common data structures */
struct ti_thermal_data { struct ti_thermal_data {
struct cpufreq_policy *policy;
struct thermal_zone_device *ti_thermal; struct thermal_zone_device *ti_thermal;
struct thermal_zone_device *pcb_tz; struct thermal_zone_device *pcb_tz;
struct thermal_cooling_device *cool_dev; struct thermal_cooling_device *cool_dev;
...@@ -247,15 +249,19 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id) ...@@ -247,15 +249,19 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
if (!data) if (!data)
return -EINVAL; return -EINVAL;
data->policy = cpufreq_cpu_get(0);
if (!data->policy) {
pr_debug("%s: CPUFreq policy not found\n", __func__);
return -EPROBE_DEFER;
}
/* Register cooling device */ /* Register cooling device */
data->cool_dev = cpufreq_cooling_register(cpu_present_mask); data->cool_dev = cpufreq_cooling_register(data->policy);
if (IS_ERR(data->cool_dev)) { if (IS_ERR(data->cool_dev)) {
int ret = PTR_ERR(data->cool_dev); int ret = PTR_ERR(data->cool_dev);
dev_err(bgp->dev, "Failed to register cpu cooling device %d\n",
if (ret != -EPROBE_DEFER)
dev_err(bgp->dev,
"Failed to register cpu cooling device %d\n",
ret); ret);
cpufreq_cpu_put(data->policy);
return ret; return ret;
} }
...@@ -270,8 +276,10 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id) ...@@ -270,8 +276,10 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
data = ti_bandgap_get_sensor_data(bgp, id); data = ti_bandgap_get_sensor_data(bgp, id);
if (data) if (data) {
cpufreq_cooling_unregister(data->cool_dev); cpufreq_cooling_unregister(data->cool_dev);
cpufreq_cpu_put(data->policy);
}
return 0; return 0;
} }
...@@ -28,47 +28,49 @@ ...@@ -28,47 +28,49 @@
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
struct cpufreq_policy;
typedef int (*get_static_t)(cpumask_t *cpumask, int interval, typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
unsigned long voltage, u32 *power); unsigned long voltage, u32 *power);
#ifdef CONFIG_CPU_THERMAL #ifdef CONFIG_CPU_THERMAL
/** /**
* cpufreq_cooling_register - function to create cpufreq cooling device. * cpufreq_cooling_register - function to create cpufreq cooling device.
* @clip_cpus: cpumask of cpus where the frequency constraints will happen * @policy: cpufreq policy.
*/ */
struct thermal_cooling_device * struct thermal_cooling_device *
cpufreq_cooling_register(const struct cpumask *clip_cpus); cpufreq_cooling_register(struct cpufreq_policy *policy);
struct thermal_cooling_device * struct thermal_cooling_device *
cpufreq_power_cooling_register(const struct cpumask *clip_cpus, cpufreq_power_cooling_register(struct cpufreq_policy *policy,
u32 capacitance, get_static_t plat_static_func); u32 capacitance, get_static_t plat_static_func);
/** /**
* of_cpufreq_cooling_register - create cpufreq cooling device based on DT. * of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
* @np: a valid struct device_node to the cooling device device tree node. * @np: a valid struct device_node to the cooling device device tree node.
* @clip_cpus: cpumask of cpus where the frequency constraints will happen * @policy: cpufreq policy.
*/ */
#ifdef CONFIG_THERMAL_OF #ifdef CONFIG_THERMAL_OF
struct thermal_cooling_device * struct thermal_cooling_device *
of_cpufreq_cooling_register(struct device_node *np, of_cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus); struct cpufreq_policy *policy);
struct thermal_cooling_device * struct thermal_cooling_device *
of_cpufreq_power_cooling_register(struct device_node *np, of_cpufreq_power_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, struct cpufreq_policy *policy,
u32 capacitance, u32 capacitance,
get_static_t plat_static_func); get_static_t plat_static_func);
#else #else
static inline struct thermal_cooling_device * static inline struct thermal_cooling_device *
of_cpufreq_cooling_register(struct device_node *np, of_cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus) struct cpufreq_policy *policy)
{ {
return ERR_PTR(-ENOSYS); return ERR_PTR(-ENOSYS);
} }
static inline struct thermal_cooling_device * static inline struct thermal_cooling_device *
of_cpufreq_power_cooling_register(struct device_node *np, of_cpufreq_power_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, struct cpufreq_policy *policy,
u32 capacitance, u32 capacitance,
get_static_t plat_static_func) get_static_t plat_static_func)
{ {
...@@ -82,15 +84,14 @@ of_cpufreq_power_cooling_register(struct device_node *np, ...@@ -82,15 +84,14 @@ of_cpufreq_power_cooling_register(struct device_node *np,
*/ */
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev); void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq);
#else /* !CONFIG_CPU_THERMAL */ #else /* !CONFIG_CPU_THERMAL */
static inline struct thermal_cooling_device * static inline struct thermal_cooling_device *
cpufreq_cooling_register(const struct cpumask *clip_cpus) cpufreq_cooling_register(struct cpufreq_policy *policy)
{ {
return ERR_PTR(-ENOSYS); return ERR_PTR(-ENOSYS);
} }
static inline struct thermal_cooling_device * static inline struct thermal_cooling_device *
cpufreq_power_cooling_register(const struct cpumask *clip_cpus, cpufreq_power_cooling_register(struct cpufreq_policy *policy,
u32 capacitance, get_static_t plat_static_func) u32 capacitance, get_static_t plat_static_func)
{ {
return NULL; return NULL;
...@@ -98,14 +99,14 @@ cpufreq_power_cooling_register(const struct cpumask *clip_cpus, ...@@ -98,14 +99,14 @@ cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
static inline struct thermal_cooling_device * static inline struct thermal_cooling_device *
of_cpufreq_cooling_register(struct device_node *np, of_cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus) struct cpufreq_policy *policy)
{ {
return ERR_PTR(-ENOSYS); return ERR_PTR(-ENOSYS);
} }
static inline struct thermal_cooling_device * static inline struct thermal_cooling_device *
of_cpufreq_power_cooling_register(struct device_node *np, of_cpufreq_power_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, struct cpufreq_policy *policy,
u32 capacitance, u32 capacitance,
get_static_t plat_static_func) get_static_t plat_static_func)
{ {
...@@ -117,11 +118,6 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) ...@@ -117,11 +118,6 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
{ {
return; return;
} }
static inline
unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
{
return THERMAL_CSTATE_INVALID;
}
#endif /* CONFIG_CPU_THERMAL */ #endif /* CONFIG_CPU_THERMAL */
#endif /* __CPU_COOLING_H__ */ #endif /* __CPU_COOLING_H__ */
...@@ -862,6 +862,20 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, ...@@ -862,6 +862,20 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
return -EINVAL; return -EINVAL;
} }
} }
static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
int count = 0;
if (unlikely(!policy->freq_table))
return 0;
cpufreq_for_each_valid_entry(pos, policy->freq_table)
count++;
return count;
}
#else #else
static inline int cpufreq_boost_trigger_state(int state) static inline int cpufreq_boost_trigger_state(int state)
{ {
......
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