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