Revert "ARM: tegra: tegratab: dummy change"
[linux-2.6.git] / drivers / edp / edp_debug.c
1 /*
2  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope 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
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/edp.h>
20 #include <linux/debugfs.h>
21 #include "edp_internal.h"
22
23 struct dentry *edp_debugfs_dir;
24
25 /*
26  * Reducing the cap is tricky - we might require throttling of other
27  * clients (therefore, involving the governor). So we will fool the
28  * framework by using a dummy client that has a single E-state (E0)
29  * equalling the reduction.
30  */
31 static int reduce_cap(struct edp_manager *m, unsigned int new_max)
32 {
33         int r = 0;
34         unsigned int delta = m->max - new_max;
35         unsigned int remain;
36         struct edp_client c = {
37                 .name = ".",
38                 .states = &delta,
39                 .num_states = 1,
40                 .e0_index = 0,
41                 .max_borrowers = 0,
42                 .priority = EDP_MIN_PRIO
43         };
44
45         r = register_client(m, &c);
46         if (r)
47                 return r;
48
49         r = edp_update_client_request_unlocked(&c, 0, NULL);
50         if (r)
51                 return r;
52
53         remain = m->remaining;
54         r = unregister_client(&c);
55         if (r)
56                 return r;
57
58         m->remaining = remain;
59         m->max = new_max;
60         return 0;
61 }
62
63 static int __manager_cap_set(struct edp_manager *m, unsigned int new_max)
64 {
65         if (new_max >= m->max) {
66                 m->remaining += new_max - m->max;
67                 m->max = new_max;
68                 schedule_promotion(m);
69                 return 0;
70         }
71
72         return reduce_cap(m, new_max);
73 }
74
75 static int manager_status_show(struct seq_file *file, void *data)
76 {
77         struct edp_manager *m;
78         struct edp_client *c;
79
80         if (!file->private)
81                 return -ENODEV;
82
83         m = file->private;
84
85         mutex_lock(&edp_lock);
86
87         seq_printf(file, "cap      : %u\n", m->max);
88         seq_printf(file, "sum(E0)  : %u\n", e0_current_sum(m));
89         seq_printf(file, "remaining: %u\n", m->remaining);
90
91         seq_printf(file, "------------------------------------------\n");
92         seq_printf(file, "%-16s %3s %5s %7s %7s\n",
93                         "client", "pri", "E0", "request", "current");
94         seq_printf(file, "------------------------------------------\n");
95
96         list_for_each_entry(c, &m->clients, link)
97                 seq_printf(file, "%-16s %3d %5u %7u %7u\n", c->name,
98                                 c->priority, e0_level(c), req_level(c),
99                                 cur_level(c));
100
101         mutex_unlock(&edp_lock);
102         return 0;
103 }
104
105 static int manager_status_open(struct inode *inode, struct file *file)
106 {
107         return single_open(file, manager_status_show, inode->i_private);
108 }
109
110 static const struct file_operations manager_status_fops = {
111         .open = manager_status_open,
112         .read = seq_read,
113 };
114
115 static int manager_cap_set(void *data, u64 val)
116 {
117         struct edp_manager *m = data;
118         int r;
119
120         mutex_lock(&edp_lock);
121         r = __manager_cap_set(m, val);
122         mutex_unlock(&edp_lock);
123         return r;
124 }
125
126 static int manager_cap_get(void *data, u64 *val)
127 {
128         struct edp_manager *m = data;
129
130         mutex_lock(&edp_lock);
131         *val = m->max;
132         mutex_unlock(&edp_lock);
133         return 0;
134 }
135
136 DEFINE_SIMPLE_ATTRIBUTE(manager_cap_fops, manager_cap_get,
137                 manager_cap_set, "%lld\n");
138
139 void manager_add_dentry(struct edp_manager *m)
140 {
141         struct dentry *d;
142
143         if (!edp_debugfs_dir)
144                 return;
145
146         d = debugfs_create_dir(m->name, edp_debugfs_dir);
147         if (IS_ERR_OR_NULL(d))
148                 return;
149
150         m->dentry = d;
151
152         d = debugfs_create_file("status", S_IRUGO, m->dentry, m,
153                         &manager_status_fops);
154         WARN_ON(IS_ERR_OR_NULL(d));
155
156         d = debugfs_create_file("cap", S_IRUGO | S_IWUSR, m->dentry, m,
157                         &manager_cap_fops);
158         WARN_ON(IS_ERR_OR_NULL(d));
159 }
160
161 void manager_remove_dentry(struct edp_manager *m)
162 {
163         debugfs_remove_recursive(m->dentry);
164         m->dentry = NULL;
165 }
166
167 static int __client_current_set(struct edp_client *c, unsigned int new)
168 {
169         struct edp_manager *m;
170         unsigned int nl;
171         unsigned int cl;
172
173         if (new >= c->num_states)
174                 return -EINVAL;
175
176         nl = c->states[new];
177         cl = cur_level(c);
178         m = c->manager;
179
180         if (nl > cl && nl - cl > m->remaining)
181                 return -EBUSY;
182
183         c->cur = c->states + new;
184         c->req = c->states + new;
185
186         if (nl < cl) {
187                 m->remaining += cl - nl;
188                 if (c->throttle)
189                         c->throttle(new, c->private_data);
190                 schedule_promotion(m);
191         } else if (nl > cl) {
192                 m->remaining -= nl - cl;
193                 if (c->notify_promotion)
194                         c->notify_promotion(new, c->private_data);
195         }
196
197         return 0;
198 }
199
200 static int client_current_set(void *data, u64 val)
201 {
202         struct edp_client *c = data;
203         int r;
204
205         mutex_lock(&edp_lock);
206         r = __client_current_set(c, val);
207         mutex_unlock(&edp_lock);
208         return r;
209 }
210
211 static int client_current_get(void *data, u64 *val)
212 {
213         struct edp_client *c = data;
214
215         mutex_lock(&edp_lock);
216         *val = cur_level(c);
217         mutex_unlock(&edp_lock);
218         return 0;
219 }
220
221 DEFINE_SIMPLE_ATTRIBUTE(client_current_fops, client_current_get,
222                 client_current_set, "%lld\n");
223
224 void client_add_dentry(struct edp_client *c)
225 {
226         struct dentry *d;
227
228         if (!c->manager->dentry)
229                 return;
230
231         d = debugfs_create_dir(c->name, c->manager->dentry);
232         if (IS_ERR_OR_NULL(d)) {
233                 WARN_ON(1);
234                 return;
235         }
236
237         c->dentry = d;
238
239         d = debugfs_create_file("current", S_IRUGO | S_IWUSR, c->dentry,
240                         c, &client_current_fops);
241         WARN_ON(IS_ERR_OR_NULL(d));
242 }
243
244 void client_remove_dentry(struct edp_client *c)
245 {
246         debugfs_remove_recursive(c->dentry);
247         c->dentry = NULL;
248 }
249
250 static void dbg_update_request(struct edp_client *c, const unsigned int *r) {}
251 static void dbg_update_loans(struct edp_client *c) {}
252 static void dbg_promote(struct edp_manager *mgr) {}
253
254 static struct edp_governor dbg_governor = {
255         .name = "debug",
256         .owner = THIS_MODULE,
257         .update_request = dbg_update_request,
258         .update_loans = dbg_update_loans,
259         .promote = dbg_promote
260 };
261
262 static int __init debug_init(void)
263 {
264         struct dentry *d;
265
266         d = debugfs_create_dir("edp", NULL);
267         if (IS_ERR_OR_NULL(d)) {
268                 WARN_ON(1);
269                 return -EFAULT;
270         }
271
272         edp_debugfs_dir = d;
273         return edp_register_governor(&dbg_governor);
274 }
275 postcore_initcall(debug_init);