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/slab.h> 7 #include <linux/init.h> 8 #include <linux/wait.h> 9 #include <linux/cpufreq.h> 10 11 #include <asm/prom.h> 12 13 #include "windfarm.h" 14 15 #define VERSION "0.3" 16 17 static int clamped; 18 static struct wf_control *clamp_control; 19 20 static int clamp_notifier_call(struct notifier_block *self, 21 unsigned long event, void *data) 22 { 23 struct cpufreq_policy *p = data; 24 unsigned long max_freq; 25 26 if (event != CPUFREQ_ADJUST) 27 return 0; 28 29 max_freq = clamped ? (p->cpuinfo.min_freq) : (p->cpuinfo.max_freq); 30 cpufreq_verify_within_limits(p, 0, max_freq); 31 32 return 0; 33 } 34 35 static struct notifier_block clamp_notifier = { 36 .notifier_call = clamp_notifier_call, 37 }; 38 39 static int clamp_set(struct wf_control *ct, s32 value) 40 { 41 if (value) 42 printk(KERN_INFO "windfarm: Clamping CPU frequency to " 43 "minimum !\n"); 44 else 45 printk(KERN_INFO "windfarm: CPU frequency unclamped !\n"); 46 clamped = value; 47 cpufreq_update_policy(0); 48 return 0; 49 } 50 51 static int clamp_get(struct wf_control *ct, s32 *value) 52 { 53 *value = clamped; 54 return 0; 55 } 56 57 static s32 clamp_min(struct wf_control *ct) 58 { 59 return 0; 60 } 61 62 static s32 clamp_max(struct wf_control *ct) 63 { 64 return 1; 65 } 66 67 static const struct wf_control_ops clamp_ops = { 68 .set_value = clamp_set, 69 .get_value = clamp_get, 70 .get_min = clamp_min, 71 .get_max = clamp_max, 72 .owner = THIS_MODULE, 73 }; 74 75 static int __init wf_cpufreq_clamp_init(void) 76 { 77 struct wf_control *clamp; 78 79 clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); 80 if (clamp == NULL) 81 return -ENOMEM; 82 cpufreq_register_notifier(&clamp_notifier, CPUFREQ_POLICY_NOTIFIER); 83 clamp->ops = &clamp_ops; 84 clamp->name = "cpufreq-clamp"; 85 if (wf_register_control(clamp)) 86 goto fail; 87 clamp_control = clamp; 88 return 0; 89 fail: 90 kfree(clamp); 91 return -ENODEV; 92 } 93 94 static void __exit wf_cpufreq_clamp_exit(void) 95 { 96 if (clamp_control) 97 wf_unregister_control(clamp_control); 98 } 99 100 101 module_init(wf_cpufreq_clamp_init); 102 module_exit(wf_cpufreq_clamp_exit); 103 104 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 105 MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control"); 106 MODULE_LICENSE("GPL"); 107 108