2 * Copyright (c) 2012-2013 NVIDIA CORPORATION. All rights reserved.
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.
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
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.
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>
29 static struct cpuquiet_driver *cpuquiet_curr_driver;
31 #ifdef CONFIG_CPUQUIET_STATS
32 struct cpuquiet_cpu_stat {
33 cputime64_t time_up_total;
35 unsigned int up_down_count;
36 struct kobject cpu_kobject;
39 struct cpuquiet_cpu_stat *stats;
41 struct cpu_attribute {
42 struct attribute attr;
43 enum { up_down_count, time_up_total } type;
46 #define CPU_ATTRIBUTE(_name) \
47 static struct cpu_attribute _name ## _attr = { \
48 .attr = {.name = __stringify(_name), .mode = 0444 }, \
52 CPU_ATTRIBUTE(up_down_count);
53 CPU_ATTRIBUTE(time_up_total);
55 static struct attribute *cpu_attributes[] = {
56 &up_down_count_attr.attr,
57 &time_up_total_attr.attr,
61 static void stats_update(struct cpuquiet_cpu_stat *stat, bool up)
63 u64 cur_jiffies = get_jiffies_64();
64 bool was_up = stat->up_down_count & 0x1;
67 stat->time_up_total += cur_jiffies - stat->last_update;
70 stat->up_down_count++;
72 stat->last_update = cur_jiffies;
75 static ssize_t stats_sysfs_show(struct kobject *kobj,
76 struct attribute *attr, char *buf)
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);
83 bool was_up = stat->up_down_count & 0x1;
85 stats_update(stat, was_up);
87 switch (cattr->type) {
89 len = sprintf(buf, "%u\n", stat->up_down_count);
92 len = sprintf(buf, "%llu\n", stat->time_up_total);
99 static const struct sysfs_ops stats_sysfs_ops = {
100 .show = stats_sysfs_show,
103 static struct kobj_type ktype_cpu_stats = {
104 .sysfs_ops = &stats_sysfs_ops,
105 .default_attrs = cpu_attributes,
109 int cpuquiet_quiesence_cpu(unsigned int cpunumber, bool sync)
113 if (cpuquiet_curr_driver && cpuquiet_curr_driver->quiesence_cpu)
114 err = cpuquiet_curr_driver->quiesence_cpu(cpunumber, sync);
116 #ifdef CONFIG_CPUQUIET_STATS
118 stats_update(stats + cpunumber, 0);
123 EXPORT_SYMBOL(cpuquiet_quiesence_cpu);
125 int cpuquiet_wake_cpu(unsigned int cpunumber, bool sync)
129 if (cpuquiet_curr_driver && cpuquiet_curr_driver->wake_cpu)
130 err = cpuquiet_curr_driver->wake_cpu(cpunumber, sync);
132 #ifdef CONFIG_CPUQUIET_STATS
134 stats_update(stats + cpunumber, 1);
139 EXPORT_SYMBOL(cpuquiet_wake_cpu);
141 int cpuquiet_register_driver(struct cpuquiet_driver *drv)
150 #ifdef CONFIG_CPUQUIET_STATS
151 stats = kzalloc(nr_cpu_ids * sizeof(*stats), GFP_KERNEL);
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;
161 stats[cpu].up_down_count = 1;
163 dev = get_cpu_device(cpu);
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);
173 mutex_lock(&cpuquiet_lock);
174 if (!cpuquiet_curr_driver) {
176 cpuquiet_curr_driver = drv;
177 cpuquiet_switch_governor(cpuquiet_get_first_governor());
179 mutex_unlock(&cpuquiet_lock);
183 EXPORT_SYMBOL(cpuquiet_register_driver);
185 struct cpuquiet_driver *cpuquiet_get_driver(void)
187 return cpuquiet_curr_driver;
190 void cpuquiet_unregister_driver(struct cpuquiet_driver *drv)
194 if (drv != cpuquiet_curr_driver) {
195 WARN(1, "invalid cpuquiet_unregister_driver(%s)\n",
200 mutex_lock(&cpuquiet_lock);
202 /* Stop current governor first */
203 cpuquiet_switch_governor(NULL);
204 cpuquiet_curr_driver = NULL;
206 for_each_possible_cpu(cpu) {
207 #ifdef CONFIG_CPUQUIET_STATS
208 kobject_put(&stats[cpu].cpu_kobject);
210 cpuquiet_remove_dev(cpu);
213 mutex_unlock(&cpuquiet_lock);
215 EXPORT_SYMBOL(cpuquiet_unregister_driver);