diff options
Diffstat (limited to 'drivers/macintosh/windfarm_cpufreq_clamp.c')
-rw-r--r-- | drivers/macintosh/windfarm_cpufreq_clamp.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c new file mode 100644 index 000000000..28d18ef22 --- /dev/null +++ b/drivers/macintosh/windfarm_cpufreq_clamp.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/pm_qos.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/wait.h> +#include <linux/cpu.h> +#include <linux/cpufreq.h> + +#include "windfarm.h" + +#define VERSION "0.3" + +static int clamped; +static struct wf_control *clamp_control; +static struct freq_qos_request qos_req; +static unsigned int min_freq, max_freq; + +static int clamp_set(struct wf_control *ct, s32 value) +{ + unsigned int freq; + + if (value) { + freq = min_freq; + printk(KERN_INFO "windfarm: Clamping CPU frequency to " + "minimum !\n"); + } else { + freq = max_freq; + printk(KERN_INFO "windfarm: CPU frequency unclamped !\n"); + } + clamped = value; + + return freq_qos_update_request(&qos_req, freq); +} + +static int clamp_get(struct wf_control *ct, s32 *value) +{ + *value = clamped; + return 0; +} + +static s32 clamp_min(struct wf_control *ct) +{ + return 0; +} + +static s32 clamp_max(struct wf_control *ct) +{ + return 1; +} + +static const struct wf_control_ops clamp_ops = { + .set_value = clamp_set, + .get_value = clamp_get, + .get_min = clamp_min, + .get_max = clamp_max, + .owner = THIS_MODULE, +}; + +static int __init wf_cpufreq_clamp_init(void) +{ + struct cpufreq_policy *policy; + struct wf_control *clamp; + struct device *dev; + int ret; + + policy = cpufreq_cpu_get(0); + if (!policy) { + pr_warn("%s: cpufreq policy not found cpu0\n", __func__); + return -EPROBE_DEFER; + } + + min_freq = policy->cpuinfo.min_freq; + max_freq = policy->cpuinfo.max_freq; + + ret = freq_qos_add_request(&policy->constraints, &qos_req, FREQ_QOS_MAX, + max_freq); + + cpufreq_cpu_put(policy); + + if (ret < 0) { + pr_err("%s: Failed to add freq constraint (%d)\n", __func__, + ret); + return ret; + } + + dev = get_cpu_device(0); + if (unlikely(!dev)) { + pr_warn("%s: No cpu device for cpu0\n", __func__); + ret = -ENODEV; + goto fail; + } + + clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); + if (clamp == NULL) { + ret = -ENOMEM; + goto fail; + } + + clamp->ops = &clamp_ops; + clamp->name = "cpufreq-clamp"; + ret = wf_register_control(clamp); + if (ret) + goto free; + + clamp_control = clamp; + return 0; + + free: + kfree(clamp); + fail: + freq_qos_remove_request(&qos_req); + return ret; +} + +static void __exit wf_cpufreq_clamp_exit(void) +{ + if (clamp_control) { + wf_unregister_control(clamp_control); + freq_qos_remove_request(&qos_req); + } +} + + +module_init(wf_cpufreq_clamp_init); +module_exit(wf_cpufreq_clamp_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); +MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control"); +MODULE_LICENSE("GPL"); + |