cpuquiet: governor support
[firefly-linux-kernel-4.4.55.git] / drivers / cpuquiet / governor.c
1 /*
2  * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16  *
17  */
18
19 #include <linux/mutex.h>
20 #include <linux/module.h>
21 #include <linux/cpuquiet.h>
22
23 #include "cpuquiet.h"
24
25 LIST_HEAD(cpuquiet_governors);
26 struct cpuquiet_governor *cpuquiet_curr_governor;
27
28 struct cpuquiet_governor *cpuquiet_get_first_governor(void)
29 {
30         if (!list_empty(&cpuquiet_governors))
31                 return list_entry(&cpuquiet_governors, struct cpuquiet_governor,
32                                         governor_list);
33         else
34                 return NULL;
35 }
36
37 struct cpuquiet_governor *cpuquiet_find_governor(const char *str)
38 {
39         struct cpuquiet_governor *gov;
40
41         list_for_each_entry(gov, &cpuquiet_governors, governor_list)
42                 if (!strnicmp(str, gov->name, CPUQUIET_NAME_LEN))
43                         return gov;
44
45         return NULL;
46 }
47
48 int cpuquiet_switch_governor(struct cpuquiet_governor *gov)
49 {
50         int err = 0;
51
52         if (cpuquiet_curr_governor) {
53                 if (cpuquiet_curr_governor->stop)
54                         cpuquiet_curr_governor->stop();
55                 module_put(cpuquiet_curr_governor->owner);
56         }
57
58         cpuquiet_curr_governor = gov;
59
60         if (gov) {
61                 if (!try_module_get(cpuquiet_curr_governor->owner))
62                         return -EINVAL;
63                 if (gov->start)
64                         err = gov->start();
65                 if (!err)
66                         cpuquiet_curr_governor = gov;
67         }
68
69         return err;
70 }
71
72 int cpuquiet_register_governor(struct cpuquiet_governor *gov)
73 {
74         int ret = -EEXIST;
75
76         if (!gov)
77                 return -EINVAL;
78
79         mutex_lock(&cpuquiet_lock);
80         if (cpuquiet_find_governor(gov->name) == NULL) {
81                 ret = 0;
82                 list_add_tail(&gov->governor_list, &cpuquiet_governors);
83                 if (!cpuquiet_curr_governor && cpuquiet_get_driver())
84                         cpuquiet_switch_governor(gov);
85         }
86         mutex_unlock(&cpuquiet_lock);
87
88         return ret;
89 }
90
91 void cpuquiet_unregister_governor(struct cpuquiet_governor *gov)
92 {
93         if (!gov)
94                 return;
95
96         mutex_lock(&cpuquiet_lock);
97         if (cpuquiet_curr_governor == gov)
98                 cpuquiet_switch_governor(NULL);
99         list_del(&gov->governor_list);
100         mutex_unlock(&cpuquiet_lock);
101 }