summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/thermal/cpu_cooling.c56
-rw-r--r--include/linux/cpu_cooling.h16
2 files changed, 65 insertions, 7 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 6ceac4f2d4b2..560c5c72daeb 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -103,6 +103,7 @@ struct cpufreq_cooling_device {
int dyn_power_table_entries;
struct device *cpu_dev;
get_static_t plat_get_static_power;
+ struct cpu_cooling_ops *plat_ops;
};
static DEFINE_IDR(cpufreq_idr);
static DEFINE_MUTEX(cooling_cpufreq_lock);
@@ -504,8 +505,13 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+ unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
- *state = cpufreq_device->cpufreq_state;
+ if (cpufreq_device->plat_ops
+ && cpufreq_device->plat_ops->get_cur_state)
+ cpufreq_device->plat_ops->get_cur_state(cpu, state);
+ else
+ *state = cpufreq_device->cpufreq_state;
return 0;
}
@@ -539,7 +545,17 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
cpufreq_device->cpufreq_state = state;
cpufreq_device->clipped_freq = clip_freq;
- cpufreq_update_policy(cpu);
+ /* Check if the device has a platform mitigation function that
+ * can handle the CPU freq mitigation, if not, notify cpufreq
+ * framework.
+ */
+ if (cpufreq_device->plat_ops) {
+ if (cpufreq_device->plat_ops->ceil_limit)
+ cpufreq_device->plat_ops->ceil_limit(cpu,
+ clip_freq);
+ } else {
+ cpufreq_update_policy(cpu);
+ }
return 0;
}
@@ -773,6 +789,9 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
* @capacitance: dynamic power coefficient for these cpus
* @plat_static_func: function to calculate the static power consumed by these
* cpus (optional)
+ * @plat_mitig_func: function that does the mitigation by changing the
+ * frequencies (Optional). By default, cpufreq framweork will
+ * be notified of the new limits.
*
* This interface function registers the cpufreq cooling device with the name
* "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
@@ -785,7 +804,8 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
static struct thermal_cooling_device *
__cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, u32 capacitance,
- get_static_t plat_static_func)
+ get_static_t plat_static_func,
+ struct cpu_cooling_ops *plat_ops)
{
struct thermal_cooling_device *cool_dev;
struct cpufreq_cooling_device *cpufreq_dev;
@@ -851,6 +871,8 @@ __cpufreq_cooling_register(struct device_node *np,
}
}
+ cpufreq_dev->plat_ops = plat_ops;
+
ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
if (ret) {
cool_dev = ERR_PTR(ret);
@@ -924,7 +946,7 @@ free_cdev:
struct thermal_cooling_device *
cpufreq_cooling_register(const struct cpumask *clip_cpus)
{
- return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL);
+ return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL, NULL);
}
EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
@@ -948,7 +970,7 @@ of_cpufreq_cooling_register(struct device_node *np,
if (!np)
return ERR_PTR(-EINVAL);
- return __cpufreq_cooling_register(np, clip_cpus, 0, NULL);
+ return __cpufreq_cooling_register(np, clip_cpus, 0, NULL, NULL);
}
EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
@@ -978,11 +1000,31 @@ cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance,
get_static_t plat_static_func)
{
return __cpufreq_cooling_register(NULL, clip_cpus, capacitance,
- plat_static_func);
+ plat_static_func, NULL);
}
EXPORT_SYMBOL(cpufreq_power_cooling_register);
/**
+ * cpufreq_platform_cooling_register() - create cpufreq cooling device with
+ * additional platform specific mitigation function.
+ *
+ * @clip_cpus: cpumask of cpus where the frequency constraints will happen
+ * @plat_ops: the platform mitigation functions that will be called insted of
+ * cpufreq, if provided.
+ *
+ * Return: a valid struct thermal_cooling_device pointer on success,
+ * on failure, it returns a corresponding ERR_PTR().
+ */
+struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+ struct cpu_cooling_ops *plat_ops)
+{
+ return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL,
+ plat_ops);
+}
+EXPORT_SYMBOL(cpufreq_platform_cooling_register);
+
+/**
* 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
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
@@ -1015,7 +1057,7 @@ of_cpufreq_power_cooling_register(struct device_node *np,
return ERR_PTR(-EINVAL);
return __cpufreq_cooling_register(np, clip_cpus, capacitance,
- plat_static_func);
+ plat_static_func, NULL);
}
EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index c156f5082758..e221494fb7a0 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -31,6 +31,11 @@
typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
unsigned long voltage, u32 *power);
+struct cpu_cooling_ops {
+ int (*ceil_limit)(int, u32);
+ int (*get_cur_state)(int, unsigned long *);
+};
+
#ifdef CONFIG_CPU_THERMAL
/**
* cpufreq_cooling_register - function to create cpufreq cooling device.
@@ -43,6 +48,10 @@ struct thermal_cooling_device *
cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
u32 capacitance, get_static_t plat_static_func);
+struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+ struct cpu_cooling_ops *ops);
+
/**
* of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
* @np: a valid struct device_node to the cooling device device tree node.
@@ -112,6 +121,13 @@ of_cpufreq_power_cooling_register(struct device_node *np,
return NULL;
}
+static inline struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+ struct cpu_cooling_ops *ops)
+{
+ return NULL;
+}
+
static inline
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
{