Revert "ARM: tegra: tegratab: dummy change"
[linux-2.6.git] / drivers / edp / edp_fair.c
1 /*
2  * Copyright (c) 2012-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 "edp_internal.h"
21
22 static unsigned int approvable_req(struct edp_client *c, unsigned int net)
23 {
24         unsigned int fair_level;
25         unsigned int step;
26         unsigned int cl;
27
28         if (req_index(c) >= c->e0_index)
29                 return req_index(c);
30
31         cl = cur_level(c);
32         fair_level = c->manager->max * e0_level(c) / net;
33         step = max(fair_level, cl + c->manager->remaining) - cl;
34         return edp_promotion_point(c, step);
35 }
36
37 static struct edp_client *throttle_pledge(struct edp_client *client,
38                 unsigned int required, unsigned int net,
39                 unsigned int *pledged)
40 {
41         struct edp_manager *m = client->manager;
42         struct edp_client *c;
43         unsigned int step;
44         unsigned int fair;
45
46         *pledged = m->remaining;
47
48         list_for_each_entry_reverse(c, &m->clients, link) {
49                 fair = c->manager->max * e0_level(c) / net;
50                 if (c == client || cur_level(c) <= fair)
51                         continue;
52
53                 step = min(cur_level(c) - fair, required - *pledged);
54                 c->gwt = edp_throttling_point(c, step);
55                 *pledged += cur_level(c) - c->states[c->gwt];
56                 if (*pledged >= required)
57                         break;
58         }
59
60         WARN_ON(*pledged < required);
61         return c;
62 }
63
64 static void throttle_recover(struct edp_client *client, struct edp_client *tp,
65                 unsigned int required)
66 {
67         struct edp_manager *m = client->manager;
68         unsigned int recovered = m->remaining;
69
70         list_for_each_entry_from(tp, &m->clients, link) {
71                 if (tp == client || cur_level(tp) <= e0_level(tp) ||
72                                 tp->gwt == cur_index(tp))
73                         continue;
74
75                 tp->throttle(tp->gwt, tp->private_data);
76                 recovered += cur_level(tp) - tp->states[tp->gwt];
77                 if (tp->cur == tp->req)
78                         m->num_denied++;
79
80                 tp->cur = tp->states + tp->gwt;
81                 if (recovered >= required)
82                         return;
83         }
84 }
85
86 static void throttle(struct edp_client *client)
87 {
88         struct edp_manager *m = client->manager;
89         struct edp_client *tp;
90         unsigned int ar;
91         unsigned int pledged;
92         unsigned int required;
93         unsigned int net;
94
95         net = e0_current_sum(m);
96         if (!net) {
97                 WARN_ON(1);
98                 return;
99         }
100
101         ar = approvable_req(client, net);
102         required = client->states[ar] - cur_level(client);
103
104         if (required <= m->remaining) {
105                 client->cur = client->states + ar;
106                 m->remaining -= required;
107                 return;
108         }
109
110         tp = throttle_pledge(client, required, net, &pledged);
111
112         /* E-states are discrete - we may get more than we asked for */
113         if (pledged > required && ar != req_index(client)) {
114                 ar = edp_promotion_point(client, pledged);
115                 required = client->states[ar] - cur_level(client);
116         }
117
118         throttle_recover(client, tp, required);
119         client->cur = client->states + ar;
120         m->remaining = pledged - required;
121 }
122
123 static void fair_update_request(struct edp_client *client,
124                 const unsigned int *req)
125 {
126         edp_default_update_request(client, req, throttle);
127 }
128
129 static unsigned int fair_promotion_point(struct edp_client *c,
130                 unsigned int step, unsigned int max)
131 {
132         unsigned int lim = cur_level(c) + step;
133         unsigned int ci = cur_index(c);
134         unsigned int i = req_index(c);
135
136         while (i < ci && c->states[i] > lim)
137                 i++;
138
139         /*
140          * While being throttled, we probably contributed more than our
141          * fare share - so take the ceiling E-state here
142          */
143         if (c->states[i] < lim && i > req_index(c)) {
144                 if (c->states[i - 1] <= cur_level(c) + max)
145                         i--;
146         }
147
148         return i;
149 }
150
151 static unsigned int promotion_pledge(struct edp_manager *m, unsigned int net)
152 {
153         unsigned int budget = m->remaining;
154         unsigned int unpledged = m->remaining;
155         unsigned int denied = m->num_denied;
156         struct edp_client *c;
157         unsigned int step;
158
159         list_for_each_entry(c, &m->clients, link) {
160                 if (req_level(c) <= cur_level(c) || !c->notify_promotion)
161                         continue;
162
163                 step = (e0_level(c) * budget + net - 1) / net;
164                 step = min(step, unpledged);
165
166                 c->gwt = fair_promotion_point(c, step, unpledged);
167                 unpledged -= c->states[c->gwt] - cur_level(c);
168                 if (req_index(c) == c->gwt)
169                         denied--;
170                 if (!unpledged || !denied)
171                         break;
172         }
173
174         return unpledged;
175 }
176
177 static void fair_promote(struct edp_manager *mgr)
178 {
179         unsigned int net = 0;
180         struct edp_client *c;
181         unsigned int step;
182         unsigned int pp;
183         unsigned int unpledged;
184
185         list_for_each_entry(c, &mgr->clients, link) {
186                 if (req_level(c) > cur_level(c) && c->notify_promotion) {
187                         net += e0_level(c);
188                         c->gwt = cur_index(c);
189                 }
190         }
191
192         /* if the net is 0, fall back on priority */
193         unpledged = net ? promotion_pledge(mgr, net) : mgr->remaining;
194
195         list_for_each_entry(c, &mgr->clients, link) {
196                 if (req_level(c) <= cur_level(c) || !c->notify_promotion ||
197                                 c->gwt == cur_index(c))
198                         continue;
199
200                 pp = c->gwt;
201
202                 /* make sure that the unpledged current is not  wasted */
203                 if (unpledged && req_index(c) != pp) {
204                         step = c->states[pp] - cur_level(c) + unpledged;
205                         pp = edp_promotion_point(c, step);
206                         unpledged -= c->states[pp] - c->states[c->gwt];
207                 }
208
209                 mgr->remaining -= c->states[pp] - cur_level(c);
210                 c->cur = c->states + pp;
211                 if (c->cur == c->req)
212                         mgr->num_denied--;
213
214                 c->notify_promotion(pp, c->private_data);
215                 if (!mgr->remaining || !mgr->num_denied)
216                         return;
217         }
218 }
219
220 static struct edp_governor fair_governor = {
221         .name = "fair",
222         .owner = THIS_MODULE,
223         .update_request = fair_update_request,
224         .update_loans = edp_default_update_loans,
225         .promote = fair_promote
226 };
227
228 static int __init fair_init(void)
229 {
230         return edp_register_governor(&fair_governor);
231 }
232 postcore_initcall(fair_init);