Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
75722d39 BH |
2 | #include <linux/types.h> |
3 | #include <linux/errno.h> | |
4 | #include <linux/kernel.h> | |
5 | #include <linux/delay.h> | |
dce2e3a8 | 6 | #include <linux/pm_qos.h> |
75722d39 BH |
7 | #include <linux/slab.h> |
8 | #include <linux/init.h> | |
9 | #include <linux/wait.h> | |
dce2e3a8 | 10 | #include <linux/cpu.h> |
75722d39 BH |
11 | #include <linux/cpufreq.h> |
12 | ||
13 | #include "windfarm.h" | |
14 | ||
15 | #define VERSION "0.3" | |
16 | ||
17 | static int clamped; | |
18 | static struct wf_control *clamp_control; | |
3000ce3c | 19 | static struct freq_qos_request qos_req; |
dce2e3a8 | 20 | static unsigned int min_freq, max_freq; |
75722d39 BH |
21 | |
22 | static int clamp_set(struct wf_control *ct, s32 value) | |
23 | { | |
dce2e3a8 VK |
24 | unsigned int freq; |
25 | ||
26 | if (value) { | |
27 | freq = min_freq; | |
75722d39 BH |
28 | printk(KERN_INFO "windfarm: Clamping CPU frequency to " |
29 | "minimum !\n"); | |
dce2e3a8 VK |
30 | } else { |
31 | freq = max_freq; | |
75722d39 | 32 | printk(KERN_INFO "windfarm: CPU frequency unclamped !\n"); |
dce2e3a8 | 33 | } |
75722d39 | 34 | clamped = value; |
dce2e3a8 | 35 | |
3000ce3c | 36 | return freq_qos_update_request(&qos_req, freq); |
75722d39 BH |
37 | } |
38 | ||
39 | static int clamp_get(struct wf_control *ct, s32 *value) | |
40 | { | |
41 | *value = clamped; | |
42 | return 0; | |
43 | } | |
44 | ||
45 | static s32 clamp_min(struct wf_control *ct) | |
46 | { | |
47 | return 0; | |
48 | } | |
49 | ||
50 | static s32 clamp_max(struct wf_control *ct) | |
51 | { | |
52 | return 1; | |
53 | } | |
54 | ||
1ad35f6e | 55 | static const struct wf_control_ops clamp_ops = { |
75722d39 BH |
56 | .set_value = clamp_set, |
57 | .get_value = clamp_get, | |
58 | .get_min = clamp_min, | |
59 | .get_max = clamp_max, | |
60 | .owner = THIS_MODULE, | |
61 | }; | |
62 | ||
63 | static int __init wf_cpufreq_clamp_init(void) | |
64 | { | |
dce2e3a8 | 65 | struct cpufreq_policy *policy; |
75722d39 | 66 | struct wf_control *clamp; |
dce2e3a8 VK |
67 | struct device *dev; |
68 | int ret; | |
69 | ||
70 | policy = cpufreq_cpu_get(0); | |
71 | if (!policy) { | |
72 | pr_warn("%s: cpufreq policy not found cpu0\n", __func__); | |
73 | return -EPROBE_DEFER; | |
74 | } | |
75 | ||
76 | min_freq = policy->cpuinfo.min_freq; | |
77 | max_freq = policy->cpuinfo.max_freq; | |
3000ce3c RW |
78 | |
79 | ret = freq_qos_add_request(&policy->constraints, &qos_req, FREQ_QOS_MAX, | |
80 | max_freq); | |
81 | ||
dce2e3a8 VK |
82 | cpufreq_cpu_put(policy); |
83 | ||
3000ce3c RW |
84 | if (ret < 0) { |
85 | pr_err("%s: Failed to add freq constraint (%d)\n", __func__, | |
86 | ret); | |
87 | return ret; | |
88 | } | |
89 | ||
dce2e3a8 VK |
90 | dev = get_cpu_device(0); |
91 | if (unlikely(!dev)) { | |
92 | pr_warn("%s: No cpu device for cpu0\n", __func__); | |
3000ce3c RW |
93 | ret = -ENODEV; |
94 | goto fail; | |
dce2e3a8 | 95 | } |
75722d39 BH |
96 | |
97 | clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); | |
3000ce3c RW |
98 | if (clamp == NULL) { |
99 | ret = -ENOMEM; | |
100 | goto fail; | |
dce2e3a8 VK |
101 | } |
102 | ||
75722d39 BH |
103 | clamp->ops = &clamp_ops; |
104 | clamp->name = "cpufreq-clamp"; | |
dce2e3a8 VK |
105 | ret = wf_register_control(clamp); |
106 | if (ret) | |
3000ce3c RW |
107 | goto free; |
108 | ||
75722d39 BH |
109 | clamp_control = clamp; |
110 | return 0; | |
dce2e3a8 VK |
111 | |
112 | free: | |
75722d39 | 113 | kfree(clamp); |
3000ce3c RW |
114 | fail: |
115 | freq_qos_remove_request(&qos_req); | |
dce2e3a8 | 116 | return ret; |
75722d39 BH |
117 | } |
118 | ||
119 | static void __exit wf_cpufreq_clamp_exit(void) | |
120 | { | |
dce2e3a8 | 121 | if (clamp_control) { |
75722d39 | 122 | wf_unregister_control(clamp_control); |
3000ce3c | 123 | freq_qos_remove_request(&qos_req); |
dce2e3a8 | 124 | } |
75722d39 BH |
125 | } |
126 | ||
127 | ||
128 | module_init(wf_cpufreq_clamp_init); | |
129 | module_exit(wf_cpufreq_clamp_exit); | |
130 | ||
131 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | |
132 | MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control"); | |
133 | MODULE_LICENSE("GPL"); | |
134 |