Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/types.h>
0003 #include <linux/errno.h>
0004 #include <linux/kernel.h>
0005 #include <linux/delay.h>
0006 #include <linux/pm_qos.h>
0007 #include <linux/slab.h>
0008 #include <linux/init.h>
0009 #include <linux/wait.h>
0010 #include <linux/cpu.h>
0011 #include <linux/cpufreq.h>
0012 
0013 #include "windfarm.h"
0014 
0015 #define VERSION "0.3"
0016 
0017 static int clamped;
0018 static struct wf_control *clamp_control;
0019 static struct freq_qos_request qos_req;
0020 static unsigned int min_freq, max_freq;
0021 
0022 static int clamp_set(struct wf_control *ct, s32 value)
0023 {
0024     unsigned int freq;
0025 
0026     if (value) {
0027         freq = min_freq;
0028         printk(KERN_INFO "windfarm: Clamping CPU frequency to "
0029                "minimum !\n");
0030     } else {
0031         freq = max_freq;
0032         printk(KERN_INFO "windfarm: CPU frequency unclamped !\n");
0033     }
0034     clamped = value;
0035 
0036     return freq_qos_update_request(&qos_req, freq);
0037 }
0038 
0039 static int clamp_get(struct wf_control *ct, s32 *value)
0040 {
0041     *value = clamped;
0042     return 0;
0043 }
0044 
0045 static s32 clamp_min(struct wf_control *ct)
0046 {
0047     return 0;
0048 }
0049 
0050 static s32 clamp_max(struct wf_control *ct)
0051 {
0052     return 1;
0053 }
0054 
0055 static const struct wf_control_ops clamp_ops = {
0056     .set_value  = clamp_set,
0057     .get_value  = clamp_get,
0058     .get_min    = clamp_min,
0059     .get_max    = clamp_max,
0060     .owner      = THIS_MODULE,
0061 };
0062 
0063 static int __init wf_cpufreq_clamp_init(void)
0064 {
0065     struct cpufreq_policy *policy;
0066     struct wf_control *clamp;
0067     struct device *dev;
0068     int ret;
0069 
0070     policy = cpufreq_cpu_get(0);
0071     if (!policy) {
0072         pr_warn("%s: cpufreq policy not found cpu0\n", __func__);
0073         return -EPROBE_DEFER;
0074     }
0075 
0076     min_freq = policy->cpuinfo.min_freq;
0077     max_freq = policy->cpuinfo.max_freq;
0078 
0079     ret = freq_qos_add_request(&policy->constraints, &qos_req, FREQ_QOS_MAX,
0080                    max_freq);
0081 
0082     cpufreq_cpu_put(policy);
0083 
0084     if (ret < 0) {
0085         pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
0086                ret);
0087         return ret;
0088     }
0089 
0090     dev = get_cpu_device(0);
0091     if (unlikely(!dev)) {
0092         pr_warn("%s: No cpu device for cpu0\n", __func__);
0093         ret = -ENODEV;
0094         goto fail;
0095     }
0096 
0097     clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
0098     if (clamp == NULL) {
0099         ret = -ENOMEM;
0100         goto fail;
0101     }
0102 
0103     clamp->ops = &clamp_ops;
0104     clamp->name = "cpufreq-clamp";
0105     ret = wf_register_control(clamp);
0106     if (ret)
0107         goto free;
0108 
0109     clamp_control = clamp;
0110     return 0;
0111 
0112  free:
0113     kfree(clamp);
0114  fail:
0115     freq_qos_remove_request(&qos_req);
0116     return ret;
0117 }
0118 
0119 static void __exit wf_cpufreq_clamp_exit(void)
0120 {
0121     if (clamp_control) {
0122         wf_unregister_control(clamp_control);
0123         freq_qos_remove_request(&qos_req);
0124     }
0125 }
0126 
0127 
0128 module_init(wf_cpufreq_clamp_init);
0129 module_exit(wf_cpufreq_clamp_exit);
0130 
0131 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
0132 MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control");
0133 MODULE_LICENSE("GPL");
0134