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