| .. | .. |
|---|
| 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 | |
|---|