Skip to content

Commit 285189c

Browse files
Liao Changrafaeljw
authored andcommitted
cpufreq: userspace: Use fine-grained mutex in userspace governor
The userspace governor currently uses a big global mutex to avoid the race condition on the governor_data field of cpufreq_policy structure. This leads to a low concurrency if multiple userspace applications are trying to set the speed of different policies at the same time. Introduce a per-policy mutex to allow the updating of different policies to be performed concurrently, improving overall concurrency. Signed-off-by: Liao Chang <[email protected]> Acked-by: Viresh Kumar <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 842c34a commit 285189c

File tree

1 file changed

+40
-29
lines changed

1 file changed

+40
-29
lines changed

drivers/cpufreq/cpufreq_userspace.c

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
#include <linux/slab.h>
1717

1818
static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
19-
static DEFINE_MUTEX(userspace_mutex);
19+
20+
struct userspace_policy {
21+
unsigned int setspeed;
22+
struct mutex mutex;
23+
};
2024

2125
/**
2226
* cpufreq_set - set the CPU frequency
@@ -28,19 +32,19 @@ static DEFINE_MUTEX(userspace_mutex);
2832
static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
2933
{
3034
int ret = -EINVAL;
31-
unsigned int *setspeed = policy->governor_data;
35+
struct userspace_policy *userspace = policy->governor_data;
3236

3337
pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
3438

35-
mutex_lock(&userspace_mutex);
39+
mutex_lock(&userspace->mutex);
3640
if (!per_cpu(cpu_is_managed, policy->cpu))
3741
goto err;
3842

39-
*setspeed = freq;
43+
userspace->setspeed = freq;
4044

4145
ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
4246
err:
43-
mutex_unlock(&userspace_mutex);
47+
mutex_unlock(&userspace->mutex);
4448
return ret;
4549
}
4650

@@ -51,67 +55,74 @@ static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
5155

5256
static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy)
5357
{
54-
unsigned int *setspeed;
58+
struct userspace_policy *userspace;
5559

56-
setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL);
57-
if (!setspeed)
60+
userspace = kzalloc(sizeof(*userspace), GFP_KERNEL);
61+
if (!userspace)
5862
return -ENOMEM;
5963

60-
policy->governor_data = setspeed;
64+
mutex_init(&userspace->mutex);
65+
66+
policy->governor_data = userspace;
6167
return 0;
6268
}
6369

70+
/*
71+
* Any routine that writes to the policy struct will hold the "rwsem" of
72+
* policy struct that means it is free to free "governor_data" here.
73+
*/
6474
static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy)
6575
{
66-
mutex_lock(&userspace_mutex);
6776
kfree(policy->governor_data);
6877
policy->governor_data = NULL;
69-
mutex_unlock(&userspace_mutex);
7078
}
7179

7280
static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy)
7381
{
74-
unsigned int *setspeed = policy->governor_data;
82+
struct userspace_policy *userspace = policy->governor_data;
7583

7684
BUG_ON(!policy->cur);
7785
pr_debug("started managing cpu %u\n", policy->cpu);
7886

79-
mutex_lock(&userspace_mutex);
87+
mutex_lock(&userspace->mutex);
8088
per_cpu(cpu_is_managed, policy->cpu) = 1;
81-
*setspeed = policy->cur;
82-
mutex_unlock(&userspace_mutex);
89+
userspace->setspeed = policy->cur;
90+
mutex_unlock(&userspace->mutex);
8391
return 0;
8492
}
8593

8694
static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy)
8795
{
88-
unsigned int *setspeed = policy->governor_data;
96+
struct userspace_policy *userspace = policy->governor_data;
8997

9098
pr_debug("managing cpu %u stopped\n", policy->cpu);
9199

92-
mutex_lock(&userspace_mutex);
100+
mutex_lock(&userspace->mutex);
93101
per_cpu(cpu_is_managed, policy->cpu) = 0;
94-
*setspeed = 0;
95-
mutex_unlock(&userspace_mutex);
102+
userspace->setspeed = 0;
103+
mutex_unlock(&userspace->mutex);
96104
}
97105

98106
static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy)
99107
{
100-
unsigned int *setspeed = policy->governor_data;
108+
struct userspace_policy *userspace = policy->governor_data;
101109

102-
mutex_lock(&userspace_mutex);
110+
mutex_lock(&userspace->mutex);
103111

104112
pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n",
105-
policy->cpu, policy->min, policy->max, policy->cur, *setspeed);
106-
107-
if (policy->max < *setspeed)
108-
__cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
109-
else if (policy->min > *setspeed)
110-
__cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
113+
policy->cpu, policy->min, policy->max, policy->cur, userspace->setspeed);
114+
115+
if (policy->max < userspace->setspeed)
116+
__cpufreq_driver_target(policy, policy->max,
117+
CPUFREQ_RELATION_H);
118+
else if (policy->min > userspace->setspeed)
119+
__cpufreq_driver_target(policy, policy->min,
120+
CPUFREQ_RELATION_L);
111121
else
112-
__cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L);
122+
__cpufreq_driver_target(policy, userspace->setspeed,
123+
CPUFREQ_RELATION_L);
113124

114-
mutex_unlock(&userspace_mutex);
125+
mutex_unlock(&userspace->mutex);
115126
}
116127

117128
static struct cpufreq_governor cpufreq_gov_userspace = {

0 commit comments

Comments
 (0)