1 2/* 3 * linux/drivers/cpufreq/cpufreq_userspace.c 4 * 5 * Copyright (C) 2001 Russell King 6 * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 */ 13 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 16#include <linux/cpufreq.h> 17#include <linux/init.h> 18#include <linux/module.h> 19#include <linux/mutex.h> 20 21static DEFINE_PER_CPU(unsigned int, cpu_is_managed); 22static DEFINE_MUTEX(userspace_mutex); 23 24/** 25 * cpufreq_set - set the CPU frequency 26 * @policy: pointer to policy struct where freq is being set 27 * @freq: target frequency in kHz 28 * 29 * Sets the CPU frequency to freq. 30 */ 31static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) 32{ 33 int ret = -EINVAL; 34 35 pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 36 37 mutex_lock(&userspace_mutex); 38 if (!per_cpu(cpu_is_managed, policy->cpu)) 39 goto err; 40 41 ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 42 err: 43 mutex_unlock(&userspace_mutex); 44 return ret; 45} 46 47static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) 48{ 49 return sprintf(buf, "%u\n", policy->cur); 50} 51 52static int cpufreq_governor_userspace(struct cpufreq_policy *policy, 53 unsigned int event) 54{ 55 unsigned int cpu = policy->cpu; 56 int rc = 0; 57 58 switch (event) { 59 case CPUFREQ_GOV_START: 60 BUG_ON(!policy->cur); 61 pr_debug("started managing cpu %u\n", cpu); 62 63 mutex_lock(&userspace_mutex); 64 per_cpu(cpu_is_managed, cpu) = 1; 65 mutex_unlock(&userspace_mutex); 66 break; 67 case CPUFREQ_GOV_STOP: 68 pr_debug("managing cpu %u stopped\n", cpu); 69 70 mutex_lock(&userspace_mutex); 71 per_cpu(cpu_is_managed, cpu) = 0; 72 mutex_unlock(&userspace_mutex); 73 break; 74 case CPUFREQ_GOV_LIMITS: 75 mutex_lock(&userspace_mutex); 76 pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n", 77 cpu, policy->min, policy->max, 78 policy->cur); 79 80 if (policy->max < policy->cur) 81 __cpufreq_driver_target(policy, policy->max, 82 CPUFREQ_RELATION_H); 83 else if (policy->min > policy->cur) 84 __cpufreq_driver_target(policy, policy->min, 85 CPUFREQ_RELATION_L); 86 mutex_unlock(&userspace_mutex); 87 break; 88 } 89 return rc; 90} 91 92#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 93static 94#endif 95struct cpufreq_governor cpufreq_gov_userspace = { 96 .name = "userspace", 97 .governor = cpufreq_governor_userspace, 98 .store_setspeed = cpufreq_set, 99 .show_setspeed = show_speed, 100 .owner = THIS_MODULE, 101}; 102 103static int __init cpufreq_gov_userspace_init(void) 104{ 105 return cpufreq_register_governor(&cpufreq_gov_userspace); 106} 107 108static void __exit cpufreq_gov_userspace_exit(void) 109{ 110 cpufreq_unregister_governor(&cpufreq_gov_userspace); 111} 112 113MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 114 "Russell King <rmk@arm.linux.org.uk>"); 115MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 116MODULE_LICENSE("GPL"); 117 118#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 119fs_initcall(cpufreq_gov_userspace_init); 120#else 121module_init(cpufreq_gov_userspace_init); 122#endif 123module_exit(cpufreq_gov_userspace_exit); 124