1c0672860SThomas Renninger 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/drivers/cpufreq/cpufreq_userspace.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2001 Russell King 61da177e4SLinus Torvalds * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 101da177e4SLinus Torvalds * published by the Free Software Foundation. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 14db701151SViresh Kumar #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15db701151SViresh Kumar 161da177e4SLinus Torvalds #include <linux/cpufreq.h> 17*d1922f02SViresh Kumar #include <linux/init.h> 18*d1922f02SViresh Kumar #include <linux/module.h> 193fc54d37Sakpm@osdl.org #include <linux/mutex.h> 201da177e4SLinus Torvalds 21b38868aaSMike Travis static DEFINE_PER_CPU(unsigned int, cpu_is_managed); 223fc54d37Sakpm@osdl.org static DEFINE_MUTEX(userspace_mutex); 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds /** 251da177e4SLinus Torvalds * cpufreq_set - set the CPU frequency 269e76988eSVenki Pallipadi * @policy: pointer to policy struct where freq is being set 271da177e4SLinus Torvalds * @freq: target frequency in kHz 281da177e4SLinus Torvalds * 291da177e4SLinus Torvalds * Sets the CPU frequency to freq. 301da177e4SLinus Torvalds */ 319e76988eSVenki Pallipadi static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) 321da177e4SLinus Torvalds { 331da177e4SLinus Torvalds int ret = -EINVAL; 341da177e4SLinus Torvalds 352d06d8c4SDominik Brodowski pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 361da177e4SLinus Torvalds 373fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 38b38868aaSMike Travis if (!per_cpu(cpu_is_managed, policy->cpu)) 391da177e4SLinus Torvalds goto err; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* 421da177e4SLinus Torvalds * We're safe from concurrent calls to ->target() here 433fc54d37Sakpm@osdl.org * as we hold the userspace_mutex lock. If we were calling 441da177e4SLinus Torvalds * cpufreq_driver_target, a deadlock situation might occur: 451bceb8d1SDave Jones * A: cpufreq_set (lock userspace_mutex) -> 461bceb8d1SDave Jones * cpufreq_driver_target(lock policy->lock) 471bceb8d1SDave Jones * B: cpufreq_set_policy(lock policy->lock) -> 481bceb8d1SDave Jones * __cpufreq_governor -> 491bceb8d1SDave Jones * cpufreq_governor_userspace (lock userspace_mutex) 501da177e4SLinus Torvalds */ 51c0672860SThomas Renninger ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds err: 543fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 551da177e4SLinus Torvalds return ret; 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) 601da177e4SLinus Torvalds { 61*d1922f02SViresh Kumar return sprintf(buf, "%u\n", policy->cur); 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds static int cpufreq_governor_userspace(struct cpufreq_policy *policy, 651da177e4SLinus Torvalds unsigned int event) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds unsigned int cpu = policy->cpu; 68914f7c31SJeff Garzik int rc = 0; 69914f7c31SJeff Garzik 701da177e4SLinus Torvalds switch (event) { 711da177e4SLinus Torvalds case CPUFREQ_GOV_START: 721da177e4SLinus Torvalds BUG_ON(!policy->cur); 73*d1922f02SViresh Kumar pr_debug("started managing cpu %u\n", cpu); 74*d1922f02SViresh Kumar 753fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 76b38868aaSMike Travis per_cpu(cpu_is_managed, cpu) = 1; 773fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 781da177e4SLinus Torvalds break; 791da177e4SLinus Torvalds case CPUFREQ_GOV_STOP: 802d06d8c4SDominik Brodowski pr_debug("managing cpu %u stopped\n", cpu); 81*d1922f02SViresh Kumar 82*d1922f02SViresh Kumar mutex_lock(&userspace_mutex); 83*d1922f02SViresh Kumar per_cpu(cpu_is_managed, cpu) = 0; 843fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 851da177e4SLinus Torvalds break; 861da177e4SLinus Torvalds case CPUFREQ_GOV_LIMITS: 873fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 88*d1922f02SViresh Kumar pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n", 89c0672860SThomas Renninger cpu, policy->min, policy->max, 90*d1922f02SViresh Kumar policy->cur); 91*d1922f02SViresh Kumar 92*d1922f02SViresh Kumar if (policy->max < policy->cur) 93c0672860SThomas Renninger __cpufreq_driver_target(policy, policy->max, 941da177e4SLinus Torvalds CPUFREQ_RELATION_H); 95*d1922f02SViresh Kumar else if (policy->min > policy->cur) 96c0672860SThomas Renninger __cpufreq_driver_target(policy, policy->min, 971da177e4SLinus Torvalds CPUFREQ_RELATION_L); 983fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 991da177e4SLinus Torvalds break; 1001da177e4SLinus Torvalds } 101914f7c31SJeff Garzik return rc; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds 105c4d14bc0SSven Wegener #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 106c4d14bc0SSven Wegener static 107c4d14bc0SSven Wegener #endif 1081da177e4SLinus Torvalds struct cpufreq_governor cpufreq_gov_userspace = { 1091da177e4SLinus Torvalds .name = "userspace", 1101da177e4SLinus Torvalds .governor = cpufreq_governor_userspace, 1119e76988eSVenki Pallipadi .store_setspeed = cpufreq_set, 1129e76988eSVenki Pallipadi .show_setspeed = show_speed, 1131da177e4SLinus Torvalds .owner = THIS_MODULE, 1141da177e4SLinus Torvalds }; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds static int __init cpufreq_gov_userspace_init(void) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds return cpufreq_register_governor(&cpufreq_gov_userspace); 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds static void __exit cpufreq_gov_userspace_exit(void) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds cpufreq_unregister_governor(&cpufreq_gov_userspace); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds 1281bceb8d1SDave Jones MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 1291bceb8d1SDave Jones "Russell King <rmk@arm.linux.org.uk>"); 1301da177e4SLinus Torvalds MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 1311da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1321da177e4SLinus Torvalds 1336915719bSJohannes Weiner #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 1341da177e4SLinus Torvalds fs_initcall(cpufreq_gov_userspace_init); 1356915719bSJohannes Weiner #else 1366915719bSJohannes Weiner module_init(cpufreq_gov_userspace_init); 1376915719bSJohannes Weiner #endif 1381da177e4SLinus Torvalds module_exit(cpufreq_gov_userspace_exit); 139