1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c0672860SThomas Renninger 31da177e4SLinus Torvalds /* 41da177e4SLinus Torvalds * linux/drivers/cpufreq/cpufreq_userspace.c 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 2001 Russell King 71da177e4SLinus Torvalds * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 10db701151SViresh Kumar #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11db701151SViresh Kumar 121da177e4SLinus Torvalds #include <linux/cpufreq.h> 13d1922f02SViresh Kumar #include <linux/init.h> 14d1922f02SViresh Kumar #include <linux/module.h> 153fc54d37Sakpm@osdl.org #include <linux/mutex.h> 16e43e94c1SSai Gurrappadi #include <linux/slab.h> 171da177e4SLinus Torvalds 18b38868aaSMike Travis static DEFINE_PER_CPU(unsigned int, cpu_is_managed); 193fc54d37Sakpm@osdl.org static DEFINE_MUTEX(userspace_mutex); 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds /** 221da177e4SLinus Torvalds * cpufreq_set - set the CPU frequency 239e76988eSVenki Pallipadi * @policy: pointer to policy struct where freq is being set 241da177e4SLinus Torvalds * @freq: target frequency in kHz 251da177e4SLinus Torvalds * 261da177e4SLinus Torvalds * Sets the CPU frequency to freq. 271da177e4SLinus Torvalds */ 289e76988eSVenki Pallipadi static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) 291da177e4SLinus Torvalds { 301da177e4SLinus Torvalds int ret = -EINVAL; 31e43e94c1SSai Gurrappadi unsigned int *setspeed = policy->governor_data; 321da177e4SLinus Torvalds 332d06d8c4SDominik Brodowski pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 341da177e4SLinus Torvalds 353fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 36b38868aaSMike Travis if (!per_cpu(cpu_is_managed, policy->cpu)) 371da177e4SLinus Torvalds goto err; 381da177e4SLinus Torvalds 39e43e94c1SSai Gurrappadi *setspeed = freq; 40e43e94c1SSai Gurrappadi 41c0672860SThomas Renninger ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 421da177e4SLinus Torvalds err: 433fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 441da177e4SLinus Torvalds return ret; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) 481da177e4SLinus Torvalds { 49d1922f02SViresh Kumar return sprintf(buf, "%u\n", policy->cur); 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 52e43e94c1SSai Gurrappadi static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) 53e43e94c1SSai Gurrappadi { 54e43e94c1SSai Gurrappadi unsigned int *setspeed; 55e43e94c1SSai Gurrappadi 56e43e94c1SSai Gurrappadi setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); 57e43e94c1SSai Gurrappadi if (!setspeed) 58e43e94c1SSai Gurrappadi return -ENOMEM; 59e43e94c1SSai Gurrappadi 60e43e94c1SSai Gurrappadi policy->governor_data = setspeed; 61e43e94c1SSai Gurrappadi return 0; 62e43e94c1SSai Gurrappadi } 63e43e94c1SSai Gurrappadi 64e788892bSRafael J. Wysocki static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) 65e788892bSRafael J. Wysocki { 66e788892bSRafael J. Wysocki mutex_lock(&userspace_mutex); 67e788892bSRafael J. Wysocki kfree(policy->governor_data); 68e788892bSRafael J. Wysocki policy->governor_data = NULL; 69e788892bSRafael J. Wysocki mutex_unlock(&userspace_mutex); 70e788892bSRafael J. Wysocki } 71e788892bSRafael J. Wysocki 72e788892bSRafael J. Wysocki static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) 731da177e4SLinus Torvalds { 74e43e94c1SSai Gurrappadi unsigned int *setspeed = policy->governor_data; 75914f7c31SJeff Garzik 761da177e4SLinus Torvalds BUG_ON(!policy->cur); 77e788892bSRafael J. Wysocki pr_debug("started managing cpu %u\n", policy->cpu); 78d1922f02SViresh Kumar 793fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 80e788892bSRafael J. Wysocki per_cpu(cpu_is_managed, policy->cpu) = 1; 81e43e94c1SSai Gurrappadi *setspeed = policy->cur; 823fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 83e788892bSRafael J. Wysocki return 0; 84e788892bSRafael J. Wysocki } 85e788892bSRafael J. Wysocki 86e788892bSRafael J. Wysocki static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) 87e788892bSRafael J. Wysocki { 88e788892bSRafael J. Wysocki unsigned int *setspeed = policy->governor_data; 89e788892bSRafael J. Wysocki 90e788892bSRafael J. Wysocki pr_debug("managing cpu %u stopped\n", policy->cpu); 91d1922f02SViresh Kumar 92d1922f02SViresh Kumar mutex_lock(&userspace_mutex); 93e788892bSRafael J. Wysocki per_cpu(cpu_is_managed, policy->cpu) = 0; 94e43e94c1SSai Gurrappadi *setspeed = 0; 953fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 96e788892bSRafael J. Wysocki } 97e788892bSRafael J. Wysocki 98e788892bSRafael J. Wysocki static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) 99e788892bSRafael J. Wysocki { 100e788892bSRafael J. Wysocki unsigned int *setspeed = policy->governor_data; 101e788892bSRafael J. Wysocki 1023fc54d37Sakpm@osdl.org mutex_lock(&userspace_mutex); 103e788892bSRafael J. Wysocki 104e43e94c1SSai Gurrappadi pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", 105e788892bSRafael J. Wysocki policy->cpu, policy->min, policy->max, policy->cur, *setspeed); 106d1922f02SViresh Kumar 107e43e94c1SSai Gurrappadi if (policy->max < *setspeed) 108e788892bSRafael J. Wysocki __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); 109e43e94c1SSai Gurrappadi else if (policy->min > *setspeed) 110e788892bSRafael J. Wysocki __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); 111e43e94c1SSai Gurrappadi else 112e788892bSRafael J. Wysocki __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L); 113e788892bSRafael J. Wysocki 1143fc54d37Sakpm@osdl.org mutex_unlock(&userspace_mutex); 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 117de1df26bSRafael J. Wysocki static struct cpufreq_governor cpufreq_gov_userspace = { 1181da177e4SLinus Torvalds .name = "userspace", 119e788892bSRafael J. Wysocki .init = cpufreq_userspace_policy_init, 120e788892bSRafael J. Wysocki .exit = cpufreq_userspace_policy_exit, 121e788892bSRafael J. Wysocki .start = cpufreq_userspace_policy_start, 122e788892bSRafael J. Wysocki .stop = cpufreq_userspace_policy_stop, 123e788892bSRafael J. Wysocki .limits = cpufreq_userspace_policy_limits, 1249e76988eSVenki Pallipadi .store_setspeed = cpufreq_set, 1259e76988eSVenki Pallipadi .show_setspeed = show_speed, 1261da177e4SLinus Torvalds .owner = THIS_MODULE, 1271da177e4SLinus Torvalds }; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds static int __init cpufreq_gov_userspace_init(void) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds return cpufreq_register_governor(&cpufreq_gov_userspace); 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds static void __exit cpufreq_gov_userspace_exit(void) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds cpufreq_unregister_governor(&cpufreq_gov_userspace); 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391bceb8d1SDave Jones MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 1401bceb8d1SDave Jones "Russell King <rmk@arm.linux.org.uk>"); 1411da177e4SLinus Torvalds MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 1421da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1431da177e4SLinus Torvalds 1446915719bSJohannes Weiner #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 145de1df26bSRafael J. Wysocki struct cpufreq_governor *cpufreq_default_governor(void) 146de1df26bSRafael J. Wysocki { 147de1df26bSRafael J. Wysocki return &cpufreq_gov_userspace; 148de1df26bSRafael J. Wysocki } 149de1df26bSRafael J. Wysocki 1501da177e4SLinus Torvalds fs_initcall(cpufreq_gov_userspace_init); 1516915719bSJohannes Weiner #else 1526915719bSJohannes Weiner module_init(cpufreq_gov_userspace_init); 1536915719bSJohannes Weiner #endif 1541da177e4SLinus Torvalds module_exit(cpufreq_gov_userspace_exit); 155