Revert "ARM: tegra: tegratab: dummy change"
[linux-2.6.git] / drivers / edp / edp_temporal.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 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/slab.h>
21 #include "edp_internal.h"
22
23 /*
24  * This file implements the (1) LRR: least recently requested (2) MRR:
25  * most recently requested and (3) RR: round robin governors.
26  *
27  * Since they are all based on some timestamps, we use a simple list
28  * (the 'temporal list') for ordering the clients according to the main
29  * selection criteria. This list is maintained in such a way that
30  * throttle-victims appear at the tail and promotions are done from the
31  * head.
32  */
33
34 static void throttle(struct edp_client *client);
35
36 /*  Temporal list is manager specific */
37 static int temporal_start(struct edp_manager *m)
38 {
39         struct list_head *head;
40         struct edp_client *c;
41
42         head = kzalloc(sizeof(*head), GFP_KERNEL);
43         if (!head)
44                 return -ENOMEM;
45
46         INIT_LIST_HEAD(head);
47         m->gov_data = head;
48
49         list_for_each_entry(c, &m->clients, link) {
50                 if (req_index(c) < c->e0_index)
51                         list_add(&c->glnk, head);
52         }
53
54         return 0;
55 }
56
57 static void temporal_stop(struct edp_manager *m)
58 {
59         kfree(m->gov_data);
60         m->gov_data = NULL;
61 }
62
63 /*
64  * We need to remember only those clients that can either be throttled
65  * or promoted - this way, we have a smaller list.
66  */
67 static void lrr_update_request(struct edp_client *client,
68                 const unsigned int *req)
69 {
70         struct list_head *head;
71
72         if (req_index(client) < client->e0_index)
73                 list_del(&client->glnk);
74
75         edp_default_update_request(client, req, throttle);
76
77         if (req_index(client) < client->e0_index) {
78                 head = client->manager->gov_data;
79                 list_add(&client->glnk, head);
80         }
81 }
82
83 /*
84  * We need to remember only those clients that can either be throttled
85  * or promoted - this way, we have a smaller list.
86  */
87 static void mrr_update_request(struct edp_client *client,
88                 const unsigned int *req)
89 {
90         struct list_head *head;
91
92         if (req_index(client) < client->e0_index)
93                 list_del(&client->glnk);
94
95         edp_default_update_request(client, req, throttle);
96
97         if (req_index(client) < client->e0_index) {
98                 head = client->manager->gov_data;
99                 list_add_tail(&client->glnk, head);
100         }
101 }
102
103 static void rr_update_request(struct edp_client *client,
104                 const unsigned int *req)
105 {
106         struct list_head *head;
107
108         /* new entry */
109         if (!client->req) {
110                 head = client->manager->gov_data;
111                 list_add(&client->glnk, head);
112         }
113
114         edp_default_update_request(client, req, throttle);
115 }
116
117 static void temporal_promote(struct edp_manager *m)
118 {
119         struct list_head *head = m->gov_data;
120         struct edp_client *c;
121         unsigned int i;
122
123         list_for_each_entry(c, head, glnk) {
124                 if (req_level(c) <= cur_level(c) || !c->notify_promotion)
125                         continue;
126
127                 i = edp_promotion_point(c, m->remaining);
128                 if (i == cur_index(c))
129                         continue;
130
131                 m->remaining -= c->states[i] - cur_level(c);
132                 c->cur = c->states + i;
133                 if (c->cur == c->req)
134                         m->num_denied--;
135
136                 c->notify_promotion(i, c->private_data);
137                 if (!m->remaining || !m->num_denied)
138                         return;
139         }
140 }
141
142 #define DEFINE_TEMPORAL_GOV(_gov, _name, _func) \
143         struct edp_governor _gov = {    \
144                 .name = _name,  \
145                 .owner = THIS_MODULE,   \
146                 .start = temporal_start,        \
147                 .stop = temporal_stop,  \
148                 .update_request = _func,        \
149                 .update_loans = edp_default_update_loans,       \
150                 .promote = temporal_promote     \
151         };
152
153 static DEFINE_TEMPORAL_GOV(lrr_governor, "least_recent", lrr_update_request);
154 static DEFINE_TEMPORAL_GOV(mrr_governor, "most_recent", mrr_update_request);
155 static DEFINE_TEMPORAL_GOV(rr_governor, "round_robin", rr_update_request);
156
157 static void throttle(struct edp_client *client)
158 {
159         struct edp_manager *m = client->manager;
160         unsigned int required = req_level(client) - cur_level(client);
161         struct list_head *head = m->gov_data;
162         struct edp_client *n;
163         struct edp_client *c;
164         unsigned int bal;
165
166         bal = m->remaining;
167         n = NULL;
168
169         list_for_each_entry_reverse(c, head, glnk) {
170                 if (cur_level(c) > e0_level(c) && c != client) {
171                         c->gwt = edp_throttling_point(c, required - bal);
172                         bal += cur_level(c) - c->states[c->gwt];
173                         n = c;
174                         if (bal >= required)
175                                 break;
176                 }
177         }
178
179         c = n;
180         bal = m->remaining;
181         if (!c)
182                 goto finish;
183
184         /* use the safe version as we might be re-arraging the list */
185         list_for_each_entry_safe_from(c, n, head, glnk) {
186                 if (cur_level(c) <= e0_level(c) || c == client ||
187                                 c->gwt == cur_index(c))
188                         continue;
189
190                 c->throttle(c->gwt, c->private_data);
191                 bal += cur_level(c) - c->states[c->gwt];
192                 if (c->cur == c->req)
193                         m->num_denied++;
194                 c->cur = c->states + c->gwt;
195
196                 /* for RR, move this client to the head */
197                 if (m->gov == &rr_governor)
198                         list_move(&c->glnk, head);
199                 if (bal >= required)
200                         break;
201         }
202
203 finish:
204         m->remaining = bal + cur_level(client);
205         client->cur = client->states + edp_promotion_point(client, bal);
206         m->remaining -= cur_level(client);
207 }
208
209 static int __init temporal_init(void)
210 {
211         int ret = 0;
212         int r;
213
214         r = edp_register_governor(&lrr_governor);
215         if (r) {
216                 pr_err("least_recent governor registration failed: %d\n", r);
217                 ret = r;
218         }
219
220         r = edp_register_governor(&mrr_governor);
221         if (r) {
222                 pr_err("most_recent governor registration failed: %d\n", r);
223                 ret = r;
224         }
225
226         r = edp_register_governor(&rr_governor);
227         if (r) {
228                 pr_err("round_robin governor registration failed: %d\n", r);
229                 ret = r;
230         }
231
232         return ret;
233 }
234 postcore_initcall(temporal_init);