ARM: tegra: cpuquiet: make userspace governor actions synchronous
[firefly-linux-kernel-4.4.55.git] / drivers / cpuquiet / driver.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 #include <linux/cpu.h>
23 #include <linux/jiffies.h>
24 #include <linux/slab.h>
25 #include <asm/cputime.h>
26
27 #include "cpuquiet.h"
28
29 static struct cpuquiet_driver *cpuquiet_curr_driver;
30
31 #ifdef CONFIG_CPUQUIET_STATS
32 struct cpuquiet_cpu_stat {
33         cputime64_t time_up_total;
34         u64 last_update;
35         unsigned int up_down_count;
36         struct kobject cpu_kobject;
37 };
38
39 struct cpuquiet_cpu_stat *stats;
40
41 struct cpu_attribute {
42         struct attribute attr;
43         enum { up_down_count, time_up_total } type;
44 };
45
46 #define CPU_ATTRIBUTE(_name) \
47         static struct cpu_attribute _name ## _attr = {                  \
48                 .attr =  {.name = __stringify(_name), .mode = 0444 },   \
49                 .type   = _name,                                        \
50 }
51
52 CPU_ATTRIBUTE(up_down_count);
53 CPU_ATTRIBUTE(time_up_total);
54
55 static struct attribute *cpu_attributes[] = {
56         &up_down_count_attr.attr,
57         &time_up_total_attr.attr,
58         NULL,
59 };
60
61 static void stats_update(struct cpuquiet_cpu_stat *stat, bool up)
62 {
63         u64 cur_jiffies = get_jiffies_64();
64         bool was_up = stat->up_down_count & 0x1;
65
66         if (was_up)
67                 stat->time_up_total += cur_jiffies - stat->last_update;
68
69         if (was_up != up)
70                 stat->up_down_count++;
71
72         stat->last_update = cur_jiffies;
73 }
74
75 static ssize_t stats_sysfs_show(struct kobject *kobj,
76                         struct attribute *attr, char *buf)
77 {
78         struct cpu_attribute *cattr =
79                 container_of(attr, struct cpu_attribute, attr);
80         struct cpuquiet_cpu_stat *stat  =
81                 container_of(kobj, struct cpuquiet_cpu_stat, cpu_kobject);
82         ssize_t len = 0;
83         bool was_up = stat->up_down_count & 0x1;
84
85         stats_update(stat, was_up);
86
87         switch (cattr->type) {
88         case up_down_count:
89                 len = sprintf(buf, "%u\n", stat->up_down_count);
90                 break;
91         case time_up_total:
92                 len =  sprintf(buf, "%llu\n", stat->time_up_total);
93                 break;
94         }
95
96         return len;
97 }
98
99 static const struct sysfs_ops stats_sysfs_ops = {
100         .show = stats_sysfs_show,
101 };
102
103 static struct kobj_type ktype_cpu_stats = {
104         .sysfs_ops = &stats_sysfs_ops,
105         .default_attrs = cpu_attributes,
106 };
107 #endif
108
109 int cpuquiet_quiesence_cpu(unsigned int cpunumber, bool sync)
110 {
111         int err = -EPERM;
112
113         if (cpuquiet_curr_driver && cpuquiet_curr_driver->quiesence_cpu)
114                 err = cpuquiet_curr_driver->quiesence_cpu(cpunumber, sync);
115
116 #ifdef CONFIG_CPUQUIET_STATS
117         if (!err)
118                 stats_update(stats + cpunumber, 0);
119 #endif
120
121         return err;
122 }
123 EXPORT_SYMBOL(cpuquiet_quiesence_cpu);
124
125 int cpuquiet_wake_cpu(unsigned int cpunumber, bool sync)
126 {
127         int err = -EPERM;
128
129         if (cpuquiet_curr_driver && cpuquiet_curr_driver->wake_cpu)
130                 err = cpuquiet_curr_driver->wake_cpu(cpunumber, sync);
131
132 #ifdef CONFIG_CPUQUIET_STATS
133         if (!err)
134                 stats_update(stats + cpunumber, 1);
135 #endif
136
137         return err;
138 }
139 EXPORT_SYMBOL(cpuquiet_wake_cpu);
140
141 int cpuquiet_register_driver(struct cpuquiet_driver *drv)
142 {
143         int err = -EBUSY;
144         unsigned int cpu;
145         struct device *dev;
146
147         if (!drv)
148                 return -EINVAL;
149
150 #ifdef CONFIG_CPUQUIET_STATS
151         stats = kzalloc(nr_cpu_ids * sizeof(*stats), GFP_KERNEL);
152         if (!stats)
153                 return -ENOMEM;
154 #endif
155
156         for_each_possible_cpu(cpu) {
157 #ifdef CONFIG_CPUQUIET_STATS
158                 u64 cur_jiffies = get_jiffies_64();
159                 stats[cpu].last_update = cur_jiffies;
160                 if (cpu_online(cpu))
161                         stats[cpu].up_down_count = 1;
162 #endif
163                 dev = get_cpu_device(cpu);
164                 if (dev) {
165                         cpuquiet_add_dev(dev, cpu);
166 #ifdef CONFIG_CPUQUIET_STATS
167                         cpuquiet_cpu_kobject_init(&stats[cpu].cpu_kobject,
168                                         &ktype_cpu_stats, "stats", cpu);
169 #endif
170                 }
171         }
172
173         mutex_lock(&cpuquiet_lock);
174         if (!cpuquiet_curr_driver) {
175                 err = 0;
176                 cpuquiet_curr_driver = drv;
177                 cpuquiet_switch_governor(cpuquiet_get_first_governor());
178         }
179         mutex_unlock(&cpuquiet_lock);
180
181         return err;
182 }
183 EXPORT_SYMBOL(cpuquiet_register_driver);
184
185 struct cpuquiet_driver *cpuquiet_get_driver(void)
186 {
187         return cpuquiet_curr_driver;
188 }
189
190 void cpuquiet_unregister_driver(struct cpuquiet_driver *drv)
191 {
192         unsigned int cpu;
193
194         if (drv != cpuquiet_curr_driver) {
195                 WARN(1, "invalid cpuquiet_unregister_driver(%s)\n",
196                         drv->name);
197                 return;
198         }
199
200         /* stop current governor first */
201         cpuquiet_switch_governor(NULL);
202
203         mutex_lock(&cpuquiet_lock);
204         cpuquiet_curr_driver = NULL;
205
206         for_each_possible_cpu(cpu) {
207 #ifdef CONFIG_CPUQUIET_STATS
208                 kobject_put(&stats[cpu].cpu_kobject);
209 #endif
210                 cpuquiet_remove_dev(cpu);
211         }
212
213         mutex_unlock(&cpuquiet_lock);
214 }
215 EXPORT_SYMBOL(cpuquiet_unregister_driver);