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> 17d1922f02SViresh Kumar #include <linux/init.h> 18d1922f02SViresh Kumar #include <linux/module.h> 193fc54d37Sakpm@osdl.org #include <linux/mutex.h> 20*e43e94c1SSai Gurrappadi #include <linux/slab.h> 211da177e4SLinus Torvalds 22b38868aaSMike Travis static DEFINE_PER_CPU(unsigned int, cpu_is_managed); 233fc54d37Sakpm@osdl.org static DEFINE_MUTEX(userspace_mutex); 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds /** 261da177e4SLinus Torvalds * cpufreq_set - set the CPU frequency 279e76988eSVenki Pallipadi * @policy: pointer to policy struct where freq is being set 281da177e4SLinus Torvalds * @freq: target frequency in kHz 291da177e4SLinus Torvalds * 301da177e4SLinus Torvalds * Sets the CPU frequency to freq. 311da177e4SLinus Torvalds */ 329e76988eSVenki Pallipadi static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds int ret = -EINVAL; 35*e43e94c1SSai Gurrappadi unsigned int *setspeed = policy->governor_data; 361da177e4SLinus Torvalds 372d06d8c4SDominik Brodowski pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 381da177e4SLinus Torvalds 393fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 40b38868aaSMike Travis if (!per_cpu(cpu_is_managed, policy->cpu)) 411da177e4SLinus Torvalds goto err; 421da177e4SLinus Torvalds 43*e43e94c1SSai Gurrappadi *setspeed = freq; 44*e43e94c1SSai Gurrappadi 45c0672860SThomas Renninger ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 461da177e4SLinus Torvalds err: 473fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 481da177e4SLinus Torvalds return ret; 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) 521da177e4SLinus Torvalds { 53d1922f02SViresh Kumar return sprintf(buf, "%u\n", policy->cur); 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 56*e43e94c1SSai Gurrappadi static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) 57*e43e94c1SSai Gurrappadi { 58*e43e94c1SSai Gurrappadi unsigned int *setspeed; 59*e43e94c1SSai Gurrappadi 60*e43e94c1SSai Gurrappadi setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); 61*e43e94c1SSai Gurrappadi if (!setspeed) 62*e43e94c1SSai Gurrappadi return -ENOMEM; 63*e43e94c1SSai Gurrappadi 64*e43e94c1SSai Gurrappadi policy->governor_data = setspeed; 65*e43e94c1SSai Gurrappadi return 0; 66*e43e94c1SSai Gurrappadi } 67*e43e94c1SSai Gurrappadi 681da177e4SLinus Torvalds static int cpufreq_governor_userspace(struct cpufreq_policy *policy, 691da177e4SLinus Torvalds unsigned int event) 701da177e4SLinus Torvalds { 71*e43e94c1SSai Gurrappadi unsigned int *setspeed = policy->governor_data; 721da177e4SLinus Torvalds unsigned int cpu = policy->cpu; 73914f7c31SJeff Garzik int rc = 0; 74914f7c31SJeff Garzik 75*e43e94c1SSai Gurrappadi if (event == CPUFREQ_GOV_POLICY_INIT) 76*e43e94c1SSai Gurrappadi return cpufreq_userspace_policy_init(policy); 77*e43e94c1SSai Gurrappadi 78*e43e94c1SSai Gurrappadi if (!setspeed) 79*e43e94c1SSai Gurrappadi return -EINVAL; 80*e43e94c1SSai Gurrappadi 811da177e4SLinus Torvalds switch (event) { 82*e43e94c1SSai Gurrappadi case CPUFREQ_GOV_POLICY_EXIT: 83*e43e94c1SSai Gurrappadi mutex_lock(&userspace_mutex); 84*e43e94c1SSai Gurrappadi policy->governor_data = NULL; 85*e43e94c1SSai Gurrappadi kfree(setspeed); 86*e43e94c1SSai Gurrappadi mutex_unlock(&userspace_mutex); 87*e43e94c1SSai Gurrappadi break; 881da177e4SLinus Torvalds case CPUFREQ_GOV_START: 891da177e4SLinus Torvalds BUG_ON(!policy->cur); 90d1922f02SViresh Kumar pr_debug("started managing cpu %u\n", cpu); 91d1922f02SViresh Kumar 923fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 93b38868aaSMike Travis per_cpu(cpu_is_managed, cpu) = 1; 94*e43e94c1SSai Gurrappadi *setspeed = policy->cur; 953fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 961da177e4SLinus Torvalds break; 971da177e4SLinus Torvalds case CPUFREQ_GOV_STOP: 982d06d8c4SDominik Brodowski pr_debug("managing cpu %u stopped\n", cpu); 99d1922f02SViresh Kumar 100d1922f02SViresh Kumar mutex_lock(&userspace_mutex); 101d1922f02SViresh Kumar per_cpu(cpu_is_managed, cpu) = 0; 102*e43e94c1SSai Gurrappadi *setspeed = 0; 1033fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 1041da177e4SLinus Torvalds break; 1051da177e4SLinus Torvalds case CPUFREQ_GOV_LIMITS: 1063fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 107*e43e94c1SSai Gurrappadi pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", 108*e43e94c1SSai Gurrappadi cpu, policy->min, policy->max, policy->cur, *setspeed); 109d1922f02SViresh Kumar 110*e43e94c1SSai Gurrappadi if (policy->max < *setspeed) 111c0672860SThomas Renninger __cpufreq_driver_target(policy, policy->max, 1121da177e4SLinus Torvalds CPUFREQ_RELATION_H); 113*e43e94c1SSai Gurrappadi else if (policy->min > *setspeed) 114c0672860SThomas Renninger __cpufreq_driver_target(policy, policy->min, 1151da177e4SLinus Torvalds CPUFREQ_RELATION_L); 116*e43e94c1SSai Gurrappadi else 117*e43e94c1SSai Gurrappadi __cpufreq_driver_target(policy, *setspeed, 118*e43e94c1SSai Gurrappadi CPUFREQ_RELATION_L); 1193fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 1201da177e4SLinus Torvalds break; 1211da177e4SLinus Torvalds } 122914f7c31SJeff Garzik return rc; 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 125de1df26bSRafael J. Wysocki static struct cpufreq_governor cpufreq_gov_userspace = { 1261da177e4SLinus Torvalds .name = "userspace", 1271da177e4SLinus Torvalds .governor = cpufreq_governor_userspace, 1289e76988eSVenki Pallipadi .store_setspeed = cpufreq_set, 1299e76988eSVenki Pallipadi .show_setspeed = show_speed, 1301da177e4SLinus Torvalds .owner = THIS_MODULE, 1311da177e4SLinus Torvalds }; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static int __init cpufreq_gov_userspace_init(void) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds return cpufreq_register_governor(&cpufreq_gov_userspace); 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds static void __exit cpufreq_gov_userspace_exit(void) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds cpufreq_unregister_governor(&cpufreq_gov_userspace); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431bceb8d1SDave Jones MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 1441bceb8d1SDave Jones "Russell King <rmk@arm.linux.org.uk>"); 1451da177e4SLinus Torvalds MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 1461da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1471da177e4SLinus Torvalds 1486915719bSJohannes Weiner #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 149de1df26bSRafael J. Wysocki struct cpufreq_governor *cpufreq_default_governor(void) 150de1df26bSRafael J. Wysocki { 151de1df26bSRafael J. Wysocki return &cpufreq_gov_userspace; 152de1df26bSRafael J. Wysocki } 153de1df26bSRafael J. Wysocki 1541da177e4SLinus Torvalds fs_initcall(cpufreq_gov_userspace_init); 1556915719bSJohannes Weiner #else 1566915719bSJohannes Weiner module_init(cpufreq_gov_userspace_init); 1576915719bSJohannes Weiner #endif 1581da177e4SLinus Torvalds module_exit(cpufreq_gov_userspace_exit); 159