0001
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