linux/drivers/macintosh/windfarm_cpufreq_clamp.c
<<
>>
Prefs
   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 <asm/prom.h>
  14
  15#include "windfarm.h"
  16
  17#define VERSION "0.3"
  18
  19static int clamped;
  20static struct wf_control *clamp_control;
  21static struct freq_qos_request qos_req;
  22static unsigned int min_freq, max_freq;
  23
  24static int clamp_set(struct wf_control *ct, s32 value)
  25{
  26        unsigned int freq;
  27
  28        if (value) {
  29                freq = min_freq;
  30                printk(KERN_INFO "windfarm: Clamping CPU frequency to "
  31                       "minimum !\n");
  32        } else {
  33                freq = max_freq;
  34                printk(KERN_INFO "windfarm: CPU frequency unclamped !\n");
  35        }
  36        clamped = value;
  37
  38        return freq_qos_update_request(&qos_req, freq);
  39}
  40
  41static int clamp_get(struct wf_control *ct, s32 *value)
  42{
  43        *value = clamped;
  44        return 0;
  45}
  46
  47static s32 clamp_min(struct wf_control *ct)
  48{
  49        return 0;
  50}
  51
  52static s32 clamp_max(struct wf_control *ct)
  53{
  54        return 1;
  55}
  56
  57static const struct wf_control_ops clamp_ops = {
  58        .set_value      = clamp_set,
  59        .get_value      = clamp_get,
  60        .get_min        = clamp_min,
  61        .get_max        = clamp_max,
  62        .owner          = THIS_MODULE,
  63};
  64
  65static int __init wf_cpufreq_clamp_init(void)
  66{
  67        struct cpufreq_policy *policy;
  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        }
  98
  99        clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
 100        if (clamp == NULL) {
 101                ret = -ENOMEM;
 102                goto fail;
 103        }
 104
 105        clamp->ops = &clamp_ops;
 106        clamp->name = "cpufreq-clamp";
 107        ret = wf_register_control(clamp);
 108        if (ret)
 109                goto free;
 110
 111        clamp_control = clamp;
 112        return 0;
 113
 114 free:
 115        kfree(clamp);
 116 fail:
 117        freq_qos_remove_request(&qos_req);
 118        return ret;
 119}
 120
 121static void __exit wf_cpufreq_clamp_exit(void)
 122{
 123        if (clamp_control) {
 124                wf_unregister_control(clamp_control);
 125                freq_qos_remove_request(&qos_req);
 126        }
 127}
 128
 129
 130module_init(wf_cpufreq_clamp_init);
 131module_exit(wf_cpufreq_clamp_exit);
 132
 133MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 134MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control");
 135MODULE_LICENSE("GPL");
 136
 137