xref: /openbmc/linux/drivers/cpufreq/cpufreq_userspace.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
1d2912cb1SThomas 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  */
cpufreq_set(struct cpufreq_policy * policy,unsigned int freq)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 
show_speed(struct cpufreq_policy * policy,char * buf)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 
cpufreq_userspace_policy_init(struct cpufreq_policy * policy)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 
cpufreq_userspace_policy_exit(struct cpufreq_policy * policy)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 
cpufreq_userspace_policy_start(struct cpufreq_policy * policy)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 
cpufreq_userspace_policy_stop(struct cpufreq_policy * policy)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 
cpufreq_userspace_policy_limits(struct cpufreq_policy * policy)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 
1291bceb8d1SDave Jones MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "
1301bceb8d1SDave Jones 		"Russell King <rmk@arm.linux.org.uk>");
1311da177e4SLinus Torvalds MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
1321da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1331da177e4SLinus Torvalds 
1346915719bSJohannes Weiner #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
cpufreq_default_governor(void)135de1df26bSRafael J. Wysocki struct cpufreq_governor *cpufreq_default_governor(void)
136de1df26bSRafael J. Wysocki {
137de1df26bSRafael J. Wysocki 	return &cpufreq_gov_userspace;
138de1df26bSRafael J. Wysocki }
1396915719bSJohannes Weiner #endif
140*10dd8573SQuentin Perret 
141*10dd8573SQuentin Perret cpufreq_governor_init(cpufreq_gov_userspace);
142*10dd8573SQuentin Perret cpufreq_governor_exit(cpufreq_gov_userspace);
143