.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | #include <linux/types.h> |
---|
2 | 3 | #include <linux/errno.h> |
---|
3 | 4 | #include <linux/kernel.h> |
---|
4 | 5 | #include <linux/delay.h> |
---|
| 6 | +#include <linux/pm_qos.h> |
---|
5 | 7 | #include <linux/slab.h> |
---|
6 | 8 | #include <linux/init.h> |
---|
7 | 9 | #include <linux/wait.h> |
---|
| 10 | +#include <linux/cpu.h> |
---|
8 | 11 | #include <linux/cpufreq.h> |
---|
9 | 12 | |
---|
10 | 13 | #include <asm/prom.h> |
---|
.. | .. |
---|
15 | 18 | |
---|
16 | 19 | static int clamped; |
---|
17 | 20 | static struct wf_control *clamp_control; |
---|
18 | | - |
---|
19 | | -static int clamp_notifier_call(struct notifier_block *self, |
---|
20 | | - unsigned long event, void *data) |
---|
21 | | -{ |
---|
22 | | - struct cpufreq_policy *p = data; |
---|
23 | | - unsigned long max_freq; |
---|
24 | | - |
---|
25 | | - if (event != CPUFREQ_ADJUST) |
---|
26 | | - return 0; |
---|
27 | | - |
---|
28 | | - max_freq = clamped ? (p->cpuinfo.min_freq) : (p->cpuinfo.max_freq); |
---|
29 | | - cpufreq_verify_within_limits(p, 0, max_freq); |
---|
30 | | - |
---|
31 | | - return 0; |
---|
32 | | -} |
---|
33 | | - |
---|
34 | | -static struct notifier_block clamp_notifier = { |
---|
35 | | - .notifier_call = clamp_notifier_call, |
---|
36 | | -}; |
---|
| 21 | +static struct freq_qos_request qos_req; |
---|
| 22 | +static unsigned int min_freq, max_freq; |
---|
37 | 23 | |
---|
38 | 24 | static int clamp_set(struct wf_control *ct, s32 value) |
---|
39 | 25 | { |
---|
40 | | - if (value) |
---|
| 26 | + unsigned int freq; |
---|
| 27 | + |
---|
| 28 | + if (value) { |
---|
| 29 | + freq = min_freq; |
---|
41 | 30 | printk(KERN_INFO "windfarm: Clamping CPU frequency to " |
---|
42 | 31 | "minimum !\n"); |
---|
43 | | - else |
---|
| 32 | + } else { |
---|
| 33 | + freq = max_freq; |
---|
44 | 34 | printk(KERN_INFO "windfarm: CPU frequency unclamped !\n"); |
---|
| 35 | + } |
---|
45 | 36 | clamped = value; |
---|
46 | | - cpufreq_update_policy(0); |
---|
47 | | - return 0; |
---|
| 37 | + |
---|
| 38 | + return freq_qos_update_request(&qos_req, freq); |
---|
48 | 39 | } |
---|
49 | 40 | |
---|
50 | 41 | static int clamp_get(struct wf_control *ct, s32 *value) |
---|
.. | .. |
---|
73 | 64 | |
---|
74 | 65 | static int __init wf_cpufreq_clamp_init(void) |
---|
75 | 66 | { |
---|
| 67 | + struct cpufreq_policy *policy; |
---|
76 | 68 | struct wf_control *clamp; |
---|
| 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; |
---|
| 80 | + |
---|
| 81 | + ret = freq_qos_add_request(&policy->constraints, &qos_req, FREQ_QOS_MAX, |
---|
| 82 | + max_freq); |
---|
| 83 | + |
---|
| 84 | + cpufreq_cpu_put(policy); |
---|
| 85 | + |
---|
| 86 | + if (ret < 0) { |
---|
| 87 | + pr_err("%s: Failed to add freq constraint (%d)\n", __func__, |
---|
| 88 | + ret); |
---|
| 89 | + return ret; |
---|
| 90 | + } |
---|
| 91 | + |
---|
| 92 | + dev = get_cpu_device(0); |
---|
| 93 | + if (unlikely(!dev)) { |
---|
| 94 | + pr_warn("%s: No cpu device for cpu0\n", __func__); |
---|
| 95 | + ret = -ENODEV; |
---|
| 96 | + goto fail; |
---|
| 97 | + } |
---|
77 | 98 | |
---|
78 | 99 | clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); |
---|
79 | | - if (clamp == NULL) |
---|
80 | | - return -ENOMEM; |
---|
81 | | - cpufreq_register_notifier(&clamp_notifier, CPUFREQ_POLICY_NOTIFIER); |
---|
| 100 | + if (clamp == NULL) { |
---|
| 101 | + ret = -ENOMEM; |
---|
| 102 | + goto fail; |
---|
| 103 | + } |
---|
| 104 | + |
---|
82 | 105 | clamp->ops = &clamp_ops; |
---|
83 | 106 | clamp->name = "cpufreq-clamp"; |
---|
84 | | - if (wf_register_control(clamp)) |
---|
85 | | - goto fail; |
---|
| 107 | + ret = wf_register_control(clamp); |
---|
| 108 | + if (ret) |
---|
| 109 | + goto free; |
---|
| 110 | + |
---|
86 | 111 | clamp_control = clamp; |
---|
87 | 112 | return 0; |
---|
88 | | - fail: |
---|
| 113 | + |
---|
| 114 | + free: |
---|
89 | 115 | kfree(clamp); |
---|
90 | | - return -ENODEV; |
---|
| 116 | + fail: |
---|
| 117 | + freq_qos_remove_request(&qos_req); |
---|
| 118 | + return ret; |
---|
91 | 119 | } |
---|
92 | 120 | |
---|
93 | 121 | static void __exit wf_cpufreq_clamp_exit(void) |
---|
94 | 122 | { |
---|
95 | | - if (clamp_control) |
---|
| 123 | + if (clamp_control) { |
---|
96 | 124 | wf_unregister_control(clamp_control); |
---|
| 125 | + freq_qos_remove_request(&qos_req); |
---|
| 126 | + } |
---|
97 | 127 | } |
---|
98 | 128 | |
---|
99 | 129 | |
---|