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