Revert "ARM: tegra: tegratab: dummy change"
[linux-2.6.git] / drivers / edp / edp_overage.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 inline unsigned int cur_overage(struct edp_client *c)
23 {
24         unsigned int cl = cur_level(c);
25         unsigned int el = e0_level(c);
26         return cl > el ? cl - el : 0;
27 }
28
29 static inline unsigned int req_overage(struct edp_client *c)
30 {
31         unsigned int rl = req_level(c);
32         unsigned int el = e0_level(c);
33         return rl > el ? rl - el : 0;
34 }
35
36 /*
37  * Find the maximum that we can allocate for this client. Since we are
38  * using a propotional allocation, ensure that the allowed budget is
39  * fare to other clients. Note that the maximum E-state level is used as
40  * reference for normalizing client requests (E0 can not be used since
41  * it could be zer0 for some clients)
42  */
43 static unsigned int approvable_req(struct edp_client *c,
44                 unsigned int net_overage, unsigned int net_max)
45 {
46         unsigned int tot_overage;
47         unsigned int tot_max;
48         unsigned int fair_level;
49         unsigned int step;
50
51         if (req_index(c) >= c->e0_index)
52                 return req_index(c);
53
54         tot_overage = net_overage + c->manager->remaining;
55         if (cur_overage(c))
56                 tot_overage += cur_overage(c);
57         else
58                 tot_overage -= e0_level(c) - cur_level(c);
59         tot_max = net_max + c->states[0];
60         fair_level = tot_overage * c->states[0] / tot_max + e0_level(c);
61         step = max(fair_level, cur_level(c) + c->manager->remaining) -
62                         cur_level(c);
63
64         return edp_promotion_point(c, step);
65 }
66
67 static void find_net(struct edp_client *client, unsigned int *net_overage,
68                 unsigned int *net_max)
69 {
70         struct edp_client *c;
71         struct edp_manager *m = client->manager;
72
73         *net_overage = 0;
74         *net_max = 0;
75
76         list_for_each_entry(c, &m->clients, link) {
77                 if (c != client && cur_level(c) > e0_level(c)) {
78                         *net_overage += cur_overage(c);
79                         *net_max += c->states[0];
80                 }
81         }
82 }
83
84 static struct edp_client *throttle_pledge(struct edp_client *client,
85                 unsigned int required, unsigned int net_overage,
86                 unsigned int *pledged)
87 {
88         struct edp_manager *m = client->manager;
89         unsigned int deficit = required - m->remaining;
90         struct edp_client *c;
91         unsigned int step;
92
93         *pledged = m->remaining;
94
95         list_for_each_entry_reverse(c, &m->clients, link) {
96                 if (c == client || cur_level(c) <= e0_level(c))
97                         continue;
98
99                 step = (deficit * cur_overage(c) +
100                                 net_overage - 1) / net_overage;
101                 c->gwt = edp_throttling_point(c, step);
102                 *pledged += cur_level(c) - c->states[c->gwt];
103                 if (*pledged >= required)
104                         return c;
105         }
106
107         WARN_ON(*pledged < required);
108         return c;
109 }
110
111 static void throttle_recover(struct edp_client *client, struct edp_client *tp,
112                 unsigned int required)
113 {
114         struct edp_manager *m = client->manager;
115         unsigned int recovered = m->remaining;
116
117         list_for_each_entry_from(tp, &m->clients, link) {
118                 if (tp == client || cur_level(tp) <= e0_level(tp) ||
119                                 tp->gwt == cur_index(tp))
120                         continue;
121
122                 tp->throttle(tp->gwt, tp->private_data);
123                 recovered += cur_level(tp) - tp->states[tp->gwt];
124                 if (tp->cur == tp->req)
125                         m->num_denied++;
126
127                 tp->cur = tp->states + tp->gwt;
128                 if (recovered >= required)
129                         return;
130         }
131 }
132
133 static void throttle(struct edp_client *client)
134 {
135         struct edp_manager *m = client->manager;
136         struct edp_client *tp;
137         unsigned int ar;
138         unsigned int pledged;
139         unsigned int required;
140         unsigned int net_overage;
141         unsigned int net_max;
142
143         find_net(client, &net_overage, &net_max);
144         ar = approvable_req(client, net_overage, net_max);
145         required = client->states[ar] - cur_level(client);
146
147         if (required <= m->remaining) {
148                 client->cur = client->states + ar;
149                 m->remaining -= required;
150                 return;
151         }
152
153         tp = throttle_pledge(client, required, net_overage, &pledged);
154
155         /* E-states are discrete - we may get more than we asked for */
156         if (pledged > required && ar != req_index(client)) {
157                 ar = edp_promotion_point(client, pledged);
158                 required = client->states[ar] - cur_level(client);
159         }
160
161         throttle_recover(client, tp, required);
162         client->cur = client->states + ar;
163         m->remaining = pledged - required;
164 }
165
166 static void overage_update_request(struct edp_client *client,
167                 const unsigned int *req)
168 {
169         edp_default_update_request(client, req, throttle);
170 }
171
172 static unsigned int overage_promotion_point(struct edp_client *c,
173                 unsigned int step, unsigned int max)
174 {
175         unsigned int lim = cur_level(c) + step;
176         unsigned int ci = cur_index(c);
177         unsigned int i = req_index(c);
178
179         while (i < ci && c->states[i] > lim)
180                 i++;
181
182         /*
183          * While being throttled, we probably contributed more than our
184          * fare share - so take the ceiling E-state here
185          */
186         if (c->states[i] < lim && i > req_index(c)) {
187                 if (c->states[i - 1] <= cur_level(c) + max)
188                         i--;
189         }
190
191         return i;
192 }
193
194 static void overage_promote(struct edp_manager *mgr)
195 {
196         unsigned int budget = mgr->remaining;
197         unsigned int net_overage = 0;
198         struct edp_client *c;
199         unsigned int step;
200         unsigned int pp;
201
202         list_for_each_entry(c, &mgr->clients, link) {
203                 if (req_level(c) > cur_level(c) && c->notify_promotion)
204                         net_overage += req_overage(c);
205         }
206
207         /* Guarding against division-by-zero */
208         if (!net_overage) {
209                 WARN_ON(1);
210                 return;
211         }
212
213         list_for_each_entry(c, &mgr->clients, link) {
214                 if (req_level(c) <= cur_level(c) || !c->notify_promotion)
215                         continue;
216
217                 step = (req_overage(c) * budget +
218                                 net_overage - 1) / net_overage;
219                 if (step > mgr->remaining)
220                         step = mgr->remaining;
221
222                 pp = overage_promotion_point(c, step, mgr->remaining);
223                 if (pp == cur_index(c))
224                         continue;
225
226                 mgr->remaining -= c->states[pp] - cur_level(c);
227                 c->cur = c->states + pp;
228
229                 if (c->cur == c->req)
230                         mgr->num_denied--;
231                 c->notify_promotion(pp, c->private_data);
232                 if (!mgr->remaining || !mgr->num_denied)
233                         return;
234         }
235 }
236
237 static struct edp_governor overage_governor = {
238         .name = "overage",
239         .owner = THIS_MODULE,
240         .update_request = overage_update_request,
241         .update_loans = edp_default_update_loans,
242         .promote = overage_promote
243 };
244
245 static int __init overage_init(void)
246 {
247         return edp_register_governor(&overage_governor);
248 }
249 postcore_initcall(overage_init);